Browse Source

!616 完善分销功能
Merge pull request !616 from 疯狂的世界/brokerate

芋道源码 1 year ago
parent
commit
18c9f22560
25 changed files with 352 additions and 100 deletions
  1. 21 19
      sql/mysql/brokerage.sql
  2. 6 0
      yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
  3. 7 0
      yudao-module-mall/yudao-module-trade-api/pom.xml
  4. 19 1
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java
  5. 39 0
      yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java
  6. 15 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java
  7. 5 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java
  8. 6 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java
  9. 15 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java
  10. 11 9
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java
  11. 9 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java
  12. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java
  13. 6 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java
  14. 1 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java
  15. 20 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java
  16. 10 5
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java
  17. 5 2
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
  18. 16 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java
  19. 9 4
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java
  20. 31 1
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java
  21. 9 0
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java
  22. 19 11
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java
  23. 11 3
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java
  24. 56 37
      yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java
  25. 5 0
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java

+ 21 - 19
sql/mysql/brokerage.sql

@@ -44,24 +44,26 @@ create index idx_agent on trade_brokerage_user (brokerage_enabled) comment '是
 
 
 create table trade_brokerage_record
 create table trade_brokerage_record
 (
 (
-    id            int auto_increment comment '编号'
+    id               int auto_increment comment '编号'
         primary key,
         primary key,
-    user_id       bigint                                                           not null comment '用户编号',
-    biz_id        varchar(64)                            default ''                not null comment '业务编号',
-    biz_type      tinyint                                default 0                 not null comment '业务类型:0-订单,1-提现',
-    title         varchar(64)                            default ''                not null comment '标题',
-    price         int                                    default 0                 not null comment '金额',
-    total_price   int                                    default 0                 not null comment '当前总佣金',
-    description   varchar(500)                           default ''                not null comment '说明',
-    status        tinyint                                default 0                 not null comment '状态:0-待结算,1-已结算,2-已取消',
-    frozen_days   int                                    default 0                 not null comment '冻结时间(天)',
-    unfreeze_time datetime                                                         null comment '解冻时间',
-    creator       varchar(64) collate utf8mb4_general_ci default ''                null comment '创建者',
-    create_time   datetime                               default CURRENT_TIMESTAMP not null comment '创建时间',
-    updater       varchar(64) collate utf8mb4_general_ci default ''                null comment '更新者',
-    update_time   datetime                               default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
-    deleted       bit                                    default b'0'              not null comment '是否删除',
-    tenant_id     bigint                                 default 0                 not null comment '租户编号'
+    user_id          bigint                                                           not null comment '用户编号',
+    biz_id           varchar(64)                            default ''                not null comment '业务编号',
+    biz_type         tinyint                                default 0                 not null comment '业务类型:1-订单,2-提现',
+    title            varchar(64)                            default ''                not null comment '标题',
+    price            int                                    default 0                 not null comment '金额',
+    total_price      int                                    default 0                 not null comment '当前总佣金',
+    description      varchar(500)                           default ''                not null comment '说明',
+    status           tinyint                                default 0                 not null comment '状态:0-待结算,1-已结算,2-已取消',
+    frozen_days      int                                    default 0                 not null comment '冻结时间(天)',
+    unfreeze_time    datetime                                                         null comment '解冻时间',
+    source_user_type tinyint                                                          not null comment '来源用户类型:1-一级推广用户,2-二级推广用户',
+    source_user_id   bigint                                                           not null comment '来源用户编号',
+    creator          varchar(64) collate utf8mb4_general_ci default ''                null comment '创建者',
+    create_time      datetime                               default CURRENT_TIMESTAMP not null comment '创建时间',
+    updater          varchar(64) collate utf8mb4_general_ci default ''                null comment '更新者',
+    update_time      datetime                               default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
+    deleted          bit                                    default b'0'              not null comment '是否删除',
+    tenant_id        bigint                                 default 0                 not null comment '租户编号'
 )
 )
     comment '佣金记录';
     comment '佣金记录';
 
 
@@ -192,9 +194,9 @@ VALUES ('分销用户推广订单查询', 'trade:brokerage-user:order-query', 3,
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
 VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0);
 VALUES ('分销用户修改推广资格', 'trade:brokerage-user:update-brokerage-enable', 3, 4, @parentId, '', '', '', 0);
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
-VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-brokerage-user', 3, 5, @parentId, '', '', '', 0);
+VALUES ('分销用户修改推广员', 'trade:brokerage-user:update-bind-user', 3, 5, @parentId, '', '', '', 0);
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status)
-VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-brokerage-user', 3, 6, @parentId, '', '', '', 0);
+VALUES ('分销用户清除推广员', 'trade:brokerage-user:clear-bind-user', 3, 6, @parentId, '', '', '', 0);
 
 
 -- 增加菜单:佣金记录
 -- 增加菜单:佣金记录
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)
 INSERT INTO system_menu(name, permission, type, sort, parent_id, path, icon, component, status, component_name)

+ 6 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm

