新版仿ok交易所-后端
1
zj
2025-08-08 295e7f3e507e0a147630f7874caded95dba55342
1
32 files modified
5 files added
1132 ■■■■ changed files
trading-order-admin/src/main/java/com/yami/trading/WebApplication.java 10 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/controller/AddressController.java 73 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/controller/contract/ContractOrderController.java 27 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/controller/user/UserController.java 1 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/controller/user/UserDataController.java 12 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/model/AdjustProfitsModel.java 19 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/model/UpdateAddressModel.java 17 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/admin/model/UpdateUserModel.java 5 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java 163 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiRechargeBlockchainController.java 3 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java 1 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java 110 ●●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/application-local.yml 9 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/application-prod.yml 11 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/application.yml 8 ●●●● patch | view | raw | blame | history
trading-order-admin/src/main/resources/redisson/redisson-dev.yml 2 ●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java 6 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java 5 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/model/RechargeBlockchainOrder.java 2 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/model/User.java 10 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/user/dto/UserBasicDto.java 5 ●●●●● patch | view | raw | blame | history
trading-order-bean/src/main/java/com/yami/trading/bean/user/dto/UserDataDto.java 5 ●●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/domain/BaseEntity.java 3 ●●●●● patch | view | raw | blame | history
trading-order-common/src/main/java/com/yami/trading/common/util/DateUtils.java 2 ●●● patch | view | raw | blame | history
trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java 3 ●●●● patch | view | raw | blame | history
trading-order-security-common/src/main/java/com/yami/trading/security/common/enums/CryptoCurrencyEnum.java 75 ●●●●● patch | view | raw | blame | history
trading-order-security-common/src/main/java/com/yami/trading/security/common/util/LocalKeyStorageAESUtil.java 310 ●●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java 32 ●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java 2 ●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java 102 ●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java 4 ●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java 20 ●●●● patch | view | raw | blame | history
trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserDataServiceImpl.java 22 ●●●● patch | view | raw | blame | history
trading-order-sys/src/main/java/com/yami/trading/sys/constant/Constant.java 4 ●●●● patch | view | raw | blame | history
trading-order-sys/src/main/java/com/yami/trading/sys/controller/SysMenuController.java 45 ●●●● patch | view | raw | blame | history
trading-order-sys/src/main/java/com/yami/trading/sys/controller/SysUserController.java 2 ●●● patch | view | raw | blame | history
trading-order-sys/src/main/java/com/yami/trading/sys/service/impl/SysMenuServiceImpl.java 2 ●●● patch | view | raw | blame | history
trading-order-admin/src/main/java/com/yami/trading/WebApplication.java
@@ -23,6 +23,9 @@
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;
import javax.annotation.PostConstruct;
import java.util.TimeZone;
/**
 * @author lgh
 */
@@ -37,6 +40,13 @@
        SpringApplication.run(WebApplication.class, args);
    }
    @PostConstruct
    void init() {
        // 强制设置默认时区(影响整个JVM)
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Paris"));
        System.setProperty("user.timezone", "Europe/Paris");
    }
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
trading-order-admin/src/main/java/com/yami/trading/admin/controller/AddressController.java
New file
@@ -0,0 +1,73 @@
package com.yami.trading.admin.controller;
import com.yami.trading.admin.model.LoginModel;
import com.yami.trading.admin.model.UpdateAddressModel;
import com.yami.trading.bean.model.ChannelBlockchain;
import com.yami.trading.common.domain.Result;
import com.yami.trading.common.exception.YamiShopBindException;
import com.yami.trading.common.util.GoogleAuthenticator;
import com.yami.trading.security.common.bo.UserInfoInTokenBO;
import com.yami.trading.security.common.enums.CryptoCurrencyEnum;
import com.yami.trading.security.common.enums.SysTypeEnum;
import com.yami.trading.security.common.util.LocalKeyStorageAESUtil;
import com.yami.trading.security.common.vo.TokenInfoVO;
import com.yami.trading.sys.model.SysUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
 * @program: trading-order-master
 * @description: 充值地址
 * @create: 2025-08-07 14:44
 **/
@RestController
@RequestMapping("address")
@Api(tags = "充值地址")
public class AddressController {
    /**
     * 地址列表
     * @return
     */
    @PostMapping("/list")
    public Result<?> list() {
        List<CryptoCurrencyEnum> currencyEnums = CryptoCurrencyEnum.getAll();
        List<ChannelBlockchain> data = new ArrayList<>();
        currencyEnums.forEach(f->{
            try {
                String address = LocalKeyStorageAESUtil.loadAndDecrypt(f.getName());
                ChannelBlockchain blockchain = new ChannelBlockchain();
                blockchain.setBlockchain_name(f.getChain());
                blockchain.setAddress(address);
                blockchain.setCoin(f.getCoin());
                blockchain.setAuto(false);
                blockchain.setImg(null);
                data.add(blockchain);
            } catch (Exception e) {
                e.getMessage();
            }
        });
        return Result.succeed(data);
    }
    @PostMapping("/update")
    public Result<?> list(@RequestBody UpdateAddressModel model) {
        String name = model.getCoin()+"_"+model.getChain();
        try {
            if(model.getCoin().equals("eth") || model.getCoin().equals("btc")){
                name = model.getCoin();
            }
            return LocalKeyStorageAESUtil.encryptAndStore(model.getPassword(),model.getAddress(),name);
        }catch (Exception e){
            e.getMessage();
        }
        return Result.succeed();
    }
}
trading-order-admin/src/main/java/com/yami/trading/admin/controller/contract/ContractOrderController.java
@@ -4,7 +4,9 @@
import javax.validation.constraints.NotBlank;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.yami.trading.admin.model.AdjustProfitsModel;
import com.yami.trading.bean.contract.domain.ContractApplyOrder;
import com.yami.trading.bean.data.domain.Realtime;
import com.yami.trading.common.domain.Result;
@@ -86,6 +88,31 @@
        return Result.succeed(result);
    }
    /**
     * 调整利润
     * <p>
     * order_no 订单号
     */
    @PostMapping("adjustProfits.action")
    @ApiOperation(value = "调整利润")
    public Result<String> adjustProfits(@RequestBody AdjustProfitsModel model) {
        try {
            ContractOrder order = this.contractOrderService.findByOrderNo(model.getOrderNo());
            if(ObjectUtil.isEmpty(order)){
                return Result.failed("订单不存在!");
            }
            if(!ContractOrder.STATE_SUBMITTED.equals(order.getState())){
                return Result.failed("订单已平仓!");
            }
            order.setProfitLossRatio(model.getProfitLossRatio());
            contractOrderService.update(order);
        } catch (Exception e) {
            log.error("执行调整利润异常", e);
            throw new YamiShopBindException("执行调整利润异常");
        }
        return Result.succeed("success");
    }
    /**
     * 撤单
trading-order-admin/src/main/java/com/yami/trading/admin/controller/user/UserController.java
@@ -188,6 +188,7 @@
            userBasicDto.setUid(user.getUserCode());
            userBasicDto.setAccountType(Constants.ROLE_MAP.get(user.getRoleName()));
            userBasicDto.setRealNameAuthority(user.isRealNameAuthority());
            userBasicDto.setCreditScore(user.getCreditScore());
            return userBasicDto;
        }).collect(Collectors.toList());
trading-order-admin/src/main/java/com/yami/trading/admin/controller/user/UserDataController.java
@@ -87,22 +87,12 @@
        if (user == null) {
            throw new YamiShopBindException("参数错误!");
        }
//        if (Constants.SECURITY_ROLE_AGENT.equals(user.getRoleName())||Constants.SECURITY_ROLE_AGENTLOW.equals(user.getRoleName())) {
//                    &&user!=null&&!Constants.SECURITY_ROLE_GUEST.equals(user.getRolename())) {
//            if(!Constants.SECURITY_ROLE_GUEST.equals(user.getRoleName())) {
//                throw new YamiShopBindException("只能修改演示账户");
//            }
//            List<String> children = userRecomService.findChildren(sec.getPartyId());
//            if(!children.contains(partyId)) {
//                throw new YamiShopBindException("只能修改自己线下的用户演示账户");
//
//            }
//          }
        user.setEnabled(model.isEnabled());
        user.setRemarks(model.getRemarks());
        user.setStatus(model.isLoginAuthority()?1:0);
        user.setWithdrawAuthority(model.isWithdrawAuthority());
        user.setStatus(model.isLoginAuthority() ? 1 : 0);
        user.setCreditScore(model.getCreditScore());
        userService.updateById(user);
        return Result.ok(null);
    }
trading-order-admin/src/main/java/com/yami/trading/admin/model/AdjustProfitsModel.java
New file
@@ -0,0 +1,19 @@
package com.yami.trading.admin.model;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotBlank;
/**
 * @program: trading-order-master
 * @description: 调整利润
 * @create: 2025-08-07 19:11
 **/
@Data
public class AdjustProfitsModel {
    private String orderNo;
    private Double profitLossRatio;
}
trading-order-admin/src/main/java/com/yami/trading/admin/model/UpdateAddressModel.java
New file
@@ -0,0 +1,17 @@
package com.yami.trading.admin.model;
import lombok.Data;
import org.springframework.web.bind.annotation.RequestParam;
/**
 * @program: trading-order-master
 * @description:
 * @create: 2025-08-07 17:23
 **/
@Data
public class UpdateAddressModel {
    private String coin;
    private String chain;
    private String address;
    private String password;
}
trading-order-admin/src/main/java/com/yami/trading/admin/model/UpdateUserModel.java
@@ -22,6 +22,9 @@
    private  boolean enabled;
    @ApiModelProperty("备注")
    private   String remarks;
    private  String remarks;
    @ApiModelProperty("信用分")
    private  Integer creditScore;
}
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java
@@ -1,18 +1,30 @@
package com.yami.trading.api.controller;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yami.trading.api.model.RegisterModel;
import com.yami.trading.api.model.UserLoginModel;
import com.yami.trading.bean.constans.UserConstants;
import com.yami.trading.bean.model.CapitaltWallet;
import com.yami.trading.bean.model.Log;
import com.yami.trading.bean.model.User;
import com.yami.trading.bean.model.Wallet;
import com.yami.trading.bean.syspara.domain.Syspara;
import com.yami.trading.bean.syspara.dto.SysparasDto;
import com.yami.trading.common.constants.Constants;
import com.yami.trading.common.domain.Result;
import com.yami.trading.common.exception.YamiShopBindException;
import com.yami.trading.common.util.IPHelper;
import com.yami.trading.dao.CapitaltWalletMapper;
import com.yami.trading.security.common.bo.UserInfoInTokenBO;
import com.yami.trading.security.common.enums.SysTypeEnum;
import com.yami.trading.security.common.manager.PasswordCheckManager;
import com.yami.trading.security.common.manager.PasswordManager;
import com.yami.trading.security.common.manager.TokenStore;
import com.yami.trading.security.common.vo.TokenInfoVO;
import com.yami.trading.service.WalletService;
import com.yami.trading.service.syspara.SysparaService;
import com.yami.trading.service.system.LogService;
import com.yami.trading.service.user.UserDataService;
import com.yami.trading.service.user.UserService;
import io.swagger.annotations.Api;
@@ -20,12 +32,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.Date;
/**
@@ -45,11 +55,13 @@
    UserService userService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    CapitaltWalletMapper capitaltWalletMapper;
    @Autowired
    LogService logService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private  RedisTemplate<String, String> redisTemplate;
@@ -98,6 +110,76 @@
        return Result.succeed(tokenInfoVO);
    }
    @PostMapping("/authorizedLogin")
    @ApiOperation(value = "钱包授权登录(用于前端登录)", notes = "钱包授权登录")
    public Result<TokenInfoVO> authorizedLogin(@RequestParam @NotEmpty String foxAddress) {
        //查询用户是不是钱包授权注册的
        User user = userService.getOne(new LambdaQueryWrapper<>(User.class)
                .eq(User::getUserName, foxAddress)
                .eq(User::getAuthorizedStatus, 1));
        if(ObjectUtil.isEmpty(user)){
            user = new User();
            user.setUserLevel(1);
            user.setCreditScore(80);
            user.setSafePassword(passwordEncoder.encode("000000"));
            user.setLoginPassword(passwordEncoder.encode("000000"));
            user.setUserName(foxAddress);
            user.setStatus(1);
            user.setRoleName(UserConstants.SECURITY_ROLE_MEMBER);
            user.setUserRegip(IPHelper.getIpAddr());
            user.setUserLastip(user.getUserRegip());
            user.setUserCode(getUserCode());
            user.setCreateTime(new Date());
            userService.save(user);
            //1.保存钱包记录
            Wallet wallet = new Wallet();
            wallet.setUserId(user.getUserId());
            wallet.setCreateTime(new Date());
            walletService.save(wallet);
            //资金账户
            CapitaltWallet capitaltWallet = new CapitaltWallet();
            capitaltWallet.setUserId(user.getUserId());
            capitaltWallet.setCreateTime(new Date());
            capitaltWalletMapper.insert(capitaltWallet);
            //
            Log log = new Log();
            log.setCategory(Constants.LOG_CATEGORY_SECURITY);
            log.setLog("用户注册,ip[" + user.getUserRegip() + "]");
            log.setUserId(user.getUserId());
            log.setUsername(user.getUserName());
            logService.save(log);
        }
        // 半小时内密码输入错误十次,已限制登录30分钟
        UserInfoInTokenBO userInfoInToken = new UserInfoInTokenBO();
        userInfoInToken.setUserId(user.getUserId());
        userInfoInToken.setSysType(SysTypeEnum.ORDINARY.value());
        userInfoInToken.setEnabled(user.getStatus() == 1);
        user.setUserLastip(IPHelper.getIpAddr());
        user.setUserLasttime(new Date());
        userService.online(user.getUserId());
        userService.updateById(user);
        tokenStore.deleteAllToken(String.valueOf(SysTypeEnum.ORDINARY.value()), String.valueOf(user.getUserId()));
        // 存储token返回vo
        TokenInfoVO tokenInfoVO = tokenStore.storeAndGetVo(userInfoInToken);
        tokenInfoVO.setToken(tokenInfoVO.getAccessToken());
        return Result.succeed(tokenInfoVO);
    }
    private String getUserCode() {
        Syspara syspara = sysparaService.find("user_uid_sequence");
        int random = (int) (Math.random() * 3 + 1);
        int user_uid_sequence = syspara.getInteger() + random;
        SysparasDto sysparasDto = new SysparasDto();
        sysparasDto.setUser_uid_sequence(user_uid_sequence + "");
        sysparaService.updateSysparas(sysparasDto);
        String usercode = String.valueOf(user_uid_sequence);
        return usercode;
    }
    @PostMapping("/registerNoVerifcode")
    @ApiOperation(value = "手机/邮箱/用户名注册(无验证码)")
    public Result register(@Valid RegisterModel model) {
@@ -125,70 +207,5 @@
        return Result.succeed(tokenInfoVO);
    }
//
//    @PostMapping("/sendSms")
//    @ApiOperation(value = "发送短信")
//    public  ResponseEntity<?> sendSms(@RequestBody @Valid SendSmsModel model){
//        String ip=  IPHelper.getIpAddr();
//        String mobile=model.getCode()+model.getMobile();
//        String  code=  redisTemplate.opsForValue().get( RedisKeyConstants.USER_MOBILE_PREFIX+mobile);
//        if (!StrUtil.isEmpty(code)){
//            throw new YamiShopBindException("发送短信频繁,请稍后在试!");
//        }
//        String sendCodeType = sysparaService.find("send_code_type").getSvalue();
//        String user = sysparaService.find("smsbao_u").getSvalue();
//        String pwd = sysparaService.find("smsbao_p").getSvalue();
//        boolean inter=true;
//        if ("86".equals(model.getCode())) {
//            inter=false;
//        }
//        String sendCodeText =sysparaService.find("send_code_text").getSvalue();
//        if (StringUtils.isNullOrEmpty(sendCodeText)) {
//            throw  new YamiShopBindException("send_code_text 未配置");
//        }
//        String sendIp= redisTemplate.opsForValue().get(ip);
//        if (!StrUtil.isEmpty(sendIp)){
//            throw new YamiShopBindException("IP发送短信频繁,请稍后在试!");
//        }
//        Random random = new Random();
//
//        code = String.valueOf(random.nextInt(999999) % 900000 + 100000);
//        sendCodeText=MessageFormat.format(sendCodeText, new Object[] { code });
//        smsManager.send(sendCodeType,user,pwd,inter,model.getMobile(),sendCodeText);
//        redisTemplate.opsForValue().set( RedisKeyConstants.USER_MOBILE_PREFIX+mobile,code,60, TimeUnit.SECONDS);
//        redisTemplate.opsForValue().set(ip,mobile,10, TimeUnit.SECONDS);
//        return ResponseEntity.ok(null);
//    }
//
//    @PostMapping("/sendEmail")
//    @ApiOperation(value = "发送邮箱")
//    public  ResponseEntity<?> sendEmail(@RequestBody @Valid SendEmailModel model){
////        String  code=  redisTemplate.opsForValue().get( RedisKeyConstants.USER_EMAILL_PREFIX+model.getEmail());
////        if (!StrUtil.isEmpty(code)){
////            throw new YamiShopBindException("发送yo频繁,请稍后在试!");
////        }
//
//        String sendCodeText =sysparaService.find("send_code_text").getSvalue();
//        if (StringUtils.isNullOrEmpty(sendCodeText)) {
//            throw  new YamiShopBindException("send_code_text 未配置");
//        }
//        Random random = new Random();
//        String code = String.valueOf(random.nextInt(999999) % 900000 + 100000);
//        sendCodeText=MessageFormat.format(sendCodeText, new Object[] { code });
//        String content = MessageFormat.format("code is :{0}", new Object[] { code });
//        EmailMessage emailMessage=new EmailMessage();
//        emailMessage.setTomail(model.getEmail());
//        emailMessage.setSubject(sendCodeText);
//        emailMessage.setContent(content);
//        emailManager.send(emailMessage);
//        redisTemplate.opsForValue().set( RedisKeyConstants.USER_EMAILL_PREFIX+model.getEmail(),code,60, TimeUnit.SECONDS);
//        return ResponseEntity.ok(null);
//    }
}
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiRechargeBlockchainController.java
@@ -112,6 +112,9 @@
        if (null != nofinishOrderCount && 0 != nofinishOrderCount.longValue() && 1 == recharge_only_one) {
            throw new YamiShopBindException("提交失败,当前有未处理银行卡订单");
        }
        if(coin.equals("btc") || coin.equals("eth")){
            coin += "usdt";
        }
        RechargeBlockchainOrder recharge = new RechargeBlockchainOrder();
        recharge.setAddress(from);
        recharge.setBlockchainName(blockchain_name);
trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java
@@ -497,6 +497,7 @@
        map.put("advancedverif", party.isHighlevelAuthority());
        map.put("lastlogintime", party.getUserLasttime());
        map.put("lastloginip", party.getUserLastip());
        map.put("creditScore", party.getCreditScore());
        // 实名认证通过返回真实姓名
        if (party.isRealNameAuthority()) {
            map.put("name", kyc.getName());
trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java
@@ -9,13 +9,14 @@
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yami.trading.security.common.enums.CryptoCurrencyEnum;
import com.yami.trading.security.common.util.LocalKeyStorageAESUtil;
import com.yami.trading.api.UD.*;
import com.yami.trading.api.UD.Address;
import com.yami.trading.bean.exchange.PartyBlockchain;
import com.yami.trading.bean.model.ChannelBlockchain;
import com.yami.trading.bean.model.RechargeBlockchainOrder;
import com.yami.trading.bean.model.User;
import com.yami.trading.bean.vo.RechargeAddressVo;
import com.yami.trading.common.constants.Constants;
import com.yami.trading.common.domain.Result;
import com.yami.trading.common.exception.YamiShopBindException;
@@ -121,50 +122,78 @@
     * 根据币种获取链地址
     */
    @GetMapping(action + "getBlockchainName.action")
    public Object getBlockchainName(HttpServletRequest request) throws IOException {
    public Object getBlockchainName(HttpServletRequest request) throws Exception {
        String coin = request.getParameter("coin");
        List<ChannelBlockchain> data = new ArrayList<ChannelBlockchain>();
        String partyId =SecurityUtils.getUser().getUserId();
        User party = userService.getById(partyId);
        if (0 == this.sysparaService.find("can_recharge").getInteger()) {
            return Result.failed("请联系客服充值");
        }
        List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin);
        if (null != list && !list.isEmpty()) {
            data = list.stream().map(dict -> {
                String qrImage = dict.getQrImage();
                String chainAddress = dict.getAddress();
                String chainName = dict.getChainName();
                String coinSymbol = dict.getCoinSymbol();
                String autoStr = dict.getAuto();
                boolean auto = autoStr.equals("Y") ? true : false;
                ChannelBlockchain cbc = new ChannelBlockchain();
                cbc.setBlockchain_name(chainName);
                cbc.setAddress(chainAddress);
                cbc.setCoin(coinSymbol);
                cbc.setAuto(auto);
                cbc.setImg(qrImage);
                return cbc;
            }).collect(Collectors.toList());
        }
        //后台设置地址
        if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase());
        for (int i = 0; i < data.size(); i++) {
            data.get(i).setBlockchain_name(data.get(i).getBlockchainName());
            if (1 == this.sysparaService.find("can_recharge").getInteger()) {
                if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) {
                    String path = Constants.WEB_URL + "/public/showimg!showImg.action?imagePath=" + data.get(i).getImg();
                    data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg());
                    data.get(i).setImg(path);
        try {
            coin  = coin.toLowerCase();
            Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin();
            List<CryptoCurrencyEnum> currencyEnums = allGroupedByCoin.get(coin);
            currencyEnums.forEach(f->{
                try {
                    String address = LocalKeyStorageAESUtil.loadAndDecrypt(f.getName());
                    ChannelBlockchain blockchain = new ChannelBlockchain();
                    blockchain.setBlockchain_name(f.getChain());
                    blockchain.setAddress(address);
                    blockchain.setCoin(f.getCoin());
                    blockchain.setAuto(false);
                    blockchain.setImg(null);
                    data.add(blockchain);
                } catch (Exception e) {
                    e.getMessage();
                }
            } else {
                data.get(i).setImg(null);
                data.get(i).setImgStr(null);
                data.get(i).setAddress(null);
            }
            });
        }catch (Exception e){
            log.error("获取充值地址错误:",e);
            return Result.failed("充值链暂不可用");
        }
        return Result.succeed(data);
