Browse Source

!649 Review代码修改
Merge pull request !649 from 疯狂的世界/feature/mall_product

芋道源码 1 year ago
parent
commit
d874346d42
16 changed files with 164 additions and 183 deletions
  1. 7 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
  2. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/UserCreateConsumer.java
  3. 29 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/coupon/UserCreateMessage.java
  4. 1 1
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
  5. 1 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
  6. 12 25
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java
  7. 45 75
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java
  8. 7 14
      yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml
  9. 0 7
      yudao-module-member/yudao-module-member-api/pom.xml
  10. 1 3
      yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
  11. 8 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java
  12. 3 3
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/UserCreateMessage.java
  13. 0 32
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/RegisterCouponProducer.java
  14. 31 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/UserCreateProducer.java
  15. 2 13
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java
  16. 13 6
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java

+ 7 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java

@@ -78,6 +78,13 @@ public class CollectionUtils {
         return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toSet());
     }
 
+    public static <T, K> Map<K, T> convertMapByFilter(Collection<T> from, Predicate<T> filter, Function<T, K> keyFunc) {
+        if (CollUtil.isEmpty(from)) {
+            return new HashMap<>();
+        }
+        return from.stream().filter(filter).collect(Collectors.toMap(keyFunc, v -> v));
+    }
+
     public static <T, K> Map<K, T> convertMap(Collection<T> from, Function<T, K> keyFunc) {
         if (CollUtil.isEmpty(from)) {
             return new HashMap<>();

+ 4 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/RegisterCouponSendConsumer.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/consumer/coupon/UserCreateConsumer.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
 
 import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
-import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
+import cn.iocoder.yudao.module.promotion.mq.message.coupon.UserCreateMessage;
 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
@@ -9,19 +9,19 @@ import org.springframework.stereotype.Component;
 import javax.annotation.Resource;
 
 /**
- * 针对 {@link RegisterCouponSendMessage} 的消费者
+ * 针对 {@link UserCreateMessage} 的消费者
  *
  * @author owen
  */
 @Component
 @Slf4j
-public class RegisterCouponSendConsumer extends AbstractStreamMessageListener<RegisterCouponSendMessage> {
+public class UserCreateConsumer extends AbstractStreamMessageListener<UserCreateMessage> {
 
     @Resource
     private CouponService couponService;
 
     @Override
-    public void onMessage(RegisterCouponSendMessage message) {
+    public void onMessage(UserCreateMessage message) {
         log.info("[onMessage][消息内容({})]", message);
         couponService.takeCouponByRegister(message.getUserId());
     }

+ 29 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/mq/message/coupon/UserCreateMessage.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.promotion.mq.message.coupon;
+
+import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 会员用户创建消息
+ *
+ * @author owen
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class UserCreateMessage extends AbstractStreamMessage {
+
+    /**
+     * 用户编号
+     */
+    @NotNull(message = "用户编号不能为空")
+    private Long userId;
+
+    @Override
+    public String getStreamKey() {
+        return "member.create.send";
+    }
+
+}

+ 1 - 1
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java

@@ -178,7 +178,7 @@ public class CouponServiceImpl implements CouponService {
     }
 
     @Override
-    // TODO @疯狂:搞个事务;
+    @Transactional(rollbackFor = Exception.class)
     public void takeCouponByRegister(Long userId) {
         List<CouponTemplateDO> templates = couponTemplateService.getCouponTemplateListByTakeType(CouponTakeTypeEnum.REGISTER);
         for (CouponTemplateDO template : templates) {

+ 1 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java

@@ -81,6 +81,7 @@ public interface ErrorCodeConstants {
     ErrorCode BROKERAGE_BIND_MODE_REGISTER = new ErrorCode(1_011_007_005, "只有在注册时可以绑定");
     ErrorCode BROKERAGE_BIND_OVERRIDE = new ErrorCode(1_011_007_006, "已绑定了推广人");
     ErrorCode BROKERAGE_BIND_LOOP = new ErrorCode(1_011_007_007, "下级不能绑定自己的上级");
+    ErrorCode BROKERAGE_USER_LEVEL_NOT_SUPPORT = new ErrorCode(1_011_007_008, "目前只支持 level 小于等于 2");
 
 
     // ========== 分销提现 模块 1-011-008-000 ==========

+ 12 - 25
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/BrokerageUserMapper.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage;
 
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.lang.Assert;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.pojo.SortingField;
@@ -17,6 +18,8 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -27,12 +30,12 @@ import java.util.List;
 @Mapper
 public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
 
-    default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Long> bindUserIds) {
+    default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO, List<Long> ids) {
         return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
+                .inIfPresent(BrokerageUserDO::getId, ids)
                 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
                 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
                 .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
-                .inIfPresent(BrokerageUserDO::getBindUserId, bindUserIds)
                 .orderByDesc(BrokerageUserDO::getId));
     }
 
@@ -124,11 +127,6 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
                 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
     }
 
-    default Long selectCountByBindUserIdIn(List<Long> bindUserIds) {
-        return selectCount(new LambdaQueryWrapperX<BrokerageUserDO>()
-                .inIfPresent(BrokerageUserDO::getBindUserId, bindUserIds));
-    }
-
     @Select("SELECT bind_user_id AS id, COUNT(1) AS brokerageUserCount FROM trade_brokerage_user " +
             "WHERE bind_user_id IS NOT NULL AND deleted = FALSE " +
             "AND bind_user_time BETWEEN #{beginTime} AND #{endTime} " +
@@ -143,32 +141,21 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
      *
      * @param bizType      业务类型
      * @param status       状态
-     * @param bindUserIds  绑定用户编号列表
+     * @param ids          用户编号列表
      * @param sortingField 排序字段
      * @return 下级分销统计分页列表
      */
     IPage<AppBrokerageUserChildSummaryRespVO> selectSummaryPageByUserId(Page<?> page,
                                                                         @Param("bizType") Integer bizType,
                                                                         @Param("status") Integer status,
-                                                                        @Param("bindUserIds") List<Long> bindUserIds,
+                                                                        @Param("ids") Collection<Long> ids,
                                                                         @Param("sortingField") SortingField sortingField);
 
-    /**
-     * 下级分销统计(不分页)
-     *
-     * @param bizType      业务类型
-     * @param status       状态
-     * @param bindUserIds  绑定用户编号列表
-     * @param sortingField 排序字段
-     * @return 下级分销统计列表
-     */
-    List<AppBrokerageUserChildSummaryRespVO> selectSummaryListByUserId(@Param("bizType") Integer bizType,
-                                                                       @Param("status") Integer status,
-                                                                       @Param("bindUserIds") List<Long> bindUserIds,
-                                                                       @Param("sortingField") SortingField sortingField);
-
-    default List<BrokerageUserDO> selectListByBindUserId(Long bindUserId) {
-        return selectList(BrokerageUserDO::getBindUserId, bindUserId);
+    default List<Long> selectIdListByBindUserIdIn(Collection<Long> bindUserIds) {
+        return Convert.toList(Long.class,
+                selectObjs(new LambdaQueryWrapperX<BrokerageUserDO>()
+                        .select(Collections.singletonList(BrokerageUserDO::getId))
+                        .in(BrokerageUserDO::getBindUserId, bindUserIds)));
     }
 
 }

+ 45 - 75
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserServiceImpl.java

@@ -31,10 +31,9 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.util.*;
-import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMapByFilter;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
 /**
@@ -67,8 +66,12 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
 
     @Override
     public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
-        List<Long> bindUserIds = buildBindUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel());
-        return brokerageUserMapper.selectPage(pageReqVO, bindUserIds);
+        List<Long> childIds = getChildUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel());
+        // 有”绑定用户编号“查询条件时,没有查到下级会员,直接返回空
+        if (pageReqVO.getBindUserId() != null && CollUtil.isEmpty(childIds)) {
+            return PageResult.empty();
+        }
+        return brokerageUserMapper.selectPage(pageReqVO, childIds);
     }
 
     @Override
@@ -154,11 +157,8 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
 
     @Override
     public Long getBrokerageUserCountByBindUserId(Long bindUserId, Integer level) {
-        List<Long> bindUserIds = buildBindUserIdsByLevel(bindUserId, level);
-        if (CollUtil.isEmpty(bindUserIds)) {
-            return 0L;
-        }
-        return brokerageUserMapper.selectCountByBindUserIdIn(bindUserIds);
+        List<Long> childIds = getChildUserIdsByLevel(bindUserId, level);
+        return (long) CollUtil.size(childIds);
     }
 
     @Override
@@ -226,70 +226,29 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
 
     @Override
     public PageResult<AppBrokerageUserChildSummaryRespVO> getBrokerageUserChildSummaryPage(AppBrokerageUserChildSummaryPageReqVO pageReqVO, Long userId) {
-        // 生成推广员编号列表
-        List<Long> bindUserIds = buildBindUserIdsByLevel(userId, pageReqVO.getLevel());
-
-        // TODO @疯狂:情况一和情况二,可以合并哈;
-        //  如果有 nickname 的时候,相当于提前查询 users,然后 nickname 过滤掉 bindUserIds;
-        //  之后,继续使用 selectSummaryPageByUserId 里面 in bindUserIds 查询;
-
-        // 情况一:没有昵称过滤条件时,直接使用数据库的分页查询
-        if (StrUtil.isBlank(pageReqVO.getNickname())) {
-            // 1.1 分页查询
-            IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
-                    MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(),
-                    BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), bindUserIds, pageReqVO.getSortingField()
-            );
-
-            // 1.2 拼接数据并返回
-            List<Long> userIds = convertList(pageResult.getRecords(), AppBrokerageUserChildSummaryRespVO::getId);
-            Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
-            BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap);
-            return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
-        }
-
-        // 情况二:有昵称过滤条件时,需要跨模块(Member)过滤
-        // 2.1 查询所有匹配的分销用户
-        List<AppBrokerageUserChildSummaryRespVO> list = brokerageUserMapper.selectSummaryListByUserId(
-                BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus(),
-                bindUserIds, pageReqVO.getSortingField()
-        );
-        if (CollUtil.isEmpty(list)) {
+        // 1.1 查询下级用户编号列表
+        List<Long> childIds = getChildUserIdsByLevel(userId, pageReqVO.getLevel());
+        if (CollUtil.isEmpty(childIds)) {
             return PageResult.empty();
         }
 
-        // 2.2 查出对应的用户信息
-        List<MemberUserRespDTO> users = memberUserApi.getUserList(convertList(list, AppBrokerageUserChildSummaryRespVO::getId));
-        if (CollUtil.isEmpty(users)) {
-            return PageResult.empty();
-        }
-
-        // 2.3 根据昵称过滤出用户编号
-        Map<Long, MemberUserRespDTO> userMap = users.stream()
-                .filter(user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()))
-                .collect(Collectors.toMap(MemberUserRespDTO::getId, dto -> dto));
+        // 1.2 根据昵称过滤下级用户
+        Map<Long, MemberUserRespDTO> userMap = convertMapByFilter(memberUserApi.getUserList(childIds),
+                user -> StrUtil.contains(user.getNickname(), pageReqVO.getNickname()),
+                MemberUserRespDTO::getId);
         if (CollUtil.isEmpty(userMap)) {
             return PageResult.empty();
         }
 
-        // 2.4 根据用户编号过滤结果
-        list.removeIf(vo -> !userMap.containsKey(vo.getId()));
-        if (CollUtil.isEmpty(list)) {
-            return PageResult.empty();
-        }
-
-        // 2.5 处理分页
-        List<AppBrokerageUserChildSummaryRespVO> result = list.stream()
-                .skip((long) (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize())
-                .limit(pageReqVO.getPageSize())
-                .collect(Collectors.toList());
-        if (CollUtil.isEmpty(result)) {
-            return PageResult.empty();
-        }
+        // 2 分页查询
+        IPage<AppBrokerageUserChildSummaryRespVO> pageResult = brokerageUserMapper.selectSummaryPageByUserId(
+                MyBatisUtils.buildPage(pageReqVO), BrokerageRecordBizTypeEnum.ORDER.getType(),
+                BrokerageRecordStatusEnum.SETTLEMENT.getStatus(), userMap.keySet(), pageReqVO.getSortingField()
+        );
 
-        // 2.6 拼接数据并返回
-        BrokerageUserConvert.INSTANCE.copyTo(result, userMap);
-        return new PageResult<>(result, (long) list.size());
+        // 3 拼接数据并返回
+        BrokerageUserConvert.INSTANCE.copyTo(pageResult.getRecords(), userMap);
+        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
     }
 
     private boolean isUserCanBind(BrokerageUserDO user) {
@@ -360,24 +319,35 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
     }
 
     /**
-     * 根据绑定用户编号,获得绑定用户编号列表
+     * 根据绑定用户编号,获得下级用户编号列表
      *
      * @param bindUserId 绑定用户编号
-     * @param level      绑定用户的层级。
+     * @param level      下级用户的层级。
      *                   如果 level 为空,则查询 1+2 两个层级
-     * @return 绑定用户编号列表
+     * @return 下级用户编号列表
      */
-    private List<Long> buildBindUserIdsByLevel(Long bindUserId, Integer level) {
+    private List<Long> getChildUserIdsByLevel(Long bindUserId, Integer level) {
         if (bindUserId == null) {
             return Collections.emptyList();
         }
-        Assert.isTrue(level == null || level <= 2, "目前只支持 level 小于等于 2");
-        List<Long> bindUserIds = CollUtil.newArrayList();
-        if (level == null || level == 1) {
-            bindUserIds.add(bindUserId);
+
+        // 先查第 1 级
+        List<Long> bindUserIds = brokerageUserMapper.selectIdListByBindUserIdIn(Collections.singleton(bindUserId));
+        if (CollUtil.isEmpty(bindUserIds)) {
+            return Collections.emptyList();
         }
-        if (level == null || level == 2) {
-            bindUserIds.addAll(convertList(brokerageUserMapper.selectListByBindUserId(bindUserId), BrokerageUserDO::getId));
+
+        if (level == null) {
+            // level 为空,再查第 2 级,并合并结果
+            bindUserIds.addAll(brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds));
+        } else if (level == 2) {
+            // 只查第 2 级
+            bindUserIds = brokerageUserMapper.selectIdListByBindUserIdIn(bindUserIds);
+        } else if (level == 1) {
+            // 只查第 1 级
+            return bindUserIds;
+        } else {
+            throw exception(BROKERAGE_USER_LEVEL_NOT_SUPPORT);
         }
         return bindUserIds;
     }

+ 7 - 14
yudao-module-mall/yudao-module-trade-biz/src/main/resources/mapper/brokerage/BrokerageUserMapper.xml

@@ -2,7 +2,9 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageUserMapper">
 
-    <sql id="selectSummaryListByUserId">
+    <select id="selectSummaryPageByUserId"
+            resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
+
         SELECT bu.id, bu.bind_user_time AS brokerageTime,
         (SELECT SUM(price) FROM trade_brokerage_record r
         WHERE r.user_id = bu.id AND biz_type = #{bizType} AND r.status = #{status} AND r.deleted = FALSE) AS brokeragePrice,
@@ -13,10 +15,10 @@
         FROM trade_brokerage_user AS bu
         <where>
             bu.deleted = false
-            <if test="bindUserIds != null and bindUserIds.size() > 0">
-                and bu.bind_user_id in
-                <foreach collection="bindUserIds" open="(" item="bindUserId" separator="," close=")">
-                    #{bindUserId}
+            <if test="ids != null and ids.size() > 0">
+                and bu.id in
+                <foreach collection="ids" open="(" item="id" separator="," close=")">
+                    #{id}
                 </foreach>
             </if>
         </where>
@@ -34,15 +36,6 @@
                 ORDER BY bu.bind_user_time DESC
             </otherwise>
         </choose>
-    </sql>
-
-    <select id="selectSummaryPageByUserId"
-            resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
-        <include refid="selectSummaryListByUserId" />
-    </select>
-    <select id="selectSummaryListByUserId"
-            resultType="cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserChildSummaryRespVO">
-        <include refid="selectSummaryListByUserId" />
     </select>
 
 </mapper>

+ 0 - 7
yudao-module-member/yudao-module-member-api/pom.xml

@@ -22,13 +22,6 @@
             <artifactId>yudao-common</artifactId>
         </dependency>
 
-        <!-- TODO @疯狂:biz 引入哈;api 保持低依赖 -->
-        <dependency>
-            <groupId>cn.iocoder.boot</groupId>
-            <artifactId>yudao-spring-boot-starter-mq</artifactId>
-            <scope>compile</scope>
-        </dependency>
-
         <!-- 参数校验 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 1 - 3
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java

@@ -38,11 +38,9 @@ public interface ErrorCodeConstants {
     //========== 签到配置 1-004-009-000 ==========
     ErrorCode SIGN_IN_CONFIG_NOT_EXISTS = new ErrorCode(1_004_009_000, "签到天数规则不存在");
     ErrorCode SIGN_IN_CONFIG_EXISTS = new ErrorCode(1_004_009_001, "签到天数规则已存在");
-    // TODO @疯狂:这个可以用 validator 去做;通过在 BaseVO 里,增加一个 @AssertTrue 注解的方式
-    ErrorCode SIGN_IN_CONFIG_AWARD_EMPTY = new ErrorCode(1_004_009_002, "签到奖励积分和经验不能同时为空");
 
     //========== 签到配置 1-004-010-000 ==========
-    ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000,"今日已签到,请勿重复签到");
+    ErrorCode SIGN_IN_RECORD_TODAY_EXISTS = new ErrorCode(1_004_010_000, "今日已签到,请勿重复签到");
 
     //========== 用户等级 1-004-011-000 ==========
     ErrorCode LEVEL_NOT_EXISTS = new ErrorCode(1_004_011_000, "用户等级不存在");

+ 8 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/signin/vo/config/MemberSignInConfigBaseVO.java

@@ -1,10 +1,13 @@
 package cn.iocoder.yudao.module.member.controller.admin.signin.vo.config;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import javax.validation.constraints.AssertTrue;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.PositiveOrZero;
 
@@ -34,4 +37,9 @@ public class MemberSignInConfigBaseVO {
     @InEnum(CommonStatusEnum.class)
     private Integer status;
 
+    @AssertTrue(message = "签到奖励积分和经验不能同时为空")
+    @JsonIgnore
+    public boolean isConfigAward() {
+        return ObjUtil.notEqual(point, 0) || ObjUtil.notEqual(experience, 0);
+    }
 }

+ 3 - 3
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/RegisterCouponSendMessage.java → yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/message/user/UserCreateMessage.java

@@ -7,13 +7,13 @@ import lombok.EqualsAndHashCode;
 import javax.validation.constraints.NotNull;
 
 /**
- * 新人券发放消息
+ * 会员用户创建消息
  *
  * @author owen
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-public class RegisterCouponSendMessage extends AbstractStreamMessage {
+public class UserCreateMessage extends AbstractStreamMessage {
 
     /**
      * 用户编号
@@ -23,7 +23,7 @@ public class RegisterCouponSendMessage extends AbstractStreamMessage {
 
     @Override
     public String getStreamKey() {
-        return "member.register-coupon.send";
+        return "member.create.send";
     }
 
 }

+ 0 - 32
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/RegisterCouponProducer.java

@@ -1,32 +0,0 @@
-package cn.iocoder.yudao.module.member.mq.producer.user;
-
-import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
-import cn.iocoder.yudao.module.member.mq.message.user.RegisterCouponSendMessage;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-
-// TODO @疯狂:发 UserCreateMessage;解耦,然后优惠劵监听到,去发卷;
-/**
- * 新人券发放 Producer
- *
- * @author owen
- */
-@Slf4j
-@Component
-public class RegisterCouponProducer {
-
-    @Resource
-    private RedisMQTemplate redisMQTemplate;
-
-    /**
-     * 发送 {@link RegisterCouponSendMessage} 消息
-     *
-     * @param userId 用户编号
-     */
-    public void sendMailSendMessage(Long userId) {
-        redisMQTemplate.send(new RegisterCouponSendMessage().setUserId(userId));
-    }
-
-}

+ 31 - 0
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/mq/producer/user/UserCreateProducer.java

@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.member.mq.producer.user;
+
+import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
+import cn.iocoder.yudao.module.member.mq.message.user.UserCreateMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 会员用户创建 Producer
+ *
+ * @author owen
+ */
+@Slf4j
+@Component
+public class UserCreateProducer {
+
+    @Resource
+    private RedisMQTemplate redisMQTemplate;
+
+    /**
+     * 发送 {@link UserCreateMessage} 消息
+     *
+     * @param userId 用户编号
+     */
+    public void sendUserCreateMessage(Long userId) {
+        redisMQTemplate.send(new UserCreateMessage().setUserId(userId));
+    }
+
+}

+ 2 - 13
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/signin/MemberSignInConfigServiceImpl.java

@@ -11,10 +11,10 @@ import org.springframework.validation.annotation.Validated;
 import javax.annotation.Resource;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
+import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_EXISTS;
+import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.SIGN_IN_CONFIG_NOT_EXISTS;
 
 /**
  * 签到规则 Service 实现类
@@ -30,8 +30,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
 
     @Override
     public Long createSignInConfig(MemberSignInConfigCreateReqVO createReqVO) {
-        // 校验奖励积分、奖励经验
-        validatePointAndExperience(createReqVO.getPoint(), createReqVO.getExperience());
         // 判断是否重复插入签到天数
         validateSignInConfigDayDuplicate(createReqVO.getDay(), null);
 
@@ -44,8 +42,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
 
     @Override
     public void updateSignInConfig(MemberSignInConfigUpdateReqVO updateReqVO) {
-        // 校验奖励积分、奖励经验
-        validatePointAndExperience(updateReqVO.getPoint(), updateReqVO.getExperience());
         // 校验存在
         validateSignInConfigExists(updateReqVO.getId());
         // 判断是否重复插入签到天数
@@ -88,13 +84,6 @@ public class MemberSignInConfigServiceImpl implements MemberSignInConfigService
         }
     }
 
-    private void validatePointAndExperience(Integer point, Integer experience) {
-        // 奖励积分、经验 至少要配置一个,否则没有意义
-        if (Objects.equals(point, 0) && Objects.equals(experience, 0)) {
-            throw exception(SIGN_IN_CONFIG_AWARD_EMPTY);
-        }
-    }
-
     @Override
     public MemberSignInConfigDO getSignInConfig(Long id) {
         return memberSignInConfigMapper.selectById(id);

+ 13 - 6
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.service.user;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.BooleanUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
@@ -18,7 +19,7 @@ import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
 import cn.iocoder.yudao.module.member.convert.user.MemberUserConvert;
 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
 import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
-import cn.iocoder.yudao.module.member.mq.producer.user.RegisterCouponProducer;
+import cn.iocoder.yudao.module.member.mq.producer.user.UserCreateProducer;
 import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
@@ -27,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionTemplate;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
@@ -60,7 +62,10 @@ public class MemberUserServiceImpl implements MemberUserService {
     private PasswordEncoder passwordEncoder;
 
     @Resource
-    private RegisterCouponProducer registerCouponProducer;
+    private UserCreateProducer registerCouponProducer;
+
+    @Resource
+    private TransactionTemplate transactionTemplate;
 
     @Override
     public MemberUserDO getUserByMobile(String mobile) {
@@ -92,11 +97,13 @@ public class MemberUserServiceImpl implements MemberUserService {
         user.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
         user.setPassword(encodePassword(password)); // 加密密码
         user.setRegisterIp(registerIp);
-        memberUserMapper.insert(user);
 
-        // 发送 MQ 消息,发放新人券
-        // TODO @疯狂:事务结束后,在发送 MQ 消息;避免出现消息已经发了,事务没提交,或者回滚了
-        registerCouponProducer.sendMailSendMessage(user.getId());
+        Boolean success = transactionTemplate.execute(status -> memberUserMapper.insert(user) > 0);
+        if (BooleanUtil.isTrue(success)) {
+            // 发送 MQ 消息:用户创建
+            registerCouponProducer.sendUserCreateMessage(user.getId());
+        }
+
         return user;
     }