Browse Source

Merge branch 'dev/2024/0514/update-admin-Y' of feifan/mall-backend-admin into master

确认微信模板信息是否发送
Yangzw 10 months ago
parent
commit
0341c70d23
56 changed files with 2597 additions and 542 deletions
  1. 1 0
      feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/ErrorCodeConstants.java
  2. 14 0
      feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/MessageTemplateConstants.java
  3. 20 0
      feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/wxmessage/WcChatMessageTemplateIdEnum.java
  4. 96 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/MessageLogController.java
  5. 49 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogPageReqVO.java
  6. 57 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogRespVO.java
  7. 48 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogSaveReqVO.java
  8. 7 9
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/order/TradeOrderController.java
  9. 65 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/dataobject/messagelog/MessageLogDO.java
  10. 33 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/mysql/messagelog/MessageLogMapper.java
  11. 7 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/mysql/order/TradeOrderItemMapper.java
  12. 43 12
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/aftersale/AfterSaleServiceImpl.java
  13. 2 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/delivery/DeliveryExpressService.java
  14. 5 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/delivery/DeliveryExpressServiceImpl.java
  15. 55 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/messagelog/MessageLogService.java
  16. 72 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/messagelog/MessageLogServiceImpl.java
  17. 541 521
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/order/TradeOrderUpdateServiceImpl.java
  18. 13 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WcChatMessageDto.java
  19. 266 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WcChatMessageUtils.java
  20. 36 0
      feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WeChatTemplateMessage.java
  21. 12 0
      feifan-module-mall/feifan-module-trade-biz/src/main/resources/mapper/messagelog/MessageLogMapper.xml
  22. 5 0
      feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/dal/dataobject/user/MemberUserDO.java
  23. 8 0
      feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/service/user/MemberUserService.java
  24. 17 0
      feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/service/user/MemberUserServiceImpl.java
  25. 10 0
      feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/constant/SystemConstants.java
  26. 2 0
      feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/enums/ErrorCodeConstants.java
  27. 6 0
      feifan-module-system/feifan-module-system-biz/pom.xml
  28. 64 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/config/StartConfig.java
  29. 94 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/SystemConfigController.java
  30. 31 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/bo/SystemConfigBO.java
  31. 36 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigPageReqVO.java
  32. 41 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigRespVO.java
  33. 28 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigSaveReqVO.java
  34. 94 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/WechatMsgTemplateController.java
  35. 17 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/bo/WechatMsgTemplateBO.java
  36. 30 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplatePageReqVO.java
  37. 33 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplateRespVO.java
  38. 22 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplateSaveReqVO.java
  39. 48 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/dataobject/config/SystemConfigDO.java
  40. 40 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/dataobject/wechatmsgtemplate/WechatMsgTemplateDO.java
  41. 29 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/config/SystemConfigMapper.java
  42. 2 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/social/SocialUserMapper.java
  43. 28 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/wechatmsgtemplate/WechatMsgTemplateMapper.java
  44. 65 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/config/SystemConfigService.java
  45. 97 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/config/SystemConfigServiceImpl.java
  46. 2 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/social/SocialUserService.java
  47. 5 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/social/SocialUserServiceImpl.java
  48. 8 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/user/AdminUserServiceImpl.java
  49. 68 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/wechatmsgtemplate/WechatMsgTemplateService.java
  50. 100 0
      feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/wechatmsgtemplate/WechatMsgTemplateServiceImpl.java
  51. 12 0
      feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/config/ConfigMapper.xml
  52. 10 0
      feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/social/SocialUserMapper.xml
  53. 12 0
      feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/wechatmsgtemplate/WechatMsgTemplateMapper.xml
  54. 16 0
      sql/mysql/建空库SQL/6_20240412.sql
  55. 20 0
      sql/mysql/建空库SQL/7_20240506.sql
  56. 55 0
      sql/mysql/建空库SQL/8_20240512.sql

+ 1 - 0
feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/ErrorCodeConstants.java

@@ -97,5 +97,6 @@ public interface ErrorCodeConstants {
     ErrorCode SUBSCRIBER_ERROR = new ErrorCode(1_011_008_006, "订阅异常");
     ErrorCode ORDER_CALLBACK_LOGS_NOT_EXISTS = new ErrorCode(1_011_008_007, "回调日志不存在");
     ErrorCode CREATE_TRADE_ORDER_LOGS_ERROR = new ErrorCode(1_011_008_008, "创建第三方日志异常");
+    ErrorCode MESSAGE_LOG_NOT_EXISTS = new ErrorCode(1_011_008_009, "微信模板消息日志不存在");
 
 }

+ 14 - 0
feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/MessageTemplateConstants.java

@@ -1,6 +1,9 @@
 package cn.newfeifan.mall.module.trade.enums;
 
 // TODO @非繁人:枚举
+
+import java.util.Arrays;
+
 /**
  * 通知模板枚举类
  *
@@ -13,4 +16,15 @@ public interface MessageTemplateConstants {
     String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过)
     String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过)
 
+    /**
+     * 售后订单待审核通知需要的权限
+     */
+    String[] AFTER_SALE_NO_CHECK_List = Arrays.asList("trade:after-sale:query", "trade:after-sale:agree", "trade:after-sale:disagree"
+            , "trade:after-sale:receive", "trade:after-sale:receive", "trade:after-sale:refund").toArray(new String[0]);
+
+    /**
+     * 订单待发货通知需要的权限
+     */
+    String[] ORDER_NO_DELIVERY_List = Arrays.asList("trade:order:query", "trade:order:update", "trade:order:pick-up").toArray(new String[0]);
+
 }

+ 20 - 0
feifan-module-mall/feifan-module-trade-api/src/main/java/cn/newfeifan/mall/module/trade/enums/wxmessage/WcChatMessageTemplateIdEnum.java

@@ -0,0 +1,20 @@
+package cn.newfeifan.mall.module.trade.enums.wxmessage;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 自定义的微信消息模板枚举
+ */
+@Getter
+@RequiredArgsConstructor
+public enum WcChatMessageTemplateIdEnum {
+
+    ORDER_DELIVERY("1","订单发货通知"),
+    AFTER_SALE_CHECK("2","售后订单审核通知"),
+    AFTER_SALE_NO_CHECK("3","售后订单待审核通知"),
+    ORDER_NO_DELIVERY("4","订单待发货通知");
+
+    private final String templateId;
+    private final String name;
+}

+ 96 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/MessageLogController.java

@@ -0,0 +1,96 @@
+package cn.newfeifan.mall.module.trade.controller.admin.messagelog;
+
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogPageReqVO;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogRespVO;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogSaveReqVO;
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.pojo.CommonResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+import static cn.newfeifan.mall.framework.common.pojo.CommonResult.success;
+
+import cn.newfeifan.mall.framework.excel.core.util.ExcelUtils;
+
+import cn.newfeifan.mall.framework.operatelog.core.annotations.OperateLog;
+import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.newfeifan.mall.module.trade.dal.dataobject.messagelog.MessageLogDO;
+import cn.newfeifan.mall.module.trade.service.messagelog.MessageLogService;
+
+@Tag(name = "管理后台 - 微信消息记录")
+@RestController
+@RequestMapping("/wechat/message-log")
+@Validated
+public class MessageLogController {
+
+    @Resource
+    private MessageLogService messageLogService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建微信消息记录")
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:create')")
+    public CommonResult<Long> createMessageLog(@Valid @RequestBody MessageLogSaveReqVO createReqVO) {
+        return success(messageLogService.createMessageLog(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新微信消息记录")
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:update')")
+    public CommonResult<Boolean> updateMessageLog(@Valid @RequestBody MessageLogSaveReqVO updateReqVO) {
+        messageLogService.updateMessageLog(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除微信消息记录")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:delete')")
+    public CommonResult<Boolean> deleteMessageLog(@RequestParam("id") Long id) {
+        messageLogService.deleteMessageLog(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得微信消息记录")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:query')")
+    public CommonResult<MessageLogRespVO> getMessageLog(@RequestParam("id") Long id) {
+        MessageLogDO messageLog = messageLogService.getMessageLog(id);
+        return success(BeanUtils.toBean(messageLog, MessageLogRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得微信消息记录分页")
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:query')")
+    public CommonResult<PageResult<MessageLogRespVO>> getMessageLogPage(@Valid MessageLogPageReqVO pageReqVO) {
+        PageResult<MessageLogDO> pageResult = messageLogService.getMessageLogPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, MessageLogRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出微信消息记录 Excel")
+    @PreAuthorize("@ss.hasPermission('wechat:message-log:export')")
+    @OperateLog(type = EXPORT)
+    public void exportMessageLogExcel(@Valid MessageLogPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<MessageLogDO> list = messageLogService.getMessageLogPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "微信消息记录.xls", "数据", MessageLogRespVO.class,
+                        BeanUtils.toBean(list, MessageLogRespVO.class));
+    }
+
+}

+ 49 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogPageReqVO.java

@@ -0,0 +1,49 @@
+package cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.newfeifan.mall.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 微信消息记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class MessageLogPageReqVO extends PageParam {
+
+    @Schema(description = "接收消息用户的openid", example = "20952")
+    private String openid;
+
+    @Schema(description = "会员用户ID", example = "16486")
+    private Long memberUserId;
+
+    @Schema(description = "系统用户ID", example = "13077")
+    private Long systemUserId;
+
+    @Schema(description = "微信消息模板ID", example = "13313")
+    private Long wechatMsgTemplateId;
+
+    @Schema(description = "微信消息模板参数")
+    private String wechatMsgTemplateParams;
+
+    @Schema(description = "对应的业务对象ID,如订单ID、售后订单ID", example = "30167")
+    private Long objectId;
+
+    @Schema(description = "发送时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] sendTime;
+
+    @Schema(description = "微信返回的消息发送状态", example = "1")
+    private Boolean sendStatus;
+
+    @Schema(description = "微信返回的消息响应结果")
+    private String responseResult;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 57 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogRespVO.java

@@ -0,0 +1,57 @@
+package cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 微信消息记录 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class MessageLogRespVO {
+
+    @Schema(description = "消息记录ID,自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "20647")
+    @ExcelProperty("消息记录ID,自增主键")
+    private Long id;
+
+    @Schema(description = "接收消息用户的openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "20952")
+    @ExcelProperty("接收消息用户的openid")
+    private String openid;
+
+    @Schema(description = "会员用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "16486")
+    @ExcelProperty("会员用户ID")
+    private Long memberUserId;
+
+    @Schema(description = "系统用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "13077")
+    @ExcelProperty("系统用户ID")
+    private Long systemUserId;
+
+    @Schema(description = "微信消息模板ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "13313")
+    @ExcelProperty("微信消息模板ID")
+    private Long wechatMsgTemplateId;
+
+    @Schema(description = "微信消息模板参数")
+    @ExcelProperty("微信消息模板参数")
+    private String wechatMsgTemplateParams;
+
+    @Schema(description = "对应的业务对象ID,如订单ID、售后订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30167")
+    @ExcelProperty("对应的业务对象ID,如订单ID、售后订单ID")
+    private Long objectId;
+
+    @Schema(description = "发送时间")
+    @ExcelProperty("发送时间")
+    private LocalDateTime sendTime;
+
+    @Schema(description = "微信返回的消息发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @ExcelProperty("微信返回的消息发送状态")
+    private Boolean sendStatus;
+
+    @Schema(description = "微信返回的消息响应结果")
+    @ExcelProperty("微信返回的消息响应结果")
+    private String responseResult;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 48 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/messagelog/vo/MessageLogSaveReqVO.java

@@ -0,0 +1,48 @@
+package cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import javax.validation.constraints.*;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 微信消息记录新增/修改 Request VO")
+@Data
+@Builder
+public class MessageLogSaveReqVO {
+
+    @Schema(description = "消息记录ID,自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "20647")
+    private Long id;
+
+    @Schema(description = "接收消息用户的openid", requiredMode = Schema.RequiredMode.REQUIRED, example = "20952")
+    @NotEmpty(message = "接收消息用户的openid不能为空")
+    private String openid;
+
+    @Schema(description = "会员用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "16486")
+    @NotNull(message = "会员用户ID不能为空")
+    private Long memberUserId;
+
+    @Schema(description = "系统用户ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "13077")
+    private Long systemUserId;
+
+    @Schema(description = "微信消息模板ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "13313")
+    @NotNull(message = "微信消息模板ID不能为空")
+    private Long wechatMsgTemplateId;
+
+    @Schema(description = "微信消息模板参数")
+    private String wechatMsgTemplateParams;
+
+    @Schema(description = "对应的业务对象ID,如订单ID、售后订单ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30167")
+    @NotNull(message = "对应的业务对象ID,如订单ID、售后订单ID不能为空")
+    private Long objectId;
+
+    @Schema(description = "发送时间")
+    private LocalDateTime sendTime;
+
+    @Schema(description = "微信返回的消息发送状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "微信返回的消息发送状态不能为空")
+    private Boolean sendStatus;
+
+    @Schema(description = "微信返回的消息响应结果")
+    private String responseResult;
+
+}

+ 7 - 9
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/controller/admin/order/TradeOrderController.java

@@ -58,7 +58,6 @@ import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils
 import static cn.newfeifan.mall.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.newfeifan.mall.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.CALLBACK_PARAMETER_ERROR;
-import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.CREATE_TRADE_ORDER_LOGS_ERROR;
 
 @Tag(name = "管理后台 - 交易订单")
 @RestController
@@ -190,6 +189,7 @@ public class TradeOrderController {
         subscribeResp.setReturnCode("200");
         subscribeResp.setMessage("成功");
         //加密如果相等,属于快递100推送;否则可以忽略掉当前请求
+        ObjectMapper mapper = new ObjectMapper();
         if (ourSign.equals(sign)) {
             //判断订单状态是否是已签收
             if (state.equals(TradeOrderStateEnum.RECEIVED.getState())) {
@@ -201,16 +201,14 @@ public class TradeOrderController {
                 tradeOrderUpdateService.updateOrderById(order);
             }
 
-            //添加到日志
-            ObjectMapper mapper = new ObjectMapper();
-            try {
-                orderCallbackLogsService.create(orderId, param, mapper.writeValueAsString(lastResult), lastResult.get("status").toString());
-            } catch (JsonProcessingException e) {
-                throw exception(CREATE_TRADE_ORDER_LOGS_ERROR);
-            }
             return subscribeResp;
         }
-        orderCallbackLogsService.create(orderId, param, null, lastResult.get("status").toString());
+        //添加到日志
+        try {
+            orderCallbackLogsService.create(orderId, param, mapper.writeValueAsString(lastResult), lastResult.get("status").toString());
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        }
         return null;
     }
 

+ 65 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/dataobject/messagelog/MessageLogDO.java

@@ -0,0 +1,65 @@
+package cn.newfeifan.mall.module.trade.dal.dataobject.messagelog;
+
+import lombok.*;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.newfeifan.mall.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 微信消息记录 DO
+ *
+ * @author 非繁人
+ */
+@TableName("wechat_message_log")
+@KeySequence("wechat_message_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MessageLogDO extends BaseDO {
+
+    /**
+     * 消息记录ID,自增主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * 接收消息用户的openid
+     */
+    private String openid;
+    /**
+     * 会员用户ID
+     */
+    private Long memberUserId;
+    /**
+     * 系统用户ID
+     */
+    private Long systemUserId;
+    /**
+     * 微信消息模板ID
+     */
+    private Long wechatMsgTemplateId;
+    /**
+     * 微信消息模板参数
+     */
+    private String wechatMsgTemplateParams;
+    /**
+     * 对应的业务对象ID,如订单ID、售后订单ID
+     */
+    private Long objectId;
+    /**
+     * 发送时间
+     */
+    private LocalDateTime sendTime;
+    /**
+     * 微信返回的消息发送状态
+     */
+    private Boolean sendStatus;
+    /**
+     * 微信返回的消息响应结果
+     */
+    private String responseResult;
+
+}

+ 33 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/mysql/messagelog/MessageLogMapper.java

@@ -0,0 +1,33 @@
+package cn.newfeifan.mall.module.trade.dal.mysql.messagelog;
+
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.newfeifan.mall.framework.mybatis.core.mapper.BaseMapperX;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogPageReqVO;
+import cn.newfeifan.mall.module.trade.dal.dataobject.messagelog.MessageLogDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 微信消息记录 Mapper
+ *
+ * @author 非繁人
+ */
+@Mapper
+public interface MessageLogMapper extends BaseMapperX<MessageLogDO> {
+
+    default PageResult<MessageLogDO> selectPage(MessageLogPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<MessageLogDO>()
+                .eqIfPresent(MessageLogDO::getOpenid, reqVO.getOpenid())
+                .eqIfPresent(MessageLogDO::getMemberUserId, reqVO.getMemberUserId())
+                .eqIfPresent(MessageLogDO::getSystemUserId, reqVO.getSystemUserId())
+                .eqIfPresent(MessageLogDO::getWechatMsgTemplateId, reqVO.getWechatMsgTemplateId())
+                .eqIfPresent(MessageLogDO::getWechatMsgTemplateParams, reqVO.getWechatMsgTemplateParams())
+                .eqIfPresent(MessageLogDO::getObjectId, reqVO.getObjectId())
+                .betweenIfPresent(MessageLogDO::getSendTime, reqVO.getSendTime())
+                .eqIfPresent(MessageLogDO::getSendStatus, reqVO.getSendStatus())
+                .eqIfPresent(MessageLogDO::getResponseResult, reqVO.getResponseResult())
+                .betweenIfPresent(MessageLogDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(MessageLogDO::getId));
+    }
+
+}

+ 7 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/dal/mysql/order/TradeOrderItemMapper.java

@@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
 import cn.newfeifan.mall.framework.mybatis.core.mapper.BaseMapperX;
 import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.newfeifan.mall.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -14,6 +15,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 @Mapper
 public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
@@ -53,4 +55,9 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
         return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0;
     }
 
+    default String getSupNameByOrderId(Long orderId){
+        List<TradeOrderItemDO> tradeOrderItemDOS = selectList(new LambdaQueryWrapper<TradeOrderItemDO>()
+                .eq(TradeOrderItemDO::getOrderId, orderId));
+        return tradeOrderItemDOS.stream().map(TradeOrderItemDO::getSpuName).collect(Collectors.joining(","));
+    }
 }

+ 43 - 12
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/aftersale/AfterSaleServiceImpl.java

@@ -27,12 +27,14 @@ import cn.newfeifan.mall.module.trade.enums.aftersale.AfterSaleTypeEnum;
 import cn.newfeifan.mall.module.trade.enums.aftersale.AfterSaleWayEnum;
 import cn.newfeifan.mall.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.newfeifan.mall.module.trade.enums.order.TradeOrderStatusEnum;
+import cn.newfeifan.mall.module.trade.enums.wxmessage.WcChatMessageTemplateIdEnum;
 import cn.newfeifan.mall.module.trade.framework.aftersale.core.annotations.AfterSaleLog;
 import cn.newfeifan.mall.module.trade.framework.aftersale.core.utils.AfterSaleLogUtils;
 import cn.newfeifan.mall.module.trade.framework.order.config.TradeOrderProperties;
 import cn.newfeifan.mall.module.trade.service.delivery.DeliveryExpressService;
 import cn.newfeifan.mall.module.trade.service.order.TradeOrderQueryService;
 import cn.newfeifan.mall.module.trade.service.order.TradeOrderUpdateService;
+import cn.newfeifan.mall.module.trade.utils.wechat.WcChatMessageUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.common.collect.Maps;
 import lombok.extern.slf4j.Slf4j;
@@ -43,7 +45,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.text.DecimalFormat;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -78,6 +83,9 @@ public class AfterSaleServiceImpl implements AfterSaleService {
     @Resource
     private TradeOrderProperties tradeOrderProperties;
 
+    @Resource
+    private WcChatMessageUtils wcChatMessageUtils;
+
     @Override
     public PageResult<AfterSaleDO> getAfterSalePage(AfterSalePageReqVO pageReqVO) {
         return tradeAfterSaleMapper.selectPage(pageReqVO);
@@ -100,7 +108,7 @@ public class AfterSaleServiceImpl implements AfterSaleService {
 
     @Override
     public List<AfterSaleDO> getAfterSaleByOrderId(Long orderId) {
-        return tradeAfterSaleMapper.selectList(new LambdaQueryWrapper<AfterSaleDO>().eq(AfterSaleDO::getOrderId,orderId));
+        return tradeAfterSaleMapper.selectList(new LambdaQueryWrapper<AfterSaleDO>().eq(AfterSaleDO::getOrderId, orderId));
     }
 
     @Override
@@ -223,7 +231,8 @@ public class AfterSaleServiceImpl implements AfterSaleService {
         // 记录售后日志
         AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(), newStatus);
 
-        // TODO 发送售后消息
+        // 发送给微信用户售后消息
+        sentWcChatMessage(afterSale,false);
 
         // 更新交易订单项的售后状态为【未申请】
         tradeOrderUpdateService.updateOrderItemWhenAfterSaleCancel(afterSale.getOrderItemId());
@@ -370,12 +379,34 @@ public class AfterSaleServiceImpl implements AfterSaleService {
         AfterSaleLogUtils.setAfterSaleInfo(afterSale.getId(), afterSale.getStatus(),
                 AfterSaleStatusEnum.COMPLETE.getStatus());
 
-        // TODO 发送售后消息
+        // 发送给微信用户售后消息
+        sentWcChatMessage(afterSale,true);
 
         // 更新交易订单项的售后状态为【已完成】
         tradeOrderUpdateService.updateOrderItemWhenAfterSaleSuccess(afterSale.getOrderItemId(), afterSale.getRefundPrice());
     }
 
+    /**
+     * 发送微信消息
+     * @param afterSale 售后订单
+     * @param afterStatus 是否同意退款
+     */
+    private void sentWcChatMessage(AfterSaleDO afterSale,Boolean afterStatus) {
+        List<String> params = new ArrayList<>();
+        params.add(afterSale.getNo());
+        params.add(afterSale.getSpuName());
+
+        DecimalFormat df = new DecimalFormat("0.00");
+        String formattedPrice = df.format((double) afterSale.getRefundPrice() / 100);
+
+        params.add("¥ " + formattedPrice);
+        params.add(afterStatus ? "商家确认退款" : "商家拒绝退款");
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        params.add(LocalDateTime.now().format(formatter));
+        wcChatMessageUtils.sendWcChatMessage(afterSale.getUserId(), WcChatMessageTemplateIdEnum.AFTER_SALE_CHECK.getTemplateId(),
+                params, null, afterSale.getUserId(), afterSale.getId());
+    }
+
     private void createPayRefund(String userIp, AfterSaleDO afterSale) {
         TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
 
@@ -427,28 +458,28 @@ public class AfterSaleServiceImpl implements AfterSaleService {
 
     @Override
     public Long getApplyingAfterSaleCount(Long userId, TradeOrderPageReqVO reqVO) {
-        return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES,reqVO);
+        return tradeAfterSaleMapper.selectCountByUserIdAndStatus(userId, AfterSaleStatusEnum.APPLYING_STATUSES, reqVO);
     }
 
     @Override
     public Map<Integer, Long> getTabsCount(AfterSalePageReqVO pageVO) {
         Map<Integer, Long> counts = Maps.newLinkedHashMapWithExpectedSize(8);
         // 查询申请售后的售后订单
-        counts.put(AfterSaleStatusEnum.APPLY.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.APPLY.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.APPLY.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.APPLY.getStatus(), pageVO));
         // 查询商品待退货的售后订单
-        counts.put(AfterSaleStatusEnum.SELLER_AGREE.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_AGREE.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.SELLER_AGREE.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_AGREE.getStatus(), pageVO));
         // 查询商家待收货的售后订单
-        counts.put(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.BUYER_DELIVERY.getStatus(), pageVO));
         // 查询等待退款的售后订单
-        counts.put(AfterSaleStatusEnum.WAIT_REFUND.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.WAIT_REFUND.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.WAIT_REFUND.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.WAIT_REFUND.getStatus(), pageVO));
         // 查询退款成功的售后订单
-        counts.put(AfterSaleStatusEnum.COMPLETE.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.COMPLETE.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.COMPLETE.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.COMPLETE.getStatus(), pageVO));
         // 查询买家取消的售后订单
-        counts.put(AfterSaleStatusEnum.BUYER_CANCEL.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.BUYER_CANCEL.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.BUYER_CANCEL.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.BUYER_CANCEL.getStatus(), pageVO));
         // 查询商家拒绝的售后订单
-        counts.put(AfterSaleStatusEnum.SELLER_DISAGREE.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_DISAGREE.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.SELLER_DISAGREE.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_DISAGREE.getStatus(), pageVO));
         // 查询商家拒收货的售后订单
-        counts.put(AfterSaleStatusEnum.SELLER_REFUSE.getStatus(),tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_REFUSE.getStatus(),pageVO));
+        counts.put(AfterSaleStatusEnum.SELLER_REFUSE.getStatus(), tradeAfterSaleMapper.selectCount(AfterSaleStatusEnum.SELLER_REFUSE.getStatus(), pageVO));
         return counts;
     }
 

+ 2 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/delivery/DeliveryExpressService.java

@@ -80,4 +80,6 @@ public interface DeliveryExpressService {
     List<DeliveryExpressDO> getDeliveryExpressListByStatus(Integer status);
 
     DeliveryExpressDO selectByCode(String code);
+
+    String getDeliveryNameById(Long id);
 }

+ 5 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/delivery/DeliveryExpressServiceImpl.java

@@ -116,4 +116,9 @@ public class DeliveryExpressServiceImpl implements DeliveryExpressService {
         return deliveryExpressMapper.selectByCode(code);
     }
 
+    @Override
+    public String getDeliveryNameById(Long id) {
+        return deliveryExpressMapper.selectById(id).getName();
+    }
+
 }

+ 55 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/messagelog/MessageLogService.java

@@ -0,0 +1,55 @@
+package cn.newfeifan.mall.module.trade.service.messagelog;
+
+import javax.validation.*;
+
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogPageReqVO;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogSaveReqVO;
+import cn.newfeifan.mall.module.trade.dal.dataobject.messagelog.MessageLogDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+
+/**
+ * 微信消息记录 Service 接口
+ *
+ * @author 非繁人
+ */
+public interface MessageLogService {
+
+    /**
+     * 创建微信消息记录
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createMessageLog(@Valid MessageLogSaveReqVO createReqVO);
+
+    /**
+     * 更新微信消息记录
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateMessageLog(@Valid MessageLogSaveReqVO updateReqVO);
+
+    /**
+     * 删除微信消息记录
+     *
+     * @param id 编号
+     */
+    void deleteMessageLog(Long id);
+
+    /**
+     * 获得微信消息记录
+     *
+     * @param id 编号
+     * @return 微信消息记录
+     */
+    MessageLogDO getMessageLog(Long id);
+
+    /**
+     * 获得微信消息记录分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 微信消息记录分页
+     */
+    PageResult<MessageLogDO> getMessageLogPage(MessageLogPageReqVO pageReqVO);
+
+}

+ 72 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/messagelog/MessageLogServiceImpl.java

@@ -0,0 +1,72 @@
+package cn.newfeifan.mall.module.trade.service.messagelog;
+
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogPageReqVO;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogSaveReqVO;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import cn.newfeifan.mall.module.trade.dal.dataobject.messagelog.MessageLogDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+
+import cn.newfeifan.mall.module.trade.dal.mysql.messagelog.MessageLogMapper;
+
+import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.newfeifan.mall.module.trade.enums.ErrorCodeConstants.MESSAGE_LOG_NOT_EXISTS;
+
+/**
+ * 微信消息记录 Service 实现类
+ *
+ * @author 非繁人
+ */
+@Service
+@Validated
+public class MessageLogServiceImpl implements MessageLogService {
+
+    @Resource
+    private MessageLogMapper messageLogMapper;
+
+    @Override
+    public Long createMessageLog(MessageLogSaveReqVO createReqVO) {
+        // 插入
+        MessageLogDO messageLog = BeanUtils.toBean(createReqVO, MessageLogDO.class);
+        messageLogMapper.insert(messageLog);
+        // 返回
+        return messageLog.getId();
+    }
+
+    @Override
+    public void updateMessageLog(MessageLogSaveReqVO updateReqVO) {
+        // 校验存在
+        validateMessageLogExists(updateReqVO.getId());
+        // 更新
+        MessageLogDO updateObj = BeanUtils.toBean(updateReqVO, MessageLogDO.class);
+        messageLogMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteMessageLog(Long id) {
+        // 校验存在
+        validateMessageLogExists(id);
+        // 删除
+        messageLogMapper.deleteById(id);
+    }
+
+    private void validateMessageLogExists(Long id) {
+        if (messageLogMapper.selectById(id) == null) {
+            throw exception(MESSAGE_LOG_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public MessageLogDO getMessageLog(Long id) {
+        return messageLogMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<MessageLogDO> getMessageLogPage(MessageLogPageReqVO pageReqVO) {
+        return messageLogMapper.selectPage(pageReqVO);
+    }
+
+}

+ 541 - 521
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/service/order/TradeOrderUpdateServiceImpl.java

@@ -37,6 +37,7 @@ import cn.newfeifan.mall.module.trade.dal.mysql.order.TradeOrderMapper;
 import cn.newfeifan.mall.module.trade.dal.redis.no.TradeNoRedisDAO;
 import cn.newfeifan.mall.module.trade.enums.delivery.DeliveryTypeEnum;
 import cn.newfeifan.mall.module.trade.enums.order.*;
+import cn.newfeifan.mall.module.trade.enums.wxmessage.WcChatMessageTemplateIdEnum;
 import cn.newfeifan.mall.module.trade.framework.order.config.TradeOrderProperties;
 import cn.newfeifan.mall.module.trade.framework.order.core.annotations.TradeOrderLog;
 import cn.newfeifan.mall.module.trade.framework.order.core.utils.TradeOrderLogUtils;
@@ -49,6 +50,7 @@ import cn.newfeifan.mall.module.trade.service.price.TradePriceService;
 import cn.newfeifan.mall.module.trade.service.price.bo.TradePriceCalculateReqBO;
 import cn.newfeifan.mall.module.trade.service.price.bo.TradePriceCalculateRespBO;
 import cn.newfeifan.mall.module.trade.service.price.calculator.TradePriceCalculatorHelper;
+import cn.newfeifan.mall.module.trade.utils.wechat.WcChatMessageUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
@@ -67,6 +69,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -117,6 +120,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
 
     @Resource
     private TradeOrderProperties tradeOrderProperties;
+    @Resource
+    private WcChatMessageUtils wcChatMessageUtils;
 
     @Value("${feifan.trade.express.kd100.key}")
     private String key;
@@ -289,6 +294,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 4. 记录订单日志
         TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.UNDELIVERED.getStatus());
         TradeOrderLogUtils.setUserInfo(order.getUserId(), UserTypeEnum.MEMBER.getValue());
+
+        // 5. 发送订单待发货消息
+
     }
 
     /**
@@ -391,614 +399,626 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
         // 4. 发送站内信
         tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO()
                 .setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null));
+
+        //5.发送微信模板消息
+        List<String> params = new ArrayList<>();
+        params.add(order.getNo());
+        params.add(deliveryExpressService.getDeliveryNameById(order.getLogisticsId()));
+        params.add(order.getLogisticsNo());
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        params.add(LocalDateTime.now().format(formatter));
+        params.add(tradeOrderItemMapper.getSupNameByOrderId(order.getId()));
+        wcChatMessageUtils.sendWcChatMessage(order.getUserId(), WcChatMessageTemplateIdEnum.ORDER_DELIVERY.getTemplateId(),
+                params, null,order.getUserId(), order.getId());
     }
 
-    /**
-     * 测试订阅物流信息
-     *
-     * @param order 交易订单对象,包含物流信息和接收人手机号
-     * @throws Exception 抛出异常,可能由于外部服务调用失败等原因
-     */
-    private void testSubscribe(TradeOrderDO order) throws Exception {
-        // 根据物流ID获取配送信息
-        DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(order.getLogisticsId());
-
-        // 设置订阅参数,包括回调URL和手机号
-        SubscribeParameters subscribeParameters = new SubscribeParameters();
-        subscribeParameters.setCallbackurl("http://47.107.28.221:8002/admin-api/trade/order/callBackUrl?orderId="+order.getId());
-        subscribeParameters.setPhone(order.getReceiverMobile());
-        //添加盐
-        subscribeParameters.setSalt(order.getLogisticsNo());
-
-        // 创建订阅参数实例,并设置相关公司代码、物流单号和密钥
-        SubscribeParam subscribeParam = new SubscribeParam();
-        subscribeParam.setParameters(subscribeParameters);
-        subscribeParam.setCompany(deliveryExpress.getCode());
-        subscribeParam.setNumber(order.getLogisticsNo());
-        subscribeParam.setKey(key);
-
-        // 构建订阅请求对象,设置请求模式和参数
-        SubscribeReq subscribeReq = new SubscribeReq();
-        subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
-        subscribeReq.setParam(new Gson().toJson(subscribeParam));
-
-        // 调用订阅服务,并打印执行结果
-        IBaseClient subscribe = new Subscribe();
-        HttpResult execute = subscribe.execute(subscribeReq);
-
-        Gson gson = new Gson();
-        JsonObject jsonObject = gson.fromJson(execute.getBody(), JsonObject.class);
-        boolean result = jsonObject.get("result").getAsBoolean();
-        String returnCode = jsonObject.get("returnCode").getAsString();
-
-        if (result && returnCode.equals("200")) {
-            log.info("订单号:{}:订阅成功",order.getLogisticsNo());
-
-            order.setSubscriptionLogisticsInfo(TradeOrderSubscribeStatusEnum.SUBSCRIBE.getStatus());
-        } else if(returnCode.equals("600") || returnCode.equals("601")) {
-            throw exception(NOT_SUFFICIENT_FUNDS);
-        } else {
-            log.info("订单号:{}:订阅失败",order.getLogisticsNo());
+/**
+ * 订阅物流信息
+ *
+ * @param order 交易订单对象,包含物流信息和接收人手机号
+ * @throws Exception 抛出异常,可能由于外部服务调用失败等原因
+ */
+private void testSubscribe(TradeOrderDO order) throws Exception {
+    // 根据物流ID获取配送信息
+    DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(order.getLogisticsId());
+
+    // 设置订阅参数,包括回调URL和手机号
+    SubscribeParameters subscribeParameters = new SubscribeParameters();
+    subscribeParameters.setCallbackurl("http://47.107.28.221:8002/admin-api/trade/order/callBackUrl?orderId=" + order.getId());
+    subscribeParameters.setPhone(order.getReceiverMobile());
+    //添加盐
+    subscribeParameters.setSalt(order.getLogisticsNo());
+
+    // 创建订阅参数实例,并设置相关公司代码、物流单号和密钥
+    SubscribeParam subscribeParam = new SubscribeParam();
+    subscribeParam.setParameters(subscribeParameters);
+    subscribeParam.setCompany(deliveryExpress.getCode());
+    subscribeParam.setNumber(order.getLogisticsNo());
+    subscribeParam.setKey(key);
+
+    // 构建订阅请求对象,设置请求模式和参数
+    SubscribeReq subscribeReq = new SubscribeReq();
+    subscribeReq.setSchema(ApiInfoConstant.SUBSCRIBE_SCHEMA);
+    subscribeReq.setParam(new Gson().toJson(subscribeParam));
+
+    // 调用订阅服务,并打印执行结果
+    IBaseClient subscribe = new Subscribe();
+    HttpResult execute = subscribe.execute(subscribeReq);
+
+    Gson gson = new Gson();
+    JsonObject jsonObject = gson.fromJson(execute.getBody(), JsonObject.class);
+    boolean result = jsonObject.get("result").getAsBoolean();
+    String returnCode = jsonObject.get("returnCode").getAsString();
+
+    if (result && returnCode.equals("200")) {
+        log.info("订单号:{}:订阅成功", order.getLogisticsNo());
+
+        order.setSubscriptionLogisticsInfo(TradeOrderSubscribeStatusEnum.SUBSCRIBE.getStatus());
+    } else if (returnCode.equals("600") || returnCode.equals("601")) {
+        throw exception(NOT_SUFFICIENT_FUNDS);
+    } else {
+        log.info("订单号:{}:订阅失败", order.getLogisticsNo());
+
+        order.setSubscriptionLogisticsInfo(TradeOrderSubscribeStatusEnum.abnormal.getStatus());
+    }
+    tradeOrderMapper.updateById(order);
 
-            order.setSubscriptionLogisticsInfo(TradeOrderSubscribeStatusEnum.abnormal.getStatus());
-        }
-        tradeOrderMapper.updateById(order);
+}
 
+/**
+ * 校验交易订单满足被发货的条件
+ * <p>
+ * 1. 交易订单未发货
+ *
+ * @param id 交易订单编号
+ * @return 交易订单
+ */
+private TradeOrderDO validateOrderDeliverable(Long id) {
+    TradeOrderDO order = validateOrderExists(id);
+    // 1. 校验订单是否未发货
+    if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
+        throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
     }
 
-    /**
-     * 校验交易订单满足被发货的条件
-     * <p>
-     * 1. 交易订单未发货
-     *
-     * @param id 交易订单编号
-     * @return 交易订单
-     */
-    private TradeOrderDO validateOrderDeliverable(Long id) {
-        TradeOrderDO order = validateOrderExists(id);
-        // 1. 校验订单是否未发货
-        if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
-            throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
-        }
+    // 2. 执行 TradeOrderHandler 前置处理
+    tradeOrderHandlers.forEach(handler -> handler.beforeDeliveryOrder(order));
+    return order;
+}
 
-        // 2. 执行 TradeOrderHandler 前置处理
-        tradeOrderHandlers.forEach(handler -> handler.beforeDeliveryOrder(order));
-        return order;
+@NotNull
+private TradeOrderDO validateOrderExists(Long id) {
+    // 校验订单是否存在
+    TradeOrderDO order = tradeOrderMapper.selectById(id);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
     }
+    return order;
+}
 
-    @NotNull
-    private TradeOrderDO validateOrderExists(Long id) {
-        // 校验订单是否存在
-        TradeOrderDO order = tradeOrderMapper.selectById(id);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        return order;
-    }
+@Override
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE)
+public void receiveOrderByMember(Long userId, Long id) {
+    // 校验并获得交易订单(可收货)
+    TradeOrderDO order = validateOrderReceivable(userId, id);
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_RECEIVE)
-    public void receiveOrderByMember(Long userId, Long id) {
-        // 校验并获得交易订单(可收货)
-        TradeOrderDO order = validateOrderReceivable(userId, id);
+    // 收货订单
+    receiveOrder0(order);
+}
 
-        // 收货订单
-        receiveOrder0(order);
+@Override
+public int receiveOrderBySystem() {
+    // 1. 查询过期的待支付订单
+    LocalDateTime expireTime = minusTime(tradeOrderProperties.getReceiveExpireTime());
+    List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
+            TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
+    if (CollUtil.isEmpty(orders)) {
+        return 0;
     }
 
-    @Override
-    public int receiveOrderBySystem() {
-        // 1. 查询过期的待支付订单
-        LocalDateTime expireTime = minusTime(tradeOrderProperties.getReceiveExpireTime());
-        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndDeliveryTimeLt(
-                TradeOrderStatusEnum.DELIVERED.getStatus(), expireTime);
-        if (CollUtil.isEmpty(orders)) {
-            return 0;
-        }
-
-        // 2. 遍历执行,逐个取消
-        int count = 0;
-        for (TradeOrderDO order : orders) {
-            try {
-                getSelf().receiveOrderBySystem(order);
-                count++;
-            } catch (Throwable e) {
-                log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e);
-            }
+    // 2. 遍历执行,逐个取消
+    int count = 0;
+    for (TradeOrderDO order : orders) {
+        try {
+            getSelf().receiveOrderBySystem(order);
+            count++;
+        } catch (Throwable e) {
+            log.error("[receiveOrderBySystem][order({}) 自动收货订单异常]", order.getId(), e);
         }
-        return count;
     }
+    return count;
+}
 
-    /**
-     * 自动收货单个订单
-     *
-     * @param order 订单
-     */
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
-    public void receiveOrderBySystem(TradeOrderDO order) {
-        receiveOrder0(order);
+/**
+ * 自动收货单个订单
+ *
+ * @param order 订单
+ */
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_RECEIVE)
+public void receiveOrderBySystem(TradeOrderDO order) {
+    receiveOrder0(order);
+}
+
+/**
+ * 收货订单的核心实现
+ *
+ * @param order 订单
+ */
+private void receiveOrder0(TradeOrderDO order) {
+    // 更新 TradeOrderDO 状态为已完成
+    int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
+            new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
+    if (updateCount == 0) {
+        throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
     }
 
-    /**
-     * 收货订单的核心实现
-     *
-     * @param order 订单
-     */
-    private void receiveOrder0(TradeOrderDO order) {
-        // 更新 TradeOrderDO 状态为已完成
-        int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
-                new TradeOrderDO().setStatus(TradeOrderStatusEnum.COMPLETED.getStatus()).setReceiveTime(LocalDateTime.now()));
-        if (updateCount == 0) {
-            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
-        }
+    // 插入订单日志
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
+}
 
-        // 插入订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus());
+/**
+ * 校验交易订单满足可售货的条件
+ * <p>
+ * 1. 交易订单待收货
+ *
+ * @param userId 用户编号
+ * @param id     交易订单编号
+ * @return 交易订单
+ */
+private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
+    // 校验订单是否存在
+    TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
     }
+    // 校验订单是否是待收货状态
+    if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
+        throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
+    }
+    return order;
+}
 
-    /**
-     * 校验交易订单满足可售货的条件
-     * <p>
-     * 1. 交易订单待收货
-     *
-     * @param userId 用户编号
-     * @param id     交易订单编号
-     * @return 交易订单
-     */
-    private TradeOrderDO validateOrderReceivable(Long userId, Long id) {
-        // 校验订单是否存在
-        TradeOrderDO order = tradeOrderMapper.selectByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 校验订单是否是待收货状态
-        if (!TradeOrderStatusEnum.isDelivered(order.getStatus())) {
-            throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
-        }
-        return order;
+@Override
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
+public void cancelOrderByMember(Long userId, Long id) {
+    // 1.1 校验存在
+    TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
+    }
+    // 1.2 校验状态
+    if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
+        throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CANCEL)
-    public void cancelOrderByMember(Long userId, Long id) {
-        // 1.1 校验存在
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 1.2 校验状态
-        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
-            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
-        }
+    // 2. 取消订单
+    cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
+}
 
-        // 2. 取消订单
-        cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
+@Override
+public int cancelOrderBySystem() {
+    // 1. 查询过期的待支付订单
+    LocalDateTime expireTime = minusTime(tradeOrderProperties.getPayExpireTime());
+    List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
+            TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
+    if (CollUtil.isEmpty(orders)) {
+        return 0;
     }
 
-    @Override
-    public int cancelOrderBySystem() {
-        // 1. 查询过期的待支付订单
-        LocalDateTime expireTime = minusTime(tradeOrderProperties.getPayExpireTime());
-        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndCreateTimeLt(
-                TradeOrderStatusEnum.UNPAID.getStatus(), expireTime);
-        if (CollUtil.isEmpty(orders)) {
-            return 0;
-        }
-
-        // 2. 遍历执行,逐个取消
-        int count = 0;
-        for (TradeOrderDO order : orders) {
-            try {
-                getSelf().cancelOrderBySystem(order);
-                count++;
-            } catch (Throwable e) {
-                log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getId(), e);
-            }
+    // 2. 遍历执行,逐个取消
+    int count = 0;
+    for (TradeOrderDO order : orders) {
+        try {
+            getSelf().cancelOrderBySystem(order);
+            count++;
+        } catch (Throwable e) {
+            log.error("[cancelOrderBySystem][order({}) 过期订单异常]", order.getId(), e);
         }
-        return count;
     }
+    return count;
+}
 
-    /**
-     * 自动取消单个订单
-     *
-     * @param order 订单
-     */
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
-    public void cancelOrderBySystem(TradeOrderDO order) {
-        cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
+/**
+ * 自动取消单个订单
+ *
+ * @param order 订单
+ */
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_CANCEL)
+public void cancelOrderBySystem(TradeOrderDO order) {
+    cancelOrder0(order, TradeOrderCancelTypeEnum.PAY_TIMEOUT);
+}
+
+/**
+ * 取消订单的核心实现
+ *
+ * @param order      订单
+ * @param cancelType 取消类型
+ */
+private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
+    // 1. 更新 TradeOrderDO 状态为已取消
+    int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
+            new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
+                    .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
+    if (updateCount == 0) {
+        throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
     }
 
-    /**
-     * 取消订单的核心实现
-     *
-     * @param order      订单
-     * @param cancelType 取消类型
-     */
-    private void cancelOrder0(TradeOrderDO order, TradeOrderCancelTypeEnum cancelType) {
-        // 1. 更新 TradeOrderDO 状态为已取消
-        int updateCount = tradeOrderMapper.updateByIdAndStatus(order.getId(), order.getStatus(),
-                new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
-                        .setCancelType(cancelType.getType()).setCancelTime(LocalDateTime.now()));
-        if (updateCount == 0) {
-            throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID);
-        }
+    // 2. 执行 TradeOrderHandler 的后置处理
+    List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
+    tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems));
 
-        // 2. 执行 TradeOrderHandler 的后置处理
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems));
+    // 3. 增加订单日志
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
+}
 
-        // 3. 增加订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus());
+/**
+ * 如果金额全部被退款,则取消订单
+ * 如果还有未被退款的金额,则无需取消订单
+ *
+ * @param order       订单
+ * @param refundPrice 退款金额
+ */
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_CANCEL_AFTER_SALE)
+public void cancelOrderByAfterSale(TradeOrderDO order, Integer refundPrice) {
+    // 1. 更新订单
+    if (refundPrice < order.getPayPrice()) {
+        return;
     }
+    tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
+            .setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
+            .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
 
-    /**
-     * 如果金额全部被退款,则取消订单
-     * 如果还有未被退款的金额,则无需取消订单
-     *
-     * @param order       订单
-     * @param refundPrice 退款金额
-     */
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_CANCEL_AFTER_SALE)
-    public void cancelOrderByAfterSale(TradeOrderDO order, Integer refundPrice) {
-        // 1. 更新订单
-        if (refundPrice < order.getPayPrice()) {
-            return;
-        }
-        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
-                .setStatus(TradeOrderStatusEnum.CANCELED.getStatus())
-                .setCancelType(TradeOrderCancelTypeEnum.AFTER_SALE_CLOSE.getType()).setCancelTime(LocalDateTime.now()));
+    // 2. 执行 TradeOrderHandler 的后置处理
+    List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
+    tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems));
+}
 
-        // 2. 执行 TradeOrderHandler 的后置处理
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        tradeOrderHandlers.forEach(handler -> handler.afterCancelOrder(order, orderItems));
+@Override
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
+public void deleteOrder(Long userId, Long id) {
+    // 1.1 校验存在
+    TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
     }
+    // 1.2 校验状态
+    if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
+        throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
+    }
+    // 2. 删除订单
+    tradeOrderMapper.deleteById(id);
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_DELETE)
-    public void deleteOrder(Long userId, Long id) {
-        // 1.1 校验存在
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        // 1.2 校验状态
-        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.CANCELED.getStatus())) {
-            throw exception(ORDER_DELETE_FAIL_STATUS_NOT_CANCEL);
-        }
-        // 2. 删除订单
-        tradeOrderMapper.deleteById(id);
+    // 3. 记录日志
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
+}
 
-        // 3. 记录日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
-    }
+@Override
+public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) {
+    // 校验并获得交易订单
+    validateOrderExists(reqVO.getId());
 
-    @Override
-    public void updateOrderRemark(TradeOrderRemarkReqVO reqVO) {
-        // 校验并获得交易订单
-        validateOrderExists(reqVO.getId());
+    // 更新
+    TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(reqVO);
+    tradeOrderMapper.updateById(order);
+}
 
-        // 更新
-        TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(reqVO);
-        tradeOrderMapper.updateById(order);
+@Override
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_PRICE)
+public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
+    // 1.1 校验交易订单
+    TradeOrderDO order = validateOrderExists(reqVO.getId());
+    if (order.getPayStatus()) {
+        throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
+    }
+    // 1.2 校验调价金额是否变化
+    if (order.getAdjustPrice() > 0) {
+        throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY);
+    }
+    // 1.3 支付价格不能为 0
+    int newPayPrice = order.getPayPrice() + order.getAdjustPrice();
+    if (newPayPrice <= 0) {
+        throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR);
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_PRICE)
-    public void updateOrderPrice(TradeOrderUpdatePriceReqVO reqVO) {
-        // 1.1 校验交易订单
-        TradeOrderDO order = validateOrderExists(reqVO.getId());
-        if (order.getPayStatus()) {
-            throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
-        }
-        // 1.2 校验调价金额是否变化
-        if (order.getAdjustPrice() > 0) {
-            throw exception(ORDER_UPDATE_PRICE_FAIL_ALREADY);
-        }
-        // 1.3 支付价格不能为 0
-        int newPayPrice = order.getPayPrice() + order.getAdjustPrice();
-        if (newPayPrice <= 0) {
-            throw exception(ORDER_UPDATE_PRICE_FAIL_PRICE_ERROR);
-        }
+    // 2. 更新订单
+    tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
+            .setAdjustPrice(reqVO.getAdjustPrice()).setPayPrice(newPayPrice));
+
+    // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊
+    List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
+    List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, newPayPrice);
+    List<TradeOrderItemDO> updateItems = new ArrayList<>();
+    for (int i = 0; i < orderOrderItems.size(); i++) {
+        TradeOrderItemDO item = orderOrderItems.get(i);
+        updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i))
+                .setPayPrice(item.getPayPrice() + dividePrices.get(i)));
+    }
+    tradeOrderItemMapper.updateBatch(updateItems);
 
-        // 2. 更新订单
-        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
-                .setAdjustPrice(reqVO.getAdjustPrice()).setPayPrice(newPayPrice));
-
-        // 3. 更新 TradeOrderItem,需要做 adjustPrice 的分摊
-        List<TradeOrderItemDO> orderOrderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        List<Integer> dividePrices = TradePriceCalculatorHelper.dividePrice2(orderOrderItems, newPayPrice);
-        List<TradeOrderItemDO> updateItems = new ArrayList<>();
-        for (int i = 0; i < orderOrderItems.size(); i++) {
-            TradeOrderItemDO item = orderOrderItems.get(i);
-            updateItems.add(new TradeOrderItemDO().setId(item.getId()).setAdjustPrice(dividePrices.get(i))
-                    .setPayPrice(item.getPayPrice() + dividePrices.get(i)));
-        }
-        tradeOrderItemMapper.updateBatch(updateItems);
+    // 4. 更新支付订单
+    payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice);
 
-        // 4. 更新支付订单
-        payOrderApi.updatePayOrderPrice(order.getPayOrderId(), newPayPrice);
+    // 5. 记录订单日志
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),
+            MapUtil.<String, Object>builder().put("oldPayPrice", MoneyUtils.fenToYuanStr(order.getPayPrice()))
+                    .put("newPayPrice", MoneyUtils.fenToYuanStr(newPayPrice)).build());
+}
 