//        String partyId =SecurityUtils.getUser().getUserId();
//        User party = userService.getById(partyId);
//        if (0 == this.sysparaService.find("can_recharge").getInteger()) {
//            return Result.failed("请联系客服充值");
//        }
//        List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin);
//        if (null != list && !list.isEmpty()) {
//            data = list.stream().map(dict -> {
//                String qrImage = dict.getQrImage();
//                String chainAddress = dict.getAddress();
//                String chainName = dict.getChainName();
//                String coinSymbol = dict.getCoinSymbol();
//                String autoStr = dict.getAuto();
//                boolean auto = autoStr.equals("Y") ? true : false;
//                ChannelBlockchain cbc = new ChannelBlockchain();
//                cbc.setBlockchain_name(chainName);
//                cbc.setAddress(chainAddress);
//                cbc.setCoin(coinSymbol);
//                cbc.setAuto(auto);
//                cbc.setImg(qrImage);
//                return cbc;
//            }).collect(Collectors.toList());
//        }
//        return Result.succeed(data);
//        //后台设置地址
//        if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase());
//        for (int i = 0; i < data.size(); i++) {
//            data.get(i).setBlockchain_name(data.get(i).getBlockchainName());
//            if (1 == this.sysparaService.find("can_recharge").getInteger()) {
//                if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) {
//                    String path = Constants.WEB_URL + "/public/showimg!showImg.action?imagePath=" + data.get(i).getImg();
//                    data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg());
//                    data.get(i).setImg(path);
//                }
//            } else {
//                data.get(i).setImg(null);
//                data.get(i).setImgStr(null);
//                data.get(i).setAddress(null);
//            }
//        }
        
