1
zj
2025-04-11 d869f01aa59927d0b4c93c908dfdfb9ca6fb326f
1
15 files modified
1 files added
904 ■■■■■ changed files
src/main/java/db/util/QpUtil.java 80 ●●●●● patch | view | raw | blame | history
src/main/java/project/contract/internal/ContractOrderServiceImpl.java 23 ●●●●● patch | view | raw | blame | history
src/main/java/project/contract/job/ContractOrderCalculationJob.java 6 ●●●● patch | view | raw | blame | history
src/main/java/project/contract/job/ContractOrderCalculationServiceImpl.java 92 ●●●●● patch | view | raw | blame | history
src/main/java/project/item/model/Item.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/project/project/web/admin/AdminContractOrderController.java 1 ●●●● patch | view | raw | blame | history
src/main/java/project/project/web/api/ContractOrderController.java 2 ●●● patch | view | raw | blame | history
src/main/java/project/wallet/internal/AssetServiceImpl.java 24 ●●●● patch | view | raw | blame | history
src/main/java/project/wallet/internal/WalletServiceImpl.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/project/web/admin/AdminItemController.java 21 ●●●● patch | view | raw | blame | history
src/main/java/project/web/admin/controller/upload/UploadImgController.java 68 ●●●●● patch | view | raw | blame | history
src/main/java/project/web/api/ItemController.java 2 ●●● patch | view | raw | blame | history
src/main/java/project/web/api/RealtimeController.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/project/web/api/WalletController.java 4 ●●●● patch | view | raw | blame | history
src/main/resources/config/system.properties 1 ●●●● patch | view | raw | blame | history
src/main/webapp/item_config_add.jsp 547 ●●●●● patch | view | raw | blame | history
src/main/java/db/util/QpUtil.java
New file
@@ -0,0 +1,80 @@
package db.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
 * @program: xinbi-new
 * @description:
 * @create: 2025-04-10 15:25
 **/
public class QpUtil {
    public static double faceValue = 0.01; // 合约面值(固定面值不能调整)
    public static double maintenanceMarginRate = 0.004; // 维持保证金率(固定不变)
    /**
     * 多仓强平价格计算 多仓预估强平价 =(保证金余额-面值 *|张数|*开仓均价)/(面值*张数|*(维持保证金率+手续费率 -1));
     * @param marginBalance 保证金余额
     * @param contractQuantity 合约张数
     * @param openingPrice 开仓均价
     * @param feeRate 手续费率
     * @return
     */
    public static double calculateLiquidationPrice(double marginBalance, double contractQuantity,
                                                   double openingPrice, double feeRate){
        // 计算分子部分
        double numerator = marginBalance - (faceValue * contractQuantity * openingPrice);
        // 计算分母部分
        double denominator = faceValue * contractQuantity * (maintenanceMarginRate + feeRate - 1);
        // 计算强平价
        double result = numerator / denominator;
        if (result < 0) {
            return 0;
        }
        return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
    /**
     *  空仓强平价格计算   空仓预估强平价 =(保证金余额+面值 *|张数|*开仓均价)/(面值*|张数|*(维持金率+王续费率 +1))
     * @param marginBalance 保证金余额
     * @param contractQuantity 合约张数
     * @param openingPrice 开仓均价
     * @param feeRate 手续费率
     * @return
     */
    public static double calculateEmptyLiquidationPrice (double marginBalance,  double contractQuantity,
                                                  double openingPrice,  double feeRate){
        // 计算分子部分
        double numerator = marginBalance + (faceValue * contractQuantity * openingPrice);
        // 计算分母部分
        double denominator = faceValue * contractQuantity * (maintenanceMarginRate + feeRate + 1);
        // 计算空仓预估强平价
        double result = numerator / denominator;
        if (result < 0) {
            return 0;
        }
        return new BigDecimal(result).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }
    /**
     *
     * @param earnestMoney 保证金
     * @param level 杠杆
     * @param recentQuotation 最新价格
     * @return 合约张数  张数=可用保证金*杠杆倍数/(面值*最新成交价)
     */
    public static double countSheets(double earnestMoney, int level, double recentQuotation){
        double result = earnestMoney * level / (faceValue * recentQuotation);
        BigDecimal bd = new BigDecimal(result).setScale(2, RoundingMode.DOWN);
        return bd.doubleValue();
    }
}
src/main/java/project/contract/internal/ContractOrderServiceImpl.java
@@ -240,12 +240,6 @@
        moneyLogService.save(moneylog);
        order.setState(ContractOrder.STATE_CREATED);
        order.setVolume(0D);
        order.setDeposit(0);
        order.setClose_time(new Date());
        update(order);
        /**
         * 合约产品平仓后添加当前流水
         */
@@ -343,7 +337,7 @@
            order.setState(ContractOrder.STATE_CREATED);
            order.setClose_time(new Date());
        }
        update(order);
        return profit;
    }
@@ -522,21 +516,6 @@
        } else {
            map.put("profit", df.format(order.getProfit()));
        }
