From 0ec835244df0a3635cac2c23aaf3bc5715537c11 Mon Sep 17 00:00:00 2001 From: wuKong Date: Wed, 5 Nov 2025 11:41:31 +0800 Subject: [PATCH 01/10] =?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 8bfc3b480b12efc3266cf5969647903e8338de22 Mon Sep 17 00:00:00 2001 From: wuKong Date: Mon, 24 Nov 2025 17:05:48 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat(pay):=20=E6=94=AF=E6=8C=81=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E8=AE=A2=E5=8D=95=E5=8F=B7=E6=9F=A5=E8=AF=A2=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 AppPayOrderController 中增加根据支付订单号查询订单的功能 - 新增 PayOrderMapper 的 selectByNo 方法用于按订单号查询 - 扩展 PayOrderService 接口及实现类以支持订单号查询 - 优化查询逻辑,优先使用订单号查询,其次使用订单ID查询 - 更新接口文档,增加支付订单号参数说明 - 使用 CharSequenceUtil 工具类判断订单号是否为空 --- .../app/order/AppPayOrderController.java | 17 +++++++++++++---- .../pay/dal/mysql/order/PayOrderMapper.java | 4 ++++ .../pay/service/order/PayOrderService.java | 8 +++++++- .../pay/service/order/PayOrderServiceImpl.java | 5 ++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java index 4f5716384..8fa78306e 100644 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.pay.controller.app.order; +import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -46,13 +47,21 @@ public class AppPayOrderController { @GetMapping("/get") @Operation(summary = "获得支付订单") @Parameters({ - @Parameter(name = "id", description = "编号", required = true, example = "1024"), + @Parameter(name = "id", description = "编号", example = "1024"), + @Parameter(name = "no", description = "支付订单号", example = "Pxxx"), @Parameter(name = "sync", description = "是否同步", example = "true") }) - public CommonResult getOrder(@RequestParam("id") Long id, + public CommonResult getOrder(@RequestParam(value = "id", required = false) Long id, + @RequestParam(value = "no", required = false) String no, @RequestParam(value = "sync", required = false) Boolean sync) { - PayOrderDO order = payOrderService.getOrder(id); - if (order== null) { + PayOrderDO order = null; + if (CharSequenceUtil.isNotEmpty(no)){ + order = payOrderService.getOrder(no); + } + if (ObjUtil.isNull(order) && ObjUtil.isNotNull(id)) { + order = payOrderService.getOrder(id); + } + if (order == null) { return success(null); } // 重要:校验订单是否是当前用户,避免越权 diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java index 95510d5f7..e83d0387c 100755 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/order/PayOrderMapper.java @@ -48,6 +48,10 @@ public interface PayOrderMapper extends BaseMapperX { PayOrderDO::getMerchantOrderId, merchantOrderId); } + default PayOrderDO selectByNo(String no) { + return selectOne(PayOrderDO::getNo, no); + } + default int updateByIdAndStatus(Long id, Integer status, PayOrderDO update) { return update(update, new LambdaQueryWrapper() .eq(PayOrderDO::getId, id).eq(PayOrderDO::getStatus, status)); diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java index c4496f829..e2af1df2d 100755 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java @@ -30,7 +30,13 @@ public interface PayOrderService { * @return 支付订单 */ PayOrderDO getOrder(Long id); - + /** + * 获得支付订单 + * + * @param no 支付订单号 + * @return 支付订单 + */ + PayOrderDO getOrder(String no); /** * 获得支付订单 * diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java index b7f18abd6..41eee7989 100755 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java @@ -78,7 +78,10 @@ public class PayOrderServiceImpl implements PayOrderService { public PayOrderDO getOrder(Long id) { return orderMapper.selectById(id); } - + @Override + public PayOrderDO getOrder(String no) { + return orderMapper.selectByNo(no); + } @Override public PayOrderDO getOrder(Long appId, String merchantOrderId) { return orderMapper.selectByAppIdAndMerchantOrderId(appId, merchantOrderId); From 4212c8aed8f74cb19a8163cb74f1158b793d12e1 Mon Sep 17 00:00:00 2001 From: wuKong Date: Mon, 24 Nov 2025 17:37:22 +0800 Subject: [PATCH 03/10] =?UTF-8?q?fix(pay):=E4=BF=AE=E5=A4=8D=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E8=AE=A2=E5=8D=95=E5=90=8C=E6=AD=A5=E5=90=8E=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=8F=82=E6=95=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复了同步支付订单后查询参数传错的问题 - 将错误的 id 参数替换为正确的 order.getId() 参数 - 确保同步后能正确获取最新的订单状态 --- .../module/pay/controller/app/order/AppPayOrderController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java index 8fa78306e..51b3bec09 100644 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java @@ -74,7 +74,7 @@ public class AppPayOrderController { if (Boolean.TRUE.equals(sync) && PayOrderStatusEnum.isWaiting(order.getStatus())) { payOrderService.syncOrderQuietly(order.getId()); // 重新查询,因为同步后,可能会有变化 - order = payOrderService.getOrder(id); + order = payOrderService.getOrder(order.getId()); } return success(BeanUtils.toBean(order, PayOrderRespVO.class)); } From 76380b5e5d6e2719bc63e942337fb1230f768829 Mon Sep 17 00:00:00 2001 From: wuKong Date: Mon, 24 Nov 2025 18:36:55 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=8E=A8=20fix(pay):=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/pay/controller/app/order/AppPayOrderController.java | 2 +- .../yudao/module/pay/service/order/PayOrderServiceImpl.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java index 51b3bec09..1de6ca915 100644 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java @@ -55,7 +55,7 @@ public class AppPayOrderController { @RequestParam(value = "no", required = false) String no, @RequestParam(value = "sync", required = false) Boolean sync) { PayOrderDO order = null; - if (CharSequenceUtil.isNotEmpty(no)){ + if (CharSequenceUtil.isNotEmpty(no)) { order = payOrderService.getOrder(no); } if (ObjUtil.isNull(order) && ObjUtil.isNotNull(id)) { diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java index 41eee7989..8a9bebde8 100755 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java @@ -78,10 +78,12 @@ public class PayOrderServiceImpl implements PayOrderService { public PayOrderDO getOrder(Long id) { return orderMapper.selectById(id); } + @Override public PayOrderDO getOrder(String no) { return orderMapper.selectByNo(no); } + @Override public PayOrderDO getOrder(Long appId, String merchantOrderId) { return orderMapper.selectByAppIdAndMerchantOrderId(appId, merchantOrderId); From a483d57eca5ec3a1a7f7edc38ce0cca38b66f8f0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 24 Nov 2025 19:21:58 +0800 Subject: [PATCH 05/10] =?UTF-8?q?feat=EF=BC=9A=E3=80=90iot=E3=80=91tdengin?= =?UTF-8?q?e=20=E8=B0=83=E6=95=B4=E6=88=90=20WS=20=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20decimal=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yaml | 7 ------- .../src/main/resources/application-local.yaml | 2 +- yudao-server/src/main/resources/application-local.yaml | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml index 21a93789d..6be335bbc 100644 --- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml +++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-dev.yaml @@ -65,13 +65,6 @@ spring: url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root password: 123456 -# tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!) -# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro -# driver-class-name: com.taosdata.jdbc.rs.RestfulDriver -# username: root -# password: taosdata -# druid: -# validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: diff --git a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml index c1d93811c..79635472b 100644 --- a/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml +++ b/yudao-module-iot/yudao-module-iot-server/src/main/resources/application-local.yaml @@ -75,7 +75,7 @@ spring: username: root password: 123456 # tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!) -# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro +# url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro # driver-class-name: com.taosdata.jdbc.rs.RestfulDriver # username: root # password: taosdata diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index ae5bd96f8..4bb280516 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -68,7 +68,7 @@ spring: username: root password: 123456 # tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!) -# url: jdbc:TAOS-RS://127.0.0.1:6041/ruoyi_vue_pro +# url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro # driver-class-name: com.taosdata.jdbc.rs.RestfulDriver # username: root # password: taosdata From 739487e528b2edce56637a3e11dee6ac41b12e7c Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 24 Nov 2025 20:20:03 +0800 Subject: [PATCH 06/10] =?UTF-8?q?!221=20feat(pay):=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=94=AF=E4=BB=98=E8=AE=A2=E5=8D=95=E5=8F=B7?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=94=AF=E4=BB=98=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/module/pay/service/order/PayOrderService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java index e2af1df2d..fcce1f5a9 100755 --- a/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java +++ b/yudao-module-pay/yudao-module-pay-server/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java @@ -30,6 +30,7 @@ public interface PayOrderService { * @return 支付订单 */ PayOrderDO getOrder(Long id); + /** * 获得支付订单 * @@ -37,6 +38,7 @@ public interface PayOrderService { * @return 支付订单 */ PayOrderDO getOrder(String no); + /** * 获得支付订单 * From 8becb49a3b82f5de87f1cb2fd3bb382dbd1027f1 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 25 Nov 2025 12:58:25 +0800 Subject: [PATCH 07/10] =?UTF-8?q?=E3=80=90=E5=90=8C=E6=AD=A5=E3=80=91BOOT?= =?UTF-8?q?=20=E5=92=8C=20CLOUD=20=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/tools/convertor.py | 10 ++- .../bpm/service/task/BpmTaskServiceImpl.java | 38 +++++----- .../file/core/utils/FileTypeUtils.java | 3 +- .../vue3_vben5_antd/general/views/form.vue.vm | 6 +- .../general/views/index.vue.vm | 63 ++++++++-------- .../general/views/modules/form_sub_erp.vue.vm | 5 +- .../views/modules/form_sub_normal.vue.vm | 55 +++++++------- .../general/views/modules/list_sub_erp.vue.vm | 72 +++++++++---------- .../views/modules/form_sub_normal.vue.vm | 29 ++++---- .../schema/views/modules/list_sub_erp.vue.vm | 4 +- .../admin/product/IotProductController.java | 2 +- .../rule/scene/IotSceneRuleServiceImpl.java | 4 +- .../IotDeviceEventPostTriggerMatcher.java | 8 +-- 13 files changed, 152 insertions(+), 147 deletions(-) diff --git a/sql/tools/convertor.py b/sql/tools/convertor.py index b54d1337c..d52a7a73c 100644 --- a/sql/tools/convertor.py +++ b/sql/tools/convertor.py @@ -52,6 +52,7 @@ def load_and_clean(sql_file: str) -> str: REPLACE_PAIR_LIST = ( (")\nVALUES ", ") VALUES "), (" CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ", " "), + (" CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ", " "), (" KEY `", " INDEX `"), ("UNIQUE INDEX", "UNIQUE KEY"), ("b'0'", "'0'"), @@ -61,6 +62,11 @@ def load_and_clean(sql_file: str) -> str: content = open(sql_file, encoding="utf-8").read() for replace_pair in REPLACE_PAIR_LIST: content = content.replace(*replace_pair) + # 移除索引字段的前缀长度定义,例如: `name`(32) -> `name` + # 移除索引定义上的 USING BTREE COMMENT 部分 + # 相关 issue:https://t.zsxq.com/96IFc 、https://t.zsxq.com/rC3A3 + content = re.sub(r'`([^`]+)`\(\d+\)', r'`\1`', content) + content = re.sub(r'\s+USING\s+BTREE\s+COMMENT\s+\'[^\']+\'', '', content) content = re.sub(r"ENGINE.*COMMENT", "COMMENT", content) content = re.sub(r"ENGINE.*;", ";", content) return content @@ -262,10 +268,10 @@ class Convertor(ABC): # 解析注释 for column in table_ddl["columns"]: column["comment"] = bytes(column["comment"], "utf-8").decode( - "unicode_escape" + r"unicode_escape" )[1:-1] table_ddl["comment"] = bytes(table_ddl["comment"], "utf-8").decode( - "unicode_escape" + r"unicode_escape" )[1:-1] # 为每个表生成个6个基本部分 diff --git a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 6545d83d6..acd437b57 100644 --- a/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-server/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -779,8 +779,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { */ private void approveDelegateTask(BpmTaskApproveReqVO reqVO, Task task) { // 1. 添加审批意见 - AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()).getCheckedData(); - AdminUserRespDTO ownerUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())).getCheckedData(); // 发起委托的用户 + AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()); + AdminUserRespDTO ownerUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); // 发起委托的用户 Assert.notNull(ownerUser, "委派任务找不到原审批人,需要检查数据"); taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_END.getType(), BpmCommentTypeEnum.DELEGATE_END.formatComment(currentUser.getNickname(), ownerUser.getNickname(), reqVO.getReason())); @@ -949,11 +949,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { Set needSimulateTaskDefinitionKeys = getNeedSimulateTaskDefinitionKeys(bpmnModel, currentTask, targetElement); // 4. 执行驳回 - // 使用 moveExecutionsToSingleActivityId 替换 moveActivityIdsToSingleActivityId 原因: - // 当多实例任务回退的时候有问题。相关 issue: https://github.com/flowable/flowable-engine/issues/3944 + // ① 使用 moveExecutionsToSingleActivityId 替换 moveActivityIdsToSingleActivityId。原因:当多实例任务回退的时候有问题。 + // 相关 issue: https://github.com/flowable/flowable-engine/issues/3944 + // ② flowable 7.2.0 版本后,继续使用 moveActivityIdsToSingleActivityId 方法。原因:flowable 7.2.0 版本修复了该问题。 + // 相关 issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/1018 runtimeService.createChangeActivityStateBuilder() .processInstanceId(currentTask.getProcessInstanceId()) - .moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) + .moveActivityIdsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) // 设置需要预测的任务 ids 的流程变量,用于辅助预测 .processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys) // 设置流程变量(local)节点退回标记, 用于退回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略,导致自动通过 @@ -1000,13 +1002,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(TASK_DELEGATE_FAIL_USER_REPEAT); } // 1.2 校验目标用户存在 - AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId()).getCheckedData(); + AdminUserRespDTO delegateUser = adminUserApi.getUser(reqVO.getDelegateUserId()); if (delegateUser == null) { throw exception(TASK_DELEGATE_FAIL_USER_NOT_EXISTS); } // 2. 添加委托意见 - AdminUserRespDTO currentUser = adminUserApi.getUser(userId).getCheckedData(); + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START.getType(), BpmCommentTypeEnum.DELEGATE_START.formatComment(currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason())); @@ -1031,13 +1033,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { throw exception(TASK_TRANSFER_FAIL_USER_REPEAT); } // 1.2 校验目标用户存在 - AdminUserRespDTO assigneeUser = adminUserApi.getUser(reqVO.getAssigneeUserId()).getCheckedData(); + AdminUserRespDTO assigneeUser = adminUserApi.getUser(reqVO.getAssigneeUserId()); if (assigneeUser == null) { throw exception(TASK_TRANSFER_FAIL_USER_NOT_EXISTS); } // 2. 添加委托意见 - AdminUserRespDTO currentUser = adminUserApi.getUser(userId).getCheckedData(); + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.TRANSFER.getType(), BpmCommentTypeEnum.TRANSFER.formatComment(currentUser.getNickname(), assigneeUser.getNickname(), reqVO.getReason())); @@ -1096,7 +1098,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { public void createSignTask(Long userId, BpmTaskSignCreateReqVO reqVO) { // 1. 获取和校验任务 TaskEntityImpl taskEntity = validateTaskCanCreateSign(userId, reqVO); - List userList = adminUserApi.getUserList(reqVO.getUserIds()).getCheckedData(); + List userList = adminUserApi.getUserList(reqVO.getUserIds()); if (CollUtil.isEmpty(userList)) { throw exception(TASK_SIGN_CREATE_USER_NOT_EXIST); } @@ -1123,7 +1125,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { createSignTaskList(convertList(reqVO.getUserIds(), String::valueOf), taskEntity); // 4. 记录加签的评论到 task 任务 - AdminUserRespDTO currentUser = adminUserApi.getUser(userId).getCheckedData(); + AdminUserRespDTO currentUser = adminUserApi.getUser(userId); String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(), BpmTaskSignTypeEnum.nameOfType(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); @@ -1155,7 +1157,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { List currentAssigneeList = convertListByFlatMap(taskList, task -> // 需要考虑 owner 的情况,因为向后加签时,它暂时没 assignee 而是 owner Stream.of(NumberUtils.parseLong(task.getAssignee()), NumberUtils.parseLong(task.getOwner()))); if (CollUtil.containsAny(currentAssigneeList, reqVO.getUserIds())) { - List userList = adminUserApi.getUserList(CollUtil.intersection(currentAssigneeList, reqVO.getUserIds())).getCheckedData(); + List userList = adminUserApi.getUserList(CollUtil.intersection(currentAssigneeList, reqVO.getUserIds())); throw exception(TASK_SIGN_CREATE_USER_REPEAT, String.join(",", convertList(userList, AdminUserRespDTO::getNickname))); } return taskEntity; @@ -1217,10 +1219,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 1.2 校验取消人存在 AdminUserRespDTO cancelUser = null; if (StrUtil.isNotBlank(task.getAssignee())) { - cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())).getCheckedData(); + cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getAssignee())); } if (cancelUser == null && StrUtil.isNotBlank(task.getOwner())) { - cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())).getCheckedData(); + cancelUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); } Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); @@ -1234,7 +1236,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.deleteTasks(convertList(childTaskList, Task::getId)); // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 - AdminUserRespDTO user = adminUserApi.getUser(userId).getCheckedData(); + AdminUserRespDTO user = adminUserApi.getUser(userId); taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType(), StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname())); @@ -1536,9 +1538,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 情况二:转交给部门负责人审批 if (ObjectUtils.equalsAny(assignStartUserHandlerType, BpmUserTaskAssignStartUserHandlerTypeEnum.TRANSFER_DEPT_LEADER.getType())) { - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData(); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); Assert.notNull(startUser, "提交人({})信息为空", processInstance.getStartUserId()); - DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()).getCheckedData() : null; + DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()) : null; Assert.notNull(dept, "提交人({})部门({})信息为空", processInstance.getStartUserId(), startUser.getDeptId()); // 找不到部门负责人的情况下,自动审批通过 // noinspection DataFlowIssue @@ -1560,7 +1562,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 FlowableUtils.execute(processInstance.getTenantId(), () -> { - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())).getCheckedData(); + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); }); } diff --git a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java index 28d6a9fa1..f8cd1c45c 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java +++ b/yudao-module-infra/yudao-module-infra-server/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java @@ -91,9 +91,8 @@ public class FileTypeUtils { } // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 if (StrUtil.containsIgnoreCase(mineType, "video")) { - response.setHeader("Content-Length", String.valueOf(content.length)); - response.setHeader("Content-Range", "bytes 0-" + (content.length - 1) + "/" + content.length); response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("Content-Length", String.valueOf(content.length)); } // 输出附件 IoUtil.write(response.getOutputStream(), false, content); diff --git a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm index 06dc0c86c..581eae041 100644 --- a/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm +++ b/yudao-module-infra/yudao-module-infra-server/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm @@ -1,6 +1,6 @@