@@ -15,6 +15,9 @@ import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}
 import static ${ServiceExceptionUtilClassName}.exception;
 import static ${ServiceExceptionUtilClassName}.exception;
 import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
 import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
 
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+
 /**
 /**
  * ${table.classComment} Service 实现类
  * ${table.classComment} Service 实现类
  *
  *
@@ -61,6 +64,9 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
 
 
     @Override
     @Override
     public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
     public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
+        if (CollUtil.isEmpty(ids)) {
+            return ListUtil.empty();
+        }
         return ${classNameVar}Mapper.selectById(id);
         return ${classNameVar}Mapper.selectById(id);
     }
     }
 
 

+ 7 - 0
yudao-module-mall/yudao-module-trade-api/pom.xml

@@ -21,6 +21,13 @@
             <groupId>cn.iocoder.boot</groupId>
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-common</artifactId>
             <artifactId>yudao-common</artifactId>
         </dependency>
         </dependency>
+
+        <!-- 参数校验 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
     </dependencies>
 
 
 </project>
 </project>

+ 19 - 1
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/api/brokerage/BrokerageApi.java

@@ -1,7 +1,11 @@
 package cn.iocoder.yudao.module.trade.api.brokerage;
 package cn.iocoder.yudao.module.trade.api.brokerage;
 
 
+import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
 import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
 import cn.iocoder.yudao.module.trade.api.brokerage.dto.BrokerageUserDTO;
 
 
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
 /**
 /**
  * 分销 API 接口
  * 分销 API 接口
  *
  *
@@ -17,6 +21,20 @@ public interface BrokerageApi {
      */
      */
     BrokerageUserDTO getBrokerageUser(Long userId);
     BrokerageUserDTO getBrokerageUser(Long userId);
 
 
+    /**
+     * 【会员】绑定推广员
+     *
+     * @param userId       用户编号
+     * @param bindUserId   推广员编号
+     * @param registerTime 用户注册时间
+     * @return 是否绑定
+     */
+    default boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull LocalDateTime registerTime) {
+        // 注册时间在30秒内的,都算新用户
+        boolean isNewUser = LocalDateTimeUtils.afterNow(registerTime.minusSeconds(30));
+        return bindUser(userId, bindUserId, isNewUser);
+    }
+
     /**
     /**
      * 绑定推广员
      * 绑定推广员
      *
      *
@@ -25,5 +43,5 @@ public interface BrokerageApi {
      * @param isNewUser  是否为新用户
      * @param isNewUser  是否为新用户
      * @return 是否绑定
      * @return 是否绑定
      */
      */
-    boolean bindUser(Long userId, Long bindUserId, Boolean isNewUser);
+    boolean bindUser(@NotNull Long userId, @NotNull Long bindUserId, @NotNull Boolean isNewUser);
 }
 }

