Răsfoiți Sursa

Revert "代码迁移"

This reverts commit d95f3e05109b88e094590c4b79d1ac23b075020f.
lutong 2 săptămâni în urmă
părinte
comite
87da9b3848
79 a modificat fișierele cu 809 adăugiri și 12258 ștergeri
  1. 9 9
      alien-dining/src/main/java/shop/alien/dining/controller/StoreInfoController.java
  2. 17 18
      alien-dining/src/main/java/shop/alien/dining/controller/StoreOrderController.java
  3. 6 6
      alien-dining/src/main/java/shop/alien/dining/service/StoreInfoService.java
  4. 11 11
      alien-dining/src/main/java/shop/alien/dining/service/StoreOrderService.java
  5. 65 66
      alien-dining/src/main/java/shop/alien/dining/service/impl/CartServiceImpl.java
  6. 48 49
      alien-dining/src/main/java/shop/alien/dining/service/impl/DiningServiceImpl.java
  7. 2 2
      alien-dining/src/main/java/shop/alien/dining/service/impl/OrderLockServiceImpl.java
  8. 52 52
      alien-dining/src/main/java/shop/alien/dining/service/impl/StoreInfoServiceImpl.java
  9. 244 248
      alien-dining/src/main/java/shop/alien/dining/service/impl/StoreOrderServiceImpl.java
  10. 4 4
      alien-dining/src/main/java/shop/alien/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java
  11. 0 96
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCart.java
  12. 0 85
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCouponUsage.java
  13. 0 137
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisine.java
  14. 0 63
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisineCategory.java
  15. 0 63
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisineCombo.java
  16. 0 138
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrder.java
  17. 0 117
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderChangeLog.java
  18. 0 105
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderDetail.java
  19. 0 73
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderLock.java
  20. 0 96
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreTable.java
  21. 0 75
      alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreTableLog.java
  22. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCartMapper.java
  23. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCouponUsageMapper.java
  24. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineCategoryMapper.java
  25. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineComboMapper.java
  26. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineMapper.java
  27. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderChangeLogMapper.java
  28. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderDetailMapper.java
  29. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderLockMapper.java
  30. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderMapper.java
  31. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreTableLogMapper.java
  32. 0 7
      alien-entity/src/main/java/shop/alien/mapper/WeChatStoreTableMapper.java
  33. 2 2
      alien-store/src/main/java/shop/alien/store/AlienStoreApplication.java
  34. 76 85
      alien-store/src/main/java/shop/alien/store/controller/DiningServiceController.java
  35. 0 26
      alien-store/src/main/java/shop/alien/store/dining/annotation/OperationLog.java
  36. 0 28
      alien-store/src/main/java/shop/alien/store/dining/aspect/OperationLogAspect.java
  37. 0 388
      alien-store/src/main/java/shop/alien/store/dining/config/CartWebSocketProcess.java
  38. 0 48
      alien-store/src/main/java/shop/alien/store/dining/controller/DiningCollectController.java
  39. 0 307
      alien-store/src/main/java/shop/alien/store/dining/controller/DiningController.java
  40. 0 188
      alien-store/src/main/java/shop/alien/store/dining/controller/DiningCouponController.java
  41. 0 60
      alien-store/src/main/java/shop/alien/store/dining/controller/DiningFileUploadController.java
  42. 0 148
      alien-store/src/main/java/shop/alien/store/dining/controller/DiningUserController.java
  43. 0 128
      alien-store/src/main/java/shop/alien/store/dining/controller/PaymentController.java
  44. 0 135
      alien-store/src/main/java/shop/alien/store/dining/controller/StoreInfoController.java
  45. 0 579
      alien-store/src/main/java/shop/alien/store/dining/controller/StoreOrderController.java
  46. 0 34
      alien-store/src/main/java/shop/alien/store/dining/dto/ChangePhoneDto.java
  47. 0 56
      alien-store/src/main/java/shop/alien/store/dining/dto/UserProfileUpdateDto.java
  48. 0 20
      alien-store/src/main/java/shop/alien/store/dining/dto/VerifyTokenDto.java
  49. 0 48
      alien-store/src/main/java/shop/alien/store/dining/enums/OrderStatus.java
  50. 0 164
      alien-store/src/main/java/shop/alien/store/dining/feign/AlienStoreFeign.java
  51. 0 26
      alien-store/src/main/java/shop/alien/store/dining/listener/RedisKeyExpirationListener.java
  52. 0 121
      alien-store/src/main/java/shop/alien/store/dining/service/CartService.java
  53. 0 22
      alien-store/src/main/java/shop/alien/store/dining/service/DiningCollectService.java
  54. 0 101
      alien-store/src/main/java/shop/alien/store/dining/service/DiningCouponService.java
  55. 0 150
      alien-store/src/main/java/shop/alien/store/dining/service/DiningService.java
  56. 0 48
      alien-store/src/main/java/shop/alien/store/dining/service/DiningUserService.java
  57. 0 61
      alien-store/src/main/java/shop/alien/store/dining/service/OrderLockService.java
  58. 0 35
      alien-store/src/main/java/shop/alien/store/dining/service/SseService.java
  59. 0 67
      alien-store/src/main/java/shop/alien/store/dining/service/StoreInfoService.java
  60. 0 189
      alien-store/src/main/java/shop/alien/store/dining/service/StoreOrderService.java
  61. 0 1072
      alien-store/src/main/java/shop/alien/store/dining/service/impl/CartServiceImpl.java
  62. 0 39
      alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningCollectServiceImpl.java
  63. 0 471
      alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningCouponServiceImpl.java
  64. 0 691
      alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningServiceImpl.java
  65. 0 306
      alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningUserServiceImpl.java
  66. 0 118
      alien-store/src/main/java/shop/alien/store/dining/service/impl/OrderLockServiceImpl.java
  67. 0 180
      alien-store/src/main/java/shop/alien/store/dining/service/impl/SseServiceImpl.java
  68. 0 239
      alien-store/src/main/java/shop/alien/store/dining/service/impl/StoreInfoServiceImpl.java
  69. 0 2020
      alien-store/src/main/java/shop/alien/store/dining/service/impl/StoreOrderServiceImpl.java
  70. 0 75
      alien-store/src/main/java/shop/alien/store/dining/strategy/payment/PaymentStrategy.java
  71. 0 64
      alien-store/src/main/java/shop/alien/store/dining/strategy/payment/PaymentStrategyFactory.java
  72. 0 850
      alien-store/src/main/java/shop/alien/store/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java
  73. 0 227
      alien-store/src/main/java/shop/alien/store/dining/util/TokenUtil.java
  74. 0 856
      alien-store/src/main/java/shop/alien/store/dining/util/WXPayUtility.java
  75. 0 65
      alien-store/src/main/java/shop/alien/store/dining/util/WeChatPayUtil.java
  76. 0 76
      alien-store/src/main/java/shop/alien/store/dining/vo/DiningUserVo.java
  77. 0 40
      alien-store/src/main/java/shop/alien/store/dining/vo/TokenVerifyVo.java
  78. 273 0
      alien-store/src/main/java/shop/alien/store/feign/DiningServiceFeign.java
  79. 0 15
      wechat_dining_tables.sql

+ 9 - 9
alien-dining/src/main/java/shop/alien/dining/controller/StoreInfoController.java

@@ -5,9 +5,9 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
-import shop.alien.entity.store.wechat.WeChatStoreCuisine;
-import shop.alien.entity.store.wechat.WeChatStoreCuisineCategory;
-import shop.alien.entity.store.wechat.WeChatStoreTable;
+import shop.alien.entity.store.StoreCuisine;
+import shop.alien.entity.store.StoreCuisineCategory;
+import shop.alien.entity.store.StoreTable;
 import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
 import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
 import shop.alien.dining.service.StoreInfoService;
@@ -32,14 +32,14 @@ public class StoreInfoController {
 
     @ApiOperation(value = "根据门店ID查询桌号列表", notes = "查询指定门店下的所有桌号")
     @GetMapping("/tables")
-    public R<List<WeChatStoreTable>> getTablesByStoreId(
+    public R<List<StoreTable>> getTablesByStoreId(
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
         log.info("StoreInfoController.getTablesByStoreId?storeId={}", storeId);
         try {
             if (storeId == null) {
                 return R.fail("门店ID不能为空");
             }
-            List<WeChatStoreTable> tables = storeInfoService.getTablesByStoreId(storeId);
+            List<StoreTable> tables = storeInfoService.getTablesByStoreId(storeId);
             return R.data(tables);
         } catch (Exception e) {
             log.error("查询桌号列表失败: {}", e.getMessage(), e);
@@ -49,14 +49,14 @@ public class StoreInfoController {
 
     @ApiOperation(value = "根据门店ID查询菜品种类列表", notes = "查询指定门店下的所有菜品种类")
     @GetMapping("/categories")
-    public R<List<WeChatStoreCuisineCategory>> getCategoriesByStoreId(
+    public R<List<StoreCuisineCategory>> getCategoriesByStoreId(
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
         log.info("StoreInfoController.getCategoriesByStoreId?storeId={}", storeId);
         try {
             if (storeId == null) {
                 return R.fail("门店ID不能为空");
             }
-            List<WeChatStoreCuisineCategory> categories = storeInfoService.getCategoriesByStoreId(storeId);
+            List<StoreCuisineCategory> categories = storeInfoService.getCategoriesByStoreId(storeId);
             return R.data(categories);
         } catch (Exception e) {
             log.error("查询菜品种类列表失败: {}", e.getMessage(), e);
@@ -101,14 +101,14 @@ public class StoreInfoController {
 
     @ApiOperation(value = "根据菜品种类ID查询菜品信息列表", notes = "查询指定分类下的所有菜品信息")
     @GetMapping("/cuisines")
-    public R<List<WeChatStoreCuisine>> getCuisinesByCategoryId(
+    public R<List<StoreCuisine>> getCuisinesByCategoryId(
             @ApiParam(value = "菜品种类ID", required = true) @RequestParam Integer categoryId) {
         log.info("StoreInfoController.getCuisinesByCategoryId?categoryId={}", categoryId);
         try {
             if (categoryId == null) {
                 return R.fail("菜品种类ID不能为空");
             }
-            List<WeChatStoreCuisine> cuisines = storeInfoService.getCuisinesByCategoryId(categoryId);
+            List<StoreCuisine> cuisines = storeInfoService.getCuisinesByCategoryId(categoryId);
             return R.data(cuisines);
         } catch (Exception e) {
             log.error("查询菜品信息列表失败: {}", e.getMessage(), e);

+ 17 - 18
alien-dining/src/main/java/shop/alien/dining/controller/StoreOrderController.java

@@ -16,7 +16,6 @@ import shop.alien.dining.service.StoreOrderService;
 import shop.alien.dining.util.TokenUtil;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.*;
-import shop.alien.entity.store.wechat.*;
 import shop.alien.entity.store.dto.AddCartItemDTO;
 import shop.alien.entity.store.dto.CartDTO;
 import shop.alien.entity.store.dto.ChangeTableDTO;
@@ -26,8 +25,8 @@ import shop.alien.entity.store.vo.OrderInfoVO;
 import shop.alien.entity.store.vo.OrderDetailWithChangeLogVO;
 import shop.alien.entity.store.vo.StoreOrderPageVO;
 import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.WeChatStoreOrderDetailMapper;
-import shop.alien.mapper.WeChatStoreTableMapper;
+import shop.alien.mapper.StoreOrderDetailMapper;
+import shop.alien.mapper.StoreTableMapper;
 
 import javax.validation.Valid;
 import java.util.List;
@@ -49,8 +48,8 @@ public class StoreOrderController {
     private final StoreOrderService orderService;
     private final CartService cartService;
     private final SseService sseService;
-    private final WeChatStoreOrderDetailMapper orderDetailMapper;
-    private final WeChatStoreTableMapper storeTableMapper;
+    private final StoreOrderDetailMapper orderDetailMapper;
+    private final StoreTableMapper storeTableMapper;
     private final StoreInfoMapper storeInfoMapper;
 
     @ApiOperation(value = "获取购物车", notes = "根据桌号ID获取购物车信息")
@@ -246,7 +245,7 @@ public class StoreOrderController {
 
             // 设置不立即支付
             dto.setImmediatePay(0);
-            WeChatStoreOrder order = orderService.createOrder(dto);
+            StoreOrder order = orderService.createOrder(dto);
 
             // 转换为OrderSuccessVO
             shop.alien.entity.store.vo.OrderSuccessVO vo = new shop.alien.entity.store.vo.OrderSuccessVO();
@@ -282,7 +281,7 @@ public class StoreOrderController {
                 return R.fail("用户未登录");
             }
             
-            WeChatStoreOrder order = orderService.getOrderById(orderId);
+            StoreOrder order = orderService.getOrderById(orderId);
             if (order == null) {
                 return R.fail("订单不存在");
             }
@@ -348,7 +347,7 @@ public class StoreOrderController {
 
     @ApiOperation(value = "查询订单明细", notes = "根据订单ID查询订单明细列表")
     @GetMapping("/detail/list/{orderId}")
-    public R<List<WeChatStoreOrderDetail>> getOrderDetailList(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
+    public R<List<StoreOrderDetail>> getOrderDetailList(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
         log.info("StoreOrderController.getOrderDetailList?orderId={}", orderId);
         try {
             // 从 token 获取用户信息
@@ -356,12 +355,12 @@ public class StoreOrderController {
             if (userId == null) {
                 return R.fail("用户未登录");
             }
-            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<WeChatStoreOrderDetail> wrapper =
+            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StoreOrderDetail> wrapper =
                     new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
-            wrapper.eq(WeChatStoreOrderDetail::getOrderId, orderId);
-            wrapper.eq(WeChatStoreOrderDetail::getDeleteFlag, 0);
-            wrapper.orderByDesc(WeChatStoreOrderDetail::getCreatedTime);
-            List<WeChatStoreOrderDetail> details = orderDetailMapper.selectList(wrapper);
+            wrapper.eq(StoreOrderDetail::getOrderId, orderId);
+            wrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
+            wrapper.orderByDesc(StoreOrderDetail::getCreatedTime);
+            List<StoreOrderDetail> details = orderDetailMapper.selectList(wrapper);
             return R.data(details);
         } catch (Exception e) {
             log.error("查询订单明细失败: {}", e.getMessage(), e);
@@ -422,7 +421,7 @@ public class StoreOrderController {
             if (userId == null) {
                 return R.fail("用户未登录");
             }
-            Page<WeChatStoreOrder> page = new Page<>(current, size);
+            Page<StoreOrder> page = new Page<>(current, size);
             IPage<StoreOrderPageVO> result = orderService.getOrderPageWithCuisines(page, storeId, tableId, orderStatus, keyword);
             return R.data(result);
         } catch (Exception e) {
@@ -444,7 +443,7 @@ public class StoreOrderController {
             if (userId == null) {
                 return R.fail("用户未登录");
             }
-            Page<WeChatStoreOrder> page = new Page<>(current, size);
+            Page<StoreOrder> page = new Page<>(current, size);
             IPage<StoreOrderPageVO> result = orderService.getMyOrdersWithCuisines(page, type);
             return R.data(result);
         } catch (Exception e) {
@@ -524,7 +523,7 @@ public class StoreOrderController {
 
     @ApiOperation(value = "更新订单优惠券", notes = "重新选择优惠券")
     @PostMapping("/update-coupon")
-    public R<WeChatStoreOrder> updateOrderCoupon(@Valid @RequestBody shop.alien.entity.store.dto.UpdateOrderCouponDTO dto) {
+    public R<StoreOrder> updateOrderCoupon(@Valid @RequestBody shop.alien.entity.store.dto.UpdateOrderCouponDTO dto) {
         log.info("StoreOrderController.updateOrderCoupon?dto={}", dto);
         try {
             // 从 token 获取用户信息
@@ -532,7 +531,7 @@ public class StoreOrderController {
             if (userId == null) {
                 return R.fail("用户未登录");
             }
-            WeChatStoreOrder order = orderService.updateOrderCoupon(dto.getOrderId(), dto.getCouponId());
+            StoreOrder order = orderService.updateOrderCoupon(dto.getOrderId(), dto.getCouponId());
             return R.data(order);
         } catch (Exception e) {
             log.error("更新订单优惠券失败: {}", e.getMessage(), e);
@@ -560,7 +559,7 @@ public class StoreOrderController {
                 emptyCart.setTotalQuantity(0);
                 
                 // 查询桌号信息
-                WeChatStoreTable table = storeTableMapper.selectById(tableId);
+                StoreTable table = storeTableMapper.selectById(tableId);
                 if (table != null) {
                     emptyCart.setTableNumber(table.getTableNumber());
                     emptyCart.setStoreId(table.getStoreId());

+ 6 - 6
alien-dining/src/main/java/shop/alien/dining/service/StoreInfoService.java

@@ -1,8 +1,8 @@
 package shop.alien.dining.service;
 
-import shop.alien.entity.store.wechat.WeChatStoreCuisine;
-import shop.alien.entity.store.wechat.WeChatStoreCuisineCategory;
-import shop.alien.entity.store.wechat.WeChatStoreTable;
+import shop.alien.entity.store.StoreCuisine;
+import shop.alien.entity.store.StoreCuisineCategory;
+import shop.alien.entity.store.StoreTable;
 import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
 import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
 
@@ -22,7 +22,7 @@ public interface StoreInfoService {
      * @param storeId 门店ID
      * @return 桌号列表
      */
-    List<WeChatStoreTable> getTablesByStoreId(Integer storeId);
+    List<StoreTable> getTablesByStoreId(Integer storeId);
 
     /**
      * 根据门店ID查询菜品种类列表
@@ -30,7 +30,7 @@ public interface StoreInfoService {
      * @param storeId 门店ID
      * @return 菜品种类列表
      */
-    List<WeChatStoreCuisineCategory> getCategoriesByStoreId(Integer storeId);
+    List<StoreCuisineCategory> getCategoriesByStoreId(Integer storeId);
 
     /**
      * 根据菜品种类ID查询菜品信息列表
@@ -38,7 +38,7 @@ public interface StoreInfoService {
      * @param categoryId 菜品种类ID
      * @return 菜品信息列表
      */
-    List<WeChatStoreCuisine> getCuisinesByCategoryId(Integer categoryId);
+    List<StoreCuisine> getCuisinesByCategoryId(Integer categoryId);
 
     /**
      * 根据门店ID查询菜品种类及每个分类下的菜品列表(一次返回种类+菜品)

+ 11 - 11
alien-dining/src/main/java/shop/alien/dining/service/StoreOrderService.java

@@ -3,7 +3,7 @@ package shop.alien.dining.service;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
-import shop.alien.entity.store.wechat.WeChatStoreOrder;
+import shop.alien.entity.store.StoreOrder;
 import shop.alien.entity.store.dto.CreateOrderDTO;
 import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
 import shop.alien.entity.store.vo.OrderInfoVO;
@@ -17,7 +17,7 @@ import java.util.List;
  * @author system
  * @since 2025-01-XX
  */
-public interface StoreOrderService extends IService<WeChatStoreOrder> {
+public interface StoreOrderService extends IService<StoreOrder> {
 
     /**
      * 创建订单
@@ -25,7 +25,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param dto 创建订单DTO
      * @return 订单信息
      */
-    WeChatStoreOrder createOrder(CreateOrderDTO dto);
+    StoreOrder createOrder(CreateOrderDTO dto);
 
     /**
      * 支付订单
@@ -34,7 +34,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param payType 支付方式
      * @return 订单信息
      */
-    WeChatStoreOrder payOrder(Integer orderId, Integer payType);
+    StoreOrder payOrder(Integer orderId, Integer payType);
 
     /**
      * 取消订单
@@ -50,7 +50,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param orderNo 订单号
      * @return 订单信息
      */
-    WeChatStoreOrder getOrderByOrderNo(String orderNo);
+    StoreOrder getOrderByOrderNo(String orderNo);
 
     /**
      * 根据ID查询订单
@@ -58,7 +58,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param orderId 订单ID
      * @return 订单信息
      */
-    WeChatStoreOrder getOrderById(Integer orderId);
+    StoreOrder getOrderById(Integer orderId);
 
     /**
      * 分页查询订单列表
@@ -70,7 +70,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param keyword  搜索关键词(订单编号或菜品名称,限15字)
      * @return 订单分页列表
      */
-    IPage<WeChatStoreOrder> getOrderPage(Page<WeChatStoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
+    IPage<StoreOrder> getOrderPage(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
 
     /**
      * 分页查询订单列表(包含菜品信息)
@@ -82,7 +82,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param keyword  搜索关键词(订单编号或菜品名称,限15字)
      * @return 订单分页列表(包含菜品信息)
      */
-    IPage<StoreOrderPageVO> getOrderPageWithCuisines(Page<WeChatStoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
+    IPage<StoreOrderPageVO> getOrderPageWithCuisines(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
 
     /**
      * 完成订单(支付完成后调用)
@@ -107,7 +107,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param couponId 优惠券ID(可为空,表示不使用优惠券)
      * @return 订单信息
      */
-    WeChatStoreOrder updateOrderCoupon(Integer orderId, Integer couponId);
+    StoreOrder updateOrderCoupon(Integer orderId, Integer couponId);
 
     /**
      * 管理员重置餐桌(删除购物车数据、未支付/已取消的订单数据,并重置餐桌表)
@@ -156,7 +156,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param type 订单类型(0或"unpaid":未支付订单, 1或"history":历史订单)
      * @return 订单分页列表
      */
-    IPage<WeChatStoreOrder> getMyOrders(Page<WeChatStoreOrder> page, String type);
+    IPage<StoreOrder> getMyOrders(Page<StoreOrder> page, String type);
 
     /**
      * 查询我的订单(包含菜品信息)
@@ -165,7 +165,7 @@ public interface StoreOrderService extends IService<WeChatStoreOrder> {
      * @param type 订单类型(0或"unpaid":未支付订单, 1或"history":历史订单)
      * @return 订单分页列表(包含菜品信息)
      */
-    IPage<StoreOrderPageVO> getMyOrdersWithCuisines(Page<WeChatStoreOrder> page, String type);
+    IPage<StoreOrderPageVO> getMyOrdersWithCuisines(Page<StoreOrder> page, String type);
 
     /**
      * 换桌时迁移所有关联数据(订单、订单变更记录、优惠券使用记录等)

+ 65 - 66
alien-dining/src/main/java/shop/alien/dining/service/impl/CartServiceImpl.java

@@ -9,19 +9,19 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import shop.alien.dining.config.BaseRedisService;
 import shop.alien.dining.service.CartService;
-import shop.alien.entity.store.wechat.WeChatStoreCart;
-import shop.alien.entity.store.wechat.WeChatStoreCouponUsage;
-import shop.alien.entity.store.wechat.WeChatStoreCuisine;
+import shop.alien.entity.store.StoreCart;
+import shop.alien.entity.store.StoreCouponUsage;
+import shop.alien.entity.store.StoreCuisine;
 import shop.alien.entity.store.StoreInfo;
-import shop.alien.entity.store.wechat.WeChatStoreTable;
+import shop.alien.entity.store.StoreTable;
 import shop.alien.entity.store.dto.AddCartItemDTO;
 import shop.alien.entity.store.dto.CartDTO;
 import shop.alien.entity.store.dto.CartItemDTO;
-import shop.alien.mapper.WeChatStoreCartMapper;
-import shop.alien.mapper.WeChatStoreCouponUsageMapper;
-import shop.alien.mapper.WeChatStoreCuisineMapper;
+import shop.alien.mapper.StoreCartMapper;
+import shop.alien.mapper.StoreCouponUsageMapper;
+import shop.alien.mapper.StoreCuisineMapper;
 import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.WeChatStoreTableMapper;
+import shop.alien.mapper.StoreTableMapper;
 import shop.alien.dining.util.TokenUtil;
 
 import java.math.BigDecimal;
@@ -44,9 +44,8 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 public class CartServiceImpl implements CartService {
 
-    /** 与 APP 端(alien-store)隔离,避免同 Redis 实例下 tableId 冲突 */
-    private static final String CART_KEY_PREFIX = "wechat:cart:table:";
-    private static final String COUPON_USED_KEY_PREFIX = "wechat:coupon:used:table:";
+    private static final String CART_KEY_PREFIX = "cart:table:";
+    private static final String COUPON_USED_KEY_PREFIX = "coupon:used:table:";
     private static final int CART_EXPIRE_SECONDS = 24 * 60 * 60; // 24小时过期
 
     // 异步写入数据库的线程池(专门用于购物车数据库写入)
@@ -57,10 +56,10 @@ public class CartServiceImpl implements CartService {
     });
 
     private final BaseRedisService baseRedisService;
-    private final WeChatStoreTableMapper storeTableMapper;
-    private final WeChatStoreCuisineMapper storeCuisineMapper;
-    private final WeChatStoreCartMapper storeCartMapper;
-    private final WeChatStoreCouponUsageMapper storeCouponUsageMapper;
+    private final StoreTableMapper storeTableMapper;
+    private final StoreCuisineMapper storeCuisineMapper;
+    private final StoreCartMapper storeCartMapper;
+    private final StoreCouponUsageMapper storeCouponUsageMapper;
     private final StoreInfoMapper storeInfoMapper;
 
     @Override
@@ -73,7 +72,7 @@ public class CartServiceImpl implements CartService {
         cart.setTableId(tableId);
 
         // 查询桌号信息
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table != null) {
             cart.setTableNumber(table.getTableNumber());
             cart.setStoreId(table.getStoreId());
@@ -125,17 +124,17 @@ public class CartServiceImpl implements CartService {
         cart.setTotalQuantity(0);
 
         // 查询桌号信息
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table != null) {
             cart.setTableNumber(table.getTableNumber());
             cart.setStoreId(table.getStoreId());
         }
 
         // 从数据库查询购物车数据
-        LambdaQueryWrapper<WeChatStoreCart> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCart::getTableId, tableId);
-        wrapper.eq(WeChatStoreCart::getDeleteFlag, 0);
-        List<WeChatStoreCart> cartList = storeCartMapper.selectList(wrapper);
+        LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCart::getTableId, tableId);
+        wrapper.eq(StoreCart::getDeleteFlag, 0);
+        List<StoreCart> cartList = storeCartMapper.selectList(wrapper);
 
         if (cartList != null && !cartList.isEmpty()) {
             List<CartItemDTO> items = cartList.stream().map(cartItem -> {
@@ -174,13 +173,13 @@ public class CartServiceImpl implements CartService {
     public CartDTO addItem(AddCartItemDTO dto) {
         log.info("添加商品到购物车, dto={}", dto);
         // 验证桌号
-        WeChatStoreTable table = storeTableMapper.selectById(dto.getTableId());
+        StoreTable table = storeTableMapper.selectById(dto.getTableId());
         if (table == null) {
             throw new RuntimeException("桌号不存在");
         }
 
         // 验证菜品
-        WeChatStoreCuisine cuisine = storeCuisineMapper.selectById(dto.getCuisineId());
+        StoreCuisine cuisine = storeCuisineMapper.selectById(dto.getCuisineId());
         if (cuisine == null) {
             throw new RuntimeException("菜品不存在");
         }
@@ -299,7 +298,7 @@ public class CartServiceImpl implements CartService {
             log.info("商品不在购物车中,自动添加, tableId={}, cuisineId={}, quantity={}", tableId, cuisineId, quantity);
             
             // 验证菜品
-            WeChatStoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
+            StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
             if (cuisine == null) {
                 throw new RuntimeException("菜品不存在");
             }
@@ -470,19 +469,19 @@ public class CartServiceImpl implements CartService {
             
             // 2. 从数据库中逻辑删除未下单的商品(排除餐具)
             if (!unorderedItems.isEmpty()) {
-                LambdaQueryWrapper<WeChatStoreCart> wrapper = new LambdaQueryWrapper<>();
-                wrapper.eq(WeChatStoreCart::getTableId, tableId);
-                wrapper.eq(WeChatStoreCart::getDeleteFlag, 0);
+                LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
+                wrapper.eq(StoreCart::getTableId, tableId);
+                wrapper.eq(StoreCart::getDeleteFlag, 0);
                 // 排除餐具(cuisineId = -1)
-                wrapper.ne(WeChatStoreCart::getCuisineId, TABLEWARE_CUISINE_ID);
+                wrapper.ne(StoreCart::getCuisineId, TABLEWARE_CUISINE_ID);
                 if (!orderedCuisineIds.isEmpty()) {
                     // 排除已下单的商品ID(包括餐具)
-                    wrapper.notIn(WeChatStoreCart::getCuisineId, orderedCuisineIds);
+                    wrapper.notIn(StoreCart::getCuisineId, orderedCuisineIds);
                 }
-                List<WeChatStoreCart> cartListToDelete = storeCartMapper.selectList(wrapper);
+                List<StoreCart> cartListToDelete = storeCartMapper.selectList(wrapper);
                 if (cartListToDelete != null && !cartListToDelete.isEmpty()) {
                     List<Integer> cartIds = cartListToDelete.stream()
-                            .map(WeChatStoreCart::getId)
+                            .map(StoreCart::getId)
                             .collect(Collectors.toList());
                     // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
                     storeCartMapper.deleteBatchIds(cartIds);
@@ -497,7 +496,7 @@ public class CartServiceImpl implements CartService {
             }
             
             // 4. 更新桌号表的购物车统计
-            WeChatStoreTable table = storeTableMapper.selectById(tableId);
+            StoreTable table = storeTableMapper.selectById(tableId);
             if (table != null) {
                 table.setCartItemCount(totalQuantity);
                 table.setCartTotalAmount(totalAmount);
@@ -518,7 +517,7 @@ public class CartServiceImpl implements CartService {
         CartDTO fromCart = getCart(fromTableId);
 
         // 验证目标桌号
-        WeChatStoreTable toTable = storeTableMapper.selectById(toTableId);
+        StoreTable toTable = storeTableMapper.selectById(toTableId);
         if (toTable == null) {
             throw new RuntimeException("目标桌号不存在");
         }
@@ -594,13 +593,13 @@ public class CartServiceImpl implements CartService {
         }
 
         // Redis中没有,查数据库
-        LambdaQueryWrapper<WeChatStoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCouponUsage::getTableId, tableId);
-        wrapper.eq(WeChatStoreCouponUsage::getDeleteFlag, 0);
-        wrapper.in(WeChatStoreCouponUsage::getUsageStatus, 0, 1, 2); // 已标记使用、已下单、已支付
-        wrapper.orderByDesc(WeChatStoreCouponUsage::getCreatedTime);
+        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCouponUsage::getTableId, tableId);
+        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
+        wrapper.in(StoreCouponUsage::getUsageStatus, 0, 1, 2); // 已标记使用、已下单、已支付
+        wrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
         wrapper.last("LIMIT 1");
-        WeChatStoreCouponUsage usage = storeCouponUsageMapper.selectOne(wrapper);
+        StoreCouponUsage usage = storeCouponUsageMapper.selectOne(wrapper);
         return usage != null;
     }
 
@@ -611,22 +610,22 @@ public class CartServiceImpl implements CartService {
         baseRedisService.setString(couponUsedKey, String.valueOf(couponId), (long) CART_EXPIRE_SECONDS);
 
         // 保存到数据库
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table == null) {
             log.warn("桌号不存在, tableId={}", tableId);
             return;
         }
 
         // 检查是否已存在
-        LambdaQueryWrapper<WeChatStoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCouponUsage::getTableId, tableId);
-        wrapper.eq(WeChatStoreCouponUsage::getCouponId, couponId);
-        wrapper.eq(WeChatStoreCouponUsage::getDeleteFlag, 0);
-        WeChatStoreCouponUsage existing = storeCouponUsageMapper.selectOne(wrapper);
+        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCouponUsage::getTableId, tableId);
+        wrapper.eq(StoreCouponUsage::getCouponId, couponId);
+        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
+        StoreCouponUsage existing = storeCouponUsageMapper.selectOne(wrapper);
 
         if (existing == null) {
             Date now = new Date();
-            WeChatStoreCouponUsage usage = new WeChatStoreCouponUsage();
+            StoreCouponUsage usage = new StoreCouponUsage();
             usage.setTableId(tableId);
             usage.setStoreId(table.getStoreId());
             usage.setCouponId(couponId);
@@ -652,21 +651,21 @@ public class CartServiceImpl implements CartService {
         baseRedisService.delete(couponUsedKey);
 
         // 更新数据库(逻辑删除未下单的记录,使用 MyBatis-Plus 的 deleteBatchIds)
-        LambdaQueryWrapper<WeChatStoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCouponUsage::getTableId, tableId);
-        wrapper.eq(WeChatStoreCouponUsage::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCouponUsage::getUsageStatus, 0); // 只删除已标记使用但未下单的
-        List<WeChatStoreCouponUsage> usageList = storeCouponUsageMapper.selectList(wrapper);
+        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCouponUsage::getTableId, tableId);
+        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
+        wrapper.eq(StoreCouponUsage::getUsageStatus, 0); // 只删除已标记使用但未下单的
+        List<StoreCouponUsage> usageList = storeCouponUsageMapper.selectList(wrapper);
         if (usageList != null && !usageList.isEmpty()) {
             List<Integer> usageIds = usageList.stream()
-                    .map(WeChatStoreCouponUsage::getId)
+                    .map(StoreCouponUsage::getId)
                     .collect(Collectors.toList());
             // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
             storeCouponUsageMapper.deleteBatchIds(usageIds);
         }
 
         // 更新桌号表的优惠券ID
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table != null) {
             table.setCurrentCouponId(null);
             storeTableMapper.updateById(table);
@@ -719,7 +718,7 @@ public class CartServiceImpl implements CartService {
         Integer storeId = cart.getStoreId();
         if (storeId == null) {
             // 如果购物车中没有门店ID,从桌号获取
-            WeChatStoreTable table = storeTableMapper.selectById(tableId);
+            StoreTable table = storeTableMapper.selectById(tableId);
             if (table != null) {
                 storeId = table.getStoreId();
             }
@@ -805,7 +804,7 @@ public class CartServiceImpl implements CartService {
         // 获取门店ID和餐具单价
         Integer storeId = cart.getStoreId();
         if (storeId == null) {
-            WeChatStoreTable table = storeTableMapper.selectById(tableId);
+            StoreTable table = storeTableMapper.selectById(tableId);
             if (table != null) {
                 storeId = table.getStoreId();
             }
@@ -1000,13 +999,13 @@ public class CartServiceImpl implements CartService {
             Integer userId = TokenUtil.getCurrentUserId();
 
             // 1. 批量逻辑删除该桌号的所有购物车记录(使用 MyBatis-Plus 的 deleteBatchIds)
-            LambdaQueryWrapper<WeChatStoreCart> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(WeChatStoreCart::getTableId, cart.getTableId())
-                    .eq(WeChatStoreCart::getDeleteFlag, 0);
-            List<WeChatStoreCart> existingCartList = storeCartMapper.selectList(queryWrapper);
+            LambdaQueryWrapper<StoreCart> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(StoreCart::getTableId, cart.getTableId())
+                    .eq(StoreCart::getDeleteFlag, 0);
+            List<StoreCart> existingCartList = storeCartMapper.selectList(queryWrapper);
             if (existingCartList != null && !existingCartList.isEmpty()) {
                 List<Integer> cartIds = existingCartList.stream()
-                        .map(WeChatStoreCart::getId)
+                        .map(StoreCart::getId)
                         .collect(Collectors.toList());
                 // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
                 storeCartMapper.deleteBatchIds(cartIds);
@@ -1014,9 +1013,9 @@ public class CartServiceImpl implements CartService {
 
             // 2. 批量插入新的购物车记录
             if (cart.getItems() != null && !cart.getItems().isEmpty()) {
-                List<WeChatStoreCart> cartList = new ArrayList<>(cart.getItems().size());
+                List<StoreCart> cartList = new ArrayList<>(cart.getItems().size());
                 for (CartItemDTO item : cart.getItems()) {
-                    WeChatStoreCart storeCart = new WeChatStoreCart();
+                    StoreCart storeCart = new StoreCart();
                     storeCart.setTableId(cart.getTableId());
                     storeCart.setStoreId(cart.getStoreId());
                     storeCart.setCuisineId(item.getCuisineId());
@@ -1039,7 +1038,7 @@ public class CartServiceImpl implements CartService {
                 // 批量插入(如果数量较少,直接循环插入;如果数量较多,可以考虑分批插入)
                 if (cartList.size() <= 50) {
                     // 小批量直接插入
-                    for (WeChatStoreCart storeCart : cartList) {
+                    for (StoreCart storeCart : cartList) {
                         storeCartMapper.insert(storeCart);
                     }
                 } else {
@@ -1047,8 +1046,8 @@ public class CartServiceImpl implements CartService {
                     int batchSize = 50;
                     for (int i = 0; i < cartList.size(); i += batchSize) {
                         int end = Math.min(i + batchSize, cartList.size());
-                        List<WeChatStoreCart> batch = cartList.subList(i, end);
-                        for (WeChatStoreCart storeCart : batch) {
+                        List<StoreCart> batch = cartList.subList(i, end);
+                        for (StoreCart storeCart : batch) {
                             storeCartMapper.insert(storeCart);
                         }
                     }
@@ -1056,7 +1055,7 @@ public class CartServiceImpl implements CartService {
             }
 
             // 3. 更新桌号表的购物车统计
-            WeChatStoreTable table = storeTableMapper.selectById(cart.getTableId());
+            StoreTable table = storeTableMapper.selectById(cart.getTableId());
             if (table != null) {
                 table.setCartItemCount(cart.getTotalQuantity());
                 table.setCartTotalAmount(cart.getTotalAmount());

+ 48 - 49
alien-dining/src/main/java/shop/alien/dining/service/impl/DiningServiceImpl.java

@@ -7,7 +7,6 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import shop.alien.entity.store.*;
-import shop.alien.entity.store.wechat.*;
 import shop.alien.entity.store.dto.CartDTO;
 import shop.alien.entity.store.dto.CartItemDTO;
 import shop.alien.entity.store.vo.*;
@@ -32,18 +31,18 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 public class DiningServiceImpl implements DiningService {
 
-    private final WeChatStoreTableMapper storeTableMapper;
+    private final StoreTableMapper storeTableMapper;
     private final StoreInfoMapper storeInfoMapper;
-    private final WeChatStoreCuisineMapper storeCuisineMapper;
-    private final WeChatStoreCuisineCategoryMapper storeCuisineCategoryMapper;
-    private final WeChatStoreCuisineComboMapper storeCuisineComboMapper;
-    private final WeChatStoreOrderDetailMapper storeOrderDetailMapper;
+    private final StoreCuisineMapper storeCuisineMapper;
+    private final StoreCuisineCategoryMapper storeCuisineCategoryMapper;
+    private final StoreCuisineComboMapper storeCuisineComboMapper;
+    private final StoreOrderDetailMapper storeOrderDetailMapper;
     private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
     private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
     private final CartService cartService;
     private final BaseRedisService baseRedisService;
     private final shop.alien.dining.service.StoreOrderService storeOrderService;
-    private final shop.alien.mapper.WeChatStoreOrderMapper storeOrderMapper;
+    private final shop.alien.mapper.StoreOrderMapper storeOrderMapper;
     private final shop.alien.dining.service.OrderLockService orderLockService;
 
     @Override
@@ -51,7 +50,7 @@ public class DiningServiceImpl implements DiningService {
         if (tableId == null) {
             return new TableDiningStatusVO(null, false, null);
         }
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table == null) {
             return new TableDiningStatusVO(tableId, false, null);
         }
@@ -66,7 +65,7 @@ public class DiningServiceImpl implements DiningService {
     @Override
     public DiningPageInfoVO getDiningPageInfo(Integer tableId, Integer dinerCount) {
         log.info("获取点餐页面信息, tableId={}, dinerCount={}", tableId, dinerCount);
-        WeChatStoreTable table = storeTableMapper.selectById(tableId);
+        StoreTable table = storeTableMapper.selectById(tableId);
         if (table == null) {
             throw new RuntimeException("桌号不存在");
         }
@@ -112,16 +111,16 @@ public class DiningServiceImpl implements DiningService {
             keyword = keyword.substring(0, 10);
         }
 
-        LambdaQueryWrapper<WeChatStoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisine::getStoreId, storeId);
-        wrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCuisine::getShelfStatus, 1); // 只查询上架的
+        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisine::getStoreId, storeId);
+        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的
         if (StringUtils.hasText(keyword)) {
-            wrapper.like(WeChatStoreCuisine::getName, keyword);
+            wrapper.like(StoreCuisine::getName, keyword);
         }
-        wrapper.orderByDesc(WeChatStoreCuisine::getCreatedTime);
+        wrapper.orderByDesc(StoreCuisine::getCreatedTime);
 
-        List<WeChatStoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
+        List<StoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
         return convertToCuisineListVO(cuisines, tableId);
     }
 
@@ -136,21 +135,21 @@ public class DiningServiceImpl implements DiningService {
             size = 12;
         }
 
-        LambdaQueryWrapper<WeChatStoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisine::getStoreId, storeId);
-        wrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCuisine::getShelfStatus, 1); // 只查询上架的
+        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisine::getStoreId, storeId);
+        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的
         if (categoryId != null) {
             // 这里假设菜品表有category_id字段,如果没有需要关联查询
-            // wrapper.eq(WeChatStoreCuisine::getCategoryId, categoryId);
+            // wrapper.eq(StoreCuisine::getCategoryId, categoryId);
         }
-        wrapper.orderByDesc(WeChatStoreCuisine::getCreatedTime);
+        wrapper.orderByDesc(StoreCuisine::getCreatedTime);
 
         // 分页查询
         int offset = (page - 1) * size;
         wrapper.last("LIMIT " + offset + ", " + size);
 
-        List<WeChatStoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
+        List<StoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
         return convertToCuisineListVO(cuisines, tableId);
     }
 
@@ -158,7 +157,7 @@ public class DiningServiceImpl implements DiningService {
     public CuisineDetailVO getCuisineDetail(Integer cuisineId, Integer tableId) {
         log.info("获取菜品详情, cuisineId={}, tableId={}", cuisineId, tableId);
 
-        WeChatStoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
+        StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
         if (cuisine == null) {
             throw new RuntimeException("菜品不存在");
         }
@@ -206,10 +205,10 @@ public class DiningServiceImpl implements DiningService {
 
         // 如果是套餐,获取套餐包含的菜品
         if (cuisine.getCuisineType() != null && cuisine.getCuisineType() == 2) {
-            LambdaQueryWrapper<WeChatStoreCuisineCombo> comboWrapper = new LambdaQueryWrapper<>();
-            comboWrapper.eq(WeChatStoreCuisineCombo::getCid, cuisineId);
-            comboWrapper.eq(WeChatStoreCuisineCombo::getDeleteFlag, 0);
-            List<WeChatStoreCuisineCombo> combos = storeCuisineComboMapper.selectList(comboWrapper);
+            LambdaQueryWrapper<StoreCuisineCombo> comboWrapper = new LambdaQueryWrapper<>();
+            comboWrapper.eq(StoreCuisineCombo::getCid, cuisineId);
+            comboWrapper.eq(StoreCuisineCombo::getDeleteFlag, 0);
+            List<StoreCuisineCombo> combos = storeCuisineComboMapper.selectList(comboWrapper);
 
             List<CuisineComboItemVO> comboItems = combos.stream().map(combo -> {
                 CuisineComboItemVO item = new CuisineComboItemVO();
@@ -217,7 +216,7 @@ public class DiningServiceImpl implements DiningService {
                 item.setQuantity(combo.getSnum());
                 item.setCategory(combo.getCategory());
                 // 查询菜品名称
-                WeChatStoreCuisine comboCuisine = storeCuisineMapper.selectById(combo.getSid());
+                StoreCuisine comboCuisine = storeCuisineMapper.selectById(combo.getSid());
                 if (comboCuisine != null) {
                     item.setCuisineName(comboCuisine.getName());
                 }
@@ -342,10 +341,10 @@ public class DiningServiceImpl implements DiningService {
                     .filter(Objects::nonNull)
                     .collect(Collectors.toSet());
             if (!cuisineIds.isEmpty()) {
-                List<WeChatStoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
+                List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
                 Map<Integer, String> tagsMap = new HashMap<>();
                 if (cuisines != null) {
-                    for (WeChatStoreCuisine c : cuisines) {
+                    for (StoreCuisine c : cuisines) {
                         if (c.getTags() != null) {
                             tagsMap.put(c.getId(), c.getTags());
                         }
@@ -455,7 +454,7 @@ public class DiningServiceImpl implements DiningService {
     /**
      * 转换为菜品列表VO
      */
-    private List<CuisineListVO> convertToCuisineListVO(List<WeChatStoreCuisine> cuisines, Integer tableId) {
+    private List<CuisineListVO> convertToCuisineListVO(List<StoreCuisine> cuisines, Integer tableId) {
         // 获取购物车
         CartDTO cart = cartService.getCart(tableId);
         Map<Integer, Integer> cartQuantityMap = new HashMap<>();
@@ -466,7 +465,7 @@ public class DiningServiceImpl implements DiningService {
 
         // 批量查询月售数量
         Map<Integer, Integer> monthlySalesMap = new HashMap<>();
-        for (WeChatStoreCuisine cuisine : cuisines) {
+        for (StoreCuisine cuisine : cuisines) {
             monthlySalesMap.put(cuisine.getId(), getMonthlySales(cuisine.getId()));
         }
 
@@ -509,16 +508,16 @@ public class DiningServiceImpl implements DiningService {
             Date monthStart = calendar.getTime();
 
             // 查询订单明细中该菜品的销售数量
-            LambdaQueryWrapper<WeChatStoreOrderDetail> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(WeChatStoreOrderDetail::getCuisineId, cuisineId);
-            wrapper.eq(WeChatStoreOrderDetail::getDeleteFlag, 0);
-            wrapper.ge(WeChatStoreOrderDetail::getCreatedTime, monthStart);
+            LambdaQueryWrapper<StoreOrderDetail> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(StoreOrderDetail::getCuisineId, cuisineId);
+            wrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
+            wrapper.ge(StoreOrderDetail::getCreatedTime, monthStart);
             // 只统计已支付的订单
-            wrapper.inSql(WeChatStoreOrderDetail::getOrderId,
+            wrapper.inSql(StoreOrderDetail::getOrderId,
                     "SELECT id FROM store_order WHERE pay_status = 1 AND delete_flag = 0");
 
-            List<WeChatStoreOrderDetail> details = storeOrderDetailMapper.selectList(wrapper);
-            return details.stream().mapToInt(WeChatStoreOrderDetail::getQuantity).sum();
+            List<StoreOrderDetail> details = storeOrderDetailMapper.selectList(wrapper);
+            return details.stream().mapToInt(StoreOrderDetail::getQuantity).sum();
         } catch (Exception e) {
             log.error("获取月售数量失败, cuisineId={}", cuisineId, e);
             return 0;
@@ -530,28 +529,28 @@ public class DiningServiceImpl implements DiningService {
         log.info("获取订单结算确认页面信息, orderId={}, userId={}", orderId, userId);
 
         // 查询订单
-        shop.alien.entity.store.wechat.WeChatStoreOrder order = storeOrderService.getOrderById(orderId);
+        shop.alien.entity.store.StoreOrder order = storeOrderService.getOrderById(orderId);
         if (order == null) {
             throw new RuntimeException("订单不存在");
         }
 
         // 查询订单明细
-        LambdaQueryWrapper<shop.alien.entity.store.wechat.WeChatStoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-        detailWrapper.eq(shop.alien.entity.store.wechat.WeChatStoreOrderDetail::getOrderId, orderId);
-        detailWrapper.eq(shop.alien.entity.store.wechat.WeChatStoreOrderDetail::getDeleteFlag, 0);
-        detailWrapper.orderByDesc(shop.alien.entity.store.wechat.WeChatStoreOrderDetail::getCreatedTime);
-        List<shop.alien.entity.store.wechat.WeChatStoreOrderDetail> details = storeOrderDetailMapper.selectList(detailWrapper);
+        LambdaQueryWrapper<shop.alien.entity.store.StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
+        detailWrapper.eq(shop.alien.entity.store.StoreOrderDetail::getOrderId, orderId);
+        detailWrapper.eq(shop.alien.entity.store.StoreOrderDetail::getDeleteFlag, 0);
+        detailWrapper.orderByDesc(shop.alien.entity.store.StoreOrderDetail::getCreatedTime);
+        List<shop.alien.entity.store.StoreOrderDetail> details = storeOrderDetailMapper.selectList(detailWrapper);
 
         // 批量查询菜品标签
         Set<Integer> cuisineIds = details.stream()
-                .map(shop.alien.entity.store.wechat.WeChatStoreOrderDetail::getCuisineId)
+                .map(shop.alien.entity.store.StoreOrderDetail::getCuisineId)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toSet());
         Map<Integer, String> cuisineIdToTags = new HashMap<>();
         if (!cuisineIds.isEmpty()) {
-            List<WeChatStoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
+            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
             if (cuisines != null) {
-                for (WeChatStoreCuisine c : cuisines) {
+                for (StoreCuisine c : cuisines) {
                     if (c.getTags() != null) {
                         cuisineIdToTags.put(c.getId(), c.getTags());
                     }

+ 2 - 2
alien-dining/src/main/java/shop/alien/dining/service/impl/OrderLockServiceImpl.java

@@ -18,8 +18,8 @@ import shop.alien.dining.service.OrderLockService;
 @RequiredArgsConstructor
 public class OrderLockServiceImpl implements OrderLockService {
 
-    private static final String ORDER_LOCK_KEY_PREFIX = "wechat:order:lock:table:";
-    private static final String SETTLEMENT_LOCK_KEY_PREFIX = "wechat:settlement:lock:order:";
+    private static final String ORDER_LOCK_KEY_PREFIX = "order:lock:table:";
+    private static final String SETTLEMENT_LOCK_KEY_PREFIX = "settlement:lock:order:";
     private static final int ORDER_LOCK_EXPIRE_SECONDS = 300; // 5分钟过期
 
     private final BaseRedisService baseRedisService;

+ 52 - 52
alien-dining/src/main/java/shop/alien/dining/service/impl/StoreInfoServiceImpl.java

@@ -5,16 +5,16 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
-import shop.alien.entity.store.wechat.WeChatStoreCuisine;
-import shop.alien.entity.store.wechat.WeChatStoreCuisineCategory;
+import shop.alien.entity.store.StoreCuisine;
+import shop.alien.entity.store.StoreCuisineCategory;
 import shop.alien.entity.store.StoreInfo;
-import shop.alien.entity.store.wechat.WeChatStoreTable;
+import shop.alien.entity.store.StoreTable;
 import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
 import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
-import shop.alien.mapper.WeChatStoreCuisineCategoryMapper;
-import shop.alien.mapper.WeChatStoreCuisineMapper;
+import shop.alien.mapper.StoreCuisineCategoryMapper;
+import shop.alien.mapper.StoreCuisineMapper;
 import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.WeChatStoreTableMapper;
+import shop.alien.mapper.StoreTableMapper;
 import shop.alien.dining.service.StoreInfoService;
 import org.apache.commons.lang3.StringUtils;
 
@@ -33,55 +33,55 @@ import java.util.stream.Collectors;
 @RequiredArgsConstructor
 public class StoreInfoServiceImpl implements StoreInfoService {
 
-    private final WeChatStoreTableMapper storeTableMapper;
-    private final WeChatStoreCuisineCategoryMapper storeCuisineCategoryMapper;
-    private final WeChatStoreCuisineMapper storeCuisineMapper;
+    private final StoreTableMapper storeTableMapper;
+    private final StoreCuisineCategoryMapper storeCuisineCategoryMapper;
+    private final StoreCuisineMapper storeCuisineMapper;
     private final StoreInfoMapper storeInfoMapper;
 
     @Override
-    public List<WeChatStoreTable> getTablesByStoreId(Integer storeId) {
+    public List<StoreTable> getTablesByStoreId(Integer storeId) {
         log.info("根据门店ID查询桌号列表, storeId={}", storeId);
         
-        LambdaQueryWrapper<WeChatStoreTable> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreTable::getStoreId, storeId);
-        wrapper.eq(WeChatStoreTable::getDeleteFlag, 0);
-        wrapper.orderByAsc(WeChatStoreTable::getTableNumber);
+        LambdaQueryWrapper<StoreTable> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreTable::getStoreId, storeId);
+        wrapper.eq(StoreTable::getDeleteFlag, 0);
+        wrapper.orderByAsc(StoreTable::getTableNumber);
         
         return storeTableMapper.selectList(wrapper);
     }
 
     @Override
-    public List<WeChatStoreCuisineCategory> getCategoriesByStoreId(Integer storeId) {
+    public List<StoreCuisineCategory> getCategoriesByStoreId(Integer storeId) {
         log.info("根据门店ID查询菜品种类列表, storeId={}", storeId);
         
-        LambdaQueryWrapper<WeChatStoreCuisineCategory> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisineCategory::getStoreId, storeId);
-        wrapper.eq(WeChatStoreCuisineCategory::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCuisineCategory::getStatus, 1); // 只查询启用的分类
-        wrapper.orderByAsc(WeChatStoreCuisineCategory::getSort); // 按排序字段排序
+        LambdaQueryWrapper<StoreCuisineCategory> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisineCategory::getStoreId, storeId);
+        wrapper.eq(StoreCuisineCategory::getDeleteFlag, 0);
+        wrapper.eq(StoreCuisineCategory::getStatus, 1); // 只查询启用的分类
+        wrapper.orderByAsc(StoreCuisineCategory::getSort); // 按排序字段排序
         
         return storeCuisineCategoryMapper.selectList(wrapper);
     }
 
     @Override
-    public List<WeChatStoreCuisine> getCuisinesByCategoryId(Integer categoryId) {
+    public List<StoreCuisine> getCuisinesByCategoryId(Integer categoryId) {
         log.info("根据菜品种类ID查询菜品信息列表, categoryId={}", categoryId);
         
         // 先查询分类信息,获取 storeId
-        WeChatStoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
+        StoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
         if (category == null) {
             log.warn("菜品种类不存在, categoryId={}", categoryId);
             return new java.util.ArrayList<>();
         }
         
         // 查询该门店下所有上架的菜品(与 getCategoriesWithCuisinesByStoreId 中 cuisines 查询条件、排序一致)
-        LambdaQueryWrapper<WeChatStoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisine::getStoreId, category.getStoreId());
-        wrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCuisine::getShelfStatus, 1); // 只查询上架的菜品
-        wrapper.orderByAsc(WeChatStoreCuisine::getId); // 与 categories-with-cuisines 中 cuisines 顺序一致
+        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisine::getStoreId, category.getStoreId());
+        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的菜品
+        wrapper.orderByAsc(StoreCuisine::getId); // 与 categories-with-cuisines 中 cuisines 顺序一致
         
-        List<WeChatStoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
+        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
         
         // 过滤出包含该分类ID的菜品
         // categoryIds 是 JSON 数组格式,如:[1,2,3]
@@ -108,26 +108,26 @@ public class StoreInfoServiceImpl implements StoreInfoService {
     @Override
     public List<CategoryWithCuisinesVO> getCategoriesWithCuisinesByStoreId(Integer storeId, String keyword) {
         log.info("根据门店ID查询菜品种类及下属菜品, storeId={}, keyword={}", storeId, keyword);
-        List<WeChatStoreCuisineCategory> categories = getCategoriesByStoreId(storeId);
+        List<StoreCuisineCategory> categories = getCategoriesByStoreId(storeId);
         if (categories == null || categories.isEmpty()) {
             return new ArrayList<>();
         }
         // 与 getCuisinesByCategoryId 相同的查询条件与排序,保证 cuisines 字段与 /store/info/cuisines 一致
-        LambdaQueryWrapper<WeChatStoreCuisine> cuisineWrapper = new LambdaQueryWrapper<>();
-        cuisineWrapper.eq(WeChatStoreCuisine::getStoreId, storeId);
-        cuisineWrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        cuisineWrapper.eq(WeChatStoreCuisine::getShelfStatus, 1);
-        cuisineWrapper.orderByAsc(WeChatStoreCuisine::getId);
-        List<WeChatStoreCuisine> allCuisines = storeCuisineMapper.selectList(cuisineWrapper);
+        LambdaQueryWrapper<StoreCuisine> cuisineWrapper = new LambdaQueryWrapper<>();
+        cuisineWrapper.eq(StoreCuisine::getStoreId, storeId);
+        cuisineWrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        cuisineWrapper.eq(StoreCuisine::getShelfStatus, 1);
+        cuisineWrapper.orderByAsc(StoreCuisine::getId);
+        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(cuisineWrapper);
         if (allCuisines == null) {
             allCuisines = new ArrayList<>();
         }
         boolean filterByName = StringUtils.isNotBlank(keyword);
         String keywordLower = filterByName ? keyword.trim().toLowerCase() : null;
         List<CategoryWithCuisinesVO> result = new ArrayList<>();
-        for (WeChatStoreCuisineCategory category : categories) {
+        for (StoreCuisineCategory category : categories) {
             Integer categoryId = category.getId();
-            List<WeChatStoreCuisine> cuisines = allCuisines.stream()
+            List<StoreCuisine> cuisines = allCuisines.stream()
                     .filter(c -> belongsToCategory(c, categoryId))
                     .filter(c -> !filterByName || (c.getName() != null && c.getName().toLowerCase().contains(keywordLower)))
                     .collect(Collectors.toList());
@@ -136,7 +136,7 @@ public class StoreInfoServiceImpl implements StoreInfoService {
         return result;
     }
 
-    private boolean belongsToCategory(WeChatStoreCuisine cuisine, Integer categoryId) {
+    private boolean belongsToCategory(StoreCuisine cuisine, Integer categoryId) {
         String categoryIdsStr = cuisine.getCategoryIds();
         if (StringUtils.isBlank(categoryIdsStr)) {
             return false;
@@ -156,19 +156,19 @@ public class StoreInfoServiceImpl implements StoreInfoService {
             log.warn("删除菜品种类失败:分类ID为空");
             return false;
         }
-        WeChatStoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
+        StoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
         if (category == null) {
             log.warn("删除菜品种类失败:分类不存在, categoryId={}", categoryId);
             return false;
         }
         Integer storeId = category.getStoreId();
         // 1. 解除绑定:将该分类ID从所有关联菜品的 category_ids 中移除,价目表菜品其它字段不变
-        LambdaQueryWrapper<WeChatStoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisine::getStoreId, storeId);
-        wrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        List<WeChatStoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
+        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisine::getStoreId, storeId);
+        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
         if (allCuisines != null) {
-            for (WeChatStoreCuisine cuisine : allCuisines) {
+            for (StoreCuisine cuisine : allCuisines) {
                 if (!belongsToCategory(cuisine, categoryId)) {
                     continue;
                 }
@@ -215,15 +215,15 @@ public class StoreInfoServiceImpl implements StoreInfoService {
         }
         
         // 2. 查询首页展示的美食价目表(is_homepage_display = 1,上架状态 = 1,审核通过 = 1)
-        LambdaQueryWrapper<WeChatStoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(WeChatStoreCuisine::getStoreId, storeId);
-        wrapper.eq(WeChatStoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(WeChatStoreCuisine::getIsHomepageDisplay, 1); // 首页展示
-        wrapper.eq(WeChatStoreCuisine::getShelfStatus, 1); // 上架状态
-        wrapper.eq(WeChatStoreCuisine::getStatus, 1); // 审核通过
-        wrapper.orderByDesc(WeChatStoreCuisine::getCreatedTime); // 按创建时间倒序
+        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(StoreCuisine::getStoreId, storeId);
+        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
+        wrapper.eq(StoreCuisine::getIsHomepageDisplay, 1); // 首页展示
+        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 上架状态
+        wrapper.eq(StoreCuisine::getStatus, 1); // 审核通过
+        wrapper.orderByDesc(StoreCuisine::getCreatedTime); // 按创建时间倒序
         
-        List<WeChatStoreCuisine> homepageCuisines = storeCuisineMapper.selectList(wrapper);
+        List<StoreCuisine> homepageCuisines = storeCuisineMapper.selectList(wrapper);
         if (homepageCuisines == null) {
             homepageCuisines = new ArrayList<>();
         }

Fișier diff suprimat deoarece este prea mare
+ 244 - 248
alien-dining/src/main/java/shop/alien/dining/service/impl/StoreOrderServiceImpl.java


+ 4 - 4
alien-dining/src/main/java/shop/alien/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java

@@ -24,7 +24,7 @@ import shop.alien.dining.util.WXPayUtility;
 import shop.alien.dining.util.WeChatPayUtil;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeDiscountCouponUser;
-import shop.alien.entity.store.wechat.WeChatStoreOrder;
+import shop.alien.entity.store.StoreOrder;
 import shop.alien.entity.store.StorePaymentConfig;
 import shop.alien.mapper.LifeDiscountCouponUserMapper;
 import shop.alien.mapper.StorePaymentConfigMapper;
@@ -193,7 +193,7 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
         request.payer.openid = payer;
 
         String wechatOutTradeNo = orderNo;
-        WeChatStoreOrder storeOrder = storeOrderService.getOrderByOrderNo(orderNo);
+        StoreOrder storeOrder = storeOrderService.getOrderByOrderNo(orderNo);
         log.info("createPrePayOrder, orderNo: {}, storeOrder: {}", orderNo, storeOrder);
         if (storeOrder != null ) {
             log.info("createPrePayOrder, orderNo: {}, storeOrder: {}", orderNo, storeOrder);
@@ -346,9 +346,9 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
             String tradeState = jsonObject.getString("trade_state");
             if ("SUCCESS".equals(tradeState)) {
                 String outTradeNo = jsonObject.getString("out_trade_no");
-                WeChatStoreOrder storeOrder = storeOrderService.getOne(new QueryWrapper<WeChatStoreOrder>().eq("order_no", outTradeNo));
+                StoreOrder storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("order_no", outTradeNo));
                 if (storeOrder == null && StringUtils.hasText(outTradeNo)) {
-                    storeOrder = storeOrderService.getOne(new QueryWrapper<WeChatStoreOrder>().eq("pay_trade_no", outTradeNo));
+                    storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("pay_trade_no", outTradeNo));
                 }
                 if (storeOrder != null && storeOrder.getPayStatus() != 1) {
                     storeOrder.setPayStatus(1);

+ 0 - 96
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCart.java

@@ -1,96 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-购物车表(字段与 {@link shop.alien.entity.store.StoreCart} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_cart")
-@ApiModel(value = "WeChatStoreCart对象", description = "微信小程序购物车表")
-public class WeChatStoreCart {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "桌号ID")
-    @TableField("table_id")
-    private Integer tableId;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "菜品ID")
-    @TableField("cuisine_id")
-    private Integer cuisineId;
-
-    @ApiModelProperty(value = "菜品名称")
-    @TableField("cuisine_name")
-    private String cuisineName;
-
-    @ApiModelProperty(value = "菜品图片")
-    @TableField("cuisine_image")
-    private String cuisineImage;
-
-    @ApiModelProperty(value = "单价")
-    @TableField("unit_price")
-    private BigDecimal unitPrice;
-
-    @ApiModelProperty(value = "数量")
-    @TableField("quantity")
-    private Integer quantity;
-
-    @ApiModelProperty(value = "已下单数量(下单时锁定的数量,不允许减少或删除)")
-    @TableField("locked_quantity")
-    private Integer lockedQuantity;
-
-    @ApiModelProperty(value = "小计金额")
-    @TableField("subtotal_amount")
-    private BigDecimal subtotalAmount;
-
-    @ApiModelProperty(value = "添加该菜品的用户ID")
-    @TableField("add_user_id")
-    private Integer addUserId;
-
-    @ApiModelProperty(value = "添加该菜品的用户手机号")
-    @TableField("add_user_phone")
-    private String addUserPhone;
-
-    @ApiModelProperty(value = "备注")
-    @TableField("remark")
-    private String remark;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 85
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCouponUsage.java

@@ -1,85 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-优惠券使用记录表(字段与 {@link shop.alien.entity.store.StoreCouponUsage} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_coupon_usage")
-@ApiModel(value = "WeChatStoreCouponUsage对象", description = "微信小程序优惠券使用记录表")
-public class WeChatStoreCouponUsage {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "桌号ID")
-    @TableField("table_id")
-    private Integer tableId;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "订单ID(下单时关联)")
-    @TableField("order_id")
-    private Integer orderId;
-
-    @ApiModelProperty(value = "优惠券ID")
-    @TableField("coupon_id")
-    private Integer couponId;
-
-    @ApiModelProperty(value = "优惠券名称")
-    @TableField("coupon_name")
-    private String couponName;
-
-    @ApiModelProperty(value = "优惠金额")
-    @TableField("discount_amount")
-    private BigDecimal discountAmount;
-
-    @ApiModelProperty(value = "使用状态(0:已标记使用, 1:已下单, 2:已支付, 3:已取消)")
-    @TableField("usage_status")
-    private Integer usageStatus;
-
-    @ApiModelProperty(value = "换桌前的桌号ID(如果是换桌迁移)")
-    @TableField("from_table_id")
-    private Integer fromTableId;
-
-    @ApiModelProperty(value = "换桌迁移时间")
-    @TableField("migrate_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date migrateTime;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 137
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisine.java

@@ -1,137 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-美食价目表(字段与 {@link shop.alien.entity.store.StoreCuisine} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_cuisine")
-@ApiModel(value = "WeChatStoreCuisine对象", description = "微信小程序美食价目表")
-public class WeChatStoreCuisine {
-
-    @ApiModelProperty(value = "主键")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "商户id")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "美食类型: 1-单品,2-套餐")
-    @TableField("cuisine_type")
-    private Integer cuisineType;
-
-    @ApiModelProperty(value = "菜品分类ids(JSON数组,如:[1,2,3])")
-    @TableField("category_ids")
-    private String categoryIds;
-
-    @ApiModelProperty(value = "菜名")
-    @TableField("name")
-    private String name;
-
-    @ApiModelProperty(value = "总价")
-    @TableField("total_price")
-    private BigDecimal totalPrice;
-
-    @ApiModelProperty(value = "首页展示(0:否, 1:是)")
-    @TableField("is_homepage_display")
-    private Integer isHomepageDisplay;
-
-    @ApiModelProperty(value = "菜品标签(JSON数组,如:[\"招牌菜\",\"推荐\"])")
-    @TableField("tags")
-    private String tags;
-
-    @ApiModelProperty(value = "菜品短评")
-    @TableField("dish_review")
-    private String dishReview;
-
-    @ApiModelProperty(value = "图片列表,最多 9 张 URL")
-    @TableField("images")
-    private String images;
-
-    @ApiModelProperty(value = "图文详情-图片")
-    @TableField("image_content")
-    private String imageContent;
-
-    @ApiModelProperty(value = "菜品原料json(原料名称:name,所需重量:height,成本价:cost,推荐价格:suggest)")
-    @TableField("raw_json")
-    private String rawJson;
-
-    @ApiModelProperty(value = "图文详情-文字")
-    @TableField("detail_content")
-    private String detailContent;
-
-    @ApiModelProperty(value = "菜品描述")
-    @TableField("description")
-    private String description;
-
-    @ApiModelProperty(value = "补充说明")
-    @TableField("extra_note")
-    private String extraNote;
-
-    @ApiModelProperty(value = "是否需要预约:0=否,1=是")
-    @TableField("need_reserve")
-    private Integer needReserve;
-
-    @ApiModelProperty(value = "预约规则")
-    @TableField("reserve_rule")
-    private String reserveRule;
-
-    @ApiModelProperty(value = "适用人数")
-    @TableField("people_limit")
-    private String peopleLimit;
-
-    @ApiModelProperty(value = "使用规则")
-    @TableField("usage_rule")
-    private String usageRule;
-
-    @ApiModelProperty(value = "状态:0-待审核 1-审核通过 2-审核拒绝")
-    @TableField("status")
-    private Integer status;
-
-    @ApiModelProperty(value = "上下架状态:1-上架,2-下架")
-    @TableField("shelf_status")
-    private Integer shelfStatus;
-
-    @ApiModelProperty(value = "拒绝原因(审核失败原因)")
-    @TableField("rejection_reason")
-    private String rejectionReason;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建人")
-    @TableField(value = "created_user_id", fill = FieldFill.INSERT)
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "更新人")
-    @TableField(value = "updated_user_id", fill = FieldFill.UPDATE)
-    private Integer updatedUserId;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "更新时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "AI审核时间")
-    @TableField(value = "audit_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date auditTime;
-}

+ 0 - 63
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisineCategory.java

@@ -1,63 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * 微信小程序-菜品分类表(字段与 {@link shop.alien.entity.store.StoreCuisineCategory} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_cuisine_category")
-@ApiModel(value = "WeChatStoreCuisineCategory对象", description = "微信小程序菜品分类表")
-public class WeChatStoreCuisineCategory {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "分类名称")
-    @TableField("category_name")
-    private String categoryName;
-
-    @ApiModelProperty(value = "状态(0:禁用, 1:启用)")
-    @TableField("status")
-    private Integer status;
-
-    @ApiModelProperty(value = "排序")
-    @TableField("sort")
-    private Integer sort;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 63
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreCuisineCombo.java

@@ -1,63 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * 微信小程序-美食套餐表(字段与 {@link shop.alien.entity.store.StoreCuisineCombo} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_cuisine_combo")
-@ApiModel(value = "WeChatStoreCuisineCombo对象", description = "微信小程序美食套餐表")
-public class WeChatStoreCuisineCombo {
-
-    @ApiModelProperty(value = "主键")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "单品id")
-    @TableField("sid")
-    private Integer sid;
-
-    @ApiModelProperty(value = "套餐id")
-    @TableField("cid")
-    private Integer cid;
-
-    @ApiModelProperty(value = "套餐包含该单品的数量")
-    @TableField("snum")
-    private Integer snum;
-
-    @ApiModelProperty(value = "类别")
-    @TableField("category")
-    private String category;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建人")
-    @TableField(value = "created_user_id", fill = FieldFill.INSERT)
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "更新人")
-    @TableField(value = "updated_user_id", fill = FieldFill.UPDATE)
-    private Integer updatedUserId;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "更新时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-}

+ 0 - 138
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrder.java

@@ -1,138 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-订单表(字段与 {@link shop.alien.entity.store.StoreOrder} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_order")
-@ApiModel(value = "WeChatStoreOrder对象", description = "微信小程序订单表")
-public class WeChatStoreOrder {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "订单号")
-    @TableField("order_no")
-    private String orderNo;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "桌号ID")
-    @TableField("table_id")
-    private Integer tableId;
-
-    @ApiModelProperty(value = "桌号")
-    @TableField("table_number")
-    private String tableNumber;
-
-    @ApiModelProperty(value = "就餐人数")
-    @TableField("diner_count")
-    private Integer dinerCount;
-
-    @ApiModelProperty(value = "支付用户ID")
-    @TableField("pay_user_id")
-    private Integer payUserId;
-
-    @ApiModelProperty(value = "支付用户手机号")
-    @TableField("pay_user_phone")
-    private String payUserPhone;
-
-    @ApiModelProperty(value = "联系电话")
-    @TableField("contact_phone")
-    private String contactPhone;
-
-    @ApiModelProperty(value = "餐具费")
-    @TableField("tableware_fee")
-    private BigDecimal tablewareFee;
-
-    @ApiModelProperty(value = "订单状态(0:待支付, 1:已支付, 2:已取消, 3:已完成)")
-    @TableField("order_status")
-    private Integer orderStatus;
-
-    @ApiModelProperty(value = "订单总金额")
-    @TableField("total_amount")
-    private BigDecimal totalAmount;
-
-    @ApiModelProperty(value = "优惠券ID")
-    @TableField("coupon_id")
-    private Integer couponId;
-
-    @ApiModelProperty(value = "当前使用的优惠券ID(用于换桌场景)")
-    @TableField("current_coupon_id")
-    private Integer currentCouponId;
-
-    @ApiModelProperty(value = "优惠金额")
-    @TableField("discount_amount")
-    private BigDecimal discountAmount;
-
-    @ApiModelProperty(value = "锁定用户ID(下单或结算时锁定)")
-    @TableField("lock_user_id")
-    private Integer lockUserId;
-
-    @ApiModelProperty(value = "锁定过期时间")
-    @TableField("lock_expire_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date lockExpireTime;
-
-    @ApiModelProperty(value = "实付金额")
-    @TableField("pay_amount")
-    private BigDecimal payAmount;
-
-    @ApiModelProperty(value = "支付方式(1:微信, 2:支付宝, 3:现金)")
-    @TableField("pay_type")
-    private Integer payType;
-
-    @ApiModelProperty(value = "支付状态(0:未支付, 1:已支付, 2:已退款)")
-    @TableField("pay_status")
-    private Integer payStatus;
-
-    @ApiModelProperty(value = "支付时间")
-    @TableField("pay_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date payTime;
-
-    @ApiModelProperty(value = "支付交易号")
-    @TableField("pay_trade_no")
-    private String payTradeNo;
-
-    @ApiModelProperty(value = "备注")
-    @TableField("remark")
-    private String remark;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 117
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderChangeLog.java

@@ -1,117 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-订单变更记录表(字段与 {@link shop.alien.entity.store.StoreOrderChangeLog} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_order_change_log")
-@ApiModel(value = "WeChatStoreOrderChangeLog对象", description = "微信小程序订单变更记录表")
-public class WeChatStoreOrderChangeLog {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "订单ID")
-    @TableField("order_id")
-    private Integer orderId;
-
-    @ApiModelProperty(value = "订单号")
-    @TableField("order_no")
-    private String orderNo;
-
-    @ApiModelProperty(value = "批次号(同一时间点的操作使用同一批次号,用于分组展示)")
-    @TableField("batch_no")
-    private String batchNo;
-
-    @ApiModelProperty(value = "操作类型(1:首次下单, 3:更新订单)")
-    @TableField("operation_type")
-    private Integer operationType;
-
-    @ApiModelProperty(value = "菜品ID")
-    @TableField("cuisine_id")
-    private Integer cuisineId;
-
-    @ApiModelProperty(value = "菜品名称")
-    @TableField("cuisine_name")
-    private String cuisineName;
-
-    @ApiModelProperty(value = "菜品类型(1:单品, 2:套餐)")
-    @TableField("cuisine_type")
-    private Integer cuisineType;
-
-    @ApiModelProperty(value = "菜品图片")
-    @TableField("cuisine_image")
-    private String cuisineImage;
-
-    @ApiModelProperty(value = "单价")
-    @TableField("unit_price")
-    private BigDecimal unitPrice;
-
-    @ApiModelProperty(value = "数量变化(新增的数量,正数表示增加,负数表示减少)")
-    @TableField("quantity_change")
-    private Integer quantityChange;
-
-    @ApiModelProperty(value = "变化前数量(用于展示变化前后对比)")
-    @TableField("quantity_before")
-    private Integer quantityBefore;
-
-    @ApiModelProperty(value = "变化后数量(用于展示变化前后对比)")
-    @TableField("quantity_after")
-    private Integer quantityAfter;
-
-    @ApiModelProperty(value = "金额变化(新增的金额)")
-    @TableField("amount_change")
-    private BigDecimal amountChange;
-
-    @ApiModelProperty(value = "操作时间")
-    @TableField("operation_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date operationTime;
-
-    @ApiModelProperty(value = "操作人ID")
-    @TableField("operator_user_id")
-    private Integer operatorUserId;
-
-    @ApiModelProperty(value = "操作人手机号")
-    @TableField("operator_user_phone")
-    private String operatorUserPhone;
-
-    @ApiModelProperty(value = "备注")
-    @TableField("remark")
-    private String remark;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 105
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderDetail.java

@@ -1,105 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-订单明细表(字段与 {@link shop.alien.entity.store.StoreOrderDetail} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_order_detail")
-@ApiModel(value = "WeChatStoreOrderDetail对象", description = "微信小程序订单明细表")
-public class WeChatStoreOrderDetail {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "订单ID")
-    @TableField("order_id")
-    private Integer orderId;
-
-    @ApiModelProperty(value = "订单号")
-    @TableField("order_no")
-    private String orderNo;
-
-    @ApiModelProperty(value = "菜品ID")
-    @TableField("cuisine_id")
-    private Integer cuisineId;
-
-    @ApiModelProperty(value = "菜品名称")
-    @TableField("cuisine_name")
-    private String cuisineName;
-
-    @ApiModelProperty(value = "菜品类型(1:单品, 2:套餐)")
-    @TableField("cuisine_type")
-    private Integer cuisineType;
-
-    @ApiModelProperty(value = "菜品图片")
-    @TableField("cuisine_image")
-    private String cuisineImage;
-
-    @ApiModelProperty(value = "单价")
-    @TableField("unit_price")
-    private BigDecimal unitPrice;
-
-    @ApiModelProperty(value = "数量")
-    @TableField("quantity")
-    private Integer quantity;
-
-    @ApiModelProperty(value = "小计金额")
-    @TableField("subtotal_amount")
-    private BigDecimal subtotalAmount;
-
-    @ApiModelProperty(value = "添加该菜品的用户ID")
-    @TableField("add_user_id")
-    private Integer addUserId;
-
-    @ApiModelProperty(value = "添加该菜品的用户手机号")
-    @TableField("add_user_phone")
-    private String addUserPhone;
-
-    @ApiModelProperty(value = "是否加餐(0:初始下单, 1:加餐)")
-    @TableField("is_add_dish")
-    private Integer isAddDish;
-
-    @ApiModelProperty(value = "加餐时间")
-    @TableField("add_dish_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date addDishTime;
-
-    @ApiModelProperty(value = "备注")
-    @TableField("remark")
-    private String remark;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 73
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreOrderLock.java

@@ -1,73 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * 微信小程序-订单锁定记录表(字段与 {@link shop.alien.entity.store.StoreOrderLock} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_order_lock")
-@ApiModel(value = "WeChatStoreOrderLock对象", description = "微信小程序订单锁定记录表")
-public class WeChatStoreOrderLock {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "桌号ID(下单锁定)")
-    @TableField("table_id")
-    private Integer tableId;
-
-    @ApiModelProperty(value = "订单ID(结算锁定)")
-    @TableField("order_id")
-    private Integer orderId;
-
-    @ApiModelProperty(value = "锁定类型(1:下单锁定, 2:结算锁定)")
-    @TableField("lock_type")
-    private Integer lockType;
-
-    @ApiModelProperty(value = "锁定用户ID")
-    @TableField("lock_user_id")
-    private Integer lockUserId;
-
-    @ApiModelProperty(value = "锁定用户手机号")
-    @TableField("lock_user_phone")
-    private String lockUserPhone;
-
-    @ApiModelProperty(value = "锁定过期时间")
-    @TableField("lock_expire_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date lockExpireTime;
-
-    @ApiModelProperty(value = "锁定状态(0:已释放, 1:锁定中)")
-    @TableField("lock_status")
-    private Integer lockStatus;
-
-    @ApiModelProperty(value = "释放时间")
-    @TableField("release_time")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date releaseTime;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-}

+ 0 - 96
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreTable.java

@@ -1,96 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * 微信小程序-桌号表(字段与 {@link shop.alien.entity.store.StoreTable} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_table")
-@ApiModel(value = "WeChatStoreTable对象", description = "微信小程序桌号表")
-public class WeChatStoreTable {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "桌号")
-    @TableField("table_number")
-    private String tableNumber;
-
-    @ApiModelProperty(value = "分类ID(关联store_booking_category表)")
-    @TableField("category_id")
-    private Integer categoryId;
-
-    @ApiModelProperty(value = "座位数")
-    @TableField("seating_capacity")
-    private Integer seatingCapacity;
-
-    @ApiModelProperty(value = "当前进行中的订单ID(订单结账或取消后清空)")
-    @TableField("current_order_id")
-    private Integer currentOrderId;
-
-    @ApiModelProperty(value = "当前使用的优惠券ID")
-    @TableField("current_coupon_id")
-    private Integer currentCouponId;
-
-    @ApiModelProperty(value = "购物车商品数量(缓存)")
-    @TableField("cart_item_count")
-    private Integer cartItemCount;
-
-    @ApiModelProperty(value = "购物车总金额(缓存)")
-    @TableField("cart_total_amount")
-    private BigDecimal cartTotalAmount;
-
-    @ApiModelProperty(value = "二维码URL")
-    @TableField("qrcode_url")
-    private String qrcodeUrl;
-
-    @ApiModelProperty(value = "状态(0:空闲, 1:就餐中, 2:其他, 3:加餐)")
-    @TableField("status")
-    private Integer status;
-
-    @ApiModelProperty(value = "当前就餐人数(就餐中时由首客填写,后续用户共用)")
-    @TableField("diner_count")
-    private Integer dinerCount;
-
-    @ApiModelProperty(value = "备注")
-    @TableField("remark")
-    private String remark;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 75
alien-entity/src/main/java/shop/alien/entity/store/wechat/WeChatStoreTableLog.java

@@ -1,75 +0,0 @@
-package shop.alien.entity.store.wechat;
-
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * 微信小程序-桌号换桌记录表(字段与 {@link shop.alien.entity.store.StoreTableLog} 对齐,独立维护)
- */
-@Data
-@JsonInclude
-@TableName("wechat_store_table_log")
-@ApiModel(value = "WeChatStoreTableLog对象", description = "微信小程序桌号换桌记录表")
-public class WeChatStoreTableLog {
-
-    @ApiModelProperty(value = "主键ID")
-    @TableId(value = "id", type = IdType.AUTO)
-    private Integer id;
-
-    @ApiModelProperty(value = "门店ID")
-    @TableField("store_id")
-    private Integer storeId;
-
-    @ApiModelProperty(value = "订单ID")
-    @TableField("order_id")
-    private Integer orderId;
-
-    @ApiModelProperty(value = "原桌号ID")
-    @TableField("from_table_id")
-    private Integer fromTableId;
-
-    @ApiModelProperty(value = "原桌号")
-    @TableField("from_table_number")
-    private String fromTableNumber;
-
-    @ApiModelProperty(value = "目标桌号ID")
-    @TableField("to_table_id")
-    private Integer toTableId;
-
-    @ApiModelProperty(value = "目标桌号")
-    @TableField("to_table_number")
-    private String toTableNumber;
-
-    @ApiModelProperty(value = "换桌原因")
-    @TableField("change_reason")
-    private String changeReason;
-
-    @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
-    @TableField("delete_flag")
-    @TableLogic
-    private Integer deleteFlag;
-
-    @ApiModelProperty(value = "创建时间")
-    @TableField(value = "created_time", fill = FieldFill.INSERT)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty(value = "创建人ID")
-    @TableField("created_user_id")
-    private Integer createdUserId;
-
-    @ApiModelProperty(value = "修改时间")
-    @TableField(value = "updated_time", fill = FieldFill.INSERT_UPDATE)
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date updatedTime;
-
-    @ApiModelProperty(value = "修改人ID")
-    @TableField("updated_user_id")
-    private Integer updatedUserId;
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCartMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreCart;
-
-public interface WeChatStoreCartMapper extends BaseMapper<WeChatStoreCart> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCouponUsageMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreCouponUsage;
-
-public interface WeChatStoreCouponUsageMapper extends BaseMapper<WeChatStoreCouponUsage> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineCategoryMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreCuisineCategory;
-
-public interface WeChatStoreCuisineCategoryMapper extends BaseMapper<WeChatStoreCuisineCategory> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineComboMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreCuisineCombo;
-
-public interface WeChatStoreCuisineComboMapper extends BaseMapper<WeChatStoreCuisineCombo> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreCuisineMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreCuisine;
-
-public interface WeChatStoreCuisineMapper extends BaseMapper<WeChatStoreCuisine> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderChangeLogMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreOrderChangeLog;
-
-public interface WeChatStoreOrderChangeLogMapper extends BaseMapper<WeChatStoreOrderChangeLog> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderDetailMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreOrderDetail;
-
-public interface WeChatStoreOrderDetailMapper extends BaseMapper<WeChatStoreOrderDetail> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderLockMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreOrderLock;
-
-public interface WeChatStoreOrderLockMapper extends BaseMapper<WeChatStoreOrderLock> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreOrderMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreOrder;
-
-public interface WeChatStoreOrderMapper extends BaseMapper<WeChatStoreOrder> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreTableLogMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreTableLog;
-
-public interface WeChatStoreTableLogMapper extends BaseMapper<WeChatStoreTableLog> {
-}

+ 0 - 7
alien-entity/src/main/java/shop/alien/mapper/WeChatStoreTableMapper.java

@@ -1,7 +0,0 @@
-package shop.alien.mapper;
-
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import shop.alien.entity.store.wechat.WeChatStoreTable;
-
-public interface WeChatStoreTableMapper extends BaseMapper<WeChatStoreTable> {
-}

+ 2 - 2
alien-store/src/main/java/shop/alien/store/AlienStoreApplication.java

@@ -8,11 +8,11 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
-@ComponentScan({"shop.alien.store", "shop.alien.util", "shop.alien.config.http", "shop.alien.config.properties"})
+@ComponentScan({"shop.alien.store.*","shop.alien.util.*","shop.alien.config.http","shop.alien.config.properties"})
 @EnableSwaggerBootstrapUI
 @MapperScan({"shop.alien.mapper"})
 @SpringBootApplication
-@EnableFeignClients(basePackages = {"shop.alien.store.feign", "shop.alien.store.dining.feign"})
+@EnableFeignClients(basePackages = "shop.alien.store.feign")
 @EnableScheduling
 public class AlienStoreApplication {
 

+ 76 - 85
alien-store/src/main/java/shop/alien/store/controller/DiningServiceController.java

@@ -6,7 +6,6 @@ import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.http.MediaType;
-import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import shop.alien.entity.result.R;
@@ -14,15 +13,18 @@ import shop.alien.entity.store.StoreTable;
 import shop.alien.entity.store.dto.CartDTO;
 import shop.alien.entity.store.dto.ChangeTableDTO;
 import shop.alien.entity.store.vo.*;
-import shop.alien.store.dining.feign.AlienStoreFeign;
-import shop.alien.store.dining.service.*;
-import shop.alien.store.dining.util.TokenUtil;
+import shop.alien.store.feign.DiningServiceFeign;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.List;
 
 /**
- * APP 端点餐网关:委托本模块内嵌的 {@code shop.alien.store.dining} 服务(读写 store_* 表),
- * 不再远程调用 alien-dining。
+ * 点餐服务 Controller
+ * 供前端调用 alien-dining 模块的接口
+ *
+ * @author ssk
+ * @version 1.0
+ * @date 2025/01/XX
  */
 @Slf4j
 @Api(tags = {"点餐服务接口"})
@@ -33,13 +35,20 @@ import java.util.List;
 @RequiredArgsConstructor
 public class DiningServiceController {
 
-    private final DiningService diningService;
-    private final CartService cartService;
-    private final StoreOrderService storeOrderService;
-    private final StoreInfoService storeInfoService;
-    private final DiningUserService diningUserService;
-    /** 同进程自省调用时请配置 feign.alienStore.url(如 http://127.0.0.1:${server.port}) */
-    private final AlienStoreFeign alienStoreFeign;
+    private final DiningServiceFeign diningServiceFeign;
+
+    /**
+     * 从请求头获取 Authorization token
+     */
+    private String getAuthorization(HttpServletRequest request) {
+        String authorization = request.getHeader("Authorization");
+        if (authorization == null || authorization.isEmpty()) {
+            authorization = request.getHeader("authorization");
+        }
+        return authorization;
+    }
+
+    // ==================== 点餐相关接口 ====================
 
     @ApiOperation(value = "查询餐桌是否处于就餐中", notes = "免登录可调用,返回 inDining、dinerCount,供前端判断是否跳过选择用餐人数")
     @ApiOperationSupport(order = 0)
@@ -48,7 +57,7 @@ public class DiningServiceController {
             @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
         try {
             log.info("查询餐桌就餐状态: tableId={}", tableId);
-            return R.data(diningService.getTableDiningStatus(tableId));
+            return diningServiceFeign.getTableDiningStatus(tableId);
         } catch (Exception e) {
             log.error("查询餐桌就餐状态失败: {}", e.getMessage(), e);
             return R.fail("查询餐桌就餐状态失败: " + e.getMessage());
@@ -59,15 +68,13 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 1)
     @GetMapping("/page-info")
     public R<DiningPageInfoVO> getDiningPageInfo(
+            HttpServletRequest request,
             @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
             @ApiParam(value = "就餐人数(首客必传;餐桌已就餐中时可省略)") @RequestParam(required = false) Integer dinerCount) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取点餐页面信息: tableId={}, dinerCount={}", tableId, dinerCount);
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data(diningService.getDiningPageInfo(tableId, dinerCount));
+            return diningServiceFeign.getDiningPageInfo(authorization, tableId, dinerCount);
         } catch (Exception e) {
             log.error("获取点餐页面信息失败: {}", e.getMessage(), e);
             return R.fail("获取点餐页面信息失败: " + e.getMessage());
@@ -78,19 +85,14 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 2)
     @GetMapping("/search")
     public R<List<CuisineListVO>> searchCuisines(
+            HttpServletRequest request,
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
             @ApiParam(value = "搜索关键词", required = true) @RequestParam String keyword,
             @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("搜索菜品: storeId={}, keyword={}, tableId={}", storeId, keyword, tableId);
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            if (StringUtils.hasText(keyword) && keyword.length() > 10) {
-                keyword = keyword.substring(0, 10);
-            }
-            return R.data(diningService.searchCuisines(storeId, keyword, tableId));
+            return diningServiceFeign.searchCuisines(authorization, storeId, keyword, tableId);
         } catch (Exception e) {
             log.error("搜索菜品失败: {}", e.getMessage(), e);
             return R.fail("搜索菜品失败: " + e.getMessage());
@@ -101,19 +103,17 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 3)
     @GetMapping("/cuisines")
     public R<List<CuisineListVO>> getCuisinesByCategory(
+            HttpServletRequest request,
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
             @ApiParam(value = "分类ID(可为空,查询所有)") @RequestParam(required = false) Integer categoryId,
             @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer page,
             @ApiParam(value = "每页数量", defaultValue = "12") @RequestParam(defaultValue = "12") Integer size) {
         try {
+            String authorization = getAuthorization(request);
             log.info("根据分类获取菜品列表: storeId={}, categoryId={}, tableId={}, page={}, size={}",
                     storeId, categoryId, tableId, page, size);
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data(diningService.getCuisinesByCategory(storeId, categoryId, tableId, page, size));
+            return diningServiceFeign.getCuisinesByCategory(authorization, storeId, categoryId, tableId, page, size);
         } catch (Exception e) {
             log.error("根据分类获取菜品列表失败: {}", e.getMessage(), e);
             return R.fail("根据分类获取菜品列表失败: " + e.getMessage());
@@ -124,15 +124,13 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 4)
     @GetMapping("/cuisine/{cuisineId}")
     public R<CuisineDetailVO> getCuisineDetail(
+            HttpServletRequest request,
             @ApiParam(value = "菜品ID", required = true) @PathVariable Integer cuisineId,
             @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取菜品详情: cuisineId={}, tableId={}", cuisineId, tableId);
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data(diningService.getCuisineDetail(cuisineId, tableId));
+            return diningServiceFeign.getCuisineDetail(authorization, cuisineId, tableId);
         } catch (Exception e) {
             log.error("获取菜品详情失败: {}", e.getMessage(), e);
             return R.fail("获取菜品详情失败: " + e.getMessage());
@@ -143,31 +141,30 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 5)
     @GetMapping("/coupons/available")
     public R<List<AvailableCouponVO>> getAvailableCoupons(
+            HttpServletRequest request,
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取可领取的优惠券列表: storeId={}", storeId);
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data(diningService.getAvailableCoupons(storeId, userId));
+            return diningServiceFeign.getAvailableCoupons(authorization, storeId);
         } catch (Exception e) {
             log.error("获取可领取的优惠券列表失败: {}", e.getMessage(), e);
             return R.fail("获取可领取的优惠券列表失败: " + e.getMessage());
         }
     }
 
+    // ==================== 订单相关接口 ====================
+
     @ApiOperation(value = "获取购物车", notes = "根据桌号ID获取购物车信息")
     @ApiOperationSupport(order = 6)
     @GetMapping("/order/cart/{tableId}")
     public R<CartDTO> getCart(
+            HttpServletRequest request,
             @ApiParam(value = "桌号ID", required = true) @PathVariable Integer tableId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取购物车: tableId={}", tableId);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            return R.data(cartService.getCart(tableId));
+            return diningServiceFeign.getCart(authorization, tableId);
         } catch (Exception e) {
             log.error("获取购物车失败: {}", e.getMessage(), e);
             return R.fail("获取购物车失败: " + e.getMessage());
@@ -178,14 +175,12 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 7)
     @PostMapping("/order/change-table")
     public R<CartDTO> changeTable(
+            HttpServletRequest request,
             @ApiParam(value = "换桌参数(原桌号ID、目标桌号ID、换桌原因)", required = true) @RequestBody ChangeTableDTO dto) {
         try {
+            String authorization = getAuthorization(request);
             log.info("换桌: fromTableId={}, toTableId={}, changeReason={}", dto.getFromTableId(), dto.getToTableId(), dto.getChangeReason());
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data(storeOrderService.changeTable(dto.getFromTableId(), dto.getToTableId(), dto.getChangeReason(), userId));
+            return diningServiceFeign.changeTable(authorization, dto);
         } catch (Exception e) {
             log.error("换桌失败: {}", e.getMessage(), e);
             return R.fail("换桌失败: " + e.getMessage());
@@ -196,13 +191,12 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 8)
     @GetMapping("/order/{orderId}")
     public R<OrderDetailWithChangeLogVO> getOrderDetail(
+            HttpServletRequest request,
             @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取订单详情: orderId={}", orderId);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            return R.data(storeOrderService.getOrderDetailWithChangeLog(orderId));
+            return diningServiceFeign.getOrderDetail(authorization, orderId);
         } catch (Exception e) {
             log.error("获取订单详情失败: {}", e.getMessage(), e);
             return R.fail("获取订单详情失败: " + e.getMessage());
@@ -213,17 +207,14 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 8)
     @GetMapping("/order/list")
     public R<IPage<StoreOrderPageVO>> getOrderList(
+            HttpServletRequest request,
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer page,
             @ApiParam(value = "每页数量", defaultValue = "10") @RequestParam(defaultValue = "10") Integer size,
             @ApiParam(value = "订单状态(可选)") @RequestParam(required = false) Integer status) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取订单列表: page={}, size={}, status={}", page, size, status);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            Page<shop.alien.entity.store.StoreOrder> p = new Page<>(page, size);
-            IPage<StoreOrderPageVO> data = storeOrderService.getOrderPageWithCuisines(p, null, null, status, null);
-            return R.data(data);
+            return diningServiceFeign.getOrderList(authorization, page, size, status);
         } catch (Exception e) {
             log.error("获取订单列表失败: {}", e.getMessage(), e);
             return R.fail("获取订单列表失败: " + e.getMessage());
@@ -234,6 +225,7 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 8)
     @GetMapping("/order/page")
     public R<IPage<StoreOrderPageVO>> getOrderPage(
+            HttpServletRequest request,
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Long current,
             @ApiParam(value = "每页数量", defaultValue = "10") @RequestParam(defaultValue = "10") Long size,
             @ApiParam(value = "门店ID") @RequestParam(required = false) Integer storeId,
@@ -241,14 +233,12 @@ public class DiningServiceController {
             @ApiParam(value = "订单状态(0:待支付, 1:已支付, 2:已取消, 3:已完成)") @RequestParam(required = false) Integer orderStatus,
             @ApiParam(value = "搜索关键词(订单编号或菜品名称,限15字)") @RequestParam(required = false) String keyword) {
         try {
+            String authorization = getAuthorization(request);
             log.info("分页查询订单列表: current={}, size={}, storeId={}, tableId={}, orderStatus={}, keyword={}",
                     current, size, storeId, tableId, orderStatus, keyword);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            Page<shop.alien.entity.store.StoreOrder> page = new Page<>(current, size);
-            IPage<StoreOrderPageVO> data = storeOrderService.getOrderPageWithCuisines(page, storeId, tableId, orderStatus, keyword);
-            return R.data(data);
+            R<Page<StoreOrderPageVO>> result = diningServiceFeign.getOrderPage(authorization, current, size, storeId, tableId, orderStatus, keyword);
+            // 将 Page 转换为 IPage 返回(Page 实现了 IPage 接口,可以直接返回)
+            return R.data(result.getData());
         } catch (Exception e) {
             log.error("分页查询订单列表失败: {}", e.getMessage(), e);
             return R.fail("分页查询订单列表失败: " + e.getMessage());
@@ -259,13 +249,12 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 9)
     @GetMapping("/order/change-log/{orderId}")
     public R<List<OrderChangeLogBatchVO>> getOrderChangeLogs(
+            HttpServletRequest request,
             @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("查询订单变更记录: orderId={}", orderId);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            return R.data(storeOrderService.getOrderChangeLogs(orderId));
+            return diningServiceFeign.getOrderChangeLogs(authorization, orderId);
         } catch (Exception e) {
             log.error("查询订单变更记录失败: {}", e.getMessage(), e);
             return R.fail("查询订单变更记录失败: " + e.getMessage());
@@ -276,36 +265,36 @@ public class DiningServiceController {
     @ApiOperationSupport(order = 10)
     @PostMapping("/order/complete-by-merchant/{orderId}")
     public R<Boolean> completeOrderByMerchant(
+            HttpServletRequest request,
             @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
         try {
+            String authorization = getAuthorization(request);
             log.info("商家手动完成订单: orderId={}", orderId);
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            return R.data(storeOrderService.completeOrderByMerchant(orderId));
+            return diningServiceFeign.completeOrderByMerchant(authorization, orderId);
         } catch (Exception e) {
             log.error("商家手动完成订单失败: {}", e.getMessage(), e);
             return R.fail("商家手动完成订单失败: " + e.getMessage());
         }
     }
 
+    // ==================== 用户相关接口 ====================
+
     @ApiOperation(value = "获取用户信息", notes = "获取当前登录用户的详细信息(从token中获取用户ID)")
     @ApiOperationSupport(order = 9)
     @GetMapping("/user/info")
-    public R<Object> getUserInfo() {
+    public R<Object> getUserInfo(HttpServletRequest request) {
         try {
+            String authorization = getAuthorization(request);
             log.info("获取用户信息");
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            return R.data((Object) diningUserService.getUserInfo(userId.longValue()));
+            return diningServiceFeign.getUserInfo(authorization);
         } catch (Exception e) {
             log.error("获取用户信息失败: {}", e.getMessage(), e);
             return R.fail("获取用户信息失败: " + e.getMessage());
         }
     }
 
+    // ==================== 门店信息接口 ====================
+
     @ApiOperation(value = "根据门店ID查询桌号列表", notes = "查询指定门店下的所有桌号")
     @ApiOperationSupport(order = 10)
     @GetMapping("/store/tables")
@@ -313,7 +302,7 @@ public class DiningServiceController {
             @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
         try {
             log.info("根据门店ID查询桌号列表: storeId={}", storeId);
-            return R.data(storeInfoService.getTablesByStoreId(storeId));
+            return diningServiceFeign.getTablesByStoreId(storeId);
         } catch (Exception e) {
             log.error("根据门店ID查询桌号列表失败: {}", e.getMessage(), e);
             return R.fail("根据门店ID查询桌号列表失败: " + e.getMessage());
@@ -328,7 +317,7 @@ public class DiningServiceController {
             @ApiParam(value = "菜品名称模糊查询关键词(可选)") @RequestParam(required = false) String keyword) {
         try {
             log.info("根据门店ID查询菜品种类及菜品: storeId={}, keyword={}", storeId, keyword);
-            return R.data(storeInfoService.getCategoriesWithCuisinesByStoreId(storeId, keyword));
+            return diningServiceFeign.getCategoriesWithCuisinesByStoreId(storeId, keyword);
         } catch (Exception e) {
             log.error("查询菜品种类及菜品失败: {}", e.getMessage(), e);
             return R.fail("查询菜品种类及菜品失败: " + e.getMessage());
@@ -342,13 +331,15 @@ public class DiningServiceController {
             @ApiParam(value = "菜品种类ID", required = true) @PathVariable Integer categoryId) {
         try {
             log.info("删除菜品种类: categoryId={}", categoryId);
-            return R.data(storeInfoService.deleteCategory(categoryId));
+            return diningServiceFeign.deleteCategory(categoryId);
         } catch (Exception e) {
             log.error("删除菜品种类失败: {}", e.getMessage(), e);
             return R.fail("删除菜品种类失败: " + e.getMessage());
         }
     }
 
+    // ==================== 文件上传接口 ====================
+
     @ApiOperation(value = "上传图片到OSS", notes = "支持图片、视频或PDF文件上传,返回OSS文件路径")
     @ApiOperationSupport(order = 11)
     @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@@ -359,7 +350,7 @@ public class DiningServiceController {
                 return R.fail("文件不能为空");
             }
             log.info("上传文件: fileName={}, size={}", file.getOriginalFilename(), file.getSize());
-            return alienStoreFeign.uploadFile(file);
+            return diningServiceFeign.uploadFile(file);
         } catch (Exception e) {
             log.error("上传文件失败: {}", e.getMessage(), e);
             return R.fail("上传文件失败: " + e.getMessage());

+ 0 - 26
alien-store/src/main/java/shop/alien/store/dining/annotation/OperationLog.java

@@ -1,26 +0,0 @@
-package shop.alien.store.dining.annotation;
-
-import java.lang.annotation.*;
-
-/**
- * 操作日志注解
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface OperationLog {
-    /**
-     * 操作描述
-     */
-    String value() default "";
-
-    /**
-     * 操作类型
-     */
-    String type() default "";
-}
-

+ 0 - 28
alien-store/src/main/java/shop/alien/store/dining/aspect/OperationLogAspect.java

@@ -1,28 +0,0 @@
-package shop.alien.store.dining.aspect;
-
-import lombok.extern.slf4j.Slf4j;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.springframework.stereotype.Component;
-import shop.alien.store.dining.annotation.OperationLog;
-
-/**
- * 操作日志切面
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Slf4j
-@Aspect
-@Component("diningMiniOperationLogAspect")
-public class OperationLogAspect {
-
-    @Before("@annotation(operationLog)")
-    public void before(JoinPoint joinPoint, OperationLog operationLog) {
-        // TODO: 实现操作日志记录逻辑
-        log.info("操作日志: {}", operationLog.value());
-    }
-}
-

+ 0 - 388
alien-store/src/main/java/shop/alien/store/dining/config/CartWebSocketProcess.java

@@ -1,388 +0,0 @@
-package shop.alien.store.dining.config;
-
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-import shop.alien.store.config.WebSocketConfig;
-import shop.alien.store.dining.service.CartService;
-import shop.alien.entity.store.dto.AddCartItemDTO;
-import shop.alien.entity.store.dto.CartDTO;
-
-import javax.websocket.*;
-import javax.websocket.server.PathParam;
-import javax.websocket.server.ServerEndpoint;
-import java.io.IOException;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * 购物车WebSocket处理类
- * 支持双向通信:前端可以发送购物车变化,后端可以推送购物车更新
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Component
-@ServerEndpoint(value = "/ws/cart/{tableId}", configurator = WebSocketConfig.WebSocketConfigurator.class)
-public class CartWebSocketProcess implements ApplicationContextAware {
-
-    private static ApplicationContext applicationContext;
-    private static CartService cartService;
-
-    // 存储每个桌号的WebSocket连接,一个桌号可以有多个连接(多个用户)
-    private static final ConcurrentHashMap<Integer, ConcurrentHashMap<String, CartWebSocketProcess>> connections = new ConcurrentHashMap<>();
-
-    /**
-     * 会话对象
-     */
-    private Session session;
-
-    /**
-     * 桌号ID
-     */
-    private Integer tableId;
-
-    /**
-     * 连接ID
-     */
-    private String connectionId;
-
-    @Override
-    public void setApplicationContext(ApplicationContext context) {
-        CartWebSocketProcess.applicationContext = context;
-        CartWebSocketProcess.cartService = context.getBean(CartService.class);
-    }
-
-    /**
-     * 客户端创建连接时触发
-     */
-    @OnOpen
-    public void onOpen(@PathParam("tableId") Integer tableId, Session session) {
-        try {
-            this.session = session;
-            this.tableId = tableId;
-            // 设置30分钟超时
-            this.session.setMaxIdleTimeout(30 * 60 * 1000);
-            
-            // 生成连接ID
-            this.connectionId = "conn_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();
-
-            // 存储连接
-            connections.computeIfAbsent(tableId, k -> new ConcurrentHashMap<>()).put(connectionId, this);
-
-            log.info("购物车WebSocket连接建立, tableId={}, connectionId={}", tableId, connectionId);
-
-            // 发送连接成功消息
-            sendMessage(createMessage("connected", "连接成功", null));
-
-            // 发送当前购物车数据
-            try {
-                CartDTO cart = cartService.getCart(tableId);
-                sendMessage(createMessage("cart_update", "购物车数据", cart));
-            } catch (Exception e) {
-                log.error("获取购物车数据失败, tableId={}", tableId, e);
-            }
-
-        } catch (Exception e) {
-            log.error("WebSocket连接建立失败, tableId={}", tableId, e);
-        }
-    }
-
-    /**
-     * 接收到客户端消息时触发
-     */
-    @OnMessage
-    public void onMessage(String message) {
-        try {
-            log.info("收到客户端消息, tableId={}, connectionId={}, message={}", tableId, connectionId, message);
-
-            // 解析消息
-            JSONObject jsonMessage = JSON.parseObject(message);
-            String type = jsonMessage.getString("type");
-
-            if (type == null) {
-                sendError("消息类型不能为空");
-                return;
-            }
-
-            // 处理不同类型的消息
-            switch (type) {
-                case "heartbeat":
-                    // 心跳消息,直接回复
-                    sendMessage(createMessage("heartbeat", "pong", null));
-                    break;
-
-                case "add_item":
-                    // 添加商品到购物车
-                    handleAddItem(jsonMessage);
-                    break;
-
-                case "update_quantity":
-                    // 更新商品数量
-                    handleUpdateQuantity(jsonMessage);
-                    break;
-
-                case "remove_item":
-                    // 删除商品
-                    handleRemoveItem(jsonMessage);
-                    break;
-
-                case "clear_cart":
-                    // 清空购物车
-                    handleClearCart();
-                    break;
-
-                default:
-                    sendError("未知的消息类型: " + type);
-                    break;
-            }
-
-        } catch (Exception e) {
-            log.error("处理客户端消息失败, tableId={}, connectionId={}", tableId, connectionId, e);
-            sendError("处理消息失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 客户端连接关闭时触发
-     */
-    @OnClose
-    public void onClose() {
-        try {
-            removeConnection();
-            log.info("购物车WebSocket连接关闭, tableId={}, connectionId={}", tableId, connectionId);
-        } catch (Exception e) {
-            log.error("关闭WebSocket连接失败, tableId={}, connectionId={}", tableId, connectionId, e);
-        }
-    }
-
-    /**
-     * 连接发生异常时触发
-     */
-    @OnError
-    public void onError(Throwable error) {
-        log.error("WebSocket连接错误, tableId={}, connectionId={}", tableId, connectionId, error);
-        removeConnection();
-    }
-
-    /**
-     * 处理添加商品
-     */
-    private void handleAddItem(JSONObject jsonMessage) {
-        try {
-            JSONObject data = jsonMessage.getJSONObject("data");
-            if (data == null) {
-                sendError("添加商品数据不能为空");
-                return;
-            }
-
-            AddCartItemDTO dto = new AddCartItemDTO();
-            dto.setTableId(tableId);
-            dto.setCuisineId(data.getInteger("cuisineId"));
-            dto.setQuantity(data.getInteger("quantity"));
-            dto.setRemark(data.getString("remark"));
-
-            // 调用服务添加商品
-            CartDTO cart = cartService.addItem(dto);
-
-            // 推送更新给该桌号的所有连接
-            pushCartUpdateToAll(tableId, cart);
-
-            // 回复成功消息
-            sendMessage(createMessage("add_item_success", "添加商品成功", cart));
-
-        } catch (Exception e) {
-            log.error("添加商品失败, tableId={}", tableId, e);
-            sendError("添加商品失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 处理更新商品数量
-     */
-    private void handleUpdateQuantity(JSONObject jsonMessage) {
-        try {
-            JSONObject data = jsonMessage.getJSONObject("data");
-            if (data == null) {
-                sendError("更新数量数据不能为空");
-                return;
-            }
-
-            Integer cuisineId = data.getInteger("cuisineId");
-            Integer quantity = data.getInteger("quantity");
-
-            if (cuisineId == null || quantity == null) {
-                sendError("菜品ID和数量不能为空");
-                return;
-            }
-
-            // 调用服务更新数量
-            CartDTO cart = cartService.updateItemQuantity(tableId, cuisineId, quantity);
-
-            // 推送更新给该桌号的所有连接
-            pushCartUpdateToAll(tableId, cart);
-
-            // 回复成功消息
-            sendMessage(createMessage("update_quantity_success", "更新数量成功", cart));
-
-        } catch (Exception e) {
-            log.error("更新商品数量失败, tableId={}", tableId, e);
-            sendError("更新数量失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 处理删除商品
-     */
-    private void handleRemoveItem(JSONObject jsonMessage) {
-        try {
-            JSONObject data = jsonMessage.getJSONObject("data");
-            if (data == null) {
-                sendError("删除商品数据不能为空");
-                return;
-            }
-
-            Integer cuisineId = data.getInteger("cuisineId");
-            if (cuisineId == null) {
-                sendError("菜品ID不能为空");
-                return;
-            }
-
-            // 调用服务删除商品
-            CartDTO cart = cartService.removeItem(tableId, cuisineId);
-
-            // 推送更新给该桌号的所有连接
-            pushCartUpdateToAll(tableId, cart);
-
-            // 回复成功消息
-            sendMessage(createMessage("remove_item_success", "删除商品成功", cart));
-
-        } catch (Exception e) {
-            log.error("删除商品失败, tableId={}", tableId, e);
-            sendError("删除商品失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 处理清空购物车
-     */
-    private void handleClearCart() {
-        try {
-            // 调用服务清空购物车
-            cartService.clearCart(tableId);
-
-            // 创建空的购物车对象
-            CartDTO cart = new CartDTO();
-            cart.setTableId(tableId);
-            cart.setItems(java.util.Collections.emptyList());
-            cart.setTotalAmount(java.math.BigDecimal.ZERO);
-            cart.setTotalQuantity(0);
-
-            // 推送更新给该桌号的所有连接
-            pushCartUpdateToAll(tableId, cart);
-
-            // 回复成功消息
-            sendMessage(createMessage("clear_cart_success", "清空购物车成功", cart));
-
-        } catch (Exception e) {
-            log.error("清空购物车失败, tableId={}", tableId, e);
-            sendError("清空购物车失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 推送购物车更新给该桌号的所有连接
-     */
-    private void pushCartUpdateToAll(Integer tableId, CartDTO cart) {
-        ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
-        if (tableConnections != null && !tableConnections.isEmpty()) {
-            tableConnections.forEach((connId, ws) -> {
-                try {
-                    ws.sendMessage(createMessage("cart_update", "购物车更新", cart));
-                } catch (Exception e) {
-                    log.error("推送购物车更新失败, tableId={}, connectionId={}", tableId, connId, e);
-                }
-            });
-        }
-    }
-
-    /**
-     * 发送消息
-     */
-    public void sendMessage(String message) {
-        try {
-            if (session != null && session.isOpen()) {
-                session.getBasicRemote().sendText(message);
-            }
-        } catch (IOException e) {
-            log.error("发送WebSocket消息失败, tableId={}, connectionId={}", tableId, connectionId, e);
-            removeConnection();
-        }
-    }
-
-    /**
-     * 发送错误消息
-     */
-    private void sendError(String errorMessage) {
-        sendMessage(createMessage("error", errorMessage, null));
-    }
-
-    /**
-     * 创建消息JSON字符串
-     */
-    private String createMessage(String type, String message, Object data) {
-        JSONObject json = new JSONObject();
-        json.put("type", type);
-        json.put("message", message);
-        json.put("data", data);
-        json.put("timestamp", System.currentTimeMillis());
-        return json.toJSONString();
-    }
-
-    /**
-     * 移除连接
-     */
-    private void removeConnection() {
-        if (tableId != null && connectionId != null) {
-            ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
-            if (tableConnections != null) {
-                tableConnections.remove(connectionId);
-                if (tableConnections.isEmpty()) {
-                    connections.remove(tableId);
-                }
-            }
-        }
-    }
-
-    /**
-     * 静态方法:推送购物车更新(供外部调用,如HTTP接口)
-     */
-    public static void pushCartUpdate(Integer tableId, CartDTO cart) {
-        ConcurrentHashMap<String, CartWebSocketProcess> tableConnections = connections.get(tableId);
-        if (tableConnections != null && !tableConnections.isEmpty()) {
-            String message = createStaticMessage("cart_update", "购物车更新", cart);
-            tableConnections.forEach((connectionId, ws) -> {
-                try {
-                    ws.sendMessage(message);
-                } catch (Exception e) {
-                    log.error("推送购物车更新失败, tableId={}, connectionId={}", tableId, connectionId, e);
-                }
-            });
-        }
-    }
-
-    /**
-     * 静态方法:创建消息
-     */
-    private static String createStaticMessage(String type, String message, Object data) {
-        JSONObject json = new JSONObject();
-        json.put("type", type);
-        json.put("message", message);
-        json.put("data", data);
-        json.put("timestamp", System.currentTimeMillis());
-        return json.toJSONString();
-    }
-}

+ 0 - 48
alien-store/src/main/java/shop/alien/store/dining/controller/DiningCollectController.java

@@ -1,48 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiOperationSupport;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiSort;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeCollect;
-import shop.alien.store.dining.service.DiningCollectService;
-
-/**
- * 点餐模块-收藏控制器(Feign 调 store,供小程序使用)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/01/XX
- */
-@Slf4j
-@Api(tags = {"微信点餐-收藏(用户端)"})
-@ApiSort(4)
-@CrossOrigin
-@RestController
-@RequestMapping("/dining/collect")
-@RequiredArgsConstructor
-public class DiningCollectController {
-
-    private final DiningCollectService diningCollectService;
-
-    /**
-     * 添加收藏
-     */
-    @ApiOperation(value = "添加收藏", notes = "添加收藏,支持收藏店铺、商品等")
-    @ApiOperationSupport(order = 1)
-    @PostMapping("/addCollect")
-    public R<Boolean> addCollect(@ApiParam(value = "收藏对象", required = true) @RequestBody LifeCollect lifeCollect) {
-        log.info("DiningCollectController.addCollect?lifeCollect={}", lifeCollect);
-        try {
-            return diningCollectService.addCollect(lifeCollect);
-        } catch (Exception e) {
-            log.error("添加收藏失败: {}", e.getMessage(), e);
-            return R.fail("添加收藏失败: " + e.getMessage());
-        }
-    }
-}

+ 0 - 307
alien-store/src/main/java/shop/alien/store/dining/controller/DiningController.java

@@ -1,307 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import io.swagger.annotations.*;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.*;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.vo.TableDiningStatusVO;
-import shop.alien.entity.store.vo.*;
-import shop.alien.store.dining.service.DiningService;
-import shop.alien.store.dining.util.TokenUtil;
-
-import java.util.List;
-
-/**
- * 点餐控制器
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Api(tags = {"小程序-点餐管理"})
-@CrossOrigin
-@RestController
-@RequestMapping("/store/dining")
-@RequiredArgsConstructor
-public class DiningController {
-
-    private final DiningService diningService;
-
-    @ApiOperation(value = "查询餐桌是否处于就餐中", notes = "免登录可调用,用于前端判断是否跳过选择用餐人数。就餐中(status=1)、加餐(status=3) 均视为就餐状态,且 diner_count 有值 时 inDining=true")
-    @GetMapping("/table-dining-status")
-    public R<TableDiningStatusVO> getTableDiningStatus(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.getTableDiningStatus?tableId={}", tableId);
-        try {
-            TableDiningStatusVO vo = diningService.getTableDiningStatus(tableId);
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("查询餐桌就餐状态失败: {}", e.getMessage(), e);
-            return R.fail("查询餐桌就餐状态失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "获取点餐页面信息", notes = "首客选桌时传就餐人数,餐桌置为就餐中并保存人数;后续用户选同一桌可不传就餐人数,将使用表中已保存人数")
-    @GetMapping("/page-info")
-    public R<DiningPageInfoVO> getDiningPageInfo(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "就餐人数(首客必传;餐桌已就餐中时可省略,将使用已保存人数)") @RequestParam(required = false) Integer dinerCount) {
-        log.info("DiningController.getDiningPageInfo?tableId={}, dinerCount={}", tableId, dinerCount);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            DiningPageInfoVO vo = diningService.getDiningPageInfo(tableId, dinerCount);
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("获取点餐页面信息失败: {}", e.getMessage(), e);
-            return R.fail("获取点餐页面信息失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "搜索菜品", notes = "模糊搜索菜品,关键词限10字")
-    @GetMapping("/search")
-    public R<List<CuisineListVO>> searchCuisines(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
-            @ApiParam(value = "搜索关键词", required = false) @RequestParam(required = false) String keyword,
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.searchCuisines?storeId={}, keyword={}, tableId={}", storeId, keyword, tableId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            // 限制关键词长度
-            if (StringUtils.hasText(keyword) && keyword.length() > 10) {
-                keyword = keyword.substring(0, 10);
-            }
-            List<CuisineListVO> list = diningService.searchCuisines(storeId, keyword, tableId);
-            return R.data(list);
-        } catch (Exception e) {
-            log.error("搜索菜品失败: {}", e.getMessage(), e);
-            return R.fail("搜索菜品失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "根据分类获取菜品列表", notes = "分页获取菜品列表,默认每页12条")
-    @GetMapping("/cuisines")
-    public R<List<CuisineListVO>> getCuisinesByCategory(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
-            @ApiParam(value = "分类ID", required = false) @RequestParam(required = false) Integer categoryId,
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "页码", required = false) @RequestParam(defaultValue = "1") Integer page,
-            @ApiParam(value = "每页数量", required = false) @RequestParam(defaultValue = "12") Integer size) {
-        log.info("DiningController.getCuisinesByCategory?storeId={}, categoryId={}, tableId={}, page={}, size={}", storeId, categoryId, tableId, page, size);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            List<CuisineListVO> list = diningService.getCuisinesByCategory(storeId, categoryId, tableId, page, size);
-            return R.data(list);
-        } catch (Exception e) {
-            log.error("获取菜品列表失败: {}", e.getMessage(), e);
-            return R.fail("获取菜品列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "获取菜品详情", notes = "获取菜品详细信息,包含图片列表、月售数量等")
-    @GetMapping("/cuisine/{cuisineId}")
-    public R<CuisineDetailVO> getCuisineDetail(
-            @ApiParam(value = "菜品ID", required = true) @PathVariable Integer cuisineId,
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.getCuisineDetail?cuisineId={}, tableId={}", cuisineId, tableId);
-        try {
-            CuisineDetailVO vo = diningService.getCuisineDetail(cuisineId, tableId);
-            
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("获取菜品详情失败: {}", e.getMessage(), e);
-            return R.fail("获取菜品详情失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "获取可领取的优惠券列表", notes = "获取用户可领取的优惠券")
-    @GetMapping("/coupons/available")
-    public R<List<AvailableCouponVO>> getAvailableCoupons(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
-        log.info("DiningController.getAvailableCoupons?storeId={}", storeId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            List<AvailableCouponVO> list = diningService.getAvailableCoupons(storeId, userId);
-            return R.data(list);
-        } catch (Exception e) {
-            log.error("获取可领取优惠券列表失败: {}", e.getMessage(), e);
-            return R.fail("获取可领取优惠券列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "领取优惠券", notes = "用户领取优惠券")
-    @PostMapping("/coupon/receive")
-    public R<Boolean> receiveCoupon(
-            @ApiParam(value = "优惠券ID", required = true) @RequestParam Integer couponId) {
-        log.info("DiningController.receiveCoupon?couponId={}", couponId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = diningService.receiveCoupon(couponId, userId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("领取优惠券失败: {}", e.getMessage(), e);
-            return R.fail("领取优惠券失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "获取订单确认页面信息", notes = "获取订单确认页面的所有信息")
-    @GetMapping("/order/confirm")
-    public R<OrderConfirmVO> getOrderConfirmInfo(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "就餐人数", required = true) @RequestParam Integer dinerCount) {
-        log.info("DiningController.getOrderConfirmInfo?tableId={}, dinerCount={}", tableId, dinerCount);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            OrderConfirmVO vo = diningService.getOrderConfirmInfo(tableId, dinerCount, userId);
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("获取订单确认页面信息失败: {}", e.getMessage(), e);
-            return R.fail("获取订单确认页面信息失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "锁定订单", notes = "锁定订单,防止多人同时下单")
-    @PostMapping("/order/lock")
-    public R<Boolean> lockOrder(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.lockOrder?tableId={}", tableId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = diningService.lockOrder(tableId, userId);
-            if (!result) {
-                return R.fail("订单已被其他用户锁定,无法下单");
-            }
-            return R.data(true);
-        } catch (Exception e) {
-            log.error("锁定订单失败: {}", e.getMessage(), e);
-            return R.fail("锁定订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "解锁订单", notes = "解锁订单")
-    @PostMapping("/order/unlock")
-    public R<Boolean> unlockOrder(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.unlockOrder?tableId={}", tableId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            diningService.unlockOrder(tableId, userId);
-            return R.data(true);
-        } catch (Exception e) {
-            log.error("解锁订单失败: {}", e.getMessage(), e);
-            return R.fail("解锁订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "检查订单锁定状态", notes = "检查订单是否被锁定")
-    @GetMapping("/order/check-lock")
-    public R<Integer> checkOrderLock(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("DiningController.checkOrderLock?tableId={}", tableId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            Integer lockUserId = diningService.checkOrderLock(tableId);
-            return R.data(lockUserId);
-        } catch (Exception e) {
-            log.error("检查订单锁定状态失败: {}", e.getMessage(), e);
-            return R.fail("检查订单锁定状态失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "获取订单结算确认页面信息", notes = "获取订单结算确认页面的所有信息")
-    @GetMapping("/order/settlement")
-    public R<shop.alien.entity.store.vo.OrderSettlementVO> getOrderSettlementInfo(
-            @ApiParam(value = "订单ID", required = true) @RequestParam Integer orderId) {
-        log.info("DiningController.getOrderSettlementInfo?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            shop.alien.entity.store.vo.OrderSettlementVO vo = diningService.getOrderSettlementInfo(orderId, userId);
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("获取订单结算确认页面信息失败: {}", e.getMessage(), e);
-            return R.fail("获取订单结算确认页面信息失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "锁定订单结算", notes = "锁定订单结算,防止多人同时结算")
-    @PostMapping("/order/settlement/lock")
-    public R<Boolean> lockSettlement(
-            @ApiParam(value = "订单ID", required = true) @RequestParam Integer orderId) {
-        log.info("DiningController.lockSettlement?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = diningService.lockSettlement(orderId, userId);
-            if (!result) {
-                return R.fail("订单已被其他用户锁定,无法结算");
-            }
-            return R.data(true);
-        } catch (Exception e) {
-            log.error("锁定订单结算失败: {}", e.getMessage(), e);
-            return R.fail("锁定订单结算失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "解锁订单结算", notes = "解锁订单结算")
-    @PostMapping("/order/settlement/unlock")
-    public R<Boolean> unlockSettlement(
-            @ApiParam(value = "订单ID", required = true) @RequestParam Integer orderId) {
-        log.info("DiningController.unlockSettlement?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            diningService.unlockSettlement(orderId, userId);
-            return R.data(true);
-        } catch (Exception e) {
-            log.error("解锁订单结算失败: {}", e.getMessage(), e);
-            return R.fail("解锁订单结算失败: " + e.getMessage());
-        }
-    }
-}

+ 0 - 188
alien-store/src/main/java/shop/alien/store/dining/controller/DiningCouponController.java

@@ -1,188 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiOperationSupport;
-import io.swagger.annotations.ApiParam;
-import io.swagger.annotations.ApiSort;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.vo.LifeDiscountCouponVo;
-import shop.alien.store.dining.service.DiningCouponService;
-
-import javax.servlet.http.HttpServletRequest;
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 点餐模块-优惠券控制器(Feign 调 store,供小程序:我的优惠券/详情/选券)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/1/29
- */
-@Slf4j
-@Api(tags = {"微信点餐-优惠券(用户端)"})
-@ApiSort(3)
-@CrossOrigin
-@RestController
-@RequestMapping({"/dining/coupon"})
-@RequiredArgsConstructor
-public class DiningCouponController {
-
-    private final DiningCouponService diningCouponService;
-
-    /**
-     * 获取该用户所有的优惠券列表
-     */
-    @ApiOperation("获取该用户所有的优惠券列表。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
-    @ApiOperationSupport(order = 9)
-    @GetMapping("/getUserCouponList")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "page", value = "分页页数", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "size", value = "分页条数", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "tabType", value = "分页类型(0:全部(未使用),1:即将过期,2:已使用,3:已过期)", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "type", value = "券类型(不传:优惠券+代金券都返回,1:仅优惠券查 life_discount_coupon,4:仅代金券查 life_coupon)", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选,仅当type不为4时有效)", dataType = "Integer", paramType = "query", required = false),
-            @ApiImplicitParam(name = "storeId", value = "商铺ID,可为空,传则仅返回该商铺的优惠券", dataType = "String", paramType = "query", required = false),
-            @ApiImplicitParam(name = "storeName", value = "商铺名称模糊查询,可为空", dataType = "String", paramType = "query", required = false)
-    })
-    public R<List<LifeDiscountCouponVo>> getUserCouponList(
-            HttpServletRequest request,
-            @RequestParam(value = "page", defaultValue = "1") int page,
-            @RequestParam(value = "size", defaultValue = "10") int size,
-            @RequestParam("tabType") String tabType,
-            @RequestParam(value = "type", required = false) Integer type,
-            @RequestParam(value = "couponType", required = false) Integer couponType,
-            @RequestParam(value = "storeId", required = false) String storeId,
-            @RequestParam(value = "storeName", required = false) String storeName) {
-        log.info("DiningCouponController.getUserCouponList?page={}, size={}, tabType={}, type={}, couponType={}, storeId={}, storeName={}", page, size, tabType, type, couponType, storeId, storeName);
-        String authorization = request.getHeader("Authorization");
-        return diningCouponService.getUserCouponList(authorization, page, size, tabType, type, couponType, storeId, storeName);
-    }
-
-    /**
-     * 根据优惠券 id 获取优惠券详情(规则、门槛等)
-     */
-    @ApiOperation(value = "获取优惠券详情", notes = "需登录,请求头带 Authorization。counponId 与 store 接口拼写一致")
-    @GetMapping("/detail")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "counponId", value = "优惠券id", dataType = "String", paramType = "query", required = true)
-    })
-    public R<LifeDiscountCouponVo> getCounponDetailById(
-            HttpServletRequest request,
-            @RequestParam("counponId") String counponId) {
-        log.info("DiningCouponController.getCounponDetailById?counponId={}", counponId);
-        String authorization = request.getHeader("Authorization");
-        return diningCouponService.getCounponDetailById(authorization, counponId);
-    }
-
-    /**
-     * 获取该门店下用户可用/不可用优惠券列表(用于购物车/下单选券,按金额区分)
-     */
-    @ApiOperation(value = "获取门店可用优惠券列表", notes = "需登录。按 storeId+amount 返回可用券与不可用券及原因(满减门槛等)。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
-    @GetMapping("/storeUsableList")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "门店id", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "amount", value = "当前消费金额(满减门槛)", dataType = "BigDecimal", paramType = "query", required = true),
-            @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false)
-    })
-    public R<Map<String, Object>> getStoreUserUsableCouponList(
-            HttpServletRequest request,
-            @RequestParam("storeId") String storeId,
-            @RequestParam("amount") BigDecimal amount,
-            @ApiParam(value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券") @RequestParam(value = "couponType", required = false) Integer couponType) {
-        log.info("DiningCouponController.getStoreUserUsableCouponList?storeId={}, amount={}, couponType={}", storeId, amount, couponType);
-        String authorization = request.getHeader("Authorization");
-        return diningCouponService.getStoreUserUsableCouponList(authorization, storeId, amount, couponType);
-    }
-
-    /**
-     * 查询用户拥有的优惠券(按符合支付条件优先,其次优惠力度大的优先)
-     */
-    @ApiOperation(value = "查询用户拥有的优惠券", notes = "需登录。查询用户拥有的优惠券,排序:符合支付条件的优先,其次优惠力度大的优先")
-    @GetMapping("/userOwned")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "门店ID(可选,如果提供则只查询该门店的优惠券)", dataType = "String", paramType = "query", required = false),
-            @ApiImplicitParam(name = "amount", value = "当前消费金额(用于判断是否符合支付条件)", dataType = "BigDecimal", paramType = "query", required = false)
-    })
-    public R<List<LifeDiscountCouponVo>> getUserOwnedCoupons(
-            @ApiParam(value = "门店ID(可选)") @RequestParam(required = false) String storeId,
-            @ApiParam(value = "当前消费金额(可选,用于判断是否符合支付条件)") @RequestParam(required = false) BigDecimal amount) {
-        log.info("DiningCouponController.getUserOwnedCoupons?storeId={}, amount={}", storeId, amount);
-        return diningCouponService.getUserOwnedCoupons(storeId, amount);
-    }
-
-    /**
-     * 获取该用户该店铺优惠券列表
-     */
-    @ApiOperation(value = "获取该用户该店铺优惠券列表", notes = "需登录,请求头带 Authorization。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
-    @ApiOperationSupport(order = 7)
-    @GetMapping("/getStoreUserCouponList")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "商户id", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false)
-    })
-    public R<List<LifeDiscountCouponVo>> getStoreUserCouponList(
-            HttpServletRequest request,
-            @ApiParam(value = "商户id", required = true) @RequestParam("storeId") String storeId,
-            @ApiParam(value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券") @RequestParam(value = "couponType", required = false) Integer couponType) {
-        log.info("DiningCouponController.getStoreUserCouponList?storeId={}, couponType={}", storeId, couponType);
-        String authorization = request.getHeader("Authorization");
-        return diningCouponService.getStoreUserCouponList(authorization, storeId, couponType);
-    }
-
-    /**
-     * 查询用户目前所拥有的优惠券(可通过商铺ID进行查询)
-     */
-    @ApiOperation(value = "查询用户目前所拥有的优惠券", notes = "需登录。查询用户目前所拥有的优惠券(未使用且未过期),可通过商铺ID进行筛选。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券")
-    @ApiOperationSupport(order = 8)
-    @GetMapping("/userOwnedByStore")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "storeId", value = "商铺ID(可选,如果提供则只查询该商铺的优惠券)", dataType = "String", paramType = "query", required = false),
-            @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false)
-    })
-    public R<List<LifeDiscountCouponVo>> getUserOwnedCouponsByStore(
-            @ApiParam(value = "商铺ID(可选)") @RequestParam(required = false) String storeId,
-            @ApiParam(value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券") @RequestParam(value = "couponType", required = false) Integer couponType) {
-        log.info("DiningCouponController.getUserOwnedCouponsByStore?storeId={}, couponType={}", storeId, couponType);
-        return diningCouponService.getUserOwnedCouponsByStore(storeId, couponType);
-    }
-
-    /**
-     * 获取该店铺所有优惠券(分页), 好友优惠券
-     */
-    @ApiOperation(value = "获取该店铺所有优惠券(分页)", notes = "需登录,请求头带 Authorization。couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券。tab: 0:全部,1:进行中,2:已结束,3:草稿,4:未开始,5:已下架,6:已清库")
-    @ApiOperationSupport(order = 10)
-    @GetMapping("/getStoreAllCouponList")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "page", value = "页码", dataType = "int", paramType = "query", required = false),
-            @ApiImplicitParam(name = "size", value = "每页条数", dataType = "int", paramType = "query", required = false),
-            @ApiImplicitParam(name = "storeId", value = "商户id", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "couponName", value = "优惠券名称", dataType = "String", paramType = "query", required = false),
-            @ApiImplicitParam(name = "tab", value = "分页类型(0:全部,1:进行中,2:已结束,3:草稿,4:未开始,5:已下架,6:已清库)", dataType = "String", paramType = "query", required = true),
-            @ApiImplicitParam(name = "couponsFromType", value = "查询类型(1:我的优惠券,2:好友的优惠券)", dataType = "int", paramType = "query", required = false),
-            @ApiImplicitParam(name = "couponStatus", value = "优惠券状态(0:草稿,1:正式)", dataType = "int", paramType = "query", required = false),
-            @ApiImplicitParam(name = "couponType", value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)", dataType = "Integer", paramType = "query", required = false)
-    })
-    public R<IPage<LifeDiscountCouponVo>> getStoreAllCouponList(
-            HttpServletRequest request,
-            @ApiParam(value = "页码", defaultValue = "1") @RequestParam(value = "page", defaultValue = "1") int page,
-            @ApiParam(value = "每页条数", defaultValue = "10") @RequestParam(value = "size", defaultValue = "10") int size,
-            @ApiParam(value = "商户id", required = true) @RequestParam("storeId") String storeId,
-            @ApiParam(value = "优惠券名称") @RequestParam(value = "couponName", required = false) String couponName,
-            @ApiParam(value = "分页类型(0:全部,1:进行中,2:已结束,3:草稿,4:未开始,5:已下架,6:已清库)", required = true) @RequestParam("tab") String tab,
-            @ApiParam(value = "查询类型(1:我的优惠券,2:好友的优惠券)", defaultValue = "1") @RequestParam(value = "couponsFromType", defaultValue = "1") int couponsFromType,
-            @ApiParam(value = "优惠券状态(0:草稿,1:正式)", defaultValue = "1") @RequestParam(value = "couponStatus", defaultValue = "1", required = false) int couponStatus,
-            @ApiParam(value = "优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券") @RequestParam(value = "couponType", required = false) Integer couponType) {
-        log.info("DiningCouponController.getStoreAllCouponList?page={}, size={}, storeId={}, couponName={}, tab={}, couponsFromType={}, couponStatus={}, couponType={}", page, size, storeId, couponName, tab, couponsFromType, couponStatus, couponType);
-        String authorization = request.getHeader("Authorization");
-        return diningCouponService.getStoreAllCouponList(authorization, page, size, storeId, couponName, tab, couponsFromType, couponStatus, couponType);
-    }
-}

+ 0 - 60
alien-store/src/main/java/shop/alien/store/dining/controller/DiningFileUploadController.java

@@ -1,60 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiOperationSupport;
-import io.swagger.annotations.ApiSort;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-import shop.alien.entity.result.R;
-import shop.alien.store.dining.feign.AlienStoreFeign;
-
-/**
- * 点餐模块-文件上传控制器
- *
- * @author ssk
- * @version 1.0
- * @date 2025/01/XX
- */
-@Slf4j
-@Api(tags = {"小程序-文件上传"})
-@ApiSort(10)
-@CrossOrigin
-@RestController
-@RequestMapping("/dining/file")
-@RequiredArgsConstructor
-public class DiningFileUploadController {
-
-    private final AlienStoreFeign alienStoreFeign;
-
-    /**
-     * 上传图片到OSS(单个文件上传,支持图片、视频或PDF)
-     *
-     * @param file 文件对象
-     * @return R.data 为文件路径(String)
-     */
-    @ApiOperation(value = "上传图片到OSS", notes = "支持图片、视频或PDF文件上传,返回OSS文件路径")
-    @ApiOperationSupport(order = 1)
-    @PostMapping("/upload")
-    public R<String> upload(@RequestParam("file") MultipartFile file) {
-        log.info("DiningFileUploadController.upload?fileName={}", file != null ? file.getOriginalFilename() : null);
-        try {
-            if (file == null || file.isEmpty()) {
-                return R.fail("文件不能为空");
-            }
-            R<String> result = alienStoreFeign.uploadFile(file);
-            if (result.isSuccess()) {
-                log.info("文件上传成功,OSS路径:{}", result.getData());
-                return result;
-            } else {
-                log.error("文件上传失败:{}", result.getMsg());
-                return R.fail("文件上传失败:" + result.getMsg());
-            }
-        } catch (Exception e) {
-            log.error("文件上传异常:{}", e.getMessage(), e);
-            return R.fail("文件上传异常:" + e.getMessage());
-        }
-    }
-}

+ 0 - 148
alien-store/src/main/java/shop/alien/store/dining/controller/DiningUserController.java

@@ -1,148 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiSort;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import shop.alien.entity.result.R;
-import shop.alien.store.dining.dto.ChangePhoneDto;
-import shop.alien.store.dining.dto.UserProfileUpdateDto;
-import shop.alien.store.dining.dto.VerifyTokenDto;
-import shop.alien.store.dining.service.DiningUserService;
-import shop.alien.store.dining.util.TokenUtil;
-import shop.alien.store.dining.vo.DiningUserVo;
-import shop.alien.store.dining.vo.TokenVerifyVo;
-import org.apache.commons.lang3.StringUtils;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.validation.Valid;
-
-/**
- * 点餐用户控制器(内嵌点餐走 APP 统一登录:先调主站登录拿 JWT,请求头带 Authorization 再调本组接口)
- */
-@Slf4j
-@Api(tags = {"微信点餐-用户(APP 登录)"})
-@ApiSort(2)
-@CrossOrigin
-@RestController
-@RequestMapping("/dining/user")
-@RequiredArgsConstructor
-public class DiningUserController {
-
-    private final DiningUserService diningUserService;
-
-    @ApiOperation(value = "获取用户信息", notes = "请求头携带 APP 登录下发的 Authorization。从 token 解析用户 ID 后返回资料")
-    @GetMapping("/getUserInfo")
-    public R<DiningUserVo> getUserInfo() {
-        // 从 token 获取当前用户ID
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId == null) {
-            return R.fail("用户未登录");
-        }
-
-        log.info("获取用户信息: userId={}", userId);
-
-        DiningUserVo userVo = diningUserService.getUserInfo(userId.longValue());
-        if (userVo == null) {
-            return R.fail("用户不存在或状态异常");
-        }
-        return R.data(userVo);
-    }
-
-    @ApiOperation(value = "更新用户个人信息", notes = "登录后完善资料,支持更新昵称、头像、性别、生日等(从token中获取用户ID)")
-    @PostMapping("/updateProfile")
-    public R<DiningUserVo> updateProfile(@Valid @RequestBody UserProfileUpdateDto dto) {
-        // 从 token 获取当前用户ID
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId == null) {
-            return R.fail("用户未登录");
-        }
-
-        // 使用 token 中的用户ID,忽略 DTO 中的 userId(防止用户修改其他用户的信息)
-        dto.setUserId(userId.longValue());
-        log.info("更新用户个人信息: userId={}", userId);
-
-        DiningUserVo userVo = diningUserService.updateProfile(dto);
-        if (userVo == null) {
-            return R.fail("更新失败,用户不存在");
-        }
-        return R.data(userVo);
-    }
-
-    @ApiOperation(value = "更换手机号", notes = "校验验证码后更新 user_phone,成功后需重新登录(从token中获取用户ID)")
-    @PostMapping("/changePhone")
-    public R<DiningUserVo> changePhone(@Valid @RequestBody ChangePhoneDto dto) {
-        // 从 token 获取当前用户ID
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId == null) {
-            return R.fail("用户未登录");
-        }
-
-        // 使用 token 中的用户ID,忽略 DTO 中的 userId(防止用户修改其他用户的手机号)
-        dto.setUserId(userId.longValue());
-        log.info("更换手机号: userId={}, newPhone={}", userId, dto.getNewPhone());
-
-        DiningUserVo userVo = diningUserService.changePhone(dto);
-        if (userVo == null) {
-            return R.fail("更换失败,请检查验证码或用户状态");
-        }
-        return R.data(userVo);
-    }
-
-    @ApiOperation(value = "校验Token", notes = "验证 APP JWT 是否有效(验签、过期、用户状态),支持 Authorization 或请求体 token")
-    @PostMapping("/verifyToken")
-    public R<TokenVerifyVo> verifyToken(@RequestBody(required = false) VerifyTokenDto dto, HttpServletRequest request) {
-        // 优先从请求体获取 token,如果没有则从请求头获取
-        String token = null;
-        if (dto != null && StringUtils.isNotBlank(dto.getToken())) {
-            token = dto.getToken();
-        } else {
-            // 从请求头获取
-            token = request.getHeader("Authorization");
-        }
-
-        if (StringUtils.isBlank(token)) {
-            return R.fail("Token 不能为空,请通过请求头 Authorization 或请求体传递");
-        }
-
-        log.info("校验Token: token={}", token.length() > 20 ? token.substring(0, 20) + "****" : token);
-
-        TokenVerifyVo verifyVo = diningUserService.verifyToken(token);
-        if (verifyVo == null) {
-            return R.fail("Token 校验失败");
-        }
-
-        if (verifyVo.getValid()) {
-            return R.data(verifyVo);
-        } else {
-            return R.fail(verifyVo.getReason() != null ? verifyVo.getReason() : "Token 无效");
-        }
-    }
-
-    @ApiOperation(value = "解析Token(调试用)", notes = "解析Token内容,用于调试,返回Token中的所有用户信息")
-    @PostMapping("/parseToken")
-    public R<com.alibaba.fastjson.JSONObject> parseToken(@RequestBody(required = false) VerifyTokenDto dto, HttpServletRequest request) {
-        // 优先从请求体获取 token,如果没有则从请求头获取
-        String token = null;
-        if (dto != null && StringUtils.isNotBlank(dto.getToken())) {
-            token = dto.getToken();
-        } else {
-            // 从请求头获取
-            token = request.getHeader("Authorization");
-        }
-
-        if (StringUtils.isBlank(token)) {
-            return R.fail("Token 不能为空");
-        }
-
-        log.info("DiningUserController.parseToken?token={}", token.length() > 20 ? token.substring(0, 20) + "****" : token);
-        com.alibaba.fastjson.JSONObject userInfo = shop.alien.store.dining.util.TokenUtil.parseToken(token);
-        if (userInfo == null) {
-            return R.fail("Token 解析失败,请查看日志获取详细信息");
-        }
-
-        return R.data(userInfo);
-    }
-}

+ 0 - 128
alien-store/src/main/java/shop/alien/store/dining/controller/PaymentController.java

@@ -1,128 +0,0 @@
-package shop.alien.store.dining.controller;
-
-
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import shop.alien.store.dining.strategy.payment.PaymentStrategyFactory;
-import shop.alien.entity.result.R;
-import shop.alien.util.common.constant.PaymentEnum;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author lyx
- * @version 1.0
- * @date 2025/11/20 17:34
- */
-@Slf4j
-@Api(tags = {"2.5-支付接口"})
-@CrossOrigin
-@RestController
-@RequestMapping("/payment")
-@RequiredArgsConstructor
-public class PaymentController {
-
-    private final PaymentStrategyFactory paymentStrategyFactory;
-
-
-    @ApiOperation("创建预支付订单")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "price", value = "订单金额", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "subject", value = "订单标题", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "payType", value = "支付类型(alipay:支付宝, wechatPay:微信支付)", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "payer", value = "支付用户", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "storeId", value = "店铺ID,用于从 MySQL 获取该店铺支付配置(StorePaymentConfig)", required = true, paramType = "query", dataType = "Integer"),
-            @ApiImplicitParam(name ="couponId", value = "优惠券Id"),
-            @ApiImplicitParam(name = "payerId", value = "payerId"),
-            @ApiImplicitParam(name = "tablewareFee", value = "餐具费"),
-            @ApiImplicitParam(name = "discountAmount", value = "优惠金额"),
-            @ApiImplicitParam(name = "payAmount", value = "支付金额")
-    })
-    @RequestMapping("/prePay")
-    public R prePay(String price, String subject, String payType, String payer, String orderNo, Integer storeId,Integer couponId, Integer payerId,String tablewareFee,String discountAmount,String payAmount) {
-        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {}, payer: {}, orderNo: {}, storeId: {},couponId:{},payerId: {},tablewareFee: {},discountAmount: {},payAmount:{}", price, subject, payType, payer, orderNo, storeId,couponId,payerId,tablewareFee,discountAmount,payAmount);
-        try {
-            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject, payer, orderNo, storeId, couponId,payerId,tablewareFee,discountAmount,payAmount);
-        } catch (Exception e) {
-            log.info("createPrePayOrder, orderNo: {}, error: {}", orderNo, e.getMessage());
-            return R.fail(e.getMessage());
-        }
-    }
-
-    /**
-     * 微信支付回调通知接口(符合微信支付 V3 规范)
-     * 验签通过:返回 204 无包体;验签失败:返回 5XX + {"code":"FAIL","message":"失败"}
-     * @param notifyData 回调 JSON 报文
-     * @return 204 无 body 或 5XX + 失败报文
-     */
-    @RequestMapping("/weChatMininNotify")
-    public ResponseEntity<?> notify(@RequestBody String notifyData, HttpServletRequest request) throws Exception {
-        log.info("[微信支付回调] 收到回调请求, Content-Length={}, Wechatpay-Serial={}", request.getContentLength(), request.getHeader("Wechatpay-Serial"));
-        try {
-            R result = paymentStrategyFactory.getStrategy(PaymentEnum.WECHAT_PAY_MININ_PROGRAM.getType()).handleNotify(notifyData, request);
-            if (R.isSuccess(result)) {
-                // 文档要求:验签通过时 HTTP 200 或 204,无需返回应答报文
-                return ResponseEntity.noContent().build();
-            } else {
-                // 文档要求:验签不通过时 4XX/5XX,并返回 {"code":"FAIL","message":"失败"}
-                String message = result.getMsg() != null ? result.getMsg() : "失败";
-                Map<String, String> failBody = new HashMap<>(2);
-                failBody.put("code", "FAIL");
-                failBody.put("message", message);
-                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
-            }
-        } catch (Exception e) {
-            log.error("[微信支付回调] 处理异常", e);
-            String msg = e.getMessage() != null ? e.getMessage() : "失败";
-            Map<String, String> failBody = new HashMap<>(2);
-            failBody.put("code", "FAIL");
-            failBody.put("message", msg);
-            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(failBody);
-        }
-    }
-
-    /**
-     * 查询订单状态
-     * @param transactionId 交易订单号(微信支付订单号/商户订单号)
-     * @param payType 支付类型
-     * @param storeId 店铺ID,用于从 MySQL 获取该店铺支付配置
-     * @return 订单状态信息
-     */
-    @RequestMapping("/searchOrderByOutTradeNoPath")
-    public R searchOrderByOutTradeNoPath(String transactionId, String payType, Integer storeId) {
-        log.info("PaymentController.searchOrderByOutTradeNoPath?transactionId={}, payType={}, storeId={}", transactionId, payType, storeId);
-        try {
-            return paymentStrategyFactory.getStrategy(payType).searchOrderByOutTradeNoPath(transactionId, storeId);
-        } catch (Exception e) {
-            return R.fail(e.getMessage());
-        }
-    }
-
-    /**
-     * 退款接口
-     * @param params 退款参数(包含订单号、退款金额等)
-     * @return 退款结果
-     */
-    @RequestMapping("/refunds")
-    public R refunds(@RequestBody Map<String, String> params) {
-        log.info("PaymentController.refunds?params={}", params);
-        try {
-            return R.data(paymentStrategyFactory.getStrategy(params.get("payType")).handleRefund(params));
-        } catch (Exception e) {
-            return R.fail(e.getMessage());
-        }
-    }
-}

+ 0 - 135
alien-store/src/main/java/shop/alien/store/dining/controller/StoreInfoController.java

@@ -1,135 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import io.swagger.annotations.*;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.*;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.StoreCuisine;
-import shop.alien.entity.store.StoreCuisineCategory;
-import shop.alien.entity.store.StoreTable;
-import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
-import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
-import shop.alien.store.dining.service.StoreInfoService;
-
-import java.util.List;
-
-/**
- * 门店信息查询控制器
- *
- * @author system
- * @since 2025-02-02
- */
-@Slf4j
-@Api(tags = {"小程序-门店信息查询"})
-@CrossOrigin
-@RestController
-@RequestMapping("/store/info")
-@RequiredArgsConstructor
-public class StoreInfoController {
-
-    private final StoreInfoService storeInfoService;
-
-    @ApiOperation(value = "根据门店ID查询桌号列表", notes = "查询指定门店下的所有桌号")
-    @GetMapping("/tables")
-    public R<List<StoreTable>> getTablesByStoreId(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
-        log.info("StoreInfoController.getTablesByStoreId?storeId={}", storeId);
-        try {
-            if (storeId == null) {
-                return R.fail("门店ID不能为空");
-            }
-            List<StoreTable> tables = storeInfoService.getTablesByStoreId(storeId);
-            return R.data(tables);
-        } catch (Exception e) {
-            log.error("查询桌号列表失败: {}", e.getMessage(), e);
-            return R.fail("查询桌号列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "根据门店ID查询菜品种类列表", notes = "查询指定门店下的所有菜品种类")
-    @GetMapping("/categories")
-    public R<List<StoreCuisineCategory>> getCategoriesByStoreId(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId) {
-        log.info("StoreInfoController.getCategoriesByStoreId?storeId={}", storeId);
-        try {
-            if (storeId == null) {
-                return R.fail("门店ID不能为空");
-            }
-            List<StoreCuisineCategory> categories = storeInfoService.getCategoriesByStoreId(storeId);
-            return R.data(categories);
-        } catch (Exception e) {
-            log.error("查询菜品种类列表失败: {}", e.getMessage(), e);
-            return R.fail("查询菜品种类列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "根据门店ID查询菜品种类及各类别下菜品", notes = "一次返回所有菜品种类及每个分类下的菜品列表;可选 keyword 按菜品名称模糊查询。返回中 category 与 /store/info/categories 单条结构一致,cuisines 与 /store/info/cuisines 返回结构一致,保证字段完整一致。")
-    @GetMapping("/categories-with-cuisines")
-    public R<List<CategoryWithCuisinesVO>> getCategoriesWithCuisinesByStoreId(
-            @ApiParam(value = "门店ID", required = true) @RequestParam Integer storeId,
-            @ApiParam(value = "菜品名称模糊查询关键词(可选)") @RequestParam(required = false) String keyword) {
-        log.info("StoreInfoController.getCategoriesWithCuisinesByStoreId?storeId={}, keyword={}", storeId, keyword);
-        try {
-            if (storeId == null) {
-                return R.fail("门店ID不能为空");
-            }
-            List<CategoryWithCuisinesVO> list = storeInfoService.getCategoriesWithCuisinesByStoreId(storeId, keyword);
-            return R.data(list);
-        } catch (Exception e) {
-            log.error("查询菜品种类及菜品失败: {}", e.getMessage(), e);
-            return R.fail("查询菜品种类及菜品失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "删除菜品种类", notes = "仅删除绑定关系和菜品种类(逻辑删除);价目表中的菜品记录不删除、其它字段不变,仅从 category_ids 中移除该分类ID")
-    @DeleteMapping("/category/{categoryId}")
-    public R<Boolean> deleteCategory(
-            @ApiParam(value = "菜品种类ID", required = true) @PathVariable Integer categoryId) {
-        log.info("StoreInfoController.deleteCategory?categoryId={}", categoryId);
-        try {
-            if (categoryId == null) {
-                return R.fail("菜品种类ID不能为空");
-            }
-            boolean result = storeInfoService.deleteCategory(categoryId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("删除菜品种类失败: {}", e.getMessage(), e);
-            return R.fail("删除菜品种类失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "根据菜品种类ID查询菜品信息列表", notes = "查询指定分类下的所有菜品信息")
-    @GetMapping("/cuisines")
-    public R<List<StoreCuisine>> getCuisinesByCategoryId(
-            @ApiParam(value = "菜品种类ID", required = true) @RequestParam Integer categoryId) {
-        log.info("StoreInfoController.getCuisinesByCategoryId?categoryId={}", categoryId);
-        try {
-            if (categoryId == null) {
-                return R.fail("菜品种类ID不能为空");
-            }
-            List<StoreCuisine> cuisines = storeInfoService.getCuisinesByCategoryId(categoryId);
-            return R.data(cuisines);
-        } catch (Exception e) {
-            log.error("查询菜品信息列表失败: {}", e.getMessage(), e);
-            return R.fail("查询菜品信息列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "根据商铺ID查询店铺信息和首页展示美食价目表", notes = "查询店铺信息和当前店铺绑定的首页展示美食价目表信息")
-    @GetMapping("/detail/{storeId}")
-    public R<StoreInfoWithHomepageCuisinesDTO> getStoreInfoWithHomepageCuisines(
-            @ApiParam(value = "商铺ID", required = true) @PathVariable Integer storeId) {
-        log.info("StoreInfoController.getStoreInfoWithHomepageCuisines?storeId={}", storeId);
-        try {
-            if (storeId == null) {
-                return R.fail("商铺ID不能为空");
-            }
-            StoreInfoWithHomepageCuisinesDTO result = storeInfoService.getStoreInfoWithHomepageCuisines(storeId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("查询店铺信息和首页展示美食价目表失败: {}", e.getMessage(), e);
-            return R.fail("查询店铺信息和首页展示美食价目表失败: " + e.getMessage());
-        }
-    }
-}

+ 0 - 579
alien-store/src/main/java/shop/alien/store/dining/controller/StoreOrderController.java

@@ -1,579 +0,0 @@
-package shop.alien.store.dining.controller;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-import shop.alien.store.dining.service.CartService;
-import shop.alien.store.dining.service.SseService;
-import shop.alien.store.dining.service.StoreOrderService;
-import shop.alien.store.dining.util.TokenUtil;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.*;
-
-import shop.alien.entity.store.dto.AddCartItemDTO;
-import shop.alien.entity.store.dto.CartDTO;
-import shop.alien.entity.store.dto.ChangeTableDTO;
-import shop.alien.entity.store.dto.CreateOrderDTO;
-import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
-import shop.alien.entity.store.vo.OrderInfoVO;
-import shop.alien.entity.store.vo.OrderDetailWithChangeLogVO;
-import shop.alien.entity.store.vo.StoreOrderPageVO;
-import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.StoreOrderDetailMapper;
-import shop.alien.mapper.StoreTableMapper;
-
-import javax.validation.Valid;
-import java.util.List;
-
-/**
- * 订单管理控制器
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Api(tags = {"小程序-订单管理"})
-@CrossOrigin
-@RestController
-@RequestMapping("/store/order")
-@RequiredArgsConstructor
-public class StoreOrderController {
-
-    private final StoreOrderService orderService;
-    private final CartService cartService;
-    private final SseService sseService;
-    private final StoreOrderDetailMapper orderDetailMapper;
-    private final StoreTableMapper storeTableMapper;
-    private final StoreInfoMapper storeInfoMapper;
-
-    @ApiOperation(value = "获取购物车", notes = "根据桌号ID获取购物车信息")
-    @GetMapping("/cart/{tableId}")
-    public R<CartDTO> getCart(@ApiParam(value = "桌号ID", required = true) @PathVariable Integer tableId) {
-        log.info("StoreOrderController.getCart?tableId={}", tableId);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            CartDTO cart = cartService.getCart(tableId);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("获取购物车失败: {}", e.getMessage(), e);
-            return R.fail("获取购物车失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "添加商品到购物车", notes = "添加商品到购物车,并推送SSE和WebSocket消息")
-    @PostMapping("/cart/add")
-    public R<CartDTO> addCartItem(@Valid @RequestBody AddCartItemDTO dto) {
-        log.info("StoreOrderController.addCartItem?dto={}", dto);
-        try {
-            // 验证 token(用户信息在 CartService 中从 token 获取)
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            CartDTO cart = cartService.addItem(dto);
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(dto.getTableId(), cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(dto.getTableId(), cart);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("添加商品到购物车失败: {}", e.getMessage(), e);
-            return R.fail("添加商品到购物车失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "更新购物车商品数量", notes = "更新购物车中商品的数量,并推送SSE和WebSocket消息")
-    @PutMapping("/cart/update")
-    public R<CartDTO> updateCartItem(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "菜品ID", required = true) @RequestParam Integer cuisineId,
-            @ApiParam(value = "数量", required = true) @RequestParam Integer quantity) {
-        log.info("StoreOrderController.updateCartItem?tableId={}, cuisineId={}, quantity={}", tableId, cuisineId, quantity);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            CartDTO cart = cartService.updateItemQuantity(tableId, cuisineId, quantity);
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(tableId, cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(tableId, cart);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("更新购物车商品数量失败: {}", e.getMessage(), e);
-            return R.fail("更新购物车商品数量失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "删除购物车商品", notes = "从购物车中删除商品,并推送SSE和WebSocket消息")
-    @DeleteMapping("/cart/remove")
-    public R<CartDTO> removeCartItem(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "菜品ID", required = true) @RequestParam Integer cuisineId) {
-        log.info("StoreOrderController.removeCartItem?tableId={}, cuisineId={}", tableId, cuisineId);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            CartDTO cart = cartService.removeItem(tableId, cuisineId);
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(tableId, cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(tableId, cart);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("删除购物车商品失败: {}", e.getMessage(), e);
-            return R.fail("删除购物车商品失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "清空购物车", notes = "清空购物车中所有商品(保留餐具和已下单商品),并推送SSE和WebSocket消息")
-    @DeleteMapping("/cart/clear")
-    public R<CartDTO> clearCart(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId) {
-        log.info("StoreOrderController.clearCart?tableId={}", tableId);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            
-            // 清空购物车(会自动保留已下单的商品和餐具)
-            cartService.clearCart(tableId);
-            
-            // 获取清空后的购物车(包含保留的餐具和已下单商品)
-            CartDTO cart = cartService.getCart(tableId);
-            
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(tableId, cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(tableId, cart);
-            
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("清空购物车失败: {}", e.getMessage(), e);
-            return R.fail("清空购物车失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "设置用餐人数", notes = "设置用餐人数,自动添加或更新餐具到购物车")
-    @PostMapping("/cart/set-diner-count")
-    public R<CartDTO> setDinerCount(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "用餐人数", required = true) @RequestParam Integer dinerCount) {
-        log.info("StoreOrderController.setDinerCount?tableId={}, dinerCount={}", tableId, dinerCount);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            if (dinerCount == null || dinerCount <= 0) {
-                return R.fail("用餐人数必须大于0");
-            }
-            CartDTO cart = cartService.setDinerCount(tableId, dinerCount);
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(tableId, cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(tableId, cart);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("设置用餐人数失败: {}", e.getMessage(), e);
-            return R.fail("设置用餐人数失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "更新餐具数量", notes = "更新购物车中餐具的数量,并推送SSE和WebSocket消息。餐具数量为0或未传时不往购物车加餐具(0会移除已有餐具项)")
-    @PutMapping("/cart/update-tableware")
-    public R<CartDTO> updateTablewareQuantity(
-            @ApiParam(value = "桌号ID", required = true) @RequestParam Integer tableId,
-            @ApiParam(value = "餐具数量,0或未传则不往购物车加餐具") @RequestParam(required = false) Integer quantity) {
-        log.info("StoreOrderController.updateTablewareQuantity?tableId={}, quantity={}", tableId, quantity);
-        try {
-            // 验证 token
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            if (quantity != null && quantity < 0) {
-                return R.fail("餐具数量不能小于0");
-            }
-            // 餐具数量为 0 或 null 时不往购物车加餐具:0 则移除已有餐具项,null 则直接返回当前购物车
-            if (quantity == null) {
-                CartDTO cart = cartService.getCart(tableId);
-                sseService.pushCartUpdate(tableId, cart);
-                return R.data(cart);
-            }
-            if (quantity == 0) {
-                CartDTO cart = cartService.updateTablewareQuantity(tableId, 0);
-                sseService.pushCartUpdate(tableId, cart);
-                return R.data(cart);
-            }
-            CartDTO cart = cartService.updateTablewareQuantity(tableId, quantity);
-            // 推送购物车更新消息(SSE)
-            sseService.pushCartUpdate(tableId, cart);
-            // 推送购物车更新消息(WebSocket)
-//            CartWebSocketProcess.pushCartUpdate(tableId, cart);
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("更新餐具数量失败: {}", e.getMessage(), e);
-            return R.fail("更新餐具数量失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "创建订单(下单)", notes = "从购物车创建订单,不立即支付。备注:创建/更新时传入,更新订单(加餐)时为覆盖")
-    @PostMapping("/create")
-    public R<shop.alien.entity.store.vo.OrderSuccessVO> createOrder(@Valid @RequestBody CreateOrderDTO dto) {
-        log.info("StoreOrderController.createOrder?dto={}", dto);
-        try {
-            // 验证 token(用户信息在 StoreOrderService 中从 token 获取)
-            if (!TokenUtil.hasValidToken()) {
-                return R.fail("用户未登录");
-            }
-            // 限制备注长度
-            if (dto.getRemark() != null && dto.getRemark().length() > 30) {
-                dto.setRemark(dto.getRemark().substring(0, 30));
-            }
-
-            // 设置不立即支付
-            dto.setImmediatePay(0);
-            StoreOrder order = orderService.createOrder(dto);
-
-            // 转换为OrderSuccessVO
-            shop.alien.entity.store.vo.OrderSuccessVO vo = new shop.alien.entity.store.vo.OrderSuccessVO();
-            vo.setOrderId(order.getId());
-            vo.setOrderNo(order.getOrderNo());
-            vo.setTableNumber(order.getTableNumber());
-            vo.setDinerCount(order.getDinerCount());
-            vo.setOrderStatus(order.getOrderStatus());
-
-            // 查询门店信息
-            StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
-            vo.setStoreName(storeInfo != null ? storeInfo.getStoreName() : null);
-
-            // 推送订单创建消息
-            sseService.pushCartUpdate(dto.getTableId(), order);
-            return R.data(vo);
-        } catch (Exception e) {
-            log.error("创建订单失败: {}", e.getMessage(), e);
-            return R.fail("创建订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "支付订单", notes = "支付订单,支付成功后订单状态变为已支付(1),需要单独调用完成订单接口将订单状态改为已完成(3)")
-    @PostMapping("/pay/{orderId}")
-    public R<Object> payOrder(
-            @ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId,
-            @ApiParam(value = "支付方式(1:微信, 2:支付宝, 3:现金)", required = true) @RequestParam Integer payType) {
-        log.info("StoreOrderController.payOrder?orderId={}, payType={}", orderId, payType);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            
-            StoreOrder order = orderService.getOrderById(orderId);
-            if (order == null) {
-                return R.fail("订单不存在");
-            }
-
-            if (order.getOrderStatus() != 0) {
-                return R.fail("订单状态不正确,无法支付");
-            }
-
-            // 如果是微信支付,调用微信支付接口
-            if (payType == 1) {
-                // TODO: 调用微信支付接口,返回支付参数
-                // 这里需要集成微信支付SDK,返回支付参数给前端拉起支付
-                // 支付成功后通过回调接口更新订单状态
-                // 暂时先更新订单状态为已支付(实际应该等支付回调)
-                order = orderService.payOrder(orderId, payType);
-                return R.data(order);
-            } else {
-                // 其他支付方式(支付宝、现金)直接更新为已支付
-                order = orderService.payOrder(orderId, payType);
-                return R.data(order);
-            }
-        } catch (Exception e) {
-            log.error("支付订单失败: {}", e.getMessage(), e);
-            return R.fail("支付订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "取消订单", notes = "取消订单")
-    @PostMapping("/cancel/{orderId}")
-    public R<Boolean> cancelOrder(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.cancelOrder?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = orderService.cancelOrder(orderId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("取消订单失败: {}", e.getMessage(), e);
-            return R.fail("取消订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "查询订单详情", notes = "根据订单ID查询订单详情,包含订单基本信息和按批次分组的变更记录,用于展示每次下单/加餐都加了什么商品")
-    @GetMapping("/detail/{orderId}")
-    public R<OrderDetailWithChangeLogVO> getOrderDetail(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.getOrderDetail?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            OrderDetailWithChangeLogVO orderDetail = orderService.getOrderDetailWithChangeLog(orderId);
-            return R.data(orderDetail);
-        } catch (Exception e) {
-            log.error("查询订单详情失败: {}", e.getMessage(), e);
-            return R.fail("查询订单详情失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "查询订单明细", notes = "根据订单ID查询订单明细列表")
-    @GetMapping("/detail/list/{orderId}")
-    public R<List<StoreOrderDetail>> getOrderDetailList(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.getOrderDetailList?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<StoreOrderDetail> wrapper =
-                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
-            wrapper.eq(StoreOrderDetail::getOrderId, orderId);
-            wrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-            wrapper.orderByDesc(StoreOrderDetail::getCreatedTime);
-            List<StoreOrderDetail> details = orderDetailMapper.selectList(wrapper);
-            return R.data(details);
-        } catch (Exception e) {
-            log.error("查询订单明细失败: {}", e.getMessage(), e);
-            return R.fail("查询订单明细失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "查询订单信息", notes = "根据订单ID查询订单完整信息(包含订单基本信息、菜品清单、价格明细)")
-    @GetMapping("/info/{orderId}")
-    public R<OrderInfoVO> getOrderInfo(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.getOrderInfo?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            OrderInfoVO orderInfo = orderService.getOrderInfo(orderId);
-            return R.data(orderInfo);
-        } catch (Exception e) {
-            log.error("查询订单信息失败: {}", e.getMessage(), e);
-            return R.fail("查询订单信息失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "查询订单变更记录", notes = "根据订单ID查询订单的所有变更记录(按批次分组),用于展示每次下单/加餐都加了什么商品")
-    @GetMapping("/change-log/{orderId}")
-    public R<List<OrderChangeLogBatchVO>> getOrderChangeLogs(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.getOrderChangeLogs?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            List<OrderChangeLogBatchVO> changeLogs = orderService.getOrderChangeLogs(orderId);
-            return R.data(changeLogs);
-        } catch (Exception e) {
-            log.error("查询订单变更记录失败: {}", e.getMessage(), e);
-            return R.fail("查询订单变更记录失败: " + e.getMessage());
-        }
-    }
-
-
-    @ApiOperation(value = "分页查询订单列表", notes = "分页查询订单列表,包含订单中的菜品数量、菜品名称、菜品图片。支持按订单编号或菜品名称搜索(限15字)")
-    @GetMapping("/page")
-    public R<IPage<StoreOrderPageVO>> getOrderPage(
-            @ApiParam(value = "页码", required = true) @RequestParam(defaultValue = "1") Long current,
-            @ApiParam(value = "每页数量", required = true) @RequestParam(defaultValue = "10") Long size,
-            @ApiParam(value = "门店ID") @RequestParam(required = false) Integer storeId,
-            @ApiParam(value = "桌号ID") @RequestParam(required = false) Integer tableId,
-            @ApiParam(value = "订单状态:0=进行中(待支付+已支付),3=已完成") @RequestParam(required = false) Integer orderStatus,
-            @ApiParam(value = "搜索关键词(订单编号或菜品名称,限15字)") @RequestParam(required = false) String keyword) {
-        log.info("StoreOrderController.getOrderPage?current={}, size={}, storeId={}, tableId={}, orderStatus={}, keyword={}", current, size, storeId, tableId, orderStatus, keyword);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            Page<StoreOrder> page = new Page<>(current, size);
-            IPage<StoreOrderPageVO> result = orderService.getOrderPageWithCuisines(page, storeId, tableId, orderStatus, keyword);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("分页查询订单列表失败: {}", e.getMessage(), e);
-            return R.fail("分页查询订单列表失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "查询我的订单", notes = "通过标识查询我的未支付订单或历史订单,包含订单中的菜品数量、菜品名称、菜品图片。type: 0或unpaid-未支付订单, 1或history-历史订单")
-    @GetMapping("/my-orders")
-    public R<IPage<StoreOrderPageVO>> getMyOrders(
-            @ApiParam(value = "页码", required = true) @RequestParam(defaultValue = "1") Long current,
-            @ApiParam(value = "每页数量", required = true) @RequestParam(defaultValue = "10") Long size,
-            @ApiParam(value = "订单类型(0或unpaid:未支付订单, 1或history:历史订单)", required = true) @RequestParam String type) {
-        log.info("StoreOrderController.getMyOrders?current={}, size={}, type={}", current, size, type);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            Page<StoreOrder> page = new Page<>(current, size);
-            IPage<StoreOrderPageVO> result = orderService.getMyOrdersWithCuisines(page, type);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("查询我的订单失败: {}", e.getMessage(), e);
-            return R.fail("查询我的订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "换桌", notes = "换桌并迁移购物车、未完成的订单以及其他关联表数据")
-    @PostMapping("/change-table")
-    public R<CartDTO> changeTable(@Valid @RequestBody ChangeTableDTO dto) {
-        log.info("StoreOrderController.changeTable?dto={}", dto);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-
-            // 调用Service层处理换桌业务逻辑
-            CartDTO cart = orderService.changeTable(dto.getFromTableId(), dto.getToTableId(), dto.getChangeReason(), userId);
-
-            return R.data(cart);
-        } catch (Exception e) {
-            log.error("换桌失败: {}", e.getMessage(), e);
-            return R.fail("换桌失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "建立SSE连接", notes = "建立SSE连接,用于接收购物车更新消息")
-    @GetMapping(value = "/sse/{tableId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
-    public SseEmitter createSseConnection(@ApiParam(value = "桌号ID", required = true) @PathVariable Integer tableId) {
-        // 验证 token
-        if (!TokenUtil.hasValidToken()) {
-            log.warn("建立SSE连接失败: 用户未登录, tableId={}", tableId);
-            return null;
-        }
-        log.info("建立SSE连接, tableId={}", tableId);
-        return sseService.createConnection(tableId);
-    }
-
-    @ApiOperation(value = "完成订单", notes = "完成订单,将已支付状态的订单改为已完成状态。订单状态:0-待支付,1-已支付,3-已完成。只有已支付状态的订单才能完成")
-    @PostMapping("/complete/{orderId}")
-    public R<Boolean> completeOrder(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.completeOrder?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = orderService.completeOrder(orderId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("完成订单失败: {}", e.getMessage(), e);
-            return R.fail("完成订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "商家手动完成订单", notes = "供商家使用,手动点击完成订单。不校验订单是否处于已支付状态,直接将订单状态改为已完成。订单状态:0-待支付,1-已支付,2-已取消,3-已完成")
-    @PostMapping("/complete-by-merchant/{orderId}")
-    public R<Boolean> completeOrderByMerchant(@ApiParam(value = "订单ID", required = true) @PathVariable Integer orderId) {
-        log.info("StoreOrderController.completeOrderByMerchant?orderId={}", orderId);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            boolean result = orderService.completeOrderByMerchant(orderId);
-            return R.data(result);
-        } catch (Exception e) {
-            log.error("商家手动完成订单失败: {}", e.getMessage(), e);
-            return R.fail("商家手动完成订单失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "更新订单优惠券", notes = "重新选择优惠券")
-    @PostMapping("/update-coupon")
-    public R<StoreOrder> updateOrderCoupon(@Valid @RequestBody shop.alien.entity.store.dto.UpdateOrderCouponDTO dto) {
-        log.info("StoreOrderController.updateOrderCoupon?dto={}", dto);
-        try {
-            // 从 token 获取用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-            StoreOrder order = orderService.updateOrderCoupon(dto.getOrderId(), dto.getCouponId());
-            return R.data(order);
-        } catch (Exception e) {
-            log.error("更新订单优惠券失败: {}", e.getMessage(), e);
-            return R.fail("更新订单优惠券失败: " + e.getMessage());
-        }
-    }
-
-    @ApiOperation(value = "管理员重置餐桌", notes = "管理员重置餐桌:删除购物车数据、未支付/已取消的订单数据,并重置餐桌表初始化。已支付/已完成的订单会被保留,避免数据丢失")
-    @PostMapping("/admin/reset-table/{tableId}")
-    public R<Boolean> resetTable(@ApiParam(value = "餐桌ID", required = true) @PathVariable Integer tableId) {
-        log.info("StoreOrderController.resetTable?tableId={}", tableId);
-        try {
-            // TODO: 这里可以添加管理员权限验证
-            // if (!isAdmin(userId)) {
-            //     return R.fail("无权限执行此操作");
-            // }
-            
-            boolean result = orderService.resetTable(tableId);
-            if (result) {
-                // 推送购物车更新消息(清空购物车)
-                CartDTO emptyCart = new CartDTO();
-                emptyCart.setTableId(tableId);
-                emptyCart.setItems(java.util.Collections.emptyList());
-                emptyCart.setTotalAmount(java.math.BigDecimal.ZERO);
-                emptyCart.setTotalQuantity(0);
-                
-                // 查询桌号信息
-                StoreTable table = storeTableMapper.selectById(tableId);
-                if (table != null) {
-                    emptyCart.setTableNumber(table.getTableNumber());
-                    emptyCart.setStoreId(table.getStoreId());
-                }
-                
-                sseService.pushCartUpdate(tableId, emptyCart);
-                return R.data(true);
-            } else {
-                return R.fail("重置餐桌失败");
-            }
-        } catch (Exception e) {
-            log.error("重置餐桌失败: {}", e.getMessage(), e);
-            return R.fail("重置餐桌失败: " + e.getMessage());
-        }
-    }
-}

+ 0 - 34
alien-store/src/main/java/shop/alien/store/dining/dto/ChangePhoneDto.java

@@ -1,34 +0,0 @@
-package shop.alien.store.dining.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-
-/**
- * 更换手机号请求
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Data
-@ApiModel("更换手机号请求")
-public class ChangePhoneDto {
-
-    @ApiModelProperty(value = "用户ID", required = true)
-    @NotNull(message = "用户ID不能为空")
-    private Long userId;
-
-    @ApiModelProperty(value = "新手机号", required = true)
-    @NotBlank(message = "新手机号不能为空")
-    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
-    private String newPhone;
-
-    @ApiModelProperty(value = "验证码", required = true)
-    @NotBlank(message = "验证码不能为空")
-    private String code;
-}

+ 0 - 56
alien-store/src/main/java/shop/alien/store/dining/dto/UserProfileUpdateDto.java

@@ -1,56 +0,0 @@
-package shop.alien.store.dining.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotNull;
-import java.util.Date;
-
-/**
- * 用户个人信息更新DTO
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Data
-@ApiModel("用户个人信息更新请求")
-public class UserProfileUpdateDto {
-
-    @ApiModelProperty(value = "用户ID", required = true)
-    @NotNull(message = "用户ID不能为空")
-    private Long userId;
-
-    @ApiModelProperty(value = "昵称")
-    private String nickName;
-
-    @ApiModelProperty(value = "头像URL")
-    private String avatarUrl;
-
-    @ApiModelProperty(value = "性别(男/女)")
-    private String gender;
-
-    @ApiModelProperty(value = "生日", example = "1990-01-01")
-    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
-    private Date birthday;
-
-    @ApiModelProperty(value = "真实姓名")
-    private String realName;
-
-    @ApiModelProperty(value = "省份")
-    private String province;
-
-    @ApiModelProperty(value = "城市")
-    private String city;
-
-    @ApiModelProperty(value = "区县")
-    private String district;
-
-    @ApiModelProperty(value = "详细地址")
-    private String address;
-
-    @ApiModelProperty(value = "个人简介")
-    private String jianjie;
-}

+ 0 - 20
alien-store/src/main/java/shop/alien/store/dining/dto/VerifyTokenDto.java

@@ -1,20 +0,0 @@
-package shop.alien.store.dining.dto;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-/**
- * Token 校验请求DTO
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Data
-@ApiModel("Token校验请求")
-public class VerifyTokenDto {
-
-    @ApiModelProperty(value = "Token(可选,如果不传则从请求头 Authorization 获取)", required = false)
-    private String token;
-}

+ 0 - 48
alien-store/src/main/java/shop/alien/store/dining/enums/OrderStatus.java

@@ -1,48 +0,0 @@
-package shop.alien.store.dining.enums;
-
-/**
- * 订单状态枚举
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-public enum OrderStatus {
-    /**
-     * 待支付
-     */
-    PENDING_PAYMENT(0, "待支付"),
-    /**
-     * 已支付
-     */
-    PAID(1, "已支付"),
-    /**
-     * 制作中
-     */
-    PREPARING(2, "制作中"),
-    /**
-     * 已完成
-     */
-    COMPLETED(3, "已完成"),
-    /**
-     * 已取消
-     */
-    CANCELLED(4, "已取消");
-
-    private final Integer code;
-    private final String desc;
-
-    OrderStatus(Integer code, String desc) {
-        this.code = code;
-        this.desc = desc;
-    }
-
-    public Integer getCode() {
-        return code;
-    }
-
-    public String getDesc() {
-        return desc;
-    }
-}
-

+ 0 - 164
alien-store/src/main/java/shop/alien/store/dining/feign/AlienStoreFeign.java

@@ -1,164 +0,0 @@
-package shop.alien.store.dining.feign;
-
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RequestPart;
-import org.springframework.web.multipart.MultipartFile;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeCollect;
-import shop.alien.entity.store.vo.LifeDiscountCouponVo;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 点餐模块调用 alien-store(发码、校验、优惠券等)
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@FeignClient(contextId = "embeddedDiningAlienStoreFeign", name = "alienStoreFeign", url = "${feign.alienStore.url:}")
-public interface AlienStoreFeign {
-
-    /**
-     * 校验短信验证码(复用 store 阿里云短信)
-     *
-     * @param phone        手机号
-     * @param appType      0:用户 1:商家 2:商家web
-     * @param businessType 3:修改手机号
-     * @param code         验证码
-     */
-    @GetMapping("ali/checkSmsCode")
-    R<?> checkSmsCode(
-            @RequestParam("phone") String phone,
-            @RequestParam("appType") Integer appType,
-            @RequestParam("businessType") Integer businessType,
-            @RequestParam("code") Integer code);
-
-    // ==================== 优惠券接口(Feign 调 store life-discount-coupon) ====================
-
-    /**
-     * 获取用户优惠券列表(分 tab:全部/即将过期/已使用/已过期)
-     *
-     * @param authorization 请求头 Authorization,供 store 解析当前用户
-     * @param tabType       0:全部(未使用),1:即将过期,2:已使用,3:已过期
-     * @param page          页码(默认1)
-     * @param size          每页条数(默认10)
-     * @param type          券类型(不传:优惠券+代金券都返回,1:仅优惠券查 life_discount_coupon,4:仅代金券查 life_coupon)(可选)
-     * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选,仅当type不为4时有效)
-     * @param storeId       商铺ID,可为空,传则仅返回该商铺的优惠券
-     * @param storeName     商铺名称模糊查询,可为空
-     * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
-     */
-    @GetMapping("life-discount-coupon/getUserCouponList")
-    R<List<LifeDiscountCouponVo>> getUserCouponList(
-            @RequestHeader(value = "Authorization", required = false) String authorization,
-            @RequestParam("tabType") String tabType,
-            @RequestParam(value = "page", defaultValue = "1") int page,
-            @RequestParam(value = "size", defaultValue = "10") int size,
-            @RequestParam(value = "type", required = false) Integer type,
-            @RequestParam(value = "couponType", required = false) Integer couponType,
-            @RequestParam(value = "storeId", required = false) String storeId,
-            @RequestParam(value = "storeName", required = false) String storeName);
-
-    /**
-     * 根据优惠券 ID 获取优惠券详情(含规则、门槛等)
-     *
-     * @param authorization 请求头 Authorization
-     * @param counponId      优惠券 id(接口拼写为 counponId)
-     * @return R.data 为 LifeDiscountCouponVo
-     */
-    @GetMapping("life-discount-coupon/getCounponDetailById")
-    R<LifeDiscountCouponVo> getCounponDetailById(
-            @RequestHeader(value = "Authorization", required = false) String authorization,
-            @RequestParam("counponId") String counponId);
-
-    /**
-     * 获取该门店下用户可用/不可用优惠券列表(按消费金额区分)
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization 请求头 Authorization
-     * @param storeId        门店 id
-     * @param amount         当前消费金额(用于满减门槛判断)
-     * @param couponType     优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 Map:canUseLifeDiscountCouponVos、forbidUseLifeDiscountCouponVos
-     */
-    @GetMapping("life-discount-coupon/getStoreUserUsableCouponList")
-    R<Map<String, Object>> getStoreUserUsableCouponList(
-            @RequestHeader(value = "Authorization", required = false) String authorization,
-            @RequestParam("storeId") String storeId,
-            @RequestParam("amount") BigDecimal amount,
-            @RequestParam(value = "couponType", required = false) Integer couponType);
-
-    /**
-     * 获取该用户该店铺优惠券列表
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization 请求头 Authorization,供 store 解析当前用户
-     * @param storeId       商户id
-     * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
-     */
-    @GetMapping("life-discount-coupon/getStoreUserCouponList")
-    R<List<LifeDiscountCouponVo>> getStoreUserCouponList(
-            @RequestHeader(value = "Authorization", required = false) String authorization,
-            @RequestParam("storeId") String storeId,
-            @RequestParam(value = "couponType", required = false) Integer couponType);
-
-    /**
-     * 获取该店铺所有优惠券(分页), 好友优惠券
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization   请求头 Authorization,供 store 解析当前用户
-     * @param page            页码(默认1)
-     * @param size            每页条数(默认10)
-     * @param storeId         商户id
-     * @param couponName      优惠券名称(可选)
-     * @param tab             分页类型(0:全部,1:进行中,2:已结束,3:草稿,4:未开始,5:已下架,6:已清库)
-     * @param couponsFromType 查询类型(1:我的优惠券,2:好友的优惠券)(默认1)
-     * @param couponStatus    优惠券状态(0:草稿,1:正式)(默认1)
-     * @param couponType      优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 Page&lt;LifeDiscountCouponVo&gt;(使用 Page 而不是 IPage,因为 Feign 需要具体类型进行反序列化)
-     */
-    @GetMapping("life-discount-coupon/getStoreAllCouponList")
-    R<Page<LifeDiscountCouponVo>> getStoreAllCouponList(
-            @RequestHeader(value = "Authorization", required = false) String authorization,
-            @RequestParam(value = "page", defaultValue = "1") int page,
-            @RequestParam(value = "size", defaultValue = "10") int size,
-            @RequestParam("storeId") String storeId,
-            @RequestParam(value = "couponName", required = false) String couponName,
-            @RequestParam("tab") String tab,
-            @RequestParam(value = "couponsFromType", defaultValue = "1") int couponsFromType,
-            @RequestParam(value = "couponStatus", defaultValue = "1", required = false) int couponStatus,
-            @RequestParam(value = "couponType", required = false) Integer couponType);
-
-    // ==================== 收藏接口 ====================
-
-    /**
-     * 添加收藏
-     *
-     * @param lifeCollect 收藏对象
-     * @return R.data 为 Boolean(是否成功)
-     */
-    @PostMapping("/collect/addCollect")
-    R<Boolean> addCollect(@RequestBody LifeCollect lifeCollect);
-
-    // ==================== 文件上传接口 ====================
-
-    /**
-     * 上传图片到OSS(单个文件上传,支持图片、视频或PDF)
-     *
-     * @param file 文件对象
-     * @return R.data 为文件路径(String)
-     */
-    @PostMapping(value = "/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
-    R<String> uploadFile(@RequestPart("file") MultipartFile file);
-}

+ 0 - 26
alien-store/src/main/java/shop/alien/store/dining/listener/RedisKeyExpirationListener.java

@@ -1,26 +0,0 @@
-package shop.alien.store.dining.listener;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.redis.connection.Message;
-import org.springframework.data.redis.connection.MessageListener;
-import org.springframework.stereotype.Component;
-
-/**
- * Redis键过期监听器
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Slf4j
-@Component("diningRedisKeyExpirationListener")
-public class RedisKeyExpirationListener implements MessageListener {
-
-    @Override
-    public void onMessage(Message message, byte[] pattern) {
-        String expiredKey = message.toString();
-        log.info("Redis键过期: {}", expiredKey);
-        // TODO: 实现键过期后的业务逻辑
-    }
-}
-

+ 0 - 121
alien-store/src/main/java/shop/alien/store/dining/service/CartService.java

@@ -1,121 +0,0 @@
-package shop.alien.store.dining.service;
-
-import shop.alien.entity.store.dto.AddCartItemDTO;
-import shop.alien.entity.store.dto.CartDTO;
-
-/**
- * 购物车服务接口
- *
- * @author system
- * @since 2025-01-XX
- */
-public interface CartService {
-
-    /**
-     * 获取购物车
-     *
-     * @param tableId 桌号ID
-     * @return 购物车信息
-     */
-    CartDTO getCart(Integer tableId);
-
-    /**
-     * 添加商品到购物车
-     *
-     * @param dto 添加购物车商品DTO
-     * @return 购物车信息
-     */
-    CartDTO addItem(AddCartItemDTO dto);
-
-    /**
-     * 更新购物车商品数量
-     *
-     * @param tableId   桌号ID
-     * @param cuisineId 菜品ID
-     * @param quantity  数量
-     * @return 购物车信息
-     */
-    CartDTO updateItemQuantity(Integer tableId, Integer cuisineId, Integer quantity);
-
-    /**
-     * 删除购物车商品
-     *
-     * @param tableId   桌号ID
-     * @param cuisineId 菜品ID
-     * @return 购物车信息
-     */
-    CartDTO removeItem(Integer tableId, Integer cuisineId);
-
-    /**
-     * 清空购物车
-     *
-     * @param tableId 桌号ID
-     */
-    void clearCart(Integer tableId);
-
-    /**
-     * 换桌时迁移购物车
-     *
-     * @param fromTableId 原桌号ID
-     * @param toTableId   目标桌号ID
-     * @return 迁移后的购物车信息
-     */
-    CartDTO migrateCart(Integer fromTableId, Integer toTableId);
-
-    /**
-     * 检查桌号是否已使用优惠券
-     *
-     * @param tableId 桌号ID
-     * @return true-已使用, false-未使用
-     */
-    boolean hasUsedCoupon(Integer tableId);
-
-    /**
-     * 标记桌号已使用优惠券
-     *
-     * @param tableId  桌号ID
-     * @param couponId 优惠券ID
-     */
-    void markCouponUsed(Integer tableId, Integer couponId);
-
-    /**
-     * 清除桌号优惠券使用标记(换桌时使用)
-     *
-     * @param tableId 桌号ID
-     */
-    void clearCouponUsed(Integer tableId);
-
-    /**
-     * 设置用餐人数(自动添加或更新餐具)
-     *
-     * @param tableId   桌号ID
-     * @param dinerCount 用餐人数
-     * @return 购物车信息
-     */
-    CartDTO setDinerCount(Integer tableId, Integer dinerCount);
-
-    /**
-     * 更新餐具数量
-     *
-     * @param tableId 桌号ID
-     * @param quantity 餐具数量
-     * @return 购物车信息
-     */
-    CartDTO updateTablewareQuantity(Integer tableId, Integer quantity);
-
-    /**
-     * 锁定购物车商品数量(下单时调用,将当前数量锁定,不允许减少或删除)
-     *
-     * @param tableId 桌号ID
-     * @return 购物车信息
-     */
-    CartDTO lockCartItems(Integer tableId);
-
-    /**
-     * 解锁购物车商品数量(取消订单时调用,清除已下单数量,允许重新下单)
-     *
-     * @param tableId 桌号ID
-     * @return 购物车信息
-     */
-    CartDTO unlockCartItems(Integer tableId);
-}

+ 0 - 22
alien-store/src/main/java/shop/alien/store/dining/service/DiningCollectService.java

@@ -1,22 +0,0 @@
-package shop.alien.store.dining.service;
-
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeCollect;
-
-/**
- * 点餐模块-收藏服务(Feign 调 store 收藏接口)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/01/XX
- */
-public interface DiningCollectService {
-
-    /**
-     * 添加收藏
-     *
-     * @param lifeCollect 收藏对象
-     * @return R.data 为 Boolean(是否成功)
-     */
-    R<Boolean> addCollect(LifeCollect lifeCollect);
-}

+ 0 - 101
alien-store/src/main/java/shop/alien/store/dining/service/DiningCouponService.java

@@ -1,101 +0,0 @@
-package shop.alien.store.dining.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.vo.LifeDiscountCouponVo;
-
-import java.math.BigDecimal;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 点餐模块-优惠券服务(Feign 调 store 优惠券接口,供小程序使用)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/1/29
- */
-public interface DiningCouponService {
-
-    /**
-     * 获取当前用户优惠券列表(分 tab)
-     *
-     * @param authorization 请求头 Authorization,透传至 store 解析用户
-     * @param page          页码
-     * @param size          每页条数
-     * @param tabType       0:全部(未使用),1:即将过期,2:已使用,3:已过期
-     * @param type          券类型(不传:优惠券+代金券都返回,1:仅优惠券查 life_discount_coupon,4:仅代金券查 life_coupon)(可选)
-     * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选,仅当type不为4时有效)
-     * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
-     */
-    R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeName);
-
-    /**
-     * 根据优惠券 id 获取优惠券详情
-     *
-     * @param authorization 请求头 Authorization
-     * @param counponId     优惠券 id(与 store 接口拼写一致)
-     * @return R.data 为 LifeDiscountCouponVo
-     */
-    R<LifeDiscountCouponVo> getCounponDetailById(String authorization, String counponId);
-
-    /**
-     * 获取该门店下用户可用/不可用优惠券列表(按消费金额区分,用于选券)
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization 请求头 Authorization
-     * @param storeId        门店 id
-     * @param amount         当前消费金额(满减门槛)
-     * @param couponType     优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 Map:canUseLifeDiscountCouponVos、forbidUseLifeDiscountCouponVos
-     */
-    R<Map<String, Object>> getStoreUserUsableCouponList(String authorization, String storeId, BigDecimal amount, Integer couponType);
-
-    /**
-     * 查询用户拥有的优惠券(按符合支付条件优先,其次优惠力度大的优先)
-     *
-     * @param storeId 门店ID(可选,如果提供则只查询该门店的优惠券)
-     * @param amount  当前消费金额(用于判断是否符合支付条件)
-     * @return 优惠券列表
-     */
-    R<List<LifeDiscountCouponVo>> getUserOwnedCoupons(String storeId, BigDecimal amount);
-
-    /**
-     * 获取该用户该店铺优惠券列表
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization 请求头 Authorization,透传至 store 解析用户
-     * @param storeId       商户id
-     * @param couponType    优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 List&lt;LifeDiscountCouponVo&gt;
-     */
-    R<List<LifeDiscountCouponVo>> getStoreUserCouponList(String authorization, String storeId, Integer couponType);
-
-    /**
-     * 获取该店铺所有优惠券(分页), 好友优惠券
-     * couponType=1仅满减券,couponType=2仅折扣券,不传返回全部优惠券
-     *
-     * @param authorization   请求头 Authorization,透传至 store 解析用户
-     * @param page            页码(默认1)
-     * @param size            每页条数(默认10)
-     * @param storeId         商户id
-     * @param couponName      优惠券名称(可选)
-     * @param tab             分页类型(0:全部,1:进行中,2:已结束,3:草稿,4:未开始,5:已下架,6:已清库)
-     * @param couponsFromType 查询类型(1:我的优惠券,2:好友的优惠券)(默认1)
-     * @param couponStatus    优惠券状态(0:草稿,1:正式)(默认1)
-     * @param couponType      优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return R.data 为 IPage&lt;LifeDiscountCouponVo&gt;
-     */
-    R<IPage<LifeDiscountCouponVo>> getStoreAllCouponList(String authorization, int page, int size, String storeId,
-                                                          String couponName, String tab, int couponsFromType,
-                                                          int couponStatus, Integer couponType);
-
-    /**
-     * 查询用户目前所拥有的优惠券(可通过商铺ID进行查询)
-     *
-     * @param storeId     商铺ID(可选,如果提供则只查询该商铺的优惠券)
-     * @param couponType  优惠券类型:1=仅满减券,2=仅折扣券,不传=全部优惠券(可选)
-     * @return 优惠券列表
-     */
-    R<List<LifeDiscountCouponVo>> getUserOwnedCouponsByStore(String storeId, Integer couponType);
-}

+ 0 - 150
alien-store/src/main/java/shop/alien/store/dining/service/DiningService.java

@@ -1,150 +0,0 @@
-package shop.alien.store.dining.service;
-
-import shop.alien.entity.store.vo.TableDiningStatusVO;
-import shop.alien.entity.store.vo.*;
-
-import java.util.List;
-
-/**
- * 点餐服务接口
- *
- * @author system
- * @since 2025-01-XX
- */
-public interface DiningService {
-
-    /**
-     * 查询餐桌是否处于就餐中(就餐人数是否有数据),免登录可调用
-     *
-     * @param tableId 桌号ID
-     * @return 就餐状态(inDining、dinerCount)
-     */
-    TableDiningStatusVO getTableDiningStatus(Integer tableId);
-
-    /**
-     * 获取点餐页面信息
-     *
-     * @param tableId 桌号ID
-     * @param dinerCount 就餐人数
-     * @return 点餐页面信息
-     */
-    DiningPageInfoVO getDiningPageInfo(Integer tableId, Integer dinerCount);
-
-    /**
-     * 搜索菜品(模糊搜索,限10字)
-     *
-     * @param storeId 门店ID
-     * @param keyword 搜索关键词
-     * @param tableId 桌号ID(用于获取购物车数量)
-     * @return 菜品列表
-     */
-    List<CuisineListVO> searchCuisines(Integer storeId, String keyword, Integer tableId);
-
-    /**
-     * 根据分类获取菜品列表
-     *
-     * @param storeId 门店ID
-     * @param categoryId 分类ID(可为空,查询所有)
-     * @param tableId 桌号ID(用于获取购物车数量)
-     * @param page 页码(默认1)
-     * @param size 每页数量(默认12)
-     * @return 菜品列表
-     */
-    List<CuisineListVO> getCuisinesByCategory(Integer storeId, Integer categoryId, Integer tableId, Integer page, Integer size);
-
-    /**
-     * 获取菜品详情
-     *
-     * @param cuisineId 菜品ID
-     * @param tableId 桌号ID(用于获取购物车数量)
-     * @return 菜品详情
-     */
-    CuisineDetailVO getCuisineDetail(Integer cuisineId, Integer tableId);
-
-    /**
-     * 获取可领取的优惠券列表
-     *
-     * @param storeId 门店ID
-     * @param userId 用户ID
-     * @return 可领取优惠券列表
-     */
-    List<AvailableCouponVO> getAvailableCoupons(Integer storeId, Integer userId);
-
-    /**
-     * 领取优惠券
-     *
-     * @param couponId 优惠券ID
-     * @param userId 用户ID
-     * @return 是否成功
-     */
-    boolean receiveCoupon(Integer couponId, Integer userId);
-
-    /**
-     * 获取订单确认页面信息
-     *
-     * @param tableId 桌号ID
-     * @param dinerCount 就餐人数
-     * @param userId 用户ID
-     * @return 订单确认页面信息
-     */
-    OrderConfirmVO getOrderConfirmInfo(Integer tableId, Integer dinerCount, Integer userId);
-
-    /**
-     * 锁定订单(防止多人同时下单)
-     *
-     * @param tableId 桌号ID
-     * @param userId 用户ID
-     * @return 是否锁定成功
-     */
-    boolean lockOrder(Integer tableId, Integer userId);
-
-    /**
-     * 解锁订单
-     *
-     * @param tableId 桌号ID
-     * @param userId 用户ID
-     */
-    void unlockOrder(Integer tableId, Integer userId);
-
-    /**
-     * 检查订单是否被锁定
-     *
-     * @param tableId 桌号ID
-     * @return 锁定用户ID,如果未锁定返回null
-     */
-    Integer checkOrderLock(Integer tableId);
-
-    /**
-     * 获取订单结算确认页面信息
-     *
-     * @param orderId 订单ID
-     * @param userId 用户ID
-     * @return 订单结算确认页面信息
-     */
-    shop.alien.entity.store.vo.OrderSettlementVO getOrderSettlementInfo(Integer orderId, Integer userId);
-
-    /**
-     * 锁定订单结算(防止多人同时结算)
-     *
-     * @param orderId 订单ID
-     * @param userId 用户ID
-     * @return 是否锁定成功
-     */
-    boolean lockSettlement(Integer orderId, Integer userId);
-
-    /**
-     * 解锁订单结算
-     *
-     * @param orderId 订单ID
-     * @param userId 用户ID
-     */
-    void unlockSettlement(Integer orderId, Integer userId);
-
-    /**
-     * 检查订单结算是否被锁定
-     *
-     * @param orderId 订单ID
-     * @return 锁定用户ID,如果未锁定返回null
-     */
-    Integer checkSettlementLock(Integer orderId);
-}

+ 0 - 48
alien-store/src/main/java/shop/alien/store/dining/service/DiningUserService.java

@@ -1,48 +0,0 @@
-package shop.alien.store.dining.service;
-
-import shop.alien.store.dining.dto.ChangePhoneDto;
-import shop.alien.store.dining.dto.UserProfileUpdateDto;
-import shop.alien.store.dining.vo.DiningUserVo;
-import shop.alien.store.dining.vo.TokenVerifyVo;
-
-/**
- * 点餐用户服务接口(与 APP 共用 JWT 登录,不提供小程序 code 登录)
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-public interface DiningUserService {
-
-    /**
-     * 更新用户个人信息
-     *
-     * @param dto 用户信息更新DTO
-     * @return 更新后的用户信息
-     */
-    DiningUserVo updateProfile(UserProfileUpdateDto dto);
-
-    /**
-     * 获取用户信息
-     *
-     * @param userId 用户ID
-     * @return 用户信息
-     */
-    DiningUserVo getUserInfo(Long userId);
-
-    /**
-     * 更换手机号:Feign 调 store 校验验证码后更新 user_phone
-     *
-     * @param dto 更换手机号请求
-     * @return 更新后的用户信息,失败返回 null
-     */
-    DiningUserVo changePhone(ChangePhoneDto dto);
-
-    /**
-     * 校验 Token 是否有效
-     *
-     * @param token Token字符串
-     * @return Token校验结果,包含用户信息和验证状态
-     */
-    TokenVerifyVo verifyToken(String token);
-}

+ 0 - 61
alien-store/src/main/java/shop/alien/store/dining/service/OrderLockService.java

@@ -1,61 +0,0 @@
-package shop.alien.store.dining.service;
-
-/**
- * 订单锁定服务接口
- * 用于管理订单和结算的锁定状态,防止并发操作
- *
- * @author system
- * @since 2025-01-XX
- */
-public interface OrderLockService {
-
-    /**
-     * 锁定订单(防止多人同时下单)
-     *
-     * @param tableId 桌号ID
-     * @param userId 用户ID
-     * @return 是否锁定成功
-     */
-    boolean lockOrder(Integer tableId, Integer userId);
-
-    /**
-     * 解锁订单
-     *
-     * @param tableId 桌号ID
-     * @param userId 用户ID
-     */
-    void unlockOrder(Integer tableId, Integer userId);
-
-    /**
-     * 检查订单是否被锁定
-     *
-     * @param tableId 桌号ID
-     * @return 锁定用户ID,如果未锁定返回null
-     */
-    Integer checkOrderLock(Integer tableId);
-
-    /**
-     * 锁定订单结算(防止多人同时结算)
-     *
-     * @param orderId 订单ID
-     * @param userId 用户ID
-     * @return 是否锁定成功
-     */
-    boolean lockSettlement(Integer orderId, Integer userId);
-
-    /**
-     * 解锁订单结算
-     *
-     * @param orderId 订单ID
-     * @param userId 用户ID
-     */
-    void unlockSettlement(Integer orderId, Integer userId);
-
-    /**
-     * 检查订单结算是否被锁定
-     *
-     * @param orderId 订单ID
-     * @return 锁定用户ID,如果未锁定返回null
-     */
-    Integer checkSettlementLock(Integer orderId);
-}

+ 0 - 35
alien-store/src/main/java/shop/alien/store/dining/service/SseService.java

@@ -1,35 +0,0 @@
-package shop.alien.store.dining.service;
-
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-
-/**
- * SSE推送服务接口
- *
- * @author system
- * @since 2025-01-XX
- */
-public interface SseService {
-
-    /**
-     * 创建SSE连接
-     *
-     * @param tableId 桌号ID
-     * @return SSE连接对象
-     */
-    SseEmitter createConnection(Integer tableId);
-
-    /**
-     * 推送购物车更新消息
-     *
-     * @param tableId 桌号ID
-     * @param message 消息内容
-     */
-    void pushCartUpdate(Integer tableId, Object message);
-
-    /**
-     * 关闭SSE连接
-     *
-     * @param tableId 桌号ID
-     */
-    void closeConnection(Integer tableId);
-}

+ 0 - 67
alien-store/src/main/java/shop/alien/store/dining/service/StoreInfoService.java

@@ -1,67 +0,0 @@
-package shop.alien.store.dining.service;
-
-import shop.alien.entity.store.StoreCuisine;
-import shop.alien.entity.store.StoreCuisineCategory;
-import shop.alien.entity.store.StoreTable;
-import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
-import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
-
-import java.util.List;
-
-/**
- * 门店信息查询服务接口
- *
- * @author system
- * @since 2025-02-02
- */
-public interface StoreInfoService {
-
-    /**
-     * 根据门店ID查询桌号列表
-     *
-     * @param storeId 门店ID
-     * @return 桌号列表
-     */
-    List<StoreTable> getTablesByStoreId(Integer storeId);
-
-    /**
-     * 根据门店ID查询菜品种类列表
-     *
-     * @param storeId 门店ID
-     * @return 菜品种类列表
-     */
-    List<StoreCuisineCategory> getCategoriesByStoreId(Integer storeId);
-
-    /**
-     * 根据菜品种类ID查询菜品信息列表
-     *
-     * @param categoryId 菜品种类ID
-     * @return 菜品信息列表
-     */
-    List<StoreCuisine> getCuisinesByCategoryId(Integer categoryId);
-
-    /**
-     * 根据门店ID查询菜品种类及每个分类下的菜品列表(一次返回种类+菜品)
-     *
-     * @param storeId 门店ID
-     * @param keyword 菜品名称模糊查询关键词(可选,为空则不按名称筛选)
-     * @return 菜品种类及下属菜品列表
-     */
-    List<CategoryWithCuisinesVO> getCategoriesWithCuisinesByStoreId(Integer storeId, String keyword);
-
-    /**
-     * 删除菜品种类:仅逻辑删除分类并解除菜品与该分类的绑定关系,价目表(菜品)本身不改动
-     *
-     * @param categoryId 菜品种类ID
-     * @return 是否成功
-     */
-    boolean deleteCategory(Integer categoryId);
-
-    /**
-     * 根据商铺ID查询店铺信息和首页展示美食价目表信息
-     *
-     * @param storeId 商铺ID
-     * @return 店铺信息和首页展示美食价目表信息
-     */
-    StoreInfoWithHomepageCuisinesDTO getStoreInfoWithHomepageCuisines(Integer storeId);
-}

+ 0 - 189
alien-store/src/main/java/shop/alien/store/dining/service/StoreOrderService.java

@@ -1,189 +0,0 @@
-package shop.alien.store.dining.service;
-
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.IService;
-import shop.alien.entity.store.StoreOrder;
-import shop.alien.entity.store.dto.CreateOrderDTO;
-import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
-import shop.alien.entity.store.vo.OrderInfoVO;
-import shop.alien.entity.store.vo.StoreOrderPageVO;
-
-import java.util.List;
-
-/**
- * 订单服务接口
- *
- * @author system
- * @since 2025-01-XX
- */
-public interface StoreOrderService extends IService<StoreOrder> {
-
-    /**
-     * 创建订单
-     *
-     * @param dto 创建订单DTO
-     * @return 订单信息
-     */
-    StoreOrder createOrder(CreateOrderDTO dto);
-
-    /**
-     * 支付订单
-     *
-     * @param orderId 订单ID
-     * @param payType 支付方式
-     * @return 订单信息
-     */
-    StoreOrder payOrder(Integer orderId, Integer payType);
-
-    /**
-     * 取消订单
-     *
-     * @param orderId 订单ID
-     * @return 是否成功
-     */
-    boolean cancelOrder(Integer orderId);
-
-    /**
-     * 根据订单号查询订单
-     *
-     * @param orderNo 订单号
-     * @return 订单信息
-     */
-    StoreOrder getOrderByOrderNo(String orderNo);
-
-    /**
-     * 根据ID查询订单
-     *
-     * @param orderId 订单ID
-     * @return 订单信息
-     */
-    StoreOrder getOrderById(Integer orderId);
-
-    /**
-     * 分页查询订单列表
-     *
-     * @param page     分页参数
-     * @param storeId  门店ID
-     * @param tableId  桌号ID
-     * @param orderStatus 订单状态
-     * @param keyword  搜索关键词(订单编号或菜品名称,限15字)
-     * @return 订单分页列表
-     */
-    IPage<StoreOrder> getOrderPage(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
-
-    /**
-     * 分页查询订单列表(包含菜品信息)
-     *
-     * @param page     分页参数
-     * @param storeId  门店ID
-     * @param tableId  桌号ID
-     * @param orderStatus 订单状态
-     * @param keyword  搜索关键词(订单编号或菜品名称,限15字)
-     * @return 订单分页列表(包含菜品信息)
-     */
-    IPage<StoreOrderPageVO> getOrderPageWithCuisines(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword);
-
-    /**
-     * 完成订单(支付完成后调用)
-     *
-     * @param orderId 订单ID
-     * @return 是否成功
-     */
-    boolean completeOrder(Integer orderId);
-
-    /**
-     * 商家手动完成订单(不校验支付状态)
-     *
-     * @param orderId 订单ID
-     * @return 是否成功
-     */
-    boolean completeOrderByMerchant(Integer orderId);
-
-    /**
-     * 更新订单优惠券
-     *
-     * @param orderId 订单ID
-     * @param couponId 优惠券ID(可为空,表示不使用优惠券)
-     * @return 订单信息
-     */
-    StoreOrder updateOrderCoupon(Integer orderId, Integer couponId);
-
-    /**
-     * 管理员重置餐桌(删除购物车数据、未支付/已取消的订单数据,并重置餐桌表)
-     * 注意:已支付/已完成的订单会被保留,避免数据丢失
-     *
-     * @param tableId 餐桌ID
-     * @return 是否成功
-     */
-    boolean resetTable(Integer tableId);
-
-    /**
-     * 查询订单信息(包含订单基本信息、菜品清单、价格明细)
-     *
-     * @param orderId 订单ID
-     * @return 订单信息
-     */
-    OrderInfoVO getOrderInfo(Integer orderId);
-
-    /**
-     * 查询订单的所有变更记录(按批次分组)
-     *
-     * @param orderId 订单ID
-     * @return 变更记录批次列表
-     */
-    List<OrderChangeLogBatchVO> getOrderChangeLogs(Integer orderId);
-
-    /**
-     * 查询订单详情(包含订单基本信息和按批次分组的变更记录)
-     *
-     * @param orderId 订单ID
-     * @return 订单详情(包含变更记录)
-     */
-    shop.alien.entity.store.vo.OrderDetailWithChangeLogVO getOrderDetailWithChangeLog(Integer orderId);
-
-    /**
-     * 支付完成后重置餐桌(保留订单数据,只重置餐桌绑定关系)
-     *
-     * @param tableId 餐桌ID
-     */
-    void resetTableAfterPayment(Integer tableId);
-
-    /**
-     * 查询我的订单(通过标识查询未支付订单或历史订单)
-     *
-     * @param page 分页参数
-     * @param type 订单类型(0或"unpaid":未支付订单, 1或"history":历史订单)
-     * @return 订单分页列表
-     */
-    IPage<StoreOrder> getMyOrders(Page<StoreOrder> page, String type);
-
-    /**
-     * 查询我的订单(包含菜品信息)
-     *
-     * @param page 分页参数
-     * @param type 订单类型(0或"unpaid":未支付订单, 1或"history":历史订单)
-     * @return 订单分页列表(包含菜品信息)
-     */
-    IPage<StoreOrderPageVO> getMyOrdersWithCuisines(Page<StoreOrder> page, String type);
-
-    /**
-     * 换桌时迁移所有关联数据(订单、订单变更记录、优惠券使用记录等)
-     *
-     * @param fromTableId 原桌号ID
-     * @param toTableId   目标桌号ID
-     * @param userId      操作用户ID
-     */
-    void migrateTableData(Integer fromTableId, Integer toTableId, Integer userId);
-
-    /**
-     * 换桌(包含所有业务逻辑:迁移购物车、订单、优惠券等,记录日志,推送消息)
-     *
-     * @param fromTableId  原桌号ID
-     * @param toTableId    目标桌号ID
-     * @param changeReason 换桌原因
-     * @param userId       操作用户ID
-     * @return 迁移后的购物车信息
-     */
-    shop.alien.entity.store.dto.CartDTO changeTable(Integer fromTableId, Integer toTableId, String changeReason, Integer userId);
-}

+ 0 - 1072
alien-store/src/main/java/shop/alien/store/dining/service/impl/CartServiceImpl.java

@@ -1,1072 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.dining.service.CartService;
-import shop.alien.entity.store.StoreCart;
-import shop.alien.entity.store.StoreCouponUsage;
-import shop.alien.entity.store.StoreCuisine;
-import shop.alien.entity.store.StoreInfo;
-import shop.alien.entity.store.StoreTable;
-import shop.alien.entity.store.dto.AddCartItemDTO;
-import shop.alien.entity.store.dto.CartDTO;
-import shop.alien.entity.store.dto.CartItemDTO;
-import shop.alien.mapper.StoreCartMapper;
-import shop.alien.mapper.StoreCouponUsageMapper;
-import shop.alien.mapper.StoreCuisineMapper;
-import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.StoreTableMapper;
-import shop.alien.store.dining.util.TokenUtil;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.stream.Collectors;
-
-/**
- * 购物车服务实现类
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class CartServiceImpl implements CartService {
-
-    private static final String CART_KEY_PREFIX = "cart:table:";
-    private static final String COUPON_USED_KEY_PREFIX = "coupon:used:table:";
-    private static final int CART_EXPIRE_SECONDS = 24 * 60 * 60; // 24小时过期
-
-    // 异步写入数据库的线程池(专门用于购物车数据库写入)
-    private static final ExecutorService CART_DB_WRITE_EXECUTOR = Executors.newFixedThreadPool(5, r -> {
-        Thread t = new Thread(r, "cart-db-write-" + System.currentTimeMillis());
-        t.setDaemon(true);
-        return t;
-    });
-
-    private final BaseRedisService baseRedisService;
-    private final StoreTableMapper storeTableMapper;
-    private final StoreCuisineMapper storeCuisineMapper;
-    private final StoreCartMapper storeCartMapper;
-    private final StoreCouponUsageMapper storeCouponUsageMapper;
-    private final StoreInfoMapper storeInfoMapper;
-
-    @Override
-    public CartDTO getCart(Integer tableId) {
-        log.info("获取购物车, tableId={}", tableId);
-        String cartKey = CART_KEY_PREFIX + tableId;
-        String cartJson = baseRedisService.getString(cartKey);
-
-        CartDTO cart = new CartDTO();
-        cart.setTableId(tableId);
-
-        // 查询桌号信息
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            cart.setTableNumber(table.getTableNumber());
-            cart.setStoreId(table.getStoreId());
-        }
-
-        if (StringUtils.hasText(cartJson)) {
-            try {
-                JSONObject cartObj = JSON.parseObject(cartJson);
-                List<CartItemDTO> items = cartObj.getList("items", CartItemDTO.class);
-                if (items != null) {
-                    cart.setItems(items);
-                    // 计算总金额和总数量
-                    BigDecimal totalAmount = items.stream()
-                            .map(CartItemDTO::getSubtotalAmount)
-                            .reduce(BigDecimal.ZERO, BigDecimal::add);
-                    Integer totalQuantity = items.stream()
-                            .mapToInt(CartItemDTO::getQuantity)
-                            .sum();
-                    cart.setTotalAmount(totalAmount);
-                    cart.setTotalQuantity(totalQuantity);
-                } else {
-                    cart.setItems(new ArrayList<>());
-                    cart.setTotalAmount(BigDecimal.ZERO);
-                    cart.setTotalQuantity(0);
-                }
-            } catch (Exception e) {
-                log.error("解析购物车数据失败: {}", e.getMessage(), e);
-                cart.setItems(new ArrayList<>());
-                cart.setTotalAmount(BigDecimal.ZERO);
-                cart.setTotalQuantity(0);
-            }
-        } else {
-            // Redis中没有,尝试从数据库加载
-            cart = loadCartFromDatabase(tableId);
-        }
-
-        return cart;
-    }
-
-    /**
-     * 从数据库加载购物车
-     */
-    private CartDTO loadCartFromDatabase(Integer tableId) {
-        log.info("从数据库加载购物车, tableId={}", tableId);
-        CartDTO cart = new CartDTO();
-        cart.setTableId(tableId);
-        cart.setItems(new ArrayList<>());
-        cart.setTotalAmount(BigDecimal.ZERO);
-        cart.setTotalQuantity(0);
-
-        // 查询桌号信息
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            cart.setTableNumber(table.getTableNumber());
-            cart.setStoreId(table.getStoreId());
-        }
-
-        // 从数据库查询购物车数据
-        LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCart::getTableId, tableId);
-        wrapper.eq(StoreCart::getDeleteFlag, 0);
-        List<StoreCart> cartList = storeCartMapper.selectList(wrapper);
-
-        if (cartList != null && !cartList.isEmpty()) {
-            List<CartItemDTO> items = cartList.stream().map(cartItem -> {
-                CartItemDTO item = new CartItemDTO();
-                item.setCuisineId(cartItem.getCuisineId());
-                item.setCuisineName(cartItem.getCuisineName());
-                item.setCuisineImage(cartItem.getCuisineImage());
-                item.setUnitPrice(cartItem.getUnitPrice());
-                item.setQuantity(cartItem.getQuantity());
-                item.setLockedQuantity(cartItem.getLockedQuantity());
-                item.setSubtotalAmount(cartItem.getSubtotalAmount());
-                item.setAddUserId(cartItem.getAddUserId());
-                item.setAddUserPhone(cartItem.getAddUserPhone());
-                item.setRemark(cartItem.getRemark());
-                return item;
-            }).collect(Collectors.toList());
-
-            cart.setItems(items);
-            BigDecimal totalAmount = items.stream()
-                    .map(CartItemDTO::getSubtotalAmount)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            Integer totalQuantity = items.stream()
-                    .mapToInt(CartItemDTO::getQuantity)
-                    .sum();
-            cart.setTotalAmount(totalAmount);
-            cart.setTotalQuantity(totalQuantity);
-
-            // 同步到Redis
-            saveCartToRedis(cart);
-        }
-
-        return cart;
-    }
-
-    @Override
-    public CartDTO addItem(AddCartItemDTO dto) {
-        log.info("添加商品到购物车, dto={}", dto);
-        // 验证桌号
-        StoreTable table = storeTableMapper.selectById(dto.getTableId());
-        if (table == null) {
-            throw new RuntimeException("桌号不存在");
-        }
-
-        // 验证菜品
-        StoreCuisine cuisine = storeCuisineMapper.selectById(dto.getCuisineId());
-        if (cuisine == null) {
-            throw new RuntimeException("菜品不存在");
-        }
-        if (cuisine.getShelfStatus() != 1) {
-            throw new RuntimeException("菜品已下架");
-        }
-
-        // 获取当前用户信息
-        Integer userId = TokenUtil.getCurrentUserId();
-        String userPhone = TokenUtil.getCurrentUserPhone();
-
-        // 获取购物车
-        CartDTO cart = getCart(dto.getTableId());
-
-        // 查找是否已存在该商品
-        List<CartItemDTO> items = cart.getItems();
-        CartItemDTO existingItem = items.stream()
-                .filter(item -> item.getCuisineId().equals(dto.getCuisineId()))
-                .findFirst()
-                .orElse(null);
-
-        if (existingItem != null) {
-            // 商品已存在
-            Integer lockedQuantity = existingItem.getLockedQuantity();
-            if (lockedQuantity != null && lockedQuantity > 0) {
-                // 如果商品有已下单数量,将新数量叠加到当前数量和已下单数量上
-                Integer newQuantity = existingItem.getQuantity() + dto.getQuantity();
-                Integer newLockedQuantity = lockedQuantity + dto.getQuantity();
-                existingItem.setQuantity(newQuantity);
-                existingItem.setLockedQuantity(newLockedQuantity);
-                existingItem.setSubtotalAmount(existingItem.getUnitPrice()
-                        .multiply(BigDecimal.valueOf(newQuantity)));
-                log.info("商品已存在且有已下单数量,叠加数量, cuisineId={}, oldQuantity={}, newQuantity={}, oldOrderedQuantity={}, newOrderedQuantity={}", 
-                        dto.getCuisineId(), existingItem.getQuantity() - dto.getQuantity(), newQuantity, lockedQuantity, newLockedQuantity);
-            } else {
-                // 商品已存在但没有已下单数量,不允许重复添加
-                throw new RuntimeException("已添加过本商品");
-            }
-        } else {
-            // 添加新商品
-            CartItemDTO newItem = new CartItemDTO();
-            newItem.setCuisineId(cuisine.getId());
-            newItem.setCuisineName(cuisine.getName());
-            newItem.setCuisineType(cuisine.getCuisineType());
-            newItem.setCuisineImage(cuisine.getImages());
-            newItem.setUnitPrice(cuisine.getTotalPrice());
-            newItem.setQuantity(dto.getQuantity());
-            newItem.setSubtotalAmount(cuisine.getTotalPrice()
-                    .multiply(BigDecimal.valueOf(dto.getQuantity())));
-            newItem.setAddUserId(userId);
-            newItem.setAddUserPhone(userPhone);
-            newItem.setRemark(dto.getRemark());
-            items.add(newItem);
-        }
-
-        // 重新计算总金额和总数量
-        BigDecimal totalAmount = items.stream()
-                .map(CartItemDTO::getSubtotalAmount)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Integer totalQuantity = items.stream()
-                .mapToInt(CartItemDTO::getQuantity)
-                .sum();
-        cart.setTotalAmount(totalAmount);
-        cart.setTotalQuantity(totalQuantity);
-
-        // 保存到Redis和数据库(双写策略)
-        saveCart(cart);
-
-        return cart;
-    }
-
-    @Override
-    public CartDTO updateItemQuantity(Integer tableId, Integer cuisineId, Integer quantity) {
-        log.info("更新购物车商品数量, tableId={}, cuisineId={}, quantity={}", tableId, cuisineId, quantity);
-        
-        // 如果数量为0或小于0,删除该商品
-        if (quantity == null || quantity <= 0) {
-            log.info("商品数量为0或小于0,删除商品, tableId={}, cuisineId={}", tableId, cuisineId);
-            return removeItem(tableId, cuisineId);
-        }
-
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-        CartItemDTO item = items.stream()
-                .filter(i -> i.getCuisineId().equals(cuisineId))
-                .findFirst()
-                .orElse(null);
-
-        if (item != null) {
-            // 商品已存在,更新数量
-            // 检查已下单数量:不允许将数量减少到小于已下单数量
-            Integer lockedQuantity = item.getLockedQuantity();
-            if (lockedQuantity != null && lockedQuantity > 0) {
-                if (quantity < lockedQuantity) {
-                    throw new RuntimeException("商品数量不能少于已下单数量(" + lockedQuantity + "),该数量已下单");
-                }
-            }
-            
-            item.setQuantity(quantity);
-            item.setSubtotalAmount(item.getUnitPrice()
-                    .multiply(BigDecimal.valueOf(quantity)));
-
-            // 重新计算总金额和总数量
-            BigDecimal totalAmount = items.stream()
-                    .map(CartItemDTO::getSubtotalAmount)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            Integer totalQuantity = items.stream()
-                    .mapToInt(CartItemDTO::getQuantity)
-                    .sum();
-            cart.setTotalAmount(totalAmount);
-            cart.setTotalQuantity(totalQuantity);
-
-            saveCart(cart);
-        } else {
-            // 商品不存在,自动添加
-            log.info("商品不在购物车中,自动添加, tableId={}, cuisineId={}, quantity={}", tableId, cuisineId, quantity);
-            
-            // 验证菜品
-            StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
-            if (cuisine == null) {
-                throw new RuntimeException("菜品不存在");
-            }
-            if (cuisine.getShelfStatus() != 1) {
-                throw new RuntimeException("菜品已下架");
-            }
-
-            // 获取当前用户信息
-            Integer userId = TokenUtil.getCurrentUserId();
-            String userPhone = TokenUtil.getCurrentUserPhone();
-
-            // 创建新的购物车商品项
-            CartItemDTO newItem = new CartItemDTO();
-            newItem.setCuisineId(cuisine.getId());
-            newItem.setCuisineName(cuisine.getName());
-            newItem.setCuisineType(cuisine.getCuisineType());
-            newItem.setCuisineImage(cuisine.getImages());
-            newItem.setUnitPrice(cuisine.getTotalPrice());
-            newItem.setQuantity(quantity);
-            newItem.setSubtotalAmount(cuisine.getTotalPrice()
-                    .multiply(BigDecimal.valueOf(quantity)));
-            newItem.setAddUserId(userId);
-            newItem.setAddUserPhone(userPhone);
-            items.add(newItem);
-
-            // 重新计算总金额和总数量
-            BigDecimal totalAmount = items.stream()
-                    .map(CartItemDTO::getSubtotalAmount)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            Integer totalQuantity = items.stream()
-                    .mapToInt(CartItemDTO::getQuantity)
-                    .sum();
-            cart.setTotalAmount(totalAmount);
-            cart.setTotalQuantity(totalQuantity);
-
-            // 保存到Redis和数据库(双写策略)
-            saveCart(cart);
-            log.info("商品已自动添加到购物车, tableId={}, cuisineId={}, quantity={}", tableId, cuisineId, quantity);
-        }
-
-        return cart;
-    }
-
-    @Override
-    public CartDTO removeItem(Integer tableId, Integer cuisineId) {
-        log.info("删除购物车商品, tableId={}, cuisineId={}", tableId, cuisineId);
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-        
-        // 检查是否有已下单数量,如果有则不允许删除
-        CartItemDTO item = items.stream()
-                .filter(i -> i.getCuisineId().equals(cuisineId))
-                .findFirst()
-                .orElse(null);
-        
-        if (item != null) {
-            Integer lockedQuantity = item.getLockedQuantity();
-            if (lockedQuantity != null && lockedQuantity > 0) {
-                throw new RuntimeException("商品已下单,已下单数量为 " + lockedQuantity + ",不允许删除");
-            }
-        }
-        
-        items.removeIf(i -> i.getCuisineId().equals(cuisineId));
-
-        // 重新计算总金额和总数量
-        BigDecimal totalAmount = items.stream()
-                .map(CartItemDTO::getSubtotalAmount)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Integer totalQuantity = items.stream()
-                .mapToInt(CartItemDTO::getQuantity)
-                .sum();
-        cart.setTotalAmount(totalAmount);
-        cart.setTotalQuantity(totalQuantity);
-
-        saveCart(cart);
-        return cart;
-    }
-
-    @Override
-    public void clearCart(Integer tableId) {
-        log.info("清空购物车(保留已下单商品), tableId={}", tableId);
-        
-        // 获取购物车
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-        
-        if (items == null || items.isEmpty()) {
-            log.info("购物车为空,无需清空, tableId={}", tableId);
-            return;
-        }
-        
-        // 分离已下单的商品、未下单的商品和餐具
-        List<CartItemDTO> orderedItems = new ArrayList<>(); // 已下单的商品(保留,数量恢复为已下单数量)
-        List<Integer> orderedCuisineIds = new ArrayList<>(); // 已下单的商品ID列表
-        List<CartItemDTO> unorderedItems = new ArrayList<>(); // 未下单的商品(删除)
-        CartItemDTO tablewareItem = null; // 餐具项(始终保留)
-        boolean hasChanges = false; // 是否有变化(需要更新)
-        
-        for (CartItemDTO item : items) {
-            // 餐具始终保留,不清空
-            if (TABLEWARE_CUISINE_ID.equals(item.getCuisineId())) {
-                tablewareItem = item;
-                continue;
-            }
-            
-            Integer lockedQuantity = item.getLockedQuantity();
-            if (lockedQuantity != null && lockedQuantity > 0) {
-                // 有已下单数量,保留该商品,但将当前数量恢复为已下单数量
-                Integer currentQuantity = item.getQuantity();
-                if (currentQuantity != null && !currentQuantity.equals(lockedQuantity)) {
-                    // 当前数量不等于已下单数量,需要恢复
-                    item.setQuantity(lockedQuantity);
-                    item.setSubtotalAmount(item.getUnitPrice().multiply(BigDecimal.valueOf(lockedQuantity)));
-                    hasChanges = true;
-                    log.info("恢复已下单商品数量, cuisineId={}, oldQuantity={}, orderedQuantity={}", 
-                            item.getCuisineId(), currentQuantity, lockedQuantity);
-                }
-                orderedItems.add(item);
-                orderedCuisineIds.add(item.getCuisineId());
-            } else {
-                // 没有已下单数量,标记为删除
-                unorderedItems.add(item);
-                hasChanges = true;
-            }
-        }
-        
-        // 将餐具项添加到保留列表中,若有已下单数量则恢复为已下单数量(与菜品逻辑一致)
-        if (tablewareItem != null) {
-            Integer tablewareLocked = tablewareItem.getLockedQuantity();
-            if (tablewareLocked != null && tablewareLocked > 0) {
-                Integer currentQty = tablewareItem.getQuantity();
-                if (currentQty == null || !currentQty.equals(tablewareLocked)) {
-                    tablewareItem.setQuantity(tablewareLocked);
-                    tablewareItem.setSubtotalAmount(tablewareItem.getUnitPrice().multiply(BigDecimal.valueOf(tablewareLocked)));
-                    hasChanges = true;
-                    log.info("恢复餐具数量为已下单数量, cuisineId={}, oldQuantity={}, orderedQuantity={}",
-                            tablewareItem.getCuisineId(), currentQty, tablewareLocked);
-                }
-            }
-            orderedItems.add(tablewareItem);
-            orderedCuisineIds.add(tablewareItem.getCuisineId());
-            log.info("保留餐具项, cuisineId={}, quantity={}", tablewareItem.getCuisineId(), tablewareItem.getQuantity());
-        }
-        
-        // 如果有变化(有未下单的商品需要删除,或者已下单商品数量需要恢复),进行更新
-        if (hasChanges) {
-            // 1. 更新购物车(删除未下单商品,已下单商品数量已恢复)
-            cart.setItems(orderedItems);
-            // 重新计算总金额和总数量(只计算保留的商品,数量已恢复为已下单数量)
-            BigDecimal totalAmount = orderedItems.stream()
-                    .map(CartItemDTO::getSubtotalAmount)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            Integer totalQuantity = orderedItems.stream()
-                    .mapToInt(CartItemDTO::getQuantity)
-                    .sum();
-            cart.setTotalAmount(totalAmount);
-            cart.setTotalQuantity(totalQuantity);
-            
-            // 更新Redis(保留已下单的商品,数量已恢复)
-            if (orderedItems.isEmpty()) {
-                // 如果所有商品都未下单,清空Redis
-                String cartKey = CART_KEY_PREFIX + tableId;
-                baseRedisService.delete(cartKey);
-            } else {
-                // 保存更新后的购物车到Redis(已下单商品数量已恢复为已下单数量)
-                saveCartToRedis(cart);
-            }
-            
-            // 2. 从数据库中逻辑删除未下单的商品(排除餐具)
-            if (!unorderedItems.isEmpty()) {
-                LambdaQueryWrapper<StoreCart> wrapper = new LambdaQueryWrapper<>();
-                wrapper.eq(StoreCart::getTableId, tableId);
-                wrapper.eq(StoreCart::getDeleteFlag, 0);
-                // 排除餐具(cuisineId = -1)
-                wrapper.ne(StoreCart::getCuisineId, TABLEWARE_CUISINE_ID);
-                if (!orderedCuisineIds.isEmpty()) {
-                    // 排除已下单的商品ID(包括餐具)
-                    wrapper.notIn(StoreCart::getCuisineId, orderedCuisineIds);
-                }
-                List<StoreCart> cartListToDelete = storeCartMapper.selectList(wrapper);
-                if (cartListToDelete != null && !cartListToDelete.isEmpty()) {
-                    List<Integer> cartIds = cartListToDelete.stream()
-                            .map(StoreCart::getId)
-                            .collect(Collectors.toList());
-                    // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-                    storeCartMapper.deleteBatchIds(cartIds);
-                    log.info("删除未下单商品(已排除餐具), tableId={}, count={}", tableId, cartIds.size());
-                }
-            }
-            
-            // 3. 更新数据库中已下单商品的数量(恢复为已下单数量)
-            if (!orderedItems.isEmpty()) {
-                // 保存更新后的购物车到数据库(会更新已下单商品的数量)
-                saveCartToDatabase(cart);
-            }
-            
-            // 4. 更新桌号表的购物车统计
-            StoreTable table = storeTableMapper.selectById(tableId);
-            if (table != null) {
-                table.setCartItemCount(totalQuantity);
-                table.setCartTotalAmount(totalAmount);
-                storeTableMapper.updateById(table);
-            }
-            
-            log.info("清空购物车完成(保留已下单商品和餐具,数量恢复为已下单数量), tableId={}, 删除商品数={}, 保留商品数={}", 
-                    tableId, unorderedItems.size(), orderedItems.size());
-        } else {
-            log.info("购物车无需更新, tableId={}", tableId);
-        }
-    }
-
-    @Override
-    public CartDTO migrateCart(Integer fromTableId, Integer toTableId) {
-        log.info("迁移购物车, fromTableId={}, toTableId={}", fromTableId, toTableId);
-        // 获取原购物车
-        CartDTO fromCart = getCart(fromTableId);
-
-        // 验证目标桌号
-        StoreTable toTable = storeTableMapper.selectById(toTableId);
-        if (toTable == null) {
-            throw new RuntimeException("目标桌号不存在");
-        }
-
-        // 获取目标购物车
-        CartDTO toCart = getCart(toTableId);
-
-        // 合并购物车(如果目标桌号已有商品,则合并)
-        List<CartItemDTO> mergedItems = new ArrayList<>(toCart.getItems());
-        for (CartItemDTO fromItem : fromCart.getItems()) {
-            CartItemDTO existingItem = mergedItems.stream()
-                    .filter(item -> item.getCuisineId().equals(fromItem.getCuisineId()))
-                    .findFirst()
-                    .orElse(null);
-
-            if (existingItem != null) {
-                // 合并数量
-                int newQuantity = (existingItem.getQuantity() != null ? existingItem.getQuantity() : 0)
-                        + (fromItem.getQuantity() != null ? fromItem.getQuantity() : 0);
-                existingItem.setQuantity(newQuantity);
-                existingItem.setSubtotalAmount(existingItem.getUnitPrice()
-                        .multiply(BigDecimal.valueOf(newQuantity)));
-                // 合并已下单数量(换桌后目标桌需保留两边的已下单数量)
-                int toLocked = existingItem.getLockedQuantity() != null ? existingItem.getLockedQuantity() : 0;
-                int fromLocked = fromItem.getLockedQuantity() != null ? fromItem.getLockedQuantity() : 0;
-                existingItem.setLockedQuantity(toLocked + fromLocked > 0 ? toLocked + fromLocked : null);
-            } else {
-                mergedItems.add(fromItem);
-            }
-        }
-
-        toCart.setItems(mergedItems);
-        toCart.setTableId(toTableId);
-        toCart.setTableNumber(toTable.getTableNumber());
-        toCart.setStoreId(toTable.getStoreId());
-
-        // 重新计算总金额和总数量
-        BigDecimal totalAmount = mergedItems.stream()
-                .map(CartItemDTO::getSubtotalAmount)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Integer totalQuantity = mergedItems.stream()
-                .mapToInt(CartItemDTO::getQuantity)
-                .sum();
-        toCart.setTotalAmount(totalAmount);
-        toCart.setTotalQuantity(totalQuantity);
-
-        // 保存目标购物车
-        saveCart(toCart);
-
-        // 清空原购物车
-        clearCart(fromTableId);
-
-        // 迁移优惠券使用标记
-        if (hasUsedCoupon(fromTableId)) {
-            String couponUsedKey = COUPON_USED_KEY_PREFIX + fromTableId;
-            String couponId = baseRedisService.getString(couponUsedKey);
-            if (StringUtils.hasText(couponId)) {
-                markCouponUsed(toTableId, Integer.parseInt(couponId));
-                clearCouponUsed(fromTableId);
-            }
-        }
-
-        return toCart;
-    }
-
-    @Override
-    public boolean hasUsedCoupon(Integer tableId) {
-        // 先查Redis
-        String couponUsedKey = COUPON_USED_KEY_PREFIX + tableId;
-        String couponId = baseRedisService.getString(couponUsedKey);
-        if (StringUtils.hasText(couponId)) {
-            return true;
-        }
-
-        // Redis中没有,查数据库
-        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCouponUsage::getTableId, tableId);
-        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-        wrapper.in(StoreCouponUsage::getUsageStatus, 0, 1, 2); // 已标记使用、已下单、已支付
-        wrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-        wrapper.last("LIMIT 1");
-        StoreCouponUsage usage = storeCouponUsageMapper.selectOne(wrapper);
-        return usage != null;
-    }
-
-    @Override
-    public void markCouponUsed(Integer tableId, Integer couponId) {
-        // 保存到Redis
-        String couponUsedKey = COUPON_USED_KEY_PREFIX + tableId;
-        baseRedisService.setString(couponUsedKey, String.valueOf(couponId), (long) CART_EXPIRE_SECONDS);
-
-        // 保存到数据库
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table == null) {
-            log.warn("桌号不存在, tableId={}", tableId);
-            return;
-        }
-
-        // 检查是否已存在
-        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCouponUsage::getTableId, tableId);
-        wrapper.eq(StoreCouponUsage::getCouponId, couponId);
-        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-        StoreCouponUsage existing = storeCouponUsageMapper.selectOne(wrapper);
-
-        if (existing == null) {
-            Date now = new Date();
-            StoreCouponUsage usage = new StoreCouponUsage();
-            usage.setTableId(tableId);
-            usage.setStoreId(table.getStoreId());
-            usage.setCouponId(couponId);
-            usage.setUsageStatus(0); // 已标记使用
-            usage.setCreatedTime(now);
-            usage.setUpdatedTime(now); // 设置更新时间,避免数据库约束错误
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId != null) {
-                usage.setCreatedUserId(userId);
-            }
-            storeCouponUsageMapper.insert(usage);
-        }
-
-        // 更新桌号表的优惠券ID
-        table.setCurrentCouponId(couponId);
-        storeTableMapper.updateById(table);
-    }
-
-    @Override
-    public void clearCouponUsed(Integer tableId) {
-        // 清空Redis
-        String couponUsedKey = COUPON_USED_KEY_PREFIX + tableId;
-        baseRedisService.delete(couponUsedKey);
-
-        // 更新数据库(逻辑删除未下单的记录,使用 MyBatis-Plus 的 deleteBatchIds)
-        LambdaQueryWrapper<StoreCouponUsage> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCouponUsage::getTableId, tableId);
-        wrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-        wrapper.eq(StoreCouponUsage::getUsageStatus, 0); // 只删除已标记使用但未下单的
-        List<StoreCouponUsage> usageList = storeCouponUsageMapper.selectList(wrapper);
-        if (usageList != null && !usageList.isEmpty()) {
-            List<Integer> usageIds = usageList.stream()
-                    .map(StoreCouponUsage::getId)
-                    .collect(Collectors.toList());
-            // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-            storeCouponUsageMapper.deleteBatchIds(usageIds);
-        }
-
-        // 更新桌号表的优惠券ID
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            table.setCurrentCouponId(null);
-            storeTableMapper.updateById(table);
-        }
-    }
-
-    /**
-     * 餐具的特殊ID(用于标识餐具项)
-     */
-    private static final Integer TABLEWARE_CUISINE_ID = -1;
-    private static final String TABLEWARE_NAME = "餐具费";
-
-    /**
-     * 获取餐具单价(从 store_info 表获取)
-     *
-     * @param storeId 门店ID
-     * @return 餐具单价(BigDecimal),如果门店不存在或未设置餐具费,返回 0.00
-     */
-    private BigDecimal getTablewareUnitPrice(Integer storeId) {
-        if (storeId == null) {
-            log.warn("门店ID为空,返回默认餐具单价 0.00");
-            return BigDecimal.ZERO;
-        }
-        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
-        if (storeInfo == null) {
-            log.warn("门店不存在, storeId={},返回默认餐具单价 0.00", storeId);
-            return BigDecimal.ZERO;
-        }
-        Integer tablewareFee = storeInfo.getTablewareFee();
-        if (tablewareFee == null || tablewareFee < 0) {
-            log.warn("门店餐具费未设置或无效, storeId={}, tablewareFee={},返回默认餐具单价 0.00", storeId, tablewareFee);
-            return BigDecimal.ZERO;
-        }
-        return BigDecimal.valueOf(tablewareFee);
-    }
-
-    @Override
-    public CartDTO setDinerCount(Integer tableId, Integer dinerCount) {
-        log.info("设置用餐人数, tableId={}, dinerCount={}", tableId, dinerCount);
-        
-        if (dinerCount == null || dinerCount <= 0) {
-            throw new RuntimeException("用餐人数必须大于0");
-        }
-
-        // 获取购物车
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-
-        // 获取门店ID和餐具单价
-        Integer storeId = cart.getStoreId();
-        if (storeId == null) {
-            // 如果购物车中没有门店ID,从桌号获取
-            StoreTable table = storeTableMapper.selectById(tableId);
-            if (table != null) {
-                storeId = table.getStoreId();
-            }
-        }
-        BigDecimal tablewareUnitPrice = getTablewareUnitPrice(storeId);
-
-        // 商铺未设置餐具费时,不往购物车加餐具;若已有餐具项则移除
-        if (tablewareUnitPrice == null || tablewareUnitPrice.compareTo(BigDecimal.ZERO) <= 0) {
-            log.info("门店未设置餐具费, storeId={},设置就餐人数时不添加餐具", storeId);
-            CartItemDTO existing = items.stream()
-                    .filter(item -> TABLEWARE_CUISINE_ID.equals(item.getCuisineId()))
-                    .findFirst()
-                    .orElse(null);
-            if (existing != null) {
-                items.remove(existing);
-            }
-        } else {
-            // 查找是否已存在餐具项
-            CartItemDTO tablewareItem = items.stream()
-                    .filter(item -> TABLEWARE_CUISINE_ID.equals(item.getCuisineId()))
-                    .findFirst()
-                    .orElse(null);
-
-            Integer userId = TokenUtil.getCurrentUserId();
-            String userPhone = TokenUtil.getCurrentUserPhone();
-
-            if (tablewareItem != null) {
-                Integer lockedQuantity = tablewareItem.getLockedQuantity();
-                if (lockedQuantity != null && lockedQuantity > 0 && dinerCount < lockedQuantity) {
-                    throw new RuntimeException("餐具数量不能少于已下单数量(" + lockedQuantity + ")");
-                }
-                tablewareItem.setQuantity(dinerCount);
-                tablewareItem.setUnitPrice(tablewareUnitPrice);
-                tablewareItem.setSubtotalAmount(tablewareUnitPrice.multiply(BigDecimal.valueOf(dinerCount)));
-            } else {
-                CartItemDTO newTablewareItem = new CartItemDTO();
-                newTablewareItem.setCuisineId(TABLEWARE_CUISINE_ID);
-                newTablewareItem.setCuisineName(TABLEWARE_NAME);
-                newTablewareItem.setCuisineType(0);
-                newTablewareItem.setCuisineImage("");
-                newTablewareItem.setUnitPrice(tablewareUnitPrice);
-                newTablewareItem.setQuantity(dinerCount);
-                newTablewareItem.setSubtotalAmount(tablewareUnitPrice.multiply(BigDecimal.valueOf(dinerCount)));
-                newTablewareItem.setAddUserId(userId);
-                newTablewareItem.setAddUserPhone(userPhone);
-                items.add(newTablewareItem);
-            }
-        }
-
-        // 重新计算总金额和总数量
-        BigDecimal totalAmount = items.stream()
-                .map(CartItemDTO::getSubtotalAmount)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Integer totalQuantity = items.stream()
-                .mapToInt(CartItemDTO::getQuantity)
-                .sum();
-        cart.setTotalAmount(totalAmount);
-        cart.setTotalQuantity(totalQuantity);
-
-        // 保存到Redis和数据库(双写策略)
-        saveCart(cart);
-
-        return cart;
-    }
-
-    @Override
-    public CartDTO updateTablewareQuantity(Integer tableId, Integer quantity) {
-        log.info("更新餐具数量, tableId={}, quantity={}", tableId, quantity);
-        
-        if (quantity == null || quantity < 0) {
-            throw new RuntimeException("餐具数量不能小于0");
-        }
-
-        if (quantity == 0) {
-            // 数量为0时,删除餐具项
-            return removeItem(tableId, TABLEWARE_CUISINE_ID);
-        }
-
-        // 获取购物车
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-
-        // 获取门店ID和餐具单价
-        Integer storeId = cart.getStoreId();
-        if (storeId == null) {
-            StoreTable table = storeTableMapper.selectById(tableId);
-            if (table != null) {
-                storeId = table.getStoreId();
-            }
-        }
-        BigDecimal tablewareUnitPrice = getTablewareUnitPrice(storeId);
-
-        // 商铺未设置餐具费(单价为0或未配置)时,不往购物车加餐具;若已有餐具项则移除
-        if (tablewareUnitPrice == null || tablewareUnitPrice.compareTo(BigDecimal.ZERO) <= 0) {
-            log.info("门店未设置餐具费, storeId={},不添加餐具到购物车", storeId);
-            CartItemDTO existing = items.stream()
-                    .filter(item -> TABLEWARE_CUISINE_ID.equals(item.getCuisineId()))
-                    .findFirst()
-                    .orElse(null);
-            if (existing != null) {
-                items.remove(existing);
-                BigDecimal totalAmount = items.stream()
-                        .map(CartItemDTO::getSubtotalAmount)
-                        .reduce(BigDecimal.ZERO, BigDecimal::add);
-                Integer totalQuantity = items.stream()
-                        .mapToInt(CartItemDTO::getQuantity)
-                        .sum();
-                cart.setTotalAmount(totalAmount);
-                cart.setTotalQuantity(totalQuantity);
-                saveCart(cart);
-            }
-            return cart;
-        }
-
-        // 查找餐具项
-        CartItemDTO tablewareItem = items.stream()
-                .filter(item -> TABLEWARE_CUISINE_ID.equals(item.getCuisineId()))
-                .findFirst()
-                .orElse(null);
-
-        if (tablewareItem == null) {
-            // 如果不存在餐具项,创建一个
-            Integer userId = TokenUtil.getCurrentUserId();
-            String userPhone = TokenUtil.getCurrentUserPhone();
-            
-            tablewareItem = new CartItemDTO();
-            tablewareItem.setCuisineId(TABLEWARE_CUISINE_ID);
-            tablewareItem.setCuisineName(TABLEWARE_NAME);
-            tablewareItem.setCuisineType(0); // 0表示餐具
-            tablewareItem.setCuisineImage("");
-            tablewareItem.setUnitPrice(tablewareUnitPrice);
-            tablewareItem.setAddUserId(userId);
-            tablewareItem.setAddUserPhone(userPhone);
-            items.add(tablewareItem);
-        } else {
-            // 下单后只能增不能减:已有已下单数量时,数量不能少于已下单数量
-            Integer lockedQuantity = tablewareItem.getLockedQuantity();
-            if (lockedQuantity != null && lockedQuantity > 0 && quantity < lockedQuantity) {
-                throw new RuntimeException("餐具数量不能少于已下单数量(" + lockedQuantity + ")");
-            }
-            // 如果已存在,更新单价(可能门店修改了餐具费)
-            tablewareItem.setUnitPrice(tablewareUnitPrice);
-        }
-
-        // 更新数量
-        tablewareItem.setQuantity(quantity);
-        tablewareItem.setSubtotalAmount(tablewareUnitPrice.multiply(BigDecimal.valueOf(quantity)));
-
-        // 重新计算总金额和总数量
-        BigDecimal totalAmount = items.stream()
-                .map(CartItemDTO::getSubtotalAmount)
-                .reduce(BigDecimal.ZERO, BigDecimal::add);
-        Integer totalQuantity = items.stream()
-                .mapToInt(CartItemDTO::getQuantity)
-                .sum();
-        cart.setTotalAmount(totalAmount);
-        cart.setTotalQuantity(totalQuantity);
-
-        // 保存到Redis和数据库(双写策略)
-        saveCart(cart);
-
-        return cart;
-    }
-
-    @Override
-    public CartDTO lockCartItems(Integer tableId) {
-        log.info("锁定购物车商品数量(设置已下单数量), tableId={}", tableId);
-        
-        // 获取购物车
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-        
-        if (items == null || items.isEmpty()) {
-            log.warn("购物车为空,无需锁定, tableId={}", tableId);
-            return cart;
-        }
-        
-        // 遍历所有商品,将当前数量设置为已下单数量
-        boolean hasChanges = false;
-        for (CartItemDTO item : items) {
-            Integer currentQuantity = item.getQuantity();
-            Integer lockedQuantity = item.getLockedQuantity();
-            
-            if (currentQuantity != null && currentQuantity > 0) {
-                if (lockedQuantity == null || lockedQuantity == 0) {
-                    // 如果还没有已下单数量,将当前数量设置为已下单数量
-                    item.setLockedQuantity(currentQuantity);
-                    hasChanges = true;
-                    log.info("设置商品已下单数量, cuisineId={}, orderedQuantity={}", item.getCuisineId(), currentQuantity);
-                } else if (currentQuantity > lockedQuantity) {
-                    // 如果已有已下单数量,且当前数量大于已下单数量(再次下单的情况),将新增数量累加到已下单数量
-                    Integer newLockedQuantity = lockedQuantity + (currentQuantity - lockedQuantity);
-                    item.setLockedQuantity(newLockedQuantity);
-                    hasChanges = true;
-                    log.info("更新商品已下单数量, cuisineId={}, oldOrderedQuantity={}, newOrderedQuantity={}", 
-                            item.getCuisineId(), lockedQuantity, newLockedQuantity);
-                }
-            }
-        }
-        
-        // 如果有变化,保存购物车
-        if (hasChanges) {
-            saveCart(cart);
-        }
-        
-        return cart;
-    }
-
-    @Override
-    public CartDTO unlockCartItems(Integer tableId) {
-        log.info("解锁购物车商品数量(清除已下单数量), tableId={}", tableId);
-        
-        // 获取购物车
-        CartDTO cart = getCart(tableId);
-        List<CartItemDTO> items = cart.getItems();
-        
-        if (items == null || items.isEmpty()) {
-            log.info("购物车为空,无需解锁, tableId={}", tableId);
-            return cart;
-        }
-        
-        // 遍历所有商品,清除已下单数量(lockedQuantity)
-        boolean hasChanges = false;
-        for (CartItemDTO item : items) {
-            if (item.getLockedQuantity() != null && item.getLockedQuantity() > 0) {
-                // 清除已下单数量,允许重新下单
-                item.setLockedQuantity(null);
-                hasChanges = true;
-                log.info("清除商品已下单数量, cuisineId={}", item.getCuisineId());
-            }
-        }
-        
-        // 如果有变化,保存购物车
-        if (hasChanges) {
-            saveCart(cart);
-            log.info("解锁购物车商品数量完成, tableId={}", tableId);
-        } else {
-            log.info("购物车无需解锁, tableId={}", tableId);
-        }
-        
-        return cart;
-    }
-
-    /**
-     * 保存购物车到Redis和数据库(优化后的双写策略)
-     * Redis同步写入(保证实时性),数据库异步批量写入(提高性能)
-     */
-    private void saveCart(CartDTO cart) {
-        // 1. 同步保存到Redis(保证实时性)
-        saveCartToRedis(cart);
-
-        // 2. 异步保存到数据库(不阻塞主流程,提高性能)
-        CompletableFuture.runAsync(() -> {
-            try {
-                saveCartToDatabase(cart);
-            } catch (Exception e) {
-                log.error("异步保存购物车到数据库失败, tableId={}, error={}", cart.getTableId(), e.getMessage(), e);
-            }
-        }, CART_DB_WRITE_EXECUTOR);
-    }
-
-    /**
-     * 保存购物车到Redis
-     */
-    private void saveCartToRedis(CartDTO cart) {
-        String cartKey = CART_KEY_PREFIX + cart.getTableId();
-        String cartJson = JSON.toJSONString(cart);
-        baseRedisService.setString(cartKey, cartJson, (long) CART_EXPIRE_SECONDS);
-    }
-
-    /**
-     * 保存购物车到数据库(优化后的批量操作版本)
-     * 使用批量逻辑删除和批量插入,提高性能
-     */
-    private void saveCartToDatabase(CartDTO cart) {
-        try {
-            Date now = new Date();
-            Integer userId = TokenUtil.getCurrentUserId();
-
-            // 1. 批量逻辑删除该桌号的所有购物车记录(使用 MyBatis-Plus 的 deleteBatchIds)
-            LambdaQueryWrapper<StoreCart> queryWrapper = new LambdaQueryWrapper<>();
-            queryWrapper.eq(StoreCart::getTableId, cart.getTableId())
-                    .eq(StoreCart::getDeleteFlag, 0);
-            List<StoreCart> existingCartList = storeCartMapper.selectList(queryWrapper);
-            if (existingCartList != null && !existingCartList.isEmpty()) {
-                List<Integer> cartIds = existingCartList.stream()
-                        .map(StoreCart::getId)
-                        .collect(Collectors.toList());
-                // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-                storeCartMapper.deleteBatchIds(cartIds);
-            }
-
-            // 2. 批量插入新的购物车记录
-            if (cart.getItems() != null && !cart.getItems().isEmpty()) {
-                List<StoreCart> cartList = new ArrayList<>(cart.getItems().size());
-                for (CartItemDTO item : cart.getItems()) {
-                    StoreCart storeCart = new StoreCart();
-                    storeCart.setTableId(cart.getTableId());
-                    storeCart.setStoreId(cart.getStoreId());
-                    storeCart.setCuisineId(item.getCuisineId());
-                    storeCart.setCuisineName(item.getCuisineName());
-                    storeCart.setCuisineImage(item.getCuisineImage());
-                    storeCart.setUnitPrice(item.getUnitPrice());
-                    storeCart.setQuantity(item.getQuantity());
-                    storeCart.setLockedQuantity(item.getLockedQuantity());
-                    storeCart.setSubtotalAmount(item.getSubtotalAmount());
-                    storeCart.setAddUserId(item.getAddUserId());
-                    storeCart.setAddUserPhone(item.getAddUserPhone());
-                    storeCart.setRemark(item.getRemark());
-                    storeCart.setDeleteFlag(0);
-                    storeCart.setCreatedTime(now);
-                    storeCart.setCreatedUserId(userId);
-                    storeCart.setUpdatedTime(now);
-                    cartList.add(storeCart);
-                }
-
-                // 批量插入(如果数量较少,直接循环插入;如果数量较多,可以考虑分批插入)
-                if (cartList.size() <= 50) {
-                    // 小批量直接插入
-                    for (StoreCart storeCart : cartList) {
-                        storeCartMapper.insert(storeCart);
-                    }
-                } else {
-                    // 大批量分批插入(每批50条)
-                    int batchSize = 50;
-                    for (int i = 0; i < cartList.size(); i += batchSize) {
-                        int end = Math.min(i + batchSize, cartList.size());
-                        List<StoreCart> batch = cartList.subList(i, end);
-                        for (StoreCart storeCart : batch) {
-                            storeCartMapper.insert(storeCart);
-                        }
-                    }
-                }
-            }
-
-            // 3. 更新桌号表的购物车统计
-            StoreTable table = storeTableMapper.selectById(cart.getTableId());
-            if (table != null) {
-                table.setCartItemCount(cart.getTotalQuantity());
-                table.setCartTotalAmount(cart.getTotalAmount());
-                storeTableMapper.updateById(table);
-            }
-
-            log.debug("购物车数据已异步保存到数据库, tableId={}, itemCount={}", 
-                    cart.getTableId(), cart.getItems() != null ? cart.getItems().size() : 0);
-        } catch (Exception e) {
-            log.error("保存购物车到数据库失败, tableId={}, error={}", cart.getTableId(), e.getMessage(), e);
-            // 数据库保存失败不影响Redis,继续执行
-        }
-    }
-}

+ 0 - 39
alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningCollectServiceImpl.java

@@ -1,39 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import shop.alien.store.dining.feign.AlienStoreFeign;
-import shop.alien.store.dining.service.DiningCollectService;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeCollect;
-
-/**
- * 点餐模块-收藏服务实现(透传 Feign 调 store)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/01/XX
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class DiningCollectServiceImpl implements DiningCollectService {
-
-    private final AlienStoreFeign alienStoreFeign;
-
-    @Override
-    public R<Boolean> addCollect(LifeCollect lifeCollect) {
-        log.info("DiningCollectService.addCollect lifeCollect={}", lifeCollect);
-        try {
-            R<Boolean> result = alienStoreFeign.addCollect(lifeCollect);
-            if (result == null) {
-                return R.fail("添加收藏失败");
-            }
-            return result;
-        } catch (Exception e) {
-            log.error("DiningCollectService.addCollect ERROR Msg={}", e.getMessage());
-            return R.fail("添加收藏失败");
-        }
-    }
-}

+ 0 - 471
alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningCouponServiceImpl.java

@@ -1,471 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import shop.alien.store.dining.feign.AlienStoreFeign;
-import shop.alien.store.dining.service.DiningCouponService;
-import shop.alien.store.dining.util.TokenUtil;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeDiscountCoupon;
-import shop.alien.entity.store.LifeDiscountCouponUser;
-import shop.alien.entity.store.vo.LifeDiscountCouponVo;
-import shop.alien.mapper.LifeDiscountCouponMapper;
-import shop.alien.mapper.LifeDiscountCouponUserMapper;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-/**
- * 点餐模块-优惠券服务实现(透传 Feign 调 store,满足小程序我的优惠券/详情/选券)
- *
- * @author ssk
- * @version 1.0
- * @date 2025/1/29
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class DiningCouponServiceImpl implements DiningCouponService {
-
-    private final AlienStoreFeign alienStoreFeign;
-    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
-    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
-
-    @Override
-    public R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeName) {
-        log.info("DiningCouponService.getUserCouponList page={}, size={}, tabType={}, type={}, couponType={}, storeId={}, storeName={}", page, size, tabType, type, couponType, storeId, storeName);
-        try {
-            // 参数校验
-            if (StringUtils.isEmpty(tabType)) {
-                log.warn("tabType参数为空");
-                return R.fail("分页类型不能为空");
-            }
-            if (page < 1) {
-                page = 1;
-            }
-            if (size < 1 || size > 100) {
-                size = 10;
-            }
-            
-            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getUserCouponList(authorization, tabType, page, size, type, couponType, storeId, storeName);
-            if (result == null) {
-                log.error("Feign调用返回null");
-                return R.fail("获取优惠券列表失败:服务返回为空");
-            }
-            // 如果 Feign 返回的是失败结果,直接返回
-            if (!result.isSuccess()) {
-                log.warn("Feign调用返回失败: code={}, msg={}", result.getCode(), result.getMsg());
-                return result;
-            }
-            return result;
-        } catch (Exception e) {
-            log.error("DiningCouponService.getUserCouponList ERROR: {}", e.getMessage(), e);
-            return R.fail("获取优惠券列表失败: " + e.getMessage());
-        }
-    }
-
-    @Override
-    public R<LifeDiscountCouponVo> getCounponDetailById(String authorization, String counponId) {
-        log.info("DiningCouponService.getCounponDetailById counponId={}", counponId);
-        try {
-            R<LifeDiscountCouponVo> result = alienStoreFeign.getCounponDetailById(authorization, counponId);
-            if (result == null) {
-                return R.fail("获取优惠券详情失败");
-            }
-            return result;
-        } catch (Exception e) {
-            log.error("DiningCouponService.getCounponDetailById ERROR Msg={}", e.getMessage());
-            return R.fail("获取优惠券详情失败");
-        }
-    }
-
-    @Override
-    public R<Map<String, Object>> getStoreUserUsableCouponList(String authorization, String storeId, BigDecimal amount, Integer couponType) {
-        log.info("DiningCouponService.getStoreUserUsableCouponList storeId={}, amount={}, couponType={}", storeId, amount, couponType);
-        try {
-            R<Map<String, Object>> result = alienStoreFeign.getStoreUserUsableCouponList(authorization, storeId, amount, couponType);
-            if (result == null) {
-                return R.fail("获取门店可用优惠券列表失败");
-            }
-            return result;
-        } catch (Exception e) {
-            log.error("DiningCouponService.getStoreUserUsableCouponList ERROR Msg={}", e.getMessage());
-            return R.fail("获取门店可用优惠券列表失败");
-        }
-    }
-
-    @Override
-    public R<List<LifeDiscountCouponVo>> getUserOwnedCoupons(String storeId, BigDecimal amount) {
-        log.info("查询用户拥有的优惠券, storeId={}, amount={}", storeId, amount);
-
-        try {
-            // 获取当前用户ID
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-
-            // 查询用户拥有的优惠券(未使用且未过期的)
-            LambdaQueryWrapper<LifeDiscountCouponUser> userWrapper = new LambdaQueryWrapper<>();
-            userWrapper.eq(LifeDiscountCouponUser::getUserId, userId);
-            userWrapper.eq(LifeDiscountCouponUser::getStatus, 0); // 0:待使用
-            userWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
-            userWrapper.ge(LifeDiscountCouponUser::getExpirationTime, LocalDate.now()); // 未过期
-            List<LifeDiscountCouponUser> userCoupons = lifeDiscountCouponUserMapper.selectList(userWrapper);
-
-            if (userCoupons == null || userCoupons.isEmpty()) {
-                log.info("用户没有可用的优惠券, userId={}", userId);
-                return R.data(new ArrayList<>());
-            }
-
-            // 获取优惠券ID列表
-            List<Integer> couponIds = userCoupons.stream()
-                    .map(LifeDiscountCouponUser::getCouponId)
-                    .collect(Collectors.toList());
-
-            // 查询优惠券详情
-            LambdaQueryWrapper<LifeDiscountCoupon> couponWrapper = new LambdaQueryWrapper<>();
-            couponWrapper.in(LifeDiscountCoupon::getId, couponIds);
-            couponWrapper.eq(LifeDiscountCoupon::getDeleteFlag, 0);
-            if (StringUtils.hasText(storeId)) {
-                couponWrapper.eq(LifeDiscountCoupon::getStoreId, storeId);
-            }
-            List<LifeDiscountCoupon> coupons = lifeDiscountCouponMapper.selectList(couponWrapper);
-
-            if (coupons == null || coupons.isEmpty()) {
-                log.info("未找到优惠券详情, userId={}, couponIds={}", userId, couponIds);
-                return R.data(new ArrayList<>());
-            }
-
-            // 转换为VO并设置用户券ID,同时过滤掉已过期和未在使用时间内的优惠券
-            LocalDate now = LocalDate.now();
-            List<LifeDiscountCouponVo> couponVos = new ArrayList<>();
-            for (LifeDiscountCoupon coupon : coupons) {
-                // 找到对应的用户券
-                LifeDiscountCouponUser userCoupon = userCoupons.stream()
-                        .filter(uc -> uc.getCouponId().equals(coupon.getId()))
-                        .findFirst()
-                        .orElse(null);
-
-                if (userCoupon == null) {
-                    continue;
-                }
-
-                // 过滤1:检查用户券的过期时间(expirationTime)
-                if (userCoupon.getExpirationTime() != null && now.isAfter(userCoupon.getExpirationTime())) {
-                    log.debug("过滤已过期的用户券, couponId={}, expirationTime={}, now={}", 
-                            coupon.getId(), userCoupon.getExpirationTime(), now);
-                    continue;
-                }
-
-                // 过滤2:检查优惠券的使用时间范围(startDate 和 endDate)
-                // 如果优惠券有设置使用时间范围,则检查当前日期是否在范围内
-                if (coupon.getStartDate() != null || coupon.getEndDate() != null) {
-                    boolean inTimeRange = true;
-                    if (coupon.getStartDate() != null && now.isBefore(coupon.getStartDate())) {
-                        // 当前日期早于开始日期,未在使用时间内
-                        inTimeRange = false;
-                    }
-                    if (coupon.getEndDate() != null && now.isAfter(coupon.getEndDate())) {
-                        // 当前日期晚于结束日期,未在使用时间内
-                        inTimeRange = false;
-                    }
-                    if (!inTimeRange) {
-                        log.debug("过滤未在使用时间内的优惠券, couponId={}, startDate={}, endDate={}, now={}", 
-                                coupon.getId(), coupon.getStartDate(), coupon.getEndDate(), now);
-                        continue;
-                    }
-                }
-
-                // 过滤3:检查优惠券的有效期(validDate)
-                if (coupon.getValidDate() != null && now.isAfter(coupon.getValidDate())) {
-                    log.debug("过滤已过期的优惠券(validDate), couponId={}, validDate={}, now={}", 
-                            coupon.getId(), coupon.getValidDate(), now);
-                    continue;
-                }
-
-                LifeDiscountCouponVo vo = convertToVo(coupon, userCoupon);
-                couponVos.add(vo);
-            }
-
-            // 排序:符合支付条件的优先,其次优惠力度大的优先
-            if (amount != null) {
-                couponVos.sort((vo1, vo2) -> {
-                    // 判断是否符合支付条件(满足最低消费要求)
-                    boolean vo1CanUse = vo1.getMinimumSpendingAmount() == null
-                            || vo1.getMinimumSpendingAmount().compareTo(amount) <= 0;
-                    boolean vo2CanUse = vo2.getMinimumSpendingAmount() == null
-                            || vo2.getMinimumSpendingAmount().compareTo(amount) <= 0;
-
-                    // 第一优先级:符合支付条件的优先
-                    if (vo1CanUse && !vo2CanUse) {
-                        return -1; // vo1 排在前面
-                    }
-                    if (!vo1CanUse && vo2CanUse) {
-                        return 1; // vo2 排在前面
-                    }
-
-                    // 第二优先级:优惠力度大的优先(根据优惠券类型计算实际优惠金额)
-                    BigDecimal discountAmount1 = calculateDiscountAmountForVO(vo1, amount);
-                    BigDecimal discountAmount2 = calculateDiscountAmountForVO(vo2, amount);
-                    return discountAmount2.compareTo(discountAmount1); // 降序排列
-                });
-            } else {
-                // 如果没有提供金额,无法计算折扣券的实际优惠金额,只按面值排序(满减券)
-                // 注意:这种情况下折扣券无法准确排序,建议前端传入订单金额
-                couponVos.sort((vo1, vo2) -> {
-                    BigDecimal nominalValue1 = vo1.getNominalValue() != null ? vo1.getNominalValue() : BigDecimal.ZERO;
-                    BigDecimal nominalValue2 = vo2.getNominalValue() != null ? vo2.getNominalValue() : BigDecimal.ZERO;
-                    return nominalValue2.compareTo(nominalValue1); // 降序排列
-                });
-            }
-
-            log.info("查询用户拥有的优惠券成功, userId={}, count={}", userId, couponVos.size());
-            return R.data(couponVos);
-
-        } catch (Exception e) {
-            log.error("查询用户拥有的优惠券失败: {}", e.getMessage(), e);
-            return R.fail("查询用户拥有的优惠券失败: " + e.getMessage());
-        }
-    }
-
-    @Override
-    public R<List<LifeDiscountCouponVo>> getStoreUserCouponList(String authorization, String storeId, Integer couponType) {
-        log.info("DiningCouponService.getStoreUserCouponList storeId={}, couponType={}", storeId, couponType);
-        try {
-            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getStoreUserCouponList(authorization, storeId, couponType);
-            if (result == null) {
-                return R.fail("获取该用户该店铺优惠券列表失败");
-            }
-            return result;
-        } catch (Exception e) {
-            log.error("DiningCouponService.getStoreUserCouponList ERROR Msg={}", e.getMessage());
-            return R.fail("获取该用户该店铺优惠券列表失败");
-        }
-    }
-
-    @Override
-    public R<IPage<LifeDiscountCouponVo>> getStoreAllCouponList(String authorization, int page, int size, String storeId,
-                                                                String couponName, String tab, int couponsFromType,
-                                                                int couponStatus, Integer couponType) {
-        log.info("DiningCouponService.getStoreAllCouponList storeId={}, page={}, size={}, couponName={}, tab={}, couponsFromType={}, couponStatus={}, couponType={}",
-                storeId, page, size, couponName, tab, couponsFromType, couponStatus, couponType);
-        try {
-            // Feign 返回 Page 类型(具体实现类),但 Service 接口使用 IPage(接口类型)
-            // Page 实现了 IPage,所以可以直接返回
-            R<com.baomidou.mybatisplus.extension.plugins.pagination.Page<LifeDiscountCouponVo>> result = alienStoreFeign.getStoreAllCouponList(
-                    authorization, page, size, storeId, couponName, tab, couponsFromType, couponStatus, couponType);
-            if (result == null) {
-                return R.fail("获取该店铺所有优惠券列表失败");
-            }
-            // Page 实现了 IPage 接口,可以直接转换
-            return R.data(result.getData());
-        } catch (Exception e) {
-            log.error("DiningCouponService.getStoreAllCouponList ERROR Msg={}", e.getMessage(), e);
-            return R.fail("获取该店铺所有优惠券列表失败");
-        }
-    }
-
-    @Override
-    public R<List<LifeDiscountCouponVo>> getUserOwnedCouponsByStore(String storeId, Integer couponType) {
-        log.info("查询用户目前所拥有的优惠券, storeId={}, couponType={}", storeId, couponType);
-
-        try {
-            // 获取当前用户ID
-            Integer userId = TokenUtil.getCurrentUserId();
-            if (userId == null) {
-                return R.fail("用户未登录");
-            }
-
-            // 查询用户拥有的优惠券(未使用且未过期的)
-            LambdaQueryWrapper<LifeDiscountCouponUser> userWrapper = new LambdaQueryWrapper<>();
-            userWrapper.eq(LifeDiscountCouponUser::getUserId, userId);
-            userWrapper.eq(LifeDiscountCouponUser::getStatus, 0); // 0:待使用
-            userWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
-            userWrapper.ge(LifeDiscountCouponUser::getExpirationTime, LocalDate.now()); // 未过期
-            List<LifeDiscountCouponUser> userCoupons = lifeDiscountCouponUserMapper.selectList(userWrapper);
-
-            if (userCoupons == null || userCoupons.isEmpty()) {
-                log.info("用户没有可用的优惠券, userId={}", userId);
-                return R.data(new ArrayList<>());
-            }
-
-            // 获取优惠券ID列表
-            List<Integer> couponIds = userCoupons.stream()
-                    .map(LifeDiscountCouponUser::getCouponId)
-                    .collect(Collectors.toList());
-
-            // 查询优惠券详情
-            LambdaQueryWrapper<LifeDiscountCoupon> couponWrapper = new LambdaQueryWrapper<>();
-            couponWrapper.in(LifeDiscountCoupon::getId, couponIds);
-            couponWrapper.eq(LifeDiscountCoupon::getDeleteFlag, 0);
-            // 如果提供了商铺ID,则只查询该商铺的优惠券
-            if (StringUtils.hasText(storeId)) {
-                couponWrapper.eq(LifeDiscountCoupon::getStoreId, storeId);
-            }
-            // 如果提供了优惠券类型,则只查询该类型的优惠券
-            if (couponType != null) {
-                couponWrapper.eq(LifeDiscountCoupon::getCouponType, couponType);
-            }
-            List<LifeDiscountCoupon> coupons = lifeDiscountCouponMapper.selectList(couponWrapper);
-
-            if (coupons == null || coupons.isEmpty()) {
-                log.info("未找到优惠券详情, userId={}, storeId={}, couponIds={}", userId, storeId, couponIds);
-                return R.data(new ArrayList<>());
-            }
-
-            // 转换为VO并设置用户券ID,同时过滤掉已过期和未在使用时间内的优惠券
-            LocalDate now = LocalDate.now();
-            List<LifeDiscountCouponVo> couponVos = new ArrayList<>();
-            for (LifeDiscountCoupon coupon : coupons) {
-                // 找到对应的用户券
-                LifeDiscountCouponUser userCoupon = userCoupons.stream()
-                        .filter(uc -> uc.getCouponId().equals(coupon.getId()))
-                        .findFirst()
-                        .orElse(null);
-
-                if (userCoupon == null) {
-                    continue;
-                }
-
-                // 过滤1:检查用户券的过期时间(expirationTime)
-                if (userCoupon.getExpirationTime() != null && now.isAfter(userCoupon.getExpirationTime())) {
-                    log.debug("过滤已过期的用户券, couponId={}, expirationTime={}, now={}", 
-                            coupon.getId(), userCoupon.getExpirationTime(), now);
-                    continue;
-                }
-
-                // 过滤2:检查优惠券的使用时间范围(startDate 和 endDate)
-                // 如果优惠券有设置使用时间范围,则检查当前日期是否在范围内
-                if (coupon.getStartDate() != null || coupon.getEndDate() != null) {
-                    boolean inTimeRange = true;
-                    if (coupon.getStartDate() != null && now.isBefore(coupon.getStartDate())) {
-                        // 当前日期早于开始日期,未在使用时间内
-                        inTimeRange = false;
-                    }
-                    if (coupon.getEndDate() != null && now.isAfter(coupon.getEndDate())) {
-                        // 当前日期晚于结束日期,未在使用时间内
-                        inTimeRange = false;
-                    }
-                    if (!inTimeRange) {
-                        log.debug("过滤未在使用时间内的优惠券, couponId={}, startDate={}, endDate={}, now={}", 
-                                coupon.getId(), coupon.getStartDate(), coupon.getEndDate(), now);
-                        continue;
-                    }
-                }
-
-                // 过滤3:检查优惠券的有效期(validDate)
-                if (coupon.getValidDate() != null && now.isAfter(coupon.getValidDate())) {
-                    log.debug("过滤已过期的优惠券(validDate), couponId={}, validDate={}, now={}", 
-                            coupon.getId(), coupon.getValidDate(), now);
-                    continue;
-                }
-
-                LifeDiscountCouponVo vo = convertToVo(coupon, userCoupon);
-                couponVos.add(vo);
-            }
-
-            // 按创建时间倒序排列(最新的在前)
-            couponVos.sort((vo1, vo2) -> {
-                if (vo1.getCreatedTime() == null && vo2.getCreatedTime() == null) {
-                    return 0;
-                }
-                if (vo1.getCreatedTime() == null) {
-                    return 1;
-                }
-                if (vo2.getCreatedTime() == null) {
-                    return -1;
-                }
-                return vo2.getCreatedTime().compareTo(vo1.getCreatedTime()); // 降序排列
-            });
-
-            log.info("查询用户拥有的优惠券成功, userId={}, storeId={}, count={}", userId, storeId, couponVos.size());
-            return R.data(couponVos);
-
-        } catch (Exception e) {
-            log.error("查询用户拥有的优惠券失败: {}", e.getMessage(), e);
-            return R.fail("查询用户拥有的优惠券失败: " + e.getMessage());
-        }
-    }
-
-    /**
-     * 将优惠券实体转换为VO
-     */
-    private LifeDiscountCouponVo convertToVo(LifeDiscountCoupon coupon, LifeDiscountCouponUser userCoupon) {
-        LifeDiscountCouponVo vo = new LifeDiscountCouponVo();
-        vo.setId(coupon.getId());
-        vo.setUserCouponId(userCoupon.getId());
-        vo.setStoreId(coupon.getStoreId());
-        vo.setUserId(String.valueOf(userCoupon.getUserId()));
-        vo.setCouponId(coupon.getId());
-        vo.setName(coupon.getName());
-        vo.setNominalValue(coupon.getNominalValue());
-        vo.setExpirationDate(coupon.getExpirationDate());
-        vo.setStartDate(coupon.getStartDate());
-        vo.setEndDate(coupon.getEndDate());
-        vo.setSingleQty(coupon.getSingleQty());
-        vo.setSupplementaryInstruction(coupon.getSupplementaryInstruction());
-        vo.setGetStatus(coupon.getGetStatus());
-        vo.setRestrictedQuantity(coupon.getRestrictedQuantity());
-        vo.setMinimumSpendingAmount(coupon.getMinimumSpendingAmount());
-        vo.setType(coupon.getType());
-        vo.setAttentionCanReceived(coupon.getAttentionCanReceived());
-        vo.setExpirationTime(userCoupon.getExpirationTime());
-        vo.setCreatedTime(coupon.getCreatedTime());
-        vo.setCouponType(coupon.getCouponType());
-        vo.setDiscountRate(coupon.getDiscountRate());
-        return vo;
-    }
-
-    /**
-     * 计算优惠券的实际优惠金额(用于排序)
-     * 根据优惠券类型(满减券或折扣券)计算实际优惠金额
-     *
-     * @param vo          优惠券VO
-     * @param orderAmount 订单金额(用于计算折扣券的优惠金额)
-     * @return 实际优惠金额
-     */
-    private BigDecimal calculateDiscountAmountForVO(LifeDiscountCouponVo vo, BigDecimal orderAmount) {
-        if (vo == null) {
-            return BigDecimal.ZERO;
-        }
-
-        Integer couponType = vo.getCouponType();
-        BigDecimal discountAmount = BigDecimal.ZERO;
-
-        if (couponType != null && couponType == 2) {
-            // 折扣券:根据折扣率计算优惠金额
-            // discountRate: 0-100,例如80表示8折,优惠金额 = 订单金额 * (100 - discountRate) / 100
-            BigDecimal discountRate = vo.getDiscountRate();
-            if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 
-                    && discountRate.compareTo(new BigDecimal(100)) <= 0 && orderAmount != null 
-                    && orderAmount.compareTo(BigDecimal.ZERO) > 0) {
-                // 计算折扣后的金额
-                BigDecimal discountedAmount = orderAmount.multiply(discountRate)
-                        .divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
-                // 优惠金额 = 原价 - 折扣后价格
-                discountAmount = orderAmount.subtract(discountedAmount);
-            }
-        } else {
-            // 满减券(默认或couponType=1):使用nominalValue
-            discountAmount = vo.getNominalValue();
-            if (discountAmount == null) {
-                discountAmount = BigDecimal.ZERO;
-            }
-            // 优惠金额不能超过订单总金额
-            if (orderAmount != null && discountAmount.compareTo(orderAmount) > 0) {
-                discountAmount = orderAmount;
-            }
-        }
-
-        return discountAmount;
-    }
-}

+ 0 - 691
alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningServiceImpl.java

@@ -1,691 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import shop.alien.entity.store.*;
-
-import shop.alien.entity.store.dto.CartDTO;
-import shop.alien.entity.store.dto.CartItemDTO;
-import shop.alien.entity.store.vo.*;
-import shop.alien.mapper.*;
-import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.dining.service.CartService;
-import shop.alien.store.dining.service.DiningService;
-
-import java.math.BigDecimal;
-import java.time.LocalDate;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 点餐服务实现类
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class DiningServiceImpl implements DiningService {
-
-    private final StoreTableMapper storeTableMapper;
-    private final StoreInfoMapper storeInfoMapper;
-    private final StoreCuisineMapper storeCuisineMapper;
-    private final StoreCuisineCategoryMapper storeCuisineCategoryMapper;
-    private final StoreCuisineComboMapper storeCuisineComboMapper;
-    private final StoreOrderDetailMapper storeOrderDetailMapper;
-    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
-    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
-    private final CartService cartService;
-    private final BaseRedisService baseRedisService;
-    private final shop.alien.store.dining.service.StoreOrderService storeOrderService;
-    private final shop.alien.mapper.StoreOrderMapper storeOrderMapper;
-    private final shop.alien.store.dining.service.OrderLockService orderLockService;
-
-    @Override
-    public TableDiningStatusVO getTableDiningStatus(Integer tableId) {
-        if (tableId == null) {
-            return new TableDiningStatusVO(null, false, null);
-        }
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table == null) {
-            return new TableDiningStatusVO(tableId, false, null);
-        }
-        // 就餐中(1)、加餐(3) 均视为就餐状态;且需已有就餐人数
-        Integer status = table.getStatus();
-        boolean inDining = (Integer.valueOf(1).equals(status) || Integer.valueOf(3).equals(status))
-                && table.getDinerCount() != null && table.getDinerCount() > 0;
-        Integer dinerCount = inDining ? table.getDinerCount() : null;
-        return new TableDiningStatusVO(tableId, inDining, dinerCount);
-    }
-
-    @Override
-    public DiningPageInfoVO getDiningPageInfo(Integer tableId, Integer dinerCount) {
-        log.info("获取点餐页面信息, tableId={}, dinerCount={}", tableId, dinerCount);
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table == null) {
-            throw new RuntimeException("桌号不存在");
-        }
-
-        StoreInfo storeInfo = storeInfoMapper.selectById(table.getStoreId());
-        if (storeInfo == null) {
-            throw new RuntimeException("门店不存在");
-        }
-
-        // 第一个用户:传入用餐人数时,将餐桌置为就餐中并保存就餐人数
-        if (dinerCount != null && dinerCount > 0) {
-            table.setStatus(1); // 就餐中
-            table.setDinerCount(dinerCount);
-            storeTableMapper.updateById(table);
-            log.info("首客选桌并填写用餐人数, tableId={}, dinerCount={}, 餐桌状态已置为就餐中", tableId, dinerCount);
-        } else {
-            // 第二个及后续用户:若餐桌已就餐中且表内已有就餐人数,直接使用
-            if (Integer.valueOf(1).equals(table.getStatus()) && table.getDinerCount() != null && table.getDinerCount() > 0) {
-                dinerCount = table.getDinerCount();
-                log.info("餐桌已就餐中,使用已保存的就餐人数, tableId={}, dinerCount={}", tableId, dinerCount);
-            } else {
-                // 餐桌空闲且未传就餐人数时要求必填
-                throw new RuntimeException("请选择用餐人数");
-            }
-        }
-
-        DiningPageInfoVO vo = new DiningPageInfoVO();
-        vo.setStoreName(storeInfo.getStoreName());
-        vo.setTableNumber(table.getTableNumber());
-        vo.setDinerCount(dinerCount);
-        vo.setStoreId(table.getStoreId());
-        vo.setTableId(tableId);
-
-        return vo;
-    }
-
-    @Override
-    public List<CuisineListVO> searchCuisines(Integer storeId, String keyword, Integer tableId) {
-        log.info("搜索菜品, storeId={}, keyword={}, tableId={}", storeId, keyword, tableId);
-
-        // 限制搜索关键词长度
-        if (StringUtils.hasText(keyword) && keyword.length() > 10) {
-            keyword = keyword.substring(0, 10);
-        }
-
-        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisine::getStoreId, storeId);
-        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的
-        if (StringUtils.hasText(keyword)) {
-            wrapper.like(StoreCuisine::getName, keyword);
-        }
-        wrapper.orderByDesc(StoreCuisine::getCreatedTime);
-
-        List<StoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
-        return convertToCuisineListVO(cuisines, tableId);
-    }
-
-    @Override
-    public List<CuisineListVO> getCuisinesByCategory(Integer storeId, Integer categoryId, Integer tableId, Integer page, Integer size) {
-        log.info("根据分类获取菜品列表, storeId={}, categoryId={}, tableId={}, page={}, size={}", storeId, categoryId, tableId, page, size);
-
-        if (page == null || page < 1) {
-            page = 1;
-        }
-        if (size == null || size < 1) {
-            size = 12;
-        }
-
-        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisine::getStoreId, storeId);
-        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的
-        if (categoryId != null) {
-            // 这里假设菜品表有category_id字段,如果没有需要关联查询
-            // wrapper.eq(StoreCuisine::getCategoryId, categoryId);
-        }
-        wrapper.orderByDesc(StoreCuisine::getCreatedTime);
-
-        // 分页查询
-        int offset = (page - 1) * size;
-        wrapper.last("LIMIT " + offset + ", " + size);
-
-        List<StoreCuisine> cuisines = storeCuisineMapper.selectList(wrapper);
-        return convertToCuisineListVO(cuisines, tableId);
-    }
-
-    @Override
-    public CuisineDetailVO getCuisineDetail(Integer cuisineId, Integer tableId) {
-        log.info("获取菜品详情, cuisineId={}, tableId={}", cuisineId, tableId);
-
-        StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
-        if (cuisine == null) {
-            throw new RuntimeException("菜品不存在");
-        }
-
-        CuisineDetailVO vo = new CuisineDetailVO();
-        // 手动映射所有字段,确保所有属性都被正确复制
-        vo.setId(cuisine.getId());
-        vo.setStoreId(cuisine.getStoreId());
-        vo.setName(cuisine.getName());
-        vo.setTotalPrice(cuisine.getTotalPrice());
-        vo.setCuisineType(cuisine.getCuisineType());
-        vo.setCategoryIds(cuisine.getCategoryIds());
-        vo.setTags(cuisine.getTags());
-        vo.setDishReview(cuisine.getDishReview());
-        vo.setDescription(cuisine.getDescription());
-        vo.setDetailContent(cuisine.getDetailContent());
-        vo.setImageContent(cuisine.getImageContent());
-        vo.setExtraNote(cuisine.getExtraNote());
-        vo.setNeedReserve(cuisine.getNeedReserve());
-        vo.setReserveRule(cuisine.getReserveRule());
-        vo.setPeopleLimit(cuisine.getPeopleLimit());
-        vo.setUsageRule(cuisine.getUsageRule());
-
-        // 处理图片列表
-        if (StringUtils.hasText(cuisine.getImages())) {
-            List<String> images = Arrays.asList(cuisine.getImages().split(","));
-            vo.setImages(images);
-        } else {
-            vo.setImages(new ArrayList<>());
-        }
-
-        // 计算月售数量
-        vo.setMonthlySales(getMonthlySales(cuisineId));
-
-        // 获取购物车数量
-        CartDTO cart = cartService.getCart(tableId);
-        if (cart.getItems() != null) {
-            Optional<CartItemDTO> cartItem = cart.getItems().stream()
-                    .filter(item -> item.getCuisineId().equals(cuisineId))
-                    .findFirst();
-            vo.setCartQuantity(cartItem.map(CartItemDTO::getQuantity).orElse(0));
-        } else {
-            vo.setCartQuantity(0);
-        }
-
-        // 如果是套餐,获取套餐包含的菜品
-        if (cuisine.getCuisineType() != null && cuisine.getCuisineType() == 2) {
-            LambdaQueryWrapper<StoreCuisineCombo> comboWrapper = new LambdaQueryWrapper<>();
-            comboWrapper.eq(StoreCuisineCombo::getCid, cuisineId);
-            comboWrapper.eq(StoreCuisineCombo::getDeleteFlag, 0);
-            List<StoreCuisineCombo> combos = storeCuisineComboMapper.selectList(comboWrapper);
-
-            List<CuisineComboItemVO> comboItems = combos.stream().map(combo -> {
-                CuisineComboItemVO item = new CuisineComboItemVO();
-                item.setCuisineId(combo.getSid());
-                item.setQuantity(combo.getSnum());
-                item.setCategory(combo.getCategory());
-                // 查询菜品名称
-                StoreCuisine comboCuisine = storeCuisineMapper.selectById(combo.getSid());
-                if (comboCuisine != null) {
-                    item.setCuisineName(comboCuisine.getName());
-                }
-                return item;
-            }).collect(Collectors.toList());
-            vo.setComboItems(comboItems);
-        }
-
-        return vo;
-    }
-
-    @Override
-    public List<AvailableCouponVO> getAvailableCoupons(Integer storeId, Integer userId) {
-        log.info("获取可领取优惠券列表, storeId={}, userId={}", storeId, userId);
-
-        // 查询门店的优惠券
-        LambdaQueryWrapper<LifeDiscountCoupon> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(LifeDiscountCoupon::getStoreId, String.valueOf(storeId));
-        wrapper.eq(LifeDiscountCoupon::getDeleteFlag, 0);
-        wrapper.eq(LifeDiscountCoupon::getGetStatus, 1); // 开启领取
-        wrapper.gt(LifeDiscountCoupon::getSingleQty, 0); // 有库存
-        LocalDate now = LocalDate.now();
-        wrapper.le(LifeDiscountCoupon::getStartDate, now);
-        wrapper.ge(LifeDiscountCoupon::getEndDate, now);
-        wrapper.orderByDesc(LifeDiscountCoupon::getCreatedTime);
-
-        List<LifeDiscountCoupon> coupons = lifeDiscountCouponMapper.selectList(wrapper);
-
-        // 查询用户已领取的优惠券
-        Set<Integer> receivedCouponIds = new HashSet<>();
-        if (userId != null) {
-            LambdaQueryWrapper<LifeDiscountCouponUser> userWrapper = new LambdaQueryWrapper<>();
-            userWrapper.eq(LifeDiscountCouponUser::getUserId, userId);
-            List<LifeDiscountCouponUser> userCoupons = lifeDiscountCouponUserMapper.selectList(userWrapper);
-            receivedCouponIds = userCoupons.stream()
-                    .map(LifeDiscountCouponUser::getCouponId)
-                    .collect(Collectors.toSet());
-        }
-
-        final Set<Integer> finalReceivedCouponIds = receivedCouponIds;
-        return coupons.stream().map(coupon -> {
-            AvailableCouponVO vo = new AvailableCouponVO();
-            vo.setId(coupon.getId());
-            vo.setName(coupon.getName());
-            vo.setNominalValue(coupon.getNominalValue());
-            vo.setMinimumSpendingAmount(coupon.getMinimumSpendingAmount());
-            vo.setEndDate(coupon.getEndDate());
-            vo.setIsReceived(finalReceivedCouponIds.contains(coupon.getId()));
-            vo.setIsAvailable(coupon.getSingleQty() > 0 && coupon.getEndDate().isAfter(now) || coupon.getEndDate().isEqual(now));
-            // 设置优惠券类型和折扣率(如果需要,可以在VO中添加这些字段)
-            return vo;
-        }).collect(Collectors.toList());
-    }
-
-    @Override
-    public boolean receiveCoupon(Integer couponId, Integer userId) {
-        log.info("领取优惠券, couponId={}, userId={}", couponId, userId);
-
-        LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(couponId);
-        if (coupon == null) {
-            throw new RuntimeException("优惠券不存在");
-        }
-
-        // 检查是否已领取
-        LambdaQueryWrapper<LifeDiscountCouponUser> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(LifeDiscountCouponUser::getUserId, userId);
-        wrapper.eq(LifeDiscountCouponUser::getCouponId, couponId);
-        LifeDiscountCouponUser existing = lifeDiscountCouponUserMapper.selectOne(wrapper);
-        if (existing != null) {
-            throw new RuntimeException("您已领取过该优惠券");
-        }
-
-        // 检查库存
-        if (coupon.getSingleQty() == null || coupon.getSingleQty() <= 0) {
-            throw new RuntimeException("优惠券已领完");
-        }
-
-        // 创建用户优惠券记录
-        LifeDiscountCouponUser userCoupon = new LifeDiscountCouponUser();
-        userCoupon.setUserId(userId);
-        userCoupon.setCouponId(couponId);
-        userCoupon.setReceiveTime(new Date());
-        userCoupon.setStatus(0); // 待使用
-        // 注意:如果需要设置 issueSource,需要确保 LifeDiscountCouponUser 实体类已包含该字段
-        if (coupon.getSpecifiedDay() != null && !coupon.getSpecifiedDay().isEmpty()) {
-            try {
-                int days = Integer.parseInt(coupon.getSpecifiedDay());
-                LocalDate expirationDate = LocalDate.now().plusDays(days);
-                userCoupon.setExpirationTime(expirationDate);
-            } catch (NumberFormatException e) {
-                userCoupon.setExpirationTime(coupon.getEndDate());
-            }
-        } else {
-            userCoupon.setExpirationTime(coupon.getEndDate());
-        }
-        lifeDiscountCouponUserMapper.insert(userCoupon);
-
-        // 更新库存
-        coupon.setSingleQty(coupon.getSingleQty() - 1);
-        lifeDiscountCouponMapper.updateById(coupon);
-
-        return true;
-    }
-
-    @Override
-    public OrderConfirmVO getOrderConfirmInfo(Integer tableId, Integer dinerCount, Integer userId) {
-        log.info("获取订单确认页面信息, tableId={}, dinerCount={}, userId={}", tableId, dinerCount, userId);
-
-        // 获取点餐页面信息(就餐中且未传人数时,内部会使用桌台已保存的就餐人数)
-        DiningPageInfoVO pageInfo = getDiningPageInfo(tableId, dinerCount);
-        int effectiveDinerCount = pageInfo.getDinerCount() != null && pageInfo.getDinerCount() > 0
-                ? pageInfo.getDinerCount() : (dinerCount != null ? dinerCount : 0);
-
-        // 获取购物车
-        CartDTO cart = cartService.getCart(tableId);
-
-        // 为购物车项补全菜品标签(购物车从 DB 加载时可能无 tags)
-        List<CartItemDTO> items = cart.getItems();
-        if (items != null && !items.isEmpty()) {
-            Set<Integer> cuisineIds = items.stream()
-                    .map(CartItemDTO::getCuisineId)
-                    .filter(Objects::nonNull)
-                    .collect(Collectors.toSet());
-            if (!cuisineIds.isEmpty()) {
-                List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
-                Map<Integer, String> tagsMap = new HashMap<>();
-                if (cuisines != null) {
-                    for (StoreCuisine c : cuisines) {
-                        if (c.getTags() != null) {
-                            tagsMap.put(c.getId(), c.getTags());
-                        }
-                    }
-                }
-                for (CartItemDTO item : items) {
-                    if (item.getCuisineId() != null && item.getTags() == null) {
-                        item.setTags(tagsMap.get(item.getCuisineId()));
-                    }
-                }
-            }
-        }
-
-        // 检查订单锁定
-        Integer lockUserId = orderLockService.checkOrderLock(tableId);
-        boolean isLocked = lockUserId != null && !lockUserId.equals(userId);
-
-        OrderConfirmVO vo = new OrderConfirmVO();
-        vo.setStoreName(pageInfo.getStoreName());
-        vo.setTableNumber(pageInfo.getTableNumber());
-        vo.setDinerCount(pageInfo.getDinerCount() != null ? pageInfo.getDinerCount() : dinerCount);
-        // 联系电话和备注由前端传入,这里不设置默认值
-        vo.setItems(items != null ? items : cart.getItems());
-        vo.setTotalAmount(cart.getTotalAmount());
-        vo.setIsLocked(isLocked);
-        vo.setLockUserId(lockUserId);
-
-        // 计算餐具费(默认1元/人)
-        BigDecimal tablewareUnitPrice = new BigDecimal("1.00");
-        BigDecimal tablewareFee = BigDecimal.ZERO;
-        if (effectiveDinerCount > 0) {
-            tablewareFee = tablewareUnitPrice.multiply(BigDecimal.valueOf(effectiveDinerCount));
-        }
-        vo.setTablewareFee(tablewareFee);
-        vo.setTablewareUnitPrice(tablewareUnitPrice);
-
-        // 自动匹配最优惠的优惠券
-        List<AvailableCouponVO> availableCoupons = new ArrayList<>();
-        if (userId != null && cart.getTotalAmount().compareTo(BigDecimal.ZERO) > 0) {
-            availableCoupons = getAvailableCoupons(pageInfo.getStoreId(), userId);
-            // 过滤出可用的优惠券(已领取且满足最低消费)
-            BigDecimal totalWithTableware = cart.getTotalAmount().add(tablewareFee);
-            // 需要查询优惠券详情来计算实际优惠金额(用于排序)
-            List<Integer> couponIds = availableCoupons.stream()
-                    .filter(c -> c.getIsReceived() && c.getIsAvailable())
-                    .filter(c -> totalWithTableware.compareTo(c.getMinimumSpendingAmount() != null ? c.getMinimumSpendingAmount() : BigDecimal.ZERO) >= 0)
-                    .map(AvailableCouponVO::getId)
-                    .collect(Collectors.toList());
-            
-            // 查询优惠券详情用于计算实际优惠金额
-            Map<Integer, LifeDiscountCoupon> couponMap = new HashMap<>();
-            if (!couponIds.isEmpty()) {
-                List<LifeDiscountCoupon> couponDetails = lifeDiscountCouponMapper.selectBatchIds(couponIds);
-                couponMap = couponDetails.stream().collect(Collectors.toMap(LifeDiscountCoupon::getId, c -> c));
-            }
-            
-            final BigDecimal finalTotal = totalWithTableware;
-            final Map<Integer, LifeDiscountCoupon> finalCouponMap = couponMap;
-            List<AvailableCouponVO> usableCoupons = availableCoupons.stream()
-                    .filter(c -> c.getIsReceived() && c.getIsAvailable())
-                    .filter(c -> totalWithTableware.compareTo(c.getMinimumSpendingAmount() != null ? c.getMinimumSpendingAmount() : BigDecimal.ZERO) >= 0)
-                    .sorted((a, b) -> {
-                        // 根据实际优惠金额排序(考虑折扣券)
-                        BigDecimal discountA = calculateDiscountAmountForVO(a, finalCouponMap, finalTotal);
-                        BigDecimal discountB = calculateDiscountAmountForVO(b, finalCouponMap, finalTotal);
-                        return discountB.compareTo(discountA); // 降序排列
-                    })
-                    .collect(Collectors.toList());
-
-            if (!usableCoupons.isEmpty()) {
-                AvailableCouponVO bestCoupon = usableCoupons.get(0);
-                vo.setCouponId(bestCoupon.getId());
-                vo.setCouponName(bestCoupon.getName());
-                // 根据优惠券类型计算优惠金额
-                // 需要查询优惠券详情来计算折扣券的优惠金额
-                LifeDiscountCoupon couponDetail = lifeDiscountCouponMapper.selectById(bestCoupon.getId());
-                BigDecimal discountAmount = calculateDiscountAmount(couponDetail, cart.getTotalAmount().add(tablewareFee));
-                BigDecimal totalAmount = cart.getTotalAmount().add(tablewareFee);
-                vo.setDiscountAmount(discountAmount);
-                vo.setPayAmount(totalAmount.subtract(discountAmount));
-            } else {
-                vo.setPayAmount(cart.getTotalAmount().add(tablewareFee));
-            }
-        } else {
-            vo.setPayAmount(cart.getTotalAmount().add(tablewareFee));
-        }
-        vo.setAvailableCoupons(availableCoupons);
-
-        return vo;
-    }
-
-    @Override
-    public boolean lockOrder(Integer tableId, Integer userId) {
-        return orderLockService.lockOrder(tableId, userId);
-    }
-
-    @Override
-    public void unlockOrder(Integer tableId, Integer userId) {
-        orderLockService.unlockOrder(tableId, userId);
-    }
-
-    @Override
-    public Integer checkOrderLock(Integer tableId) {
-        return orderLockService.checkOrderLock(tableId);
-    }
-
-    /**
-     * 转换为菜品列表VO
-     */
-    private List<CuisineListVO> convertToCuisineListVO(List<StoreCuisine> cuisines, Integer tableId) {
-        // 获取购物车
-        CartDTO cart = cartService.getCart(tableId);
-        Map<Integer, Integer> cartQuantityMap = new HashMap<>();
-        if (cart.getItems() != null) {
-            cartQuantityMap = cart.getItems().stream()
-                    .collect(Collectors.toMap(CartItemDTO::getCuisineId, CartItemDTO::getQuantity));
-        }
-
-        // 批量查询月售数量
-        Map<Integer, Integer> monthlySalesMap = new HashMap<>();
-        for (StoreCuisine cuisine : cuisines) {
-            monthlySalesMap.put(cuisine.getId(), getMonthlySales(cuisine.getId()));
-        }
-
-        final Map<Integer, Integer> finalCartQuantityMap = cartQuantityMap;
-        final Map<Integer, Integer> finalMonthlySalesMap = monthlySalesMap;
-
-        return cuisines.stream().map(cuisine -> {
-            CuisineListVO vo = new CuisineListVO();
-            BeanUtils.copyProperties(cuisine, vo);
-            vo.setPrice(cuisine.getTotalPrice());
-
-            // 处理首张图片
-            if (StringUtils.hasText(cuisine.getImages())) {
-                String[] images = cuisine.getImages().split(",");
-                vo.setFirstImage(images.length > 0 ? images[0] : null);
-            }
-
-            // 设置购物车数量
-            vo.setCartQuantity(finalCartQuantityMap.getOrDefault(cuisine.getId(), 0));
-
-            // 设置月售数量
-            vo.setMonthlySales(finalMonthlySalesMap.getOrDefault(cuisine.getId(), 0));
-
-            return vo;
-        }).collect(Collectors.toList());
-    }
-
-    /**
-     * 获取菜品月售数量(当月1日至当前日期)
-     */
-    private Integer getMonthlySales(Integer cuisineId) {
-        try {
-            // 计算当月1日
-            Calendar calendar = Calendar.getInstance();
-            calendar.set(Calendar.DAY_OF_MONTH, 1);
-            calendar.set(Calendar.HOUR_OF_DAY, 0);
-            calendar.set(Calendar.MINUTE, 0);
-            calendar.set(Calendar.SECOND, 0);
-            calendar.set(Calendar.MILLISECOND, 0);
-            Date monthStart = calendar.getTime();
-
-            // 查询订单明细中该菜品的销售数量
-            LambdaQueryWrapper<StoreOrderDetail> wrapper = new LambdaQueryWrapper<>();
-            wrapper.eq(StoreOrderDetail::getCuisineId, cuisineId);
-            wrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-            wrapper.ge(StoreOrderDetail::getCreatedTime, monthStart);
-            // 只统计已支付的订单
-            wrapper.inSql(StoreOrderDetail::getOrderId,
-                    "SELECT id FROM store_order WHERE pay_status = 1 AND delete_flag = 0");
-
-            List<StoreOrderDetail> details = storeOrderDetailMapper.selectList(wrapper);
-            return details.stream().mapToInt(StoreOrderDetail::getQuantity).sum();
-        } catch (Exception e) {
-            log.error("获取月售数量失败, cuisineId={}", cuisineId, e);
-            return 0;
-        }
-    }
-
-    @Override
-    public shop.alien.entity.store.vo.OrderSettlementVO getOrderSettlementInfo(Integer orderId, Integer userId) {
-        log.info("获取订单结算确认页面信息, orderId={}, userId={}", orderId, userId);
-
-        // 查询订单
-        shop.alien.entity.store.StoreOrder order = storeOrderService.getOrderById(orderId);
-        if (order == null) {
-            throw new RuntimeException("订单不存在");
-        }
-
-        // 查询订单明细
-        LambdaQueryWrapper<shop.alien.entity.store.StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-        detailWrapper.eq(shop.alien.entity.store.StoreOrderDetail::getOrderId, orderId);
-        detailWrapper.eq(shop.alien.entity.store.StoreOrderDetail::getDeleteFlag, 0);
-        detailWrapper.orderByDesc(shop.alien.entity.store.StoreOrderDetail::getCreatedTime);
-        List<shop.alien.entity.store.StoreOrderDetail> details = storeOrderDetailMapper.selectList(detailWrapper);
-
-        // 批量查询菜品标签
-        Set<Integer> cuisineIds = details.stream()
-                .map(shop.alien.entity.store.StoreOrderDetail::getCuisineId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, String> cuisineIdToTags = new HashMap<>();
-        if (!cuisineIds.isEmpty()) {
-            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
-            if (cuisines != null) {
-                for (StoreCuisine c : cuisines) {
-                    if (c.getTags() != null) {
-                        cuisineIdToTags.put(c.getId(), c.getTags());
-                    }
-                }
-            }
-        }
-
-        // 转换为CartItemDTO(含菜品标签)
-        Map<Integer, String> finalTagsMap = cuisineIdToTags;
-        List<shop.alien.entity.store.dto.CartItemDTO> items = details.stream().map(detail -> {
-            shop.alien.entity.store.dto.CartItemDTO item = new shop.alien.entity.store.dto.CartItemDTO();
-            item.setCuisineId(detail.getCuisineId());
-            item.setCuisineName(detail.getCuisineName());
-            item.setCuisineType(detail.getCuisineType());
-            item.setCuisineImage(detail.getCuisineImage());
-            item.setUnitPrice(detail.getUnitPrice());
-            item.setQuantity(detail.getQuantity());
-            item.setSubtotalAmount(detail.getSubtotalAmount());
-            item.setAddUserId(detail.getAddUserId());
-            item.setAddUserPhone(detail.getAddUserPhone());
-            item.setRemark(detail.getRemark());
-            item.setTags(detail.getCuisineId() != null ? finalTagsMap.get(detail.getCuisineId()) : null);
-            return item;
-        }).collect(Collectors.toList());
-
-        // 查询门店信息
-        shop.alien.entity.store.StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
-
-        // 检查结算锁定
-        Integer lockUserId = orderLockService.checkSettlementLock(orderId);
-        boolean isLocked = lockUserId != null && !lockUserId.equals(userId);
-
-        shop.alien.entity.store.vo.OrderSettlementVO vo = new shop.alien.entity.store.vo.OrderSettlementVO();
-        vo.setOrderId(order.getId());
-        vo.setOrderNo(order.getOrderNo());
-        vo.setStoreName(storeInfo != null ? storeInfo.getStoreName() : null);
-        vo.setTableNumber(order.getTableNumber());
-        vo.setDinerCount(order.getDinerCount());
-        vo.setContactPhone(order.getContactPhone());
-        vo.setRemark(order.getRemark());
-        vo.setItems(items);
-        vo.setTotalAmount(order.getTotalAmount());
-        vo.setTablewareFee(order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO);
-        vo.setCouponId(order.getCouponId());
-        vo.setDiscountAmount(order.getDiscountAmount() != null ? order.getDiscountAmount() : BigDecimal.ZERO);
-        vo.setPayAmount(order.getPayAmount());
-        vo.setIsLocked(isLocked);
-        vo.setLockUserId(lockUserId);
-
-        // 查询优惠券名称
-        if (order.getCouponId() != null) {
-            shop.alien.entity.store.LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
-            if (coupon != null) {
-                vo.setCouponName(coupon.getName());
-            }
-        }
-
-        return vo;
-    }
-
-    @Override
-    public boolean lockSettlement(Integer orderId, Integer userId) {
-        return orderLockService.lockSettlement(orderId, userId);
-    }
-
-    @Override
-    public void unlockSettlement(Integer orderId, Integer userId) {
-        orderLockService.unlockSettlement(orderId, userId);
-    }
-
-    @Override
-    public Integer checkSettlementLock(Integer orderId) {
-        return orderLockService.checkSettlementLock(orderId);
-    }
-
-    /**
-     * 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
-     *
-     * @param coupon           优惠券对象
-     * @param totalWithTableware 订单总金额(含餐具费)
-     * @return 优惠金额
-     */
-    private BigDecimal calculateDiscountAmount(LifeDiscountCoupon coupon, BigDecimal totalWithTableware) {
-        if (coupon == null || totalWithTableware == null || totalWithTableware.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-
-        Integer couponType = coupon.getCouponType();
-        BigDecimal discountAmount = BigDecimal.ZERO;
-
-        if (couponType != null && couponType == 2) {
-            // 折扣券:根据折扣率计算优惠金额
-            // discountRate: 0-100,例如80表示8折,优惠金额 = 订单金额 * (100 - discountRate) / 100
-            BigDecimal discountRate = coupon.getDiscountRate();
-            if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 && discountRate.compareTo(new BigDecimal(100)) <= 0) {
-                // 计算折扣后的金额
-                BigDecimal discountedAmount = totalWithTableware.multiply(discountRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
-                // 优惠金额 = 原价 - 折扣后价格
-                discountAmount = totalWithTableware.subtract(discountedAmount);
-            }
-        } else {
-            // 满减券(默认或couponType=1):使用nominalValue
-            discountAmount = coupon.getNominalValue();
-            if (discountAmount == null) {
-                discountAmount = BigDecimal.ZERO;
-            }
-            // 优惠金额不能超过订单总金额
-            if (discountAmount.compareTo(totalWithTableware) > 0) {
-                discountAmount = totalWithTableware;
-            }
-        }
-
-        return discountAmount;
-    }
-
-    /**
-     * 为VO计算优惠金额(用于排序)
-     *
-     * @param vo          优惠券VO
-     * @param couponMap   优惠券详情Map
-     * @param totalAmount 订单总金额
-     * @return 优惠金额
-     */
-    private BigDecimal calculateDiscountAmountForVO(AvailableCouponVO vo, Map<Integer, LifeDiscountCoupon> couponMap, BigDecimal totalAmount) {
-        if (vo == null || totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-
-        LifeDiscountCoupon coupon = couponMap.get(vo.getId());
-        if (coupon == null) {
-            // 如果没有详情,使用nominalValue作为默认值
-            return vo.getNominalValue() != null ? vo.getNominalValue() : BigDecimal.ZERO;
-        }
-
-        return calculateDiscountAmount(coupon, totalAmount);
-    }
-}

+ 0 - 306
alien-store/src/main/java/shop/alien/store/dining/service/impl/DiningUserServiceImpl.java

@@ -1,306 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import shop.alien.store.dining.dto.ChangePhoneDto;
-import shop.alien.store.dining.dto.UserProfileUpdateDto;
-import shop.alien.store.dining.feign.AlienStoreFeign;
-import shop.alien.store.dining.service.DiningUserService;
-import shop.alien.store.dining.util.TokenUtil;
-import shop.alien.entity.result.R;
-import shop.alien.store.dining.vo.DiningUserVo;
-import shop.alien.store.dining.vo.TokenVerifyVo;
-import shop.alien.entity.store.LifeUser;
-import shop.alien.mapper.LifeUserMapper;
-import shop.alien.util.common.JwtUtil;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.MalformedJwtException;
-import io.jsonwebtoken.SignatureException;
-
-import java.util.Date;
-
-/**
- * 点餐用户服务(与 APP 共用登录:前端走统一登录接口获取 JWT,此处不再提供微信小程序 code 登录)
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class DiningUserServiceImpl implements DiningUserService {
-
-    private final LifeUserMapper lifeUserMapper;
-    private final AlienStoreFeign alienStoreFeign;
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public DiningUserVo updateProfile(UserProfileUpdateDto dto) {
-        LifeUser user = lifeUserMapper.selectById(dto.getUserId().intValue());
-        if (user == null) {
-            log.warn("更新个人信息失败:用户不存在, userId={}", dto.getUserId());
-            return null;
-        }
-
-        Integer currentUserId = TokenUtil.getCurrentUserId();
-        if (currentUserId == null) {
-            currentUserId = dto.getUserId().intValue();
-        }
-
-        LambdaUpdateWrapper<LifeUser> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(LifeUser::getId, dto.getUserId().intValue());
-
-        if (StringUtils.isNotBlank(dto.getNickName())) {
-            updateWrapper.set(LifeUser::getUserName, dto.getNickName());
-        }
-        if (StringUtils.isNotBlank(dto.getAvatarUrl())) {
-            updateWrapper.set(LifeUser::getUserImage, dto.getAvatarUrl());
-        }
-        if (StringUtils.isNotBlank(dto.getGender())) {
-            updateWrapper.set(LifeUser::getUserSex, dto.getGender());
-        }
-        if (dto.getBirthday() != null) {
-            updateWrapper.set(LifeUser::getUserBirthday, dto.getBirthday());
-        }
-        if (StringUtils.isNotBlank(dto.getRealName())) {
-            updateWrapper.set(LifeUser::getRealName, dto.getRealName());
-        }
-        if (StringUtils.isNotBlank(dto.getProvince())) {
-            updateWrapper.set(LifeUser::getProvince, dto.getProvince());
-        }
-        if (StringUtils.isNotBlank(dto.getCity())) {
-            updateWrapper.set(LifeUser::getCity, dto.getCity());
-        }
-        if (StringUtils.isNotBlank(dto.getDistrict())) {
-            updateWrapper.set(LifeUser::getDistrict, dto.getDistrict());
-        }
-        if (StringUtils.isNotBlank(dto.getAddress())) {
-            updateWrapper.set(LifeUser::getAddress, dto.getAddress());
-        }
-        if (StringUtils.isNotBlank(dto.getJianjie())) {
-            updateWrapper.set(LifeUser::getJianjie, dto.getJianjie());
-        }
-
-        updateWrapper.set(LifeUser::getUpdatedTime, new Date());
-        updateWrapper.set(LifeUser::getUpdatedUserId, currentUserId);
-
-        int result = lifeUserMapper.update(null, updateWrapper);
-        if (result != 1) {
-            log.error("更新用户信息失败, userId={}", dto.getUserId());
-            return null;
-        }
-        log.info("用户信息更新成功, userId={}, updatedUserId={}", dto.getUserId(), currentUserId);
-
-        LifeUser updatedUser = lifeUserMapper.selectById(dto.getUserId().intValue());
-        if (updatedUser == null) {
-            log.error("更新后查询用户信息失败, userId={}", dto.getUserId());
-            return null;
-        }
-
-        return buildDiningUserVo(updatedUser);
-    }
-
-    @Override
-    public DiningUserVo getUserInfo(Long userId) {
-        LifeUser user = lifeUserMapper.selectById(userId.intValue());
-        if (user == null) {
-            log.warn("获取用户信息失败:用户不存在, userId={}", userId);
-            return null;
-        }
-
-        if (user.getIsBanned() != null && user.getIsBanned() == 1) {
-            log.warn("用户已被封禁: userId={}", userId);
-            return null;
-        }
-        if (user.getLogoutFlag() != null && user.getLogoutFlag() == 1) {
-            log.warn("用户已注销: userId={}", userId);
-            return null;
-        }
-
-        return buildDiningUserVo(user);
-    }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public DiningUserVo changePhone(ChangePhoneDto dto) {
-        String newPhone = dto.getNewPhone().trim();
-        String codeStr = dto.getCode().trim();
-
-        int codeInt;
-        try {
-            codeInt = Integer.parseInt(codeStr);
-        } catch (NumberFormatException e) {
-            log.warn("更换手机号失败:验证码格式错误, userId={}, newPhone={}", dto.getUserId(), newPhone);
-            return null;
-        }
-        R<?> checkRes = alienStoreFeign.checkSmsCode(newPhone, 0, 3, codeInt);
-        if (!R.isSuccess(checkRes)) {
-            log.warn("更换手机号失败:验证码错误或已过期, userId={}, newPhone={}", dto.getUserId(), newPhone);
-            return null;
-        }
-
-        LifeUser user = lifeUserMapper.selectById(dto.getUserId().intValue());
-        if (user == null) {
-            log.warn("更换手机号失败:用户不存在, userId={}", dto.getUserId());
-            return null;
-        }
-        if (user.getIsBanned() != null && user.getIsBanned() == 1) {
-            log.warn("更换手机号失败:用户已被封禁, userId={}", dto.getUserId());
-            return null;
-        }
-        if (user.getLogoutFlag() != null && user.getLogoutFlag() == 1) {
-            log.warn("更换手机号失败:用户已注销, userId={}", dto.getUserId());
-            return null;
-        }
-
-        if (newPhone.equals(user.getUserPhone())) {
-            log.info("新手机号与当前相同,无需更换, userId={}", dto.getUserId());
-            return buildDiningUserVo(user);
-        }
-
-        LambdaQueryWrapper<LifeUser> q = new LambdaQueryWrapper<>();
-        q.eq(LifeUser::getUserPhone, newPhone);
-        LifeUser existing = lifeUserMapper.selectOne(q);
-        if (existing != null && !existing.getId().equals(user.getId())) {
-            log.warn("更换手机号失败:新手机号已被其他用户使用, newPhone={}", newPhone);
-            return null;
-        }
-
-        user.setUserPhone(newPhone);
-        user.setUpdatedTime(new Date());
-        int n = lifeUserMapper.updateById(user);
-        if (n != 1) {
-            log.error("更换手机号失败:更新数据库异常, userId={}", dto.getUserId());
-            return null;
-        }
-
-        log.info("更换手机号成功, userId={}, newPhone={}", dto.getUserId(), newPhone);
-        return buildDiningUserVo(user);
-    }
-
-    /**
-     * 校验 APP 下发的 JWT:验签、过期时间与用户状态;不依赖小程序 Redis session。
-     */
-    @Override
-    public TokenVerifyVo verifyToken(String token) {
-        TokenVerifyVo verifyVo = new TokenVerifyVo();
-        verifyVo.setValid(false);
-
-        if (StringUtils.isBlank(token)) {
-            verifyVo.setReason("Token 不能为空");
-            return verifyVo;
-        }
-
-        token = token.trim();
-        if (token.length() > 7 && token.substring(0, 7).equalsIgnoreCase("Bearer ")) {
-            token = token.substring(7).trim();
-        }
-
-        if (StringUtils.isBlank(token)) {
-            verifyVo.setReason("Token 去除前缀后为空");
-            return verifyVo;
-        }
-
-        try {
-            Claims claims = JwtUtil.parseJWT(token);
-
-            Date expiration = claims.getExpiration();
-            if (expiration != null && expiration.before(new Date())) {
-                verifyVo.setReason("Token 已过期");
-                verifyVo.setExpirationTime(expiration);
-                return verifyVo;
-            }
-
-            Object subObj = claims.get("sub");
-            if (subObj == null) {
-                verifyVo.setReason("Token 缺少主体信息");
-                return verifyVo;
-            }
-
-            JSONObject tokenInfo = JSONObject.parseObject(subObj.toString());
-            String userIdStr = tokenInfo.getString("userId");
-            String phone = tokenInfo.getString("phone");
-            String userName = tokenInfo.getString("userName");
-            String openid = tokenInfo.getString("openid");
-
-            if (StringUtils.isNotBlank(userIdStr)) {
-                try {
-                    Integer userId = Integer.parseInt(userIdStr);
-                    LifeUser user = lifeUserMapper.selectById(userId);
-                    if (user == null) {
-                        verifyVo.setReason("用户不存在");
-                        return verifyVo;
-                    }
-                    if (user.getIsBanned() != null && user.getIsBanned() == 1) {
-                        verifyVo.setReason("用户已被封禁");
-                        return verifyVo;
-                    }
-                    if (user.getLogoutFlag() != null && user.getLogoutFlag() == 1) {
-                        verifyVo.setReason("用户已注销");
-                        return verifyVo;
-                    }
-                } catch (NumberFormatException e) {
-                    log.warn("Token 中的 userId 格式错误: {}", userIdStr);
-                    verifyVo.setReason("userId 格式错误");
-                    return verifyVo;
-                }
-            }
-
-            verifyVo.setValid(true);
-            if (StringUtils.isNotBlank(userIdStr)) {
-                try {
-                    verifyVo.setUserId(Long.parseLong(userIdStr));
-                } catch (NumberFormatException ignored) {
-                    // ignore
-                }
-            }
-            verifyVo.setPhone(phone);
-            verifyVo.setNickName(userName);
-            verifyVo.setOpenid(openid);
-            verifyVo.setExpirationTime(expiration);
-
-            log.debug("Token 校验通过: userId={}", userIdStr);
-            return verifyVo;
-
-        } catch (ExpiredJwtException e) {
-            log.warn("Token 已过期: {}", e.getMessage());
-            verifyVo.setReason("Token 已过期: " + e.getMessage());
-            return verifyVo;
-        } catch (MalformedJwtException e) {
-            log.warn("Token 格式错误: {}", e.getMessage());
-            verifyVo.setReason("Token 格式错误: " + e.getMessage());
-            return verifyVo;
-        } catch (SignatureException e) {
-            log.warn("Token 签名验证失败: {}", e.getMessage());
-            verifyVo.setReason("Token 签名验证失败: " + e.getMessage());
-            return verifyVo;
-        } catch (Exception e) {
-            log.error("Token 验证异常: {}", e.getMessage(), e);
-            verifyVo.setReason("Token 验证异常: " + e.getMessage());
-            return verifyVo;
-        }
-    }
-
-    private DiningUserVo buildDiningUserVo(LifeUser user) {
-        DiningUserVo diningUserVo = new DiningUserVo();
-        diningUserVo.setId(user.getId().longValue());
-        diningUserVo.setPhone(user.getUserPhone());
-        diningUserVo.setNickName(user.getUserName());
-        diningUserVo.setAvatarUrl(user.getUserImage());
-        diningUserVo.setStatus(0);
-        diningUserVo.setCreatedTime(user.getCreatedTime());
-        diningUserVo.setGender(user.getUserSex());
-        diningUserVo.setBirthday(user.getUserBirthday());
-        diningUserVo.setRealName(user.getRealName());
-        diningUserVo.setProvince(user.getProvince());
-        diningUserVo.setCity(user.getCity());
-        diningUserVo.setDistrict(user.getDistrict());
-        diningUserVo.setAddress(user.getAddress());
-        diningUserVo.setJianjie(user.getJianjie());
-        return diningUserVo;
-    }
-}

+ 0 - 118
alien-store/src/main/java/shop/alien/store/dining/service/impl/OrderLockServiceImpl.java

@@ -1,118 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.dining.service.OrderLockService;
-
-/**
- * 订单锁定服务实现类
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class OrderLockServiceImpl implements OrderLockService {
-
-    private static final String ORDER_LOCK_KEY_PREFIX = "order:lock:table:";
-    private static final String SETTLEMENT_LOCK_KEY_PREFIX = "settlement:lock:order:";
-    private static final int ORDER_LOCK_EXPIRE_SECONDS = 300; // 5分钟过期
-
-    private final BaseRedisService baseRedisService;
-
-    @Override
-    public boolean lockOrder(Integer tableId, Integer userId) {
-        log.info("锁定订单, tableId={}, userId={}", tableId, userId);
-
-        String lockKey = ORDER_LOCK_KEY_PREFIX + tableId;
-        String existingLock = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(existingLock)) {
-            // 已锁定,检查是否是当前用户
-            if (existingLock.equals(String.valueOf(userId))) {
-                // 刷新过期时间
-                baseRedisService.setString(lockKey, existingLock, (long) ORDER_LOCK_EXPIRE_SECONDS);
-                return true;
-            } else {
-                // 被其他用户锁定
-                return false;
-            }
-        }
-
-        // 设置锁定
-        baseRedisService.setString(lockKey, String.valueOf(userId), (long) ORDER_LOCK_EXPIRE_SECONDS);
-        return true;
-    }
-
-    @Override
-    public void unlockOrder(Integer tableId, Integer userId) {
-        log.info("解锁订单, tableId={}, userId={}", tableId, userId);
-
-        String lockKey = ORDER_LOCK_KEY_PREFIX + tableId;
-        String existingLock = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(existingLock) && existingLock.equals(String.valueOf(userId))) {
-            baseRedisService.delete(lockKey);
-        }
-    }
-
-    @Override
-    public Integer checkOrderLock(Integer tableId) {
-        String lockKey = ORDER_LOCK_KEY_PREFIX + tableId;
-        String lockUserId = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(lockUserId)) {
-            try {
-                return Integer.parseInt(lockUserId);
-            } catch (NumberFormatException e) {
-                return null;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public boolean lockSettlement(Integer orderId, Integer userId) {
-        log.info("锁定订单结算, orderId={}, userId={}", orderId, userId);
-
-        String lockKey = SETTLEMENT_LOCK_KEY_PREFIX + orderId;
-        String existingLock = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(existingLock)) {
-            if (existingLock.equals(String.valueOf(userId))) {
-                baseRedisService.setString(lockKey, existingLock, (long) ORDER_LOCK_EXPIRE_SECONDS);
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        baseRedisService.setString(lockKey, String.valueOf(userId), (long) ORDER_LOCK_EXPIRE_SECONDS);
-        return true;
-    }
-
-    @Override
-    public void unlockSettlement(Integer orderId, Integer userId) {
-        log.info("解锁订单结算, orderId={}, userId={}", orderId, userId);
-
-        String lockKey = SETTLEMENT_LOCK_KEY_PREFIX + orderId;
-        String existingLock = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(existingLock) && existingLock.equals(String.valueOf(userId))) {
-            baseRedisService.delete(lockKey);
-        }
-    }
-
-    @Override
-    public Integer checkSettlementLock(Integer orderId) {
-        String lockKey = SETTLEMENT_LOCK_KEY_PREFIX + orderId;
-        String lockUserId = baseRedisService.getString(lockKey);
-        if (StringUtils.hasText(lockUserId)) {
-            try {
-                return Integer.parseInt(lockUserId);
-            } catch (NumberFormatException e) {
-                return null;
-            }
-        }
-        return null;
-    }
-}

+ 0 - 180
alien-store/src/main/java/shop/alien/store/dining/service/impl/SseServiceImpl.java

@@ -1,180 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.alibaba.fastjson2.JSON;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
-
-import java.io.IOException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-/**
- * SSE推送服务实现类
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Service
-public class SseServiceImpl implements shop.alien.store.dining.service.SseService {
-
-    // 存储每个桌号的SSE连接,一个桌号可以有多个连接(多个用户)
-    private final ConcurrentHashMap<Integer, ConcurrentHashMap<String, SseEmitter>> connections = new ConcurrentHashMap<>();
-
-    // 定时任务执行器,用于发送心跳
-    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
-
-    @Override
-    public SseEmitter createConnection(Integer tableId) {
-        log.info("创建SSE连接, tableId={}", tableId);
-
-        // 创建SSE连接,设置超时时间为30分钟
-        SseEmitter emitter = new SseEmitter(30 * 60 * 1000L);
-
-        // 生成连接ID
-        String connectionId = "conn_" + System.currentTimeMillis() + "_" + Thread.currentThread().getId();
-
-        // 存储连接
-        connections.computeIfAbsent(tableId, k -> new ConcurrentHashMap<>()).put(connectionId, emitter);
-
-        // 设置完成和超时回调
-        emitter.onCompletion(() -> {
-            log.info("SSE连接完成, tableId={}, connectionId={}", tableId, connectionId);
-            removeConnection(tableId, connectionId);
-        });
-
-        emitter.onTimeout(() -> {
-            log.info("SSE连接超时, tableId={}, connectionId={}", tableId, connectionId);
-            removeConnection(tableId, connectionId);
-        });
-
-        emitter.onError((ex) -> {
-            if (isClientDisconnect(ex)) {
-                log.info("SSE客户端已断开, tableId={}, connectionId={}", tableId, connectionId);
-            } else {
-                log.error("SSE连接错误, tableId={}, connectionId={}, error={}", tableId, connectionId, ex.getMessage(), ex);
-            }
-            removeConnection(tableId, connectionId);
-        });
-
-        // 发送初始连接成功消息
-        try {
-            emitter.send(SseEmitter.event()
-                    .name("connected")
-                    .data("连接成功"));
-        } catch (IOException e) {
-            log.error("发送初始消息失败, tableId={}, connectionId={}", tableId, connectionId, e);
-            removeConnection(tableId, connectionId);
-            return null;
-        }
-
-        // 启动心跳任务
-        startHeartbeat(tableId, connectionId, emitter);
-
-        return emitter;
-    }
-
-    @Override
-    public void pushCartUpdate(Integer tableId, Object message) {
-        log.info("推送购物车更新, tableId={}", tableId);
-        ConcurrentHashMap<String, SseEmitter> tableConnections = connections.get(tableId);
-        if (tableConnections == null || tableConnections.isEmpty()) {
-            log.warn("该桌号没有SSE连接, tableId={}", tableId);
-            return;
-        }
-
-        String messageJson = JSON.toJSONString(message);
-        tableConnections.forEach((connectionId, emitter) -> {
-            try {
-                emitter.send(SseEmitter.event()
-                        .name("cart_update")
-                        .data(messageJson));
-                log.info("推送购物车更新成功, tableId={}, connectionId={}", tableId, connectionId);
-            } catch (IOException e) {
-                if (isClientDisconnect(e)) {
-                    log.debug("推送时客户端已断开, tableId={}, connectionId={}", tableId, connectionId);
-                } else {
-                    log.error("推送购物车更新失败, tableId={}, connectionId={}, error={}", tableId, connectionId, e.getMessage(), e);
-                }
-                removeConnection(tableId, connectionId);
-            }
-        });
-    }
-
-    @Override
-    public void closeConnection(Integer tableId) {
-        log.info("关闭SSE连接, tableId={}", tableId);
-        ConcurrentHashMap<String, SseEmitter> tableConnections = connections.get(tableId);
-        if (tableConnections != null) {
-            tableConnections.forEach((connectionId, emitter) -> {
-                try {
-                    emitter.complete();
-                } catch (Exception e) {
-                    log.error("关闭SSE连接失败, tableId={}, connectionId={}", tableId, connectionId, e);
-                }
-            });
-            connections.remove(tableId);
-        }
-    }
-
-    /**
-     * 判断是否为客户端主动断开(Broken pipe、Connection reset 等),此类情况属正常,无需打 ERROR。
-     */
-    private boolean isClientDisconnect(Throwable ex) {
-        if (ex == null) return false;
-        String msg = ex.getMessage();
-        if (msg != null) {
-            String lower = msg.toLowerCase();
-            if (lower.contains("broken pipe") || lower.contains("connection reset")
-                    || lower.contains("connection closed") || lower.contains("an established connection was aborted")) {
-                return true;
-            }
-        }
-        return isClientDisconnect(ex.getCause());
-    }
-
-    /**
-     * 移除连接
-     */
-    private void removeConnection(Integer tableId, String connectionId) {
-        ConcurrentHashMap<String, SseEmitter> tableConnections = connections.get(tableId);
-        if (tableConnections != null) {
-            SseEmitter emitter = tableConnections.remove(connectionId);
-            if (emitter != null) {
-                try {
-                    emitter.complete();
-                } catch (Exception e) {
-                    log.error("完成SSE连接失败, tableId={}, connectionId={}", tableId, connectionId, e);
-                }
-            }
-            if (tableConnections.isEmpty()) {
-                connections.remove(tableId);
-            }
-        }
-    }
-
-    /**
-     * 启动心跳任务
-     */
-    private void startHeartbeat(Integer tableId, String connectionId, SseEmitter emitter) {
-        scheduler.scheduleAtFixedRate(() -> {
-            try {
-                if (emitter != null) {
-                    emitter.send(SseEmitter.event()
-                            .name("heartbeat")
-                            .data("ping"));
-                }
-            } catch (IOException e) {
-                if (isClientDisconnect(e)) {
-                    log.debug("心跳时客户端已断开, tableId={}, connectionId={}", tableId, connectionId);
-                } else {
-                    log.error("发送心跳失败, tableId={}, connectionId={}", tableId, connectionId, e);
-                }
-                removeConnection(tableId, connectionId);
-            }
-        }, 30, 30, TimeUnit.SECONDS); // 每30秒发送一次心跳
-    }
-}

+ 0 - 239
alien-store/src/main/java/shop/alien/store/dining/service/impl/StoreInfoServiceImpl.java

@@ -1,239 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import shop.alien.entity.store.StoreCuisine;
-import shop.alien.entity.store.StoreCuisineCategory;
-import shop.alien.entity.store.StoreInfo;
-import shop.alien.entity.store.StoreTable;
-import shop.alien.entity.store.dto.StoreInfoWithHomepageCuisinesDTO;
-import shop.alien.entity.store.vo.CategoryWithCuisinesVO;
-import shop.alien.mapper.StoreCuisineCategoryMapper;
-import shop.alien.mapper.StoreCuisineMapper;
-import shop.alien.mapper.StoreInfoMapper;
-import shop.alien.mapper.StoreTableMapper;
-import shop.alien.store.dining.service.StoreInfoService;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * 门店信息查询服务实现类
- *
- * @author system
- * @since 2025-02-02
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class StoreInfoServiceImpl implements StoreInfoService {
-
-    private final StoreTableMapper storeTableMapper;
-    private final StoreCuisineCategoryMapper storeCuisineCategoryMapper;
-    private final StoreCuisineMapper storeCuisineMapper;
-    private final StoreInfoMapper storeInfoMapper;
-
-    @Override
-    public List<StoreTable> getTablesByStoreId(Integer storeId) {
-        log.info("根据门店ID查询桌号列表, storeId={}", storeId);
-        
-        LambdaQueryWrapper<StoreTable> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreTable::getStoreId, storeId);
-        wrapper.eq(StoreTable::getDeleteFlag, 0);
-        wrapper.orderByAsc(StoreTable::getTableNumber);
-        
-        return storeTableMapper.selectList(wrapper);
-    }
-
-    @Override
-    public List<StoreCuisineCategory> getCategoriesByStoreId(Integer storeId) {
-        log.info("根据门店ID查询菜品种类列表, storeId={}", storeId);
-        
-        LambdaQueryWrapper<StoreCuisineCategory> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisineCategory::getStoreId, storeId);
-        wrapper.eq(StoreCuisineCategory::getDeleteFlag, 0);
-        wrapper.eq(StoreCuisineCategory::getStatus, 1); // 只查询启用的分类
-        wrapper.orderByAsc(StoreCuisineCategory::getSort); // 按排序字段排序
-        
-        return storeCuisineCategoryMapper.selectList(wrapper);
-    }
-
-    @Override
-    public List<StoreCuisine> getCuisinesByCategoryId(Integer categoryId) {
-        log.info("根据菜品种类ID查询菜品信息列表, categoryId={}", categoryId);
-        
-        // 先查询分类信息,获取 storeId
-        StoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
-        if (category == null) {
-            log.warn("菜品种类不存在, categoryId={}", categoryId);
-            return new java.util.ArrayList<>();
-        }
-        
-        // 查询该门店下所有上架的菜品(与 getCategoriesWithCuisinesByStoreId 中 cuisines 查询条件、排序一致)
-        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisine::getStoreId, category.getStoreId());
-        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 只查询上架的菜品
-        wrapper.orderByAsc(StoreCuisine::getId); // 与 categories-with-cuisines 中 cuisines 顺序一致
-        
-        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
-        
-        // 过滤出包含该分类ID的菜品
-        // categoryIds 是 JSON 数组格式,如:[1,2,3]
-        return allCuisines.stream()
-                .filter(cuisine -> {
-                    String categoryIdsStr = cuisine.getCategoryIds();
-                    if (StringUtils.isBlank(categoryIdsStr)) {
-                        return false;
-                    }
-                    try {
-                        // 解析 JSON 数组
-                        List<Integer> categoryIds = JSON.parseArray(categoryIdsStr, Integer.class);
-                        return categoryIds != null && categoryIds.contains(categoryId);
-                    } catch (Exception e) {
-                        log.warn("解析菜品分类IDs失败, cuisineId={}, categoryIds={}, error={}", 
-                                cuisine.getId(), categoryIdsStr, e.getMessage());
-                        // 如果解析失败,使用简单的字符串匹配作为降级方案
-                        return categoryIdsStr.contains(String.valueOf(categoryId));
-                    }
-                })
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public List<CategoryWithCuisinesVO> getCategoriesWithCuisinesByStoreId(Integer storeId, String keyword) {
-        log.info("根据门店ID查询菜品种类及下属菜品, storeId={}, keyword={}", storeId, keyword);
-        List<StoreCuisineCategory> categories = getCategoriesByStoreId(storeId);
-        if (categories == null || categories.isEmpty()) {
-            return new ArrayList<>();
-        }
-        // 与 getCuisinesByCategoryId 相同的查询条件与排序,保证 cuisines 字段与 /store/info/cuisines 一致
-        LambdaQueryWrapper<StoreCuisine> cuisineWrapper = new LambdaQueryWrapper<>();
-        cuisineWrapper.eq(StoreCuisine::getStoreId, storeId);
-        cuisineWrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        cuisineWrapper.eq(StoreCuisine::getShelfStatus, 1);
-        cuisineWrapper.orderByAsc(StoreCuisine::getId);
-        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(cuisineWrapper);
-        if (allCuisines == null) {
-            allCuisines = new ArrayList<>();
-        }
-        boolean filterByName = StringUtils.isNotBlank(keyword);
-        String keywordLower = filterByName ? keyword.trim().toLowerCase() : null;
-        List<CategoryWithCuisinesVO> result = new ArrayList<>();
-        for (StoreCuisineCategory category : categories) {
-            Integer categoryId = category.getId();
-            List<StoreCuisine> cuisines = allCuisines.stream()
-                    .filter(c -> belongsToCategory(c, categoryId))
-                    .filter(c -> !filterByName || (c.getName() != null && c.getName().toLowerCase().contains(keywordLower)))
-                    .collect(Collectors.toList());
-            result.add(new CategoryWithCuisinesVO(category, cuisines));
-        }
-        return result;
-    }
-
-    private boolean belongsToCategory(StoreCuisine cuisine, Integer categoryId) {
-        String categoryIdsStr = cuisine.getCategoryIds();
-        if (StringUtils.isBlank(categoryIdsStr)) {
-            return false;
-        }
-        try {
-            List<Integer> categoryIds = JSON.parseArray(categoryIdsStr, Integer.class);
-            return categoryIds != null && categoryIds.contains(categoryId);
-        } catch (Exception e) {
-            return categoryIdsStr.contains(String.valueOf(categoryId));
-        }
-    }
-
-    @Override
-    public boolean deleteCategory(Integer categoryId) {
-        log.info("删除菜品种类(仅解除绑定+逻辑删分类), categoryId={}", categoryId);
-        if (categoryId == null) {
-            log.warn("删除菜品种类失败:分类ID为空");
-            return false;
-        }
-        StoreCuisineCategory category = storeCuisineCategoryMapper.selectById(categoryId);
-        if (category == null) {
-            log.warn("删除菜品种类失败:分类不存在, categoryId={}", categoryId);
-            return false;
-        }
-        Integer storeId = category.getStoreId();
-        // 1. 解除绑定:将该分类ID从所有关联菜品的 category_ids 中移除,价目表菜品其它字段不变
-        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisine::getStoreId, storeId);
-        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        List<StoreCuisine> allCuisines = storeCuisineMapper.selectList(wrapper);
-        if (allCuisines != null) {
-            for (StoreCuisine cuisine : allCuisines) {
-                if (!belongsToCategory(cuisine, categoryId)) {
-                    continue;
-                }
-                String newCategoryIds = removeCategoryIdFromJson(cuisine.getCategoryIds(), categoryId);
-                cuisine.setCategoryIds(newCategoryIds);
-                storeCuisineMapper.updateById(cuisine);
-            }
-        }
-        // 2. 逻辑删除菜品种类
-        storeCuisineCategoryMapper.deleteById(categoryId);
-        log.info("删除菜品种类完成, categoryId={}", categoryId);
-        return true;
-    }
-
-    /** 从 categoryIds 的 JSON 数组中移除指定 categoryId,返回新 JSON 字符串;若为空则返回 null */
-    private String removeCategoryIdFromJson(String categoryIdsStr, Integer categoryId) {
-        if (StringUtils.isBlank(categoryIdsStr)) {
-            return null;
-        }
-        try {
-            List<Integer> list = JSON.parseArray(categoryIdsStr, Integer.class);
-            if (list == null || list.isEmpty()) {
-                return null;
-            }
-            list.remove(categoryId);
-            if (list.isEmpty()) {
-                return null;
-            }
-            return JSON.toJSONString(list);
-        } catch (Exception e) {
-            log.warn("解析 categoryIds 失败, categoryIdsStr={}, 原样返回", categoryIdsStr, e);
-            return categoryIdsStr;
-        }
-    }
-
-    @Override
-    public StoreInfoWithHomepageCuisinesDTO getStoreInfoWithHomepageCuisines(Integer storeId) {
-        log.info("根据商铺ID查询店铺信息和首页展示美食价目表, storeId={}", storeId);
-        
-        // 1. 查询店铺信息
-        StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
-        if (storeInfo == null) {
-            throw new RuntimeException("店铺不存在");
-        }
-        
-        // 2. 查询首页展示的美食价目表(is_homepage_display = 1,上架状态 = 1,审核通过 = 1)
-        LambdaQueryWrapper<StoreCuisine> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreCuisine::getStoreId, storeId);
-        wrapper.eq(StoreCuisine::getDeleteFlag, 0);
-        wrapper.eq(StoreCuisine::getIsHomepageDisplay, 1); // 首页展示
-        wrapper.eq(StoreCuisine::getShelfStatus, 1); // 上架状态
-        wrapper.eq(StoreCuisine::getStatus, 1); // 审核通过
-        wrapper.orderByDesc(StoreCuisine::getCreatedTime); // 按创建时间倒序
-        
-        List<StoreCuisine> homepageCuisines = storeCuisineMapper.selectList(wrapper);
-        if (homepageCuisines == null) {
-            homepageCuisines = new ArrayList<>();
-        }
-        
-        // 3. 构建返回DTO
-        StoreInfoWithHomepageCuisinesDTO dto = new StoreInfoWithHomepageCuisinesDTO();
-        dto.setStoreInfo(storeInfo);
-        dto.setHomepageCuisines(homepageCuisines);
-        
-        log.info("查询完成, storeId={}, 首页展示美食数量={}", storeId, homepageCuisines.size());
-        return dto;
-    }
-}

+ 0 - 2020
alien-store/src/main/java/shop/alien/store/dining/service/impl/StoreOrderServiceImpl.java

@@ -1,2020 +0,0 @@
-package shop.alien.store.dining.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.StringUtils;
-import shop.alien.store.config.BaseRedisService;
-import shop.alien.store.dining.service.CartService;
-import shop.alien.store.dining.service.StoreOrderService;
-import shop.alien.store.dining.util.TokenUtil;
-import shop.alien.entity.store.*;
-
-import shop.alien.entity.store.dto.CartDTO;
-import shop.alien.entity.store.dto.CartItemDTO;
-import shop.alien.entity.store.dto.CreateOrderDTO;
-import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
-import shop.alien.entity.store.vo.OrderChangeLogItemVO;
-import shop.alien.entity.store.vo.OrderInfoVO;
-import shop.alien.entity.store.vo.StoreOrderPageVO;
-import shop.alien.entity.store.vo.OrderCuisineItemVO;
-import shop.alien.entity.store.vo.OrderDetailWithChangeLogVO;
-import shop.alien.mapper.*;
-
-import java.math.BigDecimal;
-import java.text.SimpleDateFormat;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 订单服务实现类
- *
- * @author system
- * @since 2025-01-XX
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-@Transactional(rollbackFor = Exception.class)
-public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOrder> implements StoreOrderService {
-
-
-    private final StoreOrderDetailMapper orderDetailMapper;
-    private final StoreTableMapper storeTableMapper;
-    private final StoreTableLogMapper storeTableLogMapper;
-    private final StoreCuisineMapper storeCuisineMapper;
-    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;
-    private final CartService cartService;
-    private final StoreOrderLockMapper storeOrderLockMapper;
-    private final StoreCouponUsageMapper storeCouponUsageMapper;
-    private final StoreCartMapper storeCartMapper;
-    private final BaseRedisService baseRedisService;
-    private final StoreInfoMapper storeInfoMapper;
-    private final StoreOrderChangeLogMapper orderChangeLogMapper;
-    private final shop.alien.store.dining.service.SseService sseService;
-    private final shop.alien.store.dining.service.OrderLockService orderLockService;
-
-    @Override
-    public StoreOrder createOrder(CreateOrderDTO dto) {
-        log.info("创建订单, dto={}", dto);
-
-        // 获取当前用户信息
-        Object[] userInfo = getCurrentUserInfo();
-        Integer userId = (Integer) userInfo[0];
-        String userPhone = (String) userInfo[1];
-
-        // 检查订单锁定状态
-        Integer lockUserId = orderLockService.checkOrderLock(dto.getTableId());
-        if (lockUserId != null && !lockUserId.equals(userId)) {
-            throw new RuntimeException("订单已被其他用户锁定,无法下单");
-        }
-
-        // 验证桌号
-        StoreTable table = storeTableMapper.selectById(dto.getTableId());
-        if (table == null) {
-            throw new RuntimeException("桌号不存在");
-        }
-
-        // 查询门店信息(用于获取餐具费)
-        StoreInfo storeInfo = storeInfoMapper.selectById(table.getStoreId());
-        if (storeInfo == null) {
-            throw new RuntimeException("门店不存在");
-        }
-
-        // 获取购物车
-        CartDTO cart = cartService.getCart(dto.getTableId());
-        if (cart.getItems() == null || cart.getItems().isEmpty()) {
-            throw new RuntimeException("购物车为空");
-        }
-        
-        // 检查是否有新增商品或商品数量增加
-        boolean hasNewItems = false; // 是否有新增商品(未下单过的商品)
-        boolean hasQuantityIncrease = false; // 是否有商品数量增加
-        
-        for (shop.alien.entity.store.dto.CartItemDTO item : cart.getItems()) {
-            Integer lockedQuantity = item.getLockedQuantity();
-            Integer currentQuantity = item.getQuantity();
-            
-            if (lockedQuantity == null || lockedQuantity == 0) {
-                // 有新增商品(未下单过的商品)
-                hasNewItems = true;
-                log.debug("发现新增商品, cuisineId={}, quantity={}", item.getCuisineId(), currentQuantity);
-            } else if (currentQuantity != null && currentQuantity > lockedQuantity) {
-                // 有商品数量增加(当前数量大于已下单数量)
-                hasQuantityIncrease = true;
-                log.debug("发现商品数量增加, cuisineId={}, currentQuantity={}, orderedQuantity={}", 
-                        item.getCuisineId(), currentQuantity, lockedQuantity);
-            }
-        }
-        
-        // 如果没有新增商品且没有商品数量增加,不允许创建/更新订单(下单后只能增不能减,不支持减量同步)
-        if (!hasNewItems && !hasQuantityIncrease) {
-            throw new RuntimeException("购物车中没有新增商品或商品数量未增加,无法创建订单");
-        }
-
-        // 直接使用前端传入的值
-        BigDecimal totalAmount = dto.getTotalAmount() != null ? dto.getTotalAmount() : BigDecimal.ZERO;
-        BigDecimal tablewareFee = dto.getTablewareFee() != null ? dto.getTablewareFee() : BigDecimal.ZERO;
-        BigDecimal discountAmount = dto.getDiscountAmount() != null ? dto.getDiscountAmount() : BigDecimal.ZERO;
-        BigDecimal payAmount = dto.getPayAmount() != null ? dto.getPayAmount() : BigDecimal.ZERO;
-        
-        // 优惠券仅校验是否存在及是否属于该门店,不做金额校验;订单总金额、餐具费、优惠金额、实付金额完全采用前端传参
-        LifeDiscountCoupon coupon = null;
-        
-        if (dto.getCouponId() != null) {
-            // 检查桌号是否已使用优惠券,如果已使用则替换为新优惠券
-            if (cartService.hasUsedCoupon(dto.getTableId())) {
-                // 获取旧的优惠券使用记录
-                LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
-                oldUsageWrapper.eq(StoreCouponUsage::getTableId, dto.getTableId());
-                oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-                oldUsageWrapper.in(StoreCouponUsage::getUsageStatus, 0, 1); // 已标记使用、已下单
-                oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-                oldUsageWrapper.last("LIMIT 1");
-                StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
-                
-                if (oldUsage != null) {
-                    // 如果旧优惠券已经关联到订单(已下单状态),需要将旧优惠券使用记录状态改为"已取消"
-                    if (oldUsage.getUsageStatus() == 1 && oldUsage.getOrderId() != null) {
-                        oldUsage.setUsageStatus(3); // 已取消
-                        oldUsage.setUpdatedTime(new Date());
-                        storeCouponUsageMapper.updateById(oldUsage);
-                        log.info("替换优惠券:取消旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}", 
-                                dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
-                    } else {
-                        // 如果只是已标记使用但未下单,直接逻辑删除
-                        storeCouponUsageMapper.deleteById(oldUsage.getId());
-                        log.info("替换优惠券:删除未下单的旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}", 
-                                dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
-                    }
-                }
-                
-                // 清除旧的优惠券使用标记
-                cartService.clearCouponUsed(dto.getTableId());
-                log.info("替换优惠券:清除旧优惠券标记, tableId={}, newCouponId={}", dto.getTableId(), dto.getCouponId());
-            }
-
-            // 验证优惠券(只查询一次)
-            coupon = lifeDiscountCouponMapper.selectById(dto.getCouponId());
-            if (coupon == null) {
-                throw new RuntimeException("优惠券不存在");
-            }
-
-            // 验证优惠券是否属于该门店(空安全:coupon.storeId 为 String,table.storeId 为 Integer)
-            String couponStoreId = coupon.getStoreId();
-            Integer tableStoreId = table.getStoreId();
-            if (couponStoreId == null || tableStoreId == null
-                    || !couponStoreId.equals(String.valueOf(tableStoreId))) {
-                throw new RuntimeException("优惠券不属于该门店");
-            }
-
-            // 标记桌号已使用新优惠券
-            cartService.markCouponUsed(dto.getTableId(), dto.getCouponId());
-        } else {
-            // 直接使用前端传入的值,如果为null则设为0
-            if (discountAmount == null) {
-                discountAmount = BigDecimal.ZERO;
-            }
-        }
-
-        Date now = new Date();
-        StoreOrder order = null;
-        String orderNo = null;
-        boolean isUpdate = false; // 是否是更新订单
-        
-        // 检查桌号是否已绑定订单
-        if (table.getCurrentOrderId() != null) {
-            // 查询已存在的订单
-            StoreOrder existingOrder = this.getById(table.getCurrentOrderId());
-            if (existingOrder != null && existingOrder.getOrderStatus() == 0 && existingOrder.getPayStatus() == 0) {
-                // 订单存在且是待支付状态,更新订单
-                isUpdate = true;
-                order = existingOrder;
-                orderNo = order.getOrderNo(); // 使用原订单号
-                log.info("桌号已绑定订单,更新订单信息, orderId={}, orderNo={}", order.getId(), orderNo);
-                
-                // 更新订单信息(完全采用前端传参,不做金额校验)
-                order.setDinerCount(dto.getDinerCount());
-                order.setContactPhone(dto.getContactPhone());
-                order.setTablewareFee(tablewareFee);
-                order.setTotalAmount(totalAmount);
-                order.setCouponId(dto.getCouponId());
-                order.setCurrentCouponId(dto.getCouponId());
-                order.setDiscountAmount(discountAmount);
-                order.setPayAmount(payAmount);
-                order.setRemark(dto.getRemark());
-                order.setUpdatedUserId(userId);
-                order.setUpdatedTime(now);
-                this.updateById(order);
-                
-                // 逻辑删除旧的订单明细
-                LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-                detailWrapper.eq(StoreOrderDetail::getOrderId, order.getId());
-                detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-                List<StoreOrderDetail> oldDetails = orderDetailMapper.selectList(detailWrapper);
-                if (oldDetails != null && !oldDetails.isEmpty()) {
-                    List<Integer> oldDetailIds = oldDetails.stream()
-                            .map(StoreOrderDetail::getId)
-                            .collect(Collectors.toList());
-                    orderDetailMapper.deleteBatchIds(oldDetailIds);
-                    log.info("删除旧订单明细, orderId={}, count={}", order.getId(), oldDetailIds.size());
-                }
-            } else {
-                log.info("桌号绑定的订单不存在或已支付/已取消,将创建新订单");
-            }
-        }
-        
-        // 如果没有订单需要更新,创建新订单
-        if (!isUpdate) {
-            // 生成订单号
-            orderNo = generateOrderNo();
-            
-            // 创建订单
-            order = new StoreOrder();
-            order.setOrderNo(orderNo);
-            order.setStoreId(table.getStoreId());
-            order.setTableId(table.getId());
-            order.setTableNumber(table.getTableNumber());
-            order.setDinerCount(dto.getDinerCount());
-            order.setContactPhone(dto.getContactPhone());
-            order.setTablewareFee(tablewareFee);
-            order.setPayUserId(userId);
-            order.setPayUserPhone(userPhone);
-            order.setOrderStatus(0); // 待支付
-            order.setTotalAmount(totalAmount);
-            order.setCouponId(dto.getCouponId());
-            order.setCurrentCouponId(dto.getCouponId());
-            order.setDiscountAmount(discountAmount);
-            order.setPayAmount(payAmount);
-            
-            // 如果immediatePay为0,只创建订单不支付;为1则创建订单并支付
-            // 暂时不实现立即支付,由前端调用支付接口
-            // payType在支付时设置
-            order.setPayStatus(0); // 未支付
-            order.setRemark(dto.getRemark());
-            order.setCreatedUserId(userId);
-            order.setUpdatedUserId(userId);
-            // 手动设置创建时间和更新时间(临时方案,避免自动填充未生效导致 created_time 为 null)
-            order.setCreatedTime(now);
-            order.setUpdatedTime(now);
-            this.save(order);
-            log.info("创建新订单, orderId={}, orderNo={}", order.getId(), orderNo);
-        }
-        
-        // 确保 order 和 orderNo 已初始化(用于后续代码)
-        if (order == null || orderNo == null) {
-            throw new RuntimeException("订单创建失败,系统错误");
-        }
-        final StoreOrder finalOrder = order;
-        final String finalOrderNo = orderNo;
-        final boolean finalIsUpdate = isUpdate; // 用于 lambda 表达式
-
-        // 更新优惠券使用记录状态为已下单
-        if (dto.getCouponId() != null) {
-            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
-            usageWrapper.eq(StoreCouponUsage::getTableId, dto.getTableId());
-            usageWrapper.eq(StoreCouponUsage::getCouponId, dto.getCouponId());
-            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-            usageWrapper.last("LIMIT 1");
-            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
-            if (usage != null) {
-                usage.setOrderId(finalOrder.getId());
-                usage.setUsageStatus(1); // 已下单
-                usage.setUpdatedTime(new Date());
-                storeCouponUsageMapper.updateById(usage);
-            }
-        }
-        
-        // 如果是更新订单,且优惠券发生变化,需要处理旧优惠券的使用记录
-        if (isUpdate && finalOrder.getCouponId() != null && 
-            (dto.getCouponId() == null || !finalOrder.getCouponId().equals(dto.getCouponId()))) {
-            // 订单的优惠券被替换或取消,需要将旧优惠券使用记录状态改为"已取消"
-            LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
-            oldUsageWrapper.eq(StoreCouponUsage::getOrderId, finalOrder.getId());
-            oldUsageWrapper.eq(StoreCouponUsage::getCouponId, finalOrder.getCouponId());
-            oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-            oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-            oldUsageWrapper.last("LIMIT 1");
-            StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
-            if (oldUsage != null) {
-                oldUsage.setUsageStatus(3); // 已取消
-                oldUsage.setUpdatedTime(new Date());
-                storeCouponUsageMapper.updateById(oldUsage);
-                log.info("更新订单时替换优惠券:取消旧优惠券使用记录, orderId={}, oldCouponId={}, newCouponId={}", 
-                        finalOrder.getId(), finalOrder.getCouponId(), dto.getCouponId());
-            }
-        }
-
-        // 创建订单明细(单价、小计来自购物车)
-        // 如果是更新订单,需要判断哪些商品是新增的或数量增加的,标记为加餐
-        // 餐具的特殊ID(用于标识餐具项)
-        final Integer TABLEWARE_CUISINE_ID = -1;
-        
-        List<StoreOrderDetail> orderDetails = cart.getItems().stream()
-                .map(item -> {
-                    StoreOrderDetail detail = new StoreOrderDetail();
-                    detail.setOrderId(finalOrder.getId());
-                    detail.setOrderNo(finalOrderNo);
-                    detail.setCuisineId(item.getCuisineId());
-                    detail.setCuisineName(item.getCuisineName());
-                    
-                    // 设置菜品类型:如果为null,根据是否为餐具设置默认值
-                    Integer cuisineType = item.getCuisineType();
-                    if (cuisineType == null) {
-                        // 如果是餐具,设置为0;否则设置为1(默认单品)
-                        if (TABLEWARE_CUISINE_ID.equals(item.getCuisineId())) {
-                            cuisineType = 0; // 0表示餐具
-                        } else {
-                            // 尝试从菜品信息中获取,如果获取不到则默认为1(单品)
-                            try {
-                                StoreCuisine cuisine = storeCuisineMapper.selectById(item.getCuisineId());
-                                if (cuisine != null && cuisine.getCuisineType() != null) {
-                                    cuisineType = cuisine.getCuisineType();
-                                } else {
-                                    cuisineType = 1; // 默认为单品
-                                }
-                            } catch (Exception e) {
-                                log.warn("获取菜品类型失败, cuisineId={}, 使用默认值1", item.getCuisineId(), e);
-                                cuisineType = 1; // 默认为单品
-                            }
-                        }
-                    }
-                    detail.setCuisineType(cuisineType);
-                    
-                    detail.setCuisineImage(item.getCuisineImage());
-                    detail.setUnitPrice(item.getUnitPrice());
-                    detail.setQuantity(item.getQuantity());
-                    detail.setSubtotalAmount(item.getSubtotalAmount());
-                    detail.setAddUserId(item.getAddUserId());
-                    detail.setAddUserPhone(item.getAddUserPhone());
-                    detail.setRemark(item.getRemark());
-                    detail.setCreatedUserId(userId);
-                    detail.setCreatedTime(now);
-                    detail.setUpdatedTime(now);
-                    
-                    // 如果是更新订单,判断是否为新增商品或数量增加的商品
-                    if (finalIsUpdate) {
-                        Integer lockedQuantity = item.getLockedQuantity();
-                        // 如果是新增商品(lockedQuantity 为 null 或 0)或数量增加的商品,标记为加餐
-                        if (lockedQuantity == null || lockedQuantity == 0 || 
-                            (item.getQuantity() != null && item.getQuantity() > lockedQuantity)) {
-                            detail.setIsAddDish(1); // 标记为加餐
-                            detail.setAddDishTime(now);
-                        }
-                    }
-                    
-                    return detail;
-                })
-                .collect(Collectors.toList());
-
-        for (StoreOrderDetail detail : orderDetails) {
-            orderDetailMapper.insert(detail);
-        }
-
-        // 记录订单变更日志
-        recordOrderChangeLog(finalOrder.getId(), finalOrderNo, cart.getItems(), finalIsUpdate ? 3 : 1, now, userId, userPhone);
-
-        // 更新桌号的当前订单ID和状态(显式用 LambdaUpdateWrapper 写入,避免 updateById 忽略更新)
-        // 约定:首次下单 → 餐桌状态=就餐中(1);后续下单(更新订单/加餐) → 餐桌状态=加餐(3)
-        Integer tableId = table.getId();
-        if (!finalIsUpdate) {
-            // 首次下单:设置订单ID,餐桌状态为就餐中(1)
-            LambdaUpdateWrapper<StoreTable> newTableWrapper = new LambdaUpdateWrapper<>();
-            newTableWrapper.eq(StoreTable::getId, tableId)
-                    .set(StoreTable::getCurrentOrderId, finalOrder.getId())
-                    .set(StoreTable::getStatus, 1)
-                    .set(StoreTable::getUpdatedTime, now);
-            if (userId != null) {
-                newTableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, newTableWrapper);
-        } else {
-            // 后续下单(更新订单/加餐):餐桌状态设为加餐(3)
-            LambdaUpdateWrapper<StoreTable> addDishTableWrapper = new LambdaUpdateWrapper<>();
-            addDishTableWrapper.eq(StoreTable::getId, tableId)
-                    .set(StoreTable::getStatus, 3)
-                    .set(StoreTable::getUpdatedTime, now);
-            if (userId != null) {
-                addDishTableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, addDishTableWrapper);
-            log.info("更新订单(加餐),设置餐桌状态为加餐, tableId={}, orderId={}", tableId, finalOrder.getId());
-        }
-
-        // 锁定购物车商品数量(禁止减少或删除已下单的商品)
-        cartService.lockCartItems(dto.getTableId());
-
-        // 下单后不清空购物车,允许加餐(加餐时添加到同一订单)
-        // 只有在支付完成后才清空购物车
-
-        // 创建订单成功后,自动解锁订单锁定
-        try {
-            orderLockService.unlockOrder(dto.getTableId(), userId);
-            log.info("订单创建成功后自动解锁订单锁定, tableId={}, userId={}", dto.getTableId(), userId);
-        } catch (Exception e) {
-            log.warn("自动解锁订单锁定失败, tableId={}, userId={}, error={}", dto.getTableId(), userId, e.getMessage());
-            // 解锁失败不影响订单创建,只记录警告日志
-        }
-
-        if (isUpdate) {
-            log.info("订单更新成功, orderId={}, orderNo={}", finalOrder.getId(), finalOrderNo);
-        } else {
-            log.info("订单创建成功, orderId={}, orderNo={}", finalOrder.getId(), finalOrderNo);
-        }
-        return finalOrder;
-    }
-
-    @Override
-    public StoreOrder payOrder(Integer orderId, Integer payType) {
-        log.info("支付订单, orderId={}, payType={}", orderId, payType);
-
-        // 获取当前用户信息
-        Object[] userInfo = getCurrentUserInfo();
-        Integer userId = (Integer) userInfo[0];
-
-        // 检查结算锁定状态
-        Integer lockUserId = orderLockService.checkSettlementLock(orderId);
-        if (lockUserId != null && !lockUserId.equals(userId)) {
-            throw new RuntimeException("订单结算已被其他用户锁定,无法支付");
-        }
-
-        // 验证订单状态
-        StoreOrder order = validateOrderForOperation(orderId, 0, "支付");
-
-        // 支付时重新计算优惠券金额和实付金额(此时订单金额已确定,不会再变化)
-        BigDecimal discountAmount = BigDecimal.ZERO;
-        BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
-        BigDecimal totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO;
-        BigDecimal totalWithTableware = totalAmount.add(tablewareFee);
-        
-        if (order.getCouponId() != null) {
-            // 查询优惠券信息
-            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
-            if (coupon == null) {
-                throw new RuntimeException("优惠券不存在");
-            }
-            
-            // 验证最低消费(菜品总价 + 餐具费)
-            if (coupon.getMinimumSpendingAmount() != null
-                    && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
-                throw new RuntimeException("订单金额未达到优惠券最低消费要求(" + coupon.getMinimumSpendingAmount() + "元)");
-            }
-            
-            // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
-            discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
-        }
-        
-        // 计算实付金额(菜品总价 + 餐具费 - 优惠金额)
-        BigDecimal payAmount = totalWithTableware.subtract(discountAmount);
-        
-        // 更新订单信息(包括优惠金额和实付金额)
-        order.setDiscountAmount(discountAmount);
-        order.setPayAmount(payAmount);
-        order.setOrderStatus(1); // 已支付
-        order.setPayStatus(1); // 已支付
-        order.setPayType(payType);
-        order.setPayTime(new Date());
-        order.setPayTradeNo("TRADE_" + System.currentTimeMillis()); // 模拟交易号
-        order.setUpdatedTime(new Date());
-        order.setUpdatedUserId(userId);
-
-        this.updateById(order);
-
-        // 更新优惠券使用记录状态为已支付
-        if (order.getCouponId() != null) {
-            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
-            usageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
-            usageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
-            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-            usageWrapper.last("LIMIT 1");
-            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
-            if (usage != null) {
-                usage.setUsageStatus(2); // 已支付
-                usage.setUpdatedTime(new Date());
-                storeCouponUsageMapper.updateById(usage);
-            }
-        }
-
-        // 支付完成后,清空购物车和重置餐桌状态(保留订单数据,不删除订单)
-        // resetTableAfterPayment 方法会清空购物车和重置餐桌状态,但不会删除订单数据
-        resetTableAfterPayment(order.getTableId());
-
-        // 支付订单成功后,自动解锁结算锁定
-        try {
-            orderLockService.unlockSettlement(orderId, userId);
-            log.info("订单支付成功后自动解锁结算锁定, orderId={}, userId={}", orderId, userId);
-        } catch (Exception e) {
-            log.warn("自动解锁结算锁定失败, orderId={}, userId={}, error={}", orderId, userId, e.getMessage());
-            // 解锁失败不影响订单支付,只记录警告日志
-        }
-
-        log.info("订单支付成功, orderId={}", orderId);
-        return order;
-    }
-
-    @Override
-    public boolean cancelOrder(Integer orderId) {
-        log.info("取消订单, orderId={}", orderId);
-
-        // 验证订单状态
-        StoreOrder order = validateOrderForOperation(orderId, 0, "取消");
-
-        order.setOrderStatus(2); // 已取消
-        order.setUpdatedTime(new Date());
-
-        // 获取当前用户信息
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            order.setUpdatedUserId(userId);
-        }
-
-        this.updateById(order);
-
-        // 恢复购物车的已下单数量(允许重新下单)
-        cartService.unlockCartItems(order.getTableId());
-
-        // 清除优惠券使用标记
-        cartService.clearCouponUsed(order.getTableId());
-
-        // 更新桌号状态:显式清空 currentOrderId(updateById 会忽略 null,必须用 LambdaUpdateWrapper)
-        Integer tableId = order.getTableId();
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
-            tableWrapper.eq(StoreTable::getId, tableId)
-                    .set(StoreTable::getCurrentOrderId, null)
-                    .set(StoreTable::getUpdatedTime, new Date());
-            CartDTO cart = cartService.getCart(tableId);
-            if (cart.getItems() == null || cart.getItems().isEmpty()) {
-                tableWrapper.set(StoreTable::getStatus, 0).set(StoreTable::getDinerCount, null);
-            } else {
-                tableWrapper.set(StoreTable::getStatus, 1); // 就餐中
-            }
-            if (userId != null) {
-                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, tableWrapper);
-        }
-
-        log.info("订单取消成功, orderId={}", orderId);
-        return true;
-    }
-
-    @Override
-    public StoreOrder getOrderByOrderNo(String orderNo) {
-        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreOrder::getOrderNo, orderNo);
-        wrapper.eq(StoreOrder::getDeleteFlag, 0);
-        return this.getOne(wrapper);
-    }
-
-    @Override
-    public StoreOrder getOrderById(Integer orderId) {
-        return this.getById(orderId);
-    }
-
-    /** 前端只传 0=进行中、3=已完成。进行中对应库表 0待支付+1已支付,已完成对应 3。 */
-    private List<Integer> resolveOrderStatusFilter(Integer orderStatus) {
-        if (orderStatus == null) {
-            return null;
-        }
-        if (orderStatus == 0) {
-            return Arrays.asList(0, 1); // 进行中 = 待支付 + 已支付
-        }
-        if (orderStatus == 3) {
-            return Collections.singletonList(3); // 已完成
-        }
-        return null; // 其他值不参与筛选
-    }
-
-    @Override
-    public IPage<StoreOrder> getOrderPage(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword) {
-        // 前端只传 0=进行中、3=已完成。进行中=待支付(0)+已支付(1),已完成=3
-        List<Integer> orderStatusList = resolveOrderStatusFilter(orderStatus);
-        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreOrder::getDeleteFlag, 0);
-        if (storeId != null) {
-            wrapper.eq(StoreOrder::getStoreId, storeId);
-        }
-        if (tableId != null) {
-            wrapper.eq(StoreOrder::getTableId, tableId);
-        }
-        if (orderStatusList != null && !orderStatusList.isEmpty()) {
-            wrapper.in(StoreOrder::getOrderStatus, orderStatusList);
-        }
-        
-        // 搜索功能:按订单编号模糊搜索
-        if (StringUtils.hasText(keyword)) {
-            // 限制搜索关键词长度(15字)
-            String searchKeyword = keyword.length() > 15 ? keyword.substring(0, 15) : keyword;
-            wrapper.like(StoreOrder::getOrderNo, searchKeyword);
-        }
-        
-        wrapper.orderByDesc(StoreOrder::getCreatedTime);
-        return this.page(page, wrapper);
-    }
-
-    @Override
-    public IPage<StoreOrderPageVO> getOrderPageWithCuisines(Page<StoreOrder> page, Integer storeId, Integer tableId, Integer orderStatus, String keyword) {
-        // 前端只传 0=进行中、3=已完成。进行中=待支付(0)+已支付(1),已完成=3
-        List<Integer> orderStatusList = resolveOrderStatusFilter(orderStatus);
-        log.info("分页查询订单列表(包含菜品信息), storeId={}, tableId={}, orderStatus={}, keyword={}", storeId, tableId, orderStatusList, keyword);
-        
-        // 限制搜索关键词长度(15字)
-        String searchKeyword = null;
-        if (StringUtils.hasText(keyword)) {
-            searchKeyword = keyword.length() > 15 ? keyword.substring(0, 15) : keyword;
-        }
-        
-        // 1. 如果有关键词,需要同时支持按订单编号和菜品名称搜索
-        final Set<Integer> matchingOrderIds;
-        if (StringUtils.hasText(searchKeyword)) {
-            Set<Integer> orderIdsSet = new HashSet<>();
-            
-            // 1.1 按订单编号搜索
-            LambdaQueryWrapper<StoreOrder> orderNoWrapper = new LambdaQueryWrapper<>();
-            orderNoWrapper.eq(StoreOrder::getDeleteFlag, 0)
-                    .like(StoreOrder::getOrderNo, searchKeyword);
-            if (storeId != null) {
-                orderNoWrapper.eq(StoreOrder::getStoreId, storeId);
-            }
-            if (tableId != null) {
-                orderNoWrapper.eq(StoreOrder::getTableId, tableId);
-            }
-            if (orderStatusList != null && !orderStatusList.isEmpty()) {
-                orderNoWrapper.in(StoreOrder::getOrderStatus, orderStatusList);
-            }
-            List<StoreOrder> orderNoMatches = this.list(orderNoWrapper);
-            orderNoMatches.forEach(order -> orderIdsSet.add(order.getId()));
-            
-            // 1.2 按菜品名称搜索
-            LambdaQueryWrapper<StoreOrderDetail> detailSearchWrapper = new LambdaQueryWrapper<>();
-            detailSearchWrapper.select(StoreOrderDetail::getOrderId)
-                    .like(StoreOrderDetail::getCuisineName, searchKeyword)
-                    .eq(StoreOrderDetail::getDeleteFlag, 0);
-            
-            // 如果有限制条件,需要先查询符合条件的订单ID
-            if (storeId != null || tableId != null || (orderStatusList != null && !orderStatusList.isEmpty())) {
-                LambdaQueryWrapper<StoreOrder> filterWrapper = new LambdaQueryWrapper<>();
-                filterWrapper.eq(StoreOrder::getDeleteFlag, 0)
-                        .select(StoreOrder::getId);
-                if (storeId != null) {
-                    filterWrapper.eq(StoreOrder::getStoreId, storeId);
-                }
-                if (tableId != null) {
-                    filterWrapper.eq(StoreOrder::getTableId, tableId);
-                }
-                if (orderStatusList != null && !orderStatusList.isEmpty()) {
-                    filterWrapper.in(StoreOrder::getOrderStatus, orderStatusList);
-                }
-                List<StoreOrder> filteredOrders = this.list(filterWrapper);
-                Set<Integer> filteredOrderIds = filteredOrders.stream()
-                        .map(StoreOrder::getId)
-                        .collect(Collectors.toSet());
-                if (!filteredOrderIds.isEmpty()) {
-                    detailSearchWrapper.in(StoreOrderDetail::getOrderId, filteredOrderIds);
-                } else {
-                    // 如果没有符合条件的订单,直接返回空结果
-                    Page<StoreOrderPageVO> emptyPage = new Page<>(page.getCurrent(), page.getSize());
-                    emptyPage.setTotal(0);
-                    emptyPage.setPages(0);
-                    return emptyPage;
-                }
-            }
-            
-            List<StoreOrderDetail> matchingDetails = orderDetailMapper.selectList(detailSearchWrapper);
-            matchingDetails.forEach(detail -> orderIdsSet.add(detail.getOrderId()));
-            
-            matchingOrderIds = orderIdsSet;
-            
-            // 如果没有任何匹配的订单,返回空结果
-            if (matchingOrderIds.isEmpty()) {
-                Page<StoreOrderPageVO> emptyPage = new Page<>(page.getCurrent(), page.getSize());
-                emptyPage.setTotal(0);
-                emptyPage.setPages(0);
-                return emptyPage;
-            }
-        } else {
-            matchingOrderIds = null;
-        }
-        
-        // 2. 查询订单列表
-        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreOrder::getDeleteFlag, 0);
-        if (storeId != null) {
-            wrapper.eq(StoreOrder::getStoreId, storeId);
-        }
-        if (tableId != null) {
-            wrapper.eq(StoreOrder::getTableId, tableId);
-        }
-        if (orderStatusList != null && !orderStatusList.isEmpty()) {
-            wrapper.in(StoreOrder::getOrderStatus, orderStatusList);
-        }
-        // 如果有关键词搜索,只查询匹配的订单ID
-        if (matchingOrderIds != null && !matchingOrderIds.isEmpty()) {
-            wrapper.in(StoreOrder::getId, matchingOrderIds);
-        }
-        wrapper.orderByDesc(StoreOrder::getCreatedTime);
-        
-        IPage<StoreOrder> orderPage = this.page(page, wrapper);
-        
-        // 3. 获取所有订单ID
-        List<StoreOrder> orders = orderPage.getRecords();
-        if (orders == null || orders.isEmpty()) {
-            // 如果没有订单,返回空的分页结果
-            Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
-            resultPage.setTotal(orderPage.getTotal());
-            resultPage.setPages(orderPage.getPages());
-            return resultPage;
-        }
-        
-        List<Integer> orderIds = orders.stream()
-                .map(StoreOrder::getId)
-                .collect(Collectors.toList());
-        
-        // 3. 批量查询所有订单的菜品详情
-        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-        detailWrapper.in(StoreOrderDetail::getOrderId, orderIds);
-        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-        detailWrapper.orderByAsc(StoreOrderDetail::getOrderId);
-        detailWrapper.orderByAsc(StoreOrderDetail::getCreatedTime);
-        List<StoreOrderDetail> allDetails = orderDetailMapper.selectList(detailWrapper);
-        
-        // 4. 按订单ID分组菜品详情
-        Map<Integer, List<StoreOrderDetail>> detailsMap = allDetails.stream()
-                .collect(Collectors.groupingBy(StoreOrderDetail::getOrderId));
-        
-        // 4.1 批量查询菜品标签(用于分页列表展示)
-        Set<Integer> cuisineIds = allDetails.stream()
-                .map(StoreOrderDetail::getCuisineId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, String> cuisineIdToTags = new HashMap<>();
-        if (!cuisineIds.isEmpty()) {
-            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
-            if (cuisines != null) {
-                for (StoreCuisine c : cuisines) {
-                    if (c.getTags() != null) {
-                        cuisineIdToTags.put(c.getId(), c.getTags());
-                    }
-                }
-            }
-        }
-        Map<Integer, String> finalCuisineIdToTags = cuisineIdToTags;
-        
-        // 5. 批量查询门店名称
-        Set<Integer> storeIds = orders.stream().map(StoreOrder::getStoreId).filter(Objects::nonNull).collect(Collectors.toSet());
-        Map<Integer, String> storeNameMap = new HashMap<>();
-        if (!storeIds.isEmpty()) {
-            List<StoreInfo> storeList = storeInfoMapper.selectBatchIds(storeIds);
-            if (storeList != null) {
-                for (StoreInfo s : storeList) {
-                    storeNameMap.put(s.getId(), s.getStoreName());
-                }
-            }
-        }
-        
-        // 6. 构建返回结果
-        List<StoreOrderPageVO> voList = orders.stream().map(order -> {
-            StoreOrderPageVO vo = new StoreOrderPageVO();
-            vo.setOrder(order);
-            vo.setStoreName(storeNameMap.getOrDefault(order.getStoreId(), ""));
-            
-            // 获取该订单的菜品列表(含菜品标签)
-            List<StoreOrderDetail> orderDetails = detailsMap.getOrDefault(order.getId(), new ArrayList<>());
-            List<OrderCuisineItemVO> cuisineItems = orderDetails.stream()
-                    .map(detail -> {
-                        OrderCuisineItemVO item = new OrderCuisineItemVO();
-                        item.setCuisineId(detail.getCuisineId());
-                        item.setCuisineName(detail.getCuisineName());
-                        item.setCuisineImage(detail.getCuisineImage());
-                        item.setQuantity(detail.getQuantity());
-                        item.setUnitPrice(detail.getUnitPrice());
-                        item.setTags(detail.getCuisineId() != null ? finalCuisineIdToTags.get(detail.getCuisineId()) : null);
-                        return item;
-                    })
-                    .collect(Collectors.toList());
-            vo.setCuisineItems(cuisineItems);
-            
-            return vo;
-        }).collect(Collectors.toList());
-        
-        // 7. 构建分页结果
-        Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
-        resultPage.setRecords(voList);
-        resultPage.setTotal(orderPage.getTotal());
-        resultPage.setPages(orderPage.getPages());
-        
-        return resultPage;
-    }
-
-    @Override
-    public boolean completeOrder(Integer orderId) {
-        log.info("完成订单, orderId={}", orderId);
-
-        StoreOrder order = this.getById(orderId);
-        if (order == null) {
-            throw new RuntimeException("订单不存在");
-        }
-
-        // 检查订单状态:只有已支付状态(1)的订单才能完成
-        if (order.getOrderStatus() != 1) {
-            throw new RuntimeException("订单状态不正确,只有已支付状态的订单才能完成");
-        }
-
-        // 检查支付状态:确保订单已支付
-        if (order.getPayStatus() != 1) {
-            throw new RuntimeException("订单未支付,无法完成");
-        }
-
-        order.setOrderStatus(3); // 已完成
-        order.setUpdatedTime(new Date());
-
-        // 从 token 获取用户信息
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            order.setUpdatedUserId(userId);
-        }
-
-        this.updateById(order);
-
-        // 更新桌号状态:显式清空 currentOrderId(updateById 会忽略 null,必须用 LambdaUpdateWrapper)
-        Integer tableId = order.getTableId();
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
-            tableWrapper.eq(StoreTable::getId, tableId)
-                    .set(StoreTable::getCurrentOrderId, null)
-                    .set(StoreTable::getStatus, 0)
-                    .set(StoreTable::getDinerCount, null)
-                    .set(StoreTable::getUpdatedTime, new Date());
-            if (userId != null) {
-                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, tableWrapper);
-        }
-
-        log.info("订单完成成功, orderId={}", orderId);
-        return true;
-    }
-
-    @Override
-    public boolean completeOrderByMerchant(Integer orderId) {
-        log.info("商家手动完成订单, orderId={}", orderId);
-
-        StoreOrder order = this.getById(orderId);
-        if (order == null) {
-            throw new RuntimeException("订单不存在");
-        }
-
-        // 商家手动完成订单,不校验支付状态,直接设置为已完成
-        order.setOrderStatus(3); // 已完成
-        order.setUpdatedTime(new Date());
-
-        // 从 token 获取用户信息
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            order.setUpdatedUserId(userId);
-        }
-
-        this.updateById(order);
-
-        // 更新桌号状态:显式清空 currentOrderId(updateById 会忽略 null,必须用 LambdaUpdateWrapper)
-        Integer tableId = order.getTableId();
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table != null) {
-            LambdaUpdateWrapper<StoreTable> tableWrapper = new LambdaUpdateWrapper<>();
-            tableWrapper.eq(StoreTable::getId, tableId)
-                    .set(StoreTable::getCurrentOrderId, null)
-                    .set(StoreTable::getStatus, 0)
-                    .set(StoreTable::getDinerCount, null)
-                    .set(StoreTable::getUpdatedTime, new Date());
-            if (userId != null) {
-                tableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, tableWrapper);
-        }
-
-        log.info("商家手动完成订单成功, orderId={}", orderId);
-        return true;
-    }
-
-    @Override
-    public StoreOrder updateOrderCoupon(Integer orderId, Integer couponId) {
-        log.info("更新订单优惠券, orderId={}, couponId={}", orderId, couponId);
-
-        // 验证订单状态
-        StoreOrder order = validateOrderForOperation(orderId, 0, "修改优惠券");
-
-        BigDecimal discountAmount = BigDecimal.ZERO;
-
-        if (couponId != null) {
-            // 验证优惠券
-            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(couponId);
-            if (coupon == null) {
-                throw new RuntimeException("优惠券不存在");
-            }
-
-            // 验证优惠券是否属于该门店
-            if (!coupon.getStoreId().equals(String.valueOf(order.getStoreId()))) {
-                throw new RuntimeException("优惠券不属于该门店");
-            }
-
-            // 验证最低消费(菜品总价 + 餐具费)
-            BigDecimal totalWithTableware = order.getTotalAmount().add(order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO);
-            if (coupon.getMinimumSpendingAmount() != null
-                    && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
-                throw new RuntimeException("订单金额未达到优惠券最低消费要求");
-            }
-
-            // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
-            discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
-        }
-
-        // 如果之前有优惠券,且优惠券发生变化(包括取消优惠券),需要处理旧优惠券使用记录
-        if (order.getCouponId() != null && (couponId == null || !order.getCouponId().equals(couponId))) {
-            // 清除旧优惠券的使用标记(如果取消优惠券或更换优惠券)
-            cartService.clearCouponUsed(order.getTableId());
-            
-            LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
-            oldUsageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
-            oldUsageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
-            oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-            oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-            oldUsageWrapper.last("LIMIT 1");
-            StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
-            if (oldUsage != null) {
-                oldUsage.setUsageStatus(3); // 已取消
-                oldUsage.setUpdatedTime(new Date());
-                storeCouponUsageMapper.updateById(oldUsage);
-            }
-        }
-
-        // 如果新设置了优惠券,需要标记桌号已使用优惠券,并更新或创建使用记录
-        if (couponId != null) {
-            // 检查桌号是否已使用优惠券(如果更换优惠券,之前的标记已清除)
-            if (!cartService.hasUsedCoupon(order.getTableId())) {
-                cartService.markCouponUsed(order.getTableId(), couponId);
-            }
-            LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
-            usageWrapper.eq(StoreCouponUsage::getTableId, order.getTableId());
-            usageWrapper.eq(StoreCouponUsage::getCouponId, couponId);
-            usageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-            usageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
-            usageWrapper.last("LIMIT 1");
-            StoreCouponUsage usage = storeCouponUsageMapper.selectOne(usageWrapper);
-            if (usage != null) {
-                usage.setOrderId(orderId);
-                usage.setUsageStatus(1); // 已下单
-                usage.setDiscountAmount(discountAmount);
-                usage.setUpdatedTime(new Date());
-                storeCouponUsageMapper.updateById(usage);
-            } else {
-                // 创建新的使用记录
-                StoreTable table = storeTableMapper.selectById(order.getTableId());
-                if (table != null) {
-                    Date now = new Date();
-                    StoreCouponUsage newUsage = new StoreCouponUsage();
-                    newUsage.setTableId(order.getTableId());
-                    newUsage.setStoreId(order.getStoreId());
-                    newUsage.setOrderId(orderId);
-                    newUsage.setCouponId(couponId);
-                    newUsage.setDiscountAmount(discountAmount);
-                    newUsage.setUsageStatus(1); // 已下单
-                    newUsage.setCreatedTime(now);
-                    newUsage.setUpdatedTime(now); // 设置更新时间,避免数据库约束错误
-                    Integer userId = TokenUtil.getCurrentUserId();
-                    if (userId != null) {
-                        newUsage.setCreatedUserId(userId);
-                    }
-                    storeCouponUsageMapper.insert(newUsage);
-                }
-            }
-        }
-
-        // 重新计算实付金额(菜品总价 + 餐具费 - 优惠金额)
-        BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
-        BigDecimal payAmount = order.getTotalAmount().add(tablewareFee).subtract(discountAmount);
-
-        order.setCouponId(couponId);
-        order.setCurrentCouponId(couponId);
-        order.setDiscountAmount(discountAmount);
-        order.setPayAmount(payAmount);
-        order.setUpdatedTime(new Date());
-
-        // 从 token 获取用户信息
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            order.setUpdatedUserId(userId);
-        }
-
-        this.updateById(order);
-
-        log.info("更新订单优惠券成功, orderId={}", orderId);
-        return order;
-    }
-
-    @Override
-    public boolean resetTable(Integer tableId) {
-        log.info("管理员重置餐桌, tableId={}", tableId);
-        
-        // 验证餐桌是否存在
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table == null) {
-            throw new RuntimeException("餐桌不存在");
-        }
-        
-        // 1. 删除购物车数据(逻辑删除,使用 MyBatis-Plus 的 removeBatchIds)
-        LambdaQueryWrapper<StoreCart> cartWrapper = new LambdaQueryWrapper<>();
-        cartWrapper.eq(StoreCart::getTableId, tableId);
-        cartWrapper.eq(StoreCart::getDeleteFlag, 0);
-        List<StoreCart> cartList = storeCartMapper.selectList(cartWrapper);
-        if (cartList != null && !cartList.isEmpty()) {
-            List<Integer> cartIds = cartList.stream()
-                    .map(StoreCart::getId)
-                    .collect(Collectors.toList());
-            // 使用 removeBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-            storeCartMapper.deleteBatchIds(cartIds);
-            log.info("删除购物车数据, tableId={}, count={}", tableId, cartList.size());
-        }
-        
-        // 2. 只删除未支付或已取消的订单(保留已支付/已完成的订单,避免数据丢失)
-        // 订单状态:0-待支付,1-已支付,2-已取消,3-已完成
-        LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
-        orderWrapper.eq(StoreOrder::getTableId, tableId);
-        orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
-        // 只查询未支付(0)或已取消(2)的订单
-        orderWrapper.in(StoreOrder::getOrderStatus, 0, 2);
-        List<StoreOrder> orderList = this.list(orderWrapper);
-        List<Integer> orderIds = new ArrayList<>();
-        if (orderList != null && !orderList.isEmpty()) {
-            orderIds = orderList.stream()
-                    .map(StoreOrder::getId)
-                    .collect(Collectors.toList());
-            
-            // 删除订单明细(逻辑删除,使用 MyBatis-Plus 的 deleteBatchIds)
-            for (Integer orderId : orderIds) {
-                LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-                detailWrapper.eq(StoreOrderDetail::getOrderId, orderId);
-                detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-                List<StoreOrderDetail> detailList = orderDetailMapper.selectList(detailWrapper);
-                if (detailList != null && !detailList.isEmpty()) {
-                    List<Integer> detailIds = detailList.stream()
-                            .map(StoreOrderDetail::getId)
-                            .collect(Collectors.toList());
-                    // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-                    orderDetailMapper.deleteBatchIds(detailIds);
-                    log.info("删除订单明细, orderId={}, count={}", orderId, detailList.size());
-                }
-            }
-            
-            // 删除订单变更记录(逻辑删除,使用 MyBatis-Plus 的 deleteBatchIds)
-            for (Integer orderId : orderIds) {
-                LambdaQueryWrapper<StoreOrderChangeLog> changeLogWrapper = new LambdaQueryWrapper<>();
-                changeLogWrapper.eq(StoreOrderChangeLog::getOrderId, orderId);
-                changeLogWrapper.eq(StoreOrderChangeLog::getDeleteFlag, 0);
-                List<StoreOrderChangeLog> changeLogList = orderChangeLogMapper.selectList(changeLogWrapper);
-                if (changeLogList != null && !changeLogList.isEmpty()) {
-                    List<Integer> changeLogIds = changeLogList.stream()
-                            .map(StoreOrderChangeLog::getId)
-                            .collect(Collectors.toList());
-                    // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-                    orderChangeLogMapper.deleteBatchIds(changeLogIds);
-                    log.info("删除订单变更记录, orderId={}, count={}", orderId, changeLogList.size());
-                }
-            }
-            
-            // 删除订单(逻辑删除,使用 MyBatis-Plus 的 removeByIds)
-            // 使用 removeByIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-            this.removeByIds(orderIds);
-            log.info("删除未支付/已取消订单数据, tableId={}, count={}", tableId, orderList.size());
-        }
-        
-        // 查询该桌号的所有订单(包括已支付/已完成的),用于后续处理锁定记录
-        LambdaQueryWrapper<StoreOrder> allOrderWrapper = new LambdaQueryWrapper<>();
-        allOrderWrapper.eq(StoreOrder::getTableId, tableId);
-        allOrderWrapper.eq(StoreOrder::getDeleteFlag, 0);
-        List<StoreOrder> allOrderList = this.list(allOrderWrapper);
-        List<Integer> allOrderIds = new ArrayList<>();
-        if (allOrderList != null && !allOrderList.isEmpty()) {
-            allOrderIds = allOrderList.stream()
-                    .map(StoreOrder::getId)
-                    .collect(Collectors.toList());
-        }
-        
-        // 3. 只删除未下单的优惠券使用记录(保留已下单/已支付的记录,避免数据丢失)
-        // usageStatus: 0-已标记使用, 1-已下单, 2-已支付, 3-已取消
-        LambdaQueryWrapper<StoreCouponUsage> couponUsageWrapper = new LambdaQueryWrapper<>();
-        couponUsageWrapper.eq(StoreCouponUsage::getTableId, tableId);
-        couponUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-        // 只删除已标记使用但未下单的记录(usageStatus=0)
-        couponUsageWrapper.eq(StoreCouponUsage::getUsageStatus, 0);
-        List<StoreCouponUsage> couponUsageList = storeCouponUsageMapper.selectList(couponUsageWrapper);
-        if (couponUsageList != null && !couponUsageList.isEmpty()) {
-            List<Integer> couponUsageIds = couponUsageList.stream()
-                    .map(StoreCouponUsage::getId)
-                    .collect(Collectors.toList());
-            // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
-            storeCouponUsageMapper.deleteBatchIds(couponUsageIds);
-            log.info("删除未下单的优惠券使用记录, tableId={}, count={}", tableId, couponUsageList.size());
-        }
-        
-        // 4. 删除该桌号的所有订单锁定记录(逻辑删除)
-        // 包括下单锁定(lock_type=1,通过 tableId 查找)和结算锁定(lock_type=2,通过订单ID关联)
-        
-        // 删除下单锁定(通过 tableId 查找)
-        LambdaQueryWrapper<StoreOrderLock> tableLockWrapper = new LambdaQueryWrapper<>();
-        tableLockWrapper.eq(StoreOrderLock::getTableId, tableId);
-        tableLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
-        List<StoreOrderLock> tableLockList = storeOrderLockMapper.selectList(tableLockWrapper);
-        if (tableLockList != null && !tableLockList.isEmpty()) {
-            List<Integer> tableLockIds = tableLockList.stream()
-                    .map(StoreOrderLock::getId)
-                    .collect(Collectors.toList());
-            storeOrderLockMapper.deleteBatchIds(tableLockIds);
-            log.info("删除下单锁定记录, tableId={}, count={}", tableId, tableLockList.size());
-        }
-        
-        // 删除结算锁定(通过 orderId 查找,如果有订单的话)
-        // 注意:这里使用 allOrderIds,包括所有订单(已删除和未删除的),因为锁定记录可能关联已支付的订单
-        if (!allOrderIds.isEmpty()) {
-            LambdaQueryWrapper<StoreOrderLock> orderLockWrapper = new LambdaQueryWrapper<>();
-            orderLockWrapper.in(StoreOrderLock::getOrderId, allOrderIds);
-            orderLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
-            List<StoreOrderLock> orderLockList = storeOrderLockMapper.selectList(orderLockWrapper);
-            if (orderLockList != null && !orderLockList.isEmpty()) {
-                List<Integer> orderLockIds = orderLockList.stream()
-                        .map(StoreOrderLock::getId)
-                        .collect(Collectors.toList());
-                storeOrderLockMapper.deleteBatchIds(orderLockIds);
-                log.info("删除结算锁定记录, orderIds={}, count={}", allOrderIds, orderLockList.size());
-            }
-        }
-        
-        // 5. 清空Redis中的购物车缓存
-        String cartKey = "cart:table:" + tableId;
-        baseRedisService.delete(cartKey);
-        log.info("清空Redis购物车缓存, tableId={}", tableId);
-        
-        // 6. 清除优惠券使用标记(Redis中的标记)
-        cartService.clearCouponUsed(tableId);
-        log.info("清除优惠券使用标记, tableId={}", tableId);
-        
-        // 7. 重置餐桌表(使用 LambdaUpdateWrapper 来显式设置 null 值)
-        LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(StoreTable::getId, tableId)
-                .set(StoreTable::getCurrentOrderId, null)  // 显式设置 null
-                .set(StoreTable::getCurrentCouponId, null)  // 显式设置 null
-                .set(StoreTable::getCartItemCount, 0)
-                .set(StoreTable::getCartTotalAmount, BigDecimal.ZERO)
-                .set(StoreTable::getStatus, 0)  // 空闲
-                .set(StoreTable::getDinerCount, null)  // 清空就餐人数
-                .set(StoreTable::getUpdatedTime, new Date());
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            updateWrapper.set(StoreTable::getUpdatedUserId, userId);
-        }
-        storeTableMapper.update(null, updateWrapper);
-        log.info("重置餐桌表完成, tableId={}", tableId);
-        
-        return true;
-    }
-
-    /**
-     * 支付完成后重置餐桌(保留订单数据,只重置餐桌绑定关系)
-     *
-     * @param tableId 餐桌ID
-     */
-    @Override
-    public void resetTableAfterPayment(Integer tableId) {
-        log.info("支付完成后重置餐桌, tableId={}", tableId);
-
-        // 验证餐桌是否存在
-        StoreTable table = storeTableMapper.selectById(tableId);
-        if (table == null) {
-            log.warn("餐桌不存在,跳过重置, tableId={}", tableId);
-            return;
-        }
-
-        // 1. 完全清空购物车(包括已下单的商品,因为订单已支付完成)
-        // 逻辑删除所有购物车数据
-        LambdaQueryWrapper<StoreCart> cartWrapper = new LambdaQueryWrapper<>();
-        cartWrapper.eq(StoreCart::getTableId, tableId);
-        cartWrapper.eq(StoreCart::getDeleteFlag, 0);
-        List<StoreCart> cartList = storeCartMapper.selectList(cartWrapper);
-        if (cartList != null && !cartList.isEmpty()) {
-            List<Integer> cartIds = cartList.stream()
-                    .map(StoreCart::getId)
-                    .collect(Collectors.toList());
-            storeCartMapper.deleteBatchIds(cartIds);
-            log.info("支付完成后删除购物车数据, tableId={}, count={}", tableId, cartList.size());
-        }
-
-        // 2. 清空Redis中的购物车缓存
-        String cartKey = "cart:table:" + tableId;
-        baseRedisService.delete(cartKey);
-        log.info("清空Redis购物车缓存, tableId={}", tableId);
-
-        // 3. 清除优惠券使用标记
-        cartService.clearCouponUsed(tableId);
-        log.info("清除优惠券使用标记, tableId={}", tableId);
-
-        // 4. 重置餐桌表(使用 LambdaUpdateWrapper 来显式设置 null 值)
-        LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(StoreTable::getId, tableId)
-                .set(StoreTable::getCurrentOrderId, null)  // 显式设置 null
-                .set(StoreTable::getCurrentCouponId, null)  // 显式设置 null
-                .set(StoreTable::getCartItemCount, 0)
-                .set(StoreTable::getCartTotalAmount, BigDecimal.ZERO)
-                .set(StoreTable::getStatus, 0)  // 空闲
-                .set(StoreTable::getDinerCount, null)  // 清空就餐人数
-                .set(StoreTable::getUpdatedTime, new Date());
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId != null) {
-            updateWrapper.set(StoreTable::getUpdatedUserId, userId);
-        }
-        storeTableMapper.update(null, updateWrapper);
-        log.info("支付完成后重置餐桌表完成, tableId={}", tableId);
-    }
-
-    @Override
-    public IPage<StoreOrder> getMyOrders(Page<StoreOrder> page, String type) {
-        log.info("查询我的订单, type={}", type);
-
-        // 获取当前用户ID
-        Integer userId = TokenUtil.getCurrentUserId();
-        if (userId == null) {
-            throw new RuntimeException("用户未登录");
-        }
-
-        LambdaQueryWrapper<StoreOrder> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreOrder::getDeleteFlag, 0);
-        wrapper.eq(StoreOrder::getCreatedUserId, userId); // 查询当前用户创建的订单
-
-        // 根据类型过滤订单
-        if ("0".equals(type) || "unpaid".equalsIgnoreCase(type)) {
-            // 未支付订单:orderStatus=0 且 payStatus=0
-            wrapper.eq(StoreOrder::getOrderStatus, 0);
-            wrapper.eq(StoreOrder::getPayStatus, 0);
-            log.info("查询未支付订单, userId={}", userId);
-        } else if ("1".equals(type) || "history".equalsIgnoreCase(type)) {
-            // 历史订单:已支付或已完成的订单(orderStatus=1 或 3,payStatus=1)
-            wrapper.and(w -> w.and(w1 -> w1.eq(StoreOrder::getOrderStatus, 1).eq(StoreOrder::getPayStatus, 1))
-                    .or(w2 -> w2.eq(StoreOrder::getOrderStatus, 3).eq(StoreOrder::getPayStatus, 1)));
-            log.info("查询历史订单, userId={}", userId);
-        } else {
-            // 如果类型不明确,返回所有订单
-            log.warn("订单类型不明确, type={}, 返回所有订单", type);
-        }
-
-        wrapper.orderByDesc(StoreOrder::getCreatedTime);
-        return this.page(page, wrapper);
-    }
-
-    @Override
-    public IPage<StoreOrderPageVO> getMyOrdersWithCuisines(Page<StoreOrder> page, String type) {
-        log.info("查询我的订单(包含菜品信息), type={}", type);
-
-        // 1. 查询订单列表
-        IPage<StoreOrder> orderPage = getMyOrders(page, type);
-
-        // 2. 获取所有订单ID
-        List<StoreOrder> orders = orderPage.getRecords();
-        if (orders == null || orders.isEmpty()) {
-            // 如果没有订单,返回空的分页结果
-            Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
-            resultPage.setTotal(orderPage.getTotal());
-            resultPage.setPages(orderPage.getPages());
-            return resultPage;
-        }
-
-        List<Integer> orderIds = orders.stream()
-                .map(StoreOrder::getId)
-                .collect(Collectors.toList());
-
-        // 3. 批量查询所有订单的菜品详情
-        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-        detailWrapper.in(StoreOrderDetail::getOrderId, orderIds);
-        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-        detailWrapper.orderByAsc(StoreOrderDetail::getOrderId);
-        detailWrapper.orderByAsc(StoreOrderDetail::getCreatedTime);
-        List<StoreOrderDetail> allDetails = orderDetailMapper.selectList(detailWrapper);
-
-        // 4. 按订单ID分组菜品详情
-        Map<Integer, List<StoreOrderDetail>> detailsMap = allDetails.stream()
-                .collect(Collectors.groupingBy(StoreOrderDetail::getOrderId));
-
-        // 4.1 批量查询菜品标签(用于我的订单分页展示)
-        Set<Integer> cuisineIdsMy = allDetails.stream()
-                .map(StoreOrderDetail::getCuisineId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, String> cuisineIdToTagsMy = new HashMap<>();
-        if (!cuisineIdsMy.isEmpty()) {
-            List<StoreCuisine> cuisinesMy = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIdsMy));
-            if (cuisinesMy != null) {
-                for (StoreCuisine c : cuisinesMy) {
-                    if (c.getTags() != null) {
-                        cuisineIdToTagsMy.put(c.getId(), c.getTags());
-                    }
-                }
-            }
-        }
-        Map<Integer, String> finalCuisineIdToTagsMy = cuisineIdToTagsMy;
-
-        // 5. 批量查询门店名称
-        Set<Integer> storeIds = orders.stream().map(StoreOrder::getStoreId).filter(Objects::nonNull).collect(Collectors.toSet());
-        Map<Integer, String> storeNameMap = new HashMap<>();
-        if (!storeIds.isEmpty()) {
-            List<StoreInfo> storeList = storeInfoMapper.selectBatchIds(storeIds);
-            if (storeList != null) {
-                for (StoreInfo s : storeList) {
-                    storeNameMap.put(s.getId(), s.getStoreName());
-                }
-            }
-        }
-
-        // 6. 构建返回结果
-        List<StoreOrderPageVO> voList = orders.stream().map(order -> {
-            StoreOrderPageVO vo = new StoreOrderPageVO();
-            vo.setOrder(order);
-            vo.setStoreName(storeNameMap.getOrDefault(order.getStoreId(), ""));
-
-            // 获取该订单的菜品列表(含菜品标签)
-            List<StoreOrderDetail> orderDetails = detailsMap.getOrDefault(order.getId(), new ArrayList<>());
-            List<OrderCuisineItemVO> cuisineItems = orderDetails.stream()
-                    .map(detail -> {
-                        OrderCuisineItemVO item = new OrderCuisineItemVO();
-                        item.setCuisineId(detail.getCuisineId());
-                        item.setCuisineName(detail.getCuisineName());
-                        item.setCuisineImage(detail.getCuisineImage());
-                        item.setQuantity(detail.getQuantity());
-                        item.setUnitPrice(detail.getUnitPrice());
-                        item.setTags(detail.getCuisineId() != null ? finalCuisineIdToTagsMy.get(detail.getCuisineId()) : null);
-                        return item;
-                    })
-                    .collect(Collectors.toList());
-            vo.setCuisineItems(cuisineItems);
-
-            return vo;
-        }).collect(Collectors.toList());
-
-        // 7. 构建分页结果
-        Page<StoreOrderPageVO> resultPage = new Page<>(page.getCurrent(), page.getSize());
-        resultPage.setRecords(voList);
-        resultPage.setTotal(orderPage.getTotal());
-        resultPage.setPages(orderPage.getPages());
-
-        return resultPage;
-    }
-
-    @Override
-    public OrderInfoVO getOrderInfo(Integer orderId) {
-        log.info("查询订单信息, orderId={}", orderId);
-        
-        // 1. 查询订单基本信息
-        StoreOrder order = this.getById(orderId);
-        if (order == null || order.getDeleteFlag() == 1) {
-            throw new RuntimeException("订单不存在");
-        }
-        
-        // 2. 查询订单明细(菜品清单)
-        LambdaQueryWrapper<StoreOrderDetail> detailWrapper = new LambdaQueryWrapper<>();
-        detailWrapper.eq(StoreOrderDetail::getOrderId, orderId);
-        detailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
-        detailWrapper.orderByDesc(StoreOrderDetail::getCreatedTime);
-        List<StoreOrderDetail> details = orderDetailMapper.selectList(detailWrapper);
-        
-        // 批量查询菜品标签(订单明细无 tags,从价目表取)
-        java.util.Set<Integer> cuisineIds = details.stream()
-                .map(StoreOrderDetail::getCuisineId)
-                .filter(java.util.Objects::nonNull)
-                .collect(Collectors.toSet());
-        java.util.Map<Integer, String> cuisineIdToTags = new java.util.HashMap<>();
-        if (!cuisineIds.isEmpty()) {
-            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(cuisineIds);
-            if (cuisines != null) {
-                for (StoreCuisine c : cuisines) {
-                    cuisineIdToTags.put(c.getId(), c.getTags());
-                }
-            }
-        }
-        final java.util.Map<Integer, String> tagsMap = cuisineIdToTags;
-        
-        // 转换为CartItemDTO(含 tags)
-        List<CartItemDTO> items = details.stream().map(detail -> {
-            CartItemDTO item = new CartItemDTO();
-            item.setCuisineId(detail.getCuisineId());
-            item.setCuisineName(detail.getCuisineName());
-            item.setCuisineType(detail.getCuisineType());
-            item.setCuisineImage(detail.getCuisineImage());
-            item.setUnitPrice(detail.getUnitPrice());
-            item.setQuantity(detail.getQuantity());
-            item.setSubtotalAmount(detail.getSubtotalAmount());
-            item.setAddUserId(detail.getAddUserId());
-            item.setAddUserPhone(detail.getAddUserPhone());
-            item.setRemark(detail.getRemark());
-            item.setTags(detail.getCuisineId() != null ? tagsMap.get(detail.getCuisineId()) : null);
-            return item;
-        }).collect(Collectors.toList());
-        
-        // 3. 查询门店信息
-        StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
-        String storeName = "";
-        String storeTel = "";
-        String storeAddress = "";
-        String storeBlurb = "";
-        String storeType = "";
-        Integer businessStatus = null;
-        if (storeInfo != null) {
-            storeName = storeInfo.getStoreName();
-            storeTel = storeInfo.getStoreTel();
-            storeAddress = storeInfo.getStoreAddress();
-            storeBlurb = storeInfo.getStoreBlurb();
-            storeType = storeInfo.getStoreType();
-            businessStatus = storeInfo.getBusinessStatus();
-        }
-
-        // 4. 查询优惠券信息(如果有)
-        String couponName = null;
-        Integer couponType = null;
-        BigDecimal discountRate = null;
-        BigDecimal nominalValue = null;
-        BigDecimal minimumSpendingAmount = null;
-        if (order.getCouponId() != null) {
-            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
-            if (coupon != null) {
-                couponName = coupon.getName();
-                couponType = coupon.getCouponType();
-                discountRate = coupon.getDiscountRate();
-                nominalValue = coupon.getNominalValue();
-                minimumSpendingAmount = coupon.getMinimumSpendingAmount();
-            }
-        }
-
-        // 5. 组装OrderInfoVO
-        OrderInfoVO vo = new OrderInfoVO();
-        vo.setOrderId(order.getId());
-        vo.setOrderNo(order.getOrderNo());
-        vo.setStoreId(order.getStoreId());
-        vo.setStoreName(storeName);
-        vo.setStoreTel(storeTel);
-        vo.setStoreAddress(storeAddress);
-        vo.setStoreBlurb(storeBlurb);
-        vo.setStoreType(storeType);
-        vo.setBusinessStatus(businessStatus);
-        vo.setTableNumber(order.getTableNumber());
-        vo.setDinerCount(order.getDinerCount());
-        vo.setContactPhone(order.getContactPhone());
-        vo.setRemark(order.getRemark());
-        vo.setItems(items);
-        vo.setTotalAmount(order.getTotalAmount());
-        vo.setTablewareFee(order.getTablewareFee());
-        vo.setCouponId(order.getCouponId());
-        vo.setCouponName(couponName);
-        vo.setCouponType(couponType);
-        vo.setDiscountRate(discountRate);
-        vo.setNominalValue(nominalValue);
-        vo.setMinimumSpendingAmount(minimumSpendingAmount);
-        vo.setDiscountAmount(order.getDiscountAmount());
-        vo.setPayAmount(order.getPayAmount());
-        vo.setOrderStatus(order.getOrderStatus());
-        vo.setPayStatus(order.getPayStatus());
-        vo.setPayType(order.getPayType());
-        vo.setCreatedTime(order.getCreatedTime());
-        vo.setPayTime(order.getPayTime());
-        
-        log.info("查询订单信息完成, orderId={}, itemCount={}", orderId, items.size());
-        return vo;
-    }
-
-    @Override
-    public List<OrderChangeLogBatchVO> getOrderChangeLogs(Integer orderId) {
-        log.info("查询订单变更记录, orderId={}", orderId);
-        
-        // 1. 查询订单的所有变更记录
-        LambdaQueryWrapper<StoreOrderChangeLog> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StoreOrderChangeLog::getOrderId, orderId);
-        wrapper.eq(StoreOrderChangeLog::getDeleteFlag, 0);
-        wrapper.orderByAsc(StoreOrderChangeLog::getOperationTime);
-        wrapper.orderByAsc(StoreOrderChangeLog::getBatchNo);
-        List<StoreOrderChangeLog> logs = orderChangeLogMapper.selectList(wrapper);
-        
-        if (logs == null || logs.isEmpty()) {
-            log.info("订单没有变更记录, orderId={}", orderId);
-            return new ArrayList<>();
-        }
-        
-        // 2. 按批次号分组
-        Map<String, List<StoreOrderChangeLog>> batchMap = logs.stream()
-                .collect(Collectors.groupingBy(StoreOrderChangeLog::getBatchNo));
-        
-        // 2.1 批量查询菜品标签(用于订单详情展示)
-        Set<Integer> cuisineIds = logs.stream()
-                .map(StoreOrderChangeLog::getCuisineId)
-                .filter(Objects::nonNull)
-                .collect(Collectors.toSet());
-        Map<Integer, String> cuisineIdToTags = new HashMap<>();
-        if (!cuisineIds.isEmpty()) {
-            List<StoreCuisine> cuisines = storeCuisineMapper.selectBatchIds(new ArrayList<>(cuisineIds));
-            if (cuisines != null) {
-                for (StoreCuisine c : cuisines) {
-                    if (c.getTags() != null) {
-                        cuisineIdToTags.put(c.getId(), c.getTags());
-                    }
-                }
-            }
-        }
-        
-        // 3. 转换为批次VO列表
-        List<OrderChangeLogBatchVO> batchList = new ArrayList<>();
-        for (Map.Entry<String, List<StoreOrderChangeLog>> entry : batchMap.entrySet()) {
-            String batchNo = entry.getKey();
-            List<StoreOrderChangeLog> batchLogs = entry.getValue();
-            
-            if (batchLogs.isEmpty()) {
-                continue;
-            }
-            
-            // 取第一条记录作为批次信息(同一批次的操作类型、时间等信息相同)
-            StoreOrderChangeLog firstLog = batchLogs.get(0);
-            
-            OrderChangeLogBatchVO batchVO = new OrderChangeLogBatchVO();
-            batchVO.setBatchNo(batchNo);
-            batchVO.setOperationType(firstLog.getOperationType());
-            batchVO.setOperationTypeText(getOperationTypeText(firstLog.getOperationType()));
-            batchVO.setOperationTime(firstLog.getOperationTime());
-            batchVO.setOperatorUserId(firstLog.getOperatorUserId());
-            batchVO.setOperatorUserPhone(firstLog.getOperatorUserPhone());
-            batchVO.setRemark(firstLog.getRemark());
-            
-            // 计算批次统计信息
-            Integer totalQuantityChange = batchLogs.stream()
-                    .mapToInt(log -> log.getQuantityChange() != null ? log.getQuantityChange() : 0)
-                    .sum();
-            BigDecimal totalAmountChange = batchLogs.stream()
-                    .map(log -> log.getAmountChange() != null ? log.getAmountChange() : BigDecimal.ZERO)
-                    .reduce(BigDecimal.ZERO, BigDecimal::add);
-            
-            batchVO.setTotalQuantityChange(totalQuantityChange);
-            batchVO.setTotalAmountChange(totalAmountChange);
-            batchVO.setItemCount(batchLogs.size());
-            
-            // 转换为商品项VO列表(含菜品标签)
-            Map<Integer, String> finalCuisineIdToTags = cuisineIdToTags;
-            List<OrderChangeLogItemVO> items = batchLogs.stream().map(log -> {
-                OrderChangeLogItemVO itemVO = new OrderChangeLogItemVO();
-                itemVO.setCuisineId(log.getCuisineId());
-                itemVO.setCuisineName(log.getCuisineName());
-                itemVO.setCuisineType(log.getCuisineType());
-                itemVO.setCuisineImage(log.getCuisineImage());
-                itemVO.setUnitPrice(log.getUnitPrice());
-                itemVO.setQuantityChange(log.getQuantityChange());
-                itemVO.setQuantityBefore(log.getQuantityBefore());
-                itemVO.setQuantityAfter(log.getQuantityAfter());
-                itemVO.setAmountChange(log.getAmountChange());
-                itemVO.setRemark(log.getRemark());
-                itemVO.setTags(log.getCuisineId() != null ? finalCuisineIdToTags.get(log.getCuisineId()) : null);
-                return itemVO;
-            }).collect(Collectors.toList());
-            
-            batchVO.setItems(items);
-            batchList.add(batchVO);
-        }
-        
-        log.info("查询订单变更记录完成, orderId={}, batchCount={}", orderId, batchList.size());
-        return batchList;
-    }
-
-    @Override
-    public OrderDetailWithChangeLogVO getOrderDetailWithChangeLog(Integer orderId) {
-        log.info("查询订单详情(包含变更记录), orderId={}", orderId);
-
-        // 1. 查询订单基本信息
-        StoreOrder order = this.getById(orderId);
-        if (order == null || order.getDeleteFlag() == 1) {
-            throw new RuntimeException("订单不存在");
-        }
-
-        // 2. 查询门店信息
-        StoreInfo storeInfo = storeInfoMapper.selectById(order.getStoreId());
-        String storeName = storeInfo != null ? storeInfo.getStoreName() : "";
-
-        // 3. 查询优惠券信息(如果有)
-        String couponName = null;
-        if (order.getCouponId() != null) {
-            LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
-            if (coupon != null) {
-                couponName = coupon.getName();
-            }
-        }
-
-        // 4. 查询订单变更记录(按批次分组)
-        List<OrderChangeLogBatchVO> changeLogBatches = getOrderChangeLogs(orderId);
-
-        // 5. 组装OrderDetailWithChangeLogVO
-        OrderDetailWithChangeLogVO vo = new OrderDetailWithChangeLogVO();
-        vo.setOrderId(order.getId());
-        vo.setOrderNo(order.getOrderNo());
-        vo.setStoreName(storeName);
-        vo.setTableNumber(order.getTableNumber());
-        vo.setDinerCount(order.getDinerCount());
-        vo.setContactPhone(order.getContactPhone());
-        vo.setRemark(order.getRemark());
-        vo.setTotalAmount(order.getTotalAmount());
-        vo.setTablewareFee(order.getTablewareFee());
-        vo.setCouponId(order.getCouponId());
-        vo.setCouponName(couponName);
-        vo.setDiscountAmount(order.getDiscountAmount());
-        vo.setPayAmount(order.getPayAmount());
-        vo.setOrderStatus(order.getOrderStatus());
-        vo.setPayStatus(order.getPayStatus());
-        vo.setPayType(order.getPayType());
-        vo.setCreatedTime(order.getCreatedTime());
-        vo.setPayTime(order.getPayTime());
-        vo.setChangeLogBatches(changeLogBatches);
-
-        log.info("查询订单详情(包含变更记录)完成, orderId={}, batchCount={}", orderId, changeLogBatches.size());
-        return vo;
-    }
-    
-    /**
-     * 获取操作类型文本
-     */
-    private String getOperationTypeText(Integer operationType) {
-        if (operationType == null) {
-            return "未知";
-        }
-        switch (operationType) {
-            case 1:
-                return "首次下单";
-            case 3:
-                return "更新订单";
-            default:
-                return "未知";
-        }
-    }
-
-    /**
-     * 记录订单变更日志
-     *
-     * @param orderId 订单ID
-     * @param orderNo 订单号
-     * @param items 商品列表
-     * @param operationType 操作类型(1:首次下单, 3:更新订单)
-     * @param operationTime 操作时间
-     * @param userId 操作人ID
-     * @param userPhone 操作人手机号
-     */
-    private void recordOrderChangeLog(Integer orderId, String orderNo, List<shop.alien.entity.store.dto.CartItemDTO> items,
-                                      Integer operationType, Date operationTime, Integer userId, String userPhone) {
-        if (items == null || items.isEmpty()) {
-            log.warn("商品列表为空,不记录变更日志, orderId={}", orderId);
-            return;
-        }
-
-        // 生成批次号:ORDER{orderId}_{yyyyMMddHHmmss}
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
-        String timestamp = sdf.format(operationTime);
-        String batchNo = "ORDER" + orderId + "_" + timestamp;
-
-        List<StoreOrderChangeLog> changeLogs = new ArrayList<>();
-
-        for (shop.alien.entity.store.dto.CartItemDTO item : items) {
-            Integer lockedQuantity = item.getLockedQuantity(); // 已下单数量
-            Integer currentQuantity = item.getQuantity(); // 当前数量
-            Integer quantityChange = 0; // 数量变化
-            Integer quantityBefore = 0; // 变化前数量
-            Integer quantityAfter = 0; // 变化后数量
-
-            if (operationType == 1) {
-                // 首次下单:记录所有商品
-                quantityBefore = 0;
-                quantityAfter = currentQuantity != null ? currentQuantity : 0;
-                quantityChange = quantityAfter;
-            } else if (operationType == 3) {
-                // 更新订单:只记录新增的商品或数量增加的商品
-                if (lockedQuantity == null || lockedQuantity == 0) {
-                    // 新增商品
-                    quantityBefore = 0;
-                    quantityAfter = currentQuantity != null ? currentQuantity : 0;
-                    quantityChange = quantityAfter;
-                } else if (currentQuantity != null && currentQuantity > lockedQuantity) {
-                    // 数量增加
-                    quantityBefore = lockedQuantity;
-                    quantityAfter = currentQuantity;
-                    quantityChange = quantityAfter - quantityBefore;
-                } else {
-                    // 没有变化,跳过
-                    continue;
-                }
-            }
-
-            // 只记录有数量变化的商品
-            if (quantityChange == null || quantityChange == 0) {
-                continue;
-            }
-
-            // 计算金额变化
-            BigDecimal amountChange = item.getUnitPrice() != null
-                    ? item.getUnitPrice().multiply(BigDecimal.valueOf(quantityChange))
-                    : BigDecimal.ZERO;
-
-            StoreOrderChangeLog changeLog = new StoreOrderChangeLog();
-            changeLog.setOrderId(orderId);
-            changeLog.setOrderNo(orderNo);
-            changeLog.setBatchNo(batchNo);
-            changeLog.setOperationType(operationType);
-            changeLog.setCuisineId(item.getCuisineId());
-            changeLog.setCuisineName(item.getCuisineName());
-            changeLog.setCuisineType(item.getCuisineType());
-            changeLog.setCuisineImage(item.getCuisineImage());
-            changeLog.setUnitPrice(item.getUnitPrice());
-            changeLog.setQuantityChange(quantityChange);
-            changeLog.setQuantityBefore(quantityBefore);
-            changeLog.setQuantityAfter(quantityAfter);
-            changeLog.setAmountChange(amountChange);
-            changeLog.setOperationTime(operationTime);
-            changeLog.setOperatorUserId(userId);
-            changeLog.setOperatorUserPhone(userPhone);
-            changeLog.setRemark(item.getRemark());
-            changeLog.setCreatedUserId(userId);
-            changeLog.setCreatedTime(operationTime);
-            changeLog.setUpdatedTime(operationTime);
-
-            changeLogs.add(changeLog);
-        }
-
-        // 批量插入变更记录(使用 MyBatis-Plus 的批量插入)
-        if (!changeLogs.isEmpty()) {
-            // 使用循环插入(MyBatis-Plus 的 BaseMapper 没有批量插入方法,需要手动实现或使用 ServiceImpl 的 saveBatch)
-            // 注意:如果变更记录数量很大,可以考虑使用 MyBatis 的批量插入
-            for (StoreOrderChangeLog log : changeLogs) {
-                orderChangeLogMapper.insert(log);
-            }
-            log.info("记录订单变更日志完成, orderId={}, batchNo={}, operationType={}, itemCount={}",
-                    orderId, batchNo, operationType, changeLogs.size());
-        } else {
-            log.warn("没有需要记录的变更, orderId={}, operationType={}", orderId, operationType);
-        }
-    }
-
-    /**
-     * 生成订单号
-     */
-    private String generateOrderNo() {
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
-        String timestamp = sdf.format(new Date());
-        String random = String.valueOf((int) (Math.random() * 10000));
-        return "ORD" + timestamp + String.format("%04d", Integer.parseInt(random));
-    }
-
-
-    @Override
-    public void migrateTableData(Integer fromTableId, Integer toTableId, Integer userId) {
-        log.info("换桌迁移数据, fromTableId={}, toTableId={}, userId={}", fromTableId, toTableId, userId);
-
-        // 1. 查询原桌号信息
-        StoreTable fromTable = storeTableMapper.selectById(fromTableId);
-        if (fromTable == null) {
-            throw new RuntimeException("原桌号不存在");
-        }
-
-        // 2. 查询目标桌号信息
-        StoreTable toTable = storeTableMapper.selectById(toTableId);
-        if (toTable == null) {
-            throw new RuntimeException("目标桌号不存在");
-        }
-
-        // 3. 迁移未完成的订单(orderStatus=0 且 payStatus=0)
-        if (fromTable.getCurrentOrderId() != null) {
-            StoreOrder pendingOrder = this.getById(fromTable.getCurrentOrderId());
-            if (pendingOrder != null && pendingOrder.getOrderStatus() == 0 && pendingOrder.getPayStatus() == 0) {
-                // 更新订单的桌号信息
-                pendingOrder.setTableId(toTableId);
-                pendingOrder.setTableNumber(toTable.getTableNumber());
-                pendingOrder.setUpdatedUserId(userId);
-                pendingOrder.setUpdatedTime(new Date());
-                this.updateById(pendingOrder);
-                log.info("迁移未完成订单, orderId={}, fromTableId={}, toTableId={}", pendingOrder.getId(), fromTableId, toTableId);
-
-                // 更新订单明细的订单号(如果需要,但通常订单号不变,所以这里只更新 table_id 关联)
-                // 订单明细通过 order_id 关联,不需要单独更新
-            }
-        }
-
-        // 4. 迁移所有未完成的订单(包括可能存在的其他未完成订单)
-        LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
-        orderWrapper.eq(StoreOrder::getTableId, fromTableId);
-        orderWrapper.eq(StoreOrder::getOrderStatus, 0); // 待支付
-        orderWrapper.eq(StoreOrder::getPayStatus, 0); // 未支付
-        orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
-        List<StoreOrder> pendingOrders = this.list(orderWrapper);
-        
-        if (pendingOrders != null && !pendingOrders.isEmpty()) {
-            for (StoreOrder order : pendingOrders) {
-                order.setTableId(toTableId);
-                order.setTableNumber(toTable.getTableNumber());
-                order.setUpdatedUserId(userId);
-                order.setUpdatedTime(new Date());
-            }
-            this.updateBatchById(pendingOrders);
-            log.info("迁移未完成订单, count={}, fromTableId={}, toTableId={}", pendingOrders.size(), fromTableId, toTableId);
-        }
-
-        // 5. 迁移优惠券使用记录
-        LambdaQueryWrapper<StoreCouponUsage> couponUsageWrapper = new LambdaQueryWrapper<>();
-        couponUsageWrapper.eq(StoreCouponUsage::getTableId, fromTableId);
-        couponUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
-        couponUsageWrapper.in(StoreCouponUsage::getUsageStatus, 0, 1, 2); // 已标记使用、已下单、已支付
-        List<StoreCouponUsage> couponUsages = storeCouponUsageMapper.selectList(couponUsageWrapper);
-        
-        if (couponUsages != null && !couponUsages.isEmpty()) {
-            Date now = new Date();
-            for (StoreCouponUsage usage : couponUsages) {
-                usage.setFromTableId(fromTableId);
-                usage.setTableId(toTableId);
-                usage.setMigrateTime(now);
-                usage.setUpdatedUserId(userId);
-                usage.setUpdatedTime(now);
-            }
-            // 批量更新
-            for (StoreCouponUsage usage : couponUsages) {
-                storeCouponUsageMapper.updateById(usage);
-            }
-            log.info("迁移优惠券使用记录, count={}, fromTableId={}, toTableId={}", couponUsages.size(), fromTableId, toTableId);
-        }
-
-        // 6. 更新桌号表的关联信息
-        // 原桌号:清空 currentOrderId 和 currentCouponId
-        LambdaUpdateWrapper<StoreTable> fromTableWrapper = new LambdaUpdateWrapper<>();
-        fromTableWrapper.eq(StoreTable::getId, fromTableId)
-                .set(StoreTable::getCurrentOrderId, null)
-                .set(StoreTable::getCurrentCouponId, null)
-                .set(StoreTable::getUpdatedTime, new Date());
-        if (userId != null) {
-            fromTableWrapper.set(StoreTable::getUpdatedUserId, userId);
-        }
-        storeTableMapper.update(null, fromTableWrapper);
-        log.info("清空原桌号关联信息, fromTableId={}", fromTableId);
-
-        // 目标桌号:设置 currentOrderId 和 currentCouponId(如果有)
-        if (fromTable.getCurrentOrderId() != null || fromTable.getCurrentCouponId() != null) {
-            LambdaUpdateWrapper<StoreTable> toTableWrapper = new LambdaUpdateWrapper<>();
-            toTableWrapper.eq(StoreTable::getId, toTableId);
-            
-            if (fromTable.getCurrentOrderId() != null) {
-                toTableWrapper.set(StoreTable::getCurrentOrderId, fromTable.getCurrentOrderId());
-            }
-            if (fromTable.getCurrentCouponId() != null) {
-                toTableWrapper.set(StoreTable::getCurrentCouponId, fromTable.getCurrentCouponId());
-            }
-            toTableWrapper.set(StoreTable::getUpdatedTime, new Date());
-            if (userId != null) {
-                toTableWrapper.set(StoreTable::getUpdatedUserId, userId);
-            }
-            storeTableMapper.update(null, toTableWrapper);
-            log.info("设置目标桌号关联信息, toTableId={}, currentOrderId={}, currentCouponId={}", 
-                    toTableId, fromTable.getCurrentOrderId(), fromTable.getCurrentCouponId());
-        }
-
-        log.info("换桌数据迁移完成, fromTableId={}, toTableId={}", fromTableId, toTableId);
-    }
-
-    @Override
-    public shop.alien.entity.store.dto.CartDTO changeTable(Integer fromTableId, Integer toTableId, String changeReason, Integer userId) {
-        log.info("换桌, fromTableId={}, toTableId={}, changeReason={}, userId={}", fromTableId, toTableId, changeReason, userId);
-
-        // 0. 校验:目标桌只能是空桌(空闲且无当前订单)
-        if (fromTableId.equals(toTableId)) {
-            throw new RuntimeException("原桌号与目标桌号不能相同");
-        }
-        StoreTable fromTable = storeTableMapper.selectById(fromTableId);
-        if (fromTable == null) {
-            throw new RuntimeException("原桌号不存在");
-        }
-        StoreTable toTable = storeTableMapper.selectById(toTableId);
-        if (toTable == null) {
-            throw new RuntimeException("目标桌号不存在");
-        }
-        if (!fromTable.getStoreId().equals(toTable.getStoreId())) {
-            throw new RuntimeException("原桌号与目标桌号须在同一门店");
-        }
-        // 空桌:状态为空闲(0)且无当前订单
-        boolean emptyStatus = (toTable.getStatus() == null || toTable.getStatus() == 0);
-        boolean noOrder = (toTable.getCurrentOrderId() == null);
-        if (!emptyStatus || !noOrder) {
-            throw new RuntimeException("只能换到空桌,请选择空闲且无订单的桌号");
-        }
-
-        // 1. 迁移购物车
-        shop.alien.entity.store.dto.CartDTO cart = cartService.migrateCart(fromTableId, toTableId);
-
-        // 2. 迁移所有关联数据(订单、订单变更记录、优惠券使用记录等)
-        migrateTableData(fromTableId, toTableId, userId);
-
-        // 3. 记录换桌日志(fromTable、toTable 已在步骤0中查询)
-        Date now = new Date();
-        StoreTableLog tableLog = new StoreTableLog();
-        tableLog.setStoreId(cart.getStoreId());
-        tableLog.setOrderId(fromTable.getCurrentOrderId()); // 有订单则记录,仅购物车换桌时为 null
-        tableLog.setFromTableId(fromTableId);
-        tableLog.setFromTableNumber(fromTable != null ? fromTable.getTableNumber() : null);
-        tableLog.setToTableId(toTableId);
-        tableLog.setToTableNumber(toTable != null ? toTable.getTableNumber() : null);
-        tableLog.setChangeReason(changeReason);
-        tableLog.setCreatedUserId(userId);
-        tableLog.setCreatedTime(now);
-        tableLog.setUpdatedTime(now);
-        tableLog.setUpdatedUserId(userId);
-        storeTableLogMapper.insert(tableLog);
-
-        // 4. 推送购物车更新消息到新桌号
-        sseService.pushCartUpdate(toTableId, cart);
-
-        log.info("换桌完成, fromTableId={}, toTableId={}", fromTableId, toTableId);
-        return cart;
-    }
-
-    /**
-     * 验证订单是否存在且状态正确(用于支付、取消、加餐、更新优惠券等操作)
-     *
-     * @param orderId      订单ID
-     * @param expectedStatus 期望的订单状态(null表示不校验状态)
-     * @param operation    操作名称(用于错误提示)
-     * @return 订单对象
-     */
-    private StoreOrder validateOrderForOperation(Integer orderId, Integer expectedStatus, String operation) {
-        StoreOrder order = this.getById(orderId);
-        if (order == null) {
-            throw new RuntimeException("订单不存在");
-        }
-        if (expectedStatus != null && order.getOrderStatus() != expectedStatus) {
-            throw new RuntimeException("订单状态不正确,无法" + operation);
-        }
-        return order;
-    }
-
-    /**
-     * 获取当前登录用户信息
-     *
-     * @return 用户ID和手机号的数组 [userId, userPhone]
-     */
-    private Object[] getCurrentUserInfo() {
-        Integer userId = TokenUtil.getCurrentUserId();
-        String userPhone = TokenUtil.getCurrentUserPhone();
-        if (userId == null) {
-            throw new RuntimeException("用户未登录");
-        }
-        return new Object[]{userId, userPhone};
-    }
-
-    /**
-     * 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
-     *
-     * @param coupon           优惠券对象
-     * @param totalWithTableware 订单总金额(含餐具费)
-     * @return 优惠金额
-     */
-    private BigDecimal calculateDiscountAmount(LifeDiscountCoupon coupon, BigDecimal totalWithTableware) {
-        if (coupon == null || totalWithTableware == null || totalWithTableware.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-
-        Integer couponType = coupon.getCouponType();
-        BigDecimal discountAmount = BigDecimal.ZERO;
-
-        if (couponType != null && couponType == 2) {
-            // 折扣券:根据折扣率计算优惠金额
-            // discountRate: 0-100,例如80表示8折,优惠金额 = 订单金额 * (100 - discountRate) / 100
-            BigDecimal discountRate = coupon.getDiscountRate();
-            if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 && discountRate.compareTo(new BigDecimal(100)) <= 0) {
-                // 计算折扣后的金额
-                BigDecimal discountedAmount = totalWithTableware.multiply(discountRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
-                // 优惠金额 = 原价 - 折扣后价格
-                discountAmount = totalWithTableware.subtract(discountedAmount);
-            }
-        } else {
-            // 满减券(默认或couponType=1):使用nominalValue
-            discountAmount = coupon.getNominalValue();
-            if (discountAmount == null) {
-                discountAmount = BigDecimal.ZERO;
-            }
-            // 优惠金额不能超过订单总金额
-            if (discountAmount.compareTo(totalWithTableware) > 0) {
-                discountAmount = totalWithTableware;
-            }
-        }
-
-        return discountAmount;
-    }
-
-}

+ 0 - 75
alien-store/src/main/java/shop/alien/store/dining/strategy/payment/PaymentStrategy.java

@@ -1,75 +0,0 @@
-package shop.alien.store.dining.strategy.payment;
-
-import shop.alien.entity.result.R;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Map;
-
-/**
- * 支付策略接口
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-public interface PaymentStrategy {
-    /** 生成预支付订单(本系统调用时需传 storeId 以从 MySQL 获取店铺支付配置)
-     *
-     * @param price 订单金额
-     * @param subject 订单标题
-     * @param payer 支付者 openid
-     * @param orderNo 订单号
-     * @param storeId 店铺ID,本系统调用时必传,用于获取 StorePaymentConfig
-     * @return 预支付订单信息
-     * @throws Exception 生成异常
-     */
-    R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId, Integer couponId, Integer payerId,String tablewareFee,String discountAmount,String payAmount) throws Exception;
-
-
-    /**
-     * 处理支付通知
-     *
-     * @param notifyData 支付通知数据
-     * @return 处理结果
-     * @throws Exception 处理异常
-     */
-    R handleNotify(String notifyData, HttpServletRequest request) throws Exception;
-
-    /**
-     * 查询订单状态(本系统调用时需传 storeId 以获取店铺支付配置)
-     *
-     * @param transactionId 交易订单号
-     * @param storeId 店铺ID,本系统调用时必传
-     * @return 订单状态信息
-     * @throws Exception 查询异常
-     */
-    R searchOrderByOutTradeNoPath(String transactionId, Integer storeId) throws Exception;
-
-    /**
-     * 处理退款请求
-     *
-     * @param params 退款请求参数
-     * @return 处理结果
-     * @throws Exception 处理异常
-     */
-    String handleRefund(Map<String,String> params) throws Exception;
-
-    /**
-     * 查询退款记录(本系统调用时需传 storeId 以获取店铺支付配置)
-     *
-     * @param outRefundNo 退款订单号
-     * @param storeId 店铺ID,本系统调用时必传
-     * @return 退款记录信息
-     * @throws Exception 查询异常
-     */
-    R searchRefundRecordByOutRefundNo(String outRefundNo, Integer storeId) throws Exception;
-
-
-    /**
-     * 获取策略类型字符串
-     *
-     * @return 策略类型字符串
-     */
-    String getType();
-}
-

+ 0 - 64
alien-store/src/main/java/shop/alien/store/dining/strategy/payment/PaymentStrategyFactory.java

@@ -1,64 +0,0 @@
-package shop.alien.store.dining.strategy.payment;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PostConstruct;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 支付策略工厂
- *
- * @author lyx
- * @date 2025/11/20
- */
-@Slf4j
-@Component
-public class PaymentStrategyFactory {
-
-    @Autowired
-    private List<PaymentStrategy> paymentStrategies;
-
-    private final Map<String, PaymentStrategy> strategyMap = new HashMap<>();
-
-        /**
-         * 初始化策略映射
-         */
-        @PostConstruct
-        public void init() {
-            if (paymentStrategies != null && !paymentStrategies.isEmpty()) {
-                for (PaymentStrategy strategy : paymentStrategies) {
-                    strategyMap.put(strategy.getType(), strategy);
-                    log.info("注册支付策略: {} -> {}", strategy.getType(), strategy.getClass().getSimpleName());
-                }
-            }
-        }
-
-    /**
-     * 根据类型获取OCR策略
-     *
-     * @param type OCR类型
-     * @return OCR策略实例
-     * @throws IllegalArgumentException 如果类型不存在
-     */
-    public PaymentStrategy getStrategy(String type) {
-        PaymentStrategy strategy = strategyMap.get(type);
-        if (strategy == null) {
-            throw new IllegalArgumentException("不支持的支付类型: " + type);
-        }
-        return strategy;
-    }
-
-    /**
-     * 检查是否支持指定的OCR类型
-     *
-     * @param type OCR类型
-     * @return 是否支持
-     */
-    public boolean supports(String type) {
-        return strategyMap.containsKey(type);
-    }
-}

+ 0 - 850
alien-store/src/main/java/shop/alien/store/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java

@@ -1,850 +0,0 @@
-package shop.alien.store.dining.strategy.payment.impl;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
-import com.wechat.pay.java.service.refund.model.Refund;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import okhttp3.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
-import shop.alien.store.dining.service.StoreOrderService;
-import shop.alien.store.dining.strategy.payment.PaymentStrategy;
-import shop.alien.store.dining.util.WXPayUtility;
-import shop.alien.store.dining.util.WeChatPayUtil;
-import shop.alien.entity.result.R;
-import shop.alien.entity.store.LifeDiscountCouponUser;
-import shop.alien.entity.store.StoreOrder;
-import shop.alien.entity.store.StorePaymentConfig;
-import shop.alien.mapper.LifeDiscountCouponUserMapper;
-import shop.alien.mapper.StorePaymentConfigMapper;
-import shop.alien.util.common.constant.DiscountCouponEnum;
-import shop.alien.util.common.constant.PaymentEnum;
-
-import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.math.BigDecimal;
-import java.nio.charset.StandardCharsets;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Signature;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-
-
-/**
- * 微信支付小程序策略
- *
- * @author lyx
- * @date 2025/11/20
- */
-
-@Slf4j
-@Component
-@RequiredArgsConstructor
-@RefreshScope
-public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
-    /**
-     * 微信支付api主机地址
-     */
-    @Value("${payment.wechatPay.host}")
-    private String wechatPayApiHost;
-    /**
-     * 微信支付预支付路径
-     */
-    @Value("${payment.wechatPay.business.miniProgram.prePayPath:/v3/pay/transactions/jsapi}")
-    private String prePayPath;
-    /**
-     * 微信支付预支付通知路径
-     */
-    @Value("${payment.wechatPay.business.miniProgram.prePayNotifyUrl:https://frp-way.com:12473/aliendining/payment/weChatMininNotify}")
-    private String prePayNotifyUrl;
-    /**
-     * 微信支付退款通知路径
-     */
-    @Value("${payment.wechatPay.business.miniProgram.refundNotifyUrl:https://www.weixin.qq.com/wxpay/pay.php}")
-    private String refundNotifyUrl;
-    /**
-     * 微信支付查询退款状态路径
-     */
-    @Value("${payment.wechatPay.searchRefundStatusByOutRefundNoPath:/v3/refund/domestic/refunds/{out_refund_no}}")
-    private String searchRefundStatusByOutRefundNoPath;
-
-    @Value("${payment.wechatPay.searchOrderByOutTradeNoPath}")
-    private String searchOrderByOutTradeNoPath;
-
-    private final StoreOrderService storeOrderService;
-    private final StorePaymentConfigMapper storePaymentConfigMapper;
-    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
-    private final ObjectMapper objectMapper;
-
-    private static String POSTMETHOD = "POST";
-    private static String GETMETHOD = "GET";
-
-    /**
-     * 根据店铺ID从 MySQL 获取支付配置(本系统内部调用时使用)
-     */
-    private StorePaymentConfig getConfigByStoreId(Integer storeId) {
-        if (storeId == null) {
-            return null;
-        }
-        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StorePaymentConfig::getStoreId, storeId);
-        return storePaymentConfigMapper.selectOne(wrapper);
-    }
-
-    /**
-     * 根据微信支付公钥序列号获取支付配置(外部回调如支付通知时使用,通过请求头 Wechatpay-Serial 判断)
-     */
-    private StorePaymentConfig getConfigByWechatPayPublicKeyId(String wechatPayPublicKeyId) {
-        if (!StringUtils.hasText(wechatPayPublicKeyId)) {
-            return null;
-        }
-        LambdaQueryWrapper<StorePaymentConfig> wrapper = new LambdaQueryWrapper<>();
-        wrapper.eq(StorePaymentConfig::getWechatPayPublicKeyId, wechatPayPublicKeyId);
-        List<StorePaymentConfig> storePaymentConfigs = storePaymentConfigMapper.selectList(wrapper);
-        if (storePaymentConfigs.isEmpty()) {
-            return null;
-        }
-        return storePaymentConfigs.get(0);
-    }
-
-    /**
-     * 从 StorePaymentConfig 加载商户私钥
-     */
-    private PrivateKey loadPrivateKeyFromConfig(StorePaymentConfig config) {
-        if (config == null) {
-            return null;
-        }
-        if (config.getWechatPrivateKeyFile() != null && config.getWechatPrivateKeyFile().length > 0) {
-            String keyStr = new String(config.getWechatPrivateKeyFile(), StandardCharsets.UTF_8);
-            return WXPayUtility.loadPrivateKeyFromString(keyStr);
-        }
-        if (StringUtils.hasText(config.getWechatPrivateKeyPath())) {
-            return WXPayUtility.loadPrivateKeyFromPath(config.getWechatPrivateKeyPath());
-        }
-        return null;
-    }
-
-    /**
-     * 从 StorePaymentConfig 加载微信支付公钥
-     */
-    private PublicKey loadPublicKeyFromConfig(StorePaymentConfig config) {
-        if (config == null) {
-            return null;
-        }
-        if (config.getWechatPayPublicKeyFile() != null && config.getWechatPayPublicKeyFile().length > 0) {
-            String keyStr = new String(config.getWechatPayPublicKeyFile(), StandardCharsets.UTF_8);
-            return WXPayUtility.loadPublicKeyFromString(keyStr);
-        }
-        if (StringUtils.hasText(config.getWechatPayPublicKeyFilePath())) {
-            return WXPayUtility.loadPublicKeyFromPath(config.getWechatPayPublicKeyFilePath());
-        }
-        return null;
-    }
-
-    @Override
-    public R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId, Integer couponId, Integer payerId,String tablewareFee,String discountAmount,String payAmount) throws Exception {
-        // 本系统调用:通过 storeId 从 MySQL 获取店铺支付配置
-        if (storeId == null) {
-            log.warn("createPrePayOrder 缺少 storeId,无法获取支付配置");
-            return R.fail("店铺ID不能为空");
-        }
-        StorePaymentConfig config = getConfigByStoreId(storeId);
-        if (config == null) {
-            log.warn("未找到店铺支付配置 storeId={}", storeId);
-            return R.fail("未找到该店铺的微信支付配置");
-        }
-        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
-        if (privateKey == null) {
-            log.warn("createPrePayOrder, storeId: {}, error: {}", storeId, "店铺微信支付私钥未配置或加载失败");
-            return R.fail("店铺微信支付私钥未配置或加载失败");
-        }
-        String appId = config.getWechatMiniAppId() != null ? config.getWechatMiniAppId() : config.getWechatAppId();
-        if (!StringUtils.hasText(appId)) {
-            log.warn("createPrePayOrder, storeId: {}, error: {}", storeId, "店铺微信小程序 appId 未配置");
-            return R.fail("店铺微信小程序 appId 未配置");
-        }
-        String mchId = config.getWechatMchId();
-        if (!StringUtils.hasText(mchId)) {
-            log.warn("createPrePayOrder, 店铺微信支付商户号未配置");
-            return R.fail("店铺微信支付商户号未配置");
-        }
-
-        DirectAPIv3JsapiPrepayRequest request = new DirectAPIv3JsapiPrepayRequest();
-        request.appid = appId;
-        request.mchid = mchId;
-        request.description = subject;
-        request.notifyUrl = prePayNotifyUrl;
-        request.amount = new CommonAmountInfo();
-        request.amount.total = Long.parseLong(price);
-        request.payer = new JsapiReqPayerInfo();
-        request.payer.openid = payer;
-
-        String wechatOutTradeNo = orderNo;
-        StoreOrder storeOrder = storeOrderService.getOrderByOrderNo(orderNo);
-        log.info("createPrePayOrder, orderNo: {}, storeOrder: {}", orderNo, storeOrder);
-        if (storeOrder != null ) {
-            log.info("createPrePayOrder, orderNo: {}, storeOrder: {}", orderNo, storeOrder);
-            if (storeOrder.getPayStatus() != null && storeOrder.getPayStatus() == 1) {
-                return R.fail("订单已支付");
-            }
-            PublicKey publicKey = loadPublicKeyFromConfig(config);
-            if (publicKey == null) {
-                return R.fail("店铺微信支付公钥未配置或加载失败");
-            }
-            if(storeOrder.getPayTradeNo() != null) {
-                QueryByWxTradeNoRequest q = new QueryByWxTradeNoRequest();
-                q.transactionId = storeOrder.getPayTradeNo();
-                q.mchid = mchId;
-                try {
-                    DirectAPIv3QueryResponse wxOrder = searchOrderRun(q, config, privateKey, publicKey);
-                    if (wxOrder != null && "SUCCESS".equals(wxOrder.tradeState)) {
-                        return R.fail("该支付单已在微信侧支付成功,请勿重复发起支付");
-                    }
-                } catch (WXPayUtility.ApiException e) {
-                    if (e.getStatusCode() != 404 && !"ORDER_NOT_EXIST".equals(e.getErrorCode())) {
-                        log.error("预支付前查询微信订单失败 out_trade_no={}, status={}, code={}, msg={}",
-                                storeOrder.getPayTradeNo(), e.getStatusCode(), e.getErrorCode(), e.getErrorMessage());
-                        return R.fail("查询微信支付订单失败:" + (e.getErrorMessage() != null ? e.getErrorMessage() : e.getMessage()));
-                    }
-                }
-            }
-            String newPayTradeNo = "WX" + storeOrder.getId() + "_" + System.currentTimeMillis();
-            storeOrder.setPayTradeNo(newPayTradeNo);
-            wechatOutTradeNo = newPayTradeNo;
-            log.info("未支付场景已换新微信商户单号 orderNo={}, payTradeNo={}", orderNo, newPayTradeNo);
-            storeOrder.setCouponId(couponId);
-            storeOrder.setPayUserId(payerId);
-            storeOrder.setTablewareFee(new BigDecimal(tablewareFee));
-            storeOrder.setDiscountAmount(new BigDecimal(discountAmount));
-            storeOrder.setPayAmount(new BigDecimal(payAmount));
-            if (!storeOrderService.updateById(storeOrder)) {
-                log.error("更新订单失败 orderNo={}", orderNo);
-                return R.fail("更新订单失败");
-            }
-        }
-        request.outTradeNo = wechatOutTradeNo;
-
-        try {
-            DirectAPIv3JsapiPrepayResponse response = doCreatePrePayOrder(request, config, privateKey);
-            log.info("微信预支付订单创建成功,预支付ID:{}", response.prepayId);
-            Map<String, String> result = new HashMap<>();
-            response.prepayId = "prepay_id=" + response.prepayId;
-            result.put("prepayId", response.prepayId);
-            result.put("appId", appId);
-            result.put("mchId", mchId);
-            result.put("orderNo", request.outTradeNo);
-            long timestamp = System.currentTimeMillis() / 1000;
-            String nonce = WXPayUtility.createNonce(32);
-            String message = String.format("%s\n%s\n%s\n%s\n", appId, timestamp, nonce, response.prepayId);
-            Signature sign = Signature.getInstance("SHA256withRSA");
-            sign.initSign(privateKey);
-            sign.update(message.getBytes(StandardCharsets.UTF_8));
-            result.put("signType", "RSA");
-            result.put("sign", Base64.getEncoder().encodeToString(sign.sign()));
-            result.put("timestamp", String.valueOf(timestamp));
-            result.put("nonce", nonce);
-            result.put("transactionId", request.outTradeNo);
-            return R.data(result);
-        } catch (WXPayUtility.ApiException e) {
-            log.error("微信支付预支付失败,状态码:{},错误信息:{}", e.getErrorCode(), e.getMessage());
-            return R.fail(e.getMessage());
-        }
-    }
-
-    @Override
-    public R handleNotify(String notifyData, HttpServletRequest request) throws Exception {
-        log.info("[微信支付回调] 进入 handleNotify, notifyData 长度={}", notifyData != null ? notifyData.length() : 0);
-        // 外部回调:通过请求头 Wechatpay-Serial 从 MySQL 查找对应店铺的支付配置
-        String serial = request.getHeader("Wechatpay-Serial");
-        String signature = request.getHeader("Wechatpay-Signature");
-        String timestamp = request.getHeader("Wechatpay-Timestamp");
-        String nonce = request.getHeader("Wechatpay-Nonce");
-
-        if (serial == null || signature == null || timestamp == null || nonce == null) {
-            log.warn("微信支付回调验签失败:核心头参数缺失 serial={}, signature={}, timestamp={}, nonce={}",
-                    serial, signature, timestamp, nonce);
-            return R.fail("验签参数缺失");
-        }
-
-        if (signature.startsWith("WECHATPAY/SIGNTEST/")) {
-            log.info("[微信支付回调] 收到签名探测请求,直接应答成功");
-            return R.success("OK");
-        }
-
-        StorePaymentConfig config = getConfigByWechatPayPublicKeyId(serial);
-        if (config == null) {
-            log.warn("微信支付回调:未找到公钥序列号对应的店铺配置 serial={}", serial);
-            return R.fail("未找到对应支付配置");
-        }
-        PublicKey wechatPayPublicKey = loadPublicKeyFromConfig(config);
-        if (wechatPayPublicKey == null) {
-            log.warn("微信支付回调:加载公钥失败 serial={}", serial);
-            return R.fail("验签公钥加载失败");
-        }
-
-        StringBuilder signStr = new StringBuilder();
-        signStr.append(timestamp).append("\n");
-        signStr.append(nonce).append("\n");
-        signStr.append(notifyData).append("\n");
-        Signature sign = Signature.getInstance("SHA256withRSA");
-        byte[] signatureBytes = Base64.getDecoder().decode(signature);
-        sign.initVerify(wechatPayPublicKey);
-        sign.update(signStr.toString().getBytes(StandardCharsets.UTF_8));
-
-        if (sign.verify(signatureBytes)) {
-            final String notifyDataCopy = notifyData;
-            final StorePaymentConfig configCopy = config;
-            CompletableFuture.runAsync(() -> processNotifyBusiness(notifyDataCopy, configCopy));
-            return R.success("OK");
-        } else {
-            return R.fail("Verified error");
-        }
-    }
-
-    /**
-     * 异步处理回调业务:解密并更新订单状态(文档建议应答后再处理业务,避免超时)
-     * @param config 已通过 Wechatpay-Serial 解析得到的店铺支付配置,内含 apiV3Key
-     */
-    private void processNotifyBusiness(String notifyData, StorePaymentConfig config) {
-        try {
-            if (config == null || !StringUtils.hasText(config.getApiV3Key())) {
-                log.warn("微信支付回调:无可用 apiV3Key 无法解密");
-                return;
-            }
-            JsonNode rootNode = objectMapper.readTree(notifyData);
-            JsonNode resourceNode = rootNode.get("resource");
-            if (resourceNode == null) {
-                log.warn("微信支付回调报文无resource字段");
-                return;
-            }
-            String encryptAlgorithm = resourceNode.get("algorithm").asText();
-            String resourceNonce = resourceNode.get("nonce").asText();
-            String associatedData = resourceNode.has("associated_data") && !resourceNode.get("associated_data").isNull()
-                    ? resourceNode.get("associated_data").asText() : "";
-            String ciphertext = resourceNode.get("ciphertext").asText();
-            if (!"AEAD_AES_256_GCM".equals(encryptAlgorithm)) {
-                log.warn("不支持的加密算法:{}", encryptAlgorithm);
-                return;
-            }
-            String plainBusinessData = WeChatPayUtil.decrypt(
-                    config.getApiV3Key(), resourceNonce, associatedData, ciphertext);
-            log.info("微信支付回调解密后的业务信息:{}", plainBusinessData);
-            JSONObject jsonObject = JSONObject.parseObject(plainBusinessData);
-            String tradeState = jsonObject.getString("trade_state");
-            if ("SUCCESS".equals(tradeState)) {
-                String outTradeNo = jsonObject.getString("out_trade_no");
-                StoreOrder storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("order_no", outTradeNo));
-                if (storeOrder == null && StringUtils.hasText(outTradeNo)) {
-                    storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("pay_trade_no", outTradeNo));
-                }
-                if (storeOrder != null && storeOrder.getPayStatus() != 1) {
-                    storeOrder.setPayStatus(1);
-                    storeOrder.setOrderStatus(1);
-                    storeOrder.setPayType(1);
-                    storeOrder.setPayTime(new Date());
-                    if (storeOrderService.updateById(storeOrder)) {
-                        log.info("小程序更新订单成功,订单号outTradeNo:{}", outTradeNo);
-                        if (storeOrder.getCouponId() != null && storeOrder.getPayUserId() != null) {
-                            LambdaQueryWrapper<LifeDiscountCouponUser> couponUserWrapper = new LambdaQueryWrapper<>();
-                            couponUserWrapper.eq(LifeDiscountCouponUser::getUserId, storeOrder.getPayUserId());
-                            couponUserWrapper.eq(LifeDiscountCouponUser::getCouponId, storeOrder.getCouponId());
-                            couponUserWrapper.eq(LifeDiscountCouponUser::getStatus,
-                                    Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
-                            couponUserWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
-                            couponUserWrapper.orderByDesc(LifeDiscountCouponUser::getCreatedTime);
-                            couponUserWrapper.last("LIMIT 1");
-                            LifeDiscountCouponUser couponUser = lifeDiscountCouponUserMapper.selectOne(couponUserWrapper);
-                            if (couponUser != null) {
-                                couponUser.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_BEEN_USED.getValue()));
-                                couponUser.setUseTime(new Date());
-                                lifeDiscountCouponUserMapper.updateById(couponUser);
-                                log.info("支付成功,已更新 life_discount_coupon_user 为已使用, id={}", couponUser.getId());
-                            }
-                        }
-                        // 支付完成后,清空购物车和重置餐桌状态(保留订单数据,不删除订单)
-                        try {
-                            storeOrderService.resetTableAfterPayment(storeOrder.getTableId());
-                            log.info("支付完成后重置餐桌成功, tableId={}", storeOrder.getTableId());
-                        } catch (Exception e) {
-                            log.error("支付完成后重置餐桌失败, tableId={}, error={}", storeOrder.getTableId(), e.getMessage(), e);
-                        }
-                    }
-                }
-            }
-        } catch (Exception e) {
-            log.error("[微信支付回调] 异步处理业务异常", e);
-        }
-    }
-
-    @Override
-    public R searchOrderByOutTradeNoPath(String transactionId, Integer storeId) throws Exception {
-        log.info("查询微信支付订单状态,交易订单号:{}, storeId:{}", transactionId, storeId);
-        if (storeId == null) {
-            return R.fail("店铺ID不能为空");
-        }
-        StorePaymentConfig config = getConfigByStoreId(storeId);
-        if (config == null) {
-            return R.fail("未找到该店铺的微信支付配置");
-        }
-        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
-        PublicKey publicKey = loadPublicKeyFromConfig(config);
-        if (privateKey == null || publicKey == null) {
-            return R.fail("店铺微信支付密钥未配置或加载失败");
-        }
-        QueryByWxTradeNoRequest request = new QueryByWxTradeNoRequest();
-        request.transactionId = transactionId;
-        request.mchid = config.getWechatMchId();
-        try {
-            DirectAPIv3QueryResponse response = searchOrderRun(request, config, privateKey, publicKey);
-            return R.data(response);
-        } catch (WXPayUtility.ApiException e) {
-            log.error("查询微信支付订单状态失败,状态码:{},错误信息:{}", e.getErrorCode(), e.getMessage());
-            return R.fail(e.getMessage());
-        }
-    }
-
-    public DirectAPIv3QueryResponse searchOrderRun(QueryByWxTradeNoRequest request,
-                                                   StorePaymentConfig config,
-                                                   PrivateKey privateKey,
-                                                   PublicKey wechatPayPublicKey) {
-        String uri = searchOrderByOutTradeNoPath;
-        uri = uri.replace("{out_trade_no}", WXPayUtility.urlEncode(request.transactionId));
-        Map<String, Object> args = new HashMap<>();
-        args.put("mchid", request.mchid);
-        String queryString = WXPayUtility.urlEncode(args);
-        if (!queryString.isEmpty()) {
-            uri = uri + "?" + queryString;
-        }
-
-        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
-        reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(request.mchid, config.getMerchantSerialNumber(), privateKey, GETMETHOD, uri, null));
-        reqBuilder.method(GETMETHOD, null);
-        Request httpRequest = reqBuilder.build();
-
-        OkHttpClient client = new OkHttpClient.Builder().build();
-        try (Response httpResponse = client.newCall(httpRequest).execute()) {
-            String respBody = WXPayUtility.extractBody(httpResponse);
-            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
-                        httpResponse.headers(), respBody);
-                return WXPayUtility.fromJson(respBody, DirectAPIv3QueryResponse.class);
-            } else {
-                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
-            }
-        } catch (IOException e) {
-            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
-        }
-    }
-
-    @Override
-    public String handleRefund(Map<String, String> params) throws Exception {
-        return null;
-    }
-
-    @Override
-    public R searchRefundRecordByOutRefundNo(String outRefundNo, Integer storeId) throws Exception {
-        Logger logger = LoggerFactory.getLogger(this.getClass());
-
-        if (outRefundNo == null || outRefundNo.trim().isEmpty()) {
-            logger.error("微信退款查询失败:外部退款单号为空");
-            return R.fail("外部退款单号不能为空");
-        }
-        if (storeId == null) {
-            return R.fail("店铺ID不能为空");
-        }
-        StorePaymentConfig config = getConfigByStoreId(storeId);
-        if (config == null) {
-            return R.fail("未找到该店铺的微信支付配置");
-        }
-        PrivateKey privateKey = loadPrivateKeyFromConfig(config);
-        PublicKey publicKey = loadPublicKeyFromConfig(config);
-        if (privateKey == null || publicKey == null) {
-            return R.fail("店铺微信支付密钥未配置或加载失败");
-        }
-
-        QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
-        request.setOutRefundNo(outRefundNo);
-
-        try {
-            Refund response = doSearchRefundRecordByOutRefundNo(request, config, privateKey, publicKey);
-
-            // 3. 空值校验(避免response为空导致空指针)
-            if (response == null) {
-                logger.error("微信退款查询失败:外部退款单号{},返回结果为空", outRefundNo);
-                return R.fail("微信支付查询退款记录失败:返回结果为空");
-            }
-
-            logger.info("微信退款查询结果:外部退款单号{},退款状态{}",
-                    outRefundNo, response.getStatus());
-
-            // 4. 细化退款状态判断(覆盖微信支付核心退款状态)
-            String refundStatus = String.valueOf(response.getStatus());
-            switch (refundStatus) {
-                case "SUCCESS":
-                    // 退款成功:执行成功业务逻辑(如更新订单状态、通知用户等)
-                    logger.info("退款成功:外部退款单号{}", outRefundNo);
-                    // TODO: 补充你的成功业务逻辑(例:updateOrderRefundStatus(outRefundNo, "SUCCESS");)
-                    return R.data(response);
-
-                case "REFUNDCLOSE":
-                    // 退款关闭:执行关闭逻辑(如记录关闭原因、人工介入等)
-                    logger.warn("退款关闭:外部退款单号{},原因{}", outRefundNo);
-                    return R.fail("微信支付退款已关闭");
-
-                case "PROCESSING":
-                    // 退款处理中:执行等待逻辑(如提示用户等待、定时任务重试等)
-                    logger.info("退款处理中:外部退款单号{}", outRefundNo);
-                    return R.fail("微信支付退款处理中,请稍后再查");
-
-                case "CHANGE":
-                    // 退款异常:执行异常处理(如记录异常、人工核查等)
-                    logger.error("退款异常:外部退款单号{}", outRefundNo);
-                    return R.fail("微信支付退款异常");
-
-                default:
-                    // 未知状态:兜底处理
-                    logger.error("退款状态未知:外部退款单号{},状态码{}", outRefundNo, refundStatus);
-                    return R.fail("微信支付查询退款记录失败:未知状态码" + refundStatus);
-            }
-
-        } catch (WXPayUtility.ApiException e) {
-            // 5. 异常处理:细化异常日志,便于排查
-            logger.error("微信退款查询API异常:外部退款单号{},错误码{},错误信息{}",
-                    outRefundNo, e.getErrorCode(), e.getMessage(), e);
-            return R.fail("微信支付查询退款记录失败:" + e.getMessage() + "(错误码:" + e.getErrorCode() + ")");
-        } catch (Exception e) {
-            // 6. 兜底异常:捕获非API异常(如空指针、网络异常等)
-            logger.error("微信退款查询系统异常:外部退款单号{}", outRefundNo, e);
-            return R.fail("微信支付查询退款记录失败:系统异常,请联系管理员");
-        }
-    }
-
-    @Override
-    public String getType() {
-        return PaymentEnum.WECHAT_PAY_MININ_PROGRAM.getType();
-    }
-
-    public Refund doSearchRefundRecordByOutRefundNo(QueryByOutRefundNoRequest request,
-                                                   StorePaymentConfig config,
-                                                   PrivateKey privateKey,
-                                                   PublicKey wechatPayPublicKey) {
-        String uri = searchRefundStatusByOutRefundNoPath;
-        uri = uri.replace("{out_refund_no}", WXPayUtility.urlEncode(request.getOutRefundNo()));
-        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
-        reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(config.getWechatMchId(), config.getMerchantSerialNumber(), privateKey, GETMETHOD, uri, null));
-        reqBuilder.method(GETMETHOD, null);
-        Request httpRequest = reqBuilder.build();
-
-        OkHttpClient client = new OkHttpClient.Builder().build();
-        try (Response httpResponse = client.newCall(httpRequest).execute()) {
-            String respBody = WXPayUtility.extractBody(httpResponse);
-            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
-                        httpResponse.headers(), respBody);
-                return WXPayUtility.fromJson(respBody, Refund.class);
-            } else {
-                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
-            }
-        } catch (IOException e) {
-            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
-        }
-    }
-
-    public DirectAPIv3JsapiPrepayResponse doCreatePrePayOrder(DirectAPIv3JsapiPrepayRequest request,
-                                                             StorePaymentConfig config,
-                                                             PrivateKey privateKey) {
-        String uri = prePayPath;
-        String reqBody = WXPayUtility.toJson(request);
-
-        Request.Builder reqBuilder = new Request.Builder().url(wechatPayApiHost + uri);
-        reqBuilder.addHeader("Accept", "application/json");
-        reqBuilder.addHeader("Wechatpay-Serial", config.getWechatPayPublicKeyId());
-        reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(config.getWechatMchId(), config.getMerchantSerialNumber(), privateKey, POSTMETHOD, uri, reqBody));
-        reqBuilder.addHeader("Content-Type", "application/json");
-        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
-        reqBuilder.method(POSTMETHOD, requestBody);
-        Request httpRequest = reqBuilder.build();
-
-        OkHttpClient client = new OkHttpClient.Builder().build();
-        try (Response httpResponse = client.newCall(httpRequest).execute()) {
-            String respBody = WXPayUtility.extractBody(httpResponse);
-            if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
-                PublicKey wechatPayPublicKey = loadPublicKeyFromConfig(config);
-                WXPayUtility.validateResponse(config.getWechatPayPublicKeyId(), wechatPayPublicKey,
-                        httpResponse.headers(), respBody);
-                return WXPayUtility.fromJson(respBody, DirectAPIv3JsapiPrepayResponse.class);
-            } else {
-                throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
-            }
-        } catch (IOException e) {
-            throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
-        }
-    }
-
-    public static class DirectAPIv3JsapiPrepayRequest {
-        @SerializedName("appid")
-        public String appid;
-
-        @SerializedName("mchid")
-        public String mchid;
-
-        @SerializedName("description")
-        public String description;
-
-        @SerializedName("out_trade_no")
-        public String outTradeNo;
-
-        @SerializedName("time_expire")
-        public String timeExpire;
-
-        @SerializedName("attach")
-        public String attach;
-
-        @SerializedName("notify_url")
-        public String notifyUrl;
-
-        @SerializedName("goods_tag")
-        public String goodsTag;
-
-        @SerializedName("support_fapiao")
-        public Boolean supportFapiao;
-
-        @SerializedName("amount")
-        public CommonAmountInfo amount;
-
-        @SerializedName("payer")
-        public JsapiReqPayerInfo payer;
-
-        @SerializedName("detail")
-        public CouponInfo detail;
-
-        @SerializedName("scene_info")
-        public CommonSceneInfo sceneInfo;
-
-        @SerializedName("settle_info")
-        public SettleInfo settleInfo;
-    }
-
-    public static class DirectAPIv3JsapiPrepayResponse {
-        @SerializedName("prepay_id")
-        public String prepayId;
-    }
-
-    public static class CommonAmountInfo {
-        @SerializedName("total")
-        public Long total;
-
-        @SerializedName("currency")
-        public String currency;
-    }
-
-    public static class JsapiReqPayerInfo {
-        @SerializedName("openid")
-        public String openid;
-    }
-
-    public static class CouponInfo {
-        @SerializedName("cost_price")
-        public Long costPrice;
-
-        @SerializedName("invoice_id")
-        public String invoiceId;
-
-        @SerializedName("goods_detail")
-        public List<GoodsDetail> goodsDetail;
-    }
-
-    public static class CommonSceneInfo {
-        @SerializedName("payer_client_ip")
-        public String payerClientIp;
-
-        @SerializedName("device_id")
-        public String deviceId;
-
-        @SerializedName("store_info")
-        public StoreInfo storeInfo;
-    }
-
-    public static class SettleInfo {
-        @SerializedName("profit_sharing")
-        public Boolean profitSharing;
-    }
-
-    public static class GoodsDetail {
-        @SerializedName("merchant_goods_id")
-        public String merchantGoodsId;
-
-        @SerializedName("wechatpay_goods_id")
-        public String wechatpayGoodsId;
-
-        @SerializedName("goods_name")
-        public String goodsName;
-
-        @SerializedName("quantity")
-        public Long quantity;
-
-        @SerializedName("unit_price")
-        public Long unitPrice;
-    }
-
-    public static class StoreInfo {
-        @SerializedName("id")
-        public String id;
-
-        @SerializedName("name")
-        public String name;
-
-        @SerializedName("area_code")
-        public String areaCode;
-
-        @SerializedName("address")
-        public String address;
-    }
-
-    public static class QueryByWxTradeNoRequest {
-        @SerializedName("mchid")
-        @Expose(serialize = false)
-        public String mchid;
-
-        @SerializedName("transaction_id")
-        @Expose(serialize = false)
-        public String transactionId;
-    }
-
-    public static class DirectAPIv3QueryResponse {
-        @SerializedName("appid")
-        public String appid;
-
-        @SerializedName("mchid")
-        public String mchid;
-
-        @SerializedName("out_trade_no")
-        public String outTradeNo;
-
-        @SerializedName("transaction_id")
-        public String transactionId;
-
-        @SerializedName("trade_type")
-        public String tradeType;
-
-        @SerializedName("trade_state")
-        public String tradeState;
-
-        @SerializedName("trade_state_desc")
-        public String tradeStateDesc;
-
-        @SerializedName("bank_type")
-        public String bankType;
-
-        @SerializedName("attach")
-        public String attach;
-
-        @SerializedName("success_time")
-        public String successTime;
-
-        @SerializedName("payer")
-        public CommRespPayerInfo payer;
-
-        @SerializedName("amount")
-        public CommRespAmountInfo amount;
-
-        @SerializedName("scene_info")
-        public CommRespSceneInfo sceneInfo;
-
-        @SerializedName("promotion_detail")
-        public List<PromotionDetail> promotionDetail;
-    }
-    public static class CommRespPayerInfo {
-        @SerializedName("openid")
-        public String openid;
-    }
-
-    public static class CommRespAmountInfo {
-        @SerializedName("total")
-        public Long total;
-
-        @SerializedName("payer_total")
-        public Long payerTotal;
-
-        @SerializedName("currency")
-        public String currency;
-
-        @SerializedName("payer_currency")
-        public String payerCurrency;
-    }
-
-    public static class CommRespSceneInfo {
-        @SerializedName("device_id")
-        public String deviceId;
-    }
-
-    public static class PromotionDetail {
-        @SerializedName("coupon_id")
-        public String couponId;
-
-        @SerializedName("name")
-        public String name;
-
-        @SerializedName("scope")
-        public String scope;
-
-        @SerializedName("type")
-        public String type;
-
-        @SerializedName("amount")
-        public Long amount;
-
-        @SerializedName("stock_id")
-        public String stockId;
-
-        @SerializedName("wechatpay_contribute")
-        public Long wechatpayContribute;
-
-        @SerializedName("merchant_contribute")
-        public Long merchantContribute;
-
-        @SerializedName("other_contribute")
-        public Long otherContribute;
-
-        @SerializedName("currency")
-        public String currency;
-
-        @SerializedName("goods_detail")
-        public List<GoodsDetailInPromotion> goodsDetail;
-    }
-
-    public static class GoodsDetailInPromotion {
-        @SerializedName("goods_id")
-        public String goodsId;
-
-        @SerializedName("quantity")
-        public Long quantity;
-
-        @SerializedName("unit_price")
-        public Long unitPrice;
-
-        @SerializedName("discount_amount")
-        public Long discountAmount;
-
-        @SerializedName("goods_remark")
-        public String goodsRemark;
-    }
-}
-

+ 0 - 227
alien-store/src/main/java/shop/alien/store/dining/util/TokenUtil.java

@@ -1,227 +0,0 @@
-package shop.alien.store.dining.util;
-
-import com.alibaba.fastjson.JSONObject;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import shop.alien.util.common.JwtUtil;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * Token 工具类
- * 用于统一处理 token 的获取和解析
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Slf4j
-public class TokenUtil {
-
-    /**
-     * 去除 token 中的 "Bearer " 前缀
-     *
-     * @param token 原始 token 字符串
-     * @return 去除前缀后的 token
-     */
-    private static String removeBearerPrefix(String token) {
-        if (StringUtils.isBlank(token)) {
-            return token;
-        }
-        // 去除首尾空格
-        token = token.trim();
-        
-        // 去除 "Bearer " 前缀(不区分大小写)
-        if (token.length() > 7 && token.substring(0, 7).equalsIgnoreCase("Bearer ")) {
-            token = token.substring(7).trim();
-        }
-        
-        return token;
-    }
-
-    /**
-     * 从请求头获取当前用户信息
-     * 兼容新的 token 格式(包含 openid)和旧格式
-     *
-     * @return 用户信息 JSONObject,包含 userId、openid、phone、userName 等,如果获取失败返回 null
-     */
-    public static JSONObject getCurrentUserInfo() {
-        try {
-            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
-            if (attributes == null) {
-                return null;
-            }
-
-            HttpServletRequest request = attributes.getRequest();
-            String token = request.getHeader("Authorization");
-            
-            if (StringUtils.isBlank(token)) {
-                return null;
-            }
-
-            // 去除 "Bearer " 前缀
-            token = removeBearerPrefix(token);
-            
-            if (StringUtils.isBlank(token)) {
-                log.warn("Token 去除前缀后为空");
-                return null;
-            }
-
-            // 解析 token,验证格式和签名(与 verifyToken 方法保持一致)
-            io.jsonwebtoken.Claims claims = JwtUtil.parseJWT(token);
-            
-            // 从 token 中提取用户信息(与 verifyToken 方法保持一致)
-            String sub = claims.get("sub").toString();
-            JSONObject userInfo = JSONObject.parseObject(sub);
-            
-            return userInfo;
-        } catch (io.jsonwebtoken.ExpiredJwtException e) {
-            log.warn("Token 已过期: {}", e.getMessage());
-            return null;
-        } catch (io.jsonwebtoken.MalformedJwtException e) {
-            log.error("Token 格式错误: {}", e.getMessage());
-            return null;
-        } catch (io.jsonwebtoken.SignatureException e) {
-            log.error("Token 签名验证失败: {}", e.getMessage());
-            return null;
-        } catch (Exception e) {
-            log.warn("获取当前用户信息失败: {}", e.getMessage());
-            return null;
-        }
-    }
-
-    /**
-     * 获取当前用户ID
-     *
-     * @return 用户ID,如果获取失败返回 null
-     */
-    public static Integer getCurrentUserId() {
-        JSONObject userInfo = getCurrentUserInfo();
-        if (userInfo == null) {
-            log.debug("getCurrentUserInfo() 返回 null,无法获取 userId");
-            return null;
-        }
-        
-        try {
-            String userIdStr = userInfo.getString("userId");
-            if (StringUtils.isBlank(userIdStr)) {
-                log.warn("Token 中的 userId 字段为空或不存在,userInfo keys: {}", userInfo.keySet());
-                return null;
-            }
-            Integer userId = Integer.parseInt(userIdStr);
-            log.debug("成功获取 userId: {}", userId);
-            return userId;
-        } catch (NumberFormatException e) {
-            log.error("解析 userId 失败,userIdStr: {}, 错误: {}", userInfo.getString("userId"), e.getMessage());
-        } catch (Exception e) {
-            log.error("获取 userId 时发生异常: {}", e.getMessage(), e);
-        }
-        
-        return null;
-    }
-
-    /**
-     * 获取当前用户的 openid
-     *
-     * @return openid,如果获取失败返回 null
-     */
-    public static String getCurrentUserOpenid() {
-        JSONObject userInfo = getCurrentUserInfo();
-        if (userInfo == null) {
-            return null;
-        }
-        return userInfo.getString("openid");
-    }
-
-    /**
-     * 获取当前用户的手机号
-     *
-     * @return 手机号,如果获取失败返回 null
-     */
-    public static String getCurrentUserPhone() {
-        JSONObject userInfo = getCurrentUserInfo();
-        if (userInfo == null) {
-            return null;
-        }
-        return userInfo.getString("phone");
-    }
-
-    /**
-     * 检查是否有有效的 token
-     *
-     * @return 如果有有效的 token 返回 true,否则返回 false
-     */
-    public static boolean hasValidToken() {
-        JSONObject userInfo = getCurrentUserInfo();
-        return userInfo != null && userInfo.containsKey("userId");
-    }
-
-    /**
-     * 从 token 字符串直接解析用户信息(用于调试)
-     *
-     * @param token Token 字符串
-     * @return 用户信息 JSONObject,如果解析失败返回 null
-     */
-    public static JSONObject parseToken(String token) {
-        if (StringUtils.isBlank(token)) {
-            log.warn("Token 字符串为空");
-            return null;
-        }
-
-        try {
-            // 去除 "Bearer " 前缀
-            token = removeBearerPrefix(token);
-            
-            if (StringUtils.isBlank(token)) {
-                log.warn("Token 去除前缀后为空");
-                return null;
-            }
-            
-            log.info("开始解析 token: {}", token.length() > 30 ? token.substring(0, 30) + "..." : token);
-
-            // 解析 token
-            io.jsonwebtoken.Claims claims = JwtUtil.parseJWT(token);
-            if (claims == null) {
-                log.warn("Token 解析失败,claims 为 null");
-                return null;
-            }
-
-            log.info("Token claims keys: {}", claims.keySet());
-
-            // 从 token 中提取用户信息
-            Object subObj = claims.get("sub");
-            if (subObj == null) {
-                log.warn("Token claims 中没有 'sub' 字段");
-                return null;
-            }
-
-            String sub;
-            if (subObj instanceof String) {
-                sub = (String) subObj;
-            } else {
-                sub = subObj.toString();
-            }
-
-            log.info("Token sub 内容: {}", sub);
-
-            JSONObject userInfo = JSONObject.parseObject(sub);
-            if (userInfo == null) {
-                log.warn("解析 sub 为 JSONObject 返回 null");
-                return null;
-            }
-
-            log.info("成功解析用户信息: userId={}, openid={}, phone={}, 所有 keys: {}",
-                    userInfo.getString("userId"),
-                    userInfo.getString("openid"),
-                    userInfo.getString("phone"),
-                    userInfo.keySet());
-
-            return userInfo;
-        } catch (Exception e) {
-            log.error("解析 token 失败: {}, 异常类型: {}", e.getMessage(), e.getClass().getName(), e);
-            return null;
-        }
-    }
-}

+ 0 - 856
alien-store/src/main/java/shop/alien/store/dining/util/WXPayUtility.java

@@ -1,856 +0,0 @@
-package shop.alien.store.dining.util;
-
-import com.google.gson.*;
-import com.google.gson.annotations.Expose;
-import com.google.gson.annotations.SerializedName;
-import okhttp3.Headers;
-import okhttp3.Response;
-import okio.BufferedSource;
-import org.bouncycastle.crypto.digests.SM3Digest;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.spec.GCMParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UncheckedIOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.security.*;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-import java.time.DateTimeException;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.*;
-import java.util.Map.Entry;
-
-public class WXPayUtility {
-    private static final Gson gson = new GsonBuilder()
-            .disableHtmlEscaping()
-            .addSerializationExclusionStrategy(new ExclusionStrategy() {
-                @Override
-                public boolean shouldSkipField(FieldAttributes fieldAttributes) {
-                    final Expose expose = fieldAttributes.getAnnotation(Expose.class);
-                    return expose != null && !expose.serialize();
-                }
-
-                @Override
-                public boolean shouldSkipClass(Class<?> aClass) {
-                    return false;
-                }
-            })
-            .addDeserializationExclusionStrategy(new ExclusionStrategy() {
-                @Override
-                public boolean shouldSkipField(FieldAttributes fieldAttributes) {
-                    final Expose expose = fieldAttributes.getAnnotation(Expose.class);
-                    return expose != null && !expose.deserialize();
-                }
-
-                @Override
-                public boolean shouldSkipClass(Class<?> aClass) {
-                    return false;
-                }
-            })
-            .create();
-    private static final char[] SYMBOLS =
-            "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
-    private static final SecureRandom random = new SecureRandom();
-
-    /**
-     * 将 Object 转换为 JSON 字符串
-     */
-    public static String toJson(Object object) {
-        return gson.toJson(object);
-    }
-
-    /**
-     * 将 JSON 字符串解析为特定类型的实例
-     */
-    public static <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
-        return gson.fromJson(json, classOfT);
-    }
-
-    /**
-     * 从公私钥文件路径中读取文件内容
-     *
-     * @param keyPath 文件路径
-     * @return 文件内容
-     */
-    private static String readKeyStringFromPath(String keyPath) {
-        try {
-            return new String(Files.readAllBytes(Paths.get(keyPath)), StandardCharsets.UTF_8);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-
-    /**
-     * 读取 PKCS#8 格式的私钥字符串并加载为私钥对象
-     *
-     * @param keyString 私钥文件内容,以 -----BEGIN PRIVATE KEY----- 开头
-     * @return PrivateKey 对象
-     */
-    public static PrivateKey loadPrivateKeyFromString(String keyString) {
-        try {
-            keyString = keyString.replace("-----BEGIN PRIVATE KEY-----", "")
-                    .replace("-----END PRIVATE KEY-----", "")
-                    .replaceAll("\\s+", "");
-            return KeyFactory.getInstance("RSA").generatePrivate(
-                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
-        } catch (NoSuchAlgorithmException e) {
-            throw new UnsupportedOperationException(e);
-        } catch (InvalidKeySpecException e) {
-            throw new IllegalArgumentException(e);
-        }
-    }
-
-    /**
-     * 从 PKCS#8 格式的私钥文件中加载私钥
-     *
-     * @param keyPath 私钥文件路径
-     * @return PrivateKey 对象
-     */
-    public static PrivateKey loadPrivateKeyFromPath(String keyPath) {
-        return loadPrivateKeyFromString(readKeyStringFromPath(keyPath));
-    }
-
-    /**
-     * 读取 PKCS#8 格式的公钥字符串并加载为公钥对象
-     *
-     * @param keyString 公钥文件内容,以 -----BEGIN PUBLIC KEY----- 开头
-     * @return PublicKey 对象
-     */
-    public static PublicKey loadPublicKeyFromString(String keyString) {
-        try {
-            keyString = keyString.replace("-----BEGIN PUBLIC KEY-----", "")
-                    .replace("-----END PUBLIC KEY-----", "")
-                    .replaceAll("\\s+", "");
-            return KeyFactory.getInstance("RSA").generatePublic(
-                    new X509EncodedKeySpec(Base64.getDecoder().decode(keyString)));
-        } catch (NoSuchAlgorithmException e) {
-            throw new UnsupportedOperationException(e);
-        } catch (InvalidKeySpecException e) {
-            throw new IllegalArgumentException(e);
-        }
-    }
-
-    /**
-     * 从 PKCS#8 格式的公钥文件中加载公钥
-     *
-     * @param keyPath 公钥文件路径
-     * @return PublicKey 对象
-     */
-    public static PublicKey loadPublicKeyFromPath(String keyPath) {
-        return loadPublicKeyFromString(readKeyStringFromPath(keyPath));
-    }
-
-    /**
-     * 创建指定长度的随机字符串,字符集为[0-9a-zA-Z],可用于安全相关用途
-     */
-    public static String createNonce(int length) {
-        char[] buf = new char[length];
-        for (int i = 0; i < length; ++i) {
-            buf[i] = SYMBOLS[random.nextInt(SYMBOLS.length)];
-        }
-        return new String(buf);
-    }
-
-    /**
-     * 使用公钥按照 RSA_PKCS1_OAEP_PADDING 算法进行加密
-     *
-     * @param publicKey 加密用公钥对象
-     * @param plaintext 待加密明文
-     * @return 加密后密文
-     */
-    public static String encrypt(PublicKey publicKey, String plaintext) {
-        final String transformation = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
-
-        try {
-            Cipher cipher = Cipher.getInstance(transformation);
-            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
-            return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
-        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
-            throw new IllegalArgumentException("The current Java environment does not support " + transformation, e);
-        } catch (InvalidKeyException e) {
-            throw new IllegalArgumentException("RSA encryption using an illegal publicKey", e);
-        } catch (BadPaddingException | IllegalBlockSizeException e) {
-            throw new IllegalArgumentException("Plaintext is too long", e);
-        }
-    }
-
-    public static String aesAeadDecrypt(byte[] key, byte[] associatedData, byte[] nonce,
-                                        byte[] ciphertext) {
-        final String transformation = "AES/GCM/NoPadding";
-        final String algorithm = "AES";
-        final int tagLengthBit = 128;
-
-        try {
-            Cipher cipher = Cipher.getInstance(transformation);
-            cipher.init(
-                    Cipher.DECRYPT_MODE,
-                    new SecretKeySpec(key, algorithm),
-                    new GCMParameterSpec(tagLengthBit, nonce));
-            if (associatedData != null) {
-                cipher.updateAAD(associatedData);
-            }
-            return new String(cipher.doFinal(ciphertext), StandardCharsets.UTF_8);
-        } catch (InvalidKeyException
-                 | InvalidAlgorithmParameterException
-                 | BadPaddingException
-                 | IllegalBlockSizeException
-                 | NoSuchAlgorithmException
-                 | NoSuchPaddingException e) {
-            throw new IllegalArgumentException(String.format("AesAeadDecrypt with %s Failed",
-                    transformation), e);
-        }
-    }
-
-    /**
-     * 使用私钥按照指定算法进行签名
-     *
-     * @param message    待签名串
-     * @param algorithm  签名算法,如 SHA256withRSA
-     * @param privateKey 签名用私钥对象
-     * @return 签名结果
-     */
-    public static String sign(String message, String algorithm, PrivateKey privateKey) {
-        byte[] sign;
-        try {
-            Signature signature = Signature.getInstance(algorithm);
-            signature.initSign(privateKey);
-            signature.update(message.getBytes(StandardCharsets.UTF_8));
-            sign = signature.sign();
-        } catch (NoSuchAlgorithmException e) {
-            throw new UnsupportedOperationException("The current Java environment does not support " + algorithm, e);
-        } catch (InvalidKeyException e) {
-            throw new IllegalArgumentException(algorithm + " signature uses an illegal privateKey.", e);
-        } catch (SignatureException e) {
-            throw new RuntimeException("An error occurred during the sign process.", e);
-        }
-        return Base64.getEncoder().encodeToString(sign);
-    }
-
-    /**
-     * 使用公钥按照特定算法验证签名
-     *
-     * @param message   待签名串
-     * @param signature 待验证的签名内容
-     * @param algorithm 签名算法,如:SHA256withRSA
-     * @param publicKey 验签用公钥对象
-     * @return 签名验证是否通过
-     */
-    public static boolean verify(String message, String signature, String algorithm,
-                                 PublicKey publicKey) {
-        try {
-            Signature sign = Signature.getInstance(algorithm);
-            sign.initVerify(publicKey);
-            sign.update(message.getBytes(StandardCharsets.UTF_8));
-            return sign.verify(Base64.getDecoder().decode(signature));
-        } catch (SignatureException e) {
-            return false;
-        } catch (InvalidKeyException e) {
-            throw new IllegalArgumentException("verify uses an illegal publickey.", e);
-        } catch (NoSuchAlgorithmException e) {
-            throw new UnsupportedOperationException("The current Java environment does not support" + algorithm, e);
-        }
-    }
-
-    /**
-     * 根据微信支付APIv3请求签名规则构造 Authorization 签名
-     *
-     * @param mchid               商户号
-     * @param certificateSerialNo 商户API证书序列号
-     * @param privateKey          商户API证书私钥
-     * @param method              请求接口的HTTP方法,请使用全大写表述,如 GET、POST、PUT、DELETE
-     * @param uri                 请求接口的URL
-     * @param body                请求接口的Body
-     * @return 构造好的微信支付APIv3 Authorization 头
-     */
-    public static String buildAuthorization(String mchid, String certificateSerialNo,
-                                            PrivateKey privateKey,
-                                            String method, String uri, String body) {
-        String nonce = createNonce(32);
-        long timestamp = Instant.now().getEpochSecond();
-
-        String message = String.format("%s\n%s\n%d\n%s\n%s\n", method, uri, timestamp, nonce,
-                body == null ? "" : body);
-
-        String signature = sign(message, "SHA256withRSA", privateKey);
-
-        return String.format(
-                "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\"," +
-                        "timestamp=\"%d\",serial_no=\"%s\"",
-                mchid, nonce, signature, timestamp, certificateSerialNo);
-    }
-
-    /**
-     * 计算输入流的哈希值
-     *
-     * @param inputStream 输入流
-     * @param algorithm   哈希算法名称,如 "SHA-256", "SHA-1"
-     * @return 哈希值的十六进制字符串
-     */
-    private static String calculateHash(InputStream inputStream, String algorithm) {
-        try {
-            MessageDigest digest = MessageDigest.getInstance(algorithm);
-            byte[] buffer = new byte[8192];
-            int bytesRead;
-            while ((bytesRead = inputStream.read(buffer)) != -1) {
-                digest.update(buffer, 0, bytesRead);
-            }
-            byte[] hashBytes = digest.digest();
-            StringBuilder hexString = new StringBuilder();
-            for (byte b : hashBytes) {
-                String hex = Integer.toHexString(0xff & b);
-                if (hex.length() == 1) {
-                    hexString.append('0');
-                }
-                hexString.append(hex);
-            }
-            return hexString.toString();
-        } catch (NoSuchAlgorithmException e) {
-            throw new UnsupportedOperationException(algorithm + " algorithm not available", e);
-        } catch (IOException e) {
-            throw new RuntimeException("Error reading from input stream", e);
-        }
-    }
-
-    /**
-     * 计算输入流的 SHA256 哈希值
-     *
-     * @param inputStream 输入流
-     * @return SHA256 哈希值的十六进制字符串
-     */
-    public static String sha256(InputStream inputStream) {
-        return calculateHash(inputStream, "SHA-256");
-    }
-
-    /**
-     * 计算输入流的 SHA1 哈希值
-     *
-     * @param inputStream 输入流
-     * @return SHA1 哈希值的十六进制字符串
-     */
-    public static String sha1(InputStream inputStream) {
-        return calculateHash(inputStream, "SHA-1");
-    }
-
-    /**
-     * 计算输入流的 SM3 哈希值
-     *
-     * @param inputStream 输入流
-     * @return SM3 哈希值的十六进制字符串
-     */
-    public static String sm3(InputStream inputStream) {
-        // 确保Bouncy Castle Provider已注册
-        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
-            Security.addProvider(new BouncyCastleProvider());
-        }
-
-        try {
-            SM3Digest digest = new SM3Digest();
-            byte[] buffer = new byte[8192];
-            int bytesRead;
-            while ((bytesRead = inputStream.read(buffer)) != -1) {
-                digest.update(buffer, 0, bytesRead);
-            }
-            byte[] hashBytes = new byte[digest.getDigestSize()];
-            digest.doFinal(hashBytes, 0);
-
-            StringBuilder hexString = new StringBuilder();
-            for (byte b : hashBytes) {
-                String hex = Integer.toHexString(0xff & b);
-                if (hex.length() == 1) {
-                    hexString.append('0');
-                }
-                hexString.append(hex);
-            }
-            return hexString.toString();
-        } catch (IOException e) {
-            throw new RuntimeException("Error reading from input stream", e);
-        }
-    }
-
-    /**
-     * 对参数进行 URL 编码
-     *
-     * @param content 参数内容
-     * @return 编码后的内容
-     */
-    public static String urlEncode(String content) {
-        try {
-            return URLEncoder.encode(content, StandardCharsets.UTF_8.name());
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * 对参数Map进行 URL 编码,生成 QueryString
-     *
-     * @param params Query参数Map
-     * @return QueryString
-     */
-    public static String urlEncode(Map<String, Object> params) {
-        if (params == null || params.isEmpty()) {
-            return "";
-        }
-
-        StringBuilder result = new StringBuilder();
-        for (Entry<String, Object> entry : params.entrySet()) {
-            if (entry.getValue() == null) {
-                continue;
-            }
-
-            String key = entry.getKey();
-            Object value = entry.getValue();
-            if (value instanceof List) {
-                List<?> list = (List<?>) entry.getValue();
-                for (Object temp : list) {
-                    appendParam(result, key, temp);
-                }
-            } else {
-                appendParam(result, key, value);
-            }
-        }
-        return result.toString();
-    }
-
-    /**
-     * 将键值对 放入返回结果
-     *
-     * @param result 返回的query string
-     * @param key 属性
-     * @param value 属性值
-     */
-    private static void appendParam(StringBuilder result, String key, Object value) {
-        if (result.length() > 0) {
-            result.append("&");
-        }
-
-        String valueString;
-        // 如果是基本类型、字符串或枚举,直接转换;如果是对象,序列化为JSON
-        if (value instanceof String || value instanceof Number ||
-                value instanceof Boolean || value instanceof Enum) {
-            valueString = value.toString();
-        } else {
-            valueString = toJson(value);
-        }
-
-        result.append(key)
-                .append("=")
-                .append(urlEncode(valueString));
-    }
-
-    /**
-     * 从应答中提取 Body
-     *
-     * @param response HTTP 请求应答对象
-     * @return 应答中的Body内容,Body为空时返回空字符串
-     */
-    public static String extractBody(Response response) {
-        if (response.body() == null) {
-            return "";
-        }
-
-        try {
-            BufferedSource source = response.body().source();
-            return source.readUtf8();
-        } catch (IOException e) {
-            throw new RuntimeException(String.format("An error occurred during reading response body. " +
-                    "Status: %d", response.code()), e);
-        }
-    }
-
-    /**
-     * 根据微信支付APIv3应答验签规则对应答签名进行验证,验证不通过时抛出异常
-     *
-     * @param wechatpayPublicKeyId 微信支付公钥ID
-     * @param wechatpayPublicKey   微信支付公钥对象
-     * @param headers              微信支付应答 Header 列表
-     * @param body                 微信支付应答 Body
-     */
-    public static void validateResponse(String wechatpayPublicKeyId, PublicKey wechatpayPublicKey,
-                                        Headers headers,
-                                        String body) {
-        String timestamp = headers.get("Wechatpay-Timestamp");
-        String requestId = headers.get("Request-ID");
-        try {
-            Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
-            // 拒绝过期请求
-            if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= 5) {
-                throw new IllegalArgumentException(
-                        String.format("Validate response failed, timestamp[%s] is expired, request-id[%s]",
-                                timestamp, requestId));
-            }
-        } catch (DateTimeException | NumberFormatException e) {
-            throw new IllegalArgumentException(
-                    String.format("Validate response failed, timestamp[%s] is invalid, request-id[%s]",
-                            timestamp, requestId));
-        }
-        String serialNumber = headers.get("Wechatpay-Serial");
-        if (!Objects.equals(serialNumber, wechatpayPublicKeyId)) {
-            throw new IllegalArgumentException(
-                    String.format("Validate response failed, Invalid Wechatpay-Serial, Local: %s, Remote: " +
-                            "%s", wechatpayPublicKeyId, serialNumber));
-        }
-
-        String signature = headers.get("Wechatpay-Signature");
-        String message = String.format("%s\n%s\n%s\n", timestamp, headers.get("Wechatpay-Nonce"),
-                body == null ? "" : body);
-
-        boolean success = verify(message, signature, "SHA256withRSA", wechatpayPublicKey);
-        if (!success) {
-            throw new IllegalArgumentException(
-                    String.format("Validate response failed,the WechatPay signature is incorrect.%n"
-                                    + "Request-ID[%s]\tresponseHeader[%s]\tresponseBody[%.1024s]",
-                            headers.get("Request-ID"), headers, body));
-        }
-    }
-
-    /**
-     * 根据微信支付APIv3通知验签规则对通知签名进行验证,验证不通过时抛出异常
-     * @param wechatpayPublicKeyId 微信支付公钥ID
-     * @param wechatpayPublicKey 微信支付公钥对象
-     * @param headers 微信支付通知 Header 列表
-     * @param body 微信支付通知 Body
-     */
-    public static void validateNotification(String wechatpayPublicKeyId,
-                                            PublicKey wechatpayPublicKey, Headers headers,
-                                            String body) {
-        String timestamp = headers.get("Wechatpay-Timestamp");
-        try {
-            Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
-            // 拒绝过期请求
-            if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= 5) {
-                throw new IllegalArgumentException(
-                        String.format("Validate notification failed, timestamp[%s] is expired", timestamp));
-            }
-        } catch (DateTimeException | NumberFormatException e) {
-            throw new IllegalArgumentException(
-                    String.format("Validate notification failed, timestamp[%s] is invalid", timestamp));
-        }
-        String serialNumber = headers.get("Wechatpay-Serial");
-        if (!Objects.equals(serialNumber, wechatpayPublicKeyId)) {
-            throw new IllegalArgumentException(
-                    String.format("Validate notification failed, Invalid Wechatpay-Serial, Local: %s, " +
-                                    "Remote: %s",
-                            wechatpayPublicKeyId,
-                            serialNumber));
-        }
-
-        String signature = headers.get("Wechatpay-Signature");
-        String message = String.format("%s\n%s\n%s\n", timestamp, headers.get("Wechatpay-Nonce"),
-                body == null ? "" : body);
-
-        boolean success = verify(message, signature, "SHA256withRSA", wechatpayPublicKey);
-        if (!success) {
-            throw new IllegalArgumentException(
-                    String.format("Validate notification failed, WechatPay signature is incorrect.\n"
-                                    + "responseHeader[%s]\tresponseBody[%.1024s]",
-                            headers, body));
-        }
-    }
-
-    /**
-     * 对微信支付通知进行签名验证、解析,同时将业务数据解密。验签名失败、解析失败、解密失败时抛出异常
-     * @param apiv3Key 商户的 APIv3 Key
-     * @param wechatpayPublicKeyId 微信支付公钥ID
-     * @param wechatpayPublicKey   微信支付公钥对象
-     * @param headers              微信支付请求 Header 列表
-     * @param body                 微信支付请求 Body
-     * @return 解析后的通知内容,解密后的业务数据可以使用 Notification.getPlaintext() 访问
-     */
-    public static Notification parseNotification(String apiv3Key, String wechatpayPublicKeyId,
-                                                 PublicKey wechatpayPublicKey, Headers headers,
-                                                 String body) {
-        validateNotification(wechatpayPublicKeyId, wechatpayPublicKey, headers, body);
-        Notification notification = gson.fromJson(body, Notification.class);
-        notification.decrypt(apiv3Key);
-        return notification;
-    }
-
-    /**
-     * 微信支付API错误异常,发送HTTP请求成功,但返回状态码不是 2XX 时抛出本异常
-     */
-    public static class ApiException extends RuntimeException {
-        private static final long serialVersionUID = 2261086748874802175L;
-
-        private final int statusCode;
-        private final String body;
-        private final Headers headers;
-        private final String errorCode;
-        private final String errorMessage;
-
-        public ApiException(int statusCode, String body, Headers headers) {
-            super(String.format("微信支付API访问失败,StatusCode: [%s], Body: [%s], Headers: [%s]", statusCode,
-                    body, headers));
-            this.statusCode = statusCode;
-            this.body = body;
-            this.headers = headers;
-
-            if (body != null && !body.isEmpty()) {
-                JsonElement code;
-                JsonElement message;
-
-                try {
-                    JsonObject jsonObject = gson.fromJson(body, JsonObject.class);
-                    code = jsonObject.get("code");
-                    message = jsonObject.get("message");
-                } catch (JsonSyntaxException ignored) {
-                    code = null;
-                    message = null;
-                }
-                this.errorCode = code == null ? null : code.getAsString();
-                this.errorMessage = message == null ? null : message.getAsString();
-            } else {
-                this.errorCode = null;
-                this.errorMessage = null;
-            }
-        }
-
-        /**
-         * 获取 HTTP 应答状态码
-         */
-        public int getStatusCode() {
-            return statusCode;
-        }
-
-        /**
-         * 获取 HTTP 应答包体内容
-         */
-        public String getBody() {
-            return body;
-        }
-
-        /**
-         * 获取 HTTP 应答 Header
-         */
-        public Headers getHeaders() {
-            return headers;
-        }
-
-        /**
-         * 获取 错误码 (错误应答中的 code 字段)
-         */
-        public String getErrorCode() {
-            return errorCode;
-        }
-
-        /**
-         * 获取 错误消息 (错误应答中的 message 字段)
-         */
-        public String getErrorMessage() {
-            return errorMessage;
-        }
-    }
-
-    public static class Notification {
-        @SerializedName("id")
-        private String id;
-        @SerializedName("create_time")
-        private String createTime;
-        @SerializedName("event_type")
-        private String eventType;
-        @SerializedName("resource_type")
-        private String resourceType;
-        @SerializedName("summary")
-        private String summary;
-        @SerializedName("resource")
-        private Resource resource;
-        private String plaintext;
-
-        public String getId() {
-            return id;
-        }
-
-        public String getCreateTime() {
-            return createTime;
-        }
-
-        public String getEventType() {
-            return eventType;
-        }
-
-        public String getResourceType() {
-            return resourceType;
-        }
-
-        public String getSummary() {
-            return summary;
-        }
-
-        public Resource getResource() {
-            return resource;
-        }
-
-        /**
-         * 获取解密后的业务数据(JSON字符串,需要自行解析)
-         */
-        public String getPlaintext() {
-            return plaintext;
-        }
-
-        private void validate() {
-            if (resource == null) {
-                throw new IllegalArgumentException("Missing required field `resource` in notification");
-            }
-            resource.validate();
-        }
-
-        /**
-         * 使用 APIv3Key 对通知中的业务数据解密,解密结果可以通过 getPlainText 访问。
-         * 外部拿到的 Notification 一定是解密过的,因此本方法没有设置为 public
-         * @param apiv3Key 商户APIv3 Key
-         */
-        private void decrypt(String apiv3Key) {
-            validate();
-
-            plaintext = aesAeadDecrypt(
-                    apiv3Key.getBytes(StandardCharsets.UTF_8),
-                    resource.associatedData.getBytes(StandardCharsets.UTF_8),
-                    resource.nonce.getBytes(StandardCharsets.UTF_8),
-                    Base64.getDecoder().decode(resource.ciphertext)
-            );
-        }
-
-        public static class Resource {
-            @SerializedName("algorithm")
-            private String algorithm;
-
-            @SerializedName("ciphertext")
-            private String ciphertext;
-
-            @SerializedName("associated_data")
-            private String associatedData;
-
-            @SerializedName("nonce")
-            private String nonce;
-
-            @SerializedName("original_type")
-            private String originalType;
-
-            public String getAlgorithm() {
-                return algorithm;
-            }
-
-            public String getCiphertext() {
-                return ciphertext;
-            }
-
-            public String getAssociatedData() {
-                return associatedData;
-            }
-
-            public String getNonce() {
-                return nonce;
-            }
-
-            public String getOriginalType() {
-                return originalType;
-            }
-
-            private void validate() {
-                if (algorithm == null || algorithm.isEmpty()) {
-                    throw new IllegalArgumentException("Missing required field `algorithm` in Notification" +
-                            ".Resource");
-                }
-                if (!Objects.equals(algorithm, "AEAD_AES_256_GCM")) {
-                    throw new IllegalArgumentException(String.format("Unsupported `algorithm`[%s] in " +
-                            "Notification.Resource", algorithm));
-                }
-
-                if (ciphertext == null || ciphertext.isEmpty()) {
-                    throw new IllegalArgumentException("Missing required field `ciphertext` in Notification" +
-                            ".Resource");
-                }
-
-                if (associatedData == null || associatedData.isEmpty()) {
-                    throw new IllegalArgumentException("Missing required field `associatedData` in " +
-                            "Notification.Resource");
-                }
-
-                if (nonce == null || nonce.isEmpty()) {
-                    throw new IllegalArgumentException("Missing required field `nonce` in Notification" +
-                            ".Resource");
-                }
-
-                if (originalType == null || originalType.isEmpty()) {
-                    throw new IllegalArgumentException("Missing required field `originalType` in " +
-                            "Notification.Resource");
-                }
-            }
-        }
-    }
-    /**
-     * 根据文件名获取对应的Content-Type
-     * @param fileName 文件名
-     * @return Content-Type字符串
-     */
-    public static String getContentTypeByFileName(String fileName) {
-        if (fileName == null || fileName.isEmpty()) {
-            return "application/octet-stream";
-        }
-
-        // 获取文件扩展名
-        String extension = "";
-        int lastDotIndex = fileName.lastIndexOf('.');
-        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
-            extension = fileName.substring(lastDotIndex + 1).toLowerCase();
-        }
-
-        // 常见文件类型映射
-        Map<String, String> contentTypeMap = new HashMap<>();
-        // 图片类型
-        contentTypeMap.put("png", "image/png");
-        contentTypeMap.put("jpg", "image/jpeg");
-        contentTypeMap.put("jpeg", "image/jpeg");
-        contentTypeMap.put("gif", "image/gif");
-        contentTypeMap.put("bmp", "image/bmp");
-        contentTypeMap.put("webp", "image/webp");
-        contentTypeMap.put("svg", "image/svg+xml");
-        contentTypeMap.put("ico", "image/x-icon");
-
-        // 文档类型
-        contentTypeMap.put("pdf", "application/pdf");
-        contentTypeMap.put("doc", "application/msword");
-        contentTypeMap.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
-        contentTypeMap.put("xls", "application/vnd.ms-excel");
-        contentTypeMap.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-        contentTypeMap.put("ppt", "application/vnd.ms-powerpoint");
-        contentTypeMap.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
-
-        // 文本类型
-        contentTypeMap.put("txt", "text/plain");
-        contentTypeMap.put("html", "text/html");
-        contentTypeMap.put("css", "text/css");
-        contentTypeMap.put("js", "application/javascript");
-        contentTypeMap.put("json", "application/json");
-        contentTypeMap.put("xml", "application/xml");
-        contentTypeMap.put("csv", "text/csv");
-
-        // 音视频类型
-        contentTypeMap.put("mp3", "audio/mpeg");
-        contentTypeMap.put("wav", "audio/wav");
-        contentTypeMap.put("mp4", "video/mp4");
-        contentTypeMap.put("avi", "video/x-msvideo");
-        contentTypeMap.put("mov", "video/quicktime");
-
-        // 压缩文件类型
-        contentTypeMap.put("zip", "application/zip");
-        contentTypeMap.put("rar", "application/x-rar-compressed");
-        contentTypeMap.put("7z", "application/x-7z-compressed");
-
-
-        return contentTypeMap.getOrDefault(extension, "application/octet-stream");
-    }
-}

+ 0 - 65
alien-store/src/main/java/shop/alien/store/dining/util/WeChatPayUtil.java

@@ -1,65 +0,0 @@
-package shop.alien.store.dining.util;
-
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.codec.binary.Base64;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.GCMParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.nio.charset.StandardCharsets;
-
-/**
- * 微信支付工具类
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Slf4j
-public class WeChatPayUtil {
-    // TODO: 实现微信支付相关工具方法
-
-    // AES-GCM模式的TAG长度(微信固定为128位/16字节)
-    private static final int GCM_TAG_LENGTH = 128;
-    // AES-256算法要求密钥长度为32字节(APIv3密钥必须是32位)
-    private static final int API_V3_KEY_LENGTH = 32;
-
-    /**
-     * 解密微信支付resource字段密文
-     * @param apiV3Key 商户平台设置的APIv3密钥(32位字符串)
-     * @param nonce resource.nonce(加密随机串)
-     * @param associatedData resource.associated_data(关联数据)
-     * @param ciphertext resource.ciphertext(Base64编码的密文)
-     * @return 解密后的明文(JSON格式业务信息)
-     * @throws Exception 解密异常(密钥错误、参数非法等)
-     */
-    public static String decrypt(String apiV3Key, String nonce, String associatedData, String ciphertext) throws Exception {
-        // 1. 校验APIv3密钥长度(必须32字节)
-        if (apiV3Key == null || apiV3Key.length() != API_V3_KEY_LENGTH) {
-            throw new IllegalArgumentException("APIv3密钥必须是32位字符串");
-        }
-
-        // 2. 转换密钥为SecretKeySpec(AES-256)
-        SecretKeySpec secretKeySpec = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
-
-        // 3. Base64解密密文
-        byte[] ciphertextBytes = Base64.decodeBase64(ciphertext);
-
-        // 4. 初始化GCM参数(nonce为16字节?微信实际是12字节,符合rfc5116)
-        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce.getBytes(StandardCharsets.UTF_8));
-
-        // 5. 初始化AES-GCM解密器
-        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
-        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, gcmParameterSpec);
-
-        // 6. 设置关联数据(AEAD附加数据)
-        cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
-
-        // 7. 执行解密
-        byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
-
-        // 8. 转换为UTF-8明文(JSON格式)
-        return new String(plaintextBytes, StandardCharsets.UTF_8);
-    }
-}
-

+ 0 - 76
alien-store/src/main/java/shop/alien/store/dining/vo/DiningUserVo.java

@@ -1,76 +0,0 @@
-package shop.alien.store.dining.vo;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * 点餐用户VO
- * 基于 LifeUser 表
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Data
-@ApiModel("点餐用户信息")
-public class DiningUserVo {
-
-    @ApiModelProperty("用户ID")
-    private Long id;
-
-    @ApiModelProperty("用户昵称")
-    private String nickName;
-
-    @ApiModelProperty("用户头像")
-    private String avatarUrl;
-
-    @ApiModelProperty("手机号")
-    private String phone;
-
-    @ApiModelProperty("性别")
-    private String gender;
-
-    @ApiModelProperty("生日")
-    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
-    private Date birthday;
-
-    @ApiModelProperty("真实姓名")
-    private String realName;
-
-    @ApiModelProperty("省份")
-    private String province;
-
-    @ApiModelProperty("城市")
-    private String city;
-
-    @ApiModelProperty("区县")
-    private String district;
-
-    @ApiModelProperty("详细地址")
-    private String address;
-
-    @ApiModelProperty("个人简介")
-    private String jianjie;
-
-    @ApiModelProperty("用户状态:0-正常,1-禁用")
-    private Integer status;
-
-    @ApiModelProperty("创建时间")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date createdTime;
-
-    @ApiModelProperty("最后登录时间")
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
-    private Date lastLoginTime;
-
-    @ApiModelProperty("JWT Token")
-    private String token;
-
-    @ApiModelProperty("微信OpenID")
-    private String openId;
-}
-

+ 0 - 40
alien-store/src/main/java/shop/alien/store/dining/vo/TokenVerifyVo.java

@@ -1,40 +0,0 @@
-package shop.alien.store.dining.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * Token 校验结果VO
- *
- * @author ssk
- * @version 1.0
- * @date 2024/12/4
- */
-@Data
-@ApiModel("Token校验结果")
-public class TokenVerifyVo {
-
-    @ApiModelProperty(value = "Token是否有效")
-    private Boolean valid;
-
-    @ApiModelProperty(value = "用户ID")
-    private Long userId;
-
-    @ApiModelProperty(value = "用户手机号")
-    private String phone;
-
-    @ApiModelProperty(value = "用户昵称")
-    private String nickName;
-
-    @ApiModelProperty(value = "微信OpenID")
-    private String openid;
-
-    @ApiModelProperty(value = "Token过期时间")
-    private Date expirationTime;
-
-    @ApiModelProperty(value = "验证失败原因")
-    private String reason;
-}

+ 273 - 0
alien-store/src/main/java/shop/alien/store/feign/DiningServiceFeign.java

@@ -0,0 +1,273 @@
+package shop.alien.store.feign;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import shop.alien.entity.result.R;
+import shop.alien.entity.store.StoreTable;
+import shop.alien.entity.store.dto.CartDTO;
+import shop.alien.entity.store.dto.ChangeTableDTO;
+import shop.alien.entity.store.vo.*;
+
+import java.util.List;
+
+/**
+ * 点餐服务 Feign 客户端
+ * 用于 alien-store 模块调用 alien-dining 模块的接口
+ *
+ * @author ssk
+ * @version 1.0
+ * @date 2025/01/XX
+ */
+@FeignClient(name = "alien-dining", url = "${feign.alienDining.url:}")
+public interface DiningServiceFeign {
+
+    // ==================== 点餐相关接口 ====================
+
+    /**
+     * 查询餐桌是否处于就餐中(免登录可调用)
+     *
+     * @param tableId 桌号ID
+     * @return R.data 为 TableDiningStatusVO(inDining、dinerCount)
+     */
+    @GetMapping("/store/dining/table-dining-status")
+    R<TableDiningStatusVO> getTableDiningStatus(@RequestParam("tableId") Integer tableId);
+
+    /**
+     * 获取点餐页面信息
+     *
+     * @param authorization 请求头 Authorization,供 dining 解析当前用户
+     * @param tableId       桌号ID
+     * @param dinerCount    就餐人数(首客必传;餐桌已就餐中时可省略)
+     * @return R.data 为 DiningPageInfoVO
+     */
+    @GetMapping("/store/dining/page-info")
+    R<DiningPageInfoVO> getDiningPageInfo(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam("tableId") Integer tableId,
+            @RequestParam(value = "dinerCount", required = false) Integer dinerCount);
+
+    /**
+     * 搜索菜品
+     *
+     * @param authorization 请求头 Authorization
+     * @param storeId       门店ID
+     * @param keyword       搜索关键词
+     * @param tableId       桌号ID
+     * @return R.data 为 List&lt;CuisineListVO&gt;
+     */
+    @GetMapping("/store/dining/search")
+    R<List<CuisineListVO>> searchCuisines(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam("storeId") Integer storeId,
+            @RequestParam("keyword") String keyword,
+            @RequestParam("tableId") Integer tableId);
+
+    /**
+     * 根据分类获取菜品列表
+     *
+     * @param authorization 请求头 Authorization
+     * @param storeId       门店ID
+     * @param categoryId    分类ID(可为空,查询所有)
+     * @param tableId       桌号ID
+     * @param page          页码(默认1)
+     * @param size          每页数量(默认12)
+     * @return R.data 为 List&lt;CuisineListVO&gt;
+     */
+    @GetMapping("/store/dining/cuisines")
+    R<List<CuisineListVO>> getCuisinesByCategory(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam("storeId") Integer storeId,
+            @RequestParam(value = "categoryId", required = false) Integer categoryId,
+            @RequestParam("tableId") Integer tableId,
+            @RequestParam(value = "page", defaultValue = "1") Integer page,
+            @RequestParam(value = "size", defaultValue = "12") Integer size);
+
+    /**
+     * 获取菜品详情
+     *
+     * @param authorization 请求头 Authorization
+     * @param cuisineId     菜品ID
+     * @param tableId       桌号ID
+     * @return R.data 为 CuisineDetailVO
+     */
+    @GetMapping("/store/dining/cuisine/{cuisineId}")
+    R<CuisineDetailVO> getCuisineDetail(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @PathVariable("cuisineId") Integer cuisineId,
+            @RequestParam("tableId") Integer tableId);
+
+    /**
+     * 获取可领取的优惠券列表
+     *
+     * @param authorization 请求头 Authorization
+     * @param storeId       门店ID
+     * @return R.data 为 List&lt;AvailableCouponVO&gt;
+     */
+    @GetMapping("/store/dining/coupons/available")
+    R<List<AvailableCouponVO>> getAvailableCoupons(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam("storeId") Integer storeId);
+
+    // ==================== 订单相关接口 ====================
+
+    /**
+     * 获取购物车
+     *
+     * @param authorization 请求头 Authorization
+     * @param tableId       桌号ID
+     * @return R.data 为 CartDTO
+     */
+    @GetMapping("/store/order/cart/{tableId}")
+    R<CartDTO> getCart(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @PathVariable("tableId") Integer tableId);
+
+    /**
+     * 换桌(迁移购物车、未完成订单及关联数据,支持点餐未下单场景,无需订单号)
+     *
+     * @param authorization 请求头 Authorization
+     * @param dto            原桌号ID、目标桌号ID、换桌原因
+     * @return R.data 为迁移后的购物车 CartDTO
+     */
+    @PostMapping("/store/order/change-table")
+    R<CartDTO> changeTable(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestBody ChangeTableDTO dto);
+
+    /**
+     * 获取订单详情
+     *
+     * @param authorization 请求头 Authorization
+     * @param orderId       订单ID
+     * @return R.data 为 OrderDetailWithChangeLogVO
+     */
+    @GetMapping("/store/order/detail/{orderId}")
+    R<OrderDetailWithChangeLogVO> getOrderDetail(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @PathVariable("orderId") Integer orderId);
+
+    /**
+     * 获取订单列表(分页)
+     *
+     * @param authorization 请求头 Authorization
+     * @param page          页码
+     * @param size          每页数量
+     * @param status        订单状态(可选)
+     * @return R.data 为 IPage&lt;StoreOrderPageVO&gt;
+     */
+    @GetMapping("/store/order/list")
+    R<IPage<StoreOrderPageVO>> getOrderList(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam(value = "page", defaultValue = "1") Integer page,
+            @RequestParam(value = "size", defaultValue = "10") Integer size,
+            @RequestParam(value = "status", required = false) Integer status);
+
+    /**
+     * 分页查询订单列表
+     * 包含订单中的菜品数量、菜品名称、菜品图片。支持按订单编号或菜品名称搜索(限15字)
+     *
+     * @param authorization 请求头 Authorization,供 dining 解析当前用户
+     * @param current       页码(默认1)
+     * @param size         每页数量(默认10)
+     * @param storeId       门店ID(可选)
+     * @param tableId       桌号ID(可选)
+     * @param orderStatus   订单状态(可选,0:待支付, 1:已支付, 2:已取消, 3:已完成)
+     * @param keyword       搜索关键词(订单编号或菜品名称,限15字)(可选)
+     * @return R.data 为 Page&lt;StoreOrderPageVO&gt;(使用具体的 Page 实现类,避免 IPage 反序列化问题)
+     */
+    @GetMapping("/store/order/page")
+    R<Page<StoreOrderPageVO>> getOrderPage(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @RequestParam(value = "current", defaultValue = "1") Long current,
+            @RequestParam(value = "size", defaultValue = "10") Long size,
+            @RequestParam(value = "storeId", required = false) Integer storeId,
+            @RequestParam(value = "tableId", required = false) Integer tableId,
+            @RequestParam(value = "orderStatus", required = false) Integer orderStatus,
+            @RequestParam(value = "keyword", required = false) String keyword);
+
+    /**
+     * 查询订单变更记录
+     *
+     * @param authorization 请求头 Authorization
+     * @param orderId       订单ID
+     * @return R.data 为 List&lt;OrderChangeLogBatchVO&gt;
+     */
+    @GetMapping("/store/order/change-log/{orderId}")
+    R<List<OrderChangeLogBatchVO>> getOrderChangeLogs(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @PathVariable("orderId") Integer orderId);
+
+    /**
+     * 商家手动完成订单(不校验支付状态)
+     *
+     * @param authorization 请求头 Authorization
+     * @param orderId       订单ID
+     * @return R.data 为 Boolean(是否成功)
+     */
+    @PostMapping("/store/order/complete-by-merchant/{orderId}")
+    R<Boolean> completeOrderByMerchant(
+            @RequestHeader(value = "Authorization", required = false) String authorization,
+            @PathVariable("orderId") Integer orderId);
+
+    // ==================== 用户相关接口 ====================
+
+    /**
+     * 获取用户信息
+     * 注意:返回类型使用 Object,因为 DiningUserVo 在 alien-dining 模块中
+     * 调用方需要自行转换为对应的 VO 对象
+     *
+     * @param authorization 请求头 Authorization
+     * @return R.data 为用户信息对象
+     */
+    @GetMapping("/dining/user/getUserInfo")
+    R<Object> getUserInfo(
+            @RequestHeader(value = "Authorization", required = false) String authorization);
+
+    // ==================== 门店信息接口 ====================
+
+    /**
+     * 根据门店ID查询桌号列表
+     *
+     * @param storeId 门店ID
+     * @return R.data 为 List&lt;StoreTable&gt;
+     */
+    @GetMapping("/store/info/tables")
+    R<List<StoreTable>> getTablesByStoreId(
+            @RequestParam("storeId") Integer storeId);
+
+    /**
+     * 根据门店ID查询菜品种类及各类别下菜品(可选按菜品名称模糊查询)
+     *
+     * @param storeId 门店ID
+     * @param keyword 菜品名称模糊查询关键词(可选)
+     * @return R.data 为 List&lt;CategoryWithCuisinesVO&gt;
+     */
+    @GetMapping("/store/info/categories-with-cuisines")
+    R<List<CategoryWithCuisinesVO>> getCategoriesWithCuisinesByStoreId(
+            @RequestParam("storeId") Integer storeId,
+            @RequestParam(value = "keyword", required = false) String keyword);
+
+    /**
+     * 删除菜品种类(仅解除绑定+逻辑删分类,价目表菜品不变)
+     *
+     * @param categoryId 菜品种类ID
+     * @return R.data 为 Boolean
+     */
+    @DeleteMapping("/store/info/category/{categoryId}")
+    R<Boolean> deleteCategory(@PathVariable("categoryId") Integer categoryId);
+
+    // ==================== 文件上传接口 ====================
+
+    /**
+     * 上传图片到OSS(单个文件上传,支持图片、视频或PDF)
+     *
+     * @param file 文件对象
+     * @return R.data 为文件路径(String)
+     */
+    @PostMapping(value = "/dining/file/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    R<String> uploadFile(@RequestPart("file") MultipartFile file);
+}

+ 0 - 15
wechat_dining_tables.sql

@@ -1,15 +0,0 @@
--- 微信小程序点餐专用表:结构与存量 store_* 一致,表名前缀 wechat_store_*
--- 与 APP(alien-store 使用 store_*)数据物理隔离;用户 / 商户(门店主表) / 优惠券主数据仍共用原库中原表。
--- 执行前请备份。MySQL 5.7+ 可用 LIKE 快速建表(不含数据)。
-
-CREATE TABLE IF NOT EXISTS wechat_store_order           LIKE store_order;
-CREATE TABLE IF NOT EXISTS wechat_store_order_detail    LIKE store_order_detail;
-CREATE TABLE IF NOT EXISTS wechat_store_cart            LIKE store_cart;
-CREATE TABLE IF NOT EXISTS wechat_store_table           LIKE store_table;
-CREATE TABLE IF NOT EXISTS wechat_store_table_log       LIKE store_table_log;
-CREATE TABLE IF NOT EXISTS wechat_store_cuisine         LIKE store_cuisine;
-CREATE TABLE IF NOT EXISTS wechat_store_cuisine_category LIKE store_cuisine_category;
-CREATE TABLE IF NOT EXISTS wechat_store_cuisine_combo   LIKE store_cuisine_combo;
-CREATE TABLE IF NOT EXISTS wechat_store_order_lock      LIKE store_order_lock;
-CREATE TABLE IF NOT EXISTS wechat_store_order_change_log LIKE store_order_change_log;
-CREATE TABLE IF NOT EXISTS wechat_store_coupon_usage    LIKE store_coupon_usage;

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff