Parcourir la source

1、添加redisson的使用

qmj il y a 6 mois
Parent
commit
30f121643f
36 fichiers modifiés avec 323 ajouts et 94 suppressions
  1. 53 0
      ruoyi-admin/src/main/java/com/ruoyi/app/order/MyTestController.java
  2. 23 10
      ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderController.java
  3. 7 6
      ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderRatingController.java
  4. 8 7
      ruoyi-admin/src/main/java/com/ruoyi/app/order/PosReviewController.java
  5. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/app/order/TaxiOrderController.java
  6. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java
  7. 2 1
      ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java
  8. 3 1
      ruoyi-admin/src/main/java/com/ruoyi/app/order/dto/OrderCreateInput.java
  9. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/app/order/dto/OrderPositionInfo.java
  10. 1 11
      ruoyi-admin/src/main/java/com/ruoyi/app/pay/PayController.java
  11. 1 11
      ruoyi-admin/src/main/java/com/ruoyi/app/pay/ZaloPayController.java
  12. 12 12
      ruoyi-admin/src/main/java/com/ruoyi/app/service/WalletService.java
  13. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/app/user/InfoUserController.java
  14. 4 2
      ruoyi-admin/src/main/java/com/ruoyi/app/user/UserPointController.java
  15. 3 1
      ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/PointOutput.java
  16. 3 0
      ruoyi-admin/src/main/resources/application.yml
  17. 5 1
      ruoyi-common/pom.xml
  18. 6 0
      ruoyi-framework/pom.xml
  19. 20 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedissonConfig.java
  20. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/controller/PosAppealController.java
  21. 5 3
      ruoyi-system/src/main/java/com/ruoyi/system/domain/OrderParent.java
  22. 3 3
      ruoyi-system/src/main/java/com/ruoyi/system/domain/PosAppeal.java
  23. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrder.java
  24. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderRating.java
  25. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/domain/PosReview.java
  26. 3 3
      ruoyi-system/src/main/java/com/ruoyi/system/domain/TaxiOrder.java
  27. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/domain/VipUserQuanyi.java
  28. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/OrderDTO.java
  29. 8 8
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosReviewMapper.java
  30. 4 0
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserWalletMapper.java
  31. 3 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/IUserWalletService.java
  32. 6 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserWalletServiceImpl.java
  33. 6 1
      ruoyi-system/src/main/resources/mapper/system/OrderParentMapper.xml
  34. 58 0
      ruoyi-system/src/main/resources/mapper/system/UserWalletMapper.xml
  35. 6 1
      ruoyi-system/target/classes/mapper/system/OrderParentMapper.xml
  36. 58 0
      ruoyi-system/target/classes/mapper/system/UserWalletMapper.xml

+ 53 - 0
ruoyi-admin/src/main/java/com/ruoyi/app/order/MyTestController.java

@@ -0,0 +1,53 @@
+package com.ruoyi.app.order;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.annotation.Anonymous;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.domain.UserWallet;
+import com.ruoyi.system.service.IUserWalletService;
+import com.ruoyi.system.utils.Auth;
+import com.ruoyi.system.utils.JwtUtil;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.math.BigDecimal;
+import java.util.concurrent.TimeUnit;
+
+@RestController
+@RequestMapping("/myTest")
+public class MyTestController {
+    @Autowired
+    private RedissonClient redissonClient;
+    @Autowired
+    private IUserWalletService userWalletService;
+
+    @Anonymous
+    @Auth
+    @GetMapping("/testWallect")
+    public AjaxResult testWallect(@RequestHeader String token, @RequestParam BigDecimal balance){
+        JwtUtil jwtUtil = new JwtUtil();
+        String id = jwtUtil.getusid(token);
+        UserWallet userWallet = userWalletService.getOne(new LambdaQueryWrapper<UserWallet>().eq(UserWallet::getUserId, Long.valueOf(id)));
+        String lockKey = "user:wallet:"+id;
+        RLock lock=redissonClient.getLock(lockKey);
+        try {
+            // 加锁
+            boolean islock = lock.tryLock(3, 10, TimeUnit.SECONDS);
+            if(islock){
+                userWalletService.updateUserWalletWithLock(userWallet.getId(),userWallet.getVersion(),null,balance);
+                // 业务逻辑
+                return AjaxResult.success("成功");
+            }else {
+                return AjaxResult.error("失败");
+            }
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } finally {
+            // 解锁
+            lock.unlock();
+        }
+    }
+
+}

+ 23 - 10
ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderController.java

@@ -27,6 +27,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.domain.*;
 import com.ruoyi.system.domain.vo.OrderDTO;