+ 39 - 0
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/brokerage/BrokerageUserTypeEnum.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.trade.enums.brokerage;
+
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 分销用户类型枚举
+ *
+ * @author owen
+ */
+@AllArgsConstructor
+@Getter
+public enum BrokerageUserTypeEnum implements IntArrayValuable {
+
+    ALL(0, "全部"),
+    FIRST(1, "一级推广人"),
+    SECOND(2, "二级推广人"),
+    ;
+
+    public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(BrokerageUserTypeEnum::getType).toArray();
+
+    /**
+     * 类型
+     */
+    private final Integer type;
+    /**
+     * 名字
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 15 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/BrokerageRecordController.java

@@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record;
 
 
 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.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO;
 import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert;
 import cn.iocoder.yudao.module.trade.convert.brokerage.record.BrokerageRecordConvert;
@@ -19,8 +21,12 @@ import org.springframework.web.bind.annotation.RestController;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
 import javax.validation.Valid;
 import javax.validation.Valid;
+import java.util.Map;
+import java.util.Set;
 
 
 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;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 
 
 @Tag(name = "管理后台 - 佣金记录")
 @Tag(name = "管理后台 - 佣金记录")
 @RestController
 @RestController
@@ -31,6 +37,9 @@ public class BrokerageRecordController {
     @Resource
     @Resource
     private BrokerageRecordService brokerageRecordService;
     private BrokerageRecordService brokerageRecordService;
 
 
+    @Resource
+    private MemberUserApi memberUserApi;
+
     @GetMapping("/get")
     @GetMapping("/get")
     @Operation(summary = "获得佣金记录")
     @Operation(summary = "获得佣金记录")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
@@ -45,7 +54,12 @@ public class BrokerageRecordController {
     @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
     public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
     public CommonResult<PageResult<BrokerageRecordRespVO>> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
         PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
         PageResult<BrokerageRecordDO> pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
-        return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult));
+
+        Set<Long> userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
+        userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
+        Map<Long, MemberUserRespDTO> userMap = memberUserApi.getUserMap(userIds);
+
+        return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
     }
     }
 
 
 }
 }

+ 5 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordBaseVO.java

@@ -57,4 +57,9 @@ public class BrokerageRecordBaseVO {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime unfreezeTime;
     private LocalDateTime unfreezeTime;
 
 
+    @Schema(description = "来源用户类型")
+    private Integer sourceUserType;
+
+    @Schema(description = "来源用户编号")
+    private Long sourceUserId;
 }
 }

+ 6 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordPageReqVO.java

@@ -1,6 +1,8 @@
 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo;
 
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 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.EqualsAndHashCode;
@@ -30,4 +32,8 @@ public class BrokerageRecordPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
     private LocalDateTime[] createTime;
 
 
+    @Schema(description = "用户类型")
+    @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")
+    private Integer sourceUserType;
+
 }
 }

+ 15 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/record/vo/BrokerageRecordRespVO.java

@@ -19,4 +19,19 @@ public class BrokerageRecordRespVO extends BrokerageRecordBaseVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
     private LocalDateTime createTime;
 
 
+
+    // ========== 用户信息 ==========
+
+    @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
+    private String userAvatar;
+    @Schema(description = "用户昵称", example = "李四")
+    private String userNickname;
+
+
+    // ========== 来源用户信息 ==========
+
+    @Schema(description = "来源用户头像", example = "https://www.iocoder.cn/xxx.png")
+    private String sourceUserAvatar;
+    @Schema(description = "来源用户昵称", example = "李四")
+    private String sourceUserNickname;
 }
 }

+ 11 - 9
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/BrokerageUserController.java

@@ -9,8 +9,9 @@ import cn.iocoder.yudao.module.trade.convert.brokerage.user.BrokerageUserConvert
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
-import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
+import cn.iocoder.yudao.module.trade.service.brokerage.record.BrokerageRecordService;
 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
 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;
@@ -42,18 +43,18 @@ public class BrokerageUserController {
     @Resource
     @Resource
     private MemberUserApi memberUserApi;
     private MemberUserApi memberUserApi;
 
 
-    @PutMapping("/update-brokerage-user")
+    @PutMapping("/update-bind-user")
     @Operation(summary = "修改推广员")
     @Operation(summary = "修改推广员")
-    @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-user')")
-    public CommonResult<Boolean> updateBrokerageUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) {
+    @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')")
+    public CommonResult<Boolean> updateBindUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) {
         brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId());
         brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId());
         return success(true);
         return success(true);
     }
     }
 
 
-    @PutMapping("/clear-brokerage-user")
+    @PutMapping("/clear-bind-user")
     @Operation(summary = "清除推广员")
     @Operation(summary = "清除推广员")
-    @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-brokerage-user')")
-    public CommonResult<Boolean> clearBrokerageUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) {
+    @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-bind-user')")
+    public CommonResult<Boolean> clearBindUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) {
         brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null);
         brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null);
         return success(true);
         return success(true);
     }
     }
@@ -72,7 +73,8 @@ public class BrokerageUserController {
     @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
     public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
     public CommonResult<BrokerageUserRespVO> getBrokerageUser(@RequestParam("id") Long id) {
         BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
         BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
-        return success(BrokerageUserConvert.INSTANCE.convert(brokerageUser));
+        BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser);
+        return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id), respVO));
     }
     }
 
 
     @GetMapping("/page")
     @GetMapping("/page")
@@ -94,7 +96,7 @@ public class BrokerageUserController {
         // 合计推广用户数量
         // 合计推广用户数量
         Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
         Map<Long, Long> brokerageUserCountMap = convertMap(userIds,
                 userId -> userId,
                 userId -> userId,
-                userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId));
+                userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, BrokerageUserTypeEnum.ALL));
 
 
         // todo 合计提现
         // todo 合计提现
 
 

+ 9 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserPageReqVO.java

@@ -1,6 +1,8 @@
 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
 package cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo;
 
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 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.EqualsAndHashCode;
@@ -27,4 +29,11 @@ public class BrokerageUserPageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;
     private LocalDateTime[] createTime;
 
 
+    @Schema(description = "用户类型")
+    @InEnum(value = BrokerageUserTypeEnum.class, message = "用户类型必须是 {value}")
+    private Integer userType;
+
+    @Schema(description = "绑定时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] bindUserTime;
 }
 }

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/user/vo/BrokerageUserRespVO.java

@@ -28,7 +28,7 @@ public class BrokerageUserRespVO extends BrokerageUserBaseVO {
 
 
     // ========== 推广信息 ==========
     // ========== 推广信息 ==========
 
 
-    @Schema(description = "推广用户数量(一级)", example = "20019")
+    @Schema(description = "推广用户数量", example = "20019")
     private Integer brokerageUserCount;
     private Integer brokerageUserCount;
     @Schema(description = "推广订单数量", example = "20019")
     @Schema(description = "推广订单数量", example = "20019")
     private Integer brokerageOrderCount;
     private Integer brokerageOrderCount;

+ 6 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/AppBrokerageRecordController.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageProductPriceRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.record.AppBrokerageRecordRespVO;
+import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
 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 lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
@@ -15,10 +16,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.RestController;
 
 
+import javax.annotation.Resource;
 import javax.validation.Valid;
 import javax.validation.Valid;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 
 
 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.web.core.util.WebFrameworkUtils.getLoginUserId;
 import static java.util.Arrays.asList;
 import static java.util.Arrays.asList;
 
 
 @Tag(name = "用户 APP - 分销用户")
 @Tag(name = "用户 APP - 分销用户")
@@ -27,6 +30,8 @@ import static java.util.Arrays.asList;
 @Validated
 @Validated
 @Slf4j
 @Slf4j
 public class AppBrokerageRecordController {
 public class AppBrokerageRecordController {
+    @Resource
+    private BrokerageUserService brokerageUserService;
 
 
     // TODO 芋艿:临时 mock =>
     // TODO 芋艿:临时 mock =>
     @GetMapping("/page")
     @GetMapping("/page")
@@ -46,7 +51,7 @@ public class AppBrokerageRecordController {
     @Operation(summary = "获得商品的分销金额")
     @Operation(summary = "获得商品的分销金额")
     public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {
     public CommonResult<AppBrokerageProductPriceRespVO> getProductBrokeragePrice(@RequestParam("spuId") Long spuId) {
         AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO();
         AppBrokerageProductPriceRespVO respVO = new AppBrokerageProductPriceRespVO();
-        respVO.setEnabled(true); // TODO @疯狂:需要开启分销 + 人允许分销
+        respVO.setEnabled(brokerageUserService.getUserBrokerageEnabled(getLoginUserId()));
         respVO.setBrokerageMinPrice(1);
         respVO.setBrokerageMinPrice(1);
         respVO.setBrokerageMaxPrice(2);
         respVO.setBrokerageMaxPrice(2);
         return success(respVO);
         return success(respVO);

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/brokerage/vo/user/AppBrokerageUserMySummaryRespVO.java

@@ -19,7 +19,7 @@ public class AppBrokerageUserMySummaryRespVO {
     @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
     @Schema(description = "冻结的佣金,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "234")
     private Integer frozenPrice;
     private Integer frozenPrice;
 
 
-    @Schema(description = "分销用户数量(一级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    @Schema(description = "分销用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
     private Integer firstBrokerageUserCount;
     private Integer firstBrokerageUserCount;
 
 
     @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
     @Schema(description = "分销用户数量(二级)", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")

+ 20 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/record/BrokerageRecordConvert.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.convert.brokerage.record;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordRespVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
@@ -13,6 +14,8 @@ import org.mapstruct.factory.Mappers;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 
 /**
 /**
  * 佣金记录 Convert
  * 佣金记录 Convert
@@ -30,10 +33,9 @@ public interface BrokerageRecordConvert {
 
 
     PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page);
     PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> page);
 
 
-    // TODO @疯狂:可能 title 不是很固化,会存在类似:沐晴成功购买《XXX JVM 实战》
     default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
     default BrokerageRecordDO convert(BrokerageUserDO user, BrokerageRecordBizTypeEnum bizType, String bizId,
                                       Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
                                       Integer brokerageFrozenDays, int brokeragePrice, LocalDateTime unfreezeTime,
-                                      String title) {
+                                      String title, Long sourceUserId, Integer sourceUserType) {
         brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
         brokerageFrozenDays = ObjectUtil.defaultIfNull(brokerageFrozenDays, 0);
         // 不冻结时,佣金直接就是结算状态
         // 不冻结时,佣金直接就是结算状态
         Integer status = brokerageFrozenDays > 0
         Integer status = brokerageFrozenDays > 0
@@ -43,8 +45,22 @@ public interface BrokerageRecordConvert {
                 .setBizType(bizType.getType()).setBizId(bizId)
                 .setBizType(bizType.getType()).setBizId(bizId)
                 .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice())
                 .setPrice(brokeragePrice).setTotalPrice(user.getBrokeragePrice())
                 .setTitle(title)
                 .setTitle(title)
-                .setDescription(StrUtil.format(bizType.getDescription(), String.valueOf(brokeragePrice / 100.0)))
-                .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime);
+                .setDescription(StrUtil.format(bizType.getDescription(), String.format("¥%.2f", brokeragePrice / 100d)))
+                .setStatus(status).setFrozenDays(brokerageFrozenDays).setUnfreezeTime(unfreezeTime)
+                .setSourceUserType(sourceUserType).setSourceUserId(sourceUserId);
     }
     }
 
 
+    default PageResult<BrokerageRecordRespVO> convertPage(PageResult<BrokerageRecordDO> pageResult, Map<Long, MemberUserRespDTO> userMap) {
+        PageResult<BrokerageRecordRespVO> result = convertPage(pageResult);
+
+        for (BrokerageRecordRespVO respVO : result.getList()) {
+            Optional.ofNullable(userMap.get(respVO.getUserId())).ifPresent(user ->
+                    respVO.setUserNickname(user.getNickname()).setUserAvatar(user.getAvatar()));
+
+            Optional.ofNullable(userMap.get(respVO.getSourceUserId())).ifPresent(user ->
+                    respVO.setSourceUserNickname(user.getNickname()).setSourceUserAvatar(user.getAvatar()));
+        }
+
+        return result;
+    }
 }
 }

+ 10 - 5
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/brokerage/user/BrokerageUserConvert.java

@@ -37,20 +37,25 @@ public interface BrokerageUserConvert {
         PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
         PageResult<BrokerageUserRespVO> result = convertPage(pageResult);
         for (BrokerageUserRespVO vo : result.getList()) {
         for (BrokerageUserRespVO vo : result.getList()) {
             // 用户信息
             // 用户信息
-            Optional.ofNullable(userMap.get(vo.getId())).ifPresent(
-                    user -> vo.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
-            // 推广用户数量(一级)
+            copyTo(userMap.get(vo.getId()), vo);
+
+            // 推广用户数量
             vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0));
             vo.setBrokerageUserCount(MapUtil.getInt(brokerageUserCountMap, vo.getId(), 0));
             // 推广订单数量、推广订单金额
             // 推广订单数量、推广订单金额
             Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));
             Optional<UserBrokerageSummaryBO> orderSummaryOptional = Optional.ofNullable(userOrderSummaryMap.get(vo.getId()));
             vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
             vo.setBrokerageOrderCount(orderSummaryOptional.map(UserBrokerageSummaryBO::getCount).orElse(0))
                     .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
                     .setBrokerageOrderPrice(orderSummaryOptional.map(UserBrokerageSummaryBO::getPrice).orElse(0));
             // todo 已提现次数、已提现金额
             // todo 已提现次数、已提现金额
-            vo.setWithdrawCount(0);
-            vo.setWithdrawPrice(0);
+            vo.setWithdrawCount(0).setWithdrawPrice(0);
         }
         }
         return result;
         return result;
     }
     }
 
 
+    default BrokerageUserRespVO copyTo(MemberUserRespDTO source, BrokerageUserRespVO target) {
+        Optional.ofNullable(source).ifPresent(
+                user -> target.setNickname(user.getNickname()).setAvatar(user.getAvatar()));
+        return target;
+    }
+
     BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser);
     BrokerageUserDTO convertDTO(BrokerageUserDO brokerageUser);
 }
 }

+ 5 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java

@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.common.util.string.StrUtils;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
-import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
 import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
@@ -28,9 +27,11 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum;
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
 import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
+import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
 import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
 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 org.mapstruct.Mapper;
 import org.mapstruct.Mapper;
@@ -279,8 +280,10 @@ public interface TradeOrderConvert {
 
 
     default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
     default BrokerageAddReqBO convert(TradeOrderItemDO item, ProductSkuRespDTO sku) {
         return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))
         return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId()))
+                .setSourceUserId(item.getUserId())
                 .setBasePrice(item.getPayPrice() * item.getCount())
                 .setBasePrice(item.getPayPrice() * item.getCount())
                 .setFirstFixedPrice(sku.getSubCommissionFirstPrice())
                 .setFirstFixedPrice(sku.getSubCommissionFirstPrice())
-                .setSecondFixedPrice(sku.getSubCommissionSecondPrice());
+                .setSecondFixedPrice(sku.getSubCommissionSecondPrice())
+                .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle());
     }
     }
 }
 }

+ 16 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/brokerage/record/BrokerageRecordDO.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -32,6 +33,8 @@ public class BrokerageRecordDO extends BaseDO {
     private Integer id;
     private Integer id;
     /**
     /**
      * 用户编号
      * 用户编号
+     * <p>
+     * 关联 MemberUserDO.id
      */
      */
     private Long userId;
     private Long userId;
     /**
     /**
@@ -79,4 +82,17 @@ public class BrokerageRecordDO extends BaseDO {
      */
      */
     private LocalDateTime unfreezeTime;
     private LocalDateTime unfreezeTime;
 
 
+    /**
+     * 来源用户类型
+     * <p>
+     * 枚举 {@link BrokerageUserTypeEnum}
+     */
+    private Integer sourceUserType;
+    /**
+     * 来源用户编号
+     * <p>
+     * 关联 MemberUserDO.id
+     */
+    private Long sourceUserId;
+
 }
 }

+ 9 - 4
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/record/BrokerageRecordMapper.java

@@ -5,6 +5,7 @@ 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;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.record.vo.BrokerageRecordPageReqVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.record.BrokerageRecordDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;
@@ -23,10 +24,14 @@ import java.util.List;
 public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
 public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
 
 
     default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
     default PageResult<BrokerageRecordDO> selectPage(BrokerageRecordPageReqVO reqVO) {
+        boolean sourceUserTypeCondition = reqVO.getSourceUserType() != null &&
+                !BrokerageUserTypeEnum.ALL.getType().equals(reqVO.getSourceUserType());
+
         return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
         return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageRecordDO>()
                 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
                 .eqIfPresent(BrokerageRecordDO::getUserId, reqVO.getUserId())
                 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
                 .eqIfPresent(BrokerageRecordDO::getBizType, reqVO.getBizType())
                 .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
                 .eqIfPresent(BrokerageRecordDO::getStatus, reqVO.getStatus())
+                .eq(sourceUserTypeCondition, BrokerageRecordDO::getSourceUserType, reqVO.getSourceUserType())
                 .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
                 .betweenIfPresent(BrokerageRecordDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(BrokerageRecordDO::getId));
                 .orderByDesc(BrokerageRecordDO::getId));
     }
     }
@@ -43,13 +48,13 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
                 .eq(BrokerageRecordDO::getStatus, status));
                 .eq(BrokerageRecordDO::getStatus, status));
     }
     }
 
 
-    default BrokerageRecordDO selectByBizTypeAndBizId(Integer bizType, String bizId) {
+    default BrokerageRecordDO selectByBizTypeAndBizIdAndUserId(Integer bizType, String bizId, Long userId) {
         return selectOne(BrokerageRecordDO::getBizType, bizType,
         return selectOne(BrokerageRecordDO::getBizType, bizType,
-                BrokerageRecordDO::getBizId, bizId);
+                BrokerageRecordDO::getBizId, bizId,
+                BrokerageRecordDO::getUserId, userId);
     }
     }
 
 
-    // TODO @疯狂:mysql 关键字,大写哈;这样看起来清晰点;例如说 SELECT COUNT(1)
-    @Select("select count(1), sum(price) from trade_brokerage_record where user_id = #{userId} and biz_type = #{bizType} and status = #{status}")
+    @Select("SELECT COUNT(1), SUM(price) FROM trade_brokerage_record WHERE user_id = #{userId} AND biz_type = #{bizType} AND status = #{status}")
     UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
     UserBrokerageSummaryBO selectCountAndSumPriceByUserIdAndBizTypeAndStatus(@Param("userId") Long userId,
                                                                              @Param("bizType") Integer bizType,
                                                                              @Param("bizType") Integer bizType,
                                                                              @Param("status") Integer status);
                                                                              @Param("status") Integer status);

+ 31 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/brokerage/user/BrokerageUserMapper.java

@@ -1,13 +1,17 @@
 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
 package cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user;
 
 
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.StrUtil;
 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;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
 
 
 /**
 /**
  * 分销用户 Mapper
  * 分销用户 Mapper
@@ -19,12 +23,32 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
 
 
     default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) {
     default PageResult<BrokerageUserDO> selectPage(BrokerageUserPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
         return selectPage(reqVO, new LambdaQueryWrapperX<BrokerageUserDO>()
-                .eqIfPresent(BrokerageUserDO::getBindUserId, reqVO.getBindUserId())
                 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
                 .eqIfPresent(BrokerageUserDO::getBrokerageEnabled, reqVO.getBrokerageEnabled())
                 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
                 .betweenIfPresent(BrokerageUserDO::getCreateTime, reqVO.getCreateTime())
+                .betweenIfPresent(BrokerageUserDO::getBindUserTime, reqVO.getBindUserTime())
+                .and(reqVO.getBindUserId() != null, w -> buildBindUserCondition(reqVO, w))
                 .orderByDesc(BrokerageUserDO::getId));
                 .orderByDesc(BrokerageUserDO::getId));
     }
     }
 
 
+    static void buildBindUserCondition(BrokerageUserPageReqVO reqVO, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
+        if (BrokerageUserTypeEnum.FIRST.getType().equals(reqVO.getUserType())) {
+            buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
+        } else if (BrokerageUserTypeEnum.SECOND.getType().equals(reqVO.getUserType())) {
+            buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper);
+        } else {
+            buildFirstBindUserCondition(reqVO.getBindUserId(), wrapper);
+            buildSecondBindUserCondition(reqVO.getBindUserId(), wrapper.or());
+        }
+    }
+
+    static void buildFirstBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> wrapper) {
+        wrapper.eq(BrokerageUserDO::getBindUserId, bindUserId);
+    }
+
+    static void buildSecondBindUserCondition(Long bindUserId, LambdaQueryWrapper<BrokerageUserDO> w) {
+        w.inSql(BrokerageUserDO::getBindUserId, StrUtil.format("SELECT id FROM trade_brokerage_user WHERE bind_user_id = {}", bindUserId));
+    }
+
     /**
     /**
      * 更新用户可用佣金(增加)
      * 更新用户可用佣金(增加)
      *
      *
@@ -112,4 +136,10 @@ public interface BrokerageUserMapper extends BaseMapperX<BrokerageUserDO> {
                 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
                 .set(BrokerageUserDO::getBrokerageEnabled, false).set(BrokerageUserDO::getBrokerageTime, null));
     }
     }
 
 
+    default Long selectCountByBindUserId(Long bindUserId) {
+        return selectCount(BrokerageUserDO::getBindUserId, bindUserId);
+    }
+
+    @Select("SELECT COUNT(1) from trade_brokerage_user WHERE bind_user_id IN (SELECT id FROM trade_brokerage_user WHERE bind_user_id = #{bindUserId})")
+    Long selectCountByBindUserIdInBindUserId(Long bindUserId);
 }
 }

+ 9 - 0
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/bo/BrokerageAddReqBO.java

@@ -36,4 +36,13 @@ public class BrokerageAddReqBO {
      */
      */
     private Integer secondFixedPrice;
     private Integer secondFixedPrice;
 
 
