Administrator
yesterday 0a9a71a81a9d4c3c0df7ddf49e5e2f2d0a10f7de
feat(mall): 添加积分排行榜功能

- 新增 scoreRecord 接口用于获取积分排行榜信息
- 实现积分排行榜的查询逻辑,支持月排行和周排行
- 添加相关 DTO 和 VO 类用于积分排行榜的数据传输
- 优化代码结构,提高可读性和可维护性
4 files modified
2 files added
280 ■■■■■ changed files
src/main/java/cc/mrbird/febs/mall/controller/member/ApiMallMemberController.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/memberLevel/ApiScoreRecordInfoDto.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java 209 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/memberLevel/ApiMemberLabelItemVo.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/memberLevel/ApiScoreRecordInfoVo.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/member/ApiMallMemberController.java
@@ -2,10 +2,8 @@
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelAddDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInfoDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInsureDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelItemDto;
import cc.mrbird.febs.mall.dto.memberLevel.*;
import cc.mrbird.febs.mall.dto.sale.ApiSaleRecordInfoDto;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallMemberPayment;
import cc.mrbird.febs.mall.service.IApiMallAgentService;
@@ -13,10 +11,8 @@
import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
import cc.mrbird.febs.mall.service.IMallMemberWithdrawService;
import cc.mrbird.febs.mall.vo.*;
import cc.mrbird.febs.mall.vo.memberLevel.ApiMemberLabelAddVo;
import cc.mrbird.febs.mall.vo.memberLevel.ApiMemberLabelInfoVo;
import cc.mrbird.febs.mall.vo.memberLevel.ApiMemberLabelItemVo;
import cc.mrbird.febs.mall.vo.memberLevel.ApiMemberLabelVo;
import cc.mrbird.febs.mall.vo.memberLevel.*;
import cc.mrbird.febs.mall.vo.sale.ApiSaleRecordInfoVo;
import cc.mrbird.febs.vip.service.IMallVipBenefitsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -84,6 +80,16 @@
        return memberService.getLabelListById(dto);
    }
    @ApiOperation(value = "积分排行榜", notes = "积分排行榜")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiScoreRecordInfoVo.class)
    })
    @PostMapping(value = "/scoreRecord")
    public FebsResponse scoreRecord(@RequestBody @Validated ApiScoreRecordInfoDto dto) {
        return memberService.scoreRecord(dto);
    }
    @ApiOperation(value = "我的团列表(我的团)", notes = "我的团列表(我的团)")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiMemberLabelItemVo.class)
src/main/java/cc/mrbird/febs/mall/dto/memberLevel/ApiScoreRecordInfoDto.java
New file
@@ -0,0 +1,16 @@
package cc.mrbird.febs.mall.dto.memberLevel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "ApiScoreRecordInfoDto", description = "参数")
public class ApiScoreRecordInfoDto {
    @NotNull(message = "分类不能为空")
    @ApiModelProperty(value = "分类 1-月排行 2-周", example = "1")
    private Integer type;
}
src/main/java/cc/mrbird/febs/mall/service/IApiMallMemberService.java
@@ -2,10 +2,7 @@
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelAddDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInfoDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInsureDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelItemDto;
import cc.mrbird.febs.mall.dto.memberLevel.*;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallMemberPayment;
import cc.mrbird.febs.mall.entity.MallShopApply;
@@ -130,6 +127,8 @@
    FebsResponse getLabelListById(ApiMemberLabelInfoDto dto);
    FebsResponse scoreRecord(ApiScoreRecordInfoDto dto);
    FebsResponse getMemberLabelListById(ApiMemberLabelItemDto dto);
    FebsResponse addLabelMember(ApiMemberLabelAddDto dto);