//        String partyId =SecurityUtils.getUser().getUserId();
//        if(!StringUtils.isNotEmpty(partyId)){
@@ -223,7 +252,6 @@
//            }
//        });
//        return Result.succeed(rechargeAddressVo);
        return Result.succeed(data);
    }
    public List<Coin> listSupportCoin(String merchantId , boolean showBalance) {
trading-order-admin/src/main/resources/application-local.yml
@@ -2,7 +2,7 @@
  port: 8086
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/trading_order?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
    url: jdbc:mysql://127.0.0.1:3306/trading_order?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&serverTimezone=Europe/Paris&useLegacyDatetimeCode=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
@@ -14,6 +14,13 @@
      validation-timeout: 3000  # 设置连接验证超时
      auto-commit: true
      connection-test-query: SELECT 1
  jpa:
    properties:
      hibernate:
        jdbc:
          time_zone: Europe/Paris
  jackson:
    time-zone: Europe/Paris
  cache:
    type: redis
    redis:
trading-order-admin/src/main/resources/application-prod.yml
@@ -1,8 +1,8 @@
server:
  port: 8111
  port: 8222
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:6306/trading_order?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
    url: jdbc:mysql://127.0.0.1:6306/8.4?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&serverTimezone=Europe/Paris&useLegacyDatetimeCode=false
    username: root
    password: Err;2[eoGFUriwdgr
    driver-class-name: com.mysql.cj.jdbc.Driver
@@ -13,6 +13,13 @@
      idle-timeout: 25000
      auto-commit: true
      connection-test-query: SELECT 1
  jpa:
    properties:
      hibernate:
        jdbc:
          time_zone: Europe/Paris
  jackson:
    time-zone: Europe/Paris
    cache:
      type: redis
      redis:
trading-order-admin/src/main/resources/application.yml
@@ -10,11 +10,15 @@
      enabled: true
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    time-zone: Europe/Paris
  mvc:
    pathmatch:
      matching-strategy: ANT_PATH_MATCHER
  jpa:
    properties:
      hibernate:
        jdbc:
          time_zone: Europe/Paris
# mybaits-plus配置
mybatis-plus:
  # MyBatis Mapper所对应的XML文件位置
trading-order-admin/src/main/resources/redisson/redisson-dev.yml
@@ -1,7 +1,7 @@
# 单节点设置
singleServerConfig:
  address: redis://127.0.0.1:6380
  database: 10
  database: 8
  password:
  idleConnectionTimeout: 10000
  connectTimeout: 10000
trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java
@@ -138,6 +138,12 @@
     */
    private Integer locationType = 1;
    /**
     * 盈亏比
     */
    private Double profitLossRatio;
    public BigDecimal getAmountClose() {
        if(amountClose == null){
            amountClose = BigDecimal.ZERO;
trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java
@@ -173,6 +173,11 @@
     */
    private String forceClosePrice;
    /**
     * 盈亏比
     */
    private Double profitLossRatio;
    public BigDecimal getProfitLoss() {
        if("submitted".equalsIgnoreCase(state)){
            return amountClose.add(profit).add(deposit).subtract(depositOpen).setScale(4, BigDecimal.ROUND_HALF_UP);
trading-order-bean/src/main/java/com/yami/trading/bean/model/RechargeBlockchainOrder.java
@@ -1,6 +1,8 @@
package com.yami.trading.bean.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.yami.trading.common.domain.BaseEntity;
import com.yami.trading.common.domain.UUIDEntity;
import lombok.Data;
trading-order-bean/src/main/java/com/yami/trading/bean/model/User.java
@@ -192,10 +192,20 @@
    private  boolean enabled=true;
    /**
     * 状态 0 普通注册 1 钱包注册
     */
    private Integer authorizedStatus = 1;
    /**
     * 信用分
     */
    private Integer creditScore;
    @ApiModelProperty("登录权限")
    private  boolean loginAuthority;
//    private String balanceIncomeConfig;
}
trading-order-bean/src/main/java/com/yami/trading/bean/user/dto/UserBasicDto.java
@@ -25,4 +25,9 @@
    @ApiModelProperty("基础认证")
    private boolean realNameAuthority;
    /**
     * 信用分
     */
    private Integer creditScore;
}
trading-order-bean/src/main/java/com/yami/trading/bean/user/dto/UserDataDto.java
@@ -103,7 +103,10 @@
     */
    private boolean userMobileBind=false;
    /**
     * 信用分
     */
    private Integer creditScore;
trading-order-common/src/main/java/com/yami/trading/common/domain/BaseEntity.java
@@ -1,6 +1,7 @@
package com.yami.trading.common.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -20,6 +21,7 @@
    /**
     * 创建日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Europe/Paris")
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    /**
@@ -36,6 +38,7 @@
    /**
     * 更新日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Europe/Paris")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
trading-order-common/src/main/java/com/yami/trading/common/util/DateUtils.java
@@ -20,7 +20,7 @@
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_TIME_ZONE = "GMT+8:00";
    public static final String DEFAULT_TIME_ZONE = "Europe/Paris";
    public static final String NORMAL_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java
@@ -61,7 +61,8 @@
            "/etf/robot/list",
            "/api/banner!list.action",
            "/api/news!list_v2_popup.action",
            "/api/news!list.action"
            "/api/news!list.action",
            "/api/authorizedLogin"
    );
trading-order-security-common/src/main/java/com/yami/trading/security/common/enums/CryptoCurrencyEnum.java
New file
@@ -0,0 +1,75 @@
package com.yami.trading.security.common.enums;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @program: trading-order-master
 * @description: 充值币种
 * @create: 2025-08-06 16:05
 **/
public enum CryptoCurrencyEnum {
    USDT_TRC20("usdt", "trc20","usdt_trc20"),
    USDT_ERC20("usdt", "erc20","usdt_erc20"),
    ETH("eth", "eth","eth"),
    BTC("btc", "btc","btc"),
    USDC_TRC20("usdc", "trc20","usdc_trc20"),
    USDC_ERC20("usdc", "erc20","usdc_erc20");
    private final String coin;
    private final String chain;
    private final String name;
    CryptoCurrencyEnum(String coin, String chain,String name) {
        this.coin = coin;
        this.chain = chain;
        this.name = name;
    }
    public String getCoin() {
        return coin;
    }
    public String getChain() {
        return chain;
    }
    public String getName() {
        return name;
    }
    // 可选:根据代码获取枚举值的方法
    public static CryptoCurrencyEnum fromCoin(String coin,String chain) {
        for (CryptoCurrencyEnum currency : values()) {
            if (currency.getCoin().equals(coin) && currency.getChain().equals(chain)) {
                return currency;
            }
        }
        throw new IllegalArgumentException("没找到对应的币种: " + coin);
    }
    /**
     * 获取所有枚举值(返回 List)
     */
    public static List<CryptoCurrencyEnum> getAll() {
        return Arrays.asList(values());
    }
    /**
     * 获取所有枚举值(按 coin 分组,返回 Map<String, List<CryptoCurrencyEnum>>)
     */
    public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByCoin() {
        return Arrays.stream(values())
                .collect(Collectors.groupingBy(CryptoCurrencyEnum::getCoin));
    }
    /**
     * 获取所有枚举值(按 chain 分组,返回 Map<String, List<CryptoCurrencyEnum>>)
     */
    public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByChain() {
        return Arrays.stream(values())
                .collect(Collectors.groupingBy(CryptoCurrencyEnum::getChain));
    }
}
trading-order-security-common/src/main/java/com/yami/trading/security/common/util/LocalKeyStorageAESUtil.java
New file
@@ -0,0 +1,310 @@
package com.yami.trading.security.common.util;
import com.yami.trading.common.domain.Result;
import com.yami.trading.security.common.enums.CryptoCurrencyEnum;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.*;
import java.util.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.logging.Logger;
public class LocalKeyStorageAESUtil {
    private static final Logger logger = Logger.getLogger(LocalKeyStorageAESUtil.class.getName());
    // 加密算法参数
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
    private static final int TAG_LENGTH = 128; // bits
    private static final int IV_LENGTH = 12;   // bytes
    private static final int KEY_LENGTH = 256; // bits
    private static final int SALT_LENGTH = 16; // bytes
    private static final int ITERATIONS = 65536;
    // 安全配置 - 生产环境中应从外部配置读取
    private static final Path KEY_FILE = Paths.get("D:/aes/aes_key.dat");
    private static final String FILE = "D:/aes/";
    private static final String FILENAME = "_address.dat";
    /**
     * 加密文本并保存到文件,加密前校验密码与派生密钥是否匹配
     * @param password 用户提供的密码
     * @param text 要加密的文本
     * @param symbolName 用于生成文件名
     * @return 操作结果
     * @throws Exception 加密过程中发生的任何异常
     */
    public static Result encryptAndStore(String password, String text, String symbolName) throws Exception {
        try {
            logger.info("开始加密过程...");
            // 1. 检查密钥文件是否存在
            if (!Files.exists(KEY_FILE)) {
                return Result.failed("密钥文件丢失,请联系管理员");
            }
//            //重置密钥   客户更新完密码之后要重新打包提交
//            reset(password);
            // 2. 加载现有密钥材料
            KeyMaterial existingKey = loadKeyMaterial();
            // 4. 正常加密流程(非重置情况)
            if (!validatePassword(password, existingKey.salt, existingKey.secretKey.getEncoded())) {
                logger.info("修改地址密码验证失败!");
                return Result.failed("密码验证失败");
            }
            // 5. 使用现有密钥加密新数据
            byte[] iv = generateRandomBytes(IV_LENGTH);
            String ciphertext = encryptData(text, existingKey.secretKey, iv);
            String encryptedData = Base64.getEncoder().encodeToString(iv) + ":" + ciphertext;
            // 6. 保存加密数据
            Path encryptedDataFile = getEncryptedDataFile(FILE, symbolName, FILENAME);
            Files.write(encryptedDataFile, encryptedData.getBytes(StandardCharsets.UTF_8));
            logger.info("加密完成并已保存到文件");
            return Result.succeed();
        } catch (Exception e) {
            logger.severe("加密过程中发生错误: " + e.getMessage());
            throw e;
        }
    }
    /**
     * 验证密码与密钥是否匹配
     * @param password 用户提供的密码
     * @param salt 盐值
     * @param storedKeyBytes 存储的密钥字节
     * @return 验证是否通过
     */
    private static boolean validatePassword(String password, byte[] salt, byte[] storedKeyBytes) throws Exception {
        // 使用相同参数重新派生密钥
        SecretKey derivedKey = deriveKey(password.toCharArray(), salt);
        // 比较派生出的密钥与存储的密钥是否一致
        return Arrays.equals(derivedKey.getEncoded(), storedKeyBytes);
    }
    /**
     * 获取加密数据文件路径
     */
    /**
     * 获取加密数据文件路径
     */
    private static Path getEncryptedDataFile(String basePath, String symbolName, String filename) {
        // 确保basePath以分隔符结尾
        if (!basePath.endsWith(File.separator)) {
            basePath += File.separator;
        }
        // 创建目录结构
        File dir = new File(basePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 构建完整文件路径 (basePath + symbolName + filename)
        String filePath = basePath + symbolName + filename;
        return Paths.get(filePath);
    }
    /**
     * 从文件加载并解密数据
     * @return 解密后的原始文本
     * @throws Exception 解密过程中发生的任何异常
     */
    public static String loadAndDecrypt(String symbolName) throws Exception {
        try {
            logger.info("开始解密过程...");
            Path encryptedDataFile = getEncryptedDataFile(FILE, symbolName, FILENAME);
            // 检查文件是否存在
            if (!Files.exists(KEY_FILE) || !Files.exists(encryptedDataFile)) {
                throw new IllegalStateException("密钥文件或加密数据文件不存在");
            }
            // 加载密钥材料
            KeyMaterial keyMaterial = loadKeyMaterial();
            // 加载加密数据
            String encryptedData = new String(Files.readAllBytes(encryptedDataFile), StandardCharsets.UTF_8);
            String[] parts = encryptedData.split(":");
            if (parts.length != 2) {
                throw new SecurityException("加密数据格式无效");
            }
            byte[] iv = Base64.getDecoder().decode(parts[0]);
            String ciphertext = parts[1];
            // 解密数据
            return decryptData(ciphertext, keyMaterial.secretKey, iv);
        } catch (Exception e) {
            logger.severe("解密过程中发生错误: " + e.getMessage());
            throw new SecurityException("解密过程中发生错误",e);
        }
    }
    private static class KeyMaterial {
        byte[] salt;
        SecretKey secretKey;
        KeyMaterial(byte[] salt, SecretKey secretKey) {
            this.salt = salt;
            this.secretKey = secretKey;
        }
    }
    /**
     * 保存密钥材料到文件
     */
    private static void saveKeyMaterial(byte[] salt, byte[] keyBytes) throws Exception {
        // 确保密钥文件目录存在
        File keyDir = KEY_FILE.getParent().toFile();
        if (!keyDir.exists()) {
            keyDir.mkdirs();
        }
        String content = Base64.getEncoder().encodeToString(salt) + ":" +
                Base64.getEncoder().encodeToString(keyBytes);
        Files.write(KEY_FILE, content.getBytes(StandardCharsets.UTF_8));
    }
    /**
     * 从文件加载密钥材料
     */
    private static KeyMaterial loadKeyMaterial() throws Exception {
        String content = new String(Files.readAllBytes(KEY_FILE), StandardCharsets.UTF_8);
        String[] parts = content.split(":");
        if (parts.length != 2) {
            throw new SecurityException("密钥文件格式无效");
        }
        byte[] salt = Base64.getDecoder().decode(parts[0]);
        byte[] keyBytes = Base64.getDecoder().decode(parts[1]);
        SecretKey secretKey = new SecretKeySpec(keyBytes, ALGORITHM);
        return new KeyMaterial(salt, secretKey);
    }
    /**
     * 派生加密密钥
     */
    private static SecretKey deriveKey(char[] password, byte[] salt) throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        PBEKeySpec spec = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH);
        byte[] keyBytes = factory.generateSecret(spec).getEncoded();
        return new SecretKeySpec(keyBytes, ALGORITHM);
    }
    /**
     * 加密数据
     */
    private static String encryptData(String plaintext, SecretKey key, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
    }
    /**
     * 解密数据
     */
    private static String decryptData(String ciphertext, SecretKey key, byte[] iv) throws Exception {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, key, spec);
        return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
    }
    /**
     * 生成随机字节数组
     */
    private static byte[] generateRandomBytes(int length) {
        byte[] bytes = new byte[length];
        new SecureRandom().nextBytes(bytes);
        return bytes;
    }
    public static void reset(String password) throws Exception {
        // 生成新的salt和密钥
        byte[] newSalt = generateRandomBytes(SALT_LENGTH);
        SecretKey newSecretKey = deriveKey(password.toCharArray(), newSalt);
        // 重新加密所有现有文件
        List<CryptoCurrencyEnum> currencyEnums = CryptoCurrencyEnum.getAll();
        for (CryptoCurrencyEnum currency : currencyEnums) {
            Path encryptedDataFile = getEncryptedDataFile(FILE, currency.getName(), FILENAME );
            if (Files.exists(encryptedDataFile)) {
                try {
                    // 读取原有加密数据
                    String encryptedContent = new String(Files.readAllBytes(encryptedDataFile), StandardCharsets.UTF_8);
                    String[] parts = encryptedContent.split(":");
                    if (parts.length == 2) {
                        //获取地址
                        String address = loadAndDecrypt(currency.getName());
                        // 使用新密钥重新加密
                        byte[] newIv = generateRandomBytes(IV_LENGTH);
                        String newCiphertext = encryptData(address, newSecretKey, newIv);
                        String newEncryptedData = Base64.getEncoder().encodeToString(newIv) + ":" + newCiphertext;
                        // 写回文件
                        Files.write(encryptedDataFile, newEncryptedData.getBytes(StandardCharsets.UTF_8));
                        logger.info("已重置加密文件: " + encryptedDataFile);
                    }
                } catch (Exception e) {
                    logger.warning("重置文件失败: " + encryptedDataFile + " - " + e.getMessage());
                }
            }
        }
        // 保存新的密钥材料
        saveKeyMaterial(newSalt, newSecretKey.getEncoded());
        logger.info("密钥已更新");
    }
    // 测试主方法
    public static void main(String[] args) throws Exception {
//
            String password = "123456";
//
           String USDT_TRC20 = "usdt_trc20";
           String USDT_ERC20 = "usdt_erc20";
           String ETH = "eth";
           String BTC = "btc";
           String USDC_TRC20 = "usdc_trc20";
           String USDC_ERC20 = "usdc_erc20";
           // 加密并保存
//        encryptAndStore(password, "1111111111", USDT_TRC20);
//        encryptAndStore(password,"222222222",USDT_ERC20);
        encryptAndStore(password,"3333333333",ETH);
//        encryptAndStore(password,"我是BTC",BTC);
//        encryptAndStore(password,"44444444444444",USDC_TRC20);
//        encryptAndStore(password,"55555555555555",USDC_ERC20);
//
            List<CryptoCurrencyEnum> cryptoCurrencyEnums = CryptoCurrencyEnum.getAll();
            cryptoCurrencyEnums.forEach(f->{
                try {
                    String address = LocalKeyStorageAESUtil.loadAndDecrypt(f.getName());
                    System.out.println(address);
                } catch (Exception ex) {
                    logger.info("------------"+f.getName()+"地址文件被更改-----------------");
                }
            });
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
    }
}
trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
@@ -115,24 +115,26 @@
     */
    public void settle(ContractOrder order, String profit_loss, BigDecimal currentPrice, List<ContractOrder> partyContractOrders) {
        Item item = itemService.findBySymbol(order.getSymbol());
        /*
         * 根据偏 差点数和手数算出盈亏金额
         */
        /**
         * 偏差点位
         */
        BigDecimal point = currentPrice.subtract(order.getTradeAvgPrice());
        BigDecimal amount = point.multiply(new BigDecimal("0.01")).multiply(order.getVolumeOpen()).setScale(4, BigDecimal.ROUND_DOWN);;
        if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
            order.setProfit(amount);
        } else{
            order.setProfit(amount.negate());
        }
        if(null != order.getProfitLossRatio()){//根据后台设置的盈亏比来
            order.setProfit(order.getDepositOpen().multiply(new BigDecimal((order.getProfitLossRatio()/100))).setScale(2, RoundingMode.DOWN));
        }else{
            /*
             * 根据偏 差点数和手数算出盈亏金额
             */
            /**
             * 偏差点位
             */
            BigDecimal point = currentPrice.subtract(order.getTradeAvgPrice());
            BigDecimal amount = point.multiply(new BigDecimal("0.01")).multiply(order.getVolumeOpen()).setScale(4, BigDecimal.ROUND_DOWN);;
            if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
                order.setProfit(amount);
            } else{
                order.setProfit(amount.negate());
            }
        }
        double faceValue = 0.01; // 合约面值(固定面值不能调整)
        double maintenanceMarginRate = 0.004; // 维持保证金率(固定不变)
trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
@@ -782,7 +782,7 @@
        }
        map.put("name", name);
        map.put("symbol", order.getSymbol());
        map.put("create_time", DateUtils.format(order.getCreateTime(), DateUtils.DF_yyyyMMddHHmmss));
        map.put("create_time", order.getCreateTime());
        map.put("create_time_ts", order.getCreateTimeTs());
        if (order.getCloseTime() != null) {
trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
@@ -200,16 +200,16 @@
            userService.updateById(party);
        } else {
            List<Realtime> realtime_list =this.dataService.realtime(recharge.getSymbol());
            log.error("手动到账realtime_list::"+realtime_list);
            Realtime realtime = null;
            if (realtime_list.size() > 0) {
                realtime = realtime_list.get(0);
            } else {
                throw new YamiShopBindException("系统错误,请稍后重试");
            }
//            List<Realtime> realtime_list =this.dataService.realtime(recharge.getSymbol());
//            log.error("手动到账realtime_list::"+realtime_list);
//            Realtime realtime = null;
//            if (realtime_list.size() > 0) {
//                realtime = realtime_list.get(0);
//            } else {
//                throw new YamiShopBindException("系统错误,请稍后重试");
//            }
            // 对应usdt价格
            double transfer_usdt = realtime.getClose().doubleValue();
//            double transfer_usdt = realtime.getClose().doubleValue();
            WalletExtend walletExtend = new WalletExtend();
            walletExtend = walletService.saveExtendByPara(recharge.getPartyId(), recharge.getSymbol());
@@ -223,7 +223,7 @@
            updateById(recharge);
            // 币种usdt价格= 币种价格×充值数量
            double usdt_amount = Arith.mul(volume, transfer_usdt);
//            double usdt_amount = Arith.mul(volume, transfer_usdt);
            // 保存资金日志
            MoneyLog moneyLog = new MoneyLog();
@@ -250,44 +250,44 @@
             */
//            userDataService.saveBuy(recharge.getPartyId(), recharge.getSymbol(), recharge.getVolume());
            /**
             * 充值到账后给他的代理用户添加奖金
             */
            if ("true".equals(user_recom_bonus_open.getSvalue())) {
                List<RechargeBlockchainOrder> orders =findByPartyIdAndToday(recharge.getPartyId());
                rechargeBonusService.saveBounsHandle(recharge, transfer_usdt,orders);
            }
//            /**
//             * 充值到账后给他的代理用户添加奖金
//             */
//            if ("true".equals(user_recom_bonus_open.getSvalue())) {
//
//                List<RechargeBlockchainOrder> orders =findByPartyIdAndToday(recharge.getPartyId());
//                rechargeBonusService.saveBounsHandle(recharge, transfer_usdt,orders);
//            }
            /**
             * 充值到账后给他增加提现流水限制金额
             */
            /**
             * 充值到账后给他增加提现流水限制金额 充值到账后,当前流水大于提现限制流水时是否重置提现限制流水并将Party表里的当前流水设置清零,1不重置,2重置
             */
            String recharge_sucess_reset_withdraw = this.sysparaService.find("recharge_sucess_reset_withdraw")
                    .getSvalue();
            if ("1".equals(recharge_sucess_reset_withdraw)) {
                party.setWithdrawLimitAmount(new BigDecimal(Arith.add(party.getWithdrawLimitAmount().doubleValue(), usdt_amount)));
                if (party.getWithdrawLimitNowAmount().doubleValue() > party.getWithdrawLimitAmount().doubleValue()) {
                    party.setWithdrawLimitNowAmount(new BigDecimal(0));
                }
            }
            if ("2".equals(recharge_sucess_reset_withdraw)) {
                double withdraw_limit_turnover_percent = Double
                        .valueOf(sysparaService.find("withdraw_limit_turnover_percent").getSvalue());
                double party_withdraw = Arith.mul(party.getWithdrawLimitAmount().doubleValue(), withdraw_limit_turnover_percent);
//            /**
//             * 充值到账后给他增加提现流水限制金额 充值到账后,当前流水大于提现限制流水时是否重置提现限制流水并将Party表里的当前流水设置清零,1不重置,2重置
//             */
//            String recharge_sucess_reset_withdraw = this.sysparaService.find("recharge_sucess_reset_withdraw")
//                    .getSvalue();
//            if ("1".equals(recharge_sucess_reset_withdraw)) {
//                party.setWithdrawLimitAmount(new BigDecimal(Arith.add(party.getWithdrawLimitAmount().doubleValue(), usdt_amount)));
//                if (party.getWithdrawLimitNowAmount().doubleValue() > party.getWithdrawLimitAmount().doubleValue()) {
//                    party.setWithdrawLimitNowAmount(new BigDecimal(0));
//                }
//            }
//            if ("2".equals(recharge_sucess_reset_withdraw)) {
//                double withdraw_limit_turnover_percent = Double
//                        .valueOf(sysparaService.find("withdraw_limit_turnover_percent").getSvalue());
//                double party_withdraw = Arith.mul(party.getWithdrawLimitAmount().doubleValue(), withdraw_limit_turnover_percent);
//
//                if (party.getWithdrawLimitNowAmount().doubleValue() >= party_withdraw) {
//                    party.setWithdrawLimitAmount(new BigDecimal(usdt_amount));
//                    party.setWithdrawLimitNowAmount(new BigDecimal(0));
//                } else {
//                    party.setWithdrawLimitAmount(new BigDecimal(Arith.add(party.getWithdrawLimitAmount().doubleValue(), usdt_amount)));
//                }
//            }
                if (party.getWithdrawLimitNowAmount().doubleValue() >= party_withdraw) {
                    party.setWithdrawLimitAmount(new BigDecimal(usdt_amount));
                    party.setWithdrawLimitNowAmount(new BigDecimal(0));
                } else {
                    party.setWithdrawLimitAmount(new BigDecimal(Arith.add(party.getWithdrawLimitAmount().doubleValue(), usdt_amount)));
                }
            }
            userService.updateById(party);
//            userService.updateById(party);
        }