-        // 5. 记录订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus(),
-                MapUtil.<String, Object>builder().put("oldPayPrice", MoneyUtils.fenToYuanStr(order.getPayPrice()))
-                        .put("newPayPrice", MoneyUtils.fenToYuanStr(newPayPrice)).build());
+@Override
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_ADDRESS)
+public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) {
+    // 校验交易订单
+    TradeOrderDO order = validateOrderExists(reqVO.getId());
+    // 只有待发货状态,才可以修改订单收货地址;
+    if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
+        throw exception(ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED);
     }
 
-    @Override
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_UPDATE_ADDRESS)
-    public void updateOrderAddress(TradeOrderUpdateAddressReqVO reqVO) {
-        // 校验交易订单
-        TradeOrderDO order = validateOrderExists(reqVO.getId());
-        // 只有待发货状态,才可以修改订单收货地址;
-        if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
-            throw exception(ORDER_UPDATE_ADDRESS_FAIL_STATUS_NOT_DELIVERED);
-        }
+    // 更新
+    tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO));
 
-        // 更新
-        tradeOrderMapper.updateById(TradeOrderConvert.INSTANCE.convert(reqVO));
+    // 记录订单日志
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
+}
 
-        // 记录订单日志
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
-    }
+@Override
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
+public void pickUpOrderByAdmin(Long id) {
+    getSelf().pickUpOrder(tradeOrderMapper.selectById(id));
+}
 
-    @Override
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
-    public void pickUpOrderByAdmin(Long id) {
-        getSelf().pickUpOrder(tradeOrderMapper.selectById(id));
-    }
+@Override
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
+public void pickUpOrderByAdmin(String pickUpVerifyCode) {
+    getSelf().pickUpOrder(tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode));
+}
 
-    @Override
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ADMIN_PICK_UP_RECEIVE)
-    public void pickUpOrderByAdmin(String pickUpVerifyCode) {
-        getSelf().pickUpOrder(tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode));
-    }
+@Override
+public TradeOrderDO getByPickUpVerifyCode(String pickUpVerifyCode) {
+    return tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode);
+}
 
-    @Override
-    public TradeOrderDO getByPickUpVerifyCode(String pickUpVerifyCode) {
-        return tradeOrderMapper.selectOneByPickUpVerifyCode(pickUpVerifyCode);
+@Transactional(rollbackFor = Exception.class)
+public void pickUpOrder(TradeOrderDO order) {
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
     }
-
-    @Transactional(rollbackFor = Exception.class)
-    public void pickUpOrder(TradeOrderDO order) {
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        if (ObjUtil.notEqual(DeliveryTypeEnum.PICK_UP.getType(), order.getDeliveryType())) {
-            throw exception(ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP);
-        }
-        receiveOrder0(order);
+    if (ObjUtil.notEqual(DeliveryTypeEnum.PICK_UP.getType(), order.getDeliveryType())) {
+        throw exception(ORDER_RECEIVE_FAIL_DELIVERY_TYPE_NOT_PICK_UP);
     }
+    receiveOrder0(order);
+}
 
-    // =================== Order Item ===================
-
-    @Override
-    public void updateOrderItemWhenAfterSaleCreate(Long id, Long afterSaleId) {
-        // 更新订单项
-        updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
-                TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), afterSaleId);
-    }
+// =================== Order Item ===================
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void updateOrderItemWhenAfterSaleSuccess(Long id, Integer refundPrice) {
-        // 1.1 更新订单项
-        updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
-                TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), null);
-        // 1.2 执行 TradeOrderHandler 的后置处理
-        TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id);
-        TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId());
-        tradeOrderHandlers.forEach(handler -> handler.afterCancelOrderItem(order, orderItem));
-
-        // 2.1 更新订单的退款金额、积分
-        Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
-        Integer orderRefundPoint = order.getRefundPoint() + orderItem.getUsePoint();
-        Integer refundStatus = isAllOrderItemAfterSaleSuccess(order.getId()) ?
-                TradeOrderRefundStatusEnum.ALL.getStatus() // 如果都售后成功,则需要取消订单
-                : TradeOrderRefundStatusEnum.PART.getStatus();
-        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
-                .setRefundStatus(refundStatus)
-                .setRefundPrice(orderRefundPrice).setRefundPoint(orderRefundPoint));
-        // 2.2 如果全部退款,则进行取消订单
-        getSelf().cancelOrderByAfterSale(order, orderRefundPrice);
-    }
+@Override
+public void updateOrderItemWhenAfterSaleCreate(Long id, Long afterSaleId) {
+    // 更新订单项
+    updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(),
+            TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(), afterSaleId);
+}
 
-    @Override
-    public void updateOrderItemWhenAfterSaleCancel(Long id) {
-        // 更新订单项
-        updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
-                TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
-    }
-
-    private void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
-                                                Long afterSaleId) {
-        // 更新订单项
-        int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus, afterSaleId);
-        if (updateCount <= 0) {
-            throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL);
-        }
+@Override
+@Transactional(rollbackFor = Exception.class)
+public void updateOrderItemWhenAfterSaleSuccess(Long id, Integer refundPrice) {
+    // 1.1 更新订单项
+    updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
+            TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus(), null);
+    // 1.2 执行 TradeOrderHandler 的后置处理
+    TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(id);
+    TradeOrderDO order = tradeOrderMapper.selectById(orderItem.getOrderId());
+    tradeOrderHandlers.forEach(handler -> handler.afterCancelOrderItem(order, orderItem));
+
+    // 2.1 更新订单的退款金额、积分
+    Integer orderRefundPrice = order.getRefundPrice() + refundPrice;
+    Integer orderRefundPoint = order.getRefundPoint() + orderItem.getUsePoint();
+    Integer refundStatus = isAllOrderItemAfterSaleSuccess(order.getId()) ?
+            TradeOrderRefundStatusEnum.ALL.getStatus() // 如果都售后成功,则需要取消订单
+            : TradeOrderRefundStatusEnum.PART.getStatus();
+    tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId())
+            .setRefundStatus(refundStatus)
+            .setRefundPrice(orderRefundPrice).setRefundPoint(orderRefundPoint));
+    // 2.2 如果全部退款,则进行取消订单
+    getSelf().cancelOrderByAfterSale(order, orderRefundPrice);
+}
 
-    }
+@Override
+public void updateOrderItemWhenAfterSaleCancel(Long id) {
+    // 更新订单项
+    updateOrderItemAfterSaleStatus(id, TradeOrderItemAfterSaleStatusEnum.APPLY.getStatus(),
+            TradeOrderItemAfterSaleStatusEnum.NONE.getStatus(), null);
+}
 
-    /**
-     * 判断指定订单的所有订单项,是不是都售后成功
-     *
-     * @param id 订单编号
-     * @return 是否都售后成功
-     */
-    private boolean isAllOrderItemAfterSaleSuccess(Long id) {
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
-        return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(),
-                TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
+private void updateOrderItemAfterSaleStatus(Long id, Integer oldAfterSaleStatus, Integer newAfterSaleStatus,
+                                            Long afterSaleId) {
+    // 更新订单项
+    int updateCount = tradeOrderItemMapper.updateAfterSaleStatus(id, oldAfterSaleStatus, newAfterSaleStatus, afterSaleId);
+    if (updateCount <= 0) {
+        throw exception(ORDER_ITEM_UPDATE_AFTER_SALE_STATUS_FAIL);
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_COMMENT)
-    public Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO) {
-        // 1.1 先通过订单项 ID,查询订单项是否存在
-        TradeOrderItemDO orderItem = tradeOrderItemMapper.selectByIdAndUserId(createReqVO.getOrderItemId(), userId);
-        if (orderItem == null) {
-            throw exception(ORDER_ITEM_NOT_FOUND);
-        }
-        // 1.2 校验订单相关状态
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderItem.getOrderId(), userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
-        }
-        if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
-            throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED);
-        }
-        if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) {
-            throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
-        }
+}
 
