From d13bd60a84b350c235d592aaec5e8f9752117d33 Mon Sep 17 00:00:00 2001 From: chen-xin-zhi <3588068430@qq.com> Date: Sun, 13 Jul 2025 11:37:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E6=9F=A5=E7=9C=8B=E6=8A=BD=E4=BD=A3=E6=AF=94=E4=BE=8B?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/config/RedisConfig.java | 7 +- .../UserPerformanceSummaryController.java | 214 ++++++++++++++---- .../EmployeePromotionRecordsMapper.java | 18 ++ .../RakeRewardsQueryRequest.java | 30 +++ .../RakeRewardsUpdateRequest.java | 40 ++++ .../CoursePromotionCommissionPending.java | 20 ++ .../entity/EmployeePromotionRecords.java | 64 ++++++ .../promotion/model/enums/CourseTypeEnum.java | 3 +- .../StaffPerformanceSummaryVO.java | 56 +++++ .../SupervisorPerformanceSummaryVO.java | 68 ++++++ .../EmployeePromotionRecordsService.java | 13 ++ .../UserPerformanceSummaryService.java | 24 ++ .../EmployeePromotionRecordsServiceImpl.java | 22 ++ .../userInfo/impl/UserInfoServiceImpl.java | 25 +- .../UserPerformanceSummaryServiceImpl.java | 51 +++++ .../wechat/impl/WechatPayServiceImpl.java | 63 +++--- .../mapper/EmployeePromotionRecordsMapper.xml | 22 ++ 17 files changed, 658 insertions(+), 82 deletions(-) create mode 100644 src/main/java/com/greenorange/promotion/mapper/EmployeePromotionRecordsMapper.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsQueryRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsUpdateRequest.java create mode 100644 src/main/java/com/greenorange/promotion/model/entity/EmployeePromotionRecords.java create mode 100644 src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/StaffPerformanceSummaryVO.java create mode 100644 src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/SupervisorPerformanceSummaryVO.java create mode 100644 src/main/java/com/greenorange/promotion/service/userInfo/EmployeePromotionRecordsService.java create mode 100644 src/main/java/com/greenorange/promotion/service/userInfo/impl/EmployeePromotionRecordsServiceImpl.java create mode 100644 src/main/resources/mapper/EmployeePromotionRecordsMapper.xml diff --git a/src/main/java/com/greenorange/promotion/config/RedisConfig.java b/src/main/java/com/greenorange/promotion/config/RedisConfig.java index 74202a9..e4b6dc9 100644 --- a/src/main/java/com/greenorange/promotion/config/RedisConfig.java +++ b/src/main/java/com/greenorange/promotion/config/RedisConfig.java @@ -18,8 +18,13 @@ public class RedisConfig { // 指定kv的序列化方式 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); - redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + // 普通 KV 用 JSON 序列化 value,用字符串序列化 key redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + + // Hash 类型:hashKey 用字符串序列化,hashValue 也用字符串 + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new StringRedisSerializer()); return redisTemplate; } diff --git a/src/main/java/com/greenorange/promotion/controller/userInfo/UserPerformanceSummaryController.java b/src/main/java/com/greenorange/promotion/controller/userInfo/UserPerformanceSummaryController.java index 062ecb4..526de45 100644 --- a/src/main/java/com/greenorange/promotion/controller/userInfo/UserPerformanceSummaryController.java +++ b/src/main/java/com/greenorange/promotion/controller/userInfo/UserPerformanceSummaryController.java @@ -1,19 +1,29 @@ package com.greenorange.promotion.controller.userInfo; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.hash.Hash; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.greenorange.promotion.annotation.RequiresPermission; import com.greenorange.promotion.common.BaseResponse; import com.greenorange.promotion.common.ResultUtils; import com.greenorange.promotion.constant.OrderStatusConstant; +import com.greenorange.promotion.constant.SystemConstant; import com.greenorange.promotion.constant.UserConstant; +import com.greenorange.promotion.model.dto.CommonStringRequest; import com.greenorange.promotion.model.dto.userPerformanceSummary.*; -import com.greenorange.promotion.model.entity.CourseOrder; -import com.greenorange.promotion.model.entity.UserInfo; -import com.greenorange.promotion.model.entity.UserPerformanceSummary; +import com.greenorange.promotion.model.entity.*; +import com.greenorange.promotion.model.enums.CommissionStatusEnum; +import com.greenorange.promotion.model.enums.UserRoleEnum; import com.greenorange.promotion.model.vo.courseOrder.CourseOrderBaseInfoVO; +import com.greenorange.promotion.model.vo.userPerformanceSummary.SupervisorPerformanceSummaryVO; import com.greenorange.promotion.model.vo.userPerformanceSummary.UserPerformanceSummaryDetailVO; import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.course.CourseOrderService; +import com.greenorange.promotion.service.course.CoursePromotionCommissionPendingService; +import com.greenorange.promotion.service.userInfo.EmployeePromotionRecordsService; import com.greenorange.promotion.service.userInfo.UserInfoService; import com.greenorange.promotion.service.userInfo.UserPerformanceSummaryService; import io.swagger.v3.oas.annotations.Operation; @@ -21,6 +31,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -28,9 +40,8 @@ import jakarta.validation.Valid; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.math.BigDecimal; +import java.util.*; import java.util.function.Function; @@ -46,16 +57,29 @@ public class UserPerformanceSummaryController { @Resource private UserPerformanceSummaryService userPerformanceSummaryService; + @Resource private CommonService commonService; + @Resource private UserInfoService userInfoService; + @Resource private CourseOrderService courseOrderService; + @Resource + private EmployeePromotionRecordsService employeePromotionRecordsService; + + + @Resource + private CoursePromotionCommissionPendingService coursePromotionCommissionPendingService; + + + + /** * Web端管理员分页查询主管绩效汇总 @@ -190,48 +214,148 @@ public class UserPerformanceSummaryController { -// /** -// * Web端管理员分页查询主管绩效排名 -// * @param userPerformanceSummaryQueryRequest 主管绩效汇总查询请求体 -// * @return 用户绩效汇总列表 -// */ -// @PostMapping("user/page") -// @Operation(summary = "Web端管理员分页查询主管绩效排名", description = "参数:用户绩效汇总查询请求体,权限:管理员,方法名:listUserPerformanceSummaryByPage") -// @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) -// public BaseResponse> listUserPerformanceSummaryByPage(@Valid @RequestBody UserCourseOrderQueryRequest userPerformanceSummaryQueryRequest) { -// long current = userPerformanceSummaryQueryRequest.getCurrent(); -// long pageSize = userPerformanceSummaryQueryRequest.getPageSize(); -// Long staffUserId = userPerformanceSummaryQueryRequest.getStaffUserId(); -// -// QueryWrapper courseOrderQueryWrapper = userPerformanceSummaryService.getCourseOrderQueryWrapper(userPerformanceSummaryQueryRequest); -// courseOrderQueryWrapper.in("orderStatus", OrderStatusConstant.SUCCESS, OrderStatusConstant.REFUNDED); -// -// List ids = userInfoService.findAllSubUser(staffUserId); -// List userInfoList = commonService.findByFieldInTargetField(ids, userInfoService, Function.identity(), UserInfo::getId); -// courseOrderQueryWrapper.in("userId", ids); -// -// Page page = courseOrderService.page(new Page<>(current, pageSize), courseOrderQueryWrapper); -// List courseOrderList = page.getRecords(); -// List courseOrderBaseInfoVOS = commonService.convertList(courseOrderList, CourseOrderBaseInfoVO.class); -// -// // 封装Map集合(键:用户id, 值:用户信息) -// Map userInfoMap = new HashMap<>(); -// for (UserInfo userInfo : userInfoList) userInfoMap.put(userInfo.getId(), userInfo); -// for (CourseOrderBaseInfoVO courseOrderBaseInfoVO : courseOrderBaseInfoVOS) { -// UserInfo userInfo = userInfoMap.get(courseOrderBaseInfoVO.getUserId()); -// courseOrderBaseInfoVO.setNickName(userInfo.getNickName()); -// courseOrderBaseInfoVO.setPhoneNumber(userInfo.getPhoneNumber()); -// } -// -// Page voPage = new Page<>(current, pageSize); -// voPage.setRecords(courseOrderBaseInfoVOS); -// voPage.setPages(page.getPages()); -// voPage.setTotal(page.getTotal()); -// return ResultUtils.success(voPage); -// } + /** + * Web端管理员分页查询主管绩效排名 + * @param userPerformanceSummaryRankQueryRequest 主管绩效排名查询请求体 + * @return 用户绩效汇总列表 + */ + @PostMapping("rank/user/page") + @Operation(summary = "Web端管理员分页查询主管绩效排名", description = "参数:主管绩效排名查询请求体,权限:管理员,方法名:listUserPerformanceSummaryRankingsByPage") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse> listUserPerformanceSummaryRankingsByPage(@Valid @RequestBody UserPerformanceSummaryRankQueryRequest userPerformanceSummaryRankQueryRequest) { + String startTimeStr = userPerformanceSummaryRankQueryRequest.getStartDate(); + String endTimeStr = userPerformanceSummaryRankQueryRequest.getEndDate(); + DateTime startDate = DateUtil.parse(startTimeStr, "yyyy-MM-dd HH:mm:ss"); + DateTime endDate = DateUtil.parse(endTimeStr, "yyyy-MM-dd HH:mm:ss"); + + QueryWrapper empQueryWrapper = new QueryWrapper<>(); + empQueryWrapper.ge(StringUtils.isNotBlank(startTimeStr), "createTime", startDate); + empQueryWrapper.le(StringUtils.isNotBlank(endTimeStr), "createTime", endDate); + List employeePromotionRecordsList = employeePromotionRecordsService.list(empQueryWrapper); + // 封装Map集合(键:主管id, 值:推广数量) + Map supervisorCntMap = new HashMap<>(); + // 封装Map集合(键:员工id, 值:推广数量) + Map staffCntMap = new HashMap<>(); + for (EmployeePromotionRecords employeePromotionRecords : employeePromotionRecordsList) { + Long firstUserId = employeePromotionRecords.getFirstUserId(); + Long secondUserId = employeePromotionRecords.getSecondUserId(); + supervisorCntMap.merge(firstUserId, 1, Integer::sum); + staffCntMap.merge(secondUserId, 1, Integer::sum); + } + + // 封装Map集合(键:主管id, 值:下单数量) + Map supervisorOrderCntMap = new HashMap<>(); + // 封装Map集合(键:员工id, 值:下单数量) + Map staffOrderCntMap = new HashMap<>(); + // (键:主管id, 值:下单金额) + Map supervisorOrderAmountMap = new HashMap<>(); + // (键:员工id, 值:下单金额) + Map staffOrderAmountMap = new HashMap<>(); + // (键:主管id, 值:净成交金额) + Map supervisorNetSalesAmountMap = new HashMap<>(); + // (键:员工id, 值:净成交金额) + Map staffNetSalesAmountMap = new HashMap<>(); + QueryWrapper coursePromotionQueryWrapper = new QueryWrapper<>(); + coursePromotionQueryWrapper.ge(StringUtils.isNotBlank(startTimeStr), "createTime", startDate); + coursePromotionQueryWrapper.le(StringUtils.isNotBlank(endTimeStr), "createTime", endDate); + List coursePromotionCommissionPendingList = coursePromotionCommissionPendingService.list(coursePromotionQueryWrapper); + for (CoursePromotionCommissionPending coursePromotionCommissionPending : coursePromotionCommissionPendingList) { + Long firstUserId = coursePromotionCommissionPending.getFirstUserId(); + Long secondUserId = coursePromotionCommissionPending.getSecondUserId(); + BigDecimal totalAmount = coursePromotionCommissionPending.getTotalAmount(); + DateTime updateDate = DateUtil.date(coursePromotionCommissionPending.getUpdateTime()); + String commissionStatus = coursePromotionCommissionPending.getCommissionStatus(); + CommissionStatusEnum commissionStatusEnum = CommissionStatusEnum.getEnumByValue(commissionStatus); + supervisorOrderCntMap.merge(firstUserId, 1, Integer::sum); + staffOrderCntMap.merge(secondUserId, 1, Integer::sum); + supervisorOrderAmountMap.merge(firstUserId, totalAmount, BigDecimal::add); + staffOrderAmountMap.merge(secondUserId, totalAmount, BigDecimal::add); + + if (!(CommissionStatusEnum.COMPLETED.equals(commissionStatusEnum) && updateDate.isAfterOrEquals(startDate) && updateDate.isBeforeOrEquals(endDate))) { + totalAmount = totalAmount.multiply(SystemConstant.FEE_RATE); + } + supervisorNetSalesAmountMap.merge(firstUserId, totalAmount, BigDecimal::add); + staffNetSalesAmountMap.merge(secondUserId, totalAmount, BigDecimal::add); + } + // 封装Map集合(键:主管id, 值:员工数量) + Map supervisorStaffCntMap = new HashMap<>(); + List userInfoList = commonService.findByFieldEqTargetField(UserInfo::getUserRole, UserRoleEnum.SUPERVISOR, userInfoService); + List userPerformanceSummaryList = commonService.findByFieldInTargetField(userInfoList, userPerformanceSummaryService, UserInfo::getId, UserPerformanceSummary::getUserId); + + // 封装Map集合(键:主管id, 用户信息) + Map userInfoMap = new HashMap<>(); + for (UserInfo userInfo : userInfoList) { + userInfoMap.put(userInfo.getId(), userInfo); + } + + // 封装主管绩效排名列表 + List supervisorPerformanceSummaryVOS = new ArrayList<>(); + for (UserPerformanceSummary userPerformanceSummary : userPerformanceSummaryList) { + Long userId = userPerformanceSummary.getUserId(); + UserInfo userInfo = userInfoMap.get(userId); + SupervisorPerformanceSummaryVO supervisorPerformanceSummaryVO = SupervisorPerformanceSummaryVO.builder() + .nickName(userInfo.getNickName()) + .phoneNumber(userInfo.getPhoneNumber()) + .empCount(userPerformanceSummary.getEmpCount()) + .orderCount(supervisorOrderCntMap.get(userId)) + .totalAmount(supervisorOrderAmountMap.get(userId)) + .netAmount(supervisorNetSalesAmountMap.get(userId)) + .promoCount(supervisorCntMap.get(userId)) + .build(); + supervisorPerformanceSummaryVOS.add(supervisorPerformanceSummaryVO); + } + long current = userPerformanceSummaryRankQueryRequest.getCurrent(); + long pageSize = userPerformanceSummaryRankQueryRequest.getPageSize(); + String nickName = userPerformanceSummaryRankQueryRequest.getNickName(); + String phoneNumber = userPerformanceSummaryRankQueryRequest.getPhoneNumber(); + String sortField = userPerformanceSummaryRankQueryRequest.getSortField(); + String sortOrder = userPerformanceSummaryRankQueryRequest.getSortOrder(); + return null; + } + + + /** + * Web端管理员修改一、二级抽成比例 + * @param rakeRewardsUpdateRequest 抽成比例更新请求体 + * @return 是否更新成功 + */ + @PostMapping("update/rate") + @Operation(summary = "Web端管理员修改一、二级抽成比例", description = "参数:抽成比例更新请求体,权限:管理员,方法名:updateRakeRewardsRate") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse updateRakeRewardsRate(@Valid @RequestBody RakeRewardsUpdateRequest rakeRewardsUpdateRequest) { + userPerformanceSummaryService.updateRakeRewards(rakeRewardsUpdateRequest); + return ResultUtils.success(true); + } + + + /** + * Web端管理员查询一、二级抽成比例 + * @return 抽成比例对象 + */ + @PostMapping("query/rate") + @Operation(summary = "Web端管理员查询一、二级抽成比例", description = "参数:无,权限:管理员,方法名:queryRakeRewardsRate") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse> queryRakeRewardsRate() { + Map rateMap = userPerformanceSummaryService.queryRakeRewardsRate(); + return ResultUtils.success(rateMap); + } + + + /** + * Web端管理员根据级别查询抽佣比例 + * @param rakeRewardsQueryRequest 级别 + * @return 抽成比例 + */ + @PostMapping("query/level/rate") + @Operation(summary = "Web端管理员根据级别查询抽佣比例", description = "参数:无,权限:管理员,方法名:queryRakeRewardsRateByLevel") + @RequiresPermission(mustRole = UserConstant.ADMIN_ROLE) + public BaseResponse queryRakeRewardsRateByLevel(@Valid @RequestBody RakeRewardsQueryRequest rakeRewardsQueryRequest) { + BigDecimal rate = userPerformanceSummaryService.queryRakeRewardsRateByLevel(rakeRewardsQueryRequest); + return ResultUtils.success(rate); + } diff --git a/src/main/java/com/greenorange/promotion/mapper/EmployeePromotionRecordsMapper.java b/src/main/java/com/greenorange/promotion/mapper/EmployeePromotionRecordsMapper.java new file mode 100644 index 0000000..0bdf848 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/mapper/EmployeePromotionRecordsMapper.java @@ -0,0 +1,18 @@ +package com.greenorange.promotion.mapper; + +import com.greenorange.promotion.model.entity.EmployeePromotionRecords; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** +* @author 35880 +* @description 针对表【employee_promotion_records(员工推广记录表)】的数据库操作Mapper +* @createDate 2025-07-12 22:27:51 +* @Entity com.greenorange.promotion.model.entity.EmployeePromotionRecords +*/ +public interface EmployeePromotionRecordsMapper extends BaseMapper { + +} + + + + diff --git a/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsQueryRequest.java b/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsQueryRequest.java new file mode 100644 index 0000000..f85c082 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsQueryRequest.java @@ -0,0 +1,30 @@ +package com.greenorange.promotion.model.dto.userPerformanceSummary; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 抽成比例查询请求体 + */ +@Data +@Schema(description = "抽成比例查询请求体", requiredProperties = {"level"}) +public class RakeRewardsQueryRequest implements Serializable { + + /** + * 级别 + */ + @NotBlank(message = "级别不能为空") + @Pattern(regexp = "first|second", message = "级别只能是first或second") + @Schema(description = "级别", example = "first") + private String level; + + + @Serial + private static final long serialVersionUID = 1L; + +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsUpdateRequest.java b/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsUpdateRequest.java new file mode 100644 index 0000000..c5b2638 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/dto/userPerformanceSummary/RakeRewardsUpdateRequest.java @@ -0,0 +1,40 @@ +package com.greenorange.promotion.model.dto.userPerformanceSummary; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.*; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + + +/** + * 抽成比例更新请求体 + */ +@Data +@Schema(description = "抽成比例更新请求体", requiredProperties = {"level", "rate"}) +public class RakeRewardsUpdateRequest implements Serializable { + + /** + * 级别 + */ + @NotBlank(message = "级别不能为空") + @Pattern(regexp = "first|second", message = "级别只能是first或second") + @Schema(description = "级别", example = "first") + private String level; + + + /** + * 抽成比例 + */ + @DecimalMin(value = "0.0", message = "抽成比例不能小于0.0") + @DecimalMax(value = "1.0", message = "抽成比例不能大于1.0") + @Schema(description = "抽成比例", example = "0.1") + private BigDecimal rate; + + + @Serial + private static final long serialVersionUID = 1L; + +} diff --git a/src/main/java/com/greenorange/promotion/model/entity/CoursePromotionCommissionPending.java b/src/main/java/com/greenorange/promotion/model/entity/CoursePromotionCommissionPending.java index 4e26276..4b71c68 100644 --- a/src/main/java/com/greenorange/promotion/model/entity/CoursePromotionCommissionPending.java +++ b/src/main/java/com/greenorange/promotion/model/entity/CoursePromotionCommissionPending.java @@ -69,6 +69,16 @@ public class CoursePromotionCommissionPending implements Serializable { */ private Long userId; + /** + * 一级抽佣比例 + */ + private BigDecimal firstRate; + + /** + * 二级抽佣比例 + */ + private BigDecimal secondRate; + /** * 订单价格 */ @@ -84,6 +94,16 @@ public class CoursePromotionCommissionPending implements Serializable { */ private Date orderCreateTime; + /** + * 一级抽成奖励 + */ + private BigDecimal firstReward; + + /** + * 二级抽成奖励 + */ + private BigDecimal secondReward; + /** * 是否删除 */ diff --git a/src/main/java/com/greenorange/promotion/model/entity/EmployeePromotionRecords.java b/src/main/java/com/greenorange/promotion/model/entity/EmployeePromotionRecords.java new file mode 100644 index 0000000..68281f1 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/entity/EmployeePromotionRecords.java @@ -0,0 +1,64 @@ +package com.greenorange.promotion.model.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.util.Date; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 员工推广记录表 + * @TableName employee_promotion_records + */ +@TableName(value ="employee_promotion_records") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class EmployeePromotionRecords implements Serializable { + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 主管ID + */ + private Long firstUserId; + + /** + * 员工ID + */ + private Long secondUserId; + + /** + * 客户ID + */ + private Long userId; + + /** + * 是否删除 + */ + private Integer isDelete; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/model/enums/CourseTypeEnum.java b/src/main/java/com/greenorange/promotion/model/enums/CourseTypeEnum.java index 63affdd..6283ab9 100644 --- a/src/main/java/com/greenorange/promotion/model/enums/CourseTypeEnum.java +++ b/src/main/java/com/greenorange/promotion/model/enums/CourseTypeEnum.java @@ -15,7 +15,8 @@ import java.util.stream.Collectors; public enum CourseTypeEnum implements BaseEnum { KAOGONG("考公"), - CAIJING("财经"); + KAOBIAN("考编"), + KAOZHENG("考证"); private final String value; diff --git a/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/StaffPerformanceSummaryVO.java b/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/StaffPerformanceSummaryVO.java new file mode 100644 index 0000000..07c0e55 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/StaffPerformanceSummaryVO.java @@ -0,0 +1,56 @@ +package com.greenorange.promotion.model.vo.userPerformanceSummary; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 员工绩效排名信息 视图对象 + */ +@Data +@Schema(description = "员工绩效排名信息 视图对象") +public class StaffPerformanceSummaryVO implements Serializable { + + /** + * 用户昵称 + */ + @Schema(description = "用户昵称", example = "chenxinzhi") + private String nickName; + + /** + * 手机号 + */ + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 推广人数 + */ + @Schema(description = "推广人数", example = "300") + private Integer promoCount; + + /** + * 下单数量 + */ + @Schema(description = "下单数量", example = "100") + private Integer orderCount; + + /** + * 订单总金额 + */ + @Schema(description = "订单总金额", example = "15.00") + private BigDecimal totalAmount; + + /** + * 净成交 + */ + @Schema(description = "净成交", example = "20.00") + private BigDecimal netAmount; + + + @Serial + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/SupervisorPerformanceSummaryVO.java b/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/SupervisorPerformanceSummaryVO.java new file mode 100644 index 0000000..f4789b7 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/model/vo/userPerformanceSummary/SupervisorPerformanceSummaryVO.java @@ -0,0 +1,68 @@ +package com.greenorange.promotion.model.vo.userPerformanceSummary; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 主管绩效排名信息 视图对象 + */ +@Data +@Schema(description = "主管绩效排名信息 视图对象") +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SupervisorPerformanceSummaryVO implements Serializable { + + /** + * 用户昵称 + */ + @Schema(description = "用户昵称", example = "chenxinzhi") + private String nickName; + + /** + * 手机号 + */ + @Schema(description = "手机号", example = "15888610253") + private String phoneNumber; + + /** + * 员工数量 + */ + @Schema(description = "员工数量", example = "150") + private Integer empCount; + + /** + * 推广人数 + */ + @Schema(description = "推广人数", example = "300") + private Integer promoCount; + + /** + * 下单数量 + */ + @Schema(description = "下单数量", example = "100") + private Integer orderCount; + + /** + * 订单总金额 + */ + @Schema(description = "订单总金额", example = "15.00") + private BigDecimal totalAmount; + + /** + * 净成交 + */ + @Schema(description = "净成交", example = "20.00") + private BigDecimal netAmount; + + + @Serial + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/com/greenorange/promotion/service/userInfo/EmployeePromotionRecordsService.java b/src/main/java/com/greenorange/promotion/service/userInfo/EmployeePromotionRecordsService.java new file mode 100644 index 0000000..2a51542 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/service/userInfo/EmployeePromotionRecordsService.java @@ -0,0 +1,13 @@ +package com.greenorange.promotion.service.userInfo; + +import com.greenorange.promotion.model.entity.EmployeePromotionRecords; +import com.baomidou.mybatisplus.extension.service.IService; + +/** +* @author 35880 +* @description 针对表【employee_promotion_records(员工推广记录表)】的数据库操作Service +* @createDate 2025-07-12 22:27:51 +*/ +public interface EmployeePromotionRecordsService extends IService { + +} diff --git a/src/main/java/com/greenorange/promotion/service/userInfo/UserPerformanceSummaryService.java b/src/main/java/com/greenorange/promotion/service/userInfo/UserPerformanceSummaryService.java index f35530d..3d58cf5 100644 --- a/src/main/java/com/greenorange/promotion/service/userInfo/UserPerformanceSummaryService.java +++ b/src/main/java/com/greenorange/promotion/service/userInfo/UserPerformanceSummaryService.java @@ -2,12 +2,18 @@ package com.greenorange.promotion.service.userInfo; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.greenorange.promotion.common.PageRequest; +import com.greenorange.promotion.model.dto.CommonStringRequest; import com.greenorange.promotion.model.dto.userPerformanceSummary.MiniUserCourseOrderQueryRequest; +import com.greenorange.promotion.model.dto.userPerformanceSummary.RakeRewardsQueryRequest; +import com.greenorange.promotion.model.dto.userPerformanceSummary.RakeRewardsUpdateRequest; import com.greenorange.promotion.model.dto.userPerformanceSummary.UserCourseOrderQueryRequest; import com.greenorange.promotion.model.entity.CourseOrder; import com.greenorange.promotion.model.entity.UserPerformanceSummary; import com.baomidou.mybatisplus.extension.service.IService; +import java.math.BigDecimal; +import java.util.Map; + /** * @author 35880 * @description 针对表【user_performance_summary(用户绩效汇总表)】的数据库操作Service @@ -25,4 +31,22 @@ public interface UserPerformanceSummaryService extends IService getCourseOrderQueryWrapper(UserCourseOrderQueryRequest userCourseOrderQueryRequest); + + + /** + * Web端管理员修改一、二级抽成比例 + */ + void updateRakeRewards(RakeRewardsUpdateRequest rakeRewardsUpdateRequest); + + + /** + * Web端管理员查询一、二级抽成比例 + */ + Map queryRakeRewardsRate(); + + + /** + * Web端管理员根据级别查询抽佣比例 + */ + BigDecimal queryRakeRewardsRateByLevel(RakeRewardsQueryRequest rakeRewardsQueryRequest); } diff --git a/src/main/java/com/greenorange/promotion/service/userInfo/impl/EmployeePromotionRecordsServiceImpl.java b/src/main/java/com/greenorange/promotion/service/userInfo/impl/EmployeePromotionRecordsServiceImpl.java new file mode 100644 index 0000000..a9782a6 --- /dev/null +++ b/src/main/java/com/greenorange/promotion/service/userInfo/impl/EmployeePromotionRecordsServiceImpl.java @@ -0,0 +1,22 @@ +package com.greenorange.promotion.service.userInfo.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.greenorange.promotion.model.entity.EmployeePromotionRecords; +import com.greenorange.promotion.service.userInfo.EmployeePromotionRecordsService; +import com.greenorange.promotion.mapper.EmployeePromotionRecordsMapper; +import org.springframework.stereotype.Service; + +/** +* @author 35880 +* @description 针对表【employee_promotion_records(员工推广记录表)】的数据库操作Service实现 +* @createDate 2025-07-12 22:27:51 +*/ +@Service +public class EmployeePromotionRecordsServiceImpl extends ServiceImpl + implements EmployeePromotionRecordsService{ + +} + + + + diff --git a/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserInfoServiceImpl.java b/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserInfoServiceImpl.java index bc70367..5ccdc6c 100644 --- a/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserInfoServiceImpl.java +++ b/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserInfoServiceImpl.java @@ -23,10 +23,7 @@ import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.project.ProjectCommissionService; import com.greenorange.promotion.service.project.ProjectDetailService; import com.greenorange.promotion.service.project.SubUserProjectCommissionService; -import com.greenorange.promotion.service.userInfo.AdvancementApplyService; -import com.greenorange.promotion.service.userInfo.UserInfoService; -import com.greenorange.promotion.service.userInfo.UserMainInfoService; -import com.greenorange.promotion.service.userInfo.UserPerformanceSummaryService; +import com.greenorange.promotion.service.userInfo.*; import com.greenorange.promotion.service.wechat.WechatGetQrcodeService; import com.greenorange.promotion.utils.JWTUtils; import com.greenorange.promotion.utils.RegexUtils; @@ -100,6 +97,10 @@ public class UserInfoServiceImpl extends ServiceImpl private UserPerformanceSummaryService userPerformanceSummaryService; + @Resource + private EmployeePromotionRecordsService employeePromotionRecordsService; + + @@ -176,9 +177,9 @@ public class UserInfoServiceImpl extends ServiceImpl myUserInfo.setUserAvatar(UserConstant.USER_DEFAULT_AVATAR); this.save(myUserInfo); - // 添加用户绩效记录 - UserPerformanceSummary userPerformanceSummary = UserPerformanceSummary.builder().userId(myUserInfo.getId()).build(); - userPerformanceSummaryService.save(userPerformanceSummary); +// // 添加用户绩效记录 +// UserPerformanceSummary userPerformanceSummary = UserPerformanceSummary.builder().userId(myUserInfo.getId()).build(); +// userPerformanceSummaryService.save(userPerformanceSummary); // 更新上级用户的数量 updateParentUserInfoEmpCount(myUserInfo.getId(), userRoleEnum); @@ -416,6 +417,16 @@ public class UserInfoServiceImpl extends ServiceImpl } } userPerformanceSummaryService.updateBatchById(userPerformanceSummaryList); + + // 如果是普通用户,就添加一条员工推广记录 + if (userRoleEnum.equals(UserRoleEnum.USER)) { + EmployeePromotionRecords employeePromotionRecords = EmployeePromotionRecords.builder() + .firstUserId(pathToRoot.get(0)) + .secondUserId(pathToRoot.get(1)) + .userId(userId) + .build(); + employeePromotionRecordsService.save(employeePromotionRecords); + } } diff --git a/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserPerformanceSummaryServiceImpl.java b/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserPerformanceSummaryServiceImpl.java index 70771d4..d957398 100644 --- a/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserPerformanceSummaryServiceImpl.java +++ b/src/main/java/com/greenorange/promotion/service/userInfo/impl/UserPerformanceSummaryServiceImpl.java @@ -6,7 +6,10 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.greenorange.promotion.common.PageRequest; import com.greenorange.promotion.constant.CommonConstant; +import com.greenorange.promotion.model.dto.CommonStringRequest; import com.greenorange.promotion.model.dto.userPerformanceSummary.MiniUserCourseOrderQueryRequest; +import com.greenorange.promotion.model.dto.userPerformanceSummary.RakeRewardsQueryRequest; +import com.greenorange.promotion.model.dto.userPerformanceSummary.RakeRewardsUpdateRequest; import com.greenorange.promotion.model.dto.userPerformanceSummary.UserCourseOrderQueryRequest; import com.greenorange.promotion.model.entity.CourseOrder; import com.greenorange.promotion.model.entity.UserPerformanceSummary; @@ -16,8 +19,15 @@ import com.greenorange.promotion.mapper.UserPerformanceSummaryMapper; import com.greenorange.promotion.utils.SqlUtils; import jakarta.annotation.Resource; import org.apache.commons.lang3.StringUtils; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.math.BigDecimal; +import java.security.Key; +import java.util.Map; +import java.util.stream.Collectors; + /** * @author 35880 * @description 针对表【user_performance_summary(用户绩效汇总表)】的数据库操作Service实现 @@ -27,6 +37,10 @@ import org.springframework.stereotype.Service; public class UserPerformanceSummaryServiceImpl extends ServiceImpl implements UserPerformanceSummaryService{ + private static final String KEY = "rakeRate"; + + @Resource + private RedisTemplate redisTemplate; /** * 获取查询条件 @@ -57,6 +71,43 @@ public class UserPerformanceSummaryServiceImpl extends ServiceImpl queryRakeRewardsRate() { + // 直接从 redisTemplate 获取 HashOperations + HashOperations hashOps = redisTemplate.opsForHash(); + Map entries = hashOps.entries(KEY); + return entries.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> new BigDecimal(e.getValue()) + )); + } + + + /** + * Web端管理员根据级别查询抽佣比例 + */ + @Override + public BigDecimal queryRakeRewardsRateByLevel(RakeRewardsQueryRequest rakeRewardsQueryRequest) { + String level = rakeRewardsQueryRequest.getLevel(); + return new BigDecimal(redisTemplate.opsForHash().get(KEY, level).toString()); + } } diff --git a/src/main/java/com/greenorange/promotion/service/wechat/impl/WechatPayServiceImpl.java b/src/main/java/com/greenorange/promotion/service/wechat/impl/WechatPayServiceImpl.java index d6a32dd..3465c22 100644 --- a/src/main/java/com/greenorange/promotion/service/wechat/impl/WechatPayServiceImpl.java +++ b/src/main/java/com/greenorange/promotion/service/wechat/impl/WechatPayServiceImpl.java @@ -40,6 +40,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.function.Function; /** @@ -153,9 +154,10 @@ public class WechatPayServiceImpl implements WechatPayService { List superUserIdList = pathToRoot.subList(1, 3); List userPerformanceSummaryList = commonService.findByFieldInTargetField(superUserIdList, userPerformanceSummaryService, Function.identity(), UserPerformanceSummary::getUserId); BigDecimal rate; + Map rateMap = userPerformanceSummaryService.queryRakeRewardsRate(); for (int i = 0; i < userPerformanceSummaryList.size(); i ++ ) { - if (i == 0) rate = SystemConstant.FIRST_LEVEL_COMMISSION_RATE; - else rate = SystemConstant.SECOND_LEVEL_COMMISSION_RATE; + if (i == 0) rate = rateMap.get("first"); + else rate = rateMap.get("second"); // 计算理论上获得的最大提成奖励 BigDecimal rakeRewards = courseOrder.getTotalAmount().multiply(rate); UserPerformanceSummary userPerformanceSummary = userPerformanceSummaryList.get(i); @@ -169,25 +171,27 @@ public class WechatPayServiceImpl implements WechatPayService { userPerformanceSummaryService.updateBatchById(userPerformanceSummaryList); -// // 添加课程推广待提成记录 -// Long userId = courseOrder.getUserId(); -// List pathToRoot = userInfoService.findPathToRoot(userId); -// Long firstUserId = pathToRoot.get(0); -// Long secondUserId = pathToRoot.get(1); -// CoursePromotionCommissionPending coursePromotionCommissionPending = CoursePromotionCommissionPending.builder() -// .firstUserId(firstUserId) -// .secondUserId(secondUserId) -// .courseId(courseId) -// .name(courseOrder.getName()) -// .type(courseOrder.getType()) -// .image(courseOrder.getImage()) -// .orderId(courseOrder.getId()) -// .userId(userId) -// .totalAmount(courseOrder.getTotalAmount()) -// .commissionStatus(CommissionStatusEnum.PENDING.getValue()) -// .orderCreateTime(courseOrder.getCreateTime()) -// .build(); -// coursePromotionCommissionPendingService.save(coursePromotionCommissionPending); + // 添加课程推广待提成记录 + Long firstUserId = pathToRoot.get(0); + Long secondUserId = pathToRoot.get(1); + CoursePromotionCommissionPending coursePromotionCommissionPending = CoursePromotionCommissionPending.builder() + .firstUserId(firstUserId) + .secondUserId(secondUserId) + .courseId(courseId) + .name(courseOrder.getName()) + .type(courseOrder.getType()) + .image(courseOrder.getImage()) + .orderId(courseOrder.getId()) + .userId(userId) + .firstRate(rateMap.get("first")) + .secondRate(rateMap.get("second")) + .firstReward(courseOrder.getTotalAmount().multiply(rateMap.get("first"))) + .secondReward(courseOrder.getTotalAmount().multiply(rateMap.get("second"))) + .totalAmount(courseOrder.getTotalAmount()) + .commissionStatus(CommissionStatusEnum.PENDING.getValue()) + .orderCreateTime(courseOrder.getCreateTime()) + .build(); + coursePromotionCommissionPendingService.save(coursePromotionCommissionPending); System.out.println("---------------------------微信支付回调(结束)-------------------------------"); @@ -278,9 +282,12 @@ public class WechatPayServiceImpl implements WechatPayService { List superUserIdList = pathToRoot.subList(1, 3); List userPerformanceSummaryList = commonService.findByFieldInTargetField(superUserIdList, userPerformanceSummaryService, Function.identity(), UserPerformanceSummary::getUserId); BigDecimal rate; + LambdaQueryWrapper coursePromotionQueryWrapper = new LambdaQueryWrapper<>(); + coursePromotionQueryWrapper.eq(CoursePromotionCommissionPending::getOrderId, courseOrder.getId()); + CoursePromotionCommissionPending coursePromotionCommissionPending = coursePromotionCommissionPendingService.getOne(coursePromotionQueryWrapper); for (int i = 0; i < userPerformanceSummaryList.size(); i ++ ) { - if (i == 0) rate = SystemConstant.FIRST_LEVEL_COMMISSION_RATE; - else rate = SystemConstant.SECOND_LEVEL_COMMISSION_RATE; + if (i == 0) rate = coursePromotionCommissionPending.getFirstRate(); + else rate = coursePromotionCommissionPending.getSecondRate(); // 计算理论上获得的最大提成奖励 BigDecimal rakeRewards = courseOrder.getTotalAmount().multiply(rate); UserPerformanceSummary userPerformanceSummary = userPerformanceSummaryList.get(i); @@ -293,11 +300,11 @@ public class WechatPayServiceImpl implements WechatPayService { } userPerformanceSummaryService.updateBatchById(userPerformanceSummaryList); -// // 修改课程推广待提成状态为"已失效" -// LambdaUpdateWrapper coursePromotionUpdateWrapper = new LambdaUpdateWrapper<>(); -// coursePromotionUpdateWrapper.eq(CoursePromotionCommissionPending::getOrderId, courseOrder.getId()) -// .set(CoursePromotionCommissionPending::getCommissionStatus, CommissionStatusEnum.EXPIRED.getValue()); -// coursePromotionCommissionPendingService.update(coursePromotionUpdateWrapper); + // 修改课程推广待提成状态为"已失效" + LambdaUpdateWrapper coursePromotionUpdateWrapper = new LambdaUpdateWrapper<>(); + coursePromotionUpdateWrapper.eq(CoursePromotionCommissionPending::getOrderId, courseOrder.getId()) + .set(CoursePromotionCommissionPending::getCommissionStatus, CommissionStatusEnum.EXPIRED.getValue()); + coursePromotionCommissionPendingService.update(coursePromotionUpdateWrapper); System.out.println("---------------------------微信退款回调(结束)-------------------------------"); return true; diff --git a/src/main/resources/mapper/EmployeePromotionRecordsMapper.xml b/src/main/resources/mapper/EmployeePromotionRecordsMapper.xml new file mode 100644 index 0000000..12199c9 --- /dev/null +++ b/src/main/resources/mapper/EmployeePromotionRecordsMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + id,firstUserId,secondUserId, + userId,isDelete,createTime, + updateTime + +