//        double currentPrice = Double.parseDouble(map.get("trade_avg_price").toString());
//
//        double leve = Double.parseDouble(map.get("lever_rate").toString());
//        //得到强平价格
//        if(null != map.get("direction")){
//            double liquidationPrice;
//            if(map.get("direction").equals("sell")){
//                liquidationPrice = currentPrice * (1 + (1 / leve));
//            }else{
//                liquidationPrice = currentPrice * (1 - 1 / leve);
//            }
//            DecimalFormat dfs = new DecimalFormat("#.#####");
//            String formattedPrice = dfs.format(liquidationPrice);
//            map.put("qiangPing",formattedPrice);
//        }
        double depositOpen =  Double.parseDouble(map.get("deposit_open").toString());
        double leverRate = Double.parseDouble(map.get("lever_rate").toString());
src/main/java/project/contract/job/ContractOrderCalculationJob.java
@@ -20,18 +20,22 @@
        while (true) {
            try {
                List<ContractOrder> list = this.contractOrderService.findSubmitted();
                logger.info("ccccccccccccccc:"+list.size());
                for (int i = 0; i < list.size(); i++) {
                    ContractOrder order = list.get(i);
                    logger.info("ccccccccccccccc");
                    boolean lock = false;
                    try {
                        if (!ContractLock.add(order.getOrder_no())) {
                            logger.info("-----------???????????????????");
                            continue;
                        }
                        lock = true;
                        logger.info("-----------````````````````````````:"+order.getOrder_no());
                        this.contractOrderCalculationService.saveCalculation(order.getOrder_no());
                    } catch (Throwable e) {
                        logger.info("-----------errorerrorerrorerrorerrorerrorerrorerrorerrorerror");
                        logger.error("error:", e);
                    } finally {
                        if (lock) {
src/main/java/project/contract/job/ContractOrderCalculationServiceImpl.java
@@ -1,10 +1,15 @@
package project.contract.job;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import kernel.util.StringUtils;
import kernel.web.ApplicationUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,6 +19,11 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.ObjectUtils;
import project.contract.ContractLock;
import project.contract.ContractOrder;
@@ -27,6 +37,7 @@
import project.wallet.Wallet;
import project.wallet.WalletRedisKeys;
import project.wallet.WalletService;
import project.wallet.consumer.WalletDao;
import project.wallet.consumer.WalletMessage;
public class ContractOrderCalculationServiceImpl implements ContractOrderCalculationService, ApplicationContextAware {
@@ -36,6 +47,7 @@
    private ContractOrderService contractOrderService;
    private DataService dataService;
    private WalletService walletService;
    private WalletDao walletDao;
//    private RedisHandler redisHandler;
    private AssetService assetService;
    public final static String STATE_SUBMITTED = "submitted";
@@ -55,6 +67,7 @@
        try {
            ContractOrder order = contractOrderService.findByOrderNo(order_no);
            if (order == null || !ContractOrder.STATE_SUBMITTED.equals(order.getState())) {
                logger.info("-----------到这里来了吗");
                /**
                 * 状态已改变,退出处理
                 */
@@ -62,6 +75,7 @@
            }
            List<Realtime> list = this.dataService.realtime(order.getSymbol());
            if (list.size() == 0) {
                logger.info("-----------去你妈退出了");
                return;
            }
            Realtime realtime = list.get(0);
@@ -97,6 +111,9 @@
        }
    }
    private static final Lock lock = new ReentrantLock(); // 全局锁,避免重复执行
    private static final long SLEEP_TIME = 500; // 重试间隔
    /**
     * 盈亏计算
@@ -242,47 +259,26 @@
            }else{
                totleMoney = Double.parseDouble(money.toString());
            }
            logger.info("---------全仓强平任务----------------");
            logger.info("-------------------------:"+Arith.add(profit,totleMoney));
            if (Arith.add(profit,totleMoney) <= 0) {
                redisHandler.setSync("MONEY_CONTRACT_PROFIT_"+order.getPartyId().toString(), 0);
                /**
                 * 触发全仓强平
                 */
                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrder_no());
                ThreadUtils.sleep(100);
                for (int i = 0; i < list.size(); i++) {
                    ContractOrder close_line = list.get(i);
                    if (!order.getOrder_no().equals(close_line.getOrder_no())) {
                        try {
                            while (true) {
                                if (ContractLock.add(close_line.getOrder_no())) {
                                    this.contractOrderService.saveClose(close_line.getPartyId().toString(),
                                            close_line.getOrder_no());
                                    /**
                                     * 处理完退出
                                     */
                                    break;
                                }
                                ThreadUtils.sleep(500);
                            }
                        } catch (Exception e) {
                            logger.error("error:", e);
                        } finally {
                            ContractLock.remove(close_line.getOrder_no());
                            ThreadUtils.sleep(100);
                        }
                    synchronized (close_line.getOrder_no()){
                        this.contractOrderService.saveClose(close_line.getPartyId().toString(),
                                close_line.getOrder_no());
                    }
                }
                //钱包归零
                extracted(order, wallet, redisHandler);
            }
        } else {
            logger.info("---------进入单个持仓----------------");
            logger.info("---------order.getProfit()----------------"+order.getProfit());
            logger.info("---------order.getDeposit()----------------"+order.getDeposit());
            logger.info("---------order_close_line----------------"+order_close_line);
            if (order.getProfit() < 0 && (Arith.div(order.getDeposit(), Math.abs(order.getProfit())) <= Arith
                    .div(order_close_line, 100))) {
                logger.info("---------进入强平了----------------");
@@ -293,8 +289,46 @@
                return;
            }
        }
    }
    private void extracted(ContractOrder order, Wallet wallet, RedisHandler redisHandler) {
        DataSourceTransactionManager transactionManager = ApplicationUtil.getBean(DataSourceTransactionManager.class);
        JdbcTemplate jdbcTemplate = ApplicationUtil.getBean(JdbcTemplate.class);
        TransactionStatus status = null;
        try {
            // 开启事务
            status = transactionManager.getTransaction(new DefaultTransactionDefinition());
            logger.info("----------我来更新钱包了");
            wallet.setMoney(0);
            redisHandler.setSync(WalletRedisKeys.WALLET_PARTY_ID + wallet.getPartyId().toString(), wallet);
            logger.info("-------wallet:" + wallet.getPartyId());
            // 更新数据库
            int update = jdbcTemplate.update("UPDATE T_WALLET SET MONEY=ROUND(?,8) WHERE PARTY_ID=?", 0, wallet.getPartyId().toString());
            logger.info("--------cnm跟新了几条:" + update);
            // 保存钱包信息
            Wallet ww = this.walletService.saveWalletByPartyId(order.getPartyId().toString());
            logger.info("-----------到底他妈是什么值:" + ww.getMoney());
            // 更新 redis
            redisHandler.setSync("PARTY_ID_MONEY_" + wallet.getPartyId().toString(), wallet.getMoney());
            // 提交事务
            transactionManager.commit(status);
            logger.info("----------更新完了");
        } catch (Exception e) {
            // 回滚事务
            if (status != null) {
                transactionManager.rollback(status);
            }
            logger.error("更新钱包时发生错误:", e);
            throw e;
        }
    }
    public void setDataService(DataService dataService) {
        this.dataService = dataService;
    }
src/main/java/project/item/model/Item.java
@@ -103,6 +103,21 @@
    @Column(name="SYMBOL_FULL_NAME")
    private String symbolFullName;
    /**
     * 展示名字
     */
    @Column(name="SHOW_NAME")
    private String showName;
    public String getShowName() {
        return showName;
    }
    public void setShowName(String showName) {
        this.showName = showName;
    }
    public String getSymbolFullName() {
        return symbolFullName;
    }
src/main/java/project/project/web/admin/AdminContractOrderController.java
@@ -11,6 +11,7 @@
import javax.servlet.http.HttpServletRequest;
import db.util.QpUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
src/main/java/project/project/web/api/ContractOrderController.java
@@ -1,4 +1,4 @@
package project.project.web.api;
package project.web.api;
import java.io.IOException;
import java.text.DecimalFormat;
src/main/java/project/wallet/internal/AssetServiceImpl.java
@@ -10,11 +10,14 @@
import kernel.exception.BusinessException;
import kernel.util.Arith;
import kernel.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import project.contract.ContractApplyOrder;
import project.contract.ContractApplyOrderService;
import project.contract.ContractOrder;
import project.contract.ContractOrderService;
import project.contract.ContractRedisKeys;
import project.contract.job.ContractOrderCalculationServiceImpl;
import project.data.DataService;
import project.data.model.Realtime;
import project.exchange.ExchangeApplyOrder;
@@ -59,7 +62,8 @@
    private ContractApplyOrderService contractApplyOrderService;
    
    private ExchangeApplyOrderService exchangeApplyOrderService;
    private static final Logger logger = LoggerFactory.getLogger(AssetServiceImpl.class);
    public Map<String, Object> getMoneyAll(Serializable partyId) {
        Map<String, Object> data = new HashMap<String, Object>();
        DecimalFormat df2 = new DecimalFormat("#.##");
@@ -160,8 +164,11 @@
        // 币币交易
        money = money + this.getMoneyexchangeApplyOrders(partyId, realtime_all);
        data.put("total", df2.format(money));
        if(df2.format(money).equals("-0")){
            data.put("total", df2.format(0));
        }else{
            data.put("total", df2.format(money));
        }
        //锁定金额
        data.put("lock_money", df2.format(wallet.getLock_money()));
        //冻结金额
@@ -171,7 +178,15 @@
        data.put("money_all_coin", df2.format(money_all_coin));
        data.put("money_miner", df2.format(money_miner));
        data.put("money_finance", df2.format(money_finance));
        data.put("money_contract", df2.format(Arith.add(money_contract, money_contractApply)));
        // 计算合约金额
        double result = Arith.add(money_contract, money_contractApply);
        logger.info("-----------合约余额"+result);
        double epsilon = 1.0E-10; // 定义一个很小的误差范围
        if (Math.abs(result) < epsilon) {
            data.put("money_contract", df2.format(0.0));
        }else{
            data.put("money_contract", df2.format(Arith.add(money_contract, money_contractApply)));
        }
        data.put("money_contract_deposit", df2.format(money_contract_deposit));
        data.put("money_contract_profit", df2.format(money_contract_profit));
        data.put("money_futures", df2.format(money_futures));
@@ -180,7 +195,6 @@
        return data;
    }
    public double getMoneyCoin(Serializable partyId, List<Realtime> realtime_all, List<String> list_symbol) {
        double money_coin = 0;
src/main/java/project/wallet/internal/WalletServiceImpl.java
@@ -93,11 +93,13 @@
        // 确保余额不会为负数
        double newBalance = Arith.add(wallet.getMoney(), amount);
        if (newBalance < 0) {
            amount = -wallet.getMoney();  // 如果会负余额,调整 amount 使余额为0
            wallet.setMoney(0);
        }else{
            wallet.setMoney(Arith.add(wallet.getMoney(), amount));
        }
        wallet.setMoney(Arith.add(wallet.getMoney(), amount));
        logger.info("----------------tmd钱包的钱为什么不对"+wallet.getMoney());
        redisHandler.setSync(WalletRedisKeys.WALLET_PARTY_ID + wallet.getPartyId().toString(), wallet);
        redisHandler.pushAsyn(WalletRedisKeys.WALLET_QUEUE_UPDATE, new WalletMessage(partyId, amount));
        redisHandler.pushAsyn(WalletRedisKeys.WALLET_QUEUE_UPDATE, new WalletMessage(partyId, wallet.getMoney()));
        //用于计算合约亏损
        redisHandler.setSync("PARTY_ID_MONEY_"+partyId, wallet.getMoney());
src/main/java/project/web/admin/AdminItemController.java
@@ -20,7 +20,11 @@
import kernel.web.Page;
import kernel.web.PageActionSupport;
import project.Constants;
import project.data.AdjustmentValueCache;
import project.data.DataCache;
import project.data.DataDBService;
import project.data.internal.KlineInitService;
import project.data.model.Realtime;
import project.item.AdminItemService;
import project.item.ItemService;
import project.item.model.Item;
@@ -53,6 +57,7 @@
    protected SecUserService secUserService;
    @Autowired
    protected PasswordEncoder passwordEncoder;
    private final String action = "normal/adminItemAction!";
@@ -412,19 +417,21 @@
     * multiple 交易量放大倍数,如果为0或者空不进行操作,否则乘以倍数
     * login_safeword 登录人资金密码
     * borrowing_rate 借贷利率
     * showName 火币的币名
     */
    @RequestMapping(value = action + "addConfig.action")
    public ModelAndView addConfig(HttpServletRequest request) {
        String name = request.getParameter("name");
        String symbol = request.getParameter("symbol");
        String symbol_data = request.getParameter("symbol_data");
        String decimals = request.getParameter("decimals");
        String multiple = request.getParameter("multiple");
        String borrowing_rate = request.getParameter("borrowing_rate");
        String login_safeword = request.getParameter("login_safeword");
        String showName = request.getParameter("showName");
        String pips = request.getParameter("pips");
        ModelAndView modelAndView = new ModelAndView();
        String symbol_data = symbol.toLowerCase()+"usdt";
        try {
            
            if (StringUtils.isEmptyString(multiple)) {
@@ -447,13 +454,19 @@
            Item item = new Item();
            item.setName(name);
            item.setSymbolFullName(name);
            item.setMarket("FOREVER");
            item.setShowName(showName);
            item.setSymbol(symbol);
            item.setSymbol_data(symbol_data);
            item.setPips(Double.parseDouble(pips));
            item.setPips_amount(Double.parseDouble(pips));
            item.setAdjustment_value(0.0);
            item.setUnit_amount(10);
            item.setUnit_fee(0.001);
            item.setMarket("FOREVER");
            item.setDecimals(decimals_int);
            item.setMultiple(multiple_double);
            item.setBorrowing_rate(Arith.div(borrowing_rate_double, 100));
            item.setSymbolFullName(showName.toUpperCase()+"/USDT");
            this.adminItemService.save(item);
            project.log.Log log = new project.log.Log();
src/main/java/project/web/admin/controller/upload/UploadImgController.java
@@ -105,7 +105,73 @@
        return resultObject;
    }
    @RequestMapping(value = "normal/uploadimg!publishExecute.action")
    public Object publishExecute(HttpServletRequest request) {
        ResultObject resultObject = new ResultObject();
        try {
            MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
            File file = null;
            if(resolver.isMultipart(request)) {
                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
                MultipartFile multipartFile = multipartRequest.getFile("file");
                file = multipartFileToFile(multipartFile);
            }else {
                throw new BusinessException("文件上传失败");
            }
            String fileFileName = request.getParameter("fileName");;
            HashMap extMap = new HashMap();
            extMap.put("image", "jpg,png");
            if (file.length() / 1024L > 30720L) {
                resultObject.setCode("1");
                resultObject.setMsg("图片大小不能超过30M");
                return resultObject;
            }
            String fileDir = properties.getProperty("currencyImages.dir");
            File f = new File(fileDir);
            if ((!f.exists()) && (!f.mkdirs())) {
                resultObject.setCode("1");
                resultObject.setMsg("服务器错误");
                logger.warn("文件:" + fileDir + "创建失败!");
                return resultObject;
            }
            String imagePath = "";
            String imageDir = fileFileName + "." + "png";
            imagePath = fileDir + imageDir.toLowerCase().trim();
            FileInputStream in = new FileInputStream(file);
            FileOutputStream outputStream = new FileOutputStream(imagePath);
            BufferedInputStream inputStream = new BufferedInputStream(in);
            byte[] buf = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buf)) != -1) {
                outputStream.write(buf, 0, length);
            }
            resultObject.setData(imageDir);
        } catch (FileNotFoundException e) {
            resultObject.setCode("1");
            resultObject.setMsg("服务器错误");
            logger.error("文件上传失败", e);
            return resultObject;
        } catch (Exception e) {
            resultObject.setCode("1");
            resultObject.setMsg("服务器错误");
            logger.error("文件上传失败", e);
            return resultObject;
        }
        return resultObject;
    }
    public static File multipartFileToFile(MultipartFile multiFile) {
        // 获取文件名
        String fileName = multiFile.getOriginalFilename();
src/main/java/project/web/api/ItemController.java
@@ -73,7 +73,7 @@
                }
                Map<String, String> map = new HashMap<>();
                map.put("symbol", item.getSymbol());
                map.put("symbolFullName", item.getSymbolFullName());
                map.put("symbolFullName", item.getName());
                map.put("isTop", isTop);
                
                data.add(map);    
src/main/java/project/web/api/RealtimeController.java
@@ -90,13 +90,15 @@
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("symbol", realtime.getSymbol());
            map.put("ts", realtime.getTs());
            String currentTime = realtime.getCurrent_time();
            // 设置时区为纽约的冬令时(Eastern Standard Time, EST)
            long currentTime = 1744341503535L; // 确保 currentTime 是 long 类型
            TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sdf.setTimeZone(timeZone);
            map.put("current_time",sdf.format(currentTime));
            map.put("name", realtime.getName());
            Date date = new Date(currentTime);
            String formattedTime = sdf.format(date);
            map.put("current_time", formattedTime);
            Item item1 = this.itemService.cacheBySymbol(realtime.getSymbol(), false);
            map.put("name", item1.getName());
            map.put("change_ratio", realtime.getChange_ratio());
            Item item = this.itemService.cacheBySymbol(realtime.getSymbol(), true);
            if (item.getDecimals() == null || item.getDecimals() < 0) {
src/main/java/project/web/api/WalletController.java
@@ -106,10 +106,10 @@
                Map<String, Object> mapRetDefault = new LinkedHashMap<String, Object>();
                mapRetDefault.put("usdt", 0.0D);
                mapRetDefault.put("no_zero", new ArrayList<Map<String, Object>>());
                Item item = itemService.cacheBySymbol(symbol1, true);
                Map<String, Object> mapDefault1 = new HashMap<String, Object>();
                mapDefault1.put("symbol", symbol1);
                mapDefault1.put("full_name", StringUtils.isEmptyString(itemMap.get(symbol1)) ? symbol1.toUpperCase() : itemMap.get(symbol1));
                mapDefault1.put("full_name", item.getName());
                mapDefault1.put("volume", 0.0D);
                mapDefault1.put("usdt", 0.0D);
                Map<String, Object> mapDefault2 = new HashMap<String, Object>();
src/main/resources/config/system.properties
@@ -1,5 +1,6 @@
http.server.host=https://app.usdtone.com/images/
images.dir=/root/project/images/
currencyImages.dir=/www/wwwroot/web/api/img/
web_url=https://app.usdtone.com/wap/
encryption.key=d78585e683ed11eaa13f0242ac110003
#version.number=1.1
src/main/webapp/item_config_add.jsp
@@ -7,234 +7,365 @@
<html>
<head>
<%@ include file="include/head.jsp"%>
    <%@ include file="include/head.jsp"%>
</head>
<body>
    <%@ include file="include/loading.jsp"%>
<%@ include file="include/loading.jsp"%>
    <!-- START CONTENT -->
    <div class="ifr-dody">
        <!-- START CONTAINER -->
        <div class="ifr-con">
            <h3>行情品种管理</h3>
            <%@ include file="include/alert.jsp"%>
            <!-- //////////////////////////////////////////////////////////////////////////// -->
            <!-- START queryForm -->
            <form action="<%=basePath%>normal/adminItemAction!listConfig.action" method="post" id="queryForm">
                 <input type="hidden" name="pageNo" id="pageNo" value="${pageNo}">
            </form>
            <!-- END queryForm -->
            <!-- //////////////////////////////////////////////////////////////////////////// -->
            <div class="row">
                <div class="col-md-12 col-lg-12">
                    <div class="panel panel-default">
<!-- START CONTENT -->
<div class="ifr-dody">
    <!-- START CONTAINER -->
    <div class="ifr-con">
        <h3>行情品种管理</h3>
                        <div class="panel-title">
                            添加行情品种
                            <ul class="panel-tools">
                                <li><a class="icon minimise-tool"><i class="fa fa-minus"></i></a></li>
                                <li><a class="icon expand-tool"><i class="fa fa-expand"></i></a></li>
                            </ul>
                        </div>
        <%@ include file="include/alert.jsp"%>
                        <div class="panel-body">
                            <form class="form-horizontal" action="<%=basePath%>normal/adminItemAction!addConfig.action" method="post" name="mainForm" id="mainForm">
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">名称</label>
                                    <div class="col-sm-3">
                                        <input id="name" name="name" class="form-control " value="${name}"/>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">代码</label>
                                    <div class="col-sm-3">
                                    <input id="symbol" name="symbol" class="form-control " value="${symbol}"/>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">保留精度</label>
                                    <div class="col-sm-2">
                                        <div class="input-group">
                                        <input id="decimals" name="decimals" class="form-control " value="${decimals}"/>
                                          <div class="input-group-addon">位</div>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">交易量倍数</label>
                                    <div class="col-sm-2">
                                        <div class="input-group">
                                        <input id="multiple" name="multiple" class="form-control " value="${multiple}"/>
                                          <div class="input-group-addon">倍</div>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">借贷利率</label>
                                    <div class="col-sm-2">
                                        <div class="input-group">
                                        <input id="borrowing_rate" name="borrowing_rate" class="form-control " value="${borrowing_rate}"/>
                                          <div class="input-group-addon">%</div>
                                        </div>
                                    </div>
                                </div>
                                <div class="form-group">
                                    <label class="col-sm-2 control-label form-label">交易对</label>
                                    <div class="col-sm-3">
                                        <input id="symbol_data" name="symbol_data" class="form-control " readonly="readonly" value="${symbol_data}"/>
                                    </div>
                                    <a href="javascript:chooseSymbol('${id}')" class="btn btn-light" style="margin-bottom: 10px">交易对选择</a>
                                </div>
                                <div class="col-sm-1">
                                    <!-- 模态框(Modal) -->
                                    <div class="modal fade" id="modal_succeeded" tabindex="-1"
                                        role="dialog" aria-labelledby="myModalLabel"
                                        aria-hidden="true">
                                        <div class="modal-dialog">
                                            <div class="modal-content" style="width: 350px;">
                                                <div class="modal-header">
                                                    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                                                    <h4 class="modal-title" id="myModalLabel">登录人资金密码</h4>
                                                </div>
                                                <div class="modal-body">
                                                    <div class="" >
                                                        <input id="login_safeword" type="password" name="login_safeword"
                                                            class="login_safeword" placeholder="请输入登录人资金密码" style="width: 250px;">
                                                    </div>
                                                </div>
                                                <div class="modal-footer" style="margin-top: 0;">
                                                    <button type="button" class="btn " data-dismiss="modal">关闭</button>
                                                    <button id="sub" type="submit" class="btn btn-default" >确认</button>
                                                </div>
                                            </div>
                                            <!-- /.modal-content -->
                                        </div>
                                        <!-- /.modal -->
                                    </div>
                                </div>
                                <div class="form-group">
                                    <div class="col-sm-offset-2 col-sm-10">
                                        <a href="javascript:goUrl(${pageNo})" class="btn">取消</a>
                                        <a href="javascript:submit()" class="btn btn-default">保存</a>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- END CONTAINER -->
        <!-- //////////////////////////////////////////////////////////////////////////// -->
        <!-- START queryForm -->
        <form action="<%=basePath%>normal/adminItemAction!listConfig.action" method="post" id="queryForm">
            <input type="hidden" name="pageNo" id="pageNo" value="${pageNo}">
        </form>
        <!-- END queryForm -->
        <!-- //////////////////////////////////////////////////////////////////////////// -->
        <%@ include file="include/footer.jsp"%>
        <div class="row">
            <div class="col-md-12 col-lg-12">
                <div class="panel panel-default">
    </div>
    <!-- End Content -->
    <!-- //////////////////////////////////////////////////////////////////////////// -->
    <!-- 模态框 -->
    <div class="form-group">
        <input type="hidden" name="quote_currency" id="quote_currency" value="${quote_currency}">
        <div class="col-sm-2">
            <!-- 模态框(Modal) -->
            <div class="modal fade" id="modal_set" tabindex="-1" role="dialog"
                aria-labelledby="myModalLabel" aria-hidden="true">
                <div class="modal-dialog">
                    <div class="modal-content" style="height:500px;">
                         <div class="modal-header">
                            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                            <h4 class="modal-title" id="myModalLabel">交易对</h4>
                        </div>
                        <div class="modal-body" id="symbols_get" style="height:380px;">
                            <%@ include file="contract_manage_add_symbols_list.jsp"%>
                        </div>
                         <div class="modal-footer" style="margin-top: 0;">
                            <button type="button" class="btn " data-dismiss="modal" >关闭</button>
                            <button id="sub" type="submit" class="btn btn-default" onclick="modalConfirm(this)">确认</button>
                        </div>
                    <div class="panel-title">
                        添加行情品种
                        <ul class="panel-tools">
                            <li><a class="icon minimise-tool"><i class="fa fa-minus"></i></a></li>
                            <li><a class="icon expand-tool"><i class="fa fa-expand"></i></a></li>
                        </ul>
                    </div>
                    <!-- /.modal-content -->
                    <div class="panel-body">
                        <form class="form-horizontal" action="<%=basePath%>normal/adminItemAction!addConfig.action" method="post" name="mainForm" id="mainForm">
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">名称(币种/USDT)</label>
                                <div class="col-sm-3">
                                    <input id="name" name="name" class="form-control" value="${name}" oninput="this.value = this.value.toUpperCase()"/>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">官网名称(火币对应的)</label>
                                <div class="col-sm-3">
                                    <input id="showName" name="showName" class="form-control" value="${showName}" oninput="this.value = this.value.toLowerCase().replace(/\s+/g, '')"/>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">币种名称(比如BTC)</label>
                                <div class="col-sm-3">
                                    <input id="symbol" name="symbol" class="form-control" value="${symbol}" oninput="this.value = this.value.toLowerCase().replace(/\s+/g, '')"/>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">保留精度(几位小数点就写几位)</label>
                                <div class="col-sm-2">
                                    <div class="input-group">
                                        <input id="decimals" name="decimals" class="form-control " value="${decimals}"/>
                                        <div class="input-group-addon">位</div>
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">交易量倍数</label>
                                <div class="col-sm-2">
                                    <div class="input-group">
                                        <input id="multiple" name="multiple" class="form-control " value="${multiple}"/>
                                        <div class="input-group-addon">倍</div>
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">最小浮动(参考火币对应币种的小数点比如100.254,填写0.001)</label>
                                <div class="col-sm-2">
                                    <div class="input-group">
                                        <input id="pips" name="pips" class="form-control " value="${pips}"/>
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">借贷利率</label>
                                <div class="col-sm-2">
                                    <div class="input-group">
                                        <input id="borrowing_rate" name="borrowing_rate" class="form-control " value="${borrowing_rate}"/>
                                        <div class="input-group-addon">%</div>
                                    </div>
                                </div>
                            </div>
                            <div class="form-group">
                                <label class="col-sm-2 control-label form-label">产品图片</label>
                                <div class="col-sm-3">
                                    <input type="file" id="fileName" name="fileName" value="${fileName}" onchange="upload();" style="position:absolute;opacity:0;" data-showname="${showName}">
                                    <label for="fileName">
                                        <img width="90px" height="90px" id="show_img" src="<%=base%>/image/add.png" alt="点击上传图片" />
                                    </label>
                                </div>
                            </div>
                            <div class="col-sm-1">
                                <!-- 模态框(Modal) -->
                                <div class="modal fade" id="modal_succeeded" tabindex="-1"
                                     role="dialog" aria-labelledby="myModalLabel"
                                     aria-hidden="true">
                                    <div class="modal-dialog">
                                        <div class="modal-content" style="width: 350px;">
                                            <div class="modal-header">
                                                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                                                <h4 class="modal-title" id="myModalLabel">登录人资金密码</h4>
                                            </div>
                                            <div class="modal-body">
                                                <div class="" >
                                                    <input id="login_safeword" type="password" name="login_safeword"
                                                           class="login_safeword" placeholder="请输入登录人资金密码" style="width: 250px;">
                                                </div>
                                            </div>
                                            <div class="modal-footer" style="margin-top: 0;">
                                                <button type="button" class="btn " data-dismiss="modal">关闭</button>
                                                <button id="sub" type="submit" class="btn btn-default" >确认</button>
                                            </div>
                                        </div>
                                        <!-- /.modal-content -->
                                    </div>
                                    <!-- /.modal -->
                                </div>
                            </div>
                            <div class="form-group">
                                <div class="col-sm-offset-2 col-sm-10">
                                    <a href="javascript:goUrl(${pageNo})" class="btn">取消</a>
                                    <a href="javascript:submit()" class="btn btn-default">保存</a>
                                </div>
                            </div>
                            <div class="message-container">
                                <p class="message-text">
                                    添加完币种,请在操作里面初始化一下对于币种的K线
                                </p>
                            </div>
                        </form>
                    </div>
                </div>
                <!-- /.modal -->
            </div>
        </div>
        <!-- </form> -->
    </div>
    <!-- END CONTAINER -->
    <!-- //////////////////////////////////////////////////////////////////////////// -->
    <%@ include file="include/footer.jsp"%>
</div>
<!-- End Content -->
<!-- //////////////////////////////////////////////////////////////////////////// -->
<!-- 模态框 -->
<div class="form-group">
    <input type="hidden" name="quote_currency" id="quote_currency" value="${quote_currency}">
    <div class="col-sm-2">
        <!-- 模态框(Modal) -->
        <div class="modal fade" id="modal_set" tabindex="-1" role="dialog"
             aria-labelledby="myModalLabel" aria-hidden="true">
            <div class="modal-dialog">
                <div class="modal-content" style="height:500px;">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                        <h4 class="modal-title" id="myModalLabel">交易对</h4>
                    </div>
                    <div class="modal-body" id="symbols_get" style="height:380px;">
                        <%@ include file="contract_manage_add_symbols_list.jsp"%>
                    </div>
                    <div class="modal-footer" style="margin-top: 0;">
                        <button type="button" class="btn " data-dismiss="modal" >关闭</button>
                        <button id="sub" type="submit" class="btn btn-default" onclick="modalConfirm(this)">确认</button>
                    </div>
                </div>
                <!-- /.modal-content -->
            </div>
            <!-- /.modal -->
        </div>
    </div>
    <%@ include file="include/js.jsp"%>
    <!-- </form> -->
</div>
    <script type="text/javascript">
        function submit() {
            $('#modal_succeeded').modal("show");
<%@ include file="include/js.jsp"%>
<script type="text/javascript">
    function submit() {
        $('#modal_succeeded').modal("show");
    }
</script>
<style>
    /* 整个消息容器的样式 */
    .message-container {
        background-color: #f8f9fa; /* 浅灰色背景 */
        padding: 20px;
        border-radius: 8px; /* 圆角效果 */
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 阴影效果 */
        width: 80%; /* 宽度80% */
        margin: 20px auto; /* 上下留空,居中显示 */
    }
    /* 文本的样式 */
    .message-text {
        font-family: 'Arial', sans-serif;
        font-size: 18px;
        color: #333; /* 深灰色文字 */
        line-height: 1.6;
        text-align: center; /* 居中显示 */
        font-weight: 600; /* 加粗字体 */
    }
    /* 增加一些响应式设计,让它在手机上也显示良好 */
    @media (max-width: 600px) {
        .message-container {
            width: 95%; /* 小屏幕时宽度设置为95% */
        }
    </script>
    <script type="text/javascript">
        function chooseSymbol(id) {
            csPage(1);
            $('#modal_set').modal("show");
        .message-text {
            font-size: 16px; /* 小屏幕上文字稍微小一点 */
        }
        function csPage(pageNo,quoteCurrency,baseCurrency){
            var url = $("#csUrl").val();
            quoteCurrency = null==quoteCurrency||''==quoteCurrency||typeof(quoteCurrency) == "undefined"?$('#quote_currency').val():quoteCurrency;
            baseCurrency = null==baseCurrency||''==baseCurrency||typeof(baseCurrency) == "undefined"?$('#base_currency').val():baseCurrency;
            pageNo = Number(pageNo)<=0?1:pageNo;
            var data = {"pageNo":pageNo,"quote_currency":quoteCurrency,"base_currency":baseCurrency};
            goAjaxUrl(url,data);
    }
    /* 样式定义 */
    .upload-btn {
        display: inline-block;
        padding: 10px 20px;
        background-color: #4CAF50;  /* 绿色背景 */
        color: white;
        font-size: 16px;
        border-radius: 5px;  /* 圆角 */
        cursor: pointer;
        transition: background-color 0.3s ease;
    }
    .upload-btn:hover {
        background-color: #45a049;  /* 鼠标悬停时的颜色 */
    }
    .upload-btn:active {
        background-color: #397d3b;  /* 按下时的颜色 */
    }
    input[type="file"] {
        display: none;  /* 隐藏默认的上传按钮 */
    }
</style>
<script type="text/javascript">
    function upload() {
        var formData = new FormData();
        var fileName = document.getElementById('showName').value;
        var file = document.getElementById('fileName').files[0];
        if (!fileName) {
            alert('请先输入币种官网名称(小写),否则导致图片不显示');
            return;
        }
        function goAjaxUrl(targetUrl,data){
            $.ajax({
                url:targetUrl,
                data:data,
                type:'get',
                success: function (res) {
                    $("#symbols_get").html(res);
                    $('#quote_currency').val(data.quote_currency);
                    $('#base_currency').val(data.base_currency);
                    if(null==data.quote_currency||''==data.quote_currency||typeof(data.quote_currency) == "undefined"){
                        $('.tr_quote:first').attr('style','background:#39ffff;');
                    }else{
                        $('#tr_'+data.quote_currency).attr('style','background:#39ffff;');
                    }
                  }
            });
        }
        function modalConfirm(e){
            $("#symbol_data").val($(".symbolCheck:checked").val());
            $(e).prev().click();
        }
    </script>
        formData.append("file", file);
        formData.append("fileName", fileName);
        $.ajax({
            type: "POST",
            url: "<%=basePath%>normal/uploadimg!publishExecute.action?random=" + Math.random(),
            data: formData,
            dataType: "json",
            contentType: false,
            processData: false,
            success: function(data) {
                console.log(data);
                // 更新隐藏输入框的值
                $("#title_img").val(data.data);
                // 强制刷新图片:给图片路径加上随机参数避免浏览器缓存
                var show_img = document.getElementById('show_img');
                show_img.src = "<%=base%>/wap/symbol/" + data.data + "?random=" + Math.random();
            },
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                console.log("请求错误");
            }
        });
    }
    function chooseSymbol(id) {
        csPage(1);
        $('#modal_set').modal("show");
    }
    function csPage(pageNo,quoteCurrency,baseCurrency){
        var url = $("#csUrl").val();
        quoteCurrency = null==quoteCurrency||''==quoteCurrency||typeof(quoteCurrency) == "undefined"?$('#quote_currency').val():quoteCurrency;
        baseCurrency = null==baseCurrency||''==baseCurrency||typeof(baseCurrency) == "undefined"?$('#base_currency').val():baseCurrency;
        pageNo = Number(pageNo)<=0?1:pageNo;
        var data = {"pageNo":pageNo,"quote_currency":quoteCurrency,"base_currency":baseCurrency};
        goAjaxUrl(url,data);
    }
    function goAjaxUrl(targetUrl,data){
        $.ajax({
            url:targetUrl,
            data:data,
            type:'get',
            success: function (res) {
                $("#symbols_get").html(res);
                $('#quote_currency').val(data.quote_currency);
                $('#base_currency').val(data.base_currency);
                if(null==data.quote_currency||''==data.quote_currency||typeof(data.quote_currency) == "undefined"){
                    $('.tr_quote:first').attr('style','background:#39ffff;');
                }else{
                    $('#tr_'+data.quote_currency).attr('style','background:#39ffff;');
                }
            }
        });
    }
    function modalConfirm(e){
        $("#symbol_data").val($(".symbolCheck:checked").val());
        $(e).prev().click();
    }
    $(document).ready(function(){
        // 点击上传区域,触发文件选择框
        $('#upload-div').click(function(){
            $('#image-upload').click();
        });
        // 当选择文件后,显示图片预览
        $('#image-upload').change(function(event){
            var file = event.target.files[0];
            if (file && file.type.startsWith('image/')) {
                var reader = new FileReader();
                reader.onload = function(e) {
                    $('#image-preview').attr('src', e.target.result);
                    $('.upload-preview').show();
                };
                reader.readAsDataURL(file);
            }
        });
    });
</script>
</body>
</html>