-        // 2. 创建评价
-        Long commentId = createOrderItemComment0(orderItem, createReqVO);
+/**
+ * 判断指定订单的所有订单项,是不是都售后成功
+ *
+ * @param id 订单编号
+ * @return 是否都售后成功
+ */
+private boolean isAllOrderItemAfterSaleSuccess(Long id) {
+    List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
+    return orderItems.stream().allMatch(orderItem -> Objects.equals(orderItem.getAfterSaleStatus(),
+            TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
+}
 
-        // 3. 如果订单项都评论了,则更新订单评价状态
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
-        if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) {
-            tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)
-                    .setFinishTime(LocalDateTime.now()));
-            // 增加订单日志。注意:只有在所有订单项都评价后,才会增加
-            TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
-        }
-        return commentId;
+@Override
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_COMMENT)
+public Long createOrderItemCommentByMember(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO) {
+    // 1.1 先通过订单项 ID,查询订单项是否存在
+    TradeOrderItemDO orderItem = tradeOrderItemMapper.selectByIdAndUserId(createReqVO.getOrderItemId(), userId);
+    if (orderItem == null) {
+        throw exception(ORDER_ITEM_NOT_FOUND);
+    }
+    // 1.2 校验订单相关状态
+    TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderItem.getOrderId(), userId);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
+    }
+    if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
+        throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED);
+    }
+    if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) {
+        throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
     }
 
-    @Override
-    public int createOrderItemCommentBySystem() {
-        // 1. 查询过期的待支付订单
-        LocalDateTime expireTime = minusTime(tradeOrderProperties.getCommentExpireTime());
-        List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndReceiveTimeLt(
-                TradeOrderStatusEnum.COMPLETED.getStatus(), expireTime, false);
-        if (CollUtil.isEmpty(orders)) {
-            return 0;
-        }
+    // 2. 创建评价
+    Long commentId = createOrderItemComment0(orderItem, createReqVO);
 
-        // 2. 遍历执行,逐个取消
-        int count = 0;
-        for (TradeOrderDO order : orders) {
-            try {
-                getSelf().createOrderItemCommentBySystemBySystem(order);
-                count++;
-            } catch (Throwable e) {
-                log.error("[createOrderItemCommentBySystem][order({}) 过期订单异常]", order.getId(), e);
-            }
-        }
-        return count;
+    // 3. 如果订单项都评论了,则更新订单评价状态
+    List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId());
+    if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) {
+        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)
+                .setFinishTime(LocalDateTime.now()));
+        // 增加订单日志。注意:只有在所有订单项都评价后,才会增加
+        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
     }
+    return commentId;
+}
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId) {
-        tradeOrderMapper.updateById(
-                new TradeOrderDO().setId(orderId).setCombinationActivityId(activityId)
-                        .setCombinationRecordId(combinationRecordId).setCombinationHeadId(headId));
+@Override
+public int createOrderItemCommentBySystem() {
+    // 1. 查询过期的待支付订单
+    LocalDateTime expireTime = minusTime(tradeOrderProperties.getCommentExpireTime());
+    List<TradeOrderDO> orders = tradeOrderMapper.selectListByStatusAndReceiveTimeLt(
+            TradeOrderStatusEnum.COMPLETED.getStatus(), expireTime, false);
+    if (CollUtil.isEmpty(orders)) {
+        return 0;
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void cancelPaidOrder(Long userId, Long orderId) {
-        // TODO 非繁人:这里实现要优化下;
-        TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId);
-        if (order == null) {
-            throw exception(ORDER_NOT_FOUND);
+    // 2. 遍历执行,逐个取消
+    int count = 0;
+    for (TradeOrderDO order : orders) {
+        try {
+            getSelf().createOrderItemCommentBySystemBySystem(order);
+            count++;
+        } catch (Throwable e) {
+            log.error("[createOrderItemCommentBySystem][order({}) 过期订单异常]", order.getId(), e);
         }
-        cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
     }
+    return count;
+}
 
-    /**
-     * 保存订单的签收时间
-     * @param com 快递公司编码
-     * @param nu 单号
-     */
-    public void updateOrder(String com, String nu, LocalDateTime time){
-        DeliveryExpressDO deliveryExpressDO = deliveryExpressService.selectByCode(com);
-        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(new LambdaQueryWrapper<TradeOrderDO>()
-                .eq(TradeOrderDO::getLogisticsNo, nu)
-                .eq(TradeOrderDO::getLogisticsId, deliveryExpressDO.getId())
-                .isNull(TradeOrderDO::getReceivingTime)
-        );
-        if(tradeOrderDO == null){
-            return;
-        }
-        tradeOrderDO.setReceivingTime(time);
+@Override
+@Transactional(rollbackFor = Exception.class)
+public void updateOrderCombinationInfo(Long orderId, Long activityId, Long combinationRecordId, Long headId) {
+    tradeOrderMapper.updateById(
+            new TradeOrderDO().setId(orderId).setCombinationActivityId(activityId)
+                    .setCombinationRecordId(combinationRecordId).setCombinationHeadId(headId));
+}
 
-        tradeOrderMapper.updateById(tradeOrderDO);
+@Override
+@Transactional(rollbackFor = Exception.class)
+public void cancelPaidOrder(Long userId, Long orderId) {
+    // TODO 非繁人:这里实现要优化下;
+    TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(orderId, userId);
+    if (order == null) {
+        throw exception(ORDER_NOT_FOUND);
     }
+    cancelOrder0(order, TradeOrderCancelTypeEnum.MEMBER_CANCEL);
+}
 
-    @Override
-    public void updateOrderById(TradeOrderDO order) {
-        tradeOrderMapper.updateById(order);
+/**
+ * 保存订单的签收时间
+ *
+ * @param com 快递公司编码
+ * @param nu  单号
+ */
+public void updateOrder(String com, String nu, LocalDateTime time) {
+    DeliveryExpressDO deliveryExpressDO = deliveryExpressService.selectByCode(com);
+    TradeOrderDO tradeOrderDO = tradeOrderMapper.selectOne(new LambdaQueryWrapper<TradeOrderDO>()
+            .eq(TradeOrderDO::getLogisticsNo, nu)
+            .eq(TradeOrderDO::getLogisticsId, deliveryExpressDO.getId())
+            .isNull(TradeOrderDO::getReceivingTime)
+    );
+    if (tradeOrderDO == null) {
+        return;
     }
+    tradeOrderDO.setReceivingTime(time);
 
-    /**
-     * 创建单个订单的评论
-     *
-     * @param order 订单
-     */
-    @Transactional(rollbackFor = Exception.class)
-    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_COMMENT)
-    public void createOrderItemCommentBySystemBySystem(TradeOrderDO order) {
-        // 1. 查询未评论的订单项
-        List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderIdAndCommentStatus(
-                order.getId(), Boolean.FALSE);
-        if (CollUtil.isEmpty(orderItems)) {
-            return;
-        }
-
-        // 2. 逐个评论
-        for (TradeOrderItemDO orderItem : orderItems) {
-            // 2.1 创建评价
-            AppTradeOrderItemCommentCreateReqVO commentCreateReqVO = new AppTradeOrderItemCommentCreateReqVO()
-                    .setOrderItemId(orderItem.getId()).setAnonymous(false).setContent("")
-                    .setBenefitScores(5).setDescriptionScores(5);
-            createOrderItemComment0(orderItem, commentCreateReqVO);
+    tradeOrderMapper.updateById(tradeOrderDO);
+}
 
-            // 2.2 更新订单项评价状态
-            tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE));
-        }
+@Override
+public void updateOrderById(TradeOrderDO order) {
+    tradeOrderMapper.updateById(order);
+}
 
-        // 3. 所有订单项都评论了,则更新订单评价状态
-        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)
-                .setFinishTime(LocalDateTime.now()));
-        // 增加订单日志。注意:只有在所有订单项都评价后,才会增加
-        TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
+/**
+ * 创建单个订单的评论
+ *
+ * @param order 订单
+ */
+@Transactional(rollbackFor = Exception.class)
+@TradeOrderLog(operateType = TradeOrderOperateTypeEnum.SYSTEM_COMMENT)
+public void createOrderItemCommentBySystemBySystem(TradeOrderDO order) {
+    // 1. 查询未评论的订单项
+    List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderIdAndCommentStatus(
+            order.getId(), Boolean.FALSE);
+    if (CollUtil.isEmpty(orderItems)) {
+        return;
     }
 
-    /**
-     * 创建订单项的评论的核心实现
-     *
-     * @param orderItem   订单项
-     * @param createReqVO 评论内容
-     * @return 评论编号
-     */
-    private Long createOrderItemComment0(TradeOrderItemDO orderItem, AppTradeOrderItemCommentCreateReqVO createReqVO) {
-        // 1. 创建评价
-        ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem);
-        Long commentId = productCommentApi.createComment(productCommentCreateReqDTO);
+    // 2. 逐个评论
+    for (TradeOrderItemDO orderItem : orderItems) {
+        // 2.1 创建评价
+        AppTradeOrderItemCommentCreateReqVO commentCreateReqVO = new AppTradeOrderItemCommentCreateReqVO()
+                .setOrderItemId(orderItem.getId()).setAnonymous(false).setContent("")
+                .setBenefitScores(5).setDescriptionScores(5);
+        createOrderItemComment0(orderItem, commentCreateReqVO);
 
-        // 2. 更新订单项评价状态
+        // 2.2 更新订单项评价状态
         tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE));
-        return commentId;
     }
 
-    // =================== 营销相关的操作 ===================
+    // 3. 所有订单项都评论了,则更新订单评价状态
+    tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)
+            .setFinishTime(LocalDateTime.now()));
+    // 增加订单日志。注意:只有在所有订单项都评价后,才会增加
+    TradeOrderLogUtils.setOrderInfo(order.getId(), order.getStatus(), order.getStatus());
+}
 
-    /**
-     * 获得自身的代理对象,解决 AOP 生效问题
-     *
-     * @return 自己
-     */
-    private TradeOrderUpdateServiceImpl getSelf() {
-        return SpringUtil.getBean(getClass());
-    }
+/**
+ * 创建订单项的评论的核心实现
+ *
+ * @param orderItem   订单项
+ * @param createReqVO 评论内容
+ * @return 评论编号
+ */
+private Long createOrderItemComment0(TradeOrderItemDO orderItem, AppTradeOrderItemCommentCreateReqVO createReqVO) {
+    // 1. 创建评价
+    ProductCommentCreateReqDTO productCommentCreateReqDTO = TradeOrderConvert.INSTANCE.convert04(createReqVO, orderItem);
+    Long commentId = productCommentApi.createComment(productCommentCreateReqDTO);
+
+    // 2. 更新订单项评价状态
+    tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE));
+    return commentId;
+}
+
+// =================== 营销相关的操作 ===================
+
+/**
+ * 获得自身的代理对象,解决 AOP 生效问题
+ *
+ * @return 自己
+ */
+private TradeOrderUpdateServiceImpl getSelf() {
+    return SpringUtil.getBean(getClass());
+}
 
 }

+ 13 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WcChatMessageDto.java

@@ -0,0 +1,13 @@
+package cn.newfeifan.mall.module.trade.utils.wechat;
+
+import lombok.Data;
+
+/**
+ * 调用微信消息的模板参数类
+ */
+@Data
+public class WcChatMessageDto {
+    private Long userId;
+    private Long wechatMsgTemplateId;
+
+}

+ 266 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WcChatMessageUtils.java

