From 539f733f62f4a368eb90a07a729b5d948378a705 Mon Sep 17 00:00:00 2001
From: zyy <zyy@email.com>
Date: Sat, 19 Jul 2025 18:29:07 +0800
Subject: [PATCH] 后台新增建仓列表 新股列表新增购买状态
---
src/main/java/com/nq/service/impl/StockAiServiceImpl.java | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 254 insertions(+), 23 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..6d354a4 100644
--- a/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
@@ -3,13 +3,18 @@
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,23 +25,25 @@
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
IUserService iUserService;
@Autowired
IUserAssetsServices iUserAssetsServices;
- @Autowired
- ExchangeRateRepository exchangeRateRepository;
/**
* 获取上架ai产品
@@ -48,7 +55,8 @@
public ServerResponse getStockAiList(Integer pageNum, Integer pageSize) {
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()));
// 获取分页信息
PageInfo<StockAI> pageInfo = new PageInfo<>(stockAiList);
return ServerResponse.createBySuccess(pageInfo);
@@ -65,14 +73,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,16 +95,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; //购买金额
+ /*BigDecimal finalBuyNum = buyNum; //购买金额
//如果不是墨西哥币需要转换金额
- if (!stockAI.getStockType().equals(EStockType.US.getCode())) {
+ if (!stockAI.getStockType().equals(EStockType.MX.getCode())) {
EStockType stockType = EStockType.getEStockTypeByCode(stockAI.getStockType());
+
ExchangeRate exchangeRate = exchangeRateRepository.findExchangeRateByCurrencyAndConversionCurrency(stockType.getSymbol(), EStockType.MX.getSymbol())
.orElse(null);
if (exchangeRate == null) {
@@ -103,7 +115,7 @@
}
//转换为墨西哥币
buyNum = iUserAssetsServices.exchangeAmountByRate(buyNum, exchangeRate.getRata());
- }
+ }*/
if(buyNum.compareTo(userAssets.getAvailableBalance()) > 0){
return ServerResponse.createByErrorMsg("可用余额不足" + userAssets.getAvailableBalance(), request);
}
@@ -111,21 +123,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 +154,239 @@
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 (model.getStockType().isEmpty() || model.getStockName().isEmpty() || model.getMinPrice() == null
+ || model.getSuccessRate() == null || model.getExpectedEarning() == null || model.getStatus().isEmpty()) {
+ return ServerResponse.createByErrorMsg("请完善必填信息");
+ }
+ if (!model.getStockType().equals(EStockType.US.getCode()) && !model.getStockType().equals(EStockType.MX.getCode())) {
+ 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 openPosition 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