diff --git a/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java b/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java index a6a7ca70e..aebe57dd6 100644 --- a/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java +++ b/yudao-module-mp/yudao-module-mp-api/src/main/java/cn/iocoder/yudao/module/mp/enums/ErrorCodeConstants.java @@ -61,7 +61,10 @@ public interface ErrorCodeConstants { ErrorCode AUTO_REPLY_ADD_MESSAGE_FAIL_EXISTS = new ErrorCode(1_006_009_002, "操作失败,原因:已存在该消息类型的回复"); ErrorCode AUTO_REPLY_ADD_KEYWORD_FAIL_EXISTS = new ErrorCode(1_006_009_003, "操作失败,原因:已关在该关键字的回复"); - // ========== 公众号消息模板 1-006-010-000 ============ - ErrorCode MSG_TEMPLATE_NOT_EXISTS = new ErrorCode(1_006_010_000, "消息模板不存在"); - ErrorCode MSG_TEMPLATE_LOG_NOT_EXISTS = new ErrorCode(1_006_010_001, "微信模版消息发送记录不存在"); + // ========== 公众号模版消息 1-006-010-000 ============ + ErrorCode MESSAGE_TEMPLATE_NOT_EXISTS = new ErrorCode(1_006_010_000, "模版消息不存在"); + ErrorCode MESSAGE_TEMPLATE_DELETE_FAIL = new ErrorCode(1_006_010_002, "删除模版消息失败,原因:{}"); + ErrorCode MESSAGE_TEMPLATE_SYNC_FAIL = new ErrorCode(1_006_010_003, "同步模版消息失败,原因:{}"); + ErrorCode MESSAGE_TEMPLATE_SEND_FAIL = new ErrorCode(1_006_010_004, "发送模版消息失败,原因:{}"); + } diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.http b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.http new file mode 100644 index 000000000..e42b52fe2 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.http @@ -0,0 +1,44 @@ +### 请求 /mp/message-template/get 接口 => 成功 +GET {{baseUrl}}/mp/message-template/get?id=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /mp/message-template/list 接口 => 成功 +GET {{baseUrl}}/mp/message-template/list?accountId=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /mp/message-template/delete 接口 => 成功 +DELETE {{baseUrl}}/mp/message-template/delete?id=1 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /mp/message-template/sync 接口 => 成功 +POST {{baseUrl}}/mp/message-template/sync?accountId=5 +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +### 请求 /mp/message-template/send 接口 => 成功 +POST {{baseUrl}}/mp/message-template/send +Content-Type: application/json +Authorization: Bearer {{token}} +tenant-id: {{adminTenantId}} + +{ + "id": 66, + "userId": 65, + "url": "https://example.com", + "data": { + "result": "领奖成功", + "withdrawMoney": "1000.00元", + "withdrawTime": "2024-01-01 10:00:00", + "cardInfo": "工商银行(尾号1234)", + "arrivedTime": "2024-01-01 10:30:00" + } +} + +// "miniprogram": "{\"appid\":\"wx1234567890\",\"pagepath\":\"pages/index/index\"}", diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.java new file mode 100644 index 000000000..f3d27fda5 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateListReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateSendReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.template.MpMessageTemplateDO; +import cn.iocoder.yudao.module.mp.service.template.MpMessageTemplateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 公众号模版消息") +@RestController +@RequestMapping("/mp/message-template") +@Validated +public class MpMessageTemplateController { + + @Resource + private MpMessageTemplateService messageTemplateService; + + @DeleteMapping("/delete") + @Operation(summary = "删除模版消息") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mp:message-template:delete')") + public CommonResult deleteMessageTemplate(@RequestParam("id") Long id) { + messageTemplateService.deleteMessageTemplate(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得模版消息") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mp:message-template:query')") + public CommonResult getMessageTemplate(@RequestParam("id") Long id) { + MpMessageTemplateDO msgTemplate = messageTemplateService.getMessageTemplate(id); + return success(BeanUtils.toBean(msgTemplate, MpMessageTemplateRespVO.class)); + } + + @GetMapping("/list") + @Operation(summary = "获得模版消息列表") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "2048") + @PreAuthorize("@ss.hasPermission('mp:message-template:query')") + public CommonResult> getMessageTemplateList(MpMessageTemplateListReqVO listReqVO) { + List list = messageTemplateService.getMessageTemplateList(listReqVO); + return success(BeanUtils.toBean(list, MpMessageTemplateRespVO.class)); + } + + @PostMapping("/sync") + @Operation(summary = "同步公众号模板") + @Parameter(name = "accountId", description = "公众号账号的编号", required = true, example = "2048") + @PreAuthorize("@ss.hasPermission('mp:message-template:sync')") + public CommonResult syncMessageTemplate(@RequestParam("accountId") Long accountId) { + messageTemplateService.syncMessageTemplate(accountId); + return success(true); + } + + @PostMapping("/send") + @Operation(summary = "给粉丝发送模版消息") + @PreAuthorize("@ss.hasPermission('mp:message-template:send')") + public CommonResult sendMessageTemplate(@Valid @RequestBody MpMessageTemplateSendReqVO sendReqVO) { + messageTemplateService.sendMessageTempalte(sendReqVO); + return success(true); + } + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateListReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateListReqVO.java new file mode 100644 index 000000000..f118b0e91 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateListReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - 公众号模版消息列表 Request VO") +@Data +public class MpMessageTemplateListReqVO { + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotNull(message = "公众号账号的编号不能为空") + private Long accountId; + +} diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateRespVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateRespVO.java new file mode 100644 index 000000000..c0abbebc8 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateRespVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 公众号模版消息 Response VO") +@Data +public class MpMessageTemplateRespVO { + + @Schema(description = "模版主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "7019") + private Long id; + + @Schema(description = "公众号账号的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long accountId; + + @Schema(description = "appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx1234567890abcdef") + private String appId; + + @Schema(description = "公众号模板ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "IjkGxO9M_mC9pE5Yl7QYJk1h0Dj2N4lC3oOp6rRsT8u") + private String templateId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单状态提醒") + private String title; + + @Schema(description = "模板内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "模板示例") + private String example; + + @Schema(description = "模板所属行业的一级行业", example = "电商") + private String primaryIndustry; + + @Schema(description = "模板所属行业的二级行业", example = "商品售后") + private String deputyIndustry; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateSendReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateSendReqVO.java new file mode 100644 index 000000000..5a82124e0 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateSendReqVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.mp.controller.admin.message.vo.template; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Map; + +@Schema(description = "管理后台 - 公众号消息模版发送 Request VO") // 关联 https://developers.weixin.qq.com/doc/service/api/notify/template/api_sendtemplatemessage.html 文档 +@Data +public class MpMessageTemplateSendReqVO { + + @Schema(description = "模版主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "7019") + @NotNull(message = "模版主键不能为空") + private Long id; + + @Schema(description = "公众号粉丝的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "公众号粉丝的编号不能为空") + private Long userId; + + @Schema(description = "模板跳转链接") + private String url; + + @Schema(description = "跳转小程序时填写") + private String miniprogram; + + @Schema(description = "模板内容") + private Map data; + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java deleted file mode 100644 index 726578a69..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java +++ /dev/null @@ -1,136 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import java.io.IOException; -import java.util.List; - -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateBatchReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplatePageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateRespVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateSaveReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateDO; -import cn.iocoder.yudao.module.mp.service.template.MsgTemplateService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import me.chanjar.weixin.common.error.WxErrorException; -/** - * @author dengsl - */ -@Tag(name = "管理后台 - 消息模板") -@RestController -@RequestMapping("/mp/template") -@Validated -public class MsgTemplateController { - - @Resource - private MsgTemplateService msgTemplateService; - - @PostMapping("/create") - @Operation(summary = "创建消息模板") - @PreAuthorize("@ss.hasPermission('mp:template:create')") - public CommonResult createMsgTemplate(@Valid @RequestBody MsgTemplateSaveReqVO createReqVO) { - return success(msgTemplateService.createMsgTemplate(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新消息模板") - @PreAuthorize("@ss.hasPermission('mp:template:update')") - public CommonResult updateMsgTemplate(@Valid @RequestBody MsgTemplateSaveReqVO updateReqVO) { - msgTemplateService.updateMsgTemplate(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除消息模板") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mp:template:delete')") - public CommonResult deleteMsgTemplate(@RequestParam("id") Long id) { - //msgTemplateService.deleteMsgTemplate(id); - //TODO 该逻辑没有实现 删除需要判断该消息模板是否被关联 - return success(true); - } - - @DeleteMapping("/delete-list") - @Parameter(name = "ids", description = "编号", required = true) - @Operation(summary = "批量删除消息模板") - @PreAuthorize("@ss.hasPermission('mp:template:delete')") - public CommonResult deleteMsgTemplateList(@RequestBody List ids) { - //msgTemplateService.deleteMsgTemplateListByIds(ids); - //TODO 该逻辑没有实现 删除需要判断该消息模板是否被关联 - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得消息模板") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('mp:template:query')") - public CommonResult getMsgTemplate(@RequestParam("id") Long id) { - MsgTemplateDO msgTemplate = msgTemplateService.getMsgTemplate(id); - return success(BeanUtils.toBean(msgTemplate, MsgTemplateRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得消息模板分页") - @PreAuthorize("@ss.hasPermission('mp:template:query')") - public CommonResult> getMsgTemplatePage(@Valid MsgTemplatePageReqVO pageReqVO) { - PageResult pageResult = msgTemplateService.getMsgTemplatePage(pageReqVO); - return success(BeanUtils.toBean(pageResult, MsgTemplateRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出消息模板 Excel") - @PreAuthorize("@ss.hasPermission('mp:template:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportMsgTemplateExcel(@Valid MsgTemplatePageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = msgTemplateService.getMsgTemplatePage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "消息模板.xls", "数据", MsgTemplateRespVO.class, - BeanUtils.toBean(list, MsgTemplateRespVO.class)); - } - - @GetMapping("/syncMsgTemplate") - @Operation(summary = "同步公众号模板") - @PreAuthorize("@ss.hasPermission('mp:template:sync')") - public CommonResult syncWxTemplate(@RequestParam("accountId") Long accountId) throws WxErrorException { - msgTemplateService.syncWxTemplate(accountId); - return success(true); - } - - /** - * 批量向用户发送模板消息 - * 通过用户筛选条件(一般使用标签筛选),将消息发送给数据库中所有符合筛选条件的用户 - */ - @PostMapping("/sendMsgBatch") - @Operation(summary = "批量向用户发送模板消息") - @PreAuthorize("@ss.hasPermission('mp:template:send')") - public CommonResult sendMsgBatch(@Valid @RequestBody MsgTemplateBatchReqVO batchReqVO) { - if (StrUtil.isEmpty(batchReqVO.getOpenid()) && StrUtil.isEmpty(batchReqVO.getUnionId()) - && StrUtil.isEmpty(batchReqVO.getNickname()) && CollUtil.isEmpty((batchReqVO.getOpenidList()))) { - return error(BAD_REQUEST.getCode(), "请选择用户"); - } - msgTemplateService.sendMsgBatch(batchReqVO); - return success(true); - } -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java deleted file mode 100644 index 04a9de589..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java +++ /dev/null @@ -1,105 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template; - -import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; - -import java.io.IOException; -import java.util.List; - -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogPageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogRespVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogSaveReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateLogDO; -import cn.iocoder.yudao.module.mp.service.template.MsgTemplateLogService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -/** - * @author dengsl - */ -@Tag(name = "管理后台 - 微信模版消息发送记录") -@RestController -@RequestMapping("/mp/template/log") -@Validated -public class MsgTemplateLogController { - - @Resource - private MsgTemplateLogService msgTemplateLogService; - - @PostMapping("/create") - @Operation(summary = "创建微信模版消息发送记录") - @PreAuthorize("@ss.hasPermission('mp:template-log:create')") - public CommonResult createMsgTemplateLog(@Valid @RequestBody MsgTemplateLogSaveReqVO createReqVO) { - return success(msgTemplateLogService.createMsgTemplateLog(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新微信模版消息发送记录") - @PreAuthorize("@ss.hasPermission('mp:template-log:update')") - public CommonResult updateMsgTemplateLog(@Valid @RequestBody MsgTemplateLogSaveReqVO updateReqVO) { - msgTemplateLogService.updateMsgTemplateLog(updateReqVO); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除微信模版消息发送记录") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('mp:template-log:delete')") - public CommonResult deleteMsgTemplateLog(@RequestParam("id") Long id) { - msgTemplateLogService.deleteMsgTemplateLog(id); - return success(true); - } - - @DeleteMapping("/delete-list") - @Parameter(name = "ids", description = "编号", required = true) - @Operation(summary = "批量删除微信模版消息发送记录") - @PreAuthorize("@ss.hasPermission('mp:template-log:delete')") - public CommonResult deleteMsgTemplateLogList(@RequestParam("ids") List ids) { - msgTemplateLogService.deleteMsgTemplateLogListByIds(ids); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得微信模版消息发送记录") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('mp:template-log:query')") - public CommonResult getMsgTemplateLog(@RequestParam("id") Long id) { - MsgTemplateLogDO msgTemplateLog = msgTemplateLogService.getMsgTemplateLog(id); - return success(BeanUtils.toBean(msgTemplateLog, MsgTemplateLogRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得微信模版消息发送记录分页") - @PreAuthorize("@ss.hasPermission('mp:template-log:query')") - public CommonResult> getMsgTemplateLogPage(@Valid MsgTemplateLogPageReqVO pageReqVO) { - PageResult pageResult = msgTemplateLogService.getMsgTemplateLogPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, MsgTemplateLogRespVO.class)); - } - - @GetMapping("/export-excel") - @Operation(summary = "导出微信模版消息发送记录 Excel") - @PreAuthorize("@ss.hasPermission('mp:template-log:export')") - @ApiAccessLog(operateType = EXPORT) - public void exportMsgTemplateLogExcel(@Valid MsgTemplateLogPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { - pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); - List list = msgTemplateLogService.getMsgTemplateLogPage(pageReqVO).getList(); - // 导出 Excel - ExcelUtils.write(response, "微信模版消息发送记录.xls", "数据", MsgTemplateLogRespVO.class, - BeanUtils.toBean(list, MsgTemplateLogRespVO.class)); - } - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java deleted file mode 100644 index 3abc18d18..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - - -import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 消息批量推送 Request VO") -@Data -public class MsgTemplateBatchReqVO extends MpUserPageReqVO { - - @Schema(description = "appId", example = "9758") - @NotNull(message = "appId不能为空") - private String appId; - - @Schema(description = "公众号模板ID", example = "14517") - @NotNull(message = "公众号模板ID不能为空") - private String templateId; -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java deleted file mode 100644 index fec6c48af..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java +++ /dev/null @@ -1,55 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; - -import java.time.LocalDateTime; - -import org.springframework.format.annotation.DateTimeFormat; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 微信模版消息发送记录分页 Request VO") -@Data -public class MsgTemplateLogPageReqVO extends PageParam { - - @Schema(description = "appId", example = "6914") - private String appId; - - @Schema(description = "用户openid") - private String toUser; - - @Schema(description = "公众号模板ID", example = "8374") - private String templateId; - - @Schema(description = "消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - private String url; - - @Schema(description = "小程序appid", example = "21567") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "发送时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] sendTime; - - @Schema(description = "发送状态 0成功,1失败", example = "2") - private Integer sendStatus; - - @Schema(description = "发送结果") - private String sendResult; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] createTime; - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java deleted file mode 100644 index e0997c299..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java +++ /dev/null @@ -1,66 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import java.time.LocalDateTime; - -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; -import cn.idev.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 微信模版消息发送记录 Response VO") -@Data -@ExcelIgnoreUnannotated -public class MsgTemplateLogRespVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "22254") - @ExcelProperty("主键") - private Long id; - - @Schema(description = "appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "6914") - @ExcelProperty("appId") - private String appId; - - @Schema(description = "用户openid") - @ExcelProperty("用户openid") - private String toUser; - - @Schema(description = "公众号模板ID", example = "8374") - @ExcelProperty("公众号模板ID") - private String templateId; - - @Schema(description = "消息内容") - @ExcelProperty("消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - @ExcelProperty("链接") - private String url; - - @Schema(description = "小程序appid", example = "21567") - @ExcelProperty("小程序appid") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - @ExcelProperty("小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "发送时间") - @ExcelProperty("发送时间") - private LocalDateTime sendTime; - - @Schema(description = "发送状态 0成功,1失败", example = "2") - @ExcelProperty("发送状态 0成功,1失败") - private String sendStatus; - - @Schema(description = "发送结果") - @ExcelProperty("发送结果") - private String sendResult; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java deleted file mode 100644 index 6cea435f7..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java +++ /dev/null @@ -1,68 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import java.time.LocalDateTime; - -import com.alibaba.fastjson.JSON; - -import cn.hutool.core.util.ObjectUtil; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import lombok.Data; -import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 微信模版消息发送记录新增/修改 Request VO") -@Data -public class MsgTemplateLogSaveReqVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "22254") - private Long id; - - @Schema(description = "appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "6914") - @NotEmpty(message = "appId不能为空") - private String appId; - - @Schema(description = "用户openid") - private String toUser; - - @Schema(description = "公众号模板ID", example = "8374") - private String templateId; - - @Schema(description = "消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - private String url; - - @Schema(description = "小程序appid", example = "21567") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "发送时间") - private LocalDateTime sendTime; - - @Schema(description = "发送状态 0成功,1失败", example = "2") - private Integer sendStatus; - - @Schema(description = "发送结果") - private String sendResult; - - public MsgTemplateLogSaveReqVO(WxMpTemplateMessage msg, String appid, Integer sendStatus, String sendResult) { - this.appId = appid; - this.toUser = msg.getToUser(); - this.templateId = msg.getTemplateId(); - this.url = msg.getUrl(); - if (ObjectUtil.isNotEmpty(msg.getMiniProgram())) { - this.miniProgramAppId = msg.getMiniProgram().getAppid(); - this.miniProgramPagePath = msg.getMiniProgram().getPagePath(); - } - this.sendStatus = sendStatus; - this.data = JSON.toJSONString(msg.getData()); - this.sendTime = LocalDateTime.now(); - this.sendResult = sendResult; - } - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java deleted file mode 100644 index 7ccd7e8cb..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import java.time.LocalDateTime; - -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 消息模板分页 Request VO") -@Data -public class MsgTemplatePageReqVO extends PageParam { - - @Schema(description = "appId", example = "9758") - private String appId; - - @Schema(description = "公众号账号的编号", example = "9758") - private Long accountId; - - @Schema(description = "公众号模板ID", example = "14517") - private String templateId; - - @Schema(description = "模版名称", example = "赵六") - private String name; - - @Schema(description = "标题") - private String title; - - @Schema(description = "模板内容") - private String content; - - @Schema(description = "消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - private String url; - - @Schema(description = "小程序appid") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "是否有效", example = "1") - private Integer status; - - @Schema(description = "创建时间") - private LocalDateTime[] createTime; - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java deleted file mode 100644 index 694be83a9..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java +++ /dev/null @@ -1,78 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import java.time.LocalDateTime; - -import cn.idev.excel.annotation.ExcelIgnore; -import cn.idev.excel.annotation.ExcelIgnoreUnannotated; -import cn.idev.excel.annotation.ExcelProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 消息模板 Response VO") -@Data -@ExcelIgnoreUnannotated -public class MsgTemplateRespVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "7019") - @ExcelProperty("主键") - private Long id; - - @Schema(description = "appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "9758") - @ExcelProperty("appId") - private String appId; - - @Schema(description = "公众号模板ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14517") - @ExcelProperty("公众号模板ID") - private String templateId; - - @Schema(description = "模版名称", example = "赵六") - @ExcelProperty("模版名称") - private String name; - - @Schema(description = "标题") - @ExcelProperty("标题") - private String title; - - @Schema(description = "模板内容") - @ExcelProperty("模板内容") - private String content; - - @Schema(description = "消息内容") - @ExcelProperty("消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - @ExcelProperty("链接") - private String url; - - @Schema(description = "小程序appId") - @ExcelProperty("小程序appId") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - @ExcelProperty("小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("是否有效") - private Integer status; - - @Schema(description = "公众号是否已移除 0未移除,1已移除", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @ExcelProperty("公众号是否已移除") - private Integer isRemoved; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; - - @Schema(description = "模板消息配置id") - @ExcelIgnore - private Long configId; - - @Schema(description = "模板类型") - @ExcelIgnore - private String templateType; - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java deleted file mode 100644 index 519f3cd92..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java +++ /dev/null @@ -1,56 +0,0 @@ -package cn.iocoder.yudao.module.mp.controller.admin.template.vo; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Data; -/** - * @author dengsl - */ -@Schema(description = "管理后台 - 消息模板新增/修改 Request VO") -@Data -public class MsgTemplateSaveReqVO { - - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "7019") - private Long id; - - @Schema(description = "appId", requiredMode = Schema.RequiredMode.REQUIRED, example = "9758") - @NotEmpty(message = "appId不能为空") - private String appId; - - @Schema(description = "公众号模板ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14517") - @NotEmpty(message = "公众号模板ID不能为空") - private String templateId; - - @Schema(description = "模版名称", example = "赵六") - private String name; - - @Schema(description = "标题") - private String title; - - @Schema(description = "模板内容") - private String content; - - @Schema(description = "消息内容") - private String data; - - @Schema(description = "链接", example = "https://www.iocoder.cn") - private String url; - - @Schema(description = "小程序appid") - private String miniProgramAppId; - - @Schema(description = "小程序页面路径") - private String miniProgramPagePath; - - @Schema(description = "模板所属行业的一级行业") - private String primaryIndustry; - - @Schema(description = "模板所属行业的二级行业") - private String deputyIndustry; - - @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "是否有效不能为空") - private Integer status; - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java index 037f05d57..bb3d0aafb 100644 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/user/vo/MpUserPageReqVO.java @@ -30,4 +30,5 @@ public class MpUserPageReqVO extends PageParam { @Schema(description = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") private List openidList; + } diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java index 483c14c9b..13ed0b34a 100644 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/convert/user/MpUserConvert.java @@ -4,8 +4,6 @@ import cn.hutool.core.date.LocalDateTimeUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateBatchReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserPageReqVO; import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserRespVO; import cn.iocoder.yudao.module.mp.controller.admin.user.vo.MpUserUpdateReqVO; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; @@ -25,8 +23,6 @@ public interface MpUserConvert { MpUserRespVO convert(MpUserDO bean); - MpUserPageReqVO convert(MsgTemplateBatchReqVO bean); - List convertList(List list); PageResult convertPage(PageResult page); diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateDO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java similarity index 50% rename from yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateDO.java rename to yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java index 0c527ba14..ca0534fa0 100644 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateDO.java +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java @@ -1,27 +1,26 @@ package cn.iocoder.yudao.module.mp.dal.dataobject.template; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; import com.baomidou.mybatisplus.annotation.KeySequence; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; /** - * 消息模板 DO + * 公众号模版消息 DO * * @author dengsl */ -@TableName("mp_msg_template") -@KeySequence("mp_msg_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("mp_message_template") +@KeySequence("mp_message_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class MsgTemplateDO extends BaseDO { +public class MpMessageTemplateDO extends BaseDO { /** * 主键 @@ -29,20 +28,21 @@ public class MsgTemplateDO extends BaseDO { @TableId private Long id; /** - * appid + * 公众号账号的编号 + * + * 关联 {@link MpAccountDO#getId()} + */ + private Long accountId; + /** + * 公众号 appId + * + * 冗余 {@link MpAccountDO#getAppId()} */ private String appId; /** - * 公众号模板ID + * 公众号模板 ID */ private String templateId; - /** - * 模版名称 - */ - private String name; - public String getName() { - return this.templateId; - } /** * 标题 @@ -53,21 +53,10 @@ public class MsgTemplateDO extends BaseDO { */ private String content; /** - * 消息内容 + * 模板示例 */ - private String data; - /** - * 链接 - */ - private String url; - /** - * 小程序appid - */ - private String miniProgramAppId; - /** - * 小程序页面路径 - */ - private String miniProgramPagePath; + private String example; + /** * 模板所属行业的一级行业 */ @@ -76,17 +65,5 @@ public class MsgTemplateDO extends BaseDO { * 模板所属行业的二级行业 */ private String deputyIndustry; - /** - * 模板示例 - */ - private String example; - /** - * 是否有效 0有效,1无效 - */ - private Integer status; - /** - * 公众号是否已移除 0未移除,1已移除 - */ - private Integer isRemoved; } \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageTemplateMapper.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageTemplateMapper.java new file mode 100644 index 000000000..546cf0dd0 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageTemplateMapper.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.mp.dal.mysql.message; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateListReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.template.MpMessageTemplateDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface MpMessageTemplateMapper extends BaseMapperX { + + default List selectList(MpMessageTemplateListReqVO listReqVO) { + return selectList(MpMessageTemplateDO::getAccountId, listReqVO.getAccountId()); + } + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java deleted file mode 100644 index c254acf3e..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.mp.dal.mysql.template; - -import org.apache.ibatis.annotations.Mapper; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogPageReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateLogDO; - -/** - * 微信模版消息发送记录 Mapper - * - * @author dengsl - */ -@Mapper -public interface MsgTemplateLogMapper extends BaseMapperX { - - default PageResult selectPage(MsgTemplateLogPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(MsgTemplateLogDO::getAppId, reqVO.getAppId()) - .eqIfPresent(MsgTemplateLogDO::getToUser, reqVO.getToUser()) - .eqIfPresent(MsgTemplateLogDO::getTemplateId, reqVO.getTemplateId()) - .eqIfPresent(MsgTemplateLogDO::getData, reqVO.getData()) - .eqIfPresent(MsgTemplateLogDO::getUrl, reqVO.getUrl()) - .eqIfPresent(MsgTemplateLogDO::getMiniProgramAppId, reqVO.getMiniProgramAppId()) - .eqIfPresent(MsgTemplateLogDO::getMiniProgramPagePath, reqVO.getMiniProgramPagePath()) - .betweenIfPresent(MsgTemplateLogDO::getSendTime, reqVO.getSendTime()) - .eqIfPresent(MsgTemplateLogDO::getSendStatus, reqVO.getSendStatus()) - .eqIfPresent(MsgTemplateLogDO::getSendResult, reqVO.getSendResult()) - .betweenIfPresent(MsgTemplateLogDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(MsgTemplateLogDO::getId)); - } - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java deleted file mode 100644 index 04a486911..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.mp.dal.mysql.template; - -import org.apache.ibatis.annotations.Mapper; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplatePageReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateDO; - -/** - * 消息模板 Mapper - * - * @author dengsl - */ -@Mapper -public interface MsgTemplateMapper extends BaseMapperX { - - default PageResult selectPage(MsgTemplatePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(MsgTemplateDO::getAppId, reqVO.getAppId()) - .eqIfPresent(MsgTemplateDO::getTemplateId, reqVO.getTemplateId()) - .likeIfPresent(MsgTemplateDO::getName, reqVO.getName()) - .eqIfPresent(MsgTemplateDO::getTitle, reqVO.getTitle()) - .eqIfPresent(MsgTemplateDO::getContent, reqVO.getContent()) - .eqIfPresent(MsgTemplateDO::getData, reqVO.getData()) - .eqIfPresent(MsgTemplateDO::getUrl, reqVO.getUrl()) - .eqIfPresent(MsgTemplateDO::getMiniProgramAppId, reqVO.getMiniProgramAppId()) - .eqIfPresent(MsgTemplateDO::getMiniProgramPagePath, reqVO.getMiniProgramPagePath()) - .eqIfPresent(MsgTemplateDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(MsgTemplateDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(MsgTemplateDO::getId)); - } - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateService.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateService.java new file mode 100644 index 000000000..ae6c74c63 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateService.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.mp.service.template; + +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateListReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateSendReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.template.MpMessageTemplateDO; + +import java.util.List; + +/** + * 公众号模版消息 Service 接口 + * + * @author dengsl + */ +public interface MpMessageTemplateService { + + /** + * 删除模版消息 + * + * @param id 编号 + */ + void deleteMessageTemplate(Long id); + + /** + * 获得模版消息 + * + * @param id 编号 + * @return 模版消息 + */ + MpMessageTemplateDO getMessageTemplate(Long id); + + /** + * 获得模版消息列表 + * + * @param listReqVO 查询条件 + * @return 模版消息列表 + */ + List getMessageTemplateList(MpMessageTemplateListReqVO listReqVO); + + /** + * 同步公众号已添加的模版消息 + * + * @param accountId 公众号账号的编号 + */ + void syncMessageTemplate(Long accountId); + + /** + * 使用公众号,给粉丝发送【模版】消息 + * + * @param sendReqVO 消息内容 + */ + void sendMessageTempalte(MpMessageTemplateSendReqVO sendReqVO); + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateServiceImpl.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateServiceImpl.java new file mode 100644 index 000000000..7b12fb6f7 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateServiceImpl.java @@ -0,0 +1,176 @@ +package cn.iocoder.yudao.module.mp.service.template; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateListReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateSendReqVO; +import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.template.MpMessageTemplateDO; +import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; +import cn.iocoder.yudao.module.mp.dal.mysql.message.MpMessageTemplateMapper; +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; +import cn.iocoder.yudao.module.mp.service.account.MpAccountService; +import cn.iocoder.yudao.module.mp.service.user.MpUserService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.template.WxMpTemplate; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + +/** + * 公众号模版消息 Service 实现类 + * + * @author dengsl + */ +@Service +@Validated +@Slf4j +public class MpMessageTemplateServiceImpl implements MpMessageTemplateService { + + @Resource + @Lazy // 延迟加载,为了解决延迟加载 + private MpServiceFactory mpServiceFactory; + + @Resource + private MpMessageTemplateMapper messageTemplateMapper; + + @Resource + private MpAccountService mpAccountService; + + @Resource + private MpUserService mpUserService; + + @Override + public void deleteMessageTemplate(Long id) { + // 校验存在 + MpMessageTemplateDO template = validateMsgTemplateExists(id); + + // 第一步,删除模板到公众号平台 + try { + mpServiceFactory.getRequiredMpService(template.getAppId()) + .getTemplateMsgService().delPrivateTemplate(template.getTemplateId()); + } catch (WxErrorException e) { + throw exception(MESSAGE_TEMPLATE_DELETE_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,删除模板到数据库 + messageTemplateMapper.deleteById(id); + } + + private MpMessageTemplateDO validateMsgTemplateExists(Long id) { + MpMessageTemplateDO template = messageTemplateMapper.selectById(id); + if (template == null) { + throw exception(MESSAGE_TEMPLATE_NOT_EXISTS); + } + return template; + } + + @Override + public MpMessageTemplateDO getMessageTemplate(Long id) { + return messageTemplateMapper.selectById(id); + } + + @Override + public List getMessageTemplateList(MpMessageTemplateListReqVO listReqVO) { + return messageTemplateMapper.selectList(listReqVO); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncMessageTemplate(Long accountId) { + MpAccountDO account = mpAccountService.getRequiredAccount(accountId); + + // 第一步,从公众号平台获取最新的模板列表 + List wxTemplates; + try { + wxTemplates = mpServiceFactory.getRequiredMpService(accountId) + .getTemplateMsgService().getAllPrivateTemplate(); + } catch (WxErrorException e) { + throw exception(MESSAGE_TEMPLATE_SYNC_FAIL, e.getError().getErrorMsg()); + } + + // 第二步,合并更新回自己的数据库 + Map templateMap = convertMap( + messageTemplateMapper.selectList(new LambdaQueryWrapperX() + .eq(MpMessageTemplateDO::getAppId, account.getAppId())), + MpMessageTemplateDO::getTemplateId); + wxTemplates.forEach(wxTemplate -> { + MpMessageTemplateDO template = templateMap.remove(wxTemplate.getTemplateId()); + // 情况一,不存在,新增 + if (template == null) { + template = new MpMessageTemplateDO().setAccountId(account.getId()).setAppId(account.getAppId()) + .setTemplateId(wxTemplate.getTemplateId()).setTitle(wxTemplate.getTitle()) + .setContent(wxTemplate.getContent()).setExample(wxTemplate.getExample()) + .setPrimaryIndustry(wxTemplate.getPrimaryIndustry()).setDeputyIndustry(wxTemplate.getDeputyIndustry()); + messageTemplateMapper.insert(template); + return; + } + // 情况二,存在,则更新 + messageTemplateMapper.updateById(new MpMessageTemplateDO().setId(template.getId()) + .setTitle(wxTemplate.getTitle()).setContent(wxTemplate.getContent()).setExample(wxTemplate.getExample()) + .setPrimaryIndustry(wxTemplate.getPrimaryIndustry()).setDeputyIndustry(wxTemplate.getDeputyIndustry())); + }); + // 情况三,部分模板已经不存在了,删除 + if (CollUtil.isNotEmpty(templateMap)) { + messageTemplateMapper.deleteByIds(convertList(templateMap.values(), MpMessageTemplateDO::getId)); + } + } + + @Override + public void sendMessageTempalte(MpMessageTemplateSendReqVO sendReqVO) { + // 获得关联信息 + MpUserDO user = mpUserService.getRequiredUser(sendReqVO.getUserId()); + MpMessageTemplateDO template = validateMsgTemplateExists(sendReqVO.getId()); + + // 发送模版消息 + WxMpTemplateMessage templateMessage = buildTemplateMessage(template, user, sendReqVO); + try { + mpServiceFactory.getRequiredMpService(template.getAppId()) + .getTemplateMsgService().sendTemplateMsg(templateMessage); + } catch (WxErrorException e) { + throw exception(MESSAGE_TEMPLATE_SEND_FAIL, e.getError().getErrorMsg()); + } + + // 不用记录 MpMessageDO 记录,因为,微信会主动推送,可见文档 https://developers.weixin.qq.com/doc/service/guide/product/template_message/Template_Message_Interface.html + } + + private WxMpTemplateMessage buildTemplateMessage(MpMessageTemplateDO msgTemplateDO, MpUserDO user, + MpMessageTemplateSendReqVO sendReqVO) { + List data = new ArrayList<>(); + WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() + .templateId(msgTemplateDO.getTemplateId()) + .data(data) + .toUser(user.getOpenid()); + // 设置跳转链接 + if (StrUtil.isNotBlank(sendReqVO.getUrl())) { + builder.url(sendReqVO.getUrl()); + } + // 设置小程序跳转 + if (StrUtil.isNotBlank(sendReqVO.getMiniprogram())) { + // https://developers.weixin.qq.com/doc/service/api/notify/template/api_sendtemplatemessage.html#Body__miniprogram + builder.miniProgram(JsonUtils.parseObject(sendReqVO.getMiniprogram(), WxMpTemplateMessage.MiniProgram.class)); + } + // 设置模板数据 + if (sendReqVO.getData() != null) { + sendReqVO.getData().forEach((key, value) -> data.add(new WxMpTemplateData(key, value))); + } + return builder.build(); + } + +} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java deleted file mode 100644 index b7ecf98d7..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java +++ /dev/null @@ -1,63 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.template; - -import java.util.List; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogPageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogSaveReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateLogDO; -import jakarta.validation.Valid; - -/** - * 微信模版消息发送记录 Service 接口 - * - * @author dengsl - */ -public interface MsgTemplateLogService { - - /** - * 创建微信模版消息发送记录 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createMsgTemplateLog(@Valid MsgTemplateLogSaveReqVO createReqVO); - - /** - * 更新微信模版消息发送记录 - * - * @param updateReqVO 更新信息 - */ - void updateMsgTemplateLog(@Valid MsgTemplateLogSaveReqVO updateReqVO); - - /** - * 删除微信模版消息发送记录 - * - * @param id 编号 - */ - void deleteMsgTemplateLog(Long id); - - /** - * 批量删除微信模版消息发送记录 - * - * @param ids 编号 - */ - void deleteMsgTemplateLogListByIds(List ids); - - /** - * 获得微信模版消息发送记录 - * - * @param id 编号 - * @return 微信模版消息发送记录 - */ - MsgTemplateLogDO getMsgTemplateLog(Long id); - - /** - * 获得微信模版消息发送记录分页 - * - * @param pageReqVO 分页查询 - * @return 微信模版消息发送记录分页 - */ - PageResult getMsgTemplateLogPage(MsgTemplateLogPageReqVO pageReqVO); - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java deleted file mode 100644 index 8b7f70916..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java +++ /dev/null @@ -1,89 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.template; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MSG_TEMPLATE_LOG_NOT_EXISTS; - -import java.util.List; - -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogPageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogSaveReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateLogDO; -import cn.iocoder.yudao.module.mp.dal.mysql.template.MsgTemplateLogMapper; -import jakarta.annotation.Resource; - -/** - * 微信模版消息发送记录 Service 实现类 - * - * @author dengsl - */ -@Service -@Validated -public class MsgTemplateLogServiceImpl implements MsgTemplateLogService { - - @Resource - private MsgTemplateLogMapper msgTemplateLogMapper; - - @Override - public Long createMsgTemplateLog(MsgTemplateLogSaveReqVO createReqVO) { - // 插入 - MsgTemplateLogDO msgTemplateLog = BeanUtils.toBean(createReqVO, MsgTemplateLogDO.class); - msgTemplateLogMapper.insert(msgTemplateLog); - // 返回 - return msgTemplateLog.getId(); - } - - @Override - public void updateMsgTemplateLog(MsgTemplateLogSaveReqVO updateReqVO) { - // 校验存在 - validateMsgTemplateLogExists(updateReqVO.getId()); - // 更新 - MsgTemplateLogDO updateObj = BeanUtils.toBean(updateReqVO, MsgTemplateLogDO.class); - msgTemplateLogMapper.updateById(updateObj); - } - - @Override - public void deleteMsgTemplateLog(Long id) { - // 校验存在 - validateMsgTemplateLogExists(id); - // 删除 - msgTemplateLogMapper.deleteById(id); - } - - @Override - public void deleteMsgTemplateLogListByIds(List ids) { - // 校验存在 - validateMsgTemplateLogExists(ids); - // 删除 - msgTemplateLogMapper.deleteByIds(ids); - } - - private void validateMsgTemplateLogExists(List ids) { - List list = msgTemplateLogMapper.selectByIds(ids); - if (CollUtil.isEmpty(list) || list.size() != ids.size()) { - throw exception(MSG_TEMPLATE_LOG_NOT_EXISTS); - } - } - - private void validateMsgTemplateLogExists(Long id) { - if (msgTemplateLogMapper.selectById(id) == null) { - throw exception(MSG_TEMPLATE_LOG_NOT_EXISTS); - } - } - - @Override - public MsgTemplateLogDO getMsgTemplateLog(Long id) { - return msgTemplateLogMapper.selectById(id); - } - - @Override - public PageResult getMsgTemplateLogPage(MsgTemplateLogPageReqVO pageReqVO) { - return msgTemplateLogMapper.selectPage(pageReqVO); - } - -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java deleted file mode 100644 index 65e3ea26b..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java +++ /dev/null @@ -1,87 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.template; - -import java.util.List; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateBatchReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplatePageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateSaveReqVO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateDO; -import jakarta.validation.Valid; -import me.chanjar.weixin.common.error.WxErrorException; - -/** - * 消息模板 Service 接口 - * - * @author dengsl - */ -public interface MsgTemplateService { - - /** - * 创建消息模板 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createMsgTemplate(@Valid MsgTemplateSaveReqVO createReqVO); - - /** - * 更新消息模板 - * - * @param updateReqVO 更新信息 - */ - void updateMsgTemplate(@Valid MsgTemplateSaveReqVO updateReqVO); - - /** - * 删除消息模板 - * - * @param id 编号 - */ - void deleteMsgTemplate(Long id); - - /** - * 批量删除消息模板 - * - * @param ids 编号 - */ - void deleteMsgTemplateListByIds(List ids); - - /** - * 获得消息模板 - * - * @param id 编号 - * @return 消息模板 - */ - MsgTemplateDO getMsgTemplate(Long id); - - /** - * 获得消息模板分页 - * - * @param pageReqVO 分页查询 - * @return 消息模板分页 - */ - PageResult getMsgTemplatePage(MsgTemplatePageReqVO pageReqVO); - - - /** - * 同步公众号已添加的消息模板 - * - * @throws WxErrorException - */ - void syncWxTemplate(Long accountId) throws WxErrorException; - - /** - * 获得公众号已添加的消息模板 - * - * @param appId 公众号 AppId - * @return 模板列表 - */ - MsgTemplateDO getWxTemplate(String appId, String templateId); - - /** - * 批量消息发送 - * - * @param batchReqVO - */ - void sendMsgBatch(MsgTemplateBatchReqVO batchReqVO); -} \ No newline at end of file diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java deleted file mode 100644 index 528110335..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java +++ /dev/null @@ -1,313 +0,0 @@ -package cn.iocoder.yudao.module.mp.service.template; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.MSG_TEMPLATE_NOT_EXISTS; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; - -import cn.hutool.core.text.CharSequenceUtil; -import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.github.yulichang.toolkit.MPJWrappers; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.exception.ServiceException; -import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateBatchReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateLogSaveReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplatePageReqVO; -import cn.iocoder.yudao.module.mp.controller.admin.template.vo.MsgTemplateSaveReqVO; -import cn.iocoder.yudao.module.mp.convert.user.MpUserConvert; -import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.template.MsgTemplateDO; -import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; -import cn.iocoder.yudao.module.mp.dal.mysql.template.MsgTemplateMapper; -import cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.mp.service.account.MpAccountService; -import cn.iocoder.yudao.module.mp.service.user.MpUserService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import me.chanjar.weixin.common.error.WxErrorException; -import me.chanjar.weixin.mp.bean.template.WxMpTemplate; -import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; -import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; - -/** - * 消息模板 Service 实现类 - * - * @author dengsl - */ -@Service -@Validated -@Slf4j -public class MsgTemplateServiceImpl implements MsgTemplateService { - @Resource - @Lazy // 延迟加载,为了解决延迟加载 - private MpServiceFactory mpServiceFactory; - @Resource - private MsgTemplateMapper msgTemplateMapper; - @Resource - private MpUserService mpUserService; - @Resource - private MpAccountService mpAccountService; - @Resource - private MsgTemplateLogService msgTemplateLogService; - - @Override - public Long createMsgTemplate(MsgTemplateSaveReqVO createReqVO) { - // 插入 - MsgTemplateDO msgTemplate = BeanUtils.toBean(createReqVO, MsgTemplateDO.class); - msgTemplateMapper.insert(msgTemplate); - // 返回 - return msgTemplate.getId(); - } - - @Override - public void updateMsgTemplate(MsgTemplateSaveReqVO updateReqVO) { - // 校验存在 - validateMsgTemplateExists(updateReqVO.getId()); - // 更新 - MsgTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MsgTemplateDO.class); - msgTemplateMapper.updateById(updateObj); - } - - @Override - public void deleteMsgTemplate(Long id) { - // 校验存在 - validateMsgTemplateExists(id); - // 删除 - msgTemplateMapper.deleteById(id); - } - - @Override - public void deleteMsgTemplateListByIds(List ids) { - // 校验存在 - validateMsgTemplateExists(ids); - // 删除 - msgTemplateMapper.deleteByIds(ids); - } - - private void validateMsgTemplateExists(List ids) { - List list = msgTemplateMapper.selectByIds(ids); - if (CollUtil.isEmpty(list) || list.size() != ids.size()) { - throw exception(MSG_TEMPLATE_NOT_EXISTS); - } - } - - private void validateMsgTemplateExists(Long id) { - if (msgTemplateMapper.selectById(id) == null) { - throw exception(MSG_TEMPLATE_NOT_EXISTS); - } - } - - @Override - public MsgTemplateDO getMsgTemplate(Long id) { - return msgTemplateMapper.selectById(id); - } - - @Override - public PageResult getMsgTemplatePage(MsgTemplatePageReqVO pageReqVO) { - MpAccountDO account = mpAccountService.getAccount(pageReqVO.getAccountId()); - if (account == null) { - throw exception(ErrorCodeConstants.ACCOUNT_NOT_EXISTS); - } - pageReqVO.setAppId(account.getAppId()); - return msgTemplateMapper.selectPage(pageReqVO); - } - - @Override - public void syncWxTemplate(Long accountId) throws WxErrorException { - // 1. 处理新增的模板(在微信中存在但在数据库中不存在) - // 2. 处理已删除的模板(在数据库中存在但在微信中不存在) - // 3. 处理已存在的模板(在两边都存在)- 更新 - MpAccountDO mpAccountDO = mpAccountService.getAccount(accountId); - String appId = mpAccountDO.getAppId(); - List wxTemplates = mpServiceFactory.getRequiredMpService(appId).getTemplateMsgService().getAllPrivateTemplate(); - if (CollUtil.isNotEmpty(wxTemplates)) { - List dbTemplates = msgTemplateMapper.selectList(new QueryWrapper() - .lambda().eq(MsgTemplateDO::getAppId, appId)); - // 将微信模板转换为Map,便于查找 - Map wxTemplateMap = wxTemplates.stream() - .collect(Collectors.toMap(WxMpTemplate::getTemplateId, Function.identity())); - - // 将数据库模板转换为Map,便于查找 - Map dbTemplateMap = dbTemplates.stream() - .collect(Collectors.toMap(MsgTemplateDO::getTemplateId, Function.identity())); - - // 1. 处理新增的模板(在微信中存在但在数据库中不存在) - handleNewTemplates(appId, wxTemplateMap, dbTemplateMap); - // 2. 处理已删除的模板(在数据库中存在但在微信中不存在) - handleDeletedTemplates(wxTemplateMap, dbTemplateMap); - // 3. 处理已存在的模板(在两边都存在)- 清空已设置的信息 - handleUpdatedTemplates(wxTemplateMap, dbTemplateMap); - return; - } - log.info("没有模板 appId {} ", appId); - } - - /** - * 处理新增的模板 - */ - private void handleNewTemplates(String appId, Map wxTemplateMap, - Map dbTemplateMap) { - List newTemplates = new ArrayList<>(); - wxTemplateMap.forEach((templateId, wxTemplate) -> { - if (!dbTemplateMap.containsKey(templateId)) { - MsgTemplateDO newTemplate = new MsgTemplateDO() - .setAppId(appId) - .setTemplateId(templateId) - .setTitle(wxTemplate.getTitle()) - .setPrimaryIndustry(wxTemplate.getPrimaryIndustry()) - .setDeputyIndustry(wxTemplate.getDeputyIndustry()) - .setContent(wxTemplate.getContent()) - .setExample(wxTemplate.getExample()); - newTemplates.add(newTemplate); - } - }); - - if (CollUtil.isNotEmpty(newTemplates)) { - msgTemplateMapper.insertBatch(newTemplates); - log.info("批量新增公众号模板: appId={}, count={}", appId, newTemplates.size()); - } - } - - /** - * 处理已删除的模板 - */ - private void handleDeletedTemplates(Map wxTemplateMap, - Map dbTemplateMap) { - List removedTemplates = new ArrayList<>(); - dbTemplateMap.forEach((templateId, dbTemplate) -> { - if (!wxTemplateMap.containsKey(templateId) && dbTemplate.getIsRemoved() == 0) { - dbTemplate.setIsRemoved(1); - removedTemplates.add(dbTemplate); - } - }); - - if (CollUtil.isNotEmpty(removedTemplates)) { - msgTemplateMapper.update(new LambdaUpdateWrapper() - .set(MsgTemplateDO::getIsRemoved, 1) - .in(MsgTemplateDO::getId, removedTemplates.stream().map(MsgTemplateDO::getId).collect(Collectors.toList()))); - log.info("批量标记公众号模板为已删除: count={}", removedTemplates.size()); - } - } - - /** - * 处理已存在的模板(在两边都存在)- 清空已设置的信息 - */ - private void handleUpdatedTemplates(Map wxTemplateMap, - Map dbTemplateMap) { - List updatedIds = new ArrayList<>(); - dbTemplateMap.forEach((templateId, dbTemplate) -> { - WxMpTemplate wxTemplate = wxTemplateMap.get(templateId); - if (wxTemplate != null) { - // 更新数据库模板信息 - updatedIds.add(dbTemplate.getId()); - } - }); - - if (CollUtil.isNotEmpty(updatedIds)) { - msgTemplateMapper.update(new LambdaUpdateWrapper() - .set(MsgTemplateDO::getData, null) - .set(MsgTemplateDO::getUrl, null) - .set(MsgTemplateDO::getMiniProgramAppId, null) - .set(MsgTemplateDO::getMiniProgramPagePath, null) - .set(MsgTemplateDO::getExample, null) - .in(MsgTemplateDO::getId, updatedIds)); - log.info("批量更新公众号模板: count={}", updatedIds.size()); - } - } - - @Override - public MsgTemplateDO getWxTemplate(String appId, String templateId) { - return msgTemplateMapper.selectOne(new LambdaQueryWrapperX() - .eq(MsgTemplateDO::getAppId, appId) - .eq(CharSequenceUtil.isNotEmpty(templateId), MsgTemplateDO::getTemplateId, templateId)); - } - - @Override - public void sendMsgBatch(MsgTemplateBatchReqVO batchReqVO) { - log.info("批量发送模板消息任务开始, 参数:{}", batchReqVO); - - // 获取微信模板信息 - MsgTemplateDO msgTemplateDO = getWxTemplate(batchReqVO.getAppId(), batchReqVO.getTemplateId()); - if (ObjectUtil.isNull(msgTemplateDO)) { - log.error("未找到对应的模板信息, appId: {}, templateId: {}", batchReqVO.getAppId(), batchReqVO.getTemplateId()); - throw exception(MSG_TEMPLATE_NOT_EXISTS); - } - if (msgTemplateDO.getIsRemoved() == 1) { - throw new ServiceException(GlobalErrorCodeConstants.ERROR_CONFIGURATION.getCode(), "模板未发布"); - } - if (msgTemplateDO.getStatus() == 1) { - throw new ServiceException(GlobalErrorCodeConstants.ERROR_CONFIGURATION.getCode(), "模板无效"); - } - // 构建基础模板消息 - WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() - .templateId(msgTemplateDO.getTemplateId()) - .url(msgTemplateDO.getUrl()) - .miniProgram(new WxMpTemplateMessage.MiniProgram( - msgTemplateDO.getMiniProgramAppId(), - msgTemplateDO.getMiniProgramPagePath(), - false)) - .data(JSON.parseArray(msgTemplateDO.getData(), WxMpTemplateData.class)); - - int currentPage = 1; - long totalPages = Long.MAX_VALUE; - - while (currentPage <= totalPages) { - // 按条件查询用户 - batchReqVO.setPageNo(currentPage); - batchReqVO.setPageSize(500); - - PageResult wxUsers = mpUserService.getUserPage(MpUserConvert.INSTANCE.convert(batchReqVO)); - log.info("批量发送模板消息任务, 使用查询条件,处理第{}页,总用户数:{}", currentPage, wxUsers.getTotal()); - - // 如果没有用户数据,直接退出循环 - if (CollUtil.isEmpty(wxUsers.getList())) { - log.warn("当前页无用户数据,结束处理, 当前页:{}", currentPage); - break; - } - - // 遍历用户并发送模板消息 - wxUsers.getList().forEach(user -> { - WxMpTemplateMessage wxMpTemplateMessage = builder.toUser(user.getOpenid()).build(); - try { - String result = mpServiceFactory.getRequiredMpService(batchReqVO.getAppId()).getTemplateMsgService().sendTemplateMsg(wxMpTemplateMessage); - - //保存发送日志 - MsgTemplateLogSaveReqVO log = new MsgTemplateLogSaveReqVO(wxMpTemplateMessage, batchReqVO.getAppId(), 0, result); - msgTemplateLogService.createMsgTemplateLog(log); - } catch (WxErrorException e) { - log.error("发送模板消息失败, 用户OpenId: {}, 错误信息: {}", user.getOpenid(), e.getMessage(), e); - // 可以选择继续处理其他用户,而不是直接抛出异常 - //保存发送日志 - MsgTemplateLogSaveReqVO log = new MsgTemplateLogSaveReqVO(wxMpTemplateMessage, batchReqVO.getAppId(), 1, e.getMessage()); - msgTemplateLogService.createMsgTemplateLog(log); - } - }); - - // 更新分页参数 - currentPage++; - // 计算总页数 - totalPages = (wxUsers.getTotal() + batchReqVO.getPageSize() - 1) / batchReqVO.getPageSize(); - } - - log.info("批量发送模板消息任务完成"); - } -} \ No newline at end of file