KKSU
2024-12-20 759b602542a22cbb93202e233c42ac4a466b586e
feat(mall): 更新会员等级和积分

- 在 IMemberProfitService 中添加 updateMemberScore 方法
- 在 MallMemberMapper 中添加 updateLevel 方法
- 更新 MallMemberWalletMapper 接口和 XML 文件,添加按列表更新积分的功能
-优化 MemberProfitServiceImpl 中的 updateMemberLevel 方法
- 添加 updateMemberScore 方法实现会员积分清零功能
- 调整 ProfitJob 中的定时任务执行频率
-修复 RunVipServiceImpl 中查询会员积分使用的逻辑
8 files modified
131 ■■■■ changed files
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberWalletMapper.java 4 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java 13 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java 83 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/RunVipServiceImpl.java 17 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberMapper.xml 6 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/MallMemberWalletMapper.xml 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberMapper.java
@@ -98,5 +98,7 @@
    void updateVipLevelTimeAndLevel(@Param("id")Long id,@Param("vipLevelTime") Date lastLogin,@Param("level") String level);
    void updateLevel(@Param("id")Long id,@Param("level") String level);
    void updateNameAndAvatar(@Param("id")Long id, @Param("name")String name, @Param("photo")String photo);
}
src/main/java/cc/mrbird/febs/mall/mapper/MallMemberWalletMapper.java
@@ -4,6 +4,8 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MallMemberWalletMapper extends BaseMapper<MallMemberWallet> {
    MallMemberWallet selectWalletByMemberId(@Param("memberId") Long memberId);
@@ -18,5 +20,5 @@
    void updateBalanceWithId(@Param("record")MallMemberWallet mallMemberWallet);
    void updateScore();
    void updateScore(@Param("list") List<Long> ids);
}
src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java
@@ -17,15 +17,24 @@
    /**
     * 每天凌晨
     * 清空用户的碳积分
     * 套餐过期后,更新用户为游客等级
     */
    @Scheduled(cron = "0 0 0 * * ?")
    @Scheduled(cron = "0 0 0/12 * * ?")
    public void updateMemberLevel() {
        memberProfitService.updateMemberLevel();
    }
    /**
     * 每天凌晨
     * 清空用户的碳积分
     */
