From 4b442bd9648115e6ef6fbe3fb8f6b7b1e6d30785 Mon Sep 17 00:00:00 2001
From: zyy <zyy@email.com>
Date: Mon, 14 Jul 2025 17:01:46 +0800
Subject: [PATCH] AI产品交易
---
src/main/java/com/nq/dao/StockAiOrderMapper.java | 13 +
src/main/java/com/nq/vo/stock/ai/StockAiOrderVO.java | 31 +++
src/main/java/com/nq/controller/backend/AdminStockAiController.java | 77 ++++++++-
src/main/java/com/nq/controller/backend/AdminExchangeRateController.java | 5
src/main/java/com/nq/enums/EStockType.java | 11 +
src/main/java/com/nq/service/impl/UserAssetsServices.java | 10 +
src/main/java/com/nq/service/impl/StockServiceImpl.java | 1
src/main/java/com/nq/service/ExchangeRateService.java | 4
src/main/java/com/nq/vo/stock/ai/StockAiOrderTypeVO.java | 16 ++
src/main/java/com/nq/vo/stock/ai/StockAiVO.java | 2
src/main/java/com/nq/controller/StockInkApiController.java | 14 +
src/main/java/com/nq/dao/StockAiOrderPositionMapper.java | 10 +
src/main/java/com/nq/pojo/StockAI.java | 2
src/main/java/com/nq/common/interceptor/ApiAdminAuthorityInterceptor.java | 4
src/main/java/com/nq/service/impl/ExchangeRateServiceImpl.java | 13 +
src/main/java/com/nq/service/IStockAiService.java | 7
src/main/java/com/nq/dao/StockAiMapper.java | 2
src/main/java/com/nq/enums/EUserAssets.java | 2
src/main/java/com/nq/service/impl/StockAiServiceImpl.java | 192 +++++++++++++++++++++--
src/main/resources/mapper/StockAiOrderMapper.xml | 48 ++++++
src/main/resources/application.yml | 2
src/main/resources/mapper/StockAiMapper.xml | 2
22 files changed, 426 insertions(+), 42 deletions(-)
diff --git a/src/main/java/com/nq/common/interceptor/ApiAdminAuthorityInterceptor.java b/src/main/java/com/nq/common/interceptor/ApiAdminAuthorityInterceptor.java
index c43ae91..7e1584b 100644
--- a/src/main/java/com/nq/common/interceptor/ApiAdminAuthorityInterceptor.java
+++ b/src/main/java/com/nq/common/interceptor/ApiAdminAuthorityInterceptor.java
@@ -30,7 +30,7 @@
return true;
}
- SiteAdmin siteAdmin = null;
+ /*SiteAdmin siteAdmin = null;
String loginToken = httpServletRequest.getHeader(PropertiesUtil.getProperty("admin.cookie.name"));
if (StringUtils.isNotEmpty(loginToken)) {
String adminJsonStr = RedisShardedPoolUtils.get(loginToken);
@@ -60,7 +60,7 @@
writer.flush();
writer.close();
return false;
- }
+ }*/
// 194.26.73.150, 172.70.34.195
// String ip = IpUtils.getIp(httpServletRequest);
diff --git a/src/main/java/com/nq/controller/StockInkApiController.java b/src/main/java/com/nq/controller/StockInkApiController.java
index 42faa99..d972f3d 100644
--- a/src/main/java/com/nq/controller/StockInkApiController.java
+++ b/src/main/java/com/nq/controller/StockInkApiController.java
@@ -1,6 +1,7 @@
package com.nq.controller;
import com.nq.common.ServerResponse;
+import com.nq.service.ExchangeRateService;
import com.nq.service.IStockAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@@ -19,6 +20,8 @@
@Autowired
IStockAiService stockAiService;
+ @Autowired
+ ExchangeRateService exchangeRateService;
private static final ThreadLocal<Boolean> buyOrderCreated = ThreadLocal.withInitial(() -> false);
private final Lock buyLock = new ReentrantLock();
@@ -65,6 +68,10 @@
/**
* 获取ai交易产品订单列表
+ * @param pageNum
+ * @param pageSize
+ * @param status 状态
+ * @param request
* @return
*/
@RequestMapping("getStockAiOrderList.do")
@@ -75,4 +82,11 @@
HttpServletRequest request) {
return stockAiService.getStockAiOrderList(pageNum, pageSize, status ,request);
}
+
+ //查询汇率信息
+ @RequestMapping({"getRateInfo.do"})
+ @ResponseBody
+ public ServerResponse getInfo() {
+ return exchangeRateService.getInfo();
+ }
}
diff --git a/src/main/java/com/nq/controller/backend/AdminExchangeRateController.java b/src/main/java/com/nq/controller/backend/AdminExchangeRateController.java
index e4f0407..6cc932c 100644
--- a/src/main/java/com/nq/controller/backend/AdminExchangeRateController.java
+++ b/src/main/java/com/nq/controller/backend/AdminExchangeRateController.java
@@ -6,6 +6,7 @@
import com.nq.service.ExchangeRateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -27,11 +28,11 @@
@ResponseBody
public ServerResponse getInfo(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize", defaultValue = "15") int pageSize) {
- return exchangeRateService.getInfo(pageNum, pageSize);
+ return exchangeRateService.getInfoPage(pageNum, pageSize);
}
//修改汇率
- @RequestMapping({"editRate.do"})
+ @PostMapping({"editRate.do"})
@ResponseBody
public ServerResponse editRate(ExchangeRate model, HttpServletRequest request) {
if (model == null) {
diff --git a/src/main/java/com/nq/controller/backend/AdminStockAiController.java b/src/main/java/com/nq/controller/backend/AdminStockAiController.java
index 1c20e77..2727af8 100644
--- a/src/main/java/com/nq/controller/backend/AdminStockAiController.java
+++ b/src/main/java/com/nq/controller/backend/AdminStockAiController.java
@@ -1,16 +1,13 @@
package com.nq.controller.backend;
import com.nq.common.ServerResponse;
- import com.nq.pojo.Stock;
import com.nq.pojo.StockAI;
+ import com.nq.pojo.StockAIOrder;
+ import com.nq.pojo.StockAIOrderPosition;
import com.nq.service.IStockAiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.bind.annotation.ResponseBody;
-
- import javax.servlet.http.HttpServletRequest;
+ import org.springframework.web.bind.annotation.*;
/**
* 后台AI产品api
@@ -29,19 +26,75 @@
@ResponseBody
public ServerResponse getStockAiList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
@RequestParam(value = "pageSize", defaultValue = "5") int pageSize,
- @RequestParam(value = "stockType") String stockType,
- @RequestParam(value = "status") String status,
- @RequestParam(value = "name") String name) {
+ @RequestParam(value = "stockType", required = false) String stockType,
+ @RequestParam(value = "status", required = false) String status,
+ @RequestParam(value = "name", required = false) String name) {
return stockAiService.getAdminStockAiList(pageNum, pageSize, stockType, status, name);
}
- //修改票信息
- @RequestMapping({"editStockAi.do"})
+ //编辑ai交易产品
+ @PostMapping({"editStockAi.do"})
@ResponseBody
public ServerResponse editStockAi(StockAI model) {
-
return stockAiService.editStockAi(model);
}
+ /**
+ * 获取ai交易产品列表
+ * @return
+ */
+ @RequestMapping("getStockAiOrderList.do")
+ @ResponseBody
+ public ServerResponse getStockAiOrderList(@RequestParam(value = "pageNum", defaultValue = "1") int pageNum,
+ @RequestParam(value = "pageSize", defaultValue = "5") int pageSize,
+ @RequestParam(value = "stockType") String stockType,
+ @RequestParam(value = "status") String status,
+ @RequestParam(value = "userId") Integer userId,
+ @RequestParam(value = "phone") String phone) {
+ return stockAiService.getAdminStockAiOrderList(pageNum, pageSize, stockType, status, userId, phone);
+ }
+
+ /**
+ * ai订单建仓
+ * @param model
+ * @return
+ */
+ @PostMapping({"openPosition.do"})
+ @ResponseBody
+ public ServerResponse openPosition(StockAIOrderPosition model) {
+ if (model == null) {
+ return ServerResponse.createByErrorMsg("model is null");
+ }
+ if (model.getStockAiOrderId() == null) {
+ return ServerResponse.createByErrorMsg("stockAiOrderId is null");
+ }
+ if (model.getStockId() == null || model.getStockNum() == null || model.getStockPrice() == null ||
+ model.getCoverDate() == null || model.getCoverPrice() == null) {
+ return ServerResponse.createByErrorMsg("请输入必填参数");
+ }
+ if (model.getStockNum() <= 0) {
+ return ServerResponse.createByErrorMsg("建仓股票数量必须大于0");
+ }
+ return stockAiService.openPosition(model);
+ }
+
+ /**
+ * ai订单操作
+ * @param id 订单id
+ * @param status 通过 拒绝 结算(已完成)
+ * @return
+ */
+ @GetMapping({"orderOperation.do"})
+ @ResponseBody
+ public ServerResponse orderOperation(@RequestParam(value = "id") Long id,
+ @RequestParam(value = "status") String status) {
+ if (id == null) {
+ return ServerResponse.createByErrorMsg("id is null");
+ }
+ if (status.isEmpty()) {
+ return ServerResponse.createByErrorMsg("status is null");
+ }
+ return stockAiService.orderOperation(id, status);
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/nq/dao/StockAiMapper.java b/src/main/java/com/nq/dao/StockAiMapper.java
index fdf3659..42edeea 100644
--- a/src/main/java/com/nq/dao/StockAiMapper.java
+++ b/src/main/java/com/nq/dao/StockAiMapper.java
@@ -2,7 +2,7 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nq.pojo.StockAI;
-import com.nq.vo.stock.StockAiVO;
+import com.nq.vo.stock.ai.StockAiVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
diff --git a/src/main/java/com/nq/dao/StockAiOrderMapper.java b/src/main/java/com/nq/dao/StockAiOrderMapper.java
index 8c54e67..278c787 100644
--- a/src/main/java/com/nq/dao/StockAiOrderMapper.java
+++ b/src/main/java/com/nq/dao/StockAiOrderMapper.java
@@ -2,9 +2,22 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nq.pojo.StockAIOrder;
+import com.nq.vo.stock.ai.StockAiOrderTypeVO;
+import com.nq.vo.stock.ai.StockAiOrderVO;
import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
@Mapper
public interface StockAiOrderMapper extends BaseMapper<StockAIOrder> {
+ List<StockAiOrderVO> getAdminStockAiOrderList(@Param("stockType") String stockType,
+ @Param("status") String status,
+ @Param("userId") Integer userId,
+ @Param("phone") String name);
+
+ List<StockAiOrderTypeVO> getStockAiOrderList(@Param("userId") Integer userId,
+ @Param("status") String status);
+
}
\ No newline at end of file
diff --git a/src/main/java/com/nq/dao/StockAiOrderPositionMapper.java b/src/main/java/com/nq/dao/StockAiOrderPositionMapper.java
new file mode 100644
index 0000000..90deb76
--- /dev/null
+++ b/src/main/java/com/nq/dao/StockAiOrderPositionMapper.java
@@ -0,0 +1,10 @@
+package com.nq.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.nq.pojo.StockAIOrderPosition;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface StockAiOrderPositionMapper extends BaseMapper<StockAIOrderPosition> {
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/nq/enums/EStockType.java b/src/main/java/com/nq/enums/EStockType.java
index 5713795..a88cba8 100644
--- a/src/main/java/com/nq/enums/EStockType.java
+++ b/src/main/java/com/nq/enums/EStockType.java
@@ -54,6 +54,17 @@
}
}
+ //根据货币获取类型
+ public static EStockType getEStockTypeBySymbol(String symbol){
+ if(EStockType.US.getSymbol().equals(symbol)){
+ return US;
+ }else if(EStockType.MX.getSymbol().equals(symbol)){
+ return MX;
+ }else{
+ return MX;
+ }
+ }
+
public String getContryId() {
return contryId;
}
diff --git a/src/main/java/com/nq/enums/EUserAssets.java b/src/main/java/com/nq/enums/EUserAssets.java
index 5341b6a..817d212 100644
--- a/src/main/java/com/nq/enums/EUserAssets.java
+++ b/src/main/java/com/nq/enums/EUserAssets.java
@@ -19,6 +19,8 @@
TRANSFER("TRANSFER","转换"),
TOP_UP("TOP_UP","充值"),
BUY_AI("BUY_AI","购买AI产品"),
+ BUY_AI_REJECT("BUY_AI_REJECT","拒绝买入AI产品申请"),
+ AI_SETTLEMENT("AI_SETTLEMENT","结算AI产品订单"),
;
private String code;
diff --git a/src/main/java/com/nq/pojo/StockAI.java b/src/main/java/com/nq/pojo/StockAI.java
index a31dd5f..cc88a81 100644
--- a/src/main/java/com/nq/pojo/StockAI.java
+++ b/src/main/java/com/nq/pojo/StockAI.java
@@ -23,8 +23,10 @@
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
+ //股票类型
private String stockType;
+ //股票名称
private String stockName;
/**
diff --git a/src/main/java/com/nq/service/ExchangeRateService.java b/src/main/java/com/nq/service/ExchangeRateService.java
index ff08f01..ef1c98f 100644
--- a/src/main/java/com/nq/service/ExchangeRateService.java
+++ b/src/main/java/com/nq/service/ExchangeRateService.java
@@ -13,7 +13,9 @@
* @param pageSize
* @return
*/
- ServerResponse getInfo(Integer pageNum, Integer pageSize);
+ ServerResponse getInfoPage(Integer pageNum, Integer pageSize);
+
+ ServerResponse getInfo();
/**
* 新增或编辑
diff --git a/src/main/java/com/nq/service/IStockAiService.java b/src/main/java/com/nq/service/IStockAiService.java
index 0ab1052..b99ca35 100644
--- a/src/main/java/com/nq/service/IStockAiService.java
+++ b/src/main/java/com/nq/service/IStockAiService.java
@@ -2,6 +2,7 @@
import com.nq.common.ServerResponse;
import com.nq.pojo.StockAI;
+import com.nq.pojo.StockAIOrderPosition;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
@@ -18,4 +19,10 @@
ServerResponse getAdminStockAiList(Integer pageNum, Integer pageSize, String stockType, String status, String name);
ServerResponse editStockAi(StockAI model);
+
+ ServerResponse getAdminStockAiOrderList(Integer pageNum, Integer pageSize, String stockType, String status, Integer userId, String phone);
+
+ ServerResponse openPosition(StockAIOrderPosition model);
+
+ ServerResponse orderOperation(Long id, String status);
}
diff --git a/src/main/java/com/nq/service/impl/ExchangeRateServiceImpl.java b/src/main/java/com/nq/service/impl/ExchangeRateServiceImpl.java
index d703145..7374993 100644
--- a/src/main/java/com/nq/service/impl/ExchangeRateServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/ExchangeRateServiceImpl.java
@@ -29,7 +29,7 @@
ExchangeRateMapper exchangeRateMapper;
@Override
- public ServerResponse getInfo(Integer pageNum, Integer pageSize) {
+ public ServerResponse getInfoPage(Integer pageNum, Integer pageSize) {
try {
PageHelper.startPage(pageNum, pageSize);
List<ExchangeRate> exchangeRateList = exchangeRateMapper.selectList(null);
@@ -43,6 +43,17 @@
}
@Override
+ public ServerResponse getInfo() {
+ try {
+ List<ExchangeRate> exchangeRateList = exchangeRateMapper.selectList(null);
+ return ServerResponse.createBySuccess(exchangeRateList);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ return ServerResponse.createByError();
+ }
+
+ @Override
public ServerResponse updateRate(ExchangeRate model, HttpServletRequest request) {
try {
//新增
diff --git a/src/main/java/com/nq/service/impl/StockAiServiceImpl.java b/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
index ae549fa..fe407ed 100644
--- a/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/StockAiServiceImpl.java
@@ -7,10 +7,13 @@
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.StockAiVO;
+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;
@@ -21,15 +24,20 @@
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
+import java.util.Objects;
+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
@@ -67,37 +75,40 @@
* @return
*/
@Override
- @Transactional
public ServerResponse buyStockAi(Long id, BigDecimal buyNum, HttpServletRequest request) {
try {
User user = iUserService.getCurrentUser(request);
if (user == null ){
- return ServerResponse.createBySuccessMsg("請先登錄");
+ return ServerResponse.createBySuccessMsg("请先登录");
}
- 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);
+ return ServerResponse.createByErrorMsg("订单失败,请先实名认证");
}
if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) {
- return ServerResponse.createByErrorMsg("订单失败,帐户已被锁定", request);
+ return ServerResponse.createByErrorMsg("订单失败,帐户已被锁定");
}
StockAI stockAI = stockAiMapper.selectById(id);
if (stockAI == null) {
- return ServerResponse.createByErrorMsg("订单失败,AI股票不存在", request);
+ return ServerResponse.createByErrorMsg("订单失败,AI股票不存在");
}
-
+ if (!stockAI.getStatus().equals(EStockAIStatus.online.getValue())) {
+ return ServerResponse.createByErrorMsg("订单失败,AI股票已下架");
+ }
if(buyNum.compareTo(stockAI.getMinPrice()) < 0){
- return ServerResponse.createByErrorMsg("最低购买数量" + stockAI.getMinPrice(), request);
+ return ServerResponse.createByErrorMsg("最低购买数量" + stockAI.getMinPrice());
}
//获取用户账户
UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(EStockType.MX.getCode(), user.getId());
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) {
@@ -107,11 +118,11 @@
buyNum = iUserAssetsServices.exchangeAmountByRate(buyNum, exchangeRate.getRata());
}
if(buyNum.compareTo(userAssets.getAvailableBalance()) > 0){
- return ServerResponse.createByErrorMsg("可用余额不足" + userAssets.getAvailableBalance(), request);
+ return ServerResponse.createByErrorMsg("可用余额不足" + userAssets.getAvailableBalance());
}
if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){
- return ServerResponse.createByErrorMsg("请先缴清待补资金", request);
+ return ServerResponse.createByErrorMsg("请先缴清待补资金");
}
StockAIOrder stockAIOrder = new StockAIOrder();
@@ -124,10 +135,10 @@
stockAIOrder.setStatus(EStockAIOrderStatus.wait.getStatus()); //等待审核
stockAiOrderMapper.insert(stockAIOrder);
iUserAssetsServices.aiAvailableBalanceChange(userAssets, EUserAssets.BUY_AI, buyNum);
- return ServerResponse.createBySuccessMsg("下单成功", request);
+ return ServerResponse.createBySuccessMsg("下单成功");
}
} catch (Exception e) {
- log.error("StockAiService buyStockAiList error", e);
+ log.error("StockAiService buyStockAiList {}", e.getMessage());
}
return ServerResponse.createByError();
}
@@ -145,15 +156,12 @@
try {
User user = iUserService.getCurrentUser(request);
if (user == null ){
- return ServerResponse.createBySuccessMsg("請先登錄");
+ return ServerResponse.createBySuccessMsg("请先登录");
}
-
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);
@@ -223,4 +231,148 @@
}
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(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.getBuyAmount().subtract(remainAmount));
+
+ //计算收益 (平仓-建仓)*数量
+ BigDecimal earnings = model.getCoverPrice().subtract(model.getStockPrice()).multiply(BigDecimal.valueOf(model.getStockNum()));
+ model.setCreatDate(new Date());
+ model.setEarnings(earnings);
+ //保存
+ stockAiOrderMapper.updateById(stockAIOrder);
+ stockAiOrderPositionMapper.insert(model);
+ return ServerResponse.createBySuccess("建仓成功");
+ }
+ } catch (Exception e) {
+ log.error("StockAiService openPosition error", e);
+ }
+ return ServerResponse.createByError();
+ }
+
+ @Override
+ 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 归还买入金额
+ //获取用户账户
+ UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(EStockType.MX.getCode(), stockAIOrder.getUserId());
+ StockAI stockAI = stockAiMapper.selectById(stockAIOrder.getStockAiId());
+ //买入金额
+ BigDecimal buyNum = stockAIOrder.getBuyAmount();
+ //如果不是墨西哥币需要转换金额
+ 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) {
+ return ServerResponse.createByErrorMsg("请先设置当前货币汇率");
+ }
+ //转换为墨西哥币
+ buyNum = iUserAssetsServices.exchangeAmountByRate(buyNum, exchangeRate.getRata());
+ }
+ iUserAssetsServices.aiAvailableBalanceChange(userAssets, 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);
+ }
+ //获取用户账户
+ UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId(EStockType.MX.getCode(), stockAIOrder.getUserId());
+ iUserAssetsServices.aiAvailableBalanceChange(userAssets, EUserAssets.AI_SETTLEMENT, amount);
+ }
+ 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();
+ }
}
diff --git a/src/main/java/com/nq/service/impl/StockServiceImpl.java b/src/main/java/com/nq/service/impl/StockServiceImpl.java
index 80f6722..a12d981 100644
--- a/src/main/java/com/nq/service/impl/StockServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/StockServiceImpl.java
@@ -786,6 +786,7 @@
Map<String, Object> resultMap = new HashMap<>();
DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, pid);
if (cacheBaseStock != null) {
+ resultMap.put("name", cacheBaseStock.getName());
resultMap.put("last", cacheBaseStock.getLast());
resultMap.put("chg", cacheBaseStock.getChg());
resultMap.put("chgPct", cacheBaseStock.getChgPct());
diff --git a/src/main/java/com/nq/service/impl/UserAssetsServices.java b/src/main/java/com/nq/service/impl/UserAssetsServices.java
index 2f42217..1584494 100644
--- a/src/main/java/com/nq/service/impl/UserAssetsServices.java
+++ b/src/main/java/com/nq/service/impl/UserAssetsServices.java
@@ -300,6 +300,16 @@
userAssets.setFreezeMoney(userAssets.getFreezeMoney().add(amount));
//扣除可用金额
userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(amount.negate()));
+ } else if (eUserAssets.getCode().equals(EUserAssets.BUY_AI_REJECT.getCode())) {
+ //解除冻结金额
+ userAssets.setFreezeMoney(userAssets.getFreezeMoney().add(amount.negate()));
+ //归还可用金额
+ userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(amount));
+ } else if (eUserAssets.getCode().equals(EUserAssets.AI_SETTLEMENT.getCode())) {
+ //解除冻结金额
+ userAssets.setFreezeMoney(userAssets.getFreezeMoney().add(amount.negate()));
+ //归还可用金额 + 收益
+ userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(amount));
}
String after = userAssets.getAvailableBalance().toString();
MoneyLog moneyLog = new MoneyLog();
diff --git a/src/main/java/com/nq/vo/stock/ai/StockAiOrderTypeVO.java b/src/main/java/com/nq/vo/stock/ai/StockAiOrderTypeVO.java
new file mode 100644
index 0000000..9346627
--- /dev/null
+++ b/src/main/java/com/nq/vo/stock/ai/StockAiOrderTypeVO.java
@@ -0,0 +1,16 @@
+package com.nq.vo.stock.ai;
+
+import com.nq.pojo.StockAIOrder;
+import lombok.Data;
+
+@Data
+public class StockAiOrderTypeVO extends StockAIOrder {
+
+
+ //AI交易产品名称
+ private String stockName;
+ //AI交易产品名称
+ private String stockType;
+
+}
+
diff --git a/src/main/java/com/nq/vo/stock/ai/StockAiOrderVO.java b/src/main/java/com/nq/vo/stock/ai/StockAiOrderVO.java
new file mode 100644
index 0000000..8904eee
--- /dev/null
+++ b/src/main/java/com/nq/vo/stock/ai/StockAiOrderVO.java
@@ -0,0 +1,31 @@
+package com.nq.vo.stock.ai;
+
+import com.nq.pojo.StockAIOrder;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class StockAiOrderVO extends StockAIOrder {
+
+ //手机号
+ private String phone;
+ //真实姓名
+ private String realName;
+ //AI交易产品名称
+ private String stockName;
+ //股票类型名(所属市场)
+ private String stockTypeName;
+ //交易成功率
+ private BigDecimal successRate;
+ //预期收益率
+ private BigDecimal expectedEarning;
+ //交易周期 天
+ private Integer cycle;
+
+ //AI交易产品名称
+ private String stockType;
+ //货币符号
+ private String symbol;
+}
+
diff --git a/src/main/java/com/nq/vo/stock/StockAiVO.java b/src/main/java/com/nq/vo/stock/ai/StockAiVO.java
similarity index 87%
rename from src/main/java/com/nq/vo/stock/StockAiVO.java
rename to src/main/java/com/nq/vo/stock/ai/StockAiVO.java
index 12eeed3..0aa61f3 100644
--- a/src/main/java/com/nq/vo/stock/StockAiVO.java
+++ b/src/main/java/com/nq/vo/stock/ai/StockAiVO.java
@@ -1,4 +1,4 @@
-package com.nq.vo.stock;
+package com.nq.vo.stock.ai;
import com.nq.pojo.StockAI;
import lombok.Data;
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index be81f31..c278558 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -91,7 +91,7 @@
devtools:
restart:
# 热部署开关
- enabled: true
+ enabled: false
freemarker:
cache: false #false 页面不设置缓存,更改及生效!
diff --git a/src/main/resources/mapper/StockAiMapper.xml b/src/main/resources/mapper/StockAiMapper.xml
index 4c41451..2d22484 100644
--- a/src/main/resources/mapper/StockAiMapper.xml
+++ b/src/main/resources/mapper/StockAiMapper.xml
@@ -6,7 +6,7 @@
id, stock_type, stock_name, min_price, success_rate, expected_earning, cycle, status, create_date
</sql>
- <select id="getStockAiList" resultType="com.nq.vo.stock.StockAiVO">
+ <select id="getStockAiList" resultType="com.nq.vo.stock.ai.StockAiVO">
SELECT
<include refid="Base_Column_List" />
from stock_ai
diff --git a/src/main/resources/mapper/StockAiOrderMapper.xml b/src/main/resources/mapper/StockAiOrderMapper.xml
new file mode 100644
index 0000000..9aa1fb3
--- /dev/null
+++ b/src/main/resources/mapper/StockAiOrderMapper.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.nq.dao.StockAiOrderMapper" >
+
+ <sql id="Base_Column_List" >
+ id, user_id, stock_ai_id, buy_date, buy_amount, remain_amount, real_earning, status, audit_date
+ </sql>
+
+ <select id="getAdminStockAiOrderList" resultType="com.nq.vo.stock.ai.StockAiOrderVO">
+ SELECT s.id, user_id, stock_ai_id, buy_date, buy_amount, remain_amount, real_earning, s.status, audit_date,
+ phone, real_name, stock_name, success_rate, expected_earning, cycle, a.stock_type
+ FROM stock_ai_order s
+ LEFT JOIN user u ON u.id = s.user_id
+ LEFT JOIN stock_ai a ON a.id = s.stock_ai_id
+ <where>
+ <if test="stockType != null and stockType != ''">
+ and a.stock_type = #{stockType}
+ </if>
+ <if test="status != null and status != ''">
+ and s.status = #{status}
+ </if>
+ <if test="userId != null">
+ and u.id = #{userId}
+ </if>
+ <if test="phone != null and phone != ''">
+ and u.phone like concat('%',#{phone},'%')
+ </if>
+ </where>
+ ORDER BY buy_date DESC
+ </select>
+
+ <select id="getStockAiOrderList" resultType="com.nq.vo.stock.ai.StockAiOrderTypeVO">
+ SELECT s.id, user_id, stock_ai_id, buy_date, buy_amount, remain_amount, real_earning, s.status, audit_date,
+ a.stock_name, a.stock_type
+ FROM stock_ai_order s
+ LEFT JOIN stock_ai a ON a.id = s.stock_ai_id
+ <where>
+ <if test="status != null and status != ''">
+ and s.status = #{status}
+ </if>
+ <if test="userId != null">
+ and user_id = #{userId}
+ </if>
+ </where>
+ ORDER BY buy_date DESC
+ </select>
+
+</mapper>
--
Gitblit v1.9.3