From bc8766c652cbb02d5e07e3abce3400a53aaeeba2 Mon Sep 17 00:00:00 2001
From: zyy <zyy@email.com>
Date: Thu, 21 Aug 2025 18:50:41 +0800
Subject: [PATCH] 平仓返回保证金修改

---
 src/main/java/com/nq/service/impl/StockAiServiceImpl.java |  292 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 259 insertions(+), 33 deletions(-)

diff --git a/src/main/java/com/nq/service/impl/StockAiServiceImpl.java b/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
index b671859..07d4fa6 100644
--- a/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
@@ -3,13 +3,19 @@
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import com.nq.Repository.ExchangeRateRepository;
+import com.nq.common.ResponseCode;
 import com.nq.common.ServerResponse;
 import com.nq.dao.StockAiMapper;
 import com.nq.dao.StockAiOrderMapper;
+import com.nq.dao.StockAiOrderPositionMapper;
 import com.nq.enums.*;
 import com.nq.pojo.*;
 import com.nq.service.*;
+import com.nq.vo.stock.ai.StockAIOrderPositionVO;
+import com.nq.vo.stock.ai.StockAiOrderTypeVO;
+import com.nq.vo.stock.ai.StockAiOrderVO;
+import com.nq.vo.stock.ai.StockAiVO;
+import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -20,15 +26,19 @@
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 @Service("iStockAiService")
 public class StockAiServiceImpl implements IStockAiService {
     private static final Logger log = LoggerFactory.getLogger(StockAiServiceImpl.class);
+    private final ConcurrentHashMap<Long, Object> locks = new ConcurrentHashMap<>();
 
     @Autowired
     StockAiMapper stockAiMapper;
     @Autowired
     StockAiOrderMapper stockAiOrderMapper;
+    @Autowired
+    StockAiOrderPositionMapper stockAiOrderPositionMapper;
     @Autowired
     ISiteProductService iSiteProductService;
     @Autowired
@@ -36,7 +46,7 @@
     @Autowired
     IUserAssetsServices iUserAssetsServices;
     @Autowired
-    ExchangeRateRepository exchangeRateRepository;
+    private UserAssetsServices userAssetsServices;
 
     /**
      * 获取上架ai产品
@@ -45,10 +55,12 @@
      * @return
      */
     @Override
-    public ServerResponse getStockAiList(Integer pageNum, Integer pageSize) {
+    public ServerResponse getStockAiList(Integer pageNum, Integer pageSize, String stockName) {
         try {
             PageHelper.startPage(pageNum, pageSize);
-            List<StockAI> stockAiList = stockAiMapper.selectList(new QueryWrapper<StockAI>().eq("status", EStockAIStatus.online.getValue()));
+            List<StockAI> stockAiList = stockAiMapper.selectList(new QueryWrapper<StockAI>()
+                    .eq("status", EStockAIStatus.online.getValue())
+                    .eq(StringUtils.isNotBlank(stockName),"stock_name", stockName));
             // 获取分页信息
             PageInfo<StockAI> pageInfo = new PageInfo<>(stockAiList);
             return ServerResponse.createBySuccess(pageInfo);
@@ -65,14 +77,15 @@
      * @return
      */
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     public ServerResponse buyStockAi(Long id, BigDecimal buyNum, HttpServletRequest request) {
         try {
             User user = iUserService.getCurrentUser(request);
             if (user == null ){
-                return ServerResponse.createBySuccessMsg("請先登錄");
+                return ServerResponse.createByErrorCodeMsg(ResponseCode.NEED_LOGIN.getCode(),"请先登录", request);
             }
-            synchronized (user.getId()){
+            Object lock = locks.computeIfAbsent(Long.valueOf(user.getId()), k -> new Object());
+            synchronized (lock){
                 SiteProduct siteProduct = iSiteProductService.getProductSetting();
                 if (siteProduct.getRealNameDisplay() && user.getIsActive() != 2) {
                     return ServerResponse.createByErrorMsg("订单失败,请先实名认证", request);
@@ -86,24 +99,19 @@
                 if (stockAI == null) {
                     return ServerResponse.createByErrorMsg("订单失败,AI股票不存在", request);
                 }
-
+                if (!stockAI.getStatus().equals(EStockAIStatus.online.getValue())) {
+                    return ServerResponse.createByErrorMsg("订单失败,AI股票已下架", request);
+                }
                 if(buyNum.compareTo(stockAI.getMinPrice()) < 0){
                     return ServerResponse.createByErrorMsg("最低购买数量" + stockAI.getMinPrice(), request);
                 }
                 //获取用户账户
-                UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(EStockType.MX.getCode(), user.getId());
-                BigDecimal finalBuyNum = buyNum;    //购买金额
-                //如果不是墨西哥币需要转换金额
-                if (!stockAI.getStockType().equals(EStockType.US.getCode())) {
-                    EStockType stockType = EStockType.getEStockTypeByCode(stockAI.getStockType());
-                    ExchangeRate exchangeRate = exchangeRateRepository.findExchangeRateByCurrencyAndConversionCurrency(stockType.getSymbol(), EStockType.MX.getSymbol())
-                            .orElse(null);
-                    if (exchangeRate == null) {
-                        return ServerResponse.createByErrorMsg("当前货币汇率无法转换");
-                    }
-                    //转换为墨西哥币
-                    buyNum = iUserAssetsServices.exchangeAmountByRate(buyNum, exchangeRate.getRata());
-                }
+                UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(stockAI.getStockType(), user.getId());
+                /*BigDecimal finalBuyNum = buyNum;
+                //如果不是默认货币需要转换金额
+                if (!stockAI.getStockType().equals(EStockType.getDefault().getCode())) {
+                    buyNum = userAssetsServices.exchangeAmountByRate(stockAI.getStockType(), buyNum);
+                }*/
                 if(buyNum.compareTo(userAssets.getAvailableBalance()) > 0){
                     return ServerResponse.createByErrorMsg("可用余额不足" + userAssets.getAvailableBalance(), request);
                 }
@@ -111,21 +119,20 @@
                 if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){
                     return ServerResponse.createByErrorMsg("请先缴清待补资金", request);
                 }
-
+                iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), user.getId(), EUserAssets.BUY_AI, buyNum);
                 StockAIOrder stockAIOrder = new StockAIOrder();
                 stockAIOrder.setUserId(user.getId());
-                stockAIOrder.setStockAiId(id);
+                stockAIOrder.setStockAiId(id.intValue());
                 stockAIOrder.setBuyDate(new Date());
-                stockAIOrder.setBuyAmount(finalBuyNum);
-                stockAIOrder.setRemainAmount(finalBuyNum);
+                stockAIOrder.setBuyAmount(buyNum);
+                stockAIOrder.setRemainAmount(buyNum);
                 stockAIOrder.setRealEarning(BigDecimal.valueOf(0));
                 stockAIOrder.setStatus(EStockAIOrderStatus.wait.getStatus());   //等待审核
                 stockAiOrderMapper.insert(stockAIOrder);
-                iUserAssetsServices.aiAvailableBalanceChange(userAssets, EUserAssets.BUY_AI, buyNum);
                 return ServerResponse.createBySuccessMsg("下单成功", request);
             }
         } catch (Exception e) {
-            log.error("StockAiService buyStockAiList error", e);
+            log.error("StockAiService buyStockAiList  {}", e.getMessage());
         }
         return ServerResponse.createByError();
     }
@@ -143,19 +150,238 @@
         try {
             User user = iUserService.getCurrentUser(request);
             if (user == null ){
-                return ServerResponse.createBySuccessMsg("請先登錄");
+                return ServerResponse.createByErrorCodeMsg(ResponseCode.NEED_LOGIN.getCode(),"请先登录", request);
             }
-
             PageHelper.startPage(pageNum, pageSize);
-            List<StockAIOrder> stockAIOrders = stockAiOrderMapper.selectList(new QueryWrapper<StockAIOrder>()
-                    .eq("user_id", user.getId())
-                    .eq(status != null && !status.isEmpty(), "status", status));
+            List<StockAiOrderTypeVO> stockAIOrders = stockAiOrderMapper.getStockAiOrderList(user.getId(), status);
             // 获取分页信息
-            PageInfo<StockAIOrder> pageInfo = new PageInfo<>(stockAIOrders);
+            PageInfo<StockAiOrderTypeVO> pageInfo = new PageInfo<>(stockAIOrders);
             return ServerResponse.createBySuccess(pageInfo);
         } catch (Exception e) {
             log.error("StockAiService getStockAiOrderList error", e);
         }
         return ServerResponse.createByError();
     }
+
+    @Override
+    public ServerResponse getAdminStockAiList(Integer pageNum, Integer pageSize, String stockType, String status, String name) {
+        try {
+            PageHelper.startPage(pageNum, pageSize);
+            List<StockAiVO> stockAiList = stockAiMapper.getStockAiList(stockType, status, name);
+            // 获取分页信息
+            PageInfo<StockAiVO> pageInfo = new PageInfo<>(stockAiList);
+
+            if (!pageInfo.getList().isEmpty()) {
+                List<StockAiVO> newStockAiList = pageInfo.getList();
+                pageInfo.getList().forEach(stockAiVO -> {
+                    EStockType eStockType = EStockType.getEStockTypeByCode(stockAiVO.getStockType());
+                    stockAiVO.setStockTypeName(eStockType.getSymbol1());
+                    stockAiVO.setSymbol(stockType);
+                });
+                pageInfo.setList(newStockAiList);
+            }
+            return ServerResponse.createBySuccess(pageInfo);
+        } catch (Exception ex) {
+            log.error("StockAiService getAdminStockAiList error", ex);
+        }
+        return ServerResponse.createByError();
+    }
+
+    /**
+     * 新增或修改
+     * @param model
+     * @return
+     */
+    @Override
+    public ServerResponse editStockAi(StockAI model) {
+        try {
+            if (model == null) {
+                return ServerResponse.createByErrorMsg("editStockAi model is null");
+            }
+            if (StringUtils.isBlank(model.getStockType()) || StringUtils.isBlank(model.getStockName()) || model.getMinPrice() == null
+                || model.getSuccessRate() == null || model.getExpectedEarning() == null || StringUtils.isBlank(model.getStatus())) {
+                return ServerResponse.createByErrorMsg("请完善必填信息");
+            }
+            if (!EStockType.isExistByCode(model.getStockType())) {
+                return ServerResponse.createByErrorMsg("股票市场不存在");
+            }
+            //新增
+            if (model.getId() == null) {
+                //查询是否存在
+                StockAI stockAI = stockAiMapper.selectOne(new QueryWrapper<StockAI>().eq("stock_name", model.getStockName()));
+                if (stockAI != null) {
+                    return ServerResponse.createByErrorMsg("当前股票已添加");
+                }
+                model.setCreateDate(new Date());
+                stockAiMapper.insert(model);
+            } else {    //修改
+                stockAiMapper.updateById(model);
+            }
+            return ServerResponse.createBySuccess("操作成功");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(e.getMessage(), e);
+        }
+        return ServerResponse.createByError();
+    }
+
+    /**
+     * 后台查询ai交易订单
+     * @param pageNum
+     * @param pageSize
+     * @param stockType
+     * @param status
+     * @param userId
+     * @param phone
+     * @return
+     */
+    @Override
+    public ServerResponse getAdminStockAiOrderList(Integer pageNum, Integer pageSize, String stockType, String status, Integer userId, String phone) {
+        try {
+            PageHelper.startPage(pageNum, pageSize);
+            List<StockAiOrderVO> stockAIOrders = stockAiOrderMapper.getAdminStockAiOrderList(stockType, status, userId, phone);
+            // 获取分页信息
+            PageInfo<StockAiOrderVO> pageInfo = new PageInfo<>(stockAIOrders);
+
+            if (!pageInfo.getList().isEmpty()) {
+                List<StockAiOrderVO> newStockAiOrders = pageInfo.getList();
+                newStockAiOrders.forEach(stockAiOrderVO -> {
+                    EStockType eStockType = EStockType.getEStockTypeByCode(stockAiOrderVO.getStockType());
+                    stockAiOrderVO.setStockTypeName(eStockType.getSymbol1());
+                    stockAiOrderVO.setSymbol(stockType);
+                });
+                pageInfo.setList(newStockAiOrders);
+            }
+            return ServerResponse.createBySuccess(pageInfo);
+        } catch (Exception e) {
+            log.error("StockAiService getAdminStockAiOrderList error", e);
+        }
+        return ServerResponse.createByError();
+    }
+
+    /**
+     * 建仓
+     * @param model
+     * @return
+     */
+    @Override
+    public ServerResponse openPosition(StockAIOrderPosition model) {
+        try {
+            Object lock = locks.computeIfAbsent(Long.valueOf(model.getStockAiOrderId()), k -> new Object());
+            synchronized (lock) {
+                StockAIOrder stockAIOrder = stockAiOrderMapper.selectById(model.getStockAiOrderId());
+                if (stockAIOrder == null) {
+                    return ServerResponse.createByErrorMsg("AI订单不存在");
+                }
+
+                if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.passed.getStatus())) {
+                    return ServerResponse.createByErrorMsg("申请通过状态才能建仓!");
+                }
+                //计算剩余金额
+                BigDecimal remainAmount = model.getStockPrice().multiply(BigDecimal.valueOf(model.getStockNum()));
+                if (stockAIOrder.getRemainAmount().compareTo(remainAmount) < 0) {
+                    return ServerResponse.createByErrorMsg("剩余买入金额不足");
+                }
+                stockAIOrder.setRemainAmount(stockAIOrder.getRemainAmount().subtract(remainAmount));
+
+                //计算收益  (平仓-建仓)*数量
+                BigDecimal earnings = model.getCoverPrice().subtract(model.getStockPrice()).multiply(BigDecimal.valueOf(model.getStockNum()));
+                model.setCreatDate(new Date());
+                model.setEarnings(earnings);
+                model.setStatus(0);
+                stockAIOrder.setRealEarning(stockAIOrder.getRealEarning().add(earnings));
+
+                //保存
+                stockAiOrderMapper.updateById(stockAIOrder);
+                stockAiOrderPositionMapper.insert(model);
+                return ServerResponse.createBySuccess("建仓成功");
+            }
+        } catch (Exception e) {
+            log.error("StockAiService openPosition error", e);
+        }
+        return ServerResponse.createByError();
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ServerResponse orderOperation(Long id, String status) {
+        try {
+            Object lock = locks.computeIfAbsent(id, k -> new Object());
+            synchronized (lock) {
+                StockAIOrder stockAIOrder = stockAiOrderMapper.selectById(id);
+                if (stockAIOrder == null) {
+                    return ServerResponse.createByErrorMsg("AI订单不存在");
+                }
+                if (status.equals(EStockAIOrderStatus.passed.getStatus())) {
+                    //通过
+                    if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.wait.getStatus())) {
+                        return ServerResponse.createByErrorMsg("只能通过待审核订单");
+                    }
+                } else if (status.equals(EStockAIOrderStatus.notPass.getStatus())) {
+                    if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.wait.getStatus())) {
+                        return ServerResponse.createByErrorMsg("只能拒绝待审核订单");
+                    }
+                    //拒绝TODO 归还买入金额
+                    StockAI stockAI = stockAiMapper.selectById(stockAIOrder.getStockAiId());
+                    //买入金额
+                    BigDecimal buyNum =  stockAIOrder.getBuyAmount();
+                    iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.BUY_AI_REJECT, buyNum);
+                } else if (status.equals(EStockAIOrderStatus.finished.getStatus())) {
+                    if (!stockAIOrder.getStatus().equals(EStockAIOrderStatus.passed.getStatus())) {
+                        return ServerResponse.createByErrorMsg("只能结算申请通过订单");
+                    }
+                    //结算 TODO结算建仓 计算收益
+                    /*//所有建仓
+
+                    List<StockAIOrderPosition> stockAIOrderPositionList = stockAiOrderPositionMapper
+                            .selectList(new QueryWrapper<StockAIOrderPosition>()
+                                    .eq("stock_ai_order_id", id));
+                    //结算金额
+                    BigDecimal amount = stockAIOrder.getBuyAmount();
+                    if (!stockAIOrderPositionList.isEmpty()) {
+                        //总收益
+                        BigDecimal earningsSUM = stockAIOrderPositionList.stream()
+                                .map(StockAIOrderPosition::getEarnings)  // 获取 BigDecimal 字段
+                                .filter(Objects::nonNull)    // 过滤 null 值
+                                .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加
+                        amount = amount.add(earningsSUM);
+                    }*/
+                    StockAI stockAI = stockAiMapper.selectById(stockAIOrder.getStockAiId());
+                    //结算修改为平仓状态
+                    stockAiOrderPositionMapper.updateStatusByOrderId(stockAIOrder.getId(), 1);
+                    //归还本金
+                    iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.AI_SETTLEMENT, stockAIOrder.getBuyAmount());
+                    //收益
+                    iUserAssetsServices.aiAvailableBalanceChange(stockAI.getStockType(), stockAIOrder.getUserId(), EUserAssets.AI_SETTLEMENT_INT, stockAIOrder.getRealEarning());
+                }
+                stockAIOrder.setStatus(status);
+                stockAIOrder.setAuditDate(new Date());
+                stockAiOrderMapper.updateById(stockAIOrder);
+                return ServerResponse.createBySuccess("操作成功");
+            }
+        } catch (Exception e) {
+            log.error("StockAiService orderOperation error", e);
+        }
+        return ServerResponse.createByError();
+    }
+
+    /**
+     * 建仓列表
+     * @param pageNum
+     * @param pageSize
+     * @param stockAiOrderId
+     * @return
+     */
+    @Override
+    public ServerResponse getPositionList(Integer pageNum, Integer pageSize, Integer stockAiOrderId) {
+        try {
+            PageHelper.startPage(pageNum, pageSize);
+            List<StockAIOrderPositionVO> positionVOList = stockAiOrderPositionMapper.getPositionListByOrderId(stockAiOrderId);
+            PageInfo<StockAIOrderPositionVO> pageInfo = new PageInfo<>(positionVOList);
+            return ServerResponse.createBySuccess(pageInfo);
+        } catch (Exception e) {
+            log.error("StockAiService getPositionList error", e);
+        }
+        return ServerResponse.createByError();
+    }
 }

--
Gitblit v1.9.3