Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/yudao-cloud
# Conflicts: # yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/history/ProductBrowseHistoryController.java # yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/social/AppSocialUserController.java # yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java # yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/SocialClientApi.java # yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/socail/SocialClientController.java # yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.javapull/132/head
commit
cce77b8add
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.ip.core;
|
package cn.iocoder.yudao.framework.ip.core;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
|
import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -54,7 +55,7 @@ public class Area {
|
||||||
/**
|
/**
|
||||||
* 子节点
|
* 子节点
|
||||||
*/
|
*/
|
||||||
@JsonManagedReference
|
@JsonBackReference
|
||||||
private List<Area> children;
|
private List<Area> children;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,10 @@ public class RandomUtils {
|
||||||
return randomString() + "@qq.com";
|
return randomString() + "@qq.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String randomMobile() {
|
||||||
|
return "13800138" + RandomUtil.randomNumbers(3);
|
||||||
|
}
|
||||||
|
|
||||||
public static String randomURL() {
|
public static String randomURL() {
|
||||||
return "https://www.iocoder.cn/" + randomString();
|
return "https://www.iocoder.cn/" + randomString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.ai.controller.admin.image;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
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.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
||||||
|
@ -41,7 +40,7 @@ public class AiImageController {
|
||||||
|
|
||||||
@GetMapping("/my-page")
|
@GetMapping("/my-page")
|
||||||
@Operation(summary = "获取【我的】绘图分页")
|
@Operation(summary = "获取【我的】绘图分页")
|
||||||
public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated PageParam pageReqVO) {
|
public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated AiImagePageReqVO pageReqVO) {
|
||||||
PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO);
|
PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO);
|
||||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -21,6 +19,9 @@ public class AiImagePageReqVO extends PageParam {
|
||||||
@Schema(description = "平台", example = "OpenAI")
|
@Schema(description = "平台", example = "OpenAI")
|
||||||
private String platform;
|
private String platform;
|
||||||
|
|
||||||
|
@Schema(description = "提示词", example = "1")
|
||||||
|
private String prompt;
|
||||||
|
|
||||||
@Schema(description = "绘画状态", example = "1")
|
@Schema(description = "绘画状态", example = "1")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package cn.iocoder.yudao.module.ai.dal.mysql.image;
|
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.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
@ -19,7 +18,7 @@ import java.util.List;
|
||||||
public interface AiImageMapper extends BaseMapperX<AiImageDO> {
|
public interface AiImageMapper extends BaseMapperX<AiImageDO> {
|
||||||
|
|
||||||
default AiImageDO selectByTaskId(String taskId) {
|
default AiImageDO selectByTaskId(String taskId) {
|
||||||
return this.selectOne(AiImageDO::getTaskId, taskId);
|
return selectOne(AiImageDO::getTaskId, taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<AiImageDO> selectPage(AiImagePageReqVO reqVO) {
|
default PageResult<AiImageDO> selectPage(AiImagePageReqVO reqVO) {
|
||||||
|
@ -32,9 +31,13 @@ public interface AiImageMapper extends BaseMapperX<AiImageDO> {
|
||||||
.orderByDesc(AiImageDO::getId));
|
.orderByDesc(AiImageDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<AiImageDO> selectPage(Long userId, PageParam pageReqVO) {
|
default PageResult<AiImageDO> selectPageMy(Long userId, AiImagePageReqVO reqVO) {
|
||||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiImageDO>()
|
return selectPage(reqVO, new LambdaQueryWrapperX<AiImageDO>()
|
||||||
.eq(AiImageDO::getUserId, userId)
|
.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));
|
.orderByDesc(AiImageDO::getId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cn.iocoder.yudao.module.ai.service.image;
|
package cn.iocoder.yudao.module.ai.service.image;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
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.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO;
|
||||||
|
@ -27,7 +26,7 @@ public interface AiImageService {
|
||||||
* @param pageReqVO 分页条件
|
* @param pageReqVO 分页条件
|
||||||
* @return 绘图分页
|
* @return 绘图分页
|
||||||
*/
|
*/
|
||||||
PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO);
|
PageResult<AiImageDO> getImagePageMy(Long userId, AiImagePageReqVO pageReqVO);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得绘图记录
|
* 获得绘图记录
|
||||||
|
|
|
@ -10,7 +10,6 @@ import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
|
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.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.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
|
||||||
|
@ -63,8 +62,8 @@ public class AiImageServiceImpl implements AiImageService {
|
||||||
private AiApiKeyService apiKeyService;
|
private AiApiKeyService apiKeyService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<AiImageDO> getImagePageMy(Long userId, PageParam pageReqVO) {
|
public PageResult<AiImageDO> getImagePageMy(Long userId, AiImagePageReqVO pageReqVO) {
|
||||||
return imageMapper.selectPage(userId, pageReqVO);
|
return imageMapper.selectPageMy(userId, pageReqVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -124,7 +124,7 @@ public class AiMindMapServiceImpl implements AiMindMapService {
|
||||||
if (role != null && role.getModelId() != null) {
|
if (role != null && role.getModelId() != null) {
|
||||||
model = chatModalService.getChatModel(role.getModelId());
|
model = chatModalService.getChatModel(role.getModelId());
|
||||||
}
|
}
|
||||||
if (model != null) {
|
if (model == null) {
|
||||||
model = chatModalService.getRequiredDefaultChatModel();
|
model = chatModalService.getRequiredDefaultChatModel();
|
||||||
}
|
}
|
||||||
Assert.notNull(model, "[AI] 获取不到模型");
|
Assert.notNull(model, "[AI] 获取不到模型");
|
||||||
|
|
|
@ -114,7 +114,7 @@ public class AiWriteServiceImpl implements AiWriteService {
|
||||||
if (Objects.nonNull(writeRole) && Objects.nonNull(writeRole.getModelId())) {
|
if (Objects.nonNull(writeRole) && Objects.nonNull(writeRole.getModelId())) {
|
||||||
model = chatModalService.getChatModel(writeRole.getModelId());
|
model = chatModalService.getChatModel(writeRole.getModelId());
|
||||||
}
|
}
|
||||||
if (Objects.isNull(model)) {
|
if (model == null) {
|
||||||
model = chatModalService.getRequiredDefaultChatModel();
|
model = chatModalService.getRequiredDefaultChatModel();
|
||||||
}
|
}
|
||||||
Assert.notNull(model, "[AI] 获取不到模型");
|
Assert.notNull(model, "[AI] 获取不到模型");
|
||||||
|
|
|
@ -1,24 +1,30 @@
|
||||||
package cn.iocoder.yudao.module.product.controller.admin.history;
|
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.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.ProductBrowseHistoryPageReqVO;
|
||||||
import cn.iocoder.yudao.module.product.controller.admin.history.vo.ProductBrowseHistoryRespVO;
|
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.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.history.ProductBrowseHistoryService;
|
||||||
|
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import java.util.Map;
|
||||||
import javax.validation.Valid;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 商品浏览记录")
|
@Tag(name = "管理后台 - 商品浏览记录")
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -28,13 +34,24 @@ public class ProductBrowseHistoryController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ProductBrowseHistoryService browseHistoryService;
|
private ProductBrowseHistoryService browseHistoryService;
|
||||||
|
@Resource
|
||||||
|
private ProductSpuService productSpuService;
|
||||||
|
|
||||||
@GetMapping("/page")
|
@GetMapping("/page")
|
||||||
@Operation(summary = "获得商品浏览记录分页")
|
@Operation(summary = "获得商品浏览记录分页")
|
||||||
@PreAuthorize("@ss.hasPermission('product:browse-history:query')")
|
@PreAuthorize("@ss.hasPermission('product:browse-history:query')")
|
||||||
public CommonResult<PageResult<ProductBrowseHistoryRespVO>> getBrowseHistoryPage(@Valid ProductBrowseHistoryPageReqVO pageReqVO) {
|
public CommonResult<PageResult<ProductBrowseHistoryRespVO>> getBrowseHistoryPage(@Valid ProductBrowseHistoryPageReqVO pageReqVO) {
|
||||||
PageResult<ProductBrowseHistoryDO> pageResult = browseHistoryService.getBrowseHistoryPage(pageReqVO);
|
PageResult<ProductBrowseHistoryDO> pageResult = browseHistoryService.getBrowseHistoryPage(pageReqVO);
|
||||||
return success(BeanUtils.toBean(pageResult, ProductBrowseHistoryRespVO.class));
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||||
|
return success(PageResult.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到商品 spu 信息
|
||||||
|
Map<Long, ProductSpuDO> 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()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,28 +7,28 @@ import lombok.Data;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
|
||||||
|
|
||||||
@Schema(description = "管理后台 - 商品浏览记录 Response VO")
|
@Schema(description = "管理后台 - 商品浏览记录 Response VO")
|
||||||
@Data
|
@Data
|
||||||
@ExcelIgnoreUnannotated
|
@ExcelIgnoreUnannotated
|
||||||
public class ProductBrowseHistoryRespVO {
|
public class ProductBrowseHistoryRespVO {
|
||||||
|
|
||||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26055")
|
@Schema(description = "编号", requiredMode = REQUIRED, example = "1")
|
||||||
@ExcelProperty("记录编号")
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4314")
|
@Schema(description = "商品 SPU 编号", requiredMode = REQUIRED, example = "29502")
|
||||||
@ExcelProperty("用户编号")
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@Schema(description = "用户是否删除", example = "false")
|
|
||||||
private Boolean userDeleted;
|
|
||||||
|
|
||||||
@Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "42")
|
|
||||||
@ExcelProperty("商品 SPU 编号")
|
|
||||||
private Long spuId;
|
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;
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.module.product.service.spu;
|
package cn.iocoder.yudao.module.product.service.spu;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
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.ProductSpuPageReqVO;
|
||||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO;
|
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO;
|
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO;
|
||||||
|
@ -58,6 +59,17 @@ public interface ProductSpuService {
|
||||||
*/
|
*/
|
||||||
List<ProductSpuDO> getSpuList(Collection<Long> ids);
|
List<ProductSpuDO> getSpuList(Collection<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得商品 SPU Map
|
||||||
|
*
|
||||||
|
* @param ids 编号数组
|
||||||
|
* @return 商品 SPU Map
|
||||||
|
*/
|
||||||
|
default Map<Long, ProductSpuDO> getSpuMap(Collection<Long> ids) {
|
||||||
|
List<ProductSpuDO> list = getSpuList(ids);
|
||||||
|
return CollectionUtils.convertMap(list, ProductSpuDO::getId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得指定状态的商品 SPU 列表
|
* 获得指定状态的商品 SPU 列表
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package cn.iocoder.yudao.module.promotion.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板枚举类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
public interface MessageTemplateConstants {
|
||||||
|
|
||||||
|
//======================= 小程序订阅消息模版 =======================
|
||||||
|
|
||||||
|
String COMBINATION_SUCCESS = "拼团结果通知";
|
||||||
|
|
||||||
|
}
|
|
@ -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.category.ProductCategoryApi;
|
||||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||||
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
|
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.system.api.user.AdminUserApi;
|
||||||
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
|
@ -12,7 +13,7 @@ import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@EnableFeignClients(clients = {ProductSkuApi.class, ProductSpuApi.class, ProductCategoryApi.class,
|
@EnableFeignClients(clients = {ProductSkuApi.class, ProductSpuApi.class, ProductCategoryApi.class,
|
||||||
MemberUserApi.class, TradeOrderApi.class, AdminUserApi.class,
|
MemberUserApi.class, TradeOrderApi.class, AdminUserApi.class, SocialClientApi.class,
|
||||||
WebSocketSenderApi.class})
|
WebSocketSenderApi.class})
|
||||||
public class RpcConfiguration {
|
public class RpcConfiguration {
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
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.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||||
|
@ -23,9 +24,12 @@ 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.dataobject.combination.CombinationRecordDO;
|
||||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
||||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
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 cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
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.afterNow;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.beforeNow;
|
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.ErrorCodeConstants.*;
|
||||||
|
import static cn.iocoder.yudao.module.promotion.enums.MessageTemplateConstants.COMBINATION_SUCCESS;
|
||||||
|
|
||||||
// TODO 芋艿:等拼团记录做完,完整 review 下
|
// TODO 芋艿:等拼团记录做完,完整 review 下
|
||||||
|
|
||||||
|
@ -66,8 +71,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||||
private ProductSkuApi productSkuApi;
|
private ProductSkuApi productSkuApi;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Lazy
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
private TradeOrderApi tradeOrderApi;
|
private TradeOrderApi tradeOrderApi;
|
||||||
|
@Resource
|
||||||
|
public SocialClientApi socialClientApi;
|
||||||
|
|
||||||
// TODO @芋艿:在详细预览下;
|
// TODO @芋艿:在详细预览下;
|
||||||
@Override
|
@Override
|
||||||
|
@ -205,7 +212,25 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
||||||
}
|
}
|
||||||
updateRecords.add(updateRecord);
|
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
|
@Override
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package cn.iocoder.yudao.module.trade.enums;
|
package cn.iocoder.yudao.module.trade.enums;
|
||||||
|
|
||||||
// TODO @芋艿:枚举
|
|
||||||
/**
|
/**
|
||||||
* 通知模板枚举类
|
* 通知模板枚举类
|
||||||
*
|
*
|
||||||
|
@ -8,9 +7,15 @@ package cn.iocoder.yudao.module.trade.enums;
|
||||||
*/
|
*/
|
||||||
public interface MessageTemplateConstants {
|
public interface MessageTemplateConstants {
|
||||||
|
|
||||||
String ORDER_DELIVERY = "order_delivery"; // 短信模版编号
|
// ======================= 短信消息模版 =======================
|
||||||
|
|
||||||
String BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过)
|
String SMS_ORDER_DELIVERY = "order_delivery"; // 短信模版编号
|
||||||
String BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过)
|
|
||||||
|
String SMS_BROKERAGE_WITHDRAW_AUDIT_APPROVE = "brokerage_withdraw_audit_approve"; // 佣金提现(审核通过)
|
||||||
|
String SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT = "brokerage_withdraw_audit_reject"; // 佣金提现(审核不通过)
|
||||||
|
|
||||||
|
// ======================= 小程序订阅消息模版 =======================
|
||||||
|
|
||||||
|
String WXA_ORDER_DELIVERY = "订单发货通知";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.reward.RewardActivityApi;
|
||||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
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.notify.NotifyMessageSendApi;
|
||||||
|
import cn.iocoder.yudao.module.system.api.social.SocialClientApi;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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,
|
MemberUserApi.class, MemberPointApi.class, MemberLevelApi.class, MemberAddressApi.class, MemberConfigApi.class,
|
||||||
ProductSpuApi.class, ProductSkuApi.class, ProductCommentApi.class, ProductCategoryApi.class,
|
ProductSpuApi.class, ProductSkuApi.class, ProductCommentApi.class, ProductCategoryApi.class,
|
||||||
PayOrderApi.class, PayRefundApi.class,
|
PayOrderApi.class, PayRefundApi.class,
|
||||||
NotifyMessageSendApi.class
|
NotifyMessageSendApi.class, SocialClientApi.class
|
||||||
})
|
})
|
||||||
public class RpcConfiguration {
|
public class RpcConfiguration {
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.TradeOrderQueryService;
|
||||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
|
@ -56,6 +57,7 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
|
||||||
public class AfterSaleServiceImpl implements AfterSaleService {
|
public class AfterSaleServiceImpl implements AfterSaleService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
private TradeOrderUpdateService tradeOrderUpdateService;
|
private TradeOrderUpdateService tradeOrderUpdateService;
|
||||||
@Resource
|
@Resource
|
||||||
private TradeOrderQueryService tradeOrderQueryService;
|
private TradeOrderQueryService tradeOrderQueryService;
|
||||||
|
|
|
@ -77,14 +77,14 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
|
||||||
|
|
||||||
String templateCode;
|
String templateCode;
|
||||||
if (BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.equals(status)) {
|
if (BrokerageWithdrawStatusEnum.AUDIT_SUCCESS.equals(status)) {
|
||||||
templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_APPROVE;
|
templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_APPROVE;
|
||||||
// 3.1 通过时佣金转余额
|
// 3.1 通过时佣金转余额
|
||||||
if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) {
|
if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) {
|
||||||
// todo 疯狂:
|
// todo 疯狂:
|
||||||
}
|
}
|
||||||
// TODO 疯狂:调用转账接口
|
// TODO 疯狂:调用转账接口
|
||||||
} else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
|
} else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
|
||||||
templateCode = MessageTemplateConstants.BROKERAGE_WITHDRAW_AUDIT_REJECT;
|
templateCode = MessageTemplateConstants.SMS_BROKERAGE_WITHDRAW_AUDIT_REJECT;
|
||||||
// 3.2 驳回时需要退还用户佣金
|
// 3.2 驳回时需要退还用户佣金
|
||||||
brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT,
|
brokerageRecordService.addBrokerage(withdraw.getUserId(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT,
|
||||||
String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle());
|
String.valueOf(withdraw.getId()), withdraw.getPrice(), BrokerageRecordBizTypeEnum.WITHDRAW_REJECT.getTitle());
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class TradeMessageServiceImpl implements TradeMessageService {
|
||||||
notifyMessageSendApi.sendSingleMessageToMember(
|
notifyMessageSendApi.sendSingleMessageToMember(
|
||||||
new NotifySendSingleToUserReqDTO()
|
new NotifySendSingleToUserReqDTO()
|
||||||
.setUserId(reqBO.getUserId())
|
.setUserId(reqBO.getUserId())
|
||||||
.setTemplateCode(MessageTemplateConstants.ORDER_DELIVERY)
|
.setTemplateCode(MessageTemplateConstants.SMS_ORDER_DELIVERY)
|
||||||
.setTemplateParams(msgMap));
|
.setTemplateParams(msgMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package cn.iocoder.yudao.module.trade.service.order;
|
package cn.iocoder.yudao.module.trade.service.order;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
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.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
|
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
|
||||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
|
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.TradeOrderDeliveryReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
|
||||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
|
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderUpdateAddressReqVO;
|
||||||
|
@ -50,6 +54,7 @@ import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||||
import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper;
|
import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.common.util.servlet.ServletUtils.getClientIP;
|
||||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal;
|
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.ErrorCodeConstants.*;
|
||||||
|
import static cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants.WXA_ORDER_DELIVERY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交易订单【写】Service 实现类
|
* 交易订单【写】Service 实现类
|
||||||
|
@ -103,6 +109,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||||
private MemberAddressApi addressApi;
|
private MemberAddressApi addressApi;
|
||||||
@Resource
|
@Resource
|
||||||
private ProductCommentApi productCommentApi;
|
private ProductCommentApi productCommentApi;
|
||||||
|
@Resource
|
||||||
|
public SocialClientApi socialClientApi;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private TradeOrderProperties tradeOrderProperties;
|
private TradeOrderProperties tradeOrderProperties;
|
||||||
|
@ -364,9 +372,26 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||||
MapUtil.<String, Object>builder().put("expressName", express != null ? express.getName() : "")
|
MapUtil.<String, Object>builder().put("expressName", express != null ? express.getName() : "")
|
||||||
.put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
|
.put("logisticsNo", express != null ? deliveryReqVO.getLogisticsNo() : "").build());
|
||||||
|
|
||||||
// 4. 发送站内信
|
// 4.1 发送站内信
|
||||||
tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO()
|
tradeMessageService.sendMessageWhenDeliveryOrder(new TradeOrderMessageWhenDeliveryOrderReqBO()
|
||||||
.setOrderId(order.getId()).setUserId(order.getUserId()).setMessage(null));
|
.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())); // 收货地址
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.enums.order.TradeOrderTypeEnum;
|
||||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
@ -28,11 +29,13 @@ import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_DELIV
|
||||||
public class TradeCombinationOrderHandler implements TradeOrderHandler {
|
public class TradeCombinationOrderHandler implements TradeOrderHandler {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
private TradeOrderUpdateService orderUpdateService;
|
private TradeOrderUpdateService orderUpdateService;
|
||||||
@Resource
|
@Resource
|
||||||
private TradeOrderQueryService orderQueryService;
|
private TradeOrderQueryService orderQueryService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
|
@Lazy // 延迟加载,避免循环依赖
|
||||||
private CombinationRecordApi combinationRecordApi;
|
private CombinationRecordApi combinationRecordApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,24 +5,19 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
|
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.*;
|
||||||
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.system.api.social.SocialClientApi;
|
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.SocialUserApi;
|
||||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
|
import cn.iocoder.yudao.module.system.api.social.dto.*;
|
||||||
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 io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import java.util.List;
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
@ -68,9 +63,16 @@ public class AppSocialUserController {
|
||||||
|
|
||||||
@PostMapping("/wxa-qrcode")
|
@PostMapping("/wxa-qrcode")
|
||||||
@Operation(summary = "获得微信小程序码(base64 image)")
|
@Operation(summary = "获得微信小程序码(base64 image)")
|
||||||
public CommonResult<String> getWxaQrcode(@RequestBody @Valid AppSocialWxQrcodeReqVO reqVO) {
|
public CommonResult<String> getWxaQrcode(@RequestBody @Valid AppSocialWxaQrcodeReqVO reqVO) {
|
||||||
byte[] wxQrcode = socialClientApi.getWxaQrcode(BeanUtils.toBean(reqVO, SocialWxQrcodeReqDTO.class)).getCheckedData();
|
byte[] wxQrcode = socialClientApi.getWxaQrcode(BeanUtils.toBean(reqVO, SocialWxQrcodeReqDTO.class)).getCheckedData();
|
||||||
return success(Base64.encode(wxQrcode));
|
return success(Base64.encode(wxQrcode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-subscribe-template-list")
|
||||||
|
@Operation(summary = "获得微信小程订阅模板列表")
|
||||||
|
public CommonResult<List<AppSocialWxaSubscribeTemplateRespVO>> getSubscribeTemplateList() {
|
||||||
|
List<SocialWxaSubscribeTemplateRespDTO> template = socialClientApi.getWxaSubscribeTemplateList(UserTypeEnum.MEMBER.getValue()).getCheckedData();
|
||||||
|
return success(BeanUtils.toBean(template, AppSocialWxaSubscribeTemplateRespVO.class));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
@Schema(description = "用户 APP - 获得获取小程序码 Request VO")
|
@Schema(description = "用户 APP - 获得获取小程序码 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class AppSocialWxQrcodeReqVO {
|
public class AppSocialWxaQrcodeReqVO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 页面路径不能携带参数(参数请放在scene字段里)
|
* 页面路径不能携带参数(参数请放在scene字段里)
|
|
@ -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 为长期订阅
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package cn.iocoder.yudao.module.pay.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知模板枚举类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
public interface MessageTemplateConstants {
|
||||||
|
|
||||||
|
// ======================= 小程序订阅消息 =======================
|
||||||
|
|
||||||
|
String WXA_WALLET_RECHARGER_PAID = "充值成功通知";
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
package cn.iocoder.yudao.module.pay.framework.rpc.config;
|
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;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@EnableFeignClients(clients = {SocialClientApi.class})
|
||||||
public class RpcConfiguration {
|
public class RpcConfiguration {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cn.iocoder.yudao.module.pay.service.wallet;
|
package cn.iocoder.yudao.module.pay.service.wallet;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
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.PageParam;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
||||||
|
@ -18,11 +20,14 @@ import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
|
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.order.PayOrderService;
|
||||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
|
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 lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -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.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime;
|
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.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.convert.wallet.PayWalletRechargeConvert.INSTANCE;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
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.*;
|
import static cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +68,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
||||||
private PayRefundService payRefundService;
|
private PayRefundService payRefundService;
|
||||||
@Resource
|
@Resource
|
||||||
private PayWalletRechargePackageService payWalletRechargePackageService;
|
private PayWalletRechargePackageService payWalletRechargePackageService;
|
||||||
|
@Resource
|
||||||
|
public SocialClientApi socialClientApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@ -126,6 +135,24 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
||||||
// TODO 需要钱包中加个可提现余额
|
// TODO 需要钱包中加个可提现余额
|
||||||
payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(id),
|
payWalletService.addWalletBalance(walletRecharge.getWalletId(), String.valueOf(id),
|
||||||
PayWalletBizTypeEnum.RECHARGE, walletRecharge.getTotalPrice());
|
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
|
@Override
|
||||||
|
@ -282,4 +309,13 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
|
||||||
return payOrder;
|
return payOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得自身的代理对象,解决 AOP 生效问题
|
||||||
|
*
|
||||||
|
* @return 自己
|
||||||
|
*/
|
||||||
|
private PayWalletRechargeServiceImpl getSelf() {
|
||||||
|
return SpringUtil.getBean(getClass());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
package cn.iocoder.yudao.module.system.api.social;
|
package cn.iocoder.yudao.module.system.api.social;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
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.*;
|
||||||
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.enums.ApiConstants;
|
import cn.iocoder.yudao.module.system.enums.ApiConstants;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
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.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import java.util.List;
|
||||||
|
|
||||||
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory =
|
||||||
@Tag(name = "RPC 服务 - 社交应用")
|
@Tag(name = "RPC 服务 - 社交应用")
|
||||||
|
@ -52,6 +54,14 @@ public interface SocialClientApi {
|
||||||
|
|
||||||
@GetMapping(PREFIX + "/get-wxa-qrcode")
|
@GetMapping(PREFIX + "/get-wxa-qrcode")
|
||||||
@Operation(summary = "获得小程序二维码")
|
@Operation(summary = "获得小程序二维码")
|
||||||
CommonResult<byte[]> getWxaQrcode(@Valid SocialWxQrcodeReqDTO reqVO);
|
CommonResult<byte[]> getWxaQrcode(@SpringQueryMap SocialWxQrcodeReqDTO reqVO);
|
||||||
|
|
||||||
|
@GetMapping(PREFIX + "/get-wxa-subscribe-template-list")
|
||||||
|
@Operation(summary = "获得微信小程订阅模板")
|
||||||
|
CommonResult<List<SocialWxaSubscribeTemplateRespDTO>> getWxaSubscribeTemplateList(@RequestParam("userType") Integer userType);
|
||||||
|
|
||||||
|
@PostMapping(PREFIX + "/send-wxa-subscribe-message")
|
||||||
|
@Operation(summary = "发送微信小程序订阅消息")
|
||||||
|
CommonResult<Boolean> sendWxaSubscribeMessage(@Valid @RequestBody SocialWxaSubscribeMessageSendReqDTO reqDTO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String, String> messages;
|
||||||
|
|
||||||
|
public SocialWxaSubscribeMessageSendReqDTO addMessage(String key, String value) {
|
||||||
|
if (messages == null) {
|
||||||
|
messages = new HashMap<>();
|
||||||
|
}
|
||||||
|
messages.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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:为长期订阅
|
||||||
|
|
||||||
|
}
|
|
@ -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_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_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_WEIXIN_MINI_APP_SUBSCRIBE_TEMPLATE_ERROR = new ErrorCode(1_002_018_202, "获得小程序订阅消息模版失败");
|
||||||
ErrorCode SOCIAL_CLIENT_UNIQUE = new ErrorCode(1_002_018_203, "社交客户端已存在配置");
|
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 =========
|
// ========== OAuth2 客户端 1-002-020-000 =========
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
package cn.iocoder.yudao.module.system.api.social;
|
package cn.iocoder.yudao.module.system.api.social;
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
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.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.*;
|
||||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxPhoneNumberInfoRespDTO;
|
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||||
import cn.iocoder.yudao.module.system.api.social.dto.SocialWxQrcodeReqDTO;
|
|
||||||
import cn.iocoder.yudao.module.system.service.social.SocialClientService;
|
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.WxJsapiSignature;
|
||||||
|
import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.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.pojo.CommonResult.success;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 社交应用的 API 实现类
|
* 社交应用的 API 实现类
|
||||||
|
@ -22,10 +31,13 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@Validated
|
@Validated
|
||||||
|
@Slf4j
|
||||||
public class SocialClientApiImpl implements SocialClientApi {
|
public class SocialClientApiImpl implements SocialClientApi {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SocialClientService socialClientService;
|
private SocialClientService socialClientService;
|
||||||
|
@Resource
|
||||||
|
private SocialUserService socialUserService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<String> getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
|
public CommonResult<String> getAuthorizeUrl(Integer socialType, Integer userType, String redirectUri) {
|
||||||
|
@ -49,4 +61,39 @@ public class SocialClientApiImpl implements SocialClientApi {
|
||||||
return success(socialClientService.getWxaQrcode(reqVO));
|
return success(socialClientService.getWxaQrcode(reqVO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<List<SocialWxaSubscribeTemplateRespDTO>> getWxaSubscribeTemplateList(Integer userType) {
|
||||||
|
List<TemplateInfo> list = socialClientService.getSubscribeTemplateList(userType);
|
||||||
|
return success(convertList(list, item -> BeanUtils.toBean(item, SocialWxaSubscribeTemplateRespDTO.class).setId(item.getPriTmplId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonResult<Boolean> sendWxaSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO) {
|
||||||
|
// 1.1 获得订阅模版列表
|
||||||
|
List<TemplateInfo> 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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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": "充值成功"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.SocialClientPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
|
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientRespVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@Tag(name = "管理后台 - 社交客户端")
|
@Tag(name = "管理后台 - 社交客户端")
|
||||||
|
@ -28,6 +29,8 @@ public class SocialClientController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SocialClientService socialClientService;
|
private SocialClientService socialClientService;
|
||||||
|
@Resource
|
||||||
|
private SocialClientApi socialClientApi;
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建社交客户端")
|
@Operation(summary = "创建社交客户端")
|
||||||
|
@ -70,4 +73,11 @@ public class SocialClientController {
|
||||||
return success(BeanUtils.toBean(pageResult, SocialClientRespVO.class));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,4 +98,13 @@ public interface RedisKeyConstants {
|
||||||
* VALUE 数据格式:String 模版信息
|
* VALUE 数据格式:String 模版信息
|
||||||
*/
|
*/
|
||||||
String SMS_TEMPLATE = "sms_template";
|
String SMS_TEMPLATE = "sms_template";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序订阅模版的缓存
|
||||||
|
*
|
||||||
|
* KEY 格式:wxa_subscribe_template:{userType}
|
||||||
|
* VALUE 数据格式 String, 模版信息
|
||||||
|
*/
|
||||||
|
String WXA_SUBSCRIBE_TEMPLATE = "wxa_subscribe_template";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,16 @@ package cn.iocoder.yudao.module.system.service.social;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
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.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.SocialClientPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
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.dataobject.social.SocialClientDO;
|
||||||
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||||
import com.xingyuv.jushauth.model.AuthUser;
|
import com.xingyuv.jushauth.model.AuthUser;
|
||||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||||
|
import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
@ -70,6 +74,25 @@ public interface SocialClientService {
|
||||||
*/
|
*/
|
||||||
byte[] getWxaQrcode(SocialWxQrcodeReqDTO reqVO);
|
byte[] getWxaQrcode(SocialWxQrcodeReqDTO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得微信小程订阅模板
|
||||||
|
*
|
||||||
|
* 缓存的目的:考虑到微信小程序订阅消息选择好模版后几乎不会变动,缓存增加查询效率
|
||||||
|
*
|
||||||
|
* @param userType 用户类型
|
||||||
|
* @return 微信小程订阅模板
|
||||||
|
*/
|
||||||
|
List<TemplateInfo> getSubscribeTemplateList(Integer userType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送微信小程序订阅消息
|
||||||
|
*
|
||||||
|
* @param reqDTO 请求
|
||||||
|
* @param templateId 模版编号
|
||||||
|
* @param openId 会员 openId
|
||||||
|
*/
|
||||||
|
void sendSubscribeMessage(SocialWxaSubscribeMessageSendReqDTO reqDTO, String templateId, String openId);
|
||||||
|
|
||||||
// =================== 客户端管理 ===================
|
// =================== 客户端管理 ===================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
package cn.iocoder.yudao.module.system.service.social;
|
package cn.iocoder.yudao.module.system.service.social;
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
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.api.impl.WxMaServiceImpl;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
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.config.impl.WxMaRedisBetterConfigImpl;
|
||||||
|
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
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.http.HttpUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
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.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.SocialClientPageReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.socail.vo.client.SocialClientSaveReqVO;
|
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.dataobject.social.SocialClientDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.social.SocialClientMapper;
|
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 cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
|
||||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
||||||
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
|
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
|
||||||
|
@ -35,23 +41,27 @@ import com.xingyuv.justauth.AuthRequestFactory;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
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.error.WxErrorException;
|
||||||
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
|
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
|
||||||
import me.chanjar.weixin.mp.api.WxMpService;
|
import me.chanjar.weixin.mp.api.WxMpService;
|
||||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||||
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
|
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
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.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
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 实现类
|
* 社交应用 Service 实现类
|
||||||
|
@ -63,7 +73,7 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SOCIAL_CLI
|
||||||
public class SocialClientServiceImpl implements SocialClientService {
|
public class SocialClientServiceImpl implements SocialClientService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小程序版本
|
* 小程序码要打开的小程序版本
|
||||||
*
|
*
|
||||||
* 1. release:正式版
|
* 1. release:正式版
|
||||||
* 2. trial:体验版
|
* 2. trial:体验版
|
||||||
|
@ -71,6 +81,15 @@ public class SocialClientServiceImpl implements SocialClientService {
|
||||||
*/
|
*/
|
||||||
@Value("${yudao.wxa-code.env-version:release}")
|
@Value("${yudao.wxa-code.env-version:release}")
|
||||||
public String envVersion;
|
public String envVersion;
|
||||||
|
/**
|
||||||
|
* 订阅消息跳转小程序类型
|
||||||
|
*
|
||||||
|
* 1. developer:开发版
|
||||||
|
* 2. trial:体验版
|
||||||
|
* 3. formal:正式版
|
||||||
|
*/
|
||||||
|
@Value("${yudao.wxa-subscribe-message.miniprogram-state:formal}")
|
||||||
|
public String miniprogramState;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AuthRequestFactory authRequestFactory;
|
private AuthRequestFactory authRequestFactory;
|
||||||
|
@ -255,11 +274,58 @@ public class SocialClientServiceImpl implements SocialClientService {
|
||||||
null,
|
null,
|
||||||
ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE));
|
ObjUtil.defaultIfNull(reqVO.getHyaline(), SocialWxQrcodeReqDTO.HYALINE));
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
log.error("[getWxQrcode][reqVO({})) 获得小程序码失败]", reqVO, e);
|
log.error("[getWxQrcode][reqVO({}) 获得小程序码失败]", reqVO, e);
|
||||||
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR);
|
throw exception(SOCIAL_CLIENT_WEIXIN_MINI_APP_QRCODE_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Cacheable(cacheNames = RedisKeyConstants.WXA_SUBSCRIBE_TEMPLATE, key = "#userType", condition = "#result != null")
|
||||||
|
public List<TemplateInfo> 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<String, String> 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 对象
|
* 获得 clientId + clientSecret 对应的 WxMpService 对象
|
||||||
*
|
*
|
||||||
|
|
|
@ -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.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
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.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
|
||||||
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
|
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.config.ConfigApi;
|
||||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||||
|
@ -31,13 +32,14 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.mzt.logapi.context.LogRecordContext;
|
import com.mzt.logapi.context.LogRecordContext;
|
||||||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -443,7 +445,14 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||||
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
|
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
|
||||||
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
|
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
|
||||||
importUsers.forEach(importUser -> {
|
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 {
|
try {
|
||||||
validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
|
validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
|
||||||
importUser.getDeptId(), null);
|
importUser.getDeptId(), null);
|
||||||
|
@ -451,7 +460,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||||
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
|
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 判断如果不存在,在进行插入
|
|
||||||
|
// 2.2.1 判断如果不存在,在进行插入
|
||||||
AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
|
AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
|
||||||
if (existUser == null) {
|
if (existUser == null) {
|
||||||
userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
|
userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
|
||||||
|
@ -459,7 +469,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||||
respVO.getCreateUsernames().add(importUser.getUsername());
|
respVO.getCreateUsernames().add(importUser.getUsername());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 如果存在,判断是否允许更新
|
// 2.2.2 如果存在,判断是否允许更新
|
||||||
if (!isUpdateSupport) {
|
if (!isUpdateSupport) {
|
||||||
respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
|
respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -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 文档
|
miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档
|
||||||
# appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的)
|
# appid: wx62056c0d5e8db250 # 测试号(牛希尧提供的)
|
||||||
# secret: 333ae72f41552af1e998fe1f54e1584a
|
# secret: 333ae72f41552af1e998fe1f54e1584a
|
||||||
appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
|
# appid: wx63c280fe3248a3e7 # wenhualian的接口测试号
|
||||||
secret: 6f270509224a7ae1296bbf1c8cb97aed
|
# secret: 6f270509224a7ae1296bbf1c8cb97aed
|
||||||
# appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的)
|
# appid: wxc4598c446f8a9cb3 # 测试号(Kongdy 提供的)
|
||||||
# secret: 4a1a04e07f6a4a0751b39c3064a92c8b
|
# secret: 4a1a04e07f6a4a0751b39c3064a92c8b
|
||||||
|
appid: wx66186af0759f47c9 # 测试号(puhui 提供的)
|
||||||
|
secret: 3218bcbd112cbc614c7264ceb20144ac
|
||||||
config-storage:
|
config-storage:
|
||||||
type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
|
type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
|
||||||
key-prefix: wa # Redis Key 的前缀
|
key-prefix: wa # Redis Key 的前缀
|
||||||
|
@ -181,6 +183,8 @@ yudao:
|
||||||
enable: false
|
enable: false
|
||||||
wxa-code:
|
wxa-code:
|
||||||
env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop"
|
env-version: develop # 小程序版本: 正式版为 "release";体验版为 "trial";开发版为 "develop"
|
||||||
|
wxa-subscribe-message:
|
||||||
|
miniprogram-state: developer # 跳转小程序类型:开发版为 “developer”;体验版为 “trial”为;正式版为 “formal”
|
||||||
|
|
||||||
justauth:
|
justauth:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
@ -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.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.UserProfileUpdatePasswordReqVO;
|
||||||
import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO;
|
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.*;
|
||||||
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.dal.dataobject.dept.DeptDO;
|
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.PostDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
|
||||||
|
@ -434,6 +431,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
|
||||||
public void testImportUserList_01() {
|
public void testImportUserList_01() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
|
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
|
||||||
|
o.setEmail(randomEmail());
|
||||||
|
o.setMobile(randomMobile());
|
||||||
});
|
});
|
||||||
// mock 方法,模拟失败
|
// mock 方法,模拟失败
|
||||||
doThrow(new ServiceException(DEPT_NOT_FOUND)).when(deptService).validateDeptList(any());
|
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 -> {
|
UserImportExcelVO importUser = randomPojo(UserImportExcelVO.class, o -> {
|
||||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||||
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
||||||
|
o.setEmail(randomEmail());
|
||||||
|
o.setMobile(randomMobile());
|
||||||
});
|
});
|
||||||
// mock deptService 的方法
|
// mock deptService 的方法
|
||||||
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
||||||
|
@ -490,6 +491,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
|
||||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||||
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
||||||
o.setUsername(dbUser.getUsername());
|
o.setUsername(dbUser.getUsername());
|
||||||
|
o.setEmail(randomEmail());
|
||||||
|
o.setMobile(randomMobile());
|
||||||
});
|
});
|
||||||
// mock deptService 的方法
|
// mock deptService 的方法
|
||||||
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
||||||
|
@ -520,6 +523,8 @@ public class AdminUserServiceImplTest extends BaseDbUnitTest {
|
||||||
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
|
||||||
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
o.setSex(randomEle(SexEnum.values()).getSex()); // 保证 sex 的范围
|
||||||
o.setUsername(dbUser.getUsername());
|
o.setUsername(dbUser.getUsername());
|
||||||
|
o.setEmail(randomEmail());
|
||||||
|
o.setMobile(randomMobile());
|
||||||
});
|
});
|
||||||
// mock deptService 的方法
|
// mock deptService 的方法
|
||||||
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
DeptDO dept = randomPojo(DeptDO.class, o -> {
|
||||||
|
|
Loading…
Reference in New Issue