@@ -0,0 +1,266 @@
+package cn.newfeifan.mall.module.trade.utils.wechat;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+import cn.newfeifan.mall.module.member.service.user.MemberUserService;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import cn.newfeifan.mall.module.system.service.config.SystemConfigService;
+import cn.newfeifan.mall.module.system.service.permission.PermissionService;
+import cn.newfeifan.mall.module.system.service.social.SocialUserService;
+import cn.newfeifan.mall.module.system.service.wechatmsgtemplate.WechatMsgTemplateService;
+import cn.newfeifan.mall.module.trade.controller.admin.messagelog.vo.MessageLogSaveReqVO;
+import cn.newfeifan.mall.module.trade.enums.wxmessage.WcChatMessageTemplateIdEnum;
+import cn.newfeifan.mall.module.trade.service.messagelog.MessageLogService;
+import com.google.gson.JsonObject;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import static cn.newfeifan.mall.module.system.constant.SystemConstants.SYSTEM_WX_ACCESS_TOKEN;
+import static cn.newfeifan.mall.module.trade.enums.MessageTemplateConstants.AFTER_SALE_NO_CHECK_List;
+import static cn.newfeifan.mall.module.trade.enums.MessageTemplateConstants.ORDER_NO_DELIVERY_List;
+
+/**
+ * 发送微信消息的工具类
+ */
+@Data
+@Component
+@Slf4j
+public class WcChatMessageUtils {
+
+    @Value("${wx.mp.app-id}")
+    private String appid;
+    @Value("${wx.mp.secret}")
+    private String Wxgsecret;
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+    @Resource
+    private WechatMsgTemplateService wechatMsgTemplateService;
+    @Resource
+    private SocialUserService socialUserService;
+    @Resource
+    private MessageLogService messageLogService;
+    @Resource
+    private SystemConfigService configService;
+    @Resource
+    private PermissionService permissionService;
+    @Resource
+    private MemberUserService memberUserService;
+
+    /**
+     * 获取微信的accessToken
+     *
+     * @return accessToken
+     */
+    public String getAccessToken() {
+
+        String accessToken = stringRedisTemplate.opsForValue().get(SYSTEM_WX_ACCESS_TOKEN);
+
+        if (StrUtil.isEmpty(accessToken)) {
+            // 服务号的appid以及秘钥
+            String requestUrl = StrUtil.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", appid, Wxgsecret);
+            String returnMsg = HttpUtil.get(requestUrl);
+            cn.hutool.json.JSONObject responseJsonObject = JSONUtil.parseObj(returnMsg);
+            if (ObjectUtil.isNull(responseJsonObject)) try {
+                throw new Exception("响应异常:获取信息为空!");
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            accessToken = responseJsonObject.getStr("access_token");
+
+            //微信的accessToken的失效时间是两个小时,这里改为一小时五十五分钟,怕双方的时间误差导致accessToken失效
+            long expireTime = 60 * 60 + 55 * 60; // 1小时55分钟转换为秒
+            stringRedisTemplate.opsForValue().set(SYSTEM_WX_ACCESS_TOKEN, accessToken, expireTime, java.util.concurrent.TimeUnit.SECONDS);
+        }
+
+
+        return accessToken;
+    }
+
+    /**
+     * 发送微信消息
+     *
+     * @param userId              接口消息的用户id
+     * @param data                模板参数
+     * @param wechatMsgTemplateId 自定义的消息模板id
+     */
+    private void sendWxgMessage(Long userId, JsonObject data, String wechatMsgTemplateId, Long systemUserId, Long memberUserId, Long objectId) {
+
+        // 组装消息内容
+        String userOpenId = null;
+        if (wechatMsgTemplateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_NO_CHECK.getTemplateId()) ||
+                wechatMsgTemplateId.equals(WcChatMessageTemplateIdEnum.ORDER_NO_DELIVERY.getTemplateId())) {
+            userOpenId = getOpenIdBySysTemUserId(systemUserId);
+        } else {
+            userOpenId = getOpenId(userId);
+        }
+
+        //如果用户没有绑定微信,则不发送消息
+        if (userOpenId == null) {
+            return;
+        }
+
+        String templateId = getTemplateId(wechatMsgTemplateId).getWechatMsgTemplateId(); // 模板id
+        String url = getDoMain(wechatMsgTemplateId, objectId);       // 跳转路径(小程序之外)
+        String client_msg_id = UUID.randomUUID().toString();  // 防重入id
+
+
+        WeChatTemplateMessage message = new WeChatTemplateMessage();
+        message.setTouser(userOpenId);
+        message.setTemplate_id(templateId);
+        message.setUrl(url);
+        message.setClient_msg_id(client_msg_id);
+        message.setData(data);
+
+        // 发送消息
+        String returnMsg = HttpUtil.post(StrUtil.format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={}", getAccessToken()), message.toString());
+        cn.hutool.json.JSONObject jsonObject2 = JSONUtil.parseObj(returnMsg);
+        String errmsg = jsonObject2.getStr("errmsg");
+
+        //记录发送的微信消息
+        MessageLogSaveReqVO messageLogSaveReqVO = MessageLogSaveReqVO.builder()
+                .openid(userOpenId)
+                .memberUserId(userId)
+                .systemUserId(systemUserId)
+                .memberUserId(memberUserId)
+                .wechatMsgTemplateId(Long.valueOf(wechatMsgTemplateId))
+                .wechatMsgTemplateParams(message.toString())
+                .objectId(objectId)
+                .sendStatus(true)
+                .sendTime(LocalDateTime.now())
+                .responseResult(returnMsg)
+                .build();
+        if (!StrUtil.equals("ok", errmsg)) {
+            log.info("=====消息发送失败,原因:{}", errmsg);
+            messageLogSaveReqVO.setSendStatus(false);
+        }
+
+        messageLogService.createMessageLog(messageLogSaveReqVO);
+    }
+
+    /**
+     * 获取待发货模板参数
+     *
+     * @return 待发货模板参数
+     */
+    public JsonObject getTemplateData(List<String> dataParams, List<String> params) {
+
+        JsonObject data = new JsonObject();
+
+        // 添加字段及其值
+        for (int i = 0; i < Math.min(params.size(), dataParams.size()); i++) {
+            String paramName = dataParams.get(i);
+            String paramValue = params.get(i);
+
+            JsonObject obj = new JsonObject();
+            obj.addProperty("value", paramValue);
+            data.add(paramName, obj);
+        }
+
+        return data;
+    }
+
+    /**
+     * 发送微信信息
+     *
+     * @param userId       用户id
+     * @param templateId   自定义消息模板id
+     * @param params       消息参数
+     * @param systemUserId 系统用户id
+     * @param memberUserId 会员用户id
+     * @param objectId     对象id
+     */
+    public void sendWcChatMessage(Long userId, String templateId, List<String> params, Long systemUserId, Long memberUserId, Long objectId) {
+        WechatMsgTemplateDO template = getTemplateId(templateId);
+        String messageTemplateParameters = template.getMessageTemplateParameters();
+
+        // 去除首尾的括号,并去除空格
+        messageTemplateParameters = messageTemplateParameters.substring(1, messageTemplateParameters.length() - 1).trim();
+
+        // 使用逗号分割字符串,并去除空格
+        String[] parts = messageTemplateParameters.split(",\\s*");
+
+        // 创建集合并将数组转换为集合
+        List<String> dataParams = Arrays.asList(parts);
+        JsonObject templateData = getTemplateData(dataParams, params);
+
+        // 发送微信消息
+        sendWxgMessage(userId, templateData, templateId, systemUserId, memberUserId, objectId);
+    }
+
+    /**
+     * 判断用户是否有接收者调消息的权限
+     *
+     * @param userId     用户id
+     * @param templateId 自定义的模板id
+     * @return 是否有权限
+     */
+    public Boolean isHavePermission(Long userId, String templateId) {
+        if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_NO_CHECK.getTemplateId())) {
+            // 售后待审核
+            return permissionService.hasAnyPermissions(userId, AFTER_SALE_NO_CHECK_List);
+        } else if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_NO_DELIVERY.getTemplateId())) {
+            // 订单待发货
+            return permissionService.hasAnyPermissions(userId, ORDER_NO_DELIVERY_List);
+        }
+        return false;
+    }
+
+    /**
+     * 获取不同端域名(不同的端的代码略有不同)
+     *
+     * @param templateId 自定义模板id
+     * @return 域名加路径
+     */
+    public String getDoMain(String templateId, Long objectId) {
+        SystemConfigDO redisConfig = configService.getRedisConfig();
+        if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_DELIVERY.getTemplateId())) {
+            //订单已发货
+            return redisConfig.getMallDomain() + "/#/pages/order/detail?id=" + objectId;
+        } else if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_CHECK.getTemplateId())) {
+            //售后订单审核完成
+            return redisConfig.getMallDomain() + "/#/pages/order/aftersale/detail?id=" + objectId;
+        } else if (templateId.equals(WcChatMessageTemplateIdEnum.AFTER_SALE_NO_CHECK.getTemplateId())) {
+            //售后订单待审核
+            return redisConfig.getPlatformDomain() + "/after-sale";
+        } else if (templateId.equals(WcChatMessageTemplateIdEnum.ORDER_NO_DELIVERY.getTemplateId())) {
+            //订单待发货
+            return redisConfig.getPlatformDomain() + "/order";
+        }
+        return null;
+    }
+
+    /**
+     * 通过自己定义消息模板id获取微信第三方模板
+     *
+     * @param wechatMsgTemplateId 自己定义消息模板id
+     * @return 微信第三方模板
+     */
+    private WechatMsgTemplateDO getTemplateId(String wechatMsgTemplateId) {
+        return wechatMsgTemplateService.getWechatSsgTemplate(Long.valueOf(wechatMsgTemplateId));
+    }
+
+    private String getOpenId(Long userId) {
+        return socialUserService.getOpenIdByUserId(userId);
+    }
+
+    private String getOpenIdBySysTemUserId(Long systemUserId) {
+        Long memberUserId = memberUserService.getUserIdBySystemUserId(systemUserId);
+        if (memberUserId == null) {
+            return null;
+        }
+        return getOpenId(memberUserId);
+    }
+}

+ 36 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/java/cn/newfeifan/mall/module/trade/utils/wechat/WeChatTemplateMessage.java

@@ -0,0 +1,36 @@
+package cn.newfeifan.mall.module.trade.utils.wechat;
+
+import com.google.gson.JsonObject;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * 微信模板消息
+ */
+@Data
+public class WeChatTemplateMessage {
+    private String touser;
+
+    private String template_id;
+
+    private String url;
+
+    private MiniProgram miniprogram;
+
+    private String client_msg_id;
+
+    private JsonObject data;
+
+    // Inner classes
+    @lombok.Data
+    @AllArgsConstructor
+    public static class MiniProgram {
+        private String appid;
+        private String pagepath;
+    }
+
+
+    public String toString(){
+        return "{\"touser\":\"" + touser + "\",\"template_id\":\"" + template_id + "\",\"url\":\"" + url + "\",\"client_msg_id\":\"" + client_msg_id + "\",\"data\":" + data.toString() + "}";
+    }
+}

+ 12 - 0
feifan-module-mall/feifan-module-trade-biz/src/main/resources/mapper/messagelog/MessageLogMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.newfeifan.mall.module.wechat.dal.mysql.messagelog.MessageLogMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.zhongxing.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 5 - 0
feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/dal/dataobject/user/MemberUserDO.java

@@ -189,4 +189,9 @@ public class MemberUserDO extends TenantBaseDO {
      */
     private Long cumulativeSpending;
 
+    /**
+     * 关联系统用户ID
+     */
+    private Long systemUsersId;
+
 }

+ 8 - 0
feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/service/user/MemberUserService.java

@@ -190,5 +190,13 @@ public interface MemberUserService {
 
     List<MemberUserDO> getAllUser();
 
+    /**
+     * 通过手机号更新用户
+     * @param systemUserId 系统用户id
+     * @param mobile 手机号
+     */
+    void updateUserByMobile(Long systemUserId, String mobile);
+
 
+    Long getUserIdBySystemUserId(Long systemUserId);
 }

+ 17 - 0
feifan-module-member/feifan-module-member-biz/src/main/java/cn/newfeifan/mall/module/member/service/user/MemberUserServiceImpl.java

@@ -319,4 +319,21 @@ public class MemberUserServiceImpl implements MemberUserService {
         return memberUserMapper.selectList();
     }
 
+    @Override
+    public void updateUserByMobile(Long systemUserId, String mobile) {
+        if(StrUtil.isEmpty(mobile)){
+            return;
+        }
+
+        MemberUserDO memberUserDO = memberUserMapper.selectByMobile(mobile);
+        memberUserDO.setSystemUsersId(systemUserId);
+        memberUserMapper.updateById(memberUserDO);
+    }
+
+    @Override
+    public Long getUserIdBySystemUserId(Long systemUserId) {
+        MemberUserDO memberUserDO = memberUserMapper.selectOne(MemberUserDO::getSystemUsersId, systemUserId);
+        return memberUserDO == null ? null : memberUserDO.getId();
+    }
+
 }

+ 10 - 0
feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/constant/SystemConstants.java

@@ -0,0 +1,10 @@
+package cn.newfeifan.mall.module.system.constant;
+
+public class SystemConstants {
+    public static final String SYSTEM_WX_ACCESS_TOKEN = "system:wx:access_token";
+
+    public static final String SYSTEM_WX_MESSAGE_TEMPLATE = "system:wx:message:template:";
+
+    public static final String SYSTEM_CONFIG = "system:config";
+
+}

+ 2 - 0
feifan-module-system/feifan-module-system-api/src/main/java/cn/newfeifan/mall/module/system/enums/ErrorCodeConstants.java

@@ -170,5 +170,7 @@ public interface ErrorCodeConstants {
 
     // ========== 站内信发送 1-002-028-000 ==========
     ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失");
+    ErrorCode WECHAT_MSG_TEMPLATE_NOT_EXISTS = new ErrorCode(1_002_028_001, "微信消息模板不存在");
+    ErrorCode CONFIG_NOT_EXISTS = new ErrorCode(1_002_028_002, "系统配置不存在");
 
 }

+ 6 - 0
feifan-module-system/feifan-module-system-biz/pom.xml

@@ -135,6 +135,12 @@
             <groupId>com.tencentcloudapi</groupId>
             <artifactId>tencentcloud-sdk-java-sms</artifactId> <!-- 短信(腾讯云) -->
         </dependency>
+        <dependency>
+            <groupId>cn.newfeifan.zx</groupId>
+            <artifactId>feifan-module-member-biz</artifactId>
+            <version>2.0.0-jdk8-snapshot</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
 </project>

+ 64 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/config/StartConfig.java

@@ -0,0 +1,64 @@
+package cn.newfeifan.mall.module.system.config;
+
+import cn.newfeifan.mall.framework.common.util.json.JsonUtils;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import cn.newfeifan.mall.module.system.service.config.SystemConfigService;
+import cn.newfeifan.mall.module.system.service.wechatmsgtemplate.WechatMsgTemplateService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.newfeifan.mall.module.system.constant.SystemConstants.SYSTEM_CONFIG;
+import static cn.newfeifan.mall.module.system.constant.SystemConstants.SYSTEM_WX_MESSAGE_TEMPLATE;
+
+
+/**
+ * 启动配置类
+ */
+@Component
+@Slf4j
+public class StartConfig {
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Resource
+    private WechatMsgTemplateService wechatMsgTemplateService;
+
+    @Resource
+    private SystemConfigService configService;
+
+    @PostConstruct
+    public void init() {
+        initWechatMsgTemplate();
+
+        initSystemConfig();
+    }
+
+    /**
+     * 初始化微信模板配置
+     */
+    private void initWechatMsgTemplate() {
+        List<WechatMsgTemplateDO> wechatMsgTemplateDOS = wechatMsgTemplateService.selectList();
+        wechatMsgTemplateDOS.forEach(wechatMsgTemplateDO -> {
+            stringRedisTemplate.opsForValue().set(SYSTEM_WX_MESSAGE_TEMPLATE + wechatMsgTemplateDO.getId(), JsonUtils.toJsonString(wechatMsgTemplateDO));
+        });
+
+        log.info("======初始化微信模板配置成功======");
+    }
+
+    /**
+     * 初始化系统配置
+     */
+    private void initSystemConfig(){
+        SystemConfigDO config = configService.getConfig();
+        stringRedisTemplate.opsForValue().set(SYSTEM_CONFIG, JsonUtils.toJsonString(config));
+
+        log.info("======初始化系统配置成功======");
+    }
+}

+ 94 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/SystemConfigController.java