+    /**
+     * 来源用户编号
+     */
+    private Long sourceUserId;
+
+    /**
+     * 佣金记录标题
+     */
+    private String title;
 }
 }

+ 19 - 11
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/record/BrokerageRecordServiceImpl.java

@@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.record.BrokerageRecordMapper;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageAddReqBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryBO;
 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
 import cn.iocoder.yudao.module.trade.service.brokerage.user.BrokerageUserService;
@@ -27,7 +28,6 @@ import javax.annotation.Resource;
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
-import java.util.function.Function;
 
 
 /**
 /**
  * 佣金记录 Service 实现类
  * 佣金记录 Service 实现类
@@ -72,7 +72,8 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
             return;
             return;
         }
         }
         // 1.2 计算一级分佣
         // 1.2 计算一级分佣
-        addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(), BrokerageAddReqBO::getFirstFixedPrice, bizType);
+        addBrokerage(firstUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageFirstPercent(),
+                bizType, BrokerageUserTypeEnum.FIRST);
 
 
         // 2.1 获得二级推广员
         // 2.1 获得二级推广员
         if (firstUser.getBindUserId() == null) {
         if (firstUser.getBindUserId() == null) {
@@ -83,15 +84,15 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
             return;
             return;
         }
         }
         // 2.2 计算二级分佣
         // 2.2 计算二级分佣
-        addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(), BrokerageAddReqBO::getSecondFixedPrice, bizType);
+        addBrokerage(secondUser, list, memberConfig.getBrokerageFrozenDays(), memberConfig.getBrokerageSecondPercent(),
+                bizType, BrokerageUserTypeEnum.SECOND);
     }
     }
 
 
     @Override
     @Override
     @Transactional(rollbackFor = Exception.class)
     @Transactional(rollbackFor = Exception.class)
     public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) {
     public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) {
-        // TODO @疯狂:userId 加进去查询,会不会更好一点?万一穿错参数;
-        BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizId(bizType.getType(), bizId);
-        if (record == null || ObjectUtil.notEqual(record.getUserId(), userId)) {
+        BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizIdAndUserId(bizType.getType(), bizId, userId);
+        if (record == null) {
             log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
             log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId);
             return;
             return;
         }
         }
@@ -139,12 +140,11 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
      * @param list                佣金增加参数列表
      * @param list                佣金增加参数列表
      * @param brokerageFrozenDays 冻结天数
      * @param brokerageFrozenDays 冻结天数
      * @param brokeragePercent    佣金比例
      * @param brokeragePercent    佣金比例
-     * @param fixedPriceFun       固定佣金 // TODO 疯狂:这里是不是可以直接传递 fixedPrice 呀?
      * @param bizType             业务类型
      * @param bizType             业务类型
+     * @param sourceUserType      来源用户类型
      */
      */
     private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
     private void addBrokerage(BrokerageUserDO user, List<BrokerageAddReqBO> list, Integer brokerageFrozenDays,
-                              Integer brokeragePercent, Function<BrokerageAddReqBO, Integer> fixedPriceFun,
-                              BrokerageRecordBizTypeEnum bizType) {
+                              Integer brokeragePercent, BrokerageRecordBizTypeEnum bizType, BrokerageUserTypeEnum sourceUserType) {
         // 1.1 处理冻结时间
         // 1.1 处理冻结时间
         LocalDateTime unfreezeTime = null;
         LocalDateTime unfreezeTime = null;
         if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
         if (brokerageFrozenDays != null && brokerageFrozenDays > 0) {
@@ -154,12 +154,20 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
         int totalBrokerage = 0;
         int totalBrokerage = 0;
         List<BrokerageRecordDO> records = new ArrayList<>();
         List<BrokerageRecordDO> records = new ArrayList<>();
         for (BrokerageAddReqBO item : list) {
         for (BrokerageAddReqBO item : list) {
-            int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPriceFun.apply(item));
+            Integer fixedPrice = 0;
+            if (BrokerageUserTypeEnum.FIRST.equals(sourceUserType)) {
+                fixedPrice = item.getFirstFixedPrice();
+            } else if (BrokerageUserTypeEnum.SECOND.equals(sourceUserType)) {
+                fixedPrice = item.getSecondFixedPrice();
+            }
+
+            int brokeragePerItem = calculatePrice(item.getBasePrice(), brokeragePercent, fixedPrice);
             if (brokeragePerItem <= 0) {
             if (brokeragePerItem <= 0) {
                 continue;
                 continue;
             }
             }
             records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
             records.add(BrokerageRecordConvert.INSTANCE.convert(user, bizType, item.getBizId(),
-                    brokerageFrozenDays, brokeragePerItem, unfreezeTime, bizType.getTitle()));
+                    brokerageFrozenDays, brokeragePerItem, unfreezeTime, item.getTitle(),
+                    item.getSourceUserId(), sourceUserType.getType()));
             totalBrokerage += brokeragePerItem;
             totalBrokerage += brokeragePerItem;
         }
         }
         if (CollUtil.isEmpty(records)) {
         if (CollUtil.isEmpty(records)) {

+ 11 - 3
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserService.java

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.brokerage.user;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.user.vo.BrokerageUserPageReqVO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.user.BrokerageUserDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 
 
 import java.util.Collection;
 import java.util.Collection;
 import java.util.List;
 import java.util.List;
@@ -86,14 +87,14 @@ public interface BrokerageUserService {
      */
      */
     void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice);
     void updateFrozenPriceDecrAndPriceIncr(Long id, Integer frozenPrice);
 
 
-    // TODO @疯狂:这个后面可能要支持下,二级
     /**
     /**
-     * 获得推广用户数量(一级)
+     * 获得推广用户数量
      *
      *
      * @param bindUserId 绑定的推广员编号
      * @param bindUserId 绑定的推广员编号
+     * @param userType   用户类型
      * @return 推广用户数量
      * @return 推广用户数量
      */
      */
-    Long getBrokerageUserCountByBindUserId(Long bindUserId);
+    Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType);
 
 
     /**
     /**
      * 【会员】绑定推广员
      * 【会员】绑定推广员
@@ -105,4 +106,11 @@ public interface BrokerageUserService {
      */
      */
     boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser);
     boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser);
 
 
+    /**
+     * 获取用户是否有分销资格
+     *
+     * @param userId 用户编号
+     * @return 是否有分销资格
+     */
+    Boolean getUserBrokerageEnabled(Long userId);
 }
 }

+ 56 - 37
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/user/BrokerageUserServiceImpl.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper;
 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.user.BrokerageUserMapper;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageUserTypeEnum;
 import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
 import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
@@ -56,7 +57,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
     @Override
     @Override
     public void updateBrokerageUserId(Long id, Long bindUserId) {
     public void updateBrokerageUserId(Long id, Long bindUserId) {
         // 校验存在
         // 校验存在
-        validateBrokerageUserExists(id);
+        BrokerageUserDO brokerageUser = validateBrokerageUserExists(id);
 
 
         // 情况一:清除推广员
         // 情况一:清除推广员
         if (bindUserId == null) {
         if (bindUserId == null) {
@@ -66,7 +67,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         }
         }
 
 
         // 情况二:修改推广员
         // 情况二:修改推广员
-        // TODO @疯狂:要复用一些 validateCanBindUser 的校验哈;
+        validateCanBindUser(brokerageUser, bindUserId);
         brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
         brokerageUserMapper.updateById(new BrokerageUserDO().setId(id)
                 .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
                 .setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now()));
     }
     }
@@ -85,10 +86,13 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         }
         }
     }
     }
 
 
-    private void validateBrokerageUserExists(Long id) {
-        if (brokerageUserMapper.selectById(id) == null) {
+    private BrokerageUserDO validateBrokerageUserExists(Long id) {
+        BrokerageUserDO brokerageUserDO = brokerageUserMapper.selectById(id);
+        if (brokerageUserDO == null) {
             throw exception(BROKERAGE_USER_NOT_EXISTS);
             throw exception(BROKERAGE_USER_NOT_EXISTS);
         }
         }
+
+        return brokerageUserDO;
     }
     }
 
 
     @Override
     @Override
@@ -128,19 +132,23 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
     }
     }
 
 
     @Override
     @Override
-    public Long getBrokerageUserCountByBindUserId(Long bindUserId) {
-        // TODO @疯狂:mapper 封装下哈;不直接在 service 调用这种基础 mapper 的基础方法
-        return brokerageUserMapper.selectCount(BrokerageUserDO::getBindUserId, bindUserId);
+    public Long getBrokerageUserCountByBindUserId(Long bindUserId, BrokerageUserTypeEnum userType) {
+        switch (userType) {
+            case ALL:
+                Long firstCount = brokerageUserMapper.selectCountByBindUserId(bindUserId);
+                Long secondCount = brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
+                return firstCount + secondCount;
+            case FIRST:
+                return brokerageUserMapper.selectCountByBindUserId(bindUserId);
+            case SECOND:
+                return brokerageUserMapper.selectCountByBindUserIdInBindUserId(bindUserId);
+            default:
+                return 0L;
+        }
     }
     }
 
 
-    // TODO @疯狂:因为现在 user 会存在使用验证码直接注册,所以 isNewUser 不太好传递;我们是不是可以约定绑定的时间,createTime 在 30 秒内,就认为新用户;
     @Override
     @Override
     public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) {
     public boolean bindBrokerageUser(Long userId, Long bindUserId, Boolean isNewUser) {
-        // TODO @疯狂:userId 为空,搞到参数校验里哇;
-        if (userId == null) {
-            throw exception(0);
-        }
-
         // 1. 获得分销用户
         // 1. 获得分销用户
         boolean isNewBrokerageUser = false;
         boolean isNewBrokerageUser = false;
         BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId);
         BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(userId);
@@ -149,20 +157,20 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
             brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0);
             brokerageUser = new BrokerageUserDO().setId(userId).setBrokerageEnabled(false).setBrokeragePrice(0).setFrozenPrice(0);
         }
         }
 
 
-        // 2.1 校验能绑定
-        boolean validated = validateCanBindUser(brokerageUser, bindUserId, isNewUser);
+        // 2.1 校验是否能绑定用户
+        boolean validated = isUserCanBind(brokerageUser, isNewUser);
         if (!validated) {
         if (!validated) {
             return false;
             return false;
         }
         }
-
-        // 2.2 绑定用户
+        // 2.3 校验能否绑定
+        validateCanBindUser(brokerageUser, bindUserId);
+        // 2.3 绑定用户
         if (isNewBrokerageUser) {
         if (isNewBrokerageUser) {
             Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
             Integer enabledCondition = tradeConfigService.getTradeConfig().getBrokerageEnabledCondition();
             if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格
             if (BrokerageEnabledConditionEnum.ALL.getCondition().equals(enabledCondition)) { // 人人分销:用户默认就有分销资格
-                // TODO @疯狂:应该设置下 brokerageTime,而不是 bindUserTime
-                brokerageUser.setBrokerageEnabled(true).setBindUserTime(LocalDateTime.now());
+                brokerageUser.setBrokerageEnabled(true).setBrokerageTime(LocalDateTime.now());
             }
             }
-            // TODO @疯狂:这里是不是要设置 bindUserId、bindUserTime 字段哈;
+            brokerageUser.setBindUserId(bindUserId).setBindUserTime(LocalDateTime.now());
             brokerageUserMapper.insert(brokerageUser);
             brokerageUserMapper.insert(brokerageUser);
         } else {
         } else {
             brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
             brokerageUserMapper.updateById(new BrokerageUserDO().setId(userId)
@@ -171,30 +179,27 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
         return true;
         return true;
     }
     }
 
 
-    // TODO @疯狂:validate 方法,一般不返回 true false,而是抛出异常;如果要返回 true false 这种,方法名字可以改成 isUserCanBind
-    private boolean validateCanBindUser(BrokerageUserDO user, Long bindUserId, Boolean isNewUser) {
-        // TODO @疯狂:bindUserId 为空,搞到参数校验里哇;
-        if (bindUserId == null) {
+    @Override
+    public Boolean getUserBrokerageEnabled(Long userId) {
+        // 全局分销功能是否开启
+        TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
+        if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
             return false;
             return false;
         }
         }
 
 
+        // 用户是否有分销资格
+        return Optional.ofNullable(getBrokerageUser(userId))
+                .map(BrokerageUserDO::getBrokerageEnabled)
+                .orElse(false);
+    }
+
+    private boolean isUserCanBind(BrokerageUserDO user, Boolean isNewUser) {
         // 校验分销功能是否启用
         // 校验分销功能是否启用
         TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
         TradeConfigDO tradeConfig = tradeConfigService.getTradeConfig();
-        if (tradeConfig == null || BooleanUtil.isFalse(tradeConfig.getBrokerageEnabled())) {
+        if (tradeConfig == null || !BooleanUtil.isTrue(tradeConfig.getBrokerageEnabled())) {
             return false;
             return false;
         }
         }
 
 
-        // 校验绑定自己
-        if (Objects.equals(user.getId(), bindUserId)) {
-            throw exception(BROKERAGE_BIND_SELF);
-        }
-
-        // 校验要绑定的用户有无推广资格
-        BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId);
-        if (bindUser == null || BooleanUtil.isFalse(bindUser.getBrokerageEnabled())) {
-            throw exception(BROKERAGE_BIND_USER_NOT_ENABLED);
-        }
-
         // 校验分佣模式:仅可后台手动设置推广员
         // 校验分佣模式:仅可后台手动设置推广员
         if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) {
         if (BrokerageEnabledConditionEnum.ADMIN.getCondition().equals(tradeConfig.getBrokerageEnabledCondition())) {
             throw exception(BROKERAGE_BIND_CONDITION_ADMIN);
             throw exception(BROKERAGE_BIND_CONDITION_ADMIN);
@@ -211,12 +216,26 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
             }
             }
         }
         }
 
 
+        return true;
+    }
+
+    private void validateCanBindUser(BrokerageUserDO user, Long bindUserId) {
+        // 校验要绑定的用户有无推广资格
+        BrokerageUserDO bindUser = brokerageUserMapper.selectById(bindUserId);
+        if (bindUser == null || !BooleanUtil.isTrue(bindUser.getBrokerageEnabled())) {
+            throw exception(BROKERAGE_BIND_USER_NOT_ENABLED);
+        }
+
+        // 校验绑定自己
+        if (Objects.equals(user.getId(), bindUserId)) {
+            throw exception(BROKERAGE_BIND_SELF);
+        }
+
         // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈
         // TODO @疯狂:这块是不是一直查询到根节点,中间不允许出现自己;就是不能形成环。虽然目前是 2 级,但是未来可能会改多级; = = 环的话,就会存在问题哈
         // A->B->A:下级不能绑定自己的上级,   A->B->C->A可以!!
         // A->B->A:下级不能绑定自己的上级,   A->B->C->A可以!!
         if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
         if (Objects.equals(user.getId(), bindUser.getBindUserId())) {
             throw exception(BROKERAGE_BIND_LOOP);
             throw exception(BROKERAGE_BIND_LOOP);
         }
         }
-        return true;
     }
     }
 
 
 }
 }

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

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.member.service.user;
 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.IdUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
@@ -103,6 +105,9 @@ public class MemberUserServiceImpl implements MemberUserService {
 
 
     @Override
     @Override
     public List<MemberUserDO> getUserList(Collection<Long> ids) {
     public List<MemberUserDO> getUserList(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return ListUtil.empty();
+        }
         return memberUserMapper.selectBatchIds(ids);
         return memberUserMapper.selectBatchIds(ids);
     }
     }