@@ -107,6 +108,8 @@ public class PosOrderController extends BaseController {
     private IPosOrderRatingService posOrderRatingService;
     @Autowired
     private IFoodStatisticsService foodStatisticsService;
+    @Autowired
+    private IOrderParentService orderParentService;
 
 
     //查询用户足迹
@@ -908,12 +911,17 @@ public class PosOrderController extends BaseController {
         queryWrapper.apply("NOT (state = 0 AND collect_payment = 0)");
         IPage<PosOrder> list = posOrderService.page(palist, queryWrapper);
         List<PosOrder> orlist = list.getRecords();
+List<String > parentDdIds = orlist.stream().map(PosOrder::getParentDdId).collect(Collectors.toList());
+        List<OrderParent> orderParents =new ArrayList<>();
+        if(!parentDdIds.isEmpty()){
+            orderParents= orderParentService.list(new LambdaQueryWrapper<>(OrderParent.class).in(OrderParent::getDdId, parentDdIds));
+        }
         JSONArray arr = new JSONArray();
         for (int i = 0; i < orlist.size(); i++) {
             JSONObject org = new JSONObject();
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
             org.put("id", orlist.get(i).getId());
-            org.put("ddId", orlist.get(i).getDdId());
+            org.put("ddId", orlist.get(i).getDdId().toString());
             org.put("shanghu", infoUserService.getById(orlist.get(i).getShId()));
             org.put("store", posStoreService.getById(orlist.get(i).getMdId()));
             org.put("cretim", sdf.format(orlist.get(i).getCretim()));
@@ -951,6 +959,11 @@ public class PosOrderController extends BaseController {
             org.put("pointsReduction", orlist.get(i).getPointsReduction());
             org.put("sdTime", orlist.get(i).getSdTime());
             org.put("payType", orlist.get(i).getPayType());
+            int finalI = i;
+            org.put("parentRemarks","");
+            if(StringUtils.isNotEmpty(orlist.get(i).getParentDdId())){
+            orderParents.stream().filter(item->item.getDdId().equals(orlist.get(finalI).getParentDdId())).findFirst().ifPresent(a-> org.put("parentRemarks",a.getRemarks()));
+            }
             arr.add(org);
         }
         return success(arr);
@@ -1262,12 +1275,12 @@ public class PosOrderController extends BaseController {
             walletQuery.eq(UserWallet::getUserId, userId);
             UserWallet userWallet = userWalletService.getOne(walletQuery);
             if (ObjectUtil.isNotNull(userWallet)) {
-                if (userWallet.getPointsWallet().compareTo(Long.valueOf(orderDTO.getPoints())) >= 0) {
+                if (userWallet.getPointsWallet().compareTo(BigDecimal.valueOf(orderDTO.getPoints())) >= 0) {
                     walletQuery.eq(UserWallet::getVersion, userWallet.getVersion());
-                    userWallet.setPointsWallet(userWallet.getPointsWallet() - orderDTO.getPoints());
+                    userWallet.setPointsWallet(userWallet.getPointsWallet().subtract(BigDecimal.valueOf(orderDTO.getPoints())));
                     userWallet.setVersion(userWallet.getVersion() + 1);
                     boolean update = userWalletService.update(userWallet, walletQuery);
-                    createPointTransaction(userId, Long.valueOf(orderDTO.getPoints()), userWallet.getPointsWallet(), orderDTO.getDdId(), "1");
+                    createPointTransaction(userId, BigDecimal.valueOf(orderDTO.getPoints()), userWallet.getPointsWallet(), orderDTO.getDdId().toString(), "1");
                     if (!update) {
                         throw new ServiceException(MessageUtils.message("no.points.update.fail"));
                     }
@@ -1284,7 +1297,7 @@ public class PosOrderController extends BaseController {
     /**
      * 创建积分流水
      */
-    private void createPointTransaction(Long userid, Long pointsChange, Long currentPoints, Long ddId, String type) {
+    private void createPointTransaction(Long userid, BigDecimal pointsChange, BigDecimal currentPoints, String ddId, String type) {
         WalletTransaction pointsTransaction = new WalletTransaction();
         pointsTransaction.setUserId(userid);
         if (type.equals("1")) {
@@ -1307,7 +1320,7 @@ public class PosOrderController extends BaseController {
      *
      * @param orderId
      */
-    private void redeemCoupons(VipUserQuanyi yh, VipUserQuanyi mdYh, Long orderId) {
+    private void redeemCoupons(VipUserQuanyi yh, VipUserQuanyi mdYh, String orderId) {
         if (ObjectUtil.isNotNull(yh)) {
             yh.setState("1");
             yh.setOrderId(orderId);
@@ -1534,7 +1547,7 @@ public class PosOrderController extends BaseController {
             }
             //退款、作废退回积分
             if ((posOrder.getState() == 7 || posOrder.getState() == 11) && posOrder.getPoints() != null && posOrder.getPoints() > 0) {
-                returnPoints(posOrder.getUserId(), posOrder.getId(), Long.valueOf(posOrder.getPoints()));
+                returnPoints(posOrder.getUserId(), posOrder.getDdId(), Long.valueOf(posOrder.getPoints()));
             }
             return toAjax(posOrderService.updatePosOrder(posOrder));
         } else {
@@ -1553,7 +1566,7 @@ public class PosOrderController extends BaseController {
      * @param ddId
      * @param points
      */
-    public void returnPoints(Long userId, Long ddId, Long points) {
+    public void returnPoints(Long userId, String ddId, Long points) {
         LambdaQueryWrapper<UserWallet> walletQuery = new LambdaQueryWrapper<>();
         walletQuery.eq(UserWallet::getUserId, userId);
         UserWallet userWallet = userWalletService.getOne(walletQuery);
@@ -1561,10 +1574,10 @@ public class PosOrderController extends BaseController {
         //该订单不存在退回的积分记录
         if (ObjectUtil.isNotNull(userWallet) && transaction == null) {
             walletQuery.eq(UserWallet::getVersion, userWallet.getVersion());
-            userWallet.setPointsWallet(userWallet.getPointsWallet() + points);
+            userWallet.setPointsWallet(userWallet.getPointsWallet().add(BigDecimal.valueOf(points)));
             userWallet.setVersion(userWallet.getVersion() + 1);
             boolean update = userWalletService.update(userWallet, walletQuery);
-            createPointTransaction(userId, Long.valueOf(points), userWallet.getPointsWallet(), ddId, "2");
+            createPointTransaction(userId, BigDecimal.valueOf(points), userWallet.getPointsWallet(), ddId.toString(), "2");
             if (!update) {
                 throw new ServiceException(MessageUtils.message("no.points.update.fail"));
             }

+ 7 - 6
ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderRatingController.java

@@ -1,5 +1,6 @@
 package com.ruoyi.app.order;
 
+import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
@@ -78,7 +79,7 @@ public class PosOrderRatingController extends BaseController
     /**
      * 添加积分
      */
-    private void addPoint(Long userid, Long ddId){
+    private void addPoint(Long userid, String ddId){
         SysPointControl control = pointControlService.getById(1);
         //开启评论获得积分
         if(control.getReviewEnable().equals(1L)){
@@ -89,13 +90,13 @@ public class PosOrderRatingController extends BaseController
             if(userWallet==null){
                 userWallet=new UserWallet();
                 userWallet.setUserId(userid);
-                userWallet.setPointsWallet(control.getReviewPoints());
+                userWallet.setPointsWallet(BigDecimal.valueOf(control.getReviewPoints()));
                 createPointTransaction(userid,control.getReviewPoints(),userWallet.getPointsWallet(),ddId);
                 userWalletService.save(userWallet);
             }else{
-                Long userPoint = userWallet.getPointsWallet();
+                BigDecimal userPoint = userWallet.getPointsWallet();
                 Long point = control.getReviewPoints();
-                Long newPoint = userPoint+point;
+                BigDecimal newPoint = userPoint.add(BigDecimal.valueOf(point));
                 userWallet.setPointsWallet(newPoint);
                 int oldVersion = userWallet.getVersion();
                 userWallet.setVersion(userWallet.getVersion()+1);
@@ -113,13 +114,13 @@ public class PosOrderRatingController extends BaseController
     /**
      * 创建积分流水
      */
-    private void createPointTransaction(Long userid,Long pointsChange,Long currentPoints,Long ddId){
+    private void createPointTransaction(Long userid, Long pointsChange, BigDecimal currentPoints, String ddId){
         WalletTransaction pointsTransaction = new WalletTransaction();
         pointsTransaction.setUserId(userid);
         pointsTransaction.setChange("+"+pointsChange);
         pointsTransaction.setCurrentBalance(currentPoints.toString());
         pointsTransaction.setType("0");
-        pointsTransaction.setDdId(ddId);
+        pointsTransaction.setDdId(String.valueOf(ddId));
         pointsTransaction.setCreateTime(new Date());
         pointsTransactionService.save(pointsTransaction);
     }

+ 8 - 7
ruoyi-admin/src/main/java/com/ruoyi/app/order/PosReviewController.java

@@ -1,5 +1,6 @@
 package com.ruoyi.app.order;
 
+import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.List;
@@ -112,7 +113,7 @@ public class PosReviewController extends BaseController
     /**
      * 添加积分
      */
-    private void addPoint(Long userid, Long ddId){
+    private void addPoint(Long userid, String ddId){
         SysPointControl control = pointControlService.getById(1);
         //开启评论获得积分
         if(control.getReviewEnable().equals(1L)){
@@ -123,13 +124,13 @@ public class PosReviewController extends BaseController
             if(userWallet==null){
                 userWallet=new UserWallet();
                 userWallet.setUserId(userid);
-                userWallet.setPointsWallet(control.getReviewPoints());
-                createPointTransaction(userid,control.getReviewPoints(),userWallet.getPointsWallet(),ddId);
+                userWallet.setPointsWallet(BigDecimal.valueOf(control.getReviewPoints()));
+                createPointTransaction(userid, BigDecimal.valueOf(control.getReviewPoints()),userWallet.getPointsWallet(),ddId.toString());
                 userWalletService.save(userWallet);
             }else{
-                Long userPoint = userWallet.getPointsWallet();
+                BigDecimal userPoint = userWallet.getPointsWallet();
                 Long point = control.getReviewPoints();
-                Long newPoint = userPoint+point;
+                BigDecimal newPoint = userPoint.add(BigDecimal.valueOf(point));
                 userWallet.setPointsWallet(newPoint);
                 int oldVersion = userWallet.getVersion();
                 userWallet.setVersion(userWallet.getVersion()+1);
@@ -138,7 +139,7 @@ public class PosReviewController extends BaseController
                if(!update){
                    throw new ServiceException(MessageUtils.message("no.points.update.fail"));
                }
-                createPointTransaction(userid,control.getReviewPoints(),userWallet.getPointsWallet(),ddId);
+                createPointTransaction(userid,BigDecimal.valueOf(control.getReviewPoints()),userWallet.getPointsWallet(),ddId.toString());
             }
 
         }
@@ -147,7 +148,7 @@ public class PosReviewController extends BaseController
     /**
      * 创建积分流水
      */
-    private void createPointTransaction(Long userid,Long pointsChange,Long currentPoints,Long ddId){
+    private void createPointTransaction(Long userid,BigDecimal pointsChange,BigDecimal currentPoints,String ddId){
         WalletTransaction pointsTransaction = new WalletTransaction();
         pointsTransaction.setUserId(userid);
         pointsTransaction.setChange("+"+pointsChange);

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/app/order/TaxiOrderController.java

@@ -37,7 +37,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
 
 /**
  * TaxiOrderController
- * 
+ *
  * @author ruoyi
  * @date 2024-01-26
  */
@@ -226,7 +226,7 @@ public class TaxiOrderController extends BaseController
         DateUtil date = new DateUtil();
         taxiOrder.setUserId(Long.valueOf(id));
         taxiOrder.setReleaseId(Long.valueOf(id));
-        taxiOrder.setDdId(date.getTimeMillis());
+        taxiOrder.setDdId(date.getTimeMillis().toString());
         int org = taxiOrderService.insertTaxiOrder(taxiOrder);
         if(org==1){
             return success(MessageUtils.message("no.order.place.success"), taxiOrder);

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java

@@ -62,7 +62,7 @@ public class TestTask {
             posOrderService.saveOrUpdate(posOrder);
             try {
                 if(posOrder.getPoints()!=null && posOrder.getPoints()>0){
-                    posorder.returnPoints(posOrder.getUserId(),Long.valueOf(posOrder.getPoints()),posOrder.getDdId());
+                    posorder.returnPoints(posOrder.getUserId(),posOrder.getDdId(),Long.valueOf(posOrder.getPoints()));
                 }
             }catch (Exception e){
                 logger.warn("定时任务取消订单,积分返还失败订单号: {},异常信息:{}", posOrder.getId(),e.getMessage());

+ 2 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java

@@ -86,6 +86,7 @@ public class UserOrderController extends BaseController {
         orderParent.setShdzId(input.getShdzId());
         orderParent.setShAddress(shdz);
         orderParent.setType(input.getType());
+        orderParent.setRemarks(input.getRemarks());
         orderParentService.save(orderParent);
     }
     //创建子订单
@@ -110,7 +111,7 @@ public class UserOrderController extends BaseController {
             PosOrder posOrder = new PosOrder();
             posOrder.setShdzId(input.getShdzId());
             // 设置子订单的基本信息
-            posOrder.setDdId(Long.parseLong(subddId));
+            posOrder.setDdId(subddId);
             posOrder.setParentDdId(input.getDdId().toString()); // 设置父订单ID
             posOrder.setCretim(new Date());
             posOrder.setState(0L); // 初始状态

+ 3 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/dto/OrderCreateInput.java

@@ -11,7 +11,7 @@ public class OrderCreateInput {
     private static final long serialVersionUID = 1L;
 
     /** 订单号 */
-    private Long ddId;
+    private String ddId;
     /** 收货地址id */
     private Long shdzId;
     /**
@@ -37,6 +37,8 @@ public class OrderCreateInput {
 
     /** 桌号 */
     private String tableNum;
+    /** 整单备注 */
+    private String remarks;
 
     private List<OrderCreatItem> items;
 }

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/order/dto/OrderPositionInfo.java

@@ -9,7 +9,7 @@ public class OrderPositionInfo {
     /**
      * 订单号
      */
-    public Long ddId;
+    public String ddId;
 
     /**
      * 配送时间

+ 1 - 11
ruoyi-admin/src/main/java/com/ruoyi/app/pay/PayController.java

@@ -155,17 +155,7 @@ public class PayController extends BaseController {
 
 
 
-    /**
-     * 设置订单取消状态
-     *
-     * @param orderId
-     */
-    public void setCancelPayOrder(Long orderId) {
-        PosOrder order = new PosOrder();
-        order.setId(orderId);
-        order.setState(10L);
-        posOrderService.saveOrUpdate(order);
-    }
+
 
 
     //接收IPN支付回调

+ 1 - 11
ruoyi-admin/src/main/java/com/ruoyi/app/pay/ZaloPayController.java

@@ -219,17 +219,7 @@ public class ZaloPayController extends BaseController {
         PayPush push = new PayPush();
 
     }
-    /**
-     * 设置订单取消状态
-     * @param orderId
-     */
-    public void setCancelPayOrder(Long orderId)
-    {
-        PosOrder order = new PosOrder();
-        order.setId(orderId);
-        order.setState(10L);
-        posOrderService.saveOrUpdate(order);
-    }
+
     //退款设置账单
     private void setRefoudBilling(UserBilling billing, String id, PayVN payVN)
     {

+ 12 - 12
ruoyi-admin/src/main/java/com/ruoyi/app/service/WalletService.java

@@ -34,7 +34,7 @@ public class WalletService {
      */
     @Retryable(value = ConcurrentUpdateException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 1.5))
     @Transactional(rollbackFor = Exception.class)
-    public void returnPoints(Long userId, Long ddId, Long points) {
+    public void returnPoints(Long userId, String ddId, Long points) {
         log.info("开始处理积分退回,用户ID: {}, 订单ID: {}, 积分: {}", userId, ddId, points);
 
         // 1. 参数校验
@@ -61,7 +61,7 @@ public class WalletService {
      */
     @Retryable(value = ConcurrentUpdateException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 1.5))
     @Transactional(rollbackFor = Exception.class)
-    public void returnBalance(Long userId, Long ddId, BigDecimal amount) {
+    public void returnBalance(Long userId, String ddId, BigDecimal amount) {
         log.info("开始处理余额退回,用户ID: {}, 订单ID: {}, 金额: {}", userId, ddId, amount);
 
         // 1. 参数校验
@@ -82,11 +82,11 @@ public class WalletService {
     /**
      * 校验积分退回参数
      */
-    private void validateReturnPointsParams(Long userId, Long ddId, Long points) {
+    private void validateReturnPointsParams(Long userId, String ddId, Long points) {
         if (userId == null || userId <= 0) {
             throw new ServiceException("用户ID不能为空或无效");
         }
-        if (ddId == null || ddId <= 0) {
+        if (ddId == null || ddId.trim().isEmpty()) {
             throw new ServiceException("订单ID不能为空或无效");
         }
         if (points == null || points <= 0) {
@@ -97,11 +97,11 @@ public class WalletService {
     /**
      * 校验余额退回参数
      */
-    private void validateReturnBalanceParams(Long userId, Long ddId, BigDecimal amount) {
+    private void validateReturnBalanceParams(Long userId, String ddId, BigDecimal amount) {
         if (userId == null || userId <= 0) {
             throw new ServiceException("用户ID不能为空或无效");
         }
-        if (ddId == null || ddId <= 0) {
+        if (ddId == null || ddId.trim().isEmpty()) {
             throw new ServiceException("订单ID不能为空或无效");
         }
         if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
@@ -125,7 +125,7 @@ public class WalletService {
     /**
      * 检查积分退回是否重复
      */
-    private void checkDuplicateReturn(Long ddId) {
+    private void checkDuplicateReturn(String ddId) {
         WalletTransaction existingTransaction = pointsTransactionService.getOne(
                 new LambdaQueryWrapper<WalletTransaction>()
                         .eq(WalletTransaction::getDdId, ddId)
@@ -139,7 +139,7 @@ public class WalletService {
     /**
      * 检查余额退回是否重复
      */
-    private void checkDuplicateBalanceReturn(Long ddId) {
+    private void checkDuplicateBalanceReturn(String ddId) {
         WalletTransaction existingTransaction = pointsTransactionService.getOne(
                 new LambdaQueryWrapper<WalletTransaction>()
                         .eq(WalletTransaction::getDdId, ddId)
@@ -153,12 +153,12 @@ public class WalletService {
     /**
      * 执行积分退回
      */
-    private void executePointsReturn(UserWallet userWallet, BigDecimal points, Long ddId) {
+    private void executePointsReturn(UserWallet userWallet, BigDecimal points, String ddId) {
         // 计算新的积分余额
         BigDecimal newBalance = (userWallet.getPointsWallet() != null ? userWallet.getPointsWallet() : BigDecimal.ZERO).add( points);
 
         // 先创建积分流水记录
-        createTransaction(userWallet.getUserId(), points, newBalance, String.valueOf(ddId), "2");
+        createTransaction(userWallet.getUserId(), points, newBalance, ddId, "2");
 
         // 乐观锁更新钱包
         updateWalletWithOptimisticLock(userWallet, newBalance, null);
@@ -167,13 +167,13 @@ public class WalletService {
     /**
      * 执行余额退回
      */
-    private void executeBalanceReturn(UserWallet userWallet, BigDecimal amount, Long ddId) {
+    private void executeBalanceReturn(UserWallet userWallet, BigDecimal amount, String ddId) {
         // 计算新的余额
         BigDecimal currentBalance = userWallet.getBalanceWallet() != null ? userWallet.getBalanceWallet() : BigDecimal.ZERO;
         BigDecimal newBalance = currentBalance.add(amount);
 
         // 先创建余额流水记录
-        createTransaction(userWallet.getUserId(), amount, newBalance, ddId.toString(), "1");
+        createTransaction(userWallet.getUserId(), amount, newBalance, ddId, "1");
 
         // 乐观锁更新钱包
         updateWalletWithOptimisticLock(userWallet, null, newBalance);

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/app/user/InfoUserController.java

@@ -544,7 +544,7 @@ public class InfoUserController  extends BaseController
              if(userWallet==null){
                   user.setPointsWallet(0L);
              }else{
-                 user.setPointsWallet(userWallet.getPointsWallet());
+                 user.setPointsWallet(Long.valueOf(userWallet.getPointsWallet().toString()));
              }
             return success(user);
         }
@@ -699,7 +699,7 @@ public class InfoUserController  extends BaseController
             list.forEach(item->{
                 Optional<UserWallet> wallet=wallets.stream().filter(w->w.getUserId().equals(item.getUserId())).findFirst();
                 if(wallet.isPresent()){
-                    item.setPointsWallet(wallet.get().getPointsWallet());
+                    item.setPointsWallet(Long.valueOf(wallet.get().getPointsWallet().toString()));
                 }else{
                     item.setPointsWallet(0L);
                 }

+ 4 - 2
ruoyi-admin/src/main/java/com/ruoyi/app/user/UserPointController.java

@@ -23,6 +23,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.math.BigDecimal;
+
 /**
  * 用户积分
  * Controller
@@ -52,14 +54,14 @@ public class UserPointController extends BaseController {
         if (pointControl.getOrderUseEnable().equals(1L)) {
             UserWallet wallet = userWalletService.getOne(new LambdaQueryWrapper<UserWallet>().eq(UserWallet::getUserId, Long.valueOf(uid)));
             if(wallet!=null) {
-                Long point = wallet.getPointsWallet();
+                BigDecimal point = wallet.getPointsWallet();
                 PointOutput pointOutput = new PointOutput();
                 pointOutput.setPoints(point);
                 pointOutput.setBl(pointControl.getVndPerpoint());
                 return R.ok(pointOutput);
             }else{
                 PointOutput pointOutput = new PointOutput();
-                pointOutput.setPoints(0L);
+                pointOutput.setPoints(BigDecimal.ZERO);
                 pointOutput.setBl(pointControl.getVndPerpoint());
             }
         }

+ 3 - 1
ruoyi-admin/src/main/java/com/ruoyi/app/user/dto/PointOutput.java

@@ -2,10 +2,12 @@ package com.ruoyi.app.user.dto;
 
 import lombok.Data;
 
+import java.math.BigDecimal;
+
 @Data
 public class PointOutput {
     /** 积分 */
-    private Long points;
+    private BigDecimal points;
 
     /** 积分兑换金额比例 */
     private double bl;

+ 3 - 0
ruoyi-admin/src/main/resources/application.yml

@@ -94,6 +94,9 @@ spring:
         max-active: 8
         # #连接池最大阻塞等待时间(使用负值表示没有限制)
         max-wait: -1ms
+  redisson:
+    address: redis://127.0.0.1:6379
+    # password: 不要写这一行
 
 # token配置
 token:

+ 5 - 1
ruoyi-common/pom.xml

@@ -65,7 +65,11 @@
 			<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
 			<version>3.5.2</version>
 		</dependency>
-
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+            <version>2.13.0</version>
+        </dependency>
         <!-- 阿里JSON解析器 -->
         <dependency>
             <groupId>com.alibaba.fastjson2</groupId>

+ 6 - 0
ruoyi-framework/pom.xml

@@ -67,6 +67,12 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-websocket</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>2.15.2</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

+ 20 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedissonConfig.java

@@ -0,0 +1,20 @@
+package com.ruoyi.framework.config;
+
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RedissonConfig {
+
+    @Bean
+    public RedissonClient redissonClient() {
+        Config config = new Config();
+        config.useSingleServer()
+                .setAddress("redis://127.0.0.1:6379");
+        // 如果有密码,添加 .setPassword("你的密码");
+        return Redisson.create(config);
+    }
+}

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/controller/PosAppealController.java

@@ -68,7 +68,7 @@ public class PosAppealController extends BaseController
     @Anonymous
 //    @Auth
     @GetMapping("/apiList")
-    public AjaxResult list(Long ddId,String userType)
+    public AjaxResult list(String ddId,String userType)
     {
         PosAppeal posAppeal = new PosAppeal();
         posAppeal.setDdId(ddId);

+ 5 - 3
ruoyi-system/src/main/java/com/ruoyi/system/domain/OrderParent.java

@@ -60,12 +60,12 @@ public class OrderParent
     private String paymentMethod;
 
     /** 支付时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date paymentTime;
-
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
-
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date updateTime;
 
     private String ddId;
@@ -88,6 +88,8 @@ public class OrderParent
      * 订单类型:0外送,1自取,2堂食
      */
     private Long type;
+    /** 整单备注 */
+    private String remarks;
     @TableField(exist = false)
     private List<PosOrder> items;
 

+ 3 - 3
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosAppeal.java

@@ -31,7 +31,7 @@ public class PosAppeal
 
     /** 订单号 */
     @Excel(name = "订单号")
-    private Long ddId;
+    private String ddId;
 
     /** 用户类型 */
     @Excel(name = "用户类型")
@@ -64,12 +64,12 @@ public class PosAppeal
     {
         return id;
     }
-    public void setDdId(Long ddId) 
+    public void setDdId(String ddId) 
     {
         this.ddId = ddId;
     }
 
-    public Long getDdId() 
+    public String getDdId() 
     {
         return ddId;
     }

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrder.java

@@ -33,7 +33,7 @@ public class PosOrder {
     /**
      * 订单号
      */
-    private Long ddId;
+    private String ddId;
 
     /**
      * 商家id

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderRating.java

@@ -34,7 +34,7 @@ public class PosOrderRating
 
     /** 订单号 */
     @Excel(name = "订单号")
-    private Long ddId;
+    private String ddId;
 
     /** 消费用户id */
     @Excel(name = "消费用户id")

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/PosReview.java

@@ -35,7 +35,7 @@ public class PosReview
 
     /** 订单id */
     @Excel(name = "订单id")
-    private Long ddId;
+    private String ddId;
 
     /** 门店id */
     @Excel(name = "门店id")

+ 3 - 3
ruoyi-system/src/main/java/com/ruoyi/system/domain/TaxiOrder.java

@@ -36,7 +36,7 @@ public class TaxiOrder
 
     /** 订单id */
     @Excel(name = "订单id")
-    private Long ddId;
+    private String ddId;
 
     /** 用户id */
     private Long userId;
@@ -125,12 +125,12 @@ public class TaxiOrder
     {
         return id;
     }
-    public void setDdId(Long ddId) 
+    public void setDdId(String ddId) 
     {
         this.ddId = ddId;
     }
 
-    public Long getDdId() 
+    public String getDdId() 
     {
         return ddId;
     }

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/VipUserQuanyi.java

@@ -103,7 +103,7 @@ public class VipUserQuanyi
      */
     private String type;
 
-    private Long orderId;
+    private String orderId;
 
     /**
      * 商家id

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/OrderDTO.java

@@ -17,7 +17,7 @@ public class OrderDTO {
     private Long id;
 
     /** 订单号 */
-    private Long ddId;
+    private String ddId;
 
     /** 商家id */
 

+ 8 - 8
ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosReviewMapper.java

@@ -10,17 +10,17 @@ import org.apache.ibatis.annotations.Select;
 
 /**
  * reviewMapper接口
- * 
+ *
  * @author ruoyi
  * @date 2023-06-08
  */
 public interface PosReviewMapper  extends BaseMapper<PosReview>
 {
     @Select("SELECT * FROM pos_review WHERE dd_id = #{ddid}")  //查询语句
-    PosReview getrewiew(@Param("ddid") Long ddid);  //反回结果
+    PosReview getrewiew(@Param("ddid") String ddid);  //反回结果
     /**
      * 查询review
-     * 
+     *
      * @param id review主键
      * @return review
      */
@@ -28,7 +28,7 @@ public interface PosReviewMapper  extends BaseMapper<PosReview>
 
     /**
      * 查询review列表
-     * 
+     *
      * @param posReview review
      * @return review集合
      */
@@ -36,7 +36,7 @@ public interface PosReviewMapper  extends BaseMapper<PosReview>
 
     /**
      * 新增review
-     * 
+     *
      * @param posReview review
      * @return 结果
      */
@@ -44,7 +44,7 @@ public interface PosReviewMapper  extends BaseMapper<PosReview>
 
     /**
      * 修改review
-     * 
+     *
      * @param posReview review
      * @return 结果
      */
@@ -52,7 +52,7 @@ public interface PosReviewMapper  extends BaseMapper<PosReview>
 
     /**
      * 删除review
-     * 
+     *
      * @param id review主键
      * @return 结果
      */
@@ -60,7 +60,7 @@ public interface PosReviewMapper  extends BaseMapper<PosReview>
 
     /**
      * 批量删除review
-     * 
+     *
      * @param ids 需要删除的数据主键集合
      * @return 结果
      */

+ 4 - 0
ruoyi-system/src/main/java/com/ruoyi/system/mapper/UserWalletMapper.java

@@ -1,8 +1,10 @@
 package com.ruoyi.system.mapper;
 
+import java.math.BigDecimal;
 import java.util.List;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.ruoyi.system.domain.UserWallet;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * 用户钱包 Mapper接口
@@ -44,6 +46,8 @@ public interface UserWalletMapper  extends BaseMapper<UserWallet>
      */
     public int updateUserWallet(UserWallet userWallet);
 
+    public int updateUserWalletWithLock(@Param("id") Long id, @Param("version") int version, @Param("pointsWallet") BigDecimal pointsWallet, @Param("balanceWallet") BigDecimal balanceWallet);
+
     /**
      * 删除【请填写功能名称】
      *

+ 3 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/IUserWalletService.java

@@ -3,6 +3,7 @@ package com.ruoyi.system.service;
 import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ruoyi.system.domain.UserWallet;
+import java.math.BigDecimal;
 
 /**
  * 用户钱包 Service接口
@@ -44,6 +45,8 @@ public interface IUserWalletService extends IService<UserWallet>
      */
     public int updateUserWallet(UserWallet userWallet);
 
+    public int updateUserWalletWithLock(Long id, int version, BigDecimal pointsWallet, BigDecimal balanceWallet);
+
     /**
      * 批量删除【请填写功能名称】
      *

+ 6 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserWalletServiceImpl.java

@@ -1,5 +1,6 @@
 package com.ruoyi.system.service.impl;
 
+import java.math.BigDecimal;
 import java.util.List;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -69,6 +70,11 @@ public class UserWalletServiceImpl extends ServiceImpl<BaseMapper<UserWallet>,Us
         return userWalletMapper.updateUserWallet(userWallet);
     }
 
+    @Override
+    public int updateUserWalletWithLock(Long id, int version, BigDecimal pointsWallet, BigDecimal balanceWallet) {
+        return userWalletMapper.updateUserWalletWithLock(id, version, pointsWallet, balanceWallet);
+    }
+
     /**
      * 批量删除【请填写功能名称】
      *

+ 6 - 1
ruoyi-system/src/main/resources/mapper/system/OrderParentMapper.xml

@@ -19,10 +19,11 @@
         <result property="tableNum"    column="table_num"    />
         <result property="shdzId"    column="shdz_id"    />
         <result property="shAddress"    column="sh_address"    />
+        <result property="remarks"    column="remarks"    />
     </resultMap>
 
     <sql id="selectOrderParentVo">
-        select id, user_id, order_status, total_amount, total_discount, actual_pay_amount, payment_method, payment_time, create_time, update_time, dd_id, table_num, shdz_id, sh_address from order_parent
+        select id, user_id, order_status, total_amount, total_discount, actual_pay_amount, payment_method, payment_time, create_time, update_time, dd_id, table_num, shdz_id, sh_address, remarks from order_parent
     </sql>
 
     <select id="selectOrderParentList" parameterType="OrderParent" resultMap="OrderParentResult">
@@ -39,6 +40,7 @@
             <if test="tableNum != null  and tableNum != ''"> and table_num = #{tableNum}</if>
             <if test="shdzId != null"> and shdz_id = #{shdzId}</if>
             <if test="shAddress != null  and shAddress != ''"> and sh_address = #{shAddress}</if>
+            <if test="remarks != null  and remarks != ''"> and remarks = #{remarks}</if>
         </where>
     </select>
 
@@ -64,6 +66,7 @@
             <if test="tableNum != null and tableNum != ''">table_num,</if>
             <if test="shdzId != null">shdz_id,</if>
             <if test="shAddress != null and shAddress != ''">sh_address,</if>
+            <if test="remarks != null and remarks != ''">remarks,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -80,6 +83,7 @@
             <if test="tableNum != null and tableNum != ''">#{tableNum},</if>
             <if test="shdzId != null">#{shdzId},</if>
             <if test="shAddress != null and shAddress != ''">#{shAddress},</if>
+            <if test="remarks != null and remarks != ''">#{remarks},</if>
         </trim>
     </insert>
 
@@ -99,6 +103,7 @@
             <if test="tableNum != null and tableNum != ''">table_num = #{tableNum},</if>
             <if test="shdzId != null">shdz_id = #{shdzId},</if>
             <if test="shAddress != null and shAddress != ''">sh_address = #{shAddress},</if>
+            <if test="remarks != null and remarks != ''">remarks = #{remarks},</if>
         </trim>
         where id = #{id}
     </update>

+ 58 - 0
ruoyi-system/src/main/resources/mapper/system/UserWalletMapper.xml

@@ -56,6 +56,64 @@
         where id = #{id}
     </update>
 
+    <!-- 检查余额是否足够 -->
+    <select id="checkBalanceSufficient" resultType="boolean">
+        select 
+        <if test="pointsWallet != null and balanceWallet != null">
+            (points_wallet + (#{pointsWallet}) >= 0) and (balance_wallet + (#{balanceWallet}) >= 0)
+        </if>
+        <if test="pointsWallet != null and balanceWallet == null">
+            points_wallet + (#{pointsWallet}) >= 0
+        </if>
+        <if test="pointsWallet == null and balanceWallet != null">
+            balance_wallet + (#{balanceWallet}) >= 0
+        </if>
+        from user_wallet 
+        where id = #{id} and version = #{version}
+    </select>
+
+    <!-- 获取余额检查结果详情 -->
+    <select id="getBalanceCheckResult" resultType="map">
+        select 
+            id,
+            points_wallet as currentPointsWallet,
+            balance_wallet as currentBalanceWallet,
+            version,
+            <if test="pointsWallet != null">
+                points_wallet + (#{pointsWallet}) as afterPointsWallet,
+                (points_wallet + (#{pointsWallet}) >= 0) as pointsWalletSufficient,
+            </if>
+            <if test="balanceWallet != null">
+                balance_wallet + (#{balanceWallet}) as afterBalanceWallet,
+                (balance_wallet + (#{balanceWallet}) >= 0) as balanceWalletSufficient,
+            </if>
+            <if test="pointsWallet != null and balanceWallet != null">
+                ((points_wallet + (#{pointsWallet}) >= 0) and (balance_wallet + (#{balanceWallet}) >= 0)) as allSufficient
+            </if>
+            <if test="pointsWallet != null and balanceWallet == null">
+                (points_wallet + (#{pointsWallet}) >= 0) as allSufficient
+            </if>
+            <if test="pointsWallet == null and balanceWallet != null">
+                (balance_wallet + (#{balanceWallet}) >= 0) as allSufficient
+            </if>
+        from user_wallet 
+        where id = #{id} and version = #{version}
+    </select>
+
+    <update id="updateUserWalletWithLock">
+        update user_wallet 
+        <set>
+            version = version+1,
+            <if test="pointsWallet != null">points_wallet = points_wallet + (#{pointsWallet}),</if>
+            <if test="balanceWallet != null">balance_wallet = balance_wallet + (#{balanceWallet}),</if>
+        </set>
+        <where>
+            id = #{id} and version = #{version}
+            <if test="pointsWallet != null">and points_wallet + (#{pointsWallet}) >= 0</if>
+            <if test="balanceWallet != null">and balance_wallet + (#{balanceWallet}) >= 0</if>
+        </where>
+    </update>
+
     <delete id="deleteUserWalletById" parameterType="Long">
         delete from user_wallet where id = #{id}
     </delete>

+ 6 - 1
ruoyi-system/target/classes/mapper/system/OrderParentMapper.xml

@@ -19,10 +19,11 @@
         <result property="tableNum"    column="table_num"    />
         <result property="shdzId"    column="shdz_id"    />
         <result property="shAddress"    column="sh_address"    />
+        <result property="remarks"    column="remarks"    />
     </resultMap>
 
     <sql id="selectOrderParentVo">
-        select id, user_id, order_status, total_amount, total_discount, actual_pay_amount, payment_method, payment_time, create_time, update_time, dd_id, table_num, shdz_id, sh_address from order_parent
+        select id, user_id, order_status, total_amount, total_discount, actual_pay_amount, payment_method, payment_time, create_time, update_time, dd_id, table_num, shdz_id, sh_address, remarks from order_parent
     </sql>
 
     <select id="selectOrderParentList" parameterType="OrderParent" resultMap="OrderParentResult">
@@ -39,6 +40,7 @@
             <if test="tableNum != null  and tableNum != ''"> and table_num = #{tableNum}</if>
             <if test="shdzId != null"> and shdz_id = #{shdzId}</if>
             <if test="shAddress != null  and shAddress != ''"> and sh_address = #{shAddress}</if>
+            <if test="remarks != null  and remarks != ''"> and remarks = #{remarks}</if>
         </where>
     </select>
 
@@ -64,6 +66,7 @@
             <if test="tableNum != null and tableNum != ''">table_num,</if>
             <if test="shdzId != null">shdz_id,</if>
             <if test="shAddress != null and shAddress != ''">sh_address,</if>
+            <if test="remarks != null and remarks != ''">remarks,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -80,6 +83,7 @@
             <if test="tableNum != null and tableNum != ''">#{tableNum},</if>
             <if test="shdzId != null">#{shdzId},</if>
             <if test="shAddress != null and shAddress != ''">#{shAddress},</if>
+            <if test="remarks != null and remarks != ''">#{remarks},</if>
         </trim>
     </insert>
 
@@ -99,6 +103,7 @@
             <if test="tableNum != null and tableNum != ''">table_num = #{tableNum},</if>
             <if test="shdzId != null">shdz_id = #{shdzId},</if>
             <if test="shAddress != null and shAddress != ''">sh_address = #{shAddress},</if>
+            <if test="remarks != null and remarks != ''">remarks = #{remarks},</if>
         </trim>
         where id = #{id}
     </update>

+ 58 - 0
ruoyi-system/target/classes/mapper/system/UserWalletMapper.xml

@@ -56,6 +56,64 @@
         where id = #{id}
     </update>
 
+    <!-- 检查余额是否足够 -->
+    <select id="checkBalanceSufficient" resultType="boolean">
+        select 
+        <if test="pointsWallet != null and balanceWallet != null">
+            (points_wallet + (#{pointsWallet}) >= 0) and (balance_wallet + (#{balanceWallet}) >= 0)
+        </if>
+        <if test="pointsWallet != null and balanceWallet == null">
+            points_wallet + (#{pointsWallet}) >= 0
+        </if>
+        <if test="pointsWallet == null and balanceWallet != null">
+            balance_wallet + (#{balanceWallet}) >= 0
+        </if>
+        from user_wallet 
+        where id = #{id} and version = #{version}
+    </select>
+
+    <!-- 获取余额检查结果详情 -->
+    <select id="getBalanceCheckResult" resultType="map">
+        select 
+            id,
+            points_wallet as currentPointsWallet,
+            balance_wallet as currentBalanceWallet,
+            version,
+            <if test="pointsWallet != null">
+                points_wallet + (#{pointsWallet}) as afterPointsWallet,
+                (points_wallet + (#{pointsWallet}) >= 0) as pointsWalletSufficient,
+            </if>
+            <if test="balanceWallet != null">
+                balance_wallet + (#{balanceWallet}) as afterBalanceWallet,
+                (balance_wallet + (#{balanceWallet}) >= 0) as balanceWalletSufficient,
+            </if>
+            <if test="pointsWallet != null and balanceWallet != null">
+                ((points_wallet + (#{pointsWallet}) >= 0) and (balance_wallet + (#{balanceWallet}) >= 0)) as allSufficient
+            </if>
+            <if test="pointsWallet != null and balanceWallet == null">
+                (points_wallet + (#{pointsWallet}) >= 0) as allSufficient
+            </if>
+            <if test="pointsWallet == null and balanceWallet != null">
+                (balance_wallet + (#{balanceWallet}) >= 0) as allSufficient
+            </if>
+        from user_wallet 
+        where id = #{id} and version = #{version}
+    </select>
+
+    <update id="updateUserWalletWithLock">
+        update user_wallet 
+        <set>
+            version = version+1,
+            <if test="pointsWallet != null">points_wallet = points_wallet + (#{pointsWallet}),</if>
+            <if test="balanceWallet != null">balance_wallet = balance_wallet + (#{balanceWallet}),</if>
+        </set>
+        <where>
+            id = #{id} and version = #{version}
+            <if test="pointsWallet != null">and points_wallet + (#{pointsWallet}) >= 0</if>
+            <if test="balanceWallet != null">and balance_wallet + (#{balanceWallet}) >= 0</if>
+        </where>
+    </update>
+
     <delete id="deleteUserWalletById" parameterType="Long">
         delete from user_wallet where id = #{id}
     </delete>