From 0ec835244df0a3635cac2c23aaf3bc5715537c11 Mon Sep 17 00:00:00 2001 From: wuKong Date: Wed, 5 Nov 2025 11:41:31 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat(mp):=20=E6=96=B0=E5=A2=9E=E5=85=AC?= =?UTF-8?q?=E4=BC=97=E5=8F=B7=E6=B6=88=E6=81=AF=E6=A8=A1=E6=9D=BF=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增消息模板和模板发送记录的增删改查接口 - 新增消息模板和发送记录的分页查询及导出功能 - 新增批量发送模板消息功能 - 新增同步公众号模板功能 - 添加相关数据对象和错误码定义 - 扩展用户分页请求参数支持openid列表查询 - 完善模板消息相关的VO类和转换逻辑 --- .../module/mp/enums/ErrorCodeConstants.java | 3 + .../admin/template/MsgTemplateController.java | 136 ++++++++ .../template/MsgTemplateLogController.java | 105 ++++++ .../template/vo/MsgTemplateBatchReqVO.java | 23 ++ .../template/vo/MsgTemplateLogPageReqVO.java | 55 +++ .../template/vo/MsgTemplateLogRespVO.java | 66 ++++ .../template/vo/MsgTemplateLogSaveReqVO.java | 68 ++++ .../template/vo/MsgTemplatePageReqVO.java | 51 +++ .../admin/template/vo/MsgTemplateRespVO.java | 78 +++++ .../template/vo/MsgTemplateSaveReqVO.java | 56 ++++ .../admin/user/vo/MpUserPageReqVO.java | 4 + .../module/mp/convert/user/MpUserConvert.java | 4 + .../dataobject/template/MsgTemplateDO.java | 92 +++++ .../dataobject/template/MsgTemplateLogDO.java | 72 ++++ .../mysql/template/MsgTemplateLogMapper.java | 35 ++ .../dal/mysql/template/MsgTemplateMapper.java | 35 ++ .../template/MsgTemplateLogService.java | 63 ++++ .../template/MsgTemplateLogServiceImpl.java | 89 +++++ .../service/template/MsgTemplateService.java | 87 +++++ .../template/MsgTemplateServiceImpl.java | 313 ++++++++++++++++++ 20 files changed, 1435 insertions(+) create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateDO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java 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 34c94fd00..a6a7ca70e 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,4 +61,7 @@ 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, "微信模版消息发送记录不存在"); } 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 new file mode 100644 index 000000000..726578a69 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java @@ -0,0 +1,136 @@ +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 new file mode 100644 index 000000000..04a9de589 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java @@ -0,0 +1,105 @@ +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 new file mode 100644 index 000000000..3abc18d18 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java @@ -0,0 +1,23 @@ +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 new file mode 100644 index 000000000..fec6c48af --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java @@ -0,0 +1,55 @@ +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 new file mode 100644 index 000000000..e0997c299 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java @@ -0,0 +1,66 @@ +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 new file mode 100644 index 000000000..6cea435f7 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java @@ -0,0 +1,68 @@ +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 new file mode 100644 index 000000000..7ccd7e8cb --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java @@ -0,0 +1,51 @@ +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 new file mode 100644 index 000000000..694be83a9 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java @@ -0,0 +1,78 @@ +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 new file mode 100644 index 000000000..519f3cd92 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java @@ -0,0 +1,56 @@ +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 cf602e659..037f05d57 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 @@ -7,6 +7,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import java.util.List; + @Schema(description = "管理后台 - 公众号粉丝分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @@ -26,4 +28,6 @@ public class MpUserPageReqVO extends PageParam { @Schema(description = "公众号粉丝昵称,模糊匹配", example = "芋艿") private String nickname; + @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 13ed0b34a..483c14c9b 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,6 +4,8 @@ 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; @@ -23,6 +25,8 @@ 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/MsgTemplateDO.java new file mode 100644 index 000000000..0c527ba14 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateDO.java @@ -0,0 +1,92 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.template; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +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 + * + * @author dengsl + */ +@TableName("mp_msg_template") +@KeySequence("mp_msg_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MsgTemplateDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * appid + */ + private String appId; + /** + * 公众号模板ID + */ + private String templateId; + /** + * 模版名称 + */ + private String name; + public String getName() { + return this.templateId; + } + + /** + * 标题 + */ + private String title; + /** + * 模板内容 + */ + private String content; + /** + * 消息内容 + */ + private String data; + /** + * 链接 + */ + private String url; + /** + * 小程序appid + */ + private String miniProgramAppId; + /** + * 小程序页面路径 + */ + private String miniProgramPagePath; + /** + * 模板所属行业的一级行业 + */ + private String primaryIndustry; + /** + * 模板所属行业的二级行业 + */ + 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/dataobject/template/MsgTemplateLogDO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java new file mode 100644 index 000000000..fdf0d9248 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.mp.dal.dataobject.template; + +import lombok.*; + +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 微信模版消息发送记录 DO + * + * @author dengsl + */ +@TableName("mp_msg_template_log") +@KeySequence("mp_msg_template_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MsgTemplateLogDO extends BaseDO { + + /** + * 主键 + */ + @TableId + private Long id; + /** + * appId + */ + private String appId; + /** + * 用户openid + */ + private String toUser; + /** + * 公众号模板ID + */ + private String templateId; + /** + * 消息内容 + */ + private String data; + /** + * 链接 + */ + private String url; + /** + * 小程序appid + */ + private String miniProgramAppId; + /** + * 小程序页面路径 + */ + private String miniProgramPagePath; + /** + * 发送时间 + */ + private LocalDateTime sendTime; + /** + * 发送状态 0成功,1失败 + */ + private Integer sendStatus; + /** + * 发送结果 + */ + private String 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/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 new file mode 100644 index 000000000..c254acf3e --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java @@ -0,0 +1,35 @@ +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 new file mode 100644 index 000000000..04a486911 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java @@ -0,0 +1,35 @@ +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/MsgTemplateLogService.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java new file mode 100644 index 000000000..b7ecf98d7 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java @@ -0,0 +1,63 @@ +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 new file mode 100644 index 000000000..8b7f70916 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java @@ -0,0 +1,89 @@ +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 new file mode 100644 index 000000000..65e3ea26b --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java @@ -0,0 +1,87 @@ +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 new file mode 100644 index 000000000..528110335 --- /dev/null +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java @@ -0,0 +1,313 @@ +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 From 04fb7b107edff81fc72f19d1ec98b797b3c6c9d5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 26 Nov 2025 18:30:07 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mp=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E2=80=9C=E6=A8=A1=E7=89=88=E6=B6=88=E6=81=AF=E2=80=9D?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/mp/enums/ErrorCodeConstants.java | 9 +- .../message/MpMessageTemplateController.http | 44 +++ .../message/MpMessageTemplateController.java | 76 +++++ .../template/MpMessageTemplateListReqVO.java | 15 + .../vo/template/MpMessageTemplateRespVO.java | 42 +++ .../template/MpMessageTemplateSendReqVO.java | 30 ++ .../admin/template/MsgTemplateController.java | 136 -------- .../template/MsgTemplateLogController.java | 105 ------ .../template/vo/MsgTemplateBatchReqVO.java | 23 -- .../template/vo/MsgTemplateLogPageReqVO.java | 55 --- .../template/vo/MsgTemplateLogRespVO.java | 66 ---- .../template/vo/MsgTemplateLogSaveReqVO.java | 68 ---- .../template/vo/MsgTemplatePageReqVO.java | 51 --- .../admin/template/vo/MsgTemplateRespVO.java | 78 ----- .../template/vo/MsgTemplateSaveReqVO.java | 56 ---- .../admin/user/vo/MpUserPageReqVO.java | 1 + .../module/mp/convert/user/MpUserConvert.java | 4 - ...mplateDO.java => MpMessageTemplateDO.java} | 59 +--- .../message/MpMessageTemplateMapper.java | 17 + .../mysql/template/MsgTemplateLogMapper.java | 35 -- .../dal/mysql/template/MsgTemplateMapper.java | 35 -- .../template/MpMessageTemplateService.java | 53 +++ .../MpMessageTemplateServiceImpl.java | 176 ++++++++++ .../template/MsgTemplateLogService.java | 63 ---- .../template/MsgTemplateLogServiceImpl.java | 89 ----- .../service/template/MsgTemplateService.java | 87 ----- .../template/MsgTemplateServiceImpl.java | 313 ------------------ 27 files changed, 478 insertions(+), 1308 deletions(-) create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.http create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpMessageTemplateController.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateListReqVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateRespVO.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/template/MpMessageTemplateSendReqVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateController.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/MsgTemplateLogController.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateBatchReqVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogPageReqVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogRespVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateLogSaveReqVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplatePageReqVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateRespVO.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/template/vo/MsgTemplateSaveReqVO.java rename yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/{MsgTemplateDO.java => MpMessageTemplateDO.java} (50%) create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageTemplateMapper.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateLogMapper.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/template/MsgTemplateMapper.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateService.java create mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateServiceImpl.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogService.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateLogServiceImpl.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateService.java delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MsgTemplateServiceImpl.java 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 From a1f7f81e8d9eb07ab12f53cc7e57470c23cf6fac Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 26 Nov 2025 18:34:03 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mp=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E2=80=9C=E6=A8=A1=E7=89=88=E6=B6=88=E6=81=AF=E2=80=9D?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 683a2c450..b0d141db6 100644 --- a/README.md +++ b/README.md @@ -235,18 +235,19 @@ ### 微信公众号 -| | 功能 | 描述 | -|-----|--------|-------------------------------| -| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 | -| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 | -| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 | -| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 | -| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 | -| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 | -| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 | -| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 | -| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 | -| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 | +| | 功能 | 描述 | +|----|--------|-------------------------------| +| 🚀 | 账号管理 | 配置接入的微信公众号,可支持多个公众号 | +| 🚀 | 数据统计 | 统计公众号的用户增减、累计用户、消息概况、接口分析等数据 | +| 🚀 | 粉丝管理 | 查看已关注、取关的粉丝列表,可对粉丝进行同步、打标签等操作 | +| 🚀 | 消息管理 | 查看粉丝发送的消息列表,可主动回复粉丝消息 | +| 🚀 | 模版消息 | 配置和发送模版消息,用于向粉丝推送通知类消息 | +| 🚀 | 自动回复 | 自动回复粉丝发送的消息,支持关注回复、消息回复、关键字回复 | +| 🚀 | 标签管理 | 对公众号的标签进行创建、查询、修改、删除等操作 | +| 🚀 | 菜单管理 | 自定义公众号的菜单,也可以从公众号同步菜单 | +| 🚀 | 素材管理 | 管理公众号的图片、语音、视频等素材,支持在线播放语音、视频 | +| 🚀 | 图文草稿箱 | 新增常用的图文素材到草稿箱,可发布到公众号 | +| 🚀 | 图文发表记录 | 查看已发布成功的图文素材,支持删除操作 | ### 商城系统 From bd31e5abb2a148918eb9a2ee7f9947904cb30514 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 26 Nov 2025 18:35:24 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mp=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E2=80=9C=E6=A8=A1=E7=89=88=E6=B6=88=E6=81=AF=E2=80=9D?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/mp/controller/admin/user/vo/MpUserPageReqVO.java | 5 ----- 1 file changed, 5 deletions(-) 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 bb3d0aafb..cf602e659 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 @@ -7,8 +7,6 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; -import java.util.List; - @Schema(description = "管理后台 - 公众号粉丝分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) @@ -28,7 +26,4 @@ public class MpUserPageReqVO extends PageParam { @Schema(description = "公众号粉丝昵称,模糊匹配", example = "芋艿") private String nickname; - @Schema(description = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M") - private List openidList; - } From 036bdc79ba8c68e7ead5340c8f78015853992e1b Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 26 Nov 2025 18:43:50 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mp=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84=E2=80=9C=E6=A8=A1=E7=89=88=E6=B6=88=E6=81=AF=E2=80=9D?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=88=E8=B0=83=E6=95=B4=E5=8C=85?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../message/MpMessageTemplateController.java | 4 +- .../MpMessageTemplateDO.java | 2 +- .../dataobject/template/MsgTemplateLogDO.java | 72 ------------------- .../message/MpMessageTemplateMapper.java | 2 +- .../MpMessageTemplateService.java | 4 +- .../MpMessageTemplateServiceImpl.java | 4 +- 6 files changed, 8 insertions(+), 80 deletions(-) rename yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/{template => message}/MpMessageTemplateDO.java (96%) delete mode 100644 yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java rename yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/{template => message}/MpMessageTemplateService.java (89%) rename yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/{template => message}/MpMessageTemplateServiceImpl.java (98%) 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 index f3d27fda5..81cb1104e 100644 --- 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 @@ -5,8 +5,8 @@ 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 cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageTemplateDO; +import cn.iocoder.yudao.module.mp.service.message.MpMessageTemplateService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageTemplateDO.java similarity index 96% rename from yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java rename to yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageTemplateDO.java index ca0534fa0..0675fa3b6 100644 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MpMessageTemplateDO.java +++ b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/message/MpMessageTemplateDO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.mp.dal.dataobject.template; +package cn.iocoder.yudao.module.mp.dal.dataobject.message; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; diff --git a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java b/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java deleted file mode 100644 index fdf0d9248..000000000 --- a/yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/dal/dataobject/template/MsgTemplateLogDO.java +++ /dev/null @@ -1,72 +0,0 @@ -package cn.iocoder.yudao.module.mp.dal.dataobject.template; - -import lombok.*; - -import java.time.LocalDateTime; - -import com.baomidou.mybatisplus.annotation.*; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; - -/** - * 微信模版消息发送记录 DO - * - * @author dengsl - */ -@TableName("mp_msg_template_log") -@KeySequence("mp_msg_template_log_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MsgTemplateLogDO extends BaseDO { - - /** - * 主键 - */ - @TableId - private Long id; - /** - * appId - */ - private String appId; - /** - * 用户openid - */ - private String toUser; - /** - * 公众号模板ID - */ - private String templateId; - /** - * 消息内容 - */ - private String data; - /** - * 链接 - */ - private String url; - /** - * 小程序appid - */ - private String miniProgramAppId; - /** - * 小程序页面路径 - */ - private String miniProgramPagePath; - /** - * 发送时间 - */ - private LocalDateTime sendTime; - /** - * 发送状态 0成功,1失败 - */ - private Integer sendStatus; - /** - * 发送结果 - */ - private String 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/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 index 546cf0dd0..8c795905d 100644 --- 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 @@ -2,7 +2,7 @@ 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 cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageTemplateDO; import org.apache.ibatis.annotations.Mapper; import java.util.List; 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/message/MpMessageTemplateService.java similarity index 89% rename from yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateService.java rename to yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageTemplateService.java index ae6c74c63..f4ae143c6 100644 --- 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/message/MpMessageTemplateService.java @@ -1,8 +1,8 @@ -package cn.iocoder.yudao.module.mp.service.template; +package cn.iocoder.yudao.module.mp.service.message; 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 cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageTemplateDO; import java.util.List; 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/message/MpMessageTemplateServiceImpl.java similarity index 98% rename from yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/template/MpMessageTemplateServiceImpl.java rename to yudao-module-mp/yudao-module-mp-server/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpMessageTemplateServiceImpl.java index 7b12fb6f7..d45a95cf9 100644 --- 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/message/MpMessageTemplateServiceImpl.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.mp.service.template; +package cn.iocoder.yudao.module.mp.service.message; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; @@ -7,7 +7,7 @@ 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.message.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;