src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallMemberServiceImpl.java
@@ -9,16 +9,14 @@
import cc.mrbird.febs.mall.conversion.MallShopApplyConversion;
import cc.mrbird.febs.mall.conversion.MallStoreConversion;
import cc.mrbird.febs.mall.dto.*;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelAddDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInfoDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelInsureDto;
import cc.mrbird.febs.mall.dto.memberLevel.ApiMemberLabelItemDto;
import cc.mrbird.febs.mall.dto.memberLevel.*;
import cc.mrbird.febs.mall.dto.signActivity.ApiNewGiftSettingDto;
import cc.mrbird.febs.mall.entity.*;
import cc.mrbird.febs.mall.mapper.*;
import cc.mrbird.febs.mall.service.*;
import cc.mrbird.febs.mall.vo.*;
import cc.mrbird.febs.mall.vo.memberLevel.*;
import cc.mrbird.febs.mall.vo.sale.ApiSaleRecordInfoVo;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.service.IXcxPayService;
import cc.mrbird.febs.pay.util.MD5;
@@ -27,6 +25,7 @@
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
@@ -55,6 +54,7 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
@@ -1741,6 +1741,7 @@
                    new LambdaQueryWrapper<HappyMemberLabel>()
                            .select( HappyMemberLabel::getId, HappyMemberLabel::getCode,HappyMemberLabel::getIconPng, HappyMemberLabel::getName, HappyMemberLabel::getContent, HappyMemberLabel::getHeaderPng)
                            .in(HappyMemberLabel::getId, collect)
                    .orderByDesc(HappyMemberLabel::getCode)
            );
            if(CollUtil.isNotEmpty(happyMemberLabels)){
                for (HappyMemberLabel happyMemberLabel : happyMemberLabels) {
@@ -1800,6 +1801,187 @@
    }
    @Override
    public FebsResponse scoreRecord(ApiScoreRecordInfoDto dto) {
        // 初始化结果列表
        List<ApiScoreRecordInfoVo> apiSaleRecordInfoVos = new ArrayList<>();
//        List<HappyMemberLabel> happyMemberLabels = happyMemberLabelMapper.selectList(
//                Wrappers.lambdaQuery(HappyMemberLabel.class)
//                        .eq(HappyMemberLabel::getCode, 1)
//                        .eq(HappyMemberLabel::getParentId, 0)
//        );
//        if(CollUtil.isEmpty(happyMemberLabels)){
//            return new FebsResponse().success().data(apiSaleRecordInfoVos);
//        }
//
//        // 获取类型参数
//        Integer type = dto.getType();
//        // 校验类型参数,确保其为1(月)或2(周)
//        if (type == null || (type != 1 && type != 2)) {
//            return new FebsResponse().fail().message("非法的类型参数");
//        }
//
//        // 根据类型参数确定开始时间
//        DateTime startTime = type == 1 ? DateUtil.beginOfMonth(new Date()) : DateUtil.beginOfWeek(new Date());
//
//        // 查询指定时间范围内的团队积分记录
//        for (HappyMemberLabel happyMemberLabel : happyMemberLabels){
//            //初始化公共部分
//            ApiScoreRecordInfoVo apiScoreRecordInfoVo = new ApiScoreRecordInfoVo();
//            apiScoreRecordInfoVo.setName(happyMemberLabel.getName());
//            apiScoreRecordInfoVo.setAvatar(happyMemberLabel.getIconPng());
//
//            //获取这个全部的标识的二级标识
//            List<HappyMemberLabel> happyMemberLabelChildList = happyMemberLabelMapper.selectList(
//                    Wrappers.lambdaQuery(HappyMemberLabel.class)
//                            .eq(HappyMemberLabel::getParentId, happyMemberLabel.getId())
//            );
//            if(CollUtil.isEmpty(happyMemberLabelChildList)){
//                apiScoreRecordInfoVo.setScore(BigDecimal.ZERO);
//                apiSaleRecordInfoVos.add(apiScoreRecordInfoVo);
//                continue;
//            }
//
//            //stream流操作happyMemberLabelChildList,返回一个id的set集合
//            Set<Long> labelIdSet = happyMemberLabelChildList.stream().map(HappyMemberLabel::getId).collect(Collectors.toSet());
//            //获取全部会员的绑定关系
//            List<HappyMemberLabelRecord> happyMemberLabelRecords = happyMemberLabelRecordMapper.selectList(
//                    Wrappers.lambdaQuery(HappyMemberLabelRecord.class)
//                            .in(HappyMemberLabelRecord::getLabelId, labelIdSet)
//            );
//            if(CollUtil.isEmpty(happyMemberLabelRecords)){
//                apiScoreRecordInfoVo.setScore(BigDecimal.ZERO);
//                apiSaleRecordInfoVos.add(apiScoreRecordInfoVo);
//                continue;
//            }
//            //stream流操作happyMemberLabelRecords,返回一个memberId的set集合
//            Set<Long> memberIdSet = happyMemberLabelRecords.stream().map(HappyMemberLabelRecord::getMemberId).collect(Collectors.toSet());
//            List<MallMoneyFlow> mallMoneyFlows = mallMoneyFlowMapper.selectList(
//                    Wrappers.lambdaQuery(MallMoneyFlow.class)
//                            .select(MallMoneyFlow::getAmount,  MallMoneyFlow::getMemberId)
//                            .in(MallMoneyFlow::getMemberId, memberIdSet)
//                            .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.PRIZE_SCORE.getValue())
//                            .gt(MallMoneyFlow::getAmount, BigDecimal.ZERO)
//                            .ge(MallMoneyFlow::getCreatedTime, startTime)
//            );
//
//        }
//
//        if(CollUtil.isNotEmpty(happyMemberLabels)){
//            List<CompletableFuture<ApiScoreRecordInfoVo>> futures = new ArrayList<>();
//            DateTime endTime = DateUtil.date();
//            happyMemberLabels.forEach(item -> {
//                CompletableFuture<ApiScoreRecordInfoVo> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
//                    //初始化公共部分
//                    ApiScoreRecordInfoVo apiScoreRecordInfoVo = new ApiScoreRecordInfoVo();
//                    apiScoreRecordInfoVo.setName(item.getName());
//                    apiScoreRecordInfoVo.setAvatar(item.getIconPng());
//                    apiScoreRecordInfoVo.setScore(BigDecimal.ZERO);
//
//                    //获取这个全部的标识的二级标识
//                    List<HappyMemberLabel> happyMemberLabelChildList = happyMemberLabelMapper.selectList(
//                            Wrappers.lambdaQuery(HappyMemberLabel.class)
//                                    .eq(HappyMemberLabel::getParentId, item.getId())
//                    );
//                    if(CollUtil.isNotEmpty(happyMemberLabelChildList)){
//                        //stream流操作happyMemberLabelChildList,返回一个id的set集合
//                        Set<Long> labelIdSet = happyMemberLabelChildList.stream().map(HappyMemberLabel::getId).collect(Collectors.toSet());
//                        //获取全部会员的绑定关系
//                        List<HappyMemberLabelRecord> happyMemberLabelRecords = happyMemberLabelRecordMapper.selectList(
//                                Wrappers.lambdaQuery(HappyMemberLabelRecord.class)
//                                        .in(HappyMemberLabelRecord::getLabelId, labelIdSet)
//                        );
//                        if(CollUtil.isNotEmpty(happyMemberLabelRecords)){
//                            apiScoreRecordInfoVo.setScore(BigDecimal.ZERO);
//                            apiSaleRecordInfoVos.add(apiScoreRecordInfoVo);
//                            continue;
//                        }
//                        //stream流操作happyMemberLabelRecords,返回一个memberId的set集合
//                        Set<Long> memberIdSet = happyMemberLabelRecords.stream().map(HappyMemberLabelRecord::getMemberId).collect(Collectors.toSet());
//                        List<MallMoneyFlow> mallMoneyFlows = mallMoneyFlowMapper.selectList(
//                                Wrappers.lambdaQuery(MallMoneyFlow.class)
//                                        .select(MallMoneyFlow::getAmount,  MallMoneyFlow::getMemberId)
//                                        .in(MallMoneyFlow::getMemberId, memberIdSet)
//                                        .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.PRIZE_SCORE.getValue())
//                                        .gt(MallMoneyFlow::getAmount, BigDecimal.ZERO)
//                                        .ge(MallMoneyFlow::getCreatedTime, startTime)
//                        );
//                    }
//
//
//                    return item;
//                }, febsConfigure.asyncThreadPoolTaskExecutor());
//                futures.add(uCompletableFuture);
//            });
//            // 等待所有任务完成
//            CompletableFuture<Void> allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
//            allOf.join(); // 阻塞直到所有任务完成
//        }
//
//
//
//        // 如果查询到销售记录,则进行处理
//        if (CollUtil.isNotEmpty(mallAchieveRecords)) {
//            // 提取 memberId 集合,避免重复 stream
//            Set<Long> memberIds = mallAchieveRecords.stream()
//                    .map(MallAchieveRecord::getMemberId)
//                    .collect(Collectors.toSet());
//
//            // 分组求和
//            Map<Long, BigDecimal> memberIdToCostAmount = mallAchieveRecords.stream()
//                    .collect(Collectors.groupingBy(
//                            MallAchieveRecord::getMemberId,
//                            Collectors.mapping(
//                                    MallAchieveRecord::getCostAmount,
//                                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
//                            )
//                    ));
//
//            // 查询会员信息
//            List<MallMember> mallMembers = this.baseMapper.selectList(
//                    new LambdaQueryWrapper<MallMember>()
//                            .select(MallMember::getId, MallMember::getName, MallMember::getAvatar)
//                            .in(MallMember::getId, memberIds)
//            );
//
//            // 构建会员信息映射表
//            Map<Long, MallMember> mallMemberMap = mallMembers.stream()
//                    .collect(Collectors.toMap(MallMember::getId, m -> m));
//
//            // 构建结果列表并避免空指针
//            for (Map.Entry<Long, BigDecimal> entry : memberIdToCostAmount.entrySet()) {
//                MallMember member = mallMemberMap.get(entry.getKey());
//                if (member == null) {
//                    continue; // 忽略不存在的会员
//                }
//                ApiSaleRecordInfoVo vo = new ApiSaleRecordInfoVo();
//                vo.setId(member.getId());
//                vo.setName(member.getName());
//                vo.setAvatar(member.getAvatar());
//                vo.setCostAmount(entry.getValue());
//                apiSaleRecordInfoVos.add(vo);
//            }
//
//            // 排序
//            apiSaleRecordInfoVos.sort(Comparator.comparing(ApiSaleRecordInfoVo::getCostAmount).reversed());
//
//            //stream流操作apiSaleRecordInfoVos获取id等于memberId的数据,并且返回第一个数据和在数组中的下标索引
//            ApiSaleRecordInfoVo memberSale = apiSaleRecordInfoVos.stream()
//                    .filter(vo -> vo.getId().equals(memberId))
//                    .findFirst()
//                    .orElse(null);
//            if (memberSale != null) {
//                apiSaleRecordInfoVo.setSortCnt(apiSaleRecordInfoVos.indexOf(memberSale)+1);
//                apiSaleRecordInfoVo.setCostAmount(memberSale.getCostAmount());
//            }
//        }
//        apiSaleRecordInfoVo.setSaleRecord(apiSaleRecordInfoVos);
        // 返回成功响应,包含销售记录信息
        return new FebsResponse().success().data(apiSaleRecordInfoVos);
    }
    @Override
    public FebsResponse getMemberLabelListById(ApiMemberLabelItemDto dto) {
        // 获取当前登录用户的ID
@@ -1822,11 +2004,30 @@
                            .in(MallMember::getId, memberIdSet)
                    .eq(MallMember::getAccountStatus, MallMember.ACCOUNT_STATUS_ENABLE)
            );
            List<MallMoneyFlow> mallMoneyFlows = mallMoneyFlowMapper.selectList(
                    Wrappers.lambdaQuery(MallMoneyFlow.class)
                            .select(MallMoneyFlow::getAmount,  MallMoneyFlow::getMemberId)
                            .in(MallMoneyFlow::getMemberId, memberIdSet)
                            .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.PRIZE_SCORE.getValue())
                            .gt(MallMoneyFlow::getAmount, BigDecimal.ZERO)
            );
            //stream流操作mallMoneyFlows,返回一个map<Long,BigDecimal>,其中key为memberId,value为mallMoneyFlow的memberId等于key的amount的总和
            Map<Long, BigDecimal> prizeScoreMap = mallMoneyFlows.stream()
                    .filter(Objects::nonNull) // 防止 MallMoneyFlow 为 null
                    .collect(Collectors.groupingBy(
                            MallMoneyFlow::getMemberId,
                            Collectors.mapping(
                                    MallMoneyFlow::getAmount,
                                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
                            )
                    ));
            for (MallMember mallMember : mallMembers){
                ApiMemberLabelItemVo apiMemberLabelItemVo = new ApiMemberLabelItemVo();
                apiMemberLabelItemVo.setName(mallMember.getName());
                apiMemberLabelItemVo.setAvatar(mallMember.getAvatar());
                apiMemberLabelItemVo.setPhone(mallMember.getPhone());
                apiMemberLabelItemVo.setScore(prizeScoreMap.get(mallMember.getId()).setScale(0,RoundingMode.DOWN));
                apiMemberLabelItemVos.add(apiMemberLabelItemVo);
            }
        }
src/main/java/cc/mrbird/febs/mall/vo/memberLevel/ApiMemberLabelItemVo.java
@@ -4,6 +4,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "ApiMemberLabelItemVo", description = "商城用户信息返回类")
public class ApiMemberLabelItemVo {
@@ -17,4 +19,7 @@
    @ApiModelProperty(value = "电话")
    private String phone;
    @ApiModelProperty(value = "积分")
    private BigDecimal score;
}
src/main/java/cc/mrbird/febs/mall/vo/memberLevel/ApiScoreRecordInfoVo.java
New file
@@ -0,0 +1,21 @@
package cc.mrbird.febs.mall.vo.memberLevel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "ApiScoreRecordInfoVo", description = "商城用户信息返回类")
public class ApiScoreRecordInfoVo {
    @ApiModelProperty(value = "昵称")
    private String name;
    @ApiModelProperty(value = "头像")
    private String avatar;
    @ApiModelProperty(value = "总积分")
    private BigDecimal score;
}