From 3ceb4d4685712b80d6643304adb895b3ca1ecf03 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 1 Aug 2024 13:08:35 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E3=80=90=E5=8A=9F=E8=83=BD=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E3=80=91=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E7=9A=84=E8=AE=A2=E9=98=85=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iocoder/yudao/framework/ip/core/Area.java | 3 +- .../framework/test/core/util/RandomUtils.java | 4 ++ .../admin/image/AiImageController.java | 3 +- .../admin/image/vo/AiImagePageReqVO.java | 5 +- .../ai/dal/mysql/image/AiImageMapper.java | 13 ++-- .../ai/service/image/AiImageService.java | 3 +- .../ai/service/image/AiImageServiceImpl.java | 5 +- .../service/mindmap/AiMindMapServiceImpl.java | 2 +- .../ai/service/write/AiWriteServiceImpl.java | 2 +- .../ProductBrowseHistoryController.java | 20 +++++- .../vo/ProductBrowseHistoryRespVO.java | 28 ++++---- .../service/spu/ProductSpuService.java | 12 ++++ .../enums/MessageTemplateConstants.java | 14 ++++ .../rpc/config/RpcConfiguration.java | 3 +- .../CombinationRecordServiceImpl.java | 29 +++++++- .../trade/enums/MessageTemplateConstants.java | 13 ++-- .../rpc/config/RpcConfiguration.java | 3 +- .../aftersale/AfterSaleServiceImpl.java | 2 + .../BrokerageWithdrawServiceImpl.java | 4 +- .../message/TradeMessageServiceImpl.java | 2 +- .../order/TradeOrderUpdateServiceImpl.java | 27 ++++++- .../handler/TradeCombinationOrderHandler.java | 3 + .../app/social/AppSocialUserController.java | 21 +++--- ...eqVO.java => AppSocialWxaQrcodeReqVO.java} | 2 +- .../AppSocialWxaSubscribeTemplateRespVO.java | 27 +++++++ .../pay/enums/MessageTemplateConstants.java | 14 ++++ .../rpc/config/RpcConfiguration.java | 3 + .../wallet/PayWalletRechargeServiceImpl.java | 38 +++++++++- .../system/api/social/SocialClientApi.java | 19 +++-- .../SocialWxaSubscribeMessageSendReqDTO.java | 43 +++++++++++ .../SocialWxaSubscribeTemplateRespDTO.java | 25 +++++++ .../system/enums/ErrorCodeConstants.java | 6 +- .../api/social/SocialClientApiImpl.java | 53 +++++++++++++- .../admin/socail/SocialClientController.http | 20 ++++++ .../admin/socail/SocialClientController.java | 16 ++++- .../system/dal/redis/RedisKeyConstants.java | 9 +++ .../service/social/SocialClientService.java | 23 ++++++ .../social/SocialClientServiceImpl.java | 72 ++++++++++++++++++- .../service/user/AdminUserServiceImpl.java | 18 +++-- .../src/main/resources/application-local.yaml | 6 +- .../user/AdminUserServiceImplTest.java | 13 ++-- 41 files changed, 548 insertions(+), 80 deletions(-) create mode 100644 yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/MessageTemplateConstants.java rename yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/{AppSocialWxQrcodeReqVO.java => AppSocialWxaQrcodeReqVO.java} (97%) create mode 100644 yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaSubscribeTemplateRespVO.java create mode 100644 yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http diff --git a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java index 262bc263c..302708587 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-ip/src/main/java/cn/iocoder/yudao/framework/ip/core/Area.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.ip.core; import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonManagedReference; import lombok.AllArgsConstructor; import lombok.Data; @@ -54,7 +55,7 @@ public class Area { /** * 子节点 */ - @JsonManagedReference + @JsonBackReference private List children; } diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java index 66d15c5bf..095269751 100644 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java @@ -103,6 +103,10 @@ public class RandomUtils { return randomString() + "@qq.com"; } + public static String randomMobile() { + return "13800138" + RandomUtil.randomNumbers(3); + } + public static String randomURL() { return "https://www.iocoder.cn/" + randomString(); } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java index de12ee1e0..fd3cdf786 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/AiImageController.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.ai.controller.admin.image; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; 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.module.ai.controller.admin.image.vo.AiImageDrawReqVO; @@ -41,7 +40,7 @@ public class AiImageController { @GetMapping("/my-page") @Operation(summary = "获取【我的】绘图分页") - public CommonResult> getImagePageMy(@Validated PageParam pageReqVO) { + public CommonResult> getImagePageMy(@Validated AiImagePageReqVO pageReqVO) { PageResult pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO); return success(BeanUtils.toBean(pageResult, AiImageRespVO.class)); } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageReqVO.java index bdf329c61..3b48686b9 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/image/vo/AiImagePageReqVO.java @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.ai.controller.admin.image.vo; import cn.iocoder.yudao.framework.common.pojo.PageParam; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; @@ -21,6 +19,9 @@ public class AiImagePageReqVO extends PageParam { @Schema(description = "平台", example = "OpenAI") private String platform; + @Schema(description = "提示词", example = "1") + private String prompt; + @Schema(description = "绘画状态", example = "1") private Integer status; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java index fd6e4b398..847a5c204 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/image/AiImageMapper.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.ai.dal.mysql.image; -import cn.iocoder.yudao.framework.common.pojo.PageParam; 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; @@ -19,7 +18,7 @@ import java.util.List; public interface AiImageMapper extends BaseMapperX { default AiImageDO selectByTaskId(String taskId) { - return this.selectOne(AiImageDO::getTaskId, taskId); + return selectOne(AiImageDO::getTaskId, taskId); } default PageResult selectPage(AiImagePageReqVO reqVO) { @@ -32,9 +31,13 @@ public interface AiImageMapper extends BaseMapperX { .orderByDesc(AiImageDO::getId)); } - default PageResult selectPage(Long userId, PageParam pageReqVO) { - return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(AiImageDO::getUserId, userId) + default PageResult selectPageMy(Long userId, AiImagePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(AiImageDO::getPrompt, reqVO.getPrompt()) + // 情况一:公开 + .eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiImageDO::getPublicStatus, reqVO.getPublicStatus()) + // 情况二:私有 + .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiImageDO::getUserId, userId) .orderByDesc(AiImageDO::getId)); } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java index 716c7ea8a..b4d76b315 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageService.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.ai.service.image; import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO; import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO; @@ -27,7 +26,7 @@ public interface AiImageService { * @param pageReqVO 分页条件 * @return 绘图分页 */ - PageResult getImagePageMy(Long userId, PageParam pageReqVO); + PageResult getImagePageMy(Long userId, AiImagePageReqVO pageReqVO); /** * 获得绘图记录 diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java index 3a8ff8346..020546ae9 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/image/AiImageServiceImpl.java @@ -10,7 +10,6 @@ import cn.hutool.extra.spring.SpringUtil; import cn.hutool.http.HttpUtil; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; -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.module.ai.controller.admin.image.vo.AiImageDrawReqVO; @@ -67,8 +66,8 @@ public class AiImageServiceImpl implements AiImageService { private AiApiKeyService apiKeyService; @Override - public PageResult getImagePageMy(Long userId, PageParam pageReqVO) { - return imageMapper.selectPage(userId, pageReqVO); + public PageResult getImagePageMy(Long userId, AiImagePageReqVO pageReqVO) { + return imageMapper.selectPageMy(userId, pageReqVO); } @Override diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java index 72be20c54..df5296df2 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/mindmap/AiMindMapServiceImpl.java @@ -124,7 +124,7 @@ public class AiMindMapServiceImpl implements AiMindMapService { if (role != null && role.getModelId() != null) { model = chatModalService.getChatModel(role.getModelId()); } - if (model != null) { + if (model == null) { model = chatModalService.getRequiredDefaultChatModel(); } Assert.notNull(model, "[AI] 获取不到模型"); diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java index 2fae31d59..b8f22a2fa 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java @@ -114,7 +114,7 @@ public class AiWriteServiceImpl implements AiWriteService { if (Objects.nonNull(writeRole) && Objects.nonNull(writeRole.getModelId())) { model = chatModalService.getChatModel(writeRole.getModelId()); } - if (Objects.isNull(model)) { + if (model == null) { model = chatModalService.getRequiredDefaultChatModel(); } Assert.notNull(model, "[AI] 获取不到模型"); diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java index b87e4ee44..0b9e6a13b 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java @@ -1,12 +1,15 @@ package cn.iocoder.yudao.module.product.controller.admin.history; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryPageReqVO; import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.history.ProductBrowseHistoryDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; @@ -17,7 +20,11 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.Map; +import java.util.Optional; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Tag(name = "管理后台 - 商品浏览记录") @RestController @@ -27,13 +34,24 @@ public class ProductBrowseHistoryController { @Resource private ProductBrowseHistoryService browseHistoryService; + @Resource + private ProductSpuService productSpuService; @GetMapping("/page") @Operation(summary = "获得商品浏览记录分页") @PreAuthorize("@ss.hasPermission('product:browse-history:query')") public CommonResult> getBrowseHistoryPage(@Valid ProductBrowseHistoryPageReqVO pageReqVO) { PageResult pageResult = browseHistoryService.getBrowseHistoryPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, ProductBrowseHistoryRespVO.class)); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); + } + + // 得到商品 spu 信息 + Map spuMap = productSpuService.getSpuMap( + convertSet(pageResult.getList(), ProductBrowseHistoryDO::getSpuId)); + return success(BeanUtils.toBean(pageResult, ProductBrowseHistoryRespVO.class, + vo -> Optional.ofNullable(spuMap.get(vo.getSpuId())) + .ifPresent(spu -> vo.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setPrice(spu.getPrice())))); } } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java index 0e2e0cbed..012f1602c 100644 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/vo/ProductBrowseHistoryRespVO.java @@ -7,28 +7,28 @@ import lombok.Data; import java.time.LocalDateTime; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + @Schema(description = "管理后台 - 商品浏览记录 Response VO") @Data @ExcelIgnoreUnannotated public class ProductBrowseHistoryRespVO { - @Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26055") - @ExcelProperty("记录编号") + @Schema(description = "编号", requiredMode = REQUIRED, example = "1") private Long id; - @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4314") - @ExcelProperty("用户编号") - private Long userId; - - @Schema(description = "用户是否删除", example = "false") - private Boolean userDeleted; - - @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "42") - @ExcelProperty("商品 SPU 编号") + @Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502") private Long spuId; - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - @ExcelProperty("创建时间") - private LocalDateTime createTime; + // ========== 商品相关字段 ========== + + @Schema(description = "商品 SPU 名称", example = "赵六") + private String spuName; + + @Schema(description = "商品封面图", example = "https://domain/pic.png") + private String picUrl; + + @Schema(description = "商品单价", example = "100") + private Integer price; } \ No newline at end of file diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index c288a76ca..d7403c159 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.product.service.spu; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO; @@ -58,6 +59,17 @@ public interface ProductSpuService { */ List getSpuList(Collection ids); + /** + * 获得商品 SPU Map + * + * @param ids 编号数组 + * @return 商品 SPU Map + */ + default Map getSpuMap(Collection ids) { + List list = getSpuList(ids); + return CollectionUtils.convertMap(list, ProductSpuDO::getId); + } + /** * 获得指定状态的商品 SPU 列表 * diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/MessageTemplateConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/MessageTemplateConstants.java new file mode 100644 index 000000000..9a6bdd41d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/MessageTemplateConstants.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.promotion.enums; + +/** + * 通知模板枚举类 + * + * @author HUIHUI + */ +public interface MessageTemplateConstants { + + //======================= 小程序订阅消息模版 ======================= + + String COMBINATION_SUCCESS = "拼团结果通知"; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/rpc/config/RpcConfiguration.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/rpc/config/RpcConfiguration.java index 69ce32dda..b94275ba6 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/framework/rpc/config/RpcConfiguration.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi; import cn.iocoder.yudao.module.product.api.category.ProductCategoryApi; import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; import org.springframework.cloud.openfeign.EnableFeignClients; @@ -12,7 +13,7 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableFeignClients(clients = {ProductSkuApi.class, ProductSpuApi.class, ProductCategoryApi.class, - MemberUserApi.class, TradeOrderApi.class, AdminUserApi.class, + MemberUserApi.class, TradeOrderApi.class, AdminUserApi.class, SocialClientApi.class, WebSocketSenderApi.class}) public class RpcConfiguration { } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java index aae868e5a..320021991 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/combination/CombinationRecordServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.member.api.user.MemberUserApi; @@ -23,11 +24,14 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationP import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper; import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi; import jakarta.annotation.Nullable; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -40,6 +44,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.afterNow; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.beforeNow; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.promotion.enums.MessageTemplateConstants.COMBINATION_SUCCESS; // TODO 芋艿:等拼团记录做完,完整 review 下 @@ -66,8 +71,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { private ProductSkuApi productSkuApi; @Resource - @Lazy + @Lazy // 延迟加载,避免循环依赖 private TradeOrderApi tradeOrderApi; + @Resource + public SocialClientApi socialClientApi; // TODO @芋艿:在详细预览下; @Override @@ -205,7 +212,25 @@ public class CombinationRecordServiceImpl implements CombinationRecordService { } updateRecords.add(updateRecord); }); - combinationRecordMapper.updateBatch(updateRecords); + Boolean updateSuccess = combinationRecordMapper.updateBatch(updateRecords); + + // 3. 拼团成功发送订阅消息 + if (updateSuccess && isFull) { + records.forEach(item -> { + getSelf().sendCombinationResultMessage(item); + }); + } + } + + @Async + public void sendCombinationResultMessage(CombinationRecordDO record) { + // 构建并发送模版消息 + socialClientApi.sendWxaSubscribeMessage(new SocialWxaSubscribeMessageSendReqDTO() + .setUserId(record.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue()) + .setTemplateTitle(COMBINATION_SUCCESS) + .setPage("pages/order/detail?id=" + record.getOrderId()) // 订单详情页 + .addMessage("thing1", "商品拼团活动") // 活动标题 + .addMessage("thing2", "恭喜您拼团成功!我们将尽快为您发货。")); // 温馨提示 } @Override diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java index 5041139b4..56c4c9005 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/MessageTemplateConstants.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.trade.enums; -// TODO @芋艿:枚举 /** * 通知模板枚举类 * @@ -8,9 +7,15 @@ package cn.iocoder.yudao.module.trade.enums; */ public interface MessageTemplateConstants { - String ORDER_DELIVERY = "order_delivery"; // 短信模版编号 + // ======================= 短信消息模版 ======================= - String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过) - String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过) + String SMS_ORDER_DELIVERY = "order_delivery"; // 短信模版编号 + + String SMS_BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过) + String SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过) + + // ======================= 小程序订阅消息模版 ======================= + + String WXA_ORDER_DELIVERY = "订单发货通知"; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/rpc/config/RpcConfiguration.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/rpc/config/RpcConfiguration.java index 2e795cb54..f51be2735 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/framework/rpc/config/RpcConfiguration.java @@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; @@ -29,7 +30,7 @@ import org.springframework.context.annotation.Configuration; MemberUserApi.class, MemberPointApi.class, MemberLevelApi.class, MemberAddressApi.class, MemberConfigApi.class, ProductSpuApi.class, ProductSkuApi.class, ProductCommentApi.class, ProductCategoryApi.class, PayOrderApi.class, PayRefundApi.class, - NotifyMessageSendApi.class + NotifyMessageSendApi.class, SocialClientApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java index 4c1fea1da..0743350de 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/AfterSaleServiceImpl.java @@ -33,6 +33,7 @@ import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; @@ -56,6 +57,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; public class AfterSaleServiceImpl implements AfterSaleService { @Resource + @Lazy // 延迟加载,避免循环依赖 private TradeOrderUpdateService tradeOrderUpdateService; @Resource private TradeOrderQueryService tradeOrderQueryService; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java index 0560c33d8..c735163a5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java @@ -77,14 +77,14 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService { String templateCode; if (BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.equals(status)) { - templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE; + templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_APPROVE; // 3.1 通过时佣金转余额 if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) { // todo 疯狂: } // TODO 疯狂:调用转账接口 } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) { - templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT; + templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT; // 3.2 驳回时需要退还用户佣金 brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT, String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle()); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java index eefd26c6e..a06c06906 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/message/TradeMessageServiceImpl.java @@ -37,7 +37,7 @@ public class TradeMessageServiceImpl implements TradeMessageService { notifyMessageSendApi.sendSingleMessageToMember( new NotifySendSingleToUserReqDTO() .setUserId(reqBO.getUserId()) - .setTemplateCode(MessageTemplateConstants.ORDER_DELIVERY) + .setTemplateCode(MessageTemplateConstants.SMS_ORDER_DELIVERY) .setTemplateParams(msgMap)); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java index ff25b7690..5aec74ce2 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderUpdateServiceImpl.java @@ -1,11 +1,13 @@ package cn.iocoder.yudao.module.trade.service.order; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.core.KeyValue; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; @@ -19,6 +21,8 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi; import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO; import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO; @@ -52,6 +56,7 @@ import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculat import jakarta.annotation.Resource; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -67,6 +72,7 @@ import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.min import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal; import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants.WXA_ORDER_DELIVERY; /** * 交易订单【写】Service 实现类 @@ -103,6 +109,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { private MemberAddressApi addressApi; @Resource private ProductCommentApi productCommentApi; + @Resource + public SocialClientApi socialClientApi; @Resource private TradeOrderProperties tradeOrderProperties; @@ -364,9 +372,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { MapUtil.builder().put("expressName", express != null ? express.getName() : "") .put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build()); - // 4. 发送站内信 + // 4.1 发送站内信 tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO() .setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null)); + // 4.2 发送订阅消息 + getSelf().sendDeliveryOrderMessage(order, deliveryReqVO); + } + + @Async + public void sendDeliveryOrderMessage(TradeOrderDO order, TradeOrderDeliveryReqVO deliveryReqVO) { + // 构建并发送模版消息 + Long orderId = order.getId(); + socialClientApi.sendWxaSubscribeMessage(new SocialWxaSubscribeMessageSendReqDTO() + .setUserId(order.getUserId()).setUserType(UserTypeEnum.MEMBER.getValue()) + .setTemplateTitle(WXA_ORDER_DELIVERY) + .setPage("pages/order/detail?id=" + orderId) // 订单详情页 + .addMessage("character_string3", String.valueOf(orderId)) // 订单编号 + .addMessage("phrase6", TradeOrderStatusEnum.DELIVERED.getName()) // 订单状态 + .addMessage("date4", LocalDateTimeUtil.formatNormal(LocalDateTime.now()))// 发货时间 + .addMessage("character_string5", StrUtil.blankToDefault(deliveryReqVO.getLogisticsNo(), "-")) // 快递单号 + .addMessage("thing9", order.getReceiverDetailAddress())); // 收货地址 } /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java index 86963d589..329dcbbaf 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeCombinationOrderHandler.java @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService; import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import jakarta.annotation.Resource; @@ -28,11 +29,13 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_DELIV public class TradeCombinationOrderHandler implements TradeOrderHandler { @Resource + @Lazy // 延迟加载,避免循环依赖 private TradeOrderUpdateService orderUpdateService; @Resource private TradeOrderQueryService orderQueryService; @Resource + @Lazy // 延迟加载,避免循环依赖 private CombinationRecordApi combinationRecordApi; @Override diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java index a40b553cc..19910e54c 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java @@ -5,16 +5,10 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserBindReqVO; -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserRespVO; -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialUserUnbindReqVO; -import cn.iocoder.yudao.module.member.controller.app.social.vo.AppSocialWxQrcodeReqVO; +import cn.iocoder.yudao.module.member.controller.app.social.vo.*; import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.social.SocialUserApi; -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialUserUnbindReqDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.*; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -23,6 +17,8 @@ import jakarta.validation.Valid; 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; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -67,9 +63,16 @@ public class AppSocialUserController { @PostMapping("/wxa-qrcode") @Operation(summary = "获得微信小程序码(base64 image)") - public CommonResult getWxaQrcode(@RequestBody @Valid AppSocialWxQrcodeReqVO reqVO) { + public CommonResult getWxaQrcode(@RequestBody @Valid AppSocialWxaQrcodeReqVO reqVO) { byte[] wxQrcode = socialClientApi.getWxaQrcode(BeanUtils.toBean(reqVO, SocialWxQrcodeReqDTO.class)).getCheckedData(); return success(Base64.encode(wxQrcode)); } + @GetMapping("/get-subscribe-template-list") + @Operation(summary = "获得微信小程订阅模板列表") + public CommonResult> getSubscribeTemplateList() { + List template = socialClientApi.getWxaSubscribeTemplateList(UserTypeEnum.MEMBER.getValue()).getCheckedData(); + return success(BeanUtils.toBean(template, AppSocialWxaSubscribeTemplateRespVO.class)); + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxQrcodeReqVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaQrcodeReqVO.java similarity index 97% rename from yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxQrcodeReqVO.java rename to yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaQrcodeReqVO.java index 8927a34c9..c12bfd700 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxQrcodeReqVO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaQrcodeReqVO.java @@ -7,7 +7,7 @@ import lombok.Data; @Schema(description = "用户 APP - 获得获取小程序码 Request VO") @Data -public class AppSocialWxQrcodeReqVO { +public class AppSocialWxaQrcodeReqVO { /** * 页面路径不能携带参数(参数请放在scene字段里) diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaSubscribeTemplateRespVO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaSubscribeTemplateRespVO.java new file mode 100644 index 000000000..445122d3f --- /dev/null +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/vo/AppSocialWxaSubscribeTemplateRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.member.controller.app.social.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "用户 APP - 获得小程序订阅模版 Response VO") +@Data +public class AppSocialWxaSubscribeTemplateRespVO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, + example = "9Aw5ZV1j9xdWTFEkqCpZ7mIBbSC34khK55OtzUPl0rU") + private String id; + + @Schema(description = "模版标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单支付通知") + private String title; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, + example = "{ {result.DATA} }\\n\\n领奖金额:{ {withdrawMoney.DATA} }\\n领奖时间: { {withdrawTime.DATA} }") + private String content; + + @Schema(description = "模板内容示例", requiredMode = Schema.RequiredMode.REQUIRED, example = "下单时间:2016年8月8日") + private String example; + + @Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; // 2 为一次性订阅,3 为长期订阅 + +} diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java new file mode 100644 index 000000000..9497d776b --- /dev/null +++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/MessageTemplateConstants.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.pay.enums; + +/** + * 通知模板枚举类 + * + * @author HUIHUI + */ +public interface MessageTemplateConstants { + + // ======================= 小程序订阅消息 ======================= + + String WXA_WALLET_RECHARGER_PAID = "充值成功通知"; + +} diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/rpc/config/RpcConfiguration.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/rpc/config/RpcConfiguration.java index ce59fac18..8d596cda4 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/rpc/config/RpcConfiguration.java @@ -1,7 +1,10 @@ package cn.iocoder.yudao.module.pay.framework.rpc.config; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) +@EnableFeignClients(clients = {SocialClientApi.class}) public class RpcConfiguration { } diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java index fd4b19e56..94c9fa611 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.pay.service.wallet; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; +import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum; @@ -18,8 +20,11 @@ import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum; import cn.iocoder.yudao.module.pay.service.order.PayOrderService; import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,8 +36,10 @@ import static cn.hutool.core.util.ObjectUtil.notEqual; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; +import static cn.iocoder.yudao.framework.common.util.number.MoneyUtils.fenToYuanStr; import static cn.iocoder.yudao.module.pay.convert.wallet.PayWalletRechargeConvert.INSTANCE; import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.pay.enums.MessageTemplateConstants.WXA_WALLET_RECHARGER_PAID; import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*; /** @@ -61,6 +68,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { private PayRefundService payRefundService; @Resource private PayWalletRechargePackageService payWalletRechargePackageService; + @Resource + public SocialClientApi socialClientApi; @Override @Transactional(rollbackFor = Exception.class) @@ -96,7 +105,7 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { @Override public PageResult getWalletRechargePackagePage(Long userId, Integer userType, - PageParam pageReqVO, Boolean payStatus) { + PageParam pageReqVO, Boolean payStatus) { PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType); return walletRechargeMapper.selectPage(pageReqVO, wallet.getId(), payStatus); } @@ -126,6 +135,24 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { // TODO 需要钱包中加个可提现余额 payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(id), PayWalletBizTypeEnum.RECHARGE, walletRecharge.getTotalPrice()); + + // 4. 发送订阅消息 + getSelf().sendWalletRechargerPaidMessage(payOrderId, walletRecharge); + } + + @Async + public void sendWalletRechargerPaidMessage(Long payOrderId, PayWalletRechargeDO walletRecharge) { + // 1. 获得会员钱包信息 + PayWalletDO wallet = payWalletService.getWallet(walletRecharge.getWalletId()); + // 2. 构建并发送模版消息 + socialClientApi.sendWxaSubscribeMessage(new SocialWxaSubscribeMessageSendReqDTO() + .setUserId(wallet.getUserId()).setUserType(wallet.getUserType()) + .setTemplateTitle(WXA_WALLET_RECHARGER_PAID) + .setPage("pages/user/wallet/money") // 钱包详情界面 + .addMessage("character_string1", String.valueOf(payOrderId)) // 支付单编号 + .addMessage("amount2", fenToYuanStr(walletRecharge.getTotalPrice())) // 充值金额 + .addMessage("time3", LocalDateTimeUtil.formatNormal(walletRecharge.getCreateTime())) // 充值时间 + .addMessage("phrase4", "充值成功")); // 充值状态 } @Override @@ -282,4 +309,13 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService { return payOrder; } + /** + * 获得自身的代理对象,解决 AOP 生效问题 + * + * @return 自己 + */ + private PayWalletRechargeServiceImpl getSelf() { + return SpringUtil.getBean(getClass()); + } + } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java index 528c64308..f70c1993b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java @@ -1,9 +1,7 @@ package cn.iocoder.yudao.module.system.api.social; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.*; import cn.iocoder.yudao.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -11,9 +9,14 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.cloud.openfeign.SpringQueryMap; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import java.util.List; + @FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - 社交应用") public interface SocialClientApi { @@ -51,6 +54,14 @@ public interface SocialClientApi { @GetMapping(PREFIX + "/get-wxa-qrcode") @Operation(summary = "获得小程序二维码") - CommonResult getWxaQrcode(@Valid SocialWxQrcodeReqDTO reqVO); + CommonResult getWxaQrcode(@SpringQueryMap SocialWxQrcodeReqDTO reqVO); + + @GetMapping(PREFIX + "/get-wxa-subscribe-template-list") + @Operation(summary = "获得微信小程订阅模板") + CommonResult> getWxaSubscribeTemplateList(@RequestParam("userType") Integer userType); + + @PostMapping(PREFIX + "/send-wxa-subscribe-message") + @Operation(summary = "发送微信小程序订阅消息") + CommonResult sendWxaSubscribeMessage(@Valid @RequestBody SocialWxaSubscribeMessageSendReqDTO reqDTO); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java new file mode 100644 index 000000000..5f3491c53 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeMessageSendReqDTO.java @@ -0,0 +1,43 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Schema(description = "RPC 服务 - 微信小程序订阅消息发送 Request DTO") +@Data +public class SocialWxaSubscribeMessageSendReqDTO { + + @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "用户编号不能为空") + private Long userId; + @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @InEnum(UserTypeEnum.class) + @NotNull(message = "用户类型不能为空") + private Integer userType; + + @Schema(description = "消息模版标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版标题") + @NotEmpty(message = "消息模版标题不能为空") + private String templateTitle; + + @Schema(description = "点击模板卡片后的跳转页面,仅限本小程序内的页面", example = "pages/index?foo=bar") + private String page; // 支持带参数,(示例 index?foo=bar )。该字段不填则模板无跳转。 + + @Schema(description = "模板内容的参数") + private Map messages; + + public SocialWxaSubscribeMessageSendReqDTO addMessage(String key, String value) { + if (messages == null) { + messages = new HashMap<>(); + } + messages.put(key, value); + return this; + } + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java new file mode 100644 index 000000000..32274cccf --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialWxaSubscribeTemplateRespDTO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.api.social.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "RPC 服务 - 小程序订阅消息模版 Response DTO") +@Data +public class SocialWxaSubscribeTemplateRespDTO { + + @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private String id; + + @Schema(description = "模版标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版标题") + private String title; + + @Schema(description = "模版内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版内容") + private String content; + + @Schema(description = "模板内容示例", requiredMode = Schema.RequiredMode.REQUIRED, example = "模版内容示例") + private String example; + + @Schema(description = "模版类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Integer type; // 2:为一次性订阅;3:为长期订阅 + +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index 585308dd6..e360a426b 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -117,8 +117,10 @@ public interface ErrorCodeConstants { ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1_002_018_200, "获得手机号失败"); ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR = new ErrorCode(1_002_018_201, "获得小程序码失败"); - ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_202, "社交客户端不存在"); - ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_203, "社交客户端已存在配置"); + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败"); + ErrorCode SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR = new ErrorCode(1_002_018_203, "发送小程序订阅消息失败"); + ErrorCode SOCIAL_CLIENT_NOT_EXISTS = new ErrorCode(1_002_018_210, "社交客户端不存在"); + ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_211, "社交客户端已存在配置"); // ========== OAuth2 客户端 1-002-020-000 ========= diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java index 1bb5fbaed..17da0ef08 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApiImpl.java @@ -1,19 +1,28 @@ package cn.iocoder.yudao.module.system.api.social; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxJsapiSignatureRespDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO; -import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.*; +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import cn.iocoder.yudao.module.system.service.social.SocialClientService; +import cn.iocoder.yudao.module.system.service.social.SocialUserService; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; import jakarta.annotation.Resource; +import java.util.List; + +import static cn.hutool.core.collection.CollUtil.findOne; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; /** * 社交应用的 API 实现类 @@ -22,10 +31,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; */ @RestController @Validated +@Slf4j public class SocialClientApiImpl implements SocialClientApi { @Resource private SocialClientService socialClientService; + @Resource + private SocialUserService socialUserService; @Override public CommonResult getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) { @@ -49,4 +61,39 @@ public class SocialClientApiImpl implements SocialClientApi { return success(socialClientService.getWxaQrcode(reqVO)); } + @Override + public CommonResult> getWxaSubscribeTemplateList(Integer userType) { + List list = socialClientService.getSubscribeTemplateList(userType); + return success(convertList(list, item -> BeanUtils.toBean(item, SocialWxaSubscribeTemplateRespDTO.class).setId(item.getPriTmplId()))); + } + + @Override + public CommonResult sendWxaSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO) { + // 1.1 获得订阅模版列表 + List templateList = socialClientService.getSubscribeTemplateList(reqDTO.getUserType()); + if (CollUtil.isEmpty(templateList)) { + log.warn("[sendSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return success(false); + } + // 1.2 获得需要使用的模版 + TemplateInfo template = findOne(templateList, item -> + ObjUtil.equal(item.getTitle(), reqDTO.getTemplateTitle())); + if (template == null) { + log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:没有找到订阅模板]", reqDTO); + return success(false); + } + + // 2. 获得社交用户 + SocialUserRespDTO socialUser = socialUserService.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(), + SocialTypeEnum.WECHAT_MINI_APP.getType()); + if (StrUtil.isBlankIfStr(socialUser.getOpenid())) { + log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO); + return success(false); + } + + // 3. 发送订阅消息 + socialClientService.sendSubscribeMessage(reqDTO, template.getPriTmplId(), socialUser.getOpenid()); + return success(true); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http new file mode 100644 index 000000000..5ab64392a --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.http @@ -0,0 +1,20 @@ +### 请求 /system/social-client/send-subscribe-message 接口 => 发送测试订阅消息 +POST {{baseUrl}}/system/social-client/send-subscribe-message +Authorization: Bearer {{token}} +Content-Type: application/json +#Authorization: Bearer test100 +tenant-id: {{adminTenentId}} + +{ + "userId": 247, + "userType": 1, + "socialType": 34, + "templateTitle": "充值成功通知", + "page": "", + "messages": { + "character_string1":"5616122165165", + "amount2":"1000.00", + "time3":"2024-01-01 10:10:10", + "phrase4": "充值成功" + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java index a029ca29b..e91a3d8a0 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.system.controller.admin.socail; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.social.SocialClientApi; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; @@ -11,13 +13,12 @@ import cn.iocoder.yudao.module.system.service.social.SocialClientService; 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 jakarta.annotation.Resource; -import jakarta.validation.Valid; - import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Tag(name = "管理后台 - 社交客户端") @@ -28,6 +29,8 @@ public class SocialClientController { @Resource private SocialClientService socialClientService; + @Resource + private SocialClientApi socialClientApi; @PostMapping("/create") @Operation(summary = "创建社交客户端") @@ -70,4 +73,11 @@ public class SocialClientController { return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class)); } + @PostMapping("/send-subscribe-message") + @Operation(summary = "发送订阅消息") // 用于测试 + @PreAuthorize("@ss.hasPermission('system:social-client:query')") + public void sendSubscribeMessage(@RequestBody SocialWxaSubscribeMessageSendReqDTO reqDTO) { + socialClientApi.sendWxaSubscribeMessage(reqDTO); + } + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java index 4964a2be2..1cd58306b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java @@ -98,4 +98,13 @@ public interface RedisKeyConstants { * VALUE 数据格式:String 模版信息 */ String SMS_TEMPLATE = "sms_template"; + + /** + * 小程序订阅模版的缓存 + * + * KEY 格式:wxa_subscribe_template:{userType} + * VALUE 数据格式 String, 模版信息 + */ + String WXA_SUBSCRIBE_TEMPLATE = "wxa_subscribe_template"; + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java index 7757d35d1..5b293c41c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientService.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.social; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; @@ -10,6 +11,9 @@ import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import com.xingyuv.jushauth.model.AuthUser; import jakarta.validation.Valid; import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; + +import java.util.List; /** * 社交应用 Service 接口 @@ -69,6 +73,25 @@ public interface SocialClientService { */ byte[] getWxaQrcode(SocialWxQrcodeReqDTO reqVO); + /** + * 获得微信小程订阅模板 + * + * 缓存的目的:考虑到微信小程序订阅消息选择好模版后几乎不会变动,缓存增加查询效率 + * + * @param userType 用户类型 + * @return 微信小程订阅模板 + */ + List getSubscribeTemplateList(Integer userType); + + /** + * 发送微信小程序订阅消息 + * + * @param reqDTO 请求 + * @param templateId 模版编号 + * @param openId 会员 openId + */ + void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId); + // =================== 客户端管理 =================== /** diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java index 37b1f0bc4..ba86165c3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialClientServiceImpl.java @@ -1,10 +1,14 @@ package cn.iocoder.yudao.module.system.service.social; import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.WxMaSubscribeService; import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage; import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl; +import cn.binarywang.wx.miniapp.constant.WxMaConstants; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ReflectUtil; @@ -15,10 +19,12 @@ import cn.iocoder.yudao.framework.common.util.cache.CacheUtils; import cn.iocoder.yudao.framework.common.util.http.HttpUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO; +import cn.iocoder.yudao.module.system.api.social.dto.SocialWxaSubscribeMessageSendReqDTO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialClientDO; import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum; import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties; import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties; @@ -36,22 +42,26 @@ import jakarta.annotation.Resource; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.bean.WxJsapiSignature; +import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import java.time.Duration; +import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR; /** * 社交应用 Service 实现类 @@ -63,7 +73,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLI public class SocialClientServiceImpl implements SocialClientService { /** - * 小程序版本 + * 小程序码要打开的小程序版本 * * 1. release:正式版 * 2. trial:体验版 @@ -71,6 +81,15 @@ public class SocialClientServiceImpl implements SocialClientService { */ @Value("${yudao.wxa-code.env-version:release}") public String envVersion; + /** + * 订阅消息跳转小程序类型 + * + * 1. developer:开发版 + * 2. trial:体验版 + * 3. formal:正式版 + */ + @Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}") + public String miniprogramState; @Resource private AuthRequestFactory authRequestFactory; @@ -255,11 +274,58 @@ public class SocialClientServiceImpl implements SocialClientService { null, ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE)); } catch (WxErrorException e) { - log.error("[getWxQrcode][reqVO({})) 获得小程序码失败]", reqVO, e); + log.error("[getWxQrcode][reqVO({}) 获得小程序码失败]", reqVO, e); throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR); } } + @Override + @Cacheable(cacheNames = RedisKeyConstants.WXA_SUBSCRIBE_TEMPLATE, key = "#userType", condition = "#result != null") + public List getSubscribeTemplateList(Integer userType) { + WxMaService service = getWxMaService(userType); + try { + WxMaSubscribeService subscribeService = service.getSubscribeService(); + return subscribeService.getTemplateList(); + } catch (WxErrorException e) { + log.error("[getSubscribeTemplate][userType({}) 获得小程序订阅消息模版]", userType, e); + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR); + } + } + + @Override + public void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId) { + WxMaService service = getWxMaService(reqDTO.getUserType()); + try { + WxMaSubscribeService subscribeService = service.getSubscribeService(); + subscribeService.sendSubscribeMsg(buildMessageSendReqDTO(reqDTO, templateId, openId)); + } catch (WxErrorException e) { + log.error("[sendSubscribeMessage][reqVO({}) templateId({}) openId({}) 发送小程序订阅消息失败]", reqDTO, templateId, openId, e); + throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_SUBSCRIBE_MESSAGE_ERROR); + } + } + + /** + * 构建发送消息请求参数 + * + * @param reqDTO 请求 + * @param templateId 模版编号 + * @param openId 会员 openId + * @return 微信小程序订阅消息请求参数 + */ + private WxMaSubscribeMessage buildMessageSendReqDTO(SocialWxaSubscribeMessageSendReqDTO reqDTO, + String templateId, String openId) { + // 设置订阅消息基本参数 + WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage().setLang(WxMaConstants.MiniProgramLang.ZH_CN) + .setMiniprogramState(miniprogramState).setTemplateId(templateId).setToUser(openId).setPage(reqDTO.getPage()); + // 设置具体消息参数 + Map messages = reqDTO.getMessages(); + if (CollUtil.isNotEmpty(messages)) { + reqDTO.getMessages().keySet().forEach(key -> findAndThen(messages, key, value -> + subscribeMessage.addData(new WxMaSubscribeMessage.MsgData(key, value)))); + } + return subscribeMessage; + } + /** * 获得 clientId + clientSecret 对应的 WxMpService 对象 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 7f905c3c0..7b41ea995 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; @@ -32,6 +33,7 @@ import com.mzt.logapi.context.LogRecordContext; import com.mzt.logapi.service.impl.DiffParseFunction; import com.mzt.logapi.starter.annotation.LogRecord; import jakarta.annotation.Resource; +import jakarta.validation.ConstraintViolationException; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.security.crypto.password.PasswordEncoder; @@ -325,7 +327,7 @@ public class AdminUserServiceImpl implements AdminUserService { } private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String mobile, String email, - Long deptId, Set postIds) { + Long deptId, Set postIds) { // 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确 return DataPermissionUtils.executeIgnore(() -> { // 校验用户存在 @@ -443,7 +445,14 @@ public class AdminUserServiceImpl implements AdminUserService { UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>()) .updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build(); importUsers.forEach(importUser -> { - // 校验,判断是否有不符合的原因 + // 2.1.1 校验字段是否符合要求 + try { + ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(initPassword)); + } catch (ConstraintViolationException ex){ + respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); + return; + } + // 2.1.2 校验,判断是否有不符合的原因 try { validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(), importUser.getDeptId(), null); @@ -451,7 +460,8 @@ public class AdminUserServiceImpl implements AdminUserService { respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage()); return; } - // 判断如果不存在,在进行插入 + + // 2.2.1 判断如果不存在,在进行插入 AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername()); if (existUser == null) { userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class) @@ -459,7 +469,7 @@ public class AdminUserServiceImpl implements AdminUserService { respVO.getCreateUsernames().add(importUser.getUsername()); return; } - // 如果存在,判断是否允许更新 + // 2.2.2 如果存在,判断是否允许更新 if (!isUpdateSupport) { respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg()); return; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml index c682d9852..62a1ec456 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml @@ -158,10 +158,12 @@ wx: miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档 # appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的) # secret: 333ae72f41552af1e998fe1f54e1584a - appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 - secret: 6f270509224a7ae1296bbf1c8cb97aed + # appid: wx63c280fe3248a3e7 # wenhualian的接口测试号 + # secret: 6f270509224a7ae1296bbf1c8cb97aed # appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的) # secret: 4a1a04e07f6a4a0751b39c3064a92c8b + appid: wx66186af0759f47c9 # 测试号(puhui 提供的) + secret: 3218bcbd112cbc614c7264ceb20144ac config-storage: type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取 key-prefix: wa # Redis Key 的前缀 diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java index 900e1fd0a..1b2a502d3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImplTest.java @@ -11,10 +11,7 @@ import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportExcelVO; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserImportRespVO; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO; -import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; @@ -434,6 +431,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { public void testImportUserList_01() { // 准备参数 UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { + o.setEmail(randomEmail()); + o.setMobile(randomMobile()); }); // mock 方法,模拟失败 doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any()); @@ -456,6 +455,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 + o.setEmail(randomEmail()); + o.setMobile(randomMobile()); }); // mock deptService 的方法 DeptDO dept = randomPojo(DeptDO.class, o -> { @@ -490,6 +491,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 o.setUsername(dbUser.getUsername()); + o.setEmail(randomEmail()); + o.setMobile(randomMobile()); }); // mock deptService 的方法 DeptDO dept = randomPojo(DeptDO.class, o -> { @@ -520,6 +523,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest { o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围 o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围 o.setUsername(dbUser.getUsername()); + o.setEmail(randomEmail()); + o.setMobile(randomMobile()); }); // mock deptService 的方法 DeptDO dept = randomPojo(DeptDO.class, o -> { From 45095b524fcf15573375c0037dc066eef068e018 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 1 Aug 2024 23:21:24 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E3=80=91SYSTEM=EF=BC=9A=E5=BE=AE=E4=BF=A1=E5=B0=8F?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=9A=84=E8=AE=A2=E9=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-local.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml index 62a1ec456..ca8b88d7a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application-local.yaml @@ -183,6 +183,8 @@ yudao: enable: false wxa-code: env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop" + wxa-subscribe-message: + miniprogram-state: developer # 跳转小程序类型:开发版为 “developer”;体验版为 “trial”为;正式版为 “formal” justauth: enabled: true