@@ -0,0 +1,94 @@
+package cn.newfeifan.mall.module.system.controller.admin.config;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.pojo.CommonResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+import static cn.newfeifan.mall.framework.common.pojo.CommonResult.success;
+
+import cn.newfeifan.mall.framework.excel.core.util.ExcelUtils;
+
+import cn.newfeifan.mall.framework.operatelog.core.annotations.OperateLog;
+import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.newfeifan.mall.module.system.controller.admin.config.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import cn.newfeifan.mall.module.system.service.config.SystemConfigService;
+
+@Tag(name = "管理后台 - 系统配置")
+@RestController
+@RequestMapping("/system/config")
+@Validated
+public class SystemConfigController {
+
+    @Resource
+    private SystemConfigService configService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建系统配置")
+    @PreAuthorize("@ss.hasPermission('system:config:create')")
+    public CommonResult<Long> createConfig(@Valid @RequestBody ConfigSaveReqVO createReqVO) {
+        return success(configService.createConfig(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新系统配置")
+    @PreAuthorize("@ss.hasPermission('system:config:update')")
+    public CommonResult<Boolean> updateConfig(@Valid @RequestBody ConfigSaveReqVO updateReqVO) {
+        configService.updateConfig(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除系统配置")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('system:config:delete')")
+    public CommonResult<Boolean> deleteConfig(@RequestParam("id") Long id) {
+        configService.deleteConfig(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得系统配置")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('system:config:query')")
+    public CommonResult<ConfigRespVO> getConfig(@RequestParam("id") Long id) {
+        SystemConfigDO config = configService.getConfig(id);
+        return success(BeanUtils.toBean(config, ConfigRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得系统配置分页")
+    @PreAuthorize("@ss.hasPermission('system:config:query')")
+    public CommonResult<PageResult<ConfigRespVO>> getConfigPage(@Valid ConfigPageReqVO pageReqVO) {
+        PageResult<SystemConfigDO> pageResult = configService.getConfigPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, ConfigRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出系统配置 Excel")
+    @PreAuthorize("@ss.hasPermission('system:config:export')")
+    @OperateLog(type = EXPORT)
+    public void exportConfigExcel(@Valid ConfigPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<SystemConfigDO> list = configService.getConfigPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "系统配置.xls", "数据", ConfigRespVO.class,
+                        BeanUtils.toBean(list, ConfigRespVO.class));
+    }
+
+}

+ 31 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/bo/SystemConfigBO.java

@@ -0,0 +1,31 @@
+package cn.newfeifan.mall.module.system.controller.admin.config.bo;
+
+import lombok.Data;
+
+/**
+ * 用来接收redis缓存中的值
+ */
+@Data
+public class SystemConfigBO {
+    private Long id;
+    /**
+     * 微信服务号appid
+     */
+    private String wechatAppid;
+    /**
+     * 微信服务号秘钥
+     */
+    private String wechatSecretKey;
+    /**
+     * 平台端协议+域名+端口
+     */
+    private String platformDomain;
+    /**
+     * 商户端协议+域名+端口
+     */
+    private String merchantDomain;
+    /**
+     * 移动商城端协议+域名+端口
+     */
+    private String mallDomain;
+}

+ 36 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigPageReqVO.java

@@ -0,0 +1,36 @@
+package cn.newfeifan.mall.module.system.controller.admin.config.vo;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.newfeifan.mall.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 系统配置分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class ConfigPageReqVO extends PageParam {
+
+    @Schema(description = "微信服务号appid", example = "31635")
+    private String wechatAppid;
+
+    @Schema(description = "微信服务号秘钥")
+    private String wechatSecretKey;
+
+    @Schema(description = "平台端协议+域名+端口")
+    private String platformDomain;
+
+    @Schema(description = "商户端协议+域名+端口")
+    private String merchantDomain;
+
+    @Schema(description = "移动商城端协议+域名+端口")
+    private String mallDomain;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 41 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigRespVO.java

@@ -0,0 +1,41 @@
+package cn.newfeifan.mall.module.system.controller.admin.config.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 系统配置 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class ConfigRespVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "18615")
+    @ExcelProperty("主键")
+    private Long id;
+
+    @Schema(description = "微信服务号appid", example = "31635")
+    @ExcelProperty("微信服务号appid")
+    private String wechatAppid;
+
+    @Schema(description = "微信服务号秘钥")
+    @ExcelProperty("微信服务号秘钥")
+    private String wechatSecretKey;
+
+    @Schema(description = "平台端协议+域名+端口")
+    @ExcelProperty("平台端协议+域名+端口")
+    private String platformDomain;
+
+    @Schema(description = "商户端协议+域名+端口")
+    @ExcelProperty("商户端协议+域名+端口")
+    private String merchantDomain;
+
+    @Schema(description = "移动商城端协议+域名+端口")
+    @ExcelProperty("移动商城端协议+域名+端口")
+    private String mallDomain;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 28 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/config/vo/ConfigSaveReqVO.java

@@ -0,0 +1,28 @@
+package cn.newfeifan.mall.module.system.controller.admin.config.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+@Schema(description = "管理后台 - 系统配置新增/修改 Request VO")
+@Data
+public class ConfigSaveReqVO {
+
+    @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "18615")
+    private Long id;
+
+    @Schema(description = "微信服务号appid", example = "31635")
+    private String wechatAppid;
+
+    @Schema(description = "微信服务号秘钥")
+    private String wechatSecretKey;
+
+    @Schema(description = "平台端协议+域名+端口")
+    private String platformDomain;
+
+    @Schema(description = "商户端协议+域名+端口")
+    private String merchantDomain;
+
+    @Schema(description = "移动商城端协议+域名+端口")
+    private String mallDomain;
+
+}

+ 94 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/WechatMsgTemplateController.java

@@ -0,0 +1,94 @@
+package cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.pojo.CommonResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+import static cn.newfeifan.mall.framework.common.pojo.CommonResult.success;
+
+import cn.newfeifan.mall.framework.excel.core.util.ExcelUtils;
+
+import cn.newfeifan.mall.framework.operatelog.core.annotations.OperateLog;
+import static cn.newfeifan.mall.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import cn.newfeifan.mall.module.system.service.wechatmsgtemplate.WechatMsgTemplateService;
+
+@Tag(name = "管理后台 - 微信消息模板")
+@RestController
+@RequestMapping("/system/wechat-msg-template")
+@Validated
+public class WechatMsgTemplateController {
+
+    @Resource
+    private WechatMsgTemplateService wechatMsgTemplateService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建微信消息模板")
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:create')")
+    public CommonResult<Long> createWechatMsgTemplate(@Valid @RequestBody WechatMsgTemplateSaveReqVO createReqVO) {
+        return success(wechatMsgTemplateService.createWechatMsgTemplate(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新微信消息模板")
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:update')")
+    public CommonResult<Boolean> updateWechatMsgTemplate(@Valid @RequestBody WechatMsgTemplateSaveReqVO updateReqVO) {
+        wechatMsgTemplateService.updateWechatMsgTemplate(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除微信消息模板")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:delete')")
+    public CommonResult<Boolean> deleteWechatMsgTemplate(@RequestParam("id") Long id) {
+        wechatMsgTemplateService.deleteWechatMsgTemplate(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得微信消息模板")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:query')")
+    public CommonResult<WechatMsgTemplateRespVO> getWechatMsgTemplate(@RequestParam("id") Long id) {
+        WechatMsgTemplateDO wechatMsgTemplate = wechatMsgTemplateService.getWechatMsgTemplate(id);
+        return success(BeanUtils.toBean(wechatMsgTemplate, WechatMsgTemplateRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得微信消息模板分页")
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:query')")
+    public CommonResult<PageResult<WechatMsgTemplateRespVO>> getWechatMsgTemplatePage(@Valid WechatMsgTemplatePageReqVO pageReqVO) {
+        PageResult<WechatMsgTemplateDO> pageResult = wechatMsgTemplateService.getWechatMsgTemplatePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, WechatMsgTemplateRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出微信消息模板 Excel")
+    @PreAuthorize("@ss.hasPermission('system:wechat-msg-template:export')")
+    @OperateLog(type = EXPORT)
+    public void exportWechatMsgTemplateExcel(@Valid WechatMsgTemplatePageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<WechatMsgTemplateDO> list = wechatMsgTemplateService.getWechatMsgTemplatePage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "微信消息模板.xls", "数据", WechatMsgTemplateRespVO.class,
+                        BeanUtils.toBean(list, WechatMsgTemplateRespVO.class));
+    }
+
+}

+ 17 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/bo/WechatMsgTemplateBO.java

@@ -0,0 +1,17 @@
+package cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.bo;
+
+import lombok.Data;
+
+/**
+ * 用来接收redis缓存中的值
+ */
+@Data
+public class WechatMsgTemplateBO {
+    private Long id;
+
+    private String wechatMsgTemplateId;
+
+    private String remark;
+
+    private String messageTemplateParameters;
+}

+ 30 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplatePageReqVO.java

@@ -0,0 +1,30 @@
+package cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.newfeifan.mall.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.newfeifan.mall.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 微信消息模板分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WechatMsgTemplatePageReqVO extends PageParam {
+
+    @Schema(description = "微信消息模板id", example = "29466")
+    private String wechatMsgTemplateId;
+
+    @Schema(description = "备注、说明", example = "随便")
+    private String remark;
+
+    @Schema(description = "消息模板参数")
+    private String messageTemplateParameters;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 33 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplateRespVO.java

@@ -0,0 +1,33 @@
+package cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 微信消息模板 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WechatMsgTemplateRespVO {
+
+    @Schema(description = "模板id,非自增,由开发人员编号,对应java中的常量", requiredMode = Schema.RequiredMode.REQUIRED, example = "13788")
+    @ExcelProperty("模板id,非自增,由开发人员编号,对应java中的常量")
+    private Long id;
+
+    @Schema(description = "微信消息模板id", example = "29466")
+    @ExcelProperty("微信消息模板id")
+    private String wechatMsgTemplateId;
+
+    @Schema(description = "备注、说明", example = "随便")
+    @ExcelProperty("备注、说明")
+    private String remark;
+
+    @Schema(description = "消息模板参数")
+    @ExcelProperty("消息模板参数")
+    private String messageTemplateParameters;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 22 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/controller/admin/wechatmsgtemplate/vo/WechatMsgTemplateSaveReqVO.java

@@ -0,0 +1,22 @@
+package cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+@Schema(description = "管理后台 - 微信消息模板新增/修改 Request VO")
+@Data
+public class WechatMsgTemplateSaveReqVO {
+
+    @Schema(description = "模板id,非自增,由开发人员编号,对应java中的常量", requiredMode = Schema.RequiredMode.REQUIRED, example = "13788")
+    private Long id;
+
+    @Schema(description = "微信消息模板id", example = "29466")
+    private String wechatMsgTemplateId;
+
+    @Schema(description = "备注、说明", example = "随便")
+    private String remark;
+
+    @Schema(description = "消息模板参数")
+    private String messageTemplateParameters;
+
+}

+ 48 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/dataobject/config/SystemConfigDO.java

@@ -0,0 +1,48 @@
+package cn.newfeifan.mall.module.system.dal.dataobject.config;
+
+import lombok.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.newfeifan.mall.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 系统配置 DO
+ *
+ * @author 非繁人
+ */
+@TableName("system_config")
+@KeySequence("system_config_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SystemConfigDO extends BaseDO {
+
+    /**
+     * 主键
+     */
+    @TableId
+    private Long id;
+    /**
+     * 微信服务号appid
+     */
+    private String wechatAppid;
+    /**
+     * 微信服务号秘钥
+     */
+    private String wechatSecretKey;
+    /**
+     * 平台端协议+域名+端口
+     */
+    private String platformDomain;
+    /**
+     * 商户端协议+域名+端口
+     */
+    private String merchantDomain;
+    /**
+     * 移动商城端协议+域名+端口
+     */
+    private String mallDomain;
+
+}

+ 40 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/dataobject/wechatmsgtemplate/WechatMsgTemplateDO.java

@@ -0,0 +1,40 @@
+package cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate;
+
+import lombok.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.newfeifan.mall.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 微信消息模板 DO
+ *
+ * @author 非繁人
+ */
+@TableName("system_wechat_msg_template")
+@KeySequence("system_wechat_msg_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WechatMsgTemplateDO extends BaseDO {
+
+    /**
+     * 模板id,非自增,由开发人员编号,对应java中的常量
+     */
+    @TableId
+    private Long id;
+    /**
+     * 微信消息模板id
+     */
+    private String wechatMsgTemplateId;
+    /**
+     * 备注、说明
+     */
+    private String remark;
+    /**
+     * 消息模板参数
+     */
+    private String messageTemplateParameters;
+
+}

+ 29 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/config/SystemConfigMapper.java

@@ -0,0 +1,29 @@
+package cn.newfeifan.mall.module.system.dal.mysql.config;
+
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.newfeifan.mall.framework.mybatis.core.mapper.BaseMapperX;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.newfeifan.mall.module.system.controller.admin.config.vo.*;
+
+/**
+ * 系统配置 Mapper
+ *
+ * @author 非繁人
+ */
+@Mapper
+public interface SystemConfigMapper extends BaseMapperX<SystemConfigDO> {
+
+    default PageResult<SystemConfigDO> selectPage(ConfigPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<SystemConfigDO>()
+                .eqIfPresent(SystemConfigDO::getWechatAppid, reqVO.getWechatAppid())
+                .eqIfPresent(SystemConfigDO::getWechatSecretKey, reqVO.getWechatSecretKey())
+                .eqIfPresent(SystemConfigDO::getPlatformDomain, reqVO.getPlatformDomain())
+                .eqIfPresent(SystemConfigDO::getMerchantDomain, reqVO.getMerchantDomain())
+                .eqIfPresent(SystemConfigDO::getMallDomain, reqVO.getMallDomain())
+                .betweenIfPresent(SystemConfigDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(SystemConfigDO::getId));
+    }
+
+}

+ 2 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/social/SocialUserMapper.java

@@ -7,6 +7,7 @@ import cn.newfeifan.mall.module.system.controller.admin.socail.vo.user.SocialUse
 import cn.newfeifan.mall.module.system.dal.dataobject.social.SocialUserDO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 @Mapper
 public interface SocialUserMapper extends BaseMapperX<SocialUserDO> {
@@ -33,4 +34,5 @@ public interface SocialUserMapper extends BaseMapperX<SocialUserDO> {
                 .orderByDesc(SocialUserDO::getId));
     }
 
+    String getOpenIdByUserId(@Param("userId") Long userId);
 }

+ 28 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/dal/mysql/wechatmsgtemplate/WechatMsgTemplateMapper.java

@@ -0,0 +1,28 @@
+package cn.newfeifan.mall.module.system.dal.mysql.wechatmsgtemplate;
+
+
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.newfeifan.mall.framework.mybatis.core.mapper.BaseMapperX;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo.*;
+
+/**
+ * 微信消息模板 Mapper
+ *
+ * @author 非繁人
+ */
+@Mapper
+public interface WechatMsgTemplateMapper extends BaseMapperX<WechatMsgTemplateDO> {
+
+    default PageResult<WechatMsgTemplateDO> selectPage(WechatMsgTemplatePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<WechatMsgTemplateDO>()
+                .eqIfPresent(WechatMsgTemplateDO::getWechatMsgTemplateId, reqVO.getWechatMsgTemplateId())
+                .eqIfPresent(WechatMsgTemplateDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(WechatMsgTemplateDO::getMessageTemplateParameters, reqVO.getMessageTemplateParameters())
+                .betweenIfPresent(WechatMsgTemplateDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(WechatMsgTemplateDO::getId));
+    }
+
+}

+ 65 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/config/SystemConfigService.java

@@ -0,0 +1,65 @@
+package cn.newfeifan.mall.module.system.service.config;
+
+import javax.validation.*;
+import cn.newfeifan.mall.module.system.controller.admin.config.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+
+/**
+ * 系统配置 Service 接口
+ *
+ * @author 非繁人
+ */
+public interface SystemConfigService {
+
+    /**
+     * 创建系统配置
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createConfig(@Valid ConfigSaveReqVO createReqVO);
+
+    /**
+     * 更新系统配置
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateConfig(@Valid ConfigSaveReqVO updateReqVO);
+
+    /**
+     * 删除系统配置
+     *
+     * @param id 编号
+     */
+    void deleteConfig(Long id);
+
+    /**
+     * 获得系统配置
+     *
+     * @param id 编号
+     * @return 系统配置
+     */
+    SystemConfigDO getConfig(Long id);
+
+    /**
+     * 获取系统配置
+     * @return 系统配置
+     */
+    SystemConfigDO getConfig();
+
+    /**
+     * 获取常量系统配置
+     * @return 系统配置
+     */
+    SystemConfigDO getRedisConfig();
+
+    /**
+     * 获得系统配置分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 系统配置分页
+     */
+    PageResult<SystemConfigDO> getConfigPage(ConfigPageReqVO pageReqVO);
+
+}

+ 97 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/config/SystemConfigServiceImpl.java

@@ -0,0 +1,97 @@
+package cn.newfeifan.mall.module.system.service.config;
+
+import cn.newfeifan.mall.module.system.controller.admin.config.bo.SystemConfigBO;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import cn.newfeifan.mall.module.system.controller.admin.config.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.config.SystemConfigDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+
+import cn.newfeifan.mall.module.system.dal.mysql.config.SystemConfigMapper;
+
+import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.newfeifan.mall.module.system.constant.SystemConstants.SYSTEM_CONFIG;
+import static cn.newfeifan.mall.module.system.enums.ErrorCodeConstants.*;
+
+/**
+ * 系统配置 Service 实现类
+ *
+ * @author 非繁人
+ */
+@Service
+@Validated
+public class SystemConfigServiceImpl implements SystemConfigService {
+
+    @Resource
+    private SystemConfigMapper systemConfigMapper;
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Override
+    public Long createConfig(ConfigSaveReqVO createReqVO) {
+        // 插入
+        SystemConfigDO config = BeanUtils.toBean(createReqVO, SystemConfigDO.class);
+        systemConfigMapper.insert(config);
+        // 返回
+        return config.getId();
+    }
+
+    @Override
+    public void updateConfig(ConfigSaveReqVO updateReqVO) {
+        // 校验存在
+        validateConfigExists(updateReqVO.getId());
+        // 更新
+        SystemConfigDO updateObj = BeanUtils.toBean(updateReqVO, SystemConfigDO.class);
+        systemConfigMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteConfig(Long id) {
+        // 校验存在
+        validateConfigExists(id);
+        // 删除
+        systemConfigMapper.deleteById(id);
+    }
+
+    private void validateConfigExists(Long id) {
+        if (systemConfigMapper.selectById(id) == null) {
+            throw exception(CONFIG_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public SystemConfigDO getConfig(Long id) {
+        return systemConfigMapper.selectById(id);
+    }
+
+    @Override
+    public SystemConfigDO getConfig() {
+        return systemConfigMapper.selectList().get(0);
+    }
+
+    @Override
+    public SystemConfigDO getRedisConfig() {
+        String s = stringRedisTemplate.opsForValue().get(SYSTEM_CONFIG);
+        if (s != null) {
+            SystemConfigBO systemConfigBO = JSONObject.parseObject(s, SystemConfigBO.class);
+            return SystemConfigDO.builder()
+                    .id(systemConfigBO.getId())
+                    .mallDomain(systemConfigBO.getMallDomain())
+                    .merchantDomain(systemConfigBO.getMerchantDomain())
+                    .platformDomain(systemConfigBO.getPlatformDomain())
+                    .build();
+        }
+        return getConfig();
+    }
+
+    @Override
+    public PageResult<SystemConfigDO> getConfigPage(ConfigPageReqVO pageReqVO) {
+        return systemConfigMapper.selectPage(pageReqVO);
+    }
+
+}

+ 2 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/social/SocialUserService.java

@@ -86,4 +86,6 @@ public interface SocialUserService {
      */
     PageResult<SocialUserDO> getSocialUserPage(SocialUserPageReqVO pageReqVO);
 
+    String getOpenIdByUserId(Long userId);
+
 }

+ 5 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/social/SocialUserServiceImpl.java

@@ -170,4 +170,9 @@ public class SocialUserServiceImpl implements SocialUserService {
         return socialUserMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public String getOpenIdByUserId(Long userId) {
+        return socialUserMapper.getOpenIdByUserId(userId);
+    }
+
 }

+ 8 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/user/AdminUserServiceImpl.java

@@ -11,6 +11,7 @@ import cn.newfeifan.mall.framework.common.util.collection.CollectionUtils;
 import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
 import cn.newfeifan.mall.framework.datapermission.core.util.DataPermissionUtils;
 import cn.newfeifan.mall.module.infra.api.file.FileApi;
+import cn.newfeifan.mall.module.member.service.user.MemberUserService;
 import cn.newfeifan.mall.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO;
 import cn.newfeifan.mall.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
 import cn.newfeifan.mall.module.system.controller.admin.user.vo.user.UserImportExcelVO;
@@ -87,6 +88,9 @@ public class AdminUserServiceImpl implements AdminUserService {
     @Resource
     private UserRoleMapper userRoleMapper;
 
+    @Resource
+    private MemberUserService memberUserService;
+
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -106,6 +110,10 @@ public class AdminUserServiceImpl implements AdminUserService {
         user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
         user.setPassword(encodePassword(createReqVO.getPassword())); // 加密密码
         userMapper.insert(user);
+
+        //绑定关联消费者
+        memberUserService.updateUserByMobile(user.getId(), user.getMobile());
+
         // 插入关联岗位
         if (CollectionUtil.isNotEmpty(user.getPostIds())) {
             userPostMapper.insertBatch(convertList(user.getPostIds(),

+ 68 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/wechatmsgtemplate/WechatMsgTemplateService.java

@@ -0,0 +1,68 @@
+package cn.newfeifan.mall.module.system.service.wechatmsgtemplate;
+
+import javax.validation.*;
+import cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+
+import java.util.List;
+
+/**
+ * 微信消息模板 Service 接口
+ *
+ * @author 非繁人
+ */
+public interface WechatMsgTemplateService {
+
+    /**
+     * 创建微信消息模板
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createWechatMsgTemplate(@Valid WechatMsgTemplateSaveReqVO createReqVO);
+
+    /**
+     * 更新微信消息模板
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateWechatMsgTemplate(@Valid WechatMsgTemplateSaveReqVO updateReqVO);
+
+    /**
+     * 删除微信消息模板
+     *
+     * @param id 编号
+     */
+    void deleteWechatMsgTemplate(Long id);
+
+    /**
+     * 获得微信消息模板
+     *
+     * @param id 编号
+     * @return 微信消息模板
+     */
+    WechatMsgTemplateDO getWechatMsgTemplate(Long id);
+
+    /**
+     * 获得微信消息模板分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 微信消息模板分页
+     */
+    PageResult<WechatMsgTemplateDO> getWechatMsgTemplatePage(WechatMsgTemplatePageReqVO pageReqVO);
+
+    /**
+     * 获取微信模板
+     * @param wechatMsgId 自定义的模板id
+     * @return 微信模板
+     */
+    WechatMsgTemplateDO getWechatSsgTemplate(Long wechatMsgId);
+
+    /**
+     * 获取微信模板
+     * @return 微信模板
+     */
+    List<WechatMsgTemplateDO> selectList();
+
+}

+ 100 - 0
feifan-module-system/feifan-module-system-biz/src/main/java/cn/newfeifan/mall/module/system/service/wechatmsgtemplate/WechatMsgTemplateServiceImpl.java

@@ -0,0 +1,100 @@
+package cn.newfeifan.mall.module.system.service.wechatmsgtemplate;
+
+import cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.bo.WechatMsgTemplateBO;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import cn.newfeifan.mall.module.system.controller.admin.wechatmsgtemplate.vo.*;
+import cn.newfeifan.mall.module.system.dal.dataobject.wechatmsgtemplate.WechatMsgTemplateDO;
+import cn.newfeifan.mall.framework.common.pojo.PageResult;
+import cn.newfeifan.mall.framework.common.util.object.BeanUtils;
+
+import cn.newfeifan.mall.module.system.dal.mysql.wechatmsgtemplate.WechatMsgTemplateMapper;
+
+import java.util.List;
+
+import static cn.newfeifan.mall.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.newfeifan.mall.module.system.constant.SystemConstants.SYSTEM_WX_MESSAGE_TEMPLATE;
+import static cn.newfeifan.mall.module.system.enums.ErrorCodeConstants.*;
+
+/**
+ * 微信消息模板 Service 实现类
+ *
+ * @author 非繁人
+ */
+@Service
+@Validated
+public class WechatMsgTemplateServiceImpl implements WechatMsgTemplateService {
+
+    @Resource
+    private WechatMsgTemplateMapper wechatMsgTemplateMapper;
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Override
+    public Long createWechatMsgTemplate(WechatMsgTemplateSaveReqVO createReqVO) {
+        // 插入
+        WechatMsgTemplateDO wechatMsgTemplate = BeanUtils.toBean(createReqVO, WechatMsgTemplateDO.class);
+        wechatMsgTemplateMapper.insert(wechatMsgTemplate);
+        // 返回
+        return wechatMsgTemplate.getId();
+    }
+
+    @Override
+    public void updateWechatMsgTemplate(WechatMsgTemplateSaveReqVO updateReqVO) {
+        // 校验存在
+        validateWechatMsgTemplateExists(updateReqVO.getId());
+        // 更新
+        WechatMsgTemplateDO updateObj = BeanUtils.toBean(updateReqVO, WechatMsgTemplateDO.class);
+        wechatMsgTemplateMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteWechatMsgTemplate(Long id) {
+        // 校验存在
+        validateWechatMsgTemplateExists(id);
+        // 删除
+        wechatMsgTemplateMapper.deleteById(id);
+    }
+
+    private void validateWechatMsgTemplateExists(Long id) {
+        if (wechatMsgTemplateMapper.selectById(id) == null) {
+            throw exception(WECHAT_MSG_TEMPLATE_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public WechatMsgTemplateDO getWechatMsgTemplate(Long id) {
+        return wechatMsgTemplateMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<WechatMsgTemplateDO> getWechatMsgTemplatePage(WechatMsgTemplatePageReqVO pageReqVO) {
+        return wechatMsgTemplateMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public WechatMsgTemplateDO getWechatSsgTemplate(Long wechatMsgId) {
+        String s = stringRedisTemplate.opsForValue().get(SYSTEM_WX_MESSAGE_TEMPLATE + wechatMsgId);
+        if(s != null){
+            WechatMsgTemplateBO wechatMsgTemplateBO = JSONObject.parseObject(s, WechatMsgTemplateBO.class);
+            return WechatMsgTemplateDO.builder()
+                    .wechatMsgTemplateId(wechatMsgTemplateBO.getWechatMsgTemplateId())
+                    .messageTemplateParameters(wechatMsgTemplateBO.getMessageTemplateParameters())
+                    .remark(wechatMsgTemplateBO.getRemark())
+                    .id(wechatMsgTemplateBO.getId())
+                    .build();
+        }
+
+        return wechatMsgTemplateMapper.selectById(wechatMsgId);
+    }
+
+    @Override
+    public List<WechatMsgTemplateDO> selectList() {
+        return wechatMsgTemplateMapper.selectList();
+    }
+
+}

+ 12 - 0
feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/config/ConfigMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.newfeifan.mall.module.system.dal.mysql.config.SystemConfigMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.zhongxing.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 10 - 0
feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/social/SocialUserMapper.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.newfeifan.mall.module.system.dal.mysql.social.SocialUserMapper">
+
+    <select id="getOpenIdByUserId" resultType="string" parameterType="long">
+        SELECT openid FROM `system_social_user` u
+        left join system_social_user_bind b on u.id = b.social_user_id
+        where b.user_id = #{userId}
+    </select>
+</mapper>

+ 12 - 0
feifan-module-system/feifan-module-system-biz/src/main/resources/mapper/wechatmsgtemplate/WechatMsgTemplateMapper.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.newfeifan.mall.module.system.dal.mysql.wechatmsgtemplate.WechatMsgTemplateMapper">
+
+    <!--
+        一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
+        无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
+        代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
+        文档可见:https://www.zhongxing.cn/MyBatis/x-plugins/
+     -->
+
+</mapper>

+ 16 - 0
sql/mysql/建空库SQL/6_20240412.sql

@@ -66,6 +66,22 @@ CREATE TABLE `distri_user_collect_before`  (
                                                   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户曾经收藏过什么商品的表' ROW_FORMAT = Dynamic;
 
+--  会员签到日志表
+CREATE TABLE `distri_user_sign_in_log`  (
+                                               `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',
+                                               `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后签到时间',
+                                               `user_id` bigint NOT NULL COMMENT '签到的用户ID',
+                                               `running_days` tinyint NOT NULL DEFAULT 0 COMMENT '连续签到天数',
+
+                                               `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
+                                               `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+                                               `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+
+                                               `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+                                               `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+                                               PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户签到日志表' ROW_FORMAT = Dynamic;
+
 
 -- 增加 会员签到表
 /*

+ 20 - 0
sql/mysql/建空库SQL/7_20240506.sql

@@ -0,0 +1,20 @@
+/* 物流系统相关扩展 */
+
+ALTER TABLE `trade_order`
+    ADD COLUMN `subscription_logistics_info` tinyint NOT NULL DEFAULT '0' COMMENT '订阅物流信息,未订阅是0,已订阅是1';
+
+ALTER TABLE `trade_order` ADD COLUMN `receiving_time` datetime COMMENT '物流签收时间';
+
+-- 记录快递100回调我们系统的日志
+CREATE TABLE `trade_order_callback_logs` (
+                                             `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '回调编号',
+                                             `order_id` varchar(255) NOT NULL COMMENT '订单ID',
+                                             `request_param` text NOT NULL COMMENT '回调推送参数体',
+                                             `response_body` text COMMENT '回调响应体',
+                                             `status` bit(1) NOT NULL DEFAULT b'0' COMMENT '回调状态,失败是0,成功是1',
+                                             `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
+                                             `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                             `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
+                                             `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                             PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='第三方回调日志(目前对接了快递100)';

+ 55 - 0
sql/mysql/建空库SQL/8_20240512.sql

@@ -0,0 +1,55 @@
+/* 发微信消息相关扩展 */
+
+ALTER TABLE `member_user`
+    ADD COLUMN `system_users_id` bigint(20) COMMENT '关联系统用户ID';
+
+-- 增加数据表,记录微信服务号的appid、服务号秘钥、平台端域名、商户端域名、移动商城端域名。
+-- 本表只会有一条记录
+CREATE TABLE `system_config` (
+                                 `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
+                                 `wechat_appid` varchar(255) DEFAULT NULL COMMENT '微信服务号appid',
+                                 `wechat_secret_key` varchar(255) DEFAULT NULL COMMENT '微信服务号秘钥',
+                                 `platform_domain` varchar(255) DEFAULT NULL COMMENT '平台端协议+域名+端口',
+                                 `merchant_domain` varchar(255) DEFAULT NULL COMMENT '商户端协议+域名+端口',
+                                 `mall_domain` varchar(255) DEFAULT NULL COMMENT '移动商城端协议+域名+端口',
+                                 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
+                                 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                 `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
+                                 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+                                 PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='系统配置表';
+
+-- 微信消息模板表,因为不好直接把微信那边的消息模板id写死在java代码中,所以增加此表
+CREATE TABLE `system_wechat_msg_template` (
+                                              `id` bigint(20) NOT NULL COMMENT '模板id,非自增,由开发人员编号,对应java中的常量',
+                                              `wechat_msg_template_id` varchar(255) DEFAULT NULL COMMENT '微信消息模板id',
+                                              `remark` varchar(255) DEFAULT NULL COMMENT '备注、说明',
+                                              `message_template_parameters` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '消息模板参数',
+                                              `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
+                                              `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                              `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
+                                              `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                              `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+                                              PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信消息模板表';
+
+
+CREATE TABLE `wechat_message_log` (
+                                      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '消息记录ID,自增主键',
+                                      `openid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '接收消息用户的openid',
+                                      `member_user_id` bigint(20) NOT NULL COMMENT '会员用户ID',
+                                      `system_user_id` bigint(20) DEFAULT NULL COMMENT '系统用户ID',
+                                      `wechat_msg_template_id` bigint(20) NOT NULL COMMENT '微信消息模板ID',
+                                      `wechat_msg_template_params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '微信消息模板参数',
+                                      `object_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '对应的业务对象ID,如订单ID、售后订单ID',
+                                      `send_time` datetime DEFAULT NULL COMMENT '发送时间',
+                                      `send_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '微信返回的消息发送状态(0异常  1正常)',
+                                      `response_result` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '微信返回的消息响应结果',
+                                      `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
+                                      `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                      `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
+                                      `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                      `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+                                      PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='微信消息记录表';