From 6fc0b3fc546b3aa41e9d1f9a3f49cb9f23deb97d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Tue, 17 Jan 2023 00:58:35 +0800 Subject: [PATCH] =?UTF-8?q?mp=EF=BC=9A=E5=A2=9E=E5=8A=A0=E3=80=90=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=9B=9E=E5=A4=8D=E3=80=91=E7=9A=84=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=81=E4=BF=AE=E6=94=B9=E3=80=81=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/mp/enums/ErrorCodeConstants.java | 6 ++ .../admin/message/MpAutoReplyController.java | 31 +++++- .../vo/autoreply/MpAutoReplyCreateReqVO.java | 4 - .../convert/message/MpAutoReplyConvert.java | 5 + .../dal/mysql/message/MpAutoReplyMapper.java | 18 ++++ .../service/message/MpAutoReplyService.java | 26 +++++ .../message/MpAutoReplyServiceImpl.java | 102 ++++++++++++++++++ .../src/views/mp/autoReply/index.vue | 50 ++++----- 8 files changed, 210 insertions(+), 32 deletions(-) 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 5bb9d3f01..c8e5846f2 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 @@ -55,4 +55,10 @@ public interface ErrorCodeConstants { ErrorCode MENU_SAVE_FAIL = new ErrorCode(1006008000, "创建菜单失败,原因:{}"); ErrorCode MENU_DELETE_FAIL = new ErrorCode(1006008001, "删除菜单失败,原因:{}"); + // ========== 公众号自动回复 1006009000============ + ErrorCode AUTO_REPLY_NOT_EXISTS = new ErrorCode(1006009000, "自动回复不存在"); + ErrorCode AUTO_REPLY_ADD_SUBSCRIBE_FAIL_EXISTS = new ErrorCode(1006009001, "操作失败,原因:已存在关注时的回复"); + ErrorCode AUTO_REPLY_ADD_MESSAGE_FAIL_EXISTS = new ErrorCode(1006009002, "操作失败,原因:已存在该消息类型的回复"); + ErrorCode AUTO_REPLY_ADD_KEYWORD_FAIL_EXISTS = new ErrorCode(1006009003, "操作失败,原因:已关在该关键字的回复"); + } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java index 397d091b6..374588d6d 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/MpAutoReplyController.java @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.mp.controller.admin.message; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; import cn.iocoder.yudao.module.mp.convert.message.MpAutoReplyConvert; import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; @@ -12,10 +14,7 @@ import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; @@ -48,4 +47,28 @@ public class MpAutoReplyController { return success(MpAutoReplyConvert.INSTANCE.convert(autoReply)); } + @PostMapping("/create") + @ApiOperation("创建公众号自动回复") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:create')") + public CommonResult createAutoReply(@Valid @RequestBody MpAutoReplyCreateReqVO createReqVO) { + return success(mpAutoReplyService.createAutoReply(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新公众号自动回复") + @PreAuthorize("@ss.hasPermission('mp:auto-reply:update')") + public CommonResult updateAutoReply(@Valid @RequestBody MpAutoReplyUpdateReqVO updateReqVO) { + mpAutoReplyService.updateAutoReply(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除公众号自动回复") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('mp:auto-reply:delete')") + public CommonResult deleteAutoReply(@RequestParam("id") Long id) { + mpAutoReplyService.deleteAutoReply(id); + return success(true); + } + } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java index db82cbad7..2cfe25254 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/autoreply/MpAutoReplyCreateReqVO.java @@ -18,8 +18,4 @@ public class MpAutoReplyCreateReqVO extends MpAutoReplyBaseVO { @NotNull(message = "微信公众号 ID不能为空") private Long accountId; - @ApiModelProperty(value = "回复类型", required = true, example = "1", notes = "参见 MpAutoReplyTypeEnum 枚举") - @NotNull(message = "回复类型不能为空") - private Integer type; - } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java index c33aa2449..c7cf8902e 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/convert/message/MpAutoReplyConvert.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.mp.convert.message; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyRespVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; import org.mapstruct.Mapper; @@ -29,4 +31,7 @@ public interface MpAutoReplyConvert { MpAutoReplyRespVO convert(MpAutoReplyDO bean); + MpAutoReplyDO convert(MpAutoReplyCreateReqVO bean); + + MpAutoReplyDO convert(MpAutoReplyUpdateReqVO bean); } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java index c85387c00..c8260e8c7 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpAutoReplyMapper.java @@ -49,4 +49,22 @@ public interface MpAutoReplyMapper extends BaseMapperX { .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType())); } + default MpAutoReplyDO selectByAccountIdAndSubscribe(Long accountId) { + return selectOne(MpAutoReplyDO::getAccountId, accountId, + MpAutoReplyDO::getType, MpAutoReplyTypeEnum.SUBSCRIBE.getType()); + } + + default MpAutoReplyDO selectByAccountIdAndMessage(Long accountId, String requestMessageType) { + return selectOne(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAccountId, accountId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.MESSAGE.getType()) + .eq(MpAutoReplyDO::getRequestMessageType, requestMessageType)); + } + + default MpAutoReplyDO selectByAccountIdAndKeyword(Long accountId, String requestKeyword) { + return selectOne(new LambdaQueryWrapperX() + .eq(MpAutoReplyDO::getAccountId, accountId) + .eq(MpAutoReplyDO::getType, MpAutoReplyTypeEnum.KEYWORD.getType()) + .eq(MpAutoReplyDO::getRequestKeyword, requestKeyword)); + } } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java index 28278f2b5..601995dc8 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyService.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.mp.service.message; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; @@ -29,6 +31,29 @@ public interface MpAutoReplyService { */ MpAutoReplyDO getAutoReply(Long id); + + /** + * 创建公众号自动回复 + * + * @param createReqVO 创建请求 + * @return 自动回复的编号 + */ + Long createAutoReply(MpAutoReplyCreateReqVO createReqVO); + + /** + * 更新公众号自动回复 + * + * @param updateReqVO 更新请求 + */ + void updateAutoReply(MpAutoReplyUpdateReqVO updateReqVO); + + /** + * 删除公众号自动回复 + * + * @param id 自动回复的编号 + */ + void deleteAutoReply(Long id); + /** * 当收到消息时,自动回复 * @@ -46,4 +71,5 @@ public interface MpAutoReplyService { * @return 回复的消息 */ WxMpXmlOutMessage replyForSubscribe(String appId, WxMpXmlMessage wxMessage); + } diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java index c818895ed..87fe27511 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message/MpAutoReplyServiceImpl.java @@ -2,13 +2,18 @@ package cn.iocoder.yudao.module.mp.service.message; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ObjUtil; +import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyCreateReqVO; +import cn.iocoder.yudao.module.mp.controller.admin.message.vo.autoreply.MpAutoReplyUpdateReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.message.MpMessagePageReqVO; import cn.iocoder.yudao.module.mp.convert.message.MpAutoReplyConvert; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpAutoReplyDO; import cn.iocoder.yudao.module.mp.dal.mysql.message.MpAutoReplyMapper; import cn.iocoder.yudao.module.mp.enums.message.MpAutoReplyTypeEnum; +import cn.iocoder.yudao.module.mp.framework.mp.core.util.MpUtils; import cn.iocoder.yudao.module.mp.service.account.MpAccountService; import cn.iocoder.yudao.module.mp.service.message.bo.MpMessageSendOutReqBO; import me.chanjar.weixin.common.api.WxConsts; @@ -19,8 +24,12 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import javax.validation.Validator; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; + /** * 公众号的自动回复 Service 实现类 * @@ -36,6 +45,9 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService { @Lazy // 延迟加载,避免循环依赖 private MpAccountService mpAccountService; + @Resource + private Validator validator; + @Resource private MpAutoReplyMapper mpAutoReplyMapper; @@ -49,6 +61,96 @@ public class MpAutoReplyServiceImpl implements MpAutoReplyService { return mpAutoReplyMapper.selectById(id); } + @Override + public Long createAutoReply(MpAutoReplyCreateReqVO createReqVO) { + // 第一步,校验数据 + if (createReqVO.getResponseMessageType() != null) { + MpUtils.validateMessage(validator, createReqVO.getResponseMessageType(), createReqVO); + } + validateAutoReplyConflict(null, createReqVO.getAccountId(), createReqVO.getType(), + createReqVO.getRequestKeyword(), createReqVO.getRequestMessageType()); + + // 第二步,插入数据 + MpAccountDO account = mpAccountService.getRequiredAccount(createReqVO.getAccountId()); + MpAutoReplyDO autoReply = MpAutoReplyConvert.INSTANCE.convert(createReqVO) + .setAppId(account.getAppId()); + mpAutoReplyMapper.insert(autoReply); + return autoReply.getId(); + } + + @Override + public void updateAutoReply(MpAutoReplyUpdateReqVO updateReqVO) { + // 第一步,校验数据 + if (updateReqVO.getResponseMessageType() != null) { + MpUtils.validateMessage(validator, updateReqVO.getResponseMessageType(), updateReqVO); + } + MpAutoReplyDO autoReply = validateAutoReplyExists(updateReqVO.getId()); + validateAutoReplyConflict(updateReqVO.getId(), autoReply.getAccountId(), updateReqVO.getType(), + updateReqVO.getRequestKeyword(), updateReqVO.getRequestMessageType()); + + // 第二步,更新数据 + MpAutoReplyDO updateObj = MpAutoReplyConvert.INSTANCE.convert(updateReqVO) + .setAccountId(null).setAppId(null); // 避免前端传递,更新着两个字段 + mpAutoReplyMapper.updateById(updateObj); + } + + /** + * 校验自动回复是否冲突 + * + * 不同的 type,会有不同的逻辑: + * 1. type = SUBSCRIBE 时,不允许有其他的自动回复 + * 2. type = MESSAGE 时,校验 requestMessageType 已经存在自动回复 + * 3. type = KEYWORD 时,校验 keyword 已经存在自动回复 + * + * @param id 自动回复编号 + * @param accountId 公众号账号的编号 + * @param type 类型 + * @param requestKeyword 请求关键词 + * @param requestMessageType 请求消息类型 + */ + private void validateAutoReplyConflict(Long id, Long accountId, Integer type, + String requestKeyword, String requestMessageType) { + // 获得已经存在的自动回复 + MpAutoReplyDO autoReply = null; + ErrorCode errorCode = null; + if (MpAutoReplyTypeEnum.SUBSCRIBE.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndSubscribe(accountId); + errorCode = AUTO_REPLY_ADD_SUBSCRIBE_FAIL_EXISTS; + } else if (MpAutoReplyTypeEnum.MESSAGE.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndMessage(accountId, requestMessageType); + errorCode = AUTO_REPLY_ADD_MESSAGE_FAIL_EXISTS; + } else if (MpAutoReplyTypeEnum.KEYWORD.getType().equals(type)) { + autoReply = mpAutoReplyMapper.selectByAccountIdAndKeyword(accountId, requestKeyword); + errorCode = AUTO_REPLY_ADD_KEYWORD_FAIL_EXISTS; + } + if (autoReply == null) { + return; + } + + // 存在冲突,抛出业务异常 + if (id == null // 情况一,新增(id == null),存在记录,说明冲突 + || ObjUtil.notEqual(id, autoReply.getId())) { // 情况二,修改(id != null),id 不匹配,说明冲突 + throw exception(errorCode); + } + } + + @Override + public void deleteAutoReply(Long id) { + // 校验用户存在 + validateAutoReplyExists(id); + + // 删除自动回复 + mpAutoReplyMapper.deleteById(id); + } + + private MpAutoReplyDO validateAutoReplyExists(Long id) { + MpAutoReplyDO autoReply = mpAutoReplyMapper.selectById(id); + if (autoReply == null) { + throw exception(AUTO_REPLY_NOT_EXISTS); + } + return autoReply; + } + @Override public WxMpXmlOutMessage replyForMessage(String appId, WxMpXmlMessage wxMessage) { // 第一步,匹配自动回复 diff --git a/yudao-ui-admin/src/views/mp/autoReply/index.vue b/yudao-ui-admin/src/views/mp/autoReply/index.vue index 586b1db23..9314011b8 100644 --- a/yudao-ui-admin/src/views/mp/autoReply/index.vue +++ b/yudao-ui-admin/src/views/mp/autoReply/index.vue @@ -96,33 +96,35 @@ SOFTWARE. 关键词回复 - - - - - - - - - - - - - + + + + + + + + + + + + + + +