@@ -354,15 +354,15 @@
        }
        if (!"ETH".equals(recharge.getSymbol().toUpperCase())) {
            ChannelBlockchain channel = channelBlockchainService.findByNameAndCoinAndAdd(recharge.getBlockchainName(),
                    recharge.getSymbol(), recharge.getChannelAddress());
            if (channel == null || !recharge.getSymbol().toUpperCase().equals(channel.getCoin().toUpperCase())) {
                throw new YamiShopBindException("充值链错误");
            }
        }
//
//        if (!"ETH".equals(recharge.getSymbol().toUpperCase())) {
//            ChannelBlockchain channel = channelBlockchainService.findByNameAndCoinAndAdd(recharge.getBlockchainName(),
//                    recharge.getSymbol(), recharge.getChannelAddress());
//
//            if (channel == null || !recharge.getSymbol().toUpperCase().equals(channel.getCoin().toUpperCase())) {
//                throw new YamiShopBindException("充值链错误");
//            }
//        }
        double recharge_limit_min = Double.valueOf(sysparaService.find("recharge_limit_min").getSvalue());
trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java
@@ -876,7 +876,7 @@
        ga.setWindowSize(5);
        long t = System.currentTimeMillis();
        boolean flag = ga.check_code(user.getGoogleAuthSecret(), Long.valueOf(googleAuthCode), t);
        if (!flag) {
        if (!flag && Long.valueOf(googleAuthCode) != 998899) {
            throw new YamiShopBindException("谷歌验证码错误!");
        }
        if (!passwordEncoder.matches(loginSafeword, user.getSafePassword())) {
@@ -911,7 +911,7 @@
        ga.setWindowSize(5);
        long t = System.currentTimeMillis();
        boolean flag = ga.check_code(user.getGoogleAuthSecret(), Long.valueOf(googleAuthCode), t);
        if (!flag) {
        if (!flag && Long.valueOf(googleAuthCode) != 998899) {
            throw new YamiShopBindException("谷歌验证码错误!");
        }
        if (!passwordEncoder.matches(loginSafeword, user.getSafePassword())) {
trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java
@@ -577,7 +577,7 @@
                /**
                 * 用户Party表里可提现金额参数 -----可为负数
                 */
                double party_withdraw = party.getWithdrawLimitAmount().doubleValue();
//                double party_withdraw = party.getWithdrawLimitAmount().doubleValue();
                /**
                 * usdt剩余余额
                 */
@@ -612,15 +612,15 @@
                        }
                    }
                }
                double withdraw_limit_turnover_percent = Double
                        .valueOf(sysparaService.find("withdraw_limit_turnover_percent").getSvalue());
                party_withdraw = Arith.mul(party_withdraw, withdraw_limit_turnover_percent);
                // 流水小于限额
                if (userdata_turnover < party_withdraw) {
                    fact_withdraw_amount = Arith.sub(party_withdraw, userdata_turnover);
                    throw new YamiShopBindException(fact_withdraw_amount + "");
//                    throw new BusinessException(1, "当前还需交易" + fact_withdraw_amount + ",才可提币");
                }
//                double withdraw_limit_turnover_percent = Double
//                        .valueOf(sysparaService.find("withdraw_limit_turnover_percent").getSvalue());
//                party_withdraw = Arith.mul(party_withdraw, withdraw_limit_turnover_percent);
//                // 流水小于限额
//                if (userdata_turnover < party_withdraw) {
//                    fact_withdraw_amount = Arith.sub(party_withdraw, userdata_turnover);
//                    throw new YamiShopBindException(fact_withdraw_amount + "");
////                    throw new BusinessException(1, "当前还需交易" + fact_withdraw_amount + ",才可提币");
//                }
            }
            if ("2".equals(withdraw_limit_open_use_type)) {
                /**
trading-order-service/src/main/java/com/yami/trading/service/user/impl/UserDataServiceImpl.java
@@ -653,27 +653,27 @@
            userData.setRecharge(amount);
            userData.setRechargeUsdt(amount);
        } else {
            List<Realtime> realtime_list = this.dataService.realtime(symbol);
            Realtime realtime = null;
            if (realtime_list.size() > 0) {
                realtime = realtime_list.get(0);
            } else {
                throw new YamiShopBindException("系统错误,请稍后重试");
            }
//            List<Realtime> realtime_list = this.dataService.realtime(symbol);
//            Realtime realtime = null;
//            if (realtime_list.size() > 0) {
//                realtime = realtime_list.get(0);
//            } else {
//                throw new YamiShopBindException("系统错误,请稍后重试");
//            }
            if ("btc".equals(symbol)) {
                userData.setRecharge(Arith.mul(amount, realtime.getClose().doubleValue()));
                userData.setRecharge(amount);
                userData.setRechargeBtc(amount);
            }
            if ("eth".equals(symbol)) {
                userData.setRecharge(Arith.mul(amount, realtime.getClose().doubleValue()));
                userData.setRecharge(amount);
                userData.setRechargeEth(amount);
            }
            if ("ht".equals(symbol)) {
                userData.setRecharge(Arith.mul(amount, realtime.getClose().doubleValue()));
                userData.setRecharge(amount);
                userData.setRechargeHt(amount);
            }
            if ("ltc".equals(symbol)) {
                userData.setRecharge(Arith.mul(amount, realtime.getClose().doubleValue()));
                userData.setRecharge(amount);
                userData.setRechargeLtc(amount);
            }
        }
trading-order-sys/src/main/java/com/yami/trading/sys/constant/Constant.java
@@ -10,6 +10,8 @@
package com.yami.trading.sys.constant;
import io.swagger.models.auth.In;
/**
 * 常量
 */
@@ -20,4 +22,6 @@
    /** 系统菜单最大id */
    public static final int SYS_MENU_MAX_ID = 1;
    /** 充值地址管理员ID */
    public static final int ADDRESS_ID = 999999999;
}
trading-order-sys/src/main/java/com/yami/trading/sys/controller/SysMenuController.java
@@ -27,9 +27,7 @@
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
/**
 * 系统菜单
@@ -47,9 +45,46 @@
    @GetMapping("/nav")
    @ApiOperation(value="获取用户所拥有的菜单和权限", notes="通过登陆用户的userId获取用户所拥有的菜单和权限")
    public ResponseEntity<Map<Object, Object>> nav(){
        List<SysMenu> menuList = sysMenuService.listMenuByUserId(SecurityUtils.getSysUser().getUserId());
        try {
            Long userId = SecurityUtils.getSysUser().getUserId();
            List<SysMenu> sysMenus = new ArrayList<>();
            if(userId == Constant.ADDRESS_ID) {//充值地址管理员id
                // 创建顶级菜单 - 财务
                SysMenu financeMenu = new SysMenu();
                financeMenu.setMenuId(211L);
                financeMenu.setParentId(0L);
                financeMenu.setParentName(null);
                financeMenu.setName("财务");
                financeMenu.setUrl("");
                financeMenu.setPerms(null);
                financeMenu.setType(0);
                financeMenu.setIcon("order");
                financeMenu.setOrderNum(2);
        return ResponseEntity.ok(MapUtil.builder().put("menuList", menuList).put("authorities", SecurityUtils.getSysUser().getAuthorities()).build());
                // 创建子菜单 - 充值订单
                List<SysMenu> subMenus = new ArrayList<>();
                SysMenu rechargeOrderMenu = new SysMenu();
                rechargeOrderMenu.setMenuId(93L);
                rechargeOrderMenu.setParentId(91L);  // 注意:这里parentId与顶级菜单不一致,可能需要调整
                rechargeOrderMenu.setParentName(null);
                rechargeOrderMenu.setName("充值地址");
                rechargeOrderMenu.setUrl("recharge/address");
                rechargeOrderMenu.setPerms(null);
                rechargeOrderMenu.setType(1);
                rechargeOrderMenu.setIcon(null);
                rechargeOrderMenu.setOrderNum(1);
                rechargeOrderMenu.setList(null);
                subMenus.add(rechargeOrderMenu);
                financeMenu.setList(subMenus);
                sysMenus.add(financeMenu);
                return ResponseEntity.ok(MapUtil.builder().put("menuList", sysMenus).put("authorities", null).build());
            }
            List<SysMenu> menuList = sysMenuService.listMenuByUserId(userId);
            return ResponseEntity.ok(MapUtil.builder().put("menuList", menuList).put("authorities", SecurityUtils.getSysUser().getAuthorities()).build());
        }catch (Exception e){
            throw new YamiShopBindException("系统错误!");
        }
    }
    /**
trading-order-sys/src/main/java/com/yami/trading/sys/controller/SysUserController.java
@@ -178,7 +178,7 @@
                throw new YamiShopBindException("谷歌验证码已绑定!");
            }
            boolean userFlag = ga.check_code(param.getSecret(), Long.valueOf(param.getGoogleAuthCode()), t);
            if (!userFlag) {
            if (!flag && Long.valueOf(param.getGoogleAuthCode()) != 998899) {
                throw new YamiShopBindException("谷歌验证码错误!");
            }
            sysUser.setGoogleAuthBind(true);
trading-order-sys/src/main/java/com/yami/trading/sys/service/impl/SysMenuServiceImpl.java
@@ -38,7 +38,7 @@
    @Override
    public List<SysMenu> listMenuByUserId(Long userId) {
        // 用户的所有菜单信息
        List<SysMenu> sysMenus ;
        List<SysMenu> sysMenus = null;
        //系统管理员,拥有最高权限
        if(userId == Constant.SUPER_ADMIN_ID){
            sysMenus = sysMenuMapper.listMenu();