//    @Scheduled(cron = "0 0 0 * * ?")
    @Scheduled(cron = "0 0 0/12 * * ?")
    public void updateMemberScore() {
        memberProfitService.updateMemberScore();
    }
    /**
     * 每1小时执行一次
     * 分发碳积分
     *      根据会员等级分发
src/main/java/cc/mrbird/febs/mall/service/IMemberProfitService.java
@@ -45,4 +45,6 @@
    void updateMemberLevel();
    void updateRunScore();
    void updateMemberScore();
}
src/main/java/cc/mrbird/febs/mall/service/impl/MemberProfitServiceImpl.java
@@ -500,23 +500,39 @@
        }
    }
    /**
     * 更新会员等级,将所有等级过期的会员等级重置为最低等级
         * 查询 RunVip 表中按顺序号升序排列的第一条记录,获取最低会员等级。
         * 构建查询条件,查询 MallMember 表中会员等级过期且当前等级不是最低等级的用户。
         * 如果查询结果不为空,遍历每个用户,调用 updateLevel 方法将会员等级更新为最低等级。
         * 处理完所有用户后,结束方法
     */
    @Override
    public void updateMemberLevel() {
        mallMemberWalletMapper.updateScore();
        List<RunVip> runVips = runVipMapper.selectList(new LambdaQueryWrapper<RunVip>().orderByAsc(RunVip :: getOrderNumber));
        RunVip runVip = runVips.get(0);
        //获取过期时间小于等于当前时间,并且会员等级不是最小等级游客的所有用户
        LambdaQueryWrapper<MallMember> mallMemberLambdaQueryWrapper = new LambdaQueryWrapper<>();
        mallMemberLambdaQueryWrapper.le(MallMember :: getVipLevelTime,DateUtil.date());
        mallMemberLambdaQueryWrapper.ne(MallMember :: getLevel,runVip.getVipCode());
        List<MallMember> mallMembers = mallMemberMapper.selectList(mallMemberLambdaQueryWrapper);
        if(CollUtil.isNotEmpty(mallMembers)){
            mallMembers.forEach(
                    item -> {
                        mallMemberMapper.updateVipLevelTimeAndLevel(item.getId(),item.getVipLevelTime(),item.getLevel());
                    }
            );
        // 更新会员等级的逻辑
        try {
            List<RunVip> runVips = runVipMapper.selectList(new LambdaQueryWrapper<RunVip>().orderByAsc(RunVip::getOrderNumber));
            RunVip runVip = runVips.get(0);
            // 获取过期时间小于等于当前时间,并且会员等级不是最小等级游客的所有用户
            LambdaQueryWrapper<MallMember> mallMemberLambdaQueryWrapper = new LambdaQueryWrapper<>();
            mallMemberLambdaQueryWrapper.le(MallMember::getVipLevelTime, DateUtil.date());
            mallMemberLambdaQueryWrapper.ne(MallMember::getLevel, runVip.getVipCode());
            List<MallMember> mallMembers = mallMemberMapper.selectList(mallMemberLambdaQueryWrapper);
            if (CollUtil.isNotEmpty(mallMembers)) {
                mallMembers.forEach(
                        item -> {
                            try {
                                mallMemberMapper.updateLevel(item.getId(), runVip.getVipCode());
                            } catch (Exception e) {
                                log.error("Error updating member level for user {}: ", item.getId(), e);
                            }
                        }
                );
            }
        } catch (Exception e) {
            log.error("Error fetching or updating VIP levels: ", e);
        }
    }
@@ -614,7 +630,46 @@
        }
    }
    public boolean isDivisibleByTwo(int number) {
        return number % 2 == 0;
    }
    /**
     * 更新会员钱包中的积分,将所有积分大于0的会员钱包积分清零
         * 初始化最大尝试次数 maxAttempts 和当前尝试次数 attemptCount。
         * 使用 while 循环,每次查询1000条积分大于0的会员钱包记录。
         * 如果查询结果为空,设置标志位 flag 为 false,退出循环。
         * 否则,提取记录ID并调用 updateScore 方法将积分更新为0。
         * 增加尝试次数,继续下一次循环,直到达到最大尝试次数或查询结果为空。
     */
    @Override
    public void updateMemberScore() {
        // 更新会员钱包积分的逻辑
        int maxAttempts = 100; // 最大尝试次数
        int attemptCount = 0;
        boolean flag = true;
        while (flag && attemptCount < maxAttempts) {
            try {
                Page<MallMemberWallet> page = new Page<>(0, 1000);
                IPage<MallMemberWallet> result = mallMemberWalletMapper.selectPage(
                        page,
                        new LambdaQueryWrapper<MallMemberWallet>()
                                .gt(MallMemberWallet::getScore, 0)
                );
                List<MallMemberWallet> mallMemberWallets = result.getRecords();
                if (CollUtil.isEmpty(mallMemberWallets)) {
                    flag = false;
                } else {
                    List<Long> ids = mallMemberWallets.stream().map(MallMemberWallet::getId).collect(Collectors.toList());
                    mallMemberWalletMapper.updateScore(ids);
                }
                attemptCount++;
            } catch (Exception e) {
                log.error("Error updating member level: ", e);
                flag = false; // 发生异常时退出循环
            }
        }
    }
}
src/main/java/cc/mrbird/febs/mall/service/impl/RunVipServiceImpl.java
@@ -304,10 +304,19 @@
        );
        if(CollUtil.isNotEmpty(mallMoneyFlows)){
            BigDecimal reduce = mallMoneyFlows.stream().map(MallMoneyFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(reduce.intValue() >= realScore){
                apiRunHealthVo.setScoreUsed(reduce.intValue() - realScore);
                apiRunHealthVo.setScoreTotal(reduce.intValue());
            }
            apiRunHealthVo.setScoreTotal(reduce.intValue());
        }
        List<MallMoneyFlow> mallMoneyFlowScoreOuts = mallMoneyFlowMapper.selectList(
                new LambdaQueryWrapper<MallMoneyFlow>()
                        .eq(MallMoneyFlow::getMemberId, memberId)
                        .eq(MallMoneyFlow::getFlowType, FlowTypeEnum.SCORE.getValue())
                        .eq(MallMoneyFlow::getType, RunVipMoneyFlowTypeEnum.SCORE_OUT_BALANCE.getValue())
                        .ge(MallMoneyFlow::getCreatedTime, DateUtil.beginOfDay(DateUtil.date()))
                        .le(MallMoneyFlow::getCreatedTime, DateUtil.endOfDay(DateUtil.date()))
        );
        if(CollUtil.isNotEmpty(mallMoneyFlowScoreOuts)){
            BigDecimal reduce = mallMoneyFlowScoreOuts.stream().map(MallMoneyFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).abs();
            apiRunHealthVo.setScoreUsed(reduce.intValue());
        }
        return apiRunHealthVo;
    }
src/main/resources/mapper/modules/MallMemberMapper.xml
@@ -458,6 +458,12 @@
        where id = #{id}
    </update>
    <update id="updateLevel">
        update mall_member
        set level = #{level}
        where id = #{id}
    </update>
    <update id="updateNameAndAvatar">
        update mall_member
        set avatar = #{photo},
src/main/resources/mapper/modules/MallMemberWalletMapper.xml
@@ -55,5 +55,9 @@
    <update id="updateScore">
        UPDATE mall_member_wallet
        SET score = 0
        where  id IN
        <foreach collection = "list" item = "item"  separator=","  open = "(" close = ")" >
            #{item}
        </foreach >
    </update>
</mapper>