mirror of
https://gitee.com/zhijiantianya/yudao-cloud.git
synced 2025-12-30 01:12:26 +00:00
feat:【mp】完善“模版消息”的功能
This commit is contained in:
@@ -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, "发送模版消息失败,原因:{}");
|
||||
|
||||
}
|
||||
|
||||
@@ -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\"}",
|
||||
@@ -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<Boolean> 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<MpMessageTemplateRespVO> 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<List<MpMessageTemplateRespVO>> getMessageTemplateList(MpMessageTemplateListReqVO listReqVO) {
|
||||
List<MpMessageTemplateDO> 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<Boolean> syncMessageTemplate(@RequestParam("accountId") Long accountId) {
|
||||
messageTemplateService.syncMessageTemplate(accountId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/send")
|
||||
@Operation(summary = "给粉丝发送模版消息")
|
||||
@PreAuthorize("@ss.hasPermission('mp:message-template:send')")
|
||||
public CommonResult<Boolean> sendMessageTemplate(@Valid @RequestBody MpMessageTemplateSendReqVO sendReqVO) {
|
||||
messageTemplateService.sendMessageTempalte(sendReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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<String, String> data;
|
||||
|
||||
}
|
||||
@@ -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<Long> createMsgTemplate(@Valid @RequestBody MsgTemplateSaveReqVO createReqVO) {
|
||||
return success(msgTemplateService.createMsgTemplate(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新消息模板")
|
||||
@PreAuthorize("@ss.hasPermission('mp:template:update')")
|
||||
public CommonResult<Boolean> 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<Boolean> 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<Boolean> deleteMsgTemplateList(@RequestBody List<Long> 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<MsgTemplateRespVO> 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<PageResult<MsgTemplateRespVO>> getMsgTemplatePage(@Valid MsgTemplatePageReqVO pageReqVO) {
|
||||
PageResult<MsgTemplateDO> 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<MsgTemplateDO> 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<Boolean> 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<Boolean> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<Long> createMsgTemplateLog(@Valid @RequestBody MsgTemplateLogSaveReqVO createReqVO) {
|
||||
return success(msgTemplateLogService.createMsgTemplateLog(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新微信模版消息发送记录")
|
||||
@PreAuthorize("@ss.hasPermission('mp:template-log:update')")
|
||||
public CommonResult<Boolean> 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<Boolean> 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<Boolean> deleteMsgTemplateLogList(@RequestParam("ids") List<Long> 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<MsgTemplateLogRespVO> 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<PageResult<MsgTemplateLogRespVO>> getMsgTemplateLogPage(@Valid MsgTemplateLogPageReqVO pageReqVO) {
|
||||
PageResult<MsgTemplateLogDO> 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<MsgTemplateLogDO> list = msgTemplateLogService.getMsgTemplateLogPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "微信模版消息发送记录.xls", "数据", MsgTemplateLogRespVO.class,
|
||||
BeanUtils.toBean(list, MsgTemplateLogRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -30,4 +30,5 @@ public class MpUserPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "公众号粉丝标识", example = "o6_bmjrPTlm6_2sgVt7hMZOPfL2M")
|
||||
private List<String> openidList;
|
||||
|
||||
}
|
||||
|
||||
@@ -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<MpUserRespVO> convertList(List<MpUserDO> list);
|
||||
|
||||
PageResult<MpUserRespVO> convertPage(PageResult<MpUserDO> page);
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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<MpMessageTemplateDO> {
|
||||
|
||||
default List<MpMessageTemplateDO> selectList(MpMessageTemplateListReqVO listReqVO) {
|
||||
return selectList(MpMessageTemplateDO::getAccountId, listReqVO.getAccountId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MsgTemplateLogDO> {
|
||||
|
||||
default PageResult<MsgTemplateLogDO> selectPage(MsgTemplateLogPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<MsgTemplateLogDO>()
|
||||
.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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MsgTemplateDO> {
|
||||
|
||||
default PageResult<MsgTemplateDO> selectPage(MsgTemplatePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<MsgTemplateDO>()
|
||||
.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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MpMessageTemplateDO> getMessageTemplateList(MpMessageTemplateListReqVO listReqVO);
|
||||
|
||||
/**
|
||||
* 同步公众号已添加的模版消息
|
||||
*
|
||||
* @param accountId 公众号账号的编号
|
||||
*/
|
||||
void syncMessageTemplate(Long accountId);
|
||||
|
||||
/**
|
||||
* 使用公众号,给粉丝发送【模版】消息
|
||||
*
|
||||
* @param sendReqVO 消息内容
|
||||
*/
|
||||
void sendMessageTempalte(MpMessageTemplateSendReqVO sendReqVO);
|
||||
|
||||
}
|
||||
@@ -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<MpMessageTemplateDO> getMessageTemplateList(MpMessageTemplateListReqVO listReqVO) {
|
||||
return messageTemplateMapper.selectList(listReqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void syncMessageTemplate(Long accountId) {
|
||||
MpAccountDO account = mpAccountService.getRequiredAccount(accountId);
|
||||
|
||||
// 第一步,从公众号平台获取最新的模板列表
|
||||
List<WxMpTemplate> wxTemplates;
|
||||
try {
|
||||
wxTemplates = mpServiceFactory.getRequiredMpService(accountId)
|
||||
.getTemplateMsgService().getAllPrivateTemplate();
|
||||
} catch (WxErrorException e) {
|
||||
throw exception(MESSAGE_TEMPLATE_SYNC_FAIL, e.getError().getErrorMsg());
|
||||
}
|
||||
|
||||
// 第二步,合并更新回自己的数据库
|
||||
Map<String, MpMessageTemplateDO> templateMap = convertMap(
|
||||
messageTemplateMapper.selectList(new LambdaQueryWrapperX<MpMessageTemplateDO>()
|
||||
.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<WxMpTemplateData> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得微信模版消息发送记录
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 微信模版消息发送记录
|
||||
*/
|
||||
MsgTemplateLogDO getMsgTemplateLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得微信模版消息发送记录分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 微信模版消息发送记录分页
|
||||
*/
|
||||
PageResult<MsgTemplateLogDO> getMsgTemplateLogPage(MsgTemplateLogPageReqVO pageReqVO);
|
||||
|
||||
}
|
||||
@@ -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<Long> ids) {
|
||||
// 校验存在
|
||||
validateMsgTemplateLogExists(ids);
|
||||
// 删除
|
||||
msgTemplateLogMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
private void validateMsgTemplateLogExists(List<Long> ids) {
|
||||
List<MsgTemplateLogDO> 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<MsgTemplateLogDO> getMsgTemplateLogPage(MsgTemplateLogPageReqVO pageReqVO) {
|
||||
return msgTemplateLogMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得消息模板
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 消息模板
|
||||
*/
|
||||
MsgTemplateDO getMsgTemplate(Long id);
|
||||
|
||||
/**
|
||||
* 获得消息模板分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 消息模板分页
|
||||
*/
|
||||
PageResult<MsgTemplateDO> 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);
|
||||
}
|
||||
@@ -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<Long> ids) {
|
||||
// 校验存在
|
||||
validateMsgTemplateExists(ids);
|
||||
// 删除
|
||||
msgTemplateMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
private void validateMsgTemplateExists(List<Long> ids) {
|
||||
List<MsgTemplateDO> 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<MsgTemplateDO> 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<WxMpTemplate> wxTemplates = mpServiceFactory.getRequiredMpService(appId).getTemplateMsgService().getAllPrivateTemplate();
|
||||
if (CollUtil.isNotEmpty(wxTemplates)) {
|
||||
List<MsgTemplateDO> dbTemplates = msgTemplateMapper.selectList(new QueryWrapper<MsgTemplateDO>()
|
||||
.lambda().eq(MsgTemplateDO::getAppId, appId));
|
||||
// 将微信模板转换为Map,便于查找
|
||||
Map<String, WxMpTemplate> wxTemplateMap = wxTemplates.stream()
|
||||
.collect(Collectors.toMap(WxMpTemplate::getTemplateId, Function.identity()));
|
||||
|
||||
// 将数据库模板转换为Map,便于查找
|
||||
Map<String, MsgTemplateDO> 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<String, WxMpTemplate> wxTemplateMap,
|
||||
Map<String, MsgTemplateDO> dbTemplateMap) {
|
||||
List<MsgTemplateDO> 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<String, WxMpTemplate> wxTemplateMap,
|
||||
Map<String, MsgTemplateDO> dbTemplateMap) {
|
||||
List<MsgTemplateDO> 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<MsgTemplateDO>()
|
||||
.set(MsgTemplateDO::getIsRemoved, 1)
|
||||
.in(MsgTemplateDO::getId, removedTemplates.stream().map(MsgTemplateDO::getId).collect(Collectors.toList())));
|
||||
log.info("批量标记公众号模板为已删除: count={}", removedTemplates.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理已存在的模板(在两边都存在)- 清空已设置的信息
|
||||
*/
|
||||
private void handleUpdatedTemplates(Map<String, WxMpTemplate> wxTemplateMap,
|
||||
Map<String, MsgTemplateDO> dbTemplateMap) {
|
||||
List<Long> 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<MsgTemplateDO>()
|
||||
.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<MsgTemplateDO>()
|
||||
.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<MpUserDO> 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("批量发送模板消息任务完成");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user