Administrator
5 days ago ed5a6de6023e73e7f5b5af86a94aa4f1e43a3fc4
feat(mall): 添加活动报名人数减少逻辑

- 在创建活动订单时,增加剩余报名人数的判断和更新
- 新增 overtimeJob 方法处理未支付订单的过期逻辑
- 修改 HappyActivityService接口,移除 substructJoinCnt 方法
- 在 HappyActivityServiceImpl 中实现 overtimeJob 方法
- 更新数据库 mapper 和 XML 文件,添加更新剩余报名人数的方法
6 files modified
141 ■■■■ changed files
src/main/java/cc/mrbird/febs/mall/mapper/HappyActivityMapper.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java 17 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/HappyActivityService.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminHappyActivityServiceImpl.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/HappyActivityServiceImpl.java 111 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/HappyActivityOptionMapper.xml 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/HappyActivityMapper.java
@@ -22,6 +22,8 @@
    void updateHappyActivityOptionLikeCnt(@Param("id")Long sourceOptionId);
    void updateHappyActivitySurplusCnt(@Param("id")Long activityId, @Param("cnt")Integer cnt);
    Page<ApiActivityOptionListVo> getVoteOptionInPage(Page<ApiActivityOptionListVo> page, @Param("record")ApiVoteOptionInPageDto dto);
    Page<HappyActivityOrder> selectOrderInPage(Page<HappyActivityOrder> page, @Param("record")AdminHappyActivityOrderDto dto);
src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java
@@ -2,9 +2,10 @@
import cc.mrbird.febs.common.enumerates.AgentLevelEnum;
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.utils.MallUtils;
import cc.mrbird.febs.mall.entity.MallMember;
import cc.mrbird.febs.mall.entity.MallMoneyFlow;
import cc.mrbird.febs.mall.entity.*;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.mall.mapper.MallMoneyFlowMapper;
import cc.mrbird.febs.mall.service.HappyActivityService;
@@ -15,6 +16,7 @@
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
@@ -58,4 +60,15 @@
    }
    /**
     * 订单失效
     *          五分钟运行一次
     */
    @Scheduled(cron = "0 0/5 * * * ? ")
    public void overtimeJob() {
        happyActivityService.overtimeJob();
    }
}
src/main/java/cc/mrbird/febs/mall/service/HappyActivityService.java
@@ -53,8 +53,6 @@
    void addLikeCnt(Long sourceOptionId);
    void substructJoinCnt(Long activityId,Integer cnt);
    FebsResponse orderList(ApiActivityOrderListDto dto);
    FebsResponse orderInfo(Long id);
@@ -68,4 +66,6 @@
    FebsResponse checkOrder(ApiCheckOrderDto dto);
    void checkActivityItem(Long orderId);
    void overtimeJob();
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminHappyActivityServiceImpl.java
@@ -169,6 +169,8 @@
        HappyActivity happyActivity = new HappyActivity();
        BeanUtil.copyProperties(dto, happyActivity);
        happyActivity.setCode(code);
        happyActivity.setExpectCnt(dto.getJoinCnt());
        happyActivity.setSurplusCnt(dto.getJoinCnt());
        this.baseMapper.insert(happyActivity);
        return new FebsResponse().success().message("操作成功");
src/main/java/cc/mrbird/febs/mall/service/impl/HappyActivityServiceImpl.java
@@ -30,7 +30,6 @@
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
@@ -71,55 +70,33 @@
        // 检查分页结果是否包含数据
        if(CollUtil.isNotEmpty(happyActivityPage.getRecords())){
            List<ApiActivityInfoVo> records = happyActivityPage.getRecords();
            // 使用Stream流操作records,获取所有活动的ID
            List<Long> ids = records.stream().map(ApiActivityInfoVo::getId).collect(Collectors.toList());
            // 查询关注点赞转发记录,筛选出关注活动类型且未删除的关注记录,并按ID升序排序,限制结果数量为3
            List<HappyFollow> happyFollows = happyFollowMapper.selectList(
                    new LambdaQueryWrapper<HappyFollow>()
                            .eq(HappyFollow::getSourceType, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode())
                            .in(HappyFollow::getSourceId, ids)
                            .eq(HappyFollow::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
                            .orderByAsc(HappyFollow::getId)
                            .last("limit 3")
            );
            // 检查关注记录是否不为空
            if(CollUtil.isNotEmpty(happyFollows)){
                // 使用Stream流操作关注记录,获取所有成员ID的集合
                Set<Long> memberIds = happyFollows.stream().collect(Collectors.mapping(HappyFollow::getMemberId, Collectors.toSet()));
                // 查询成员信息,获取成员的ID和头像
                List<MallMember> mallMembers = mallMemberMapper.selectList(
                        new LambdaQueryWrapper<MallMember>()
                                .select(MallMember::getId,MallMember::getAvatar)
                                .in(MallMember::getId, memberIds)
            // 遍历活动记录,为每个活动添加成员头像信息
            records.forEach(record -> {
                // 查询关注点赞转发记录,筛选出关注活动类型且未删除的关注记录,并按ID升序排序,限制结果数量为3
                List<HappyFollow> happyFollows = happyFollowMapper.selectList(
                        new LambdaQueryWrapper<HappyFollow>()
                                .eq(HappyFollow::getSourceType, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode())
                                .eq(HappyFollow::getSourceId, record.getId())
                                .eq(HappyFollow::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
                                .groupBy(HappyFollow::getMemberId)
                                .orderByAsc(HappyFollow::getId)
                                .last("limit 3")
                );
                // 检查关注记录是否不为空
                if(CollUtil.isNotEmpty(happyFollows)){
                    // 使用Stream流操作关注记录,获取所有成员ID的集合
                    Set<Long> memberIds = happyFollows.stream().collect(Collectors.mapping(HappyFollow::getMemberId, Collectors.toSet()));
                // 使用Stream流操作成员信息,生成一个以成员ID为键,成员信息为值的Map
                Map<Long, MallMember> memberMap = mallMembers.stream()
                        .collect(Collectors.toMap(MallMember::getId, member -> member));
                // 使用Stream流操作关注记录,生成一个以活动ID为键,成员ID列表为值的Map
                Map<Long, List<Long>> followMap = happyFollows.stream()
                        .collect(Collectors.groupingBy(
                                HappyFollow::getSourceId,
                                Collectors.mapping(HappyFollow::getMemberId, Collectors.toList())
                        ));
                // 遍历活动记录,为每个活动添加成员头像信息
                records.forEach(record -> {
                    List<Long> memberIdsForRecord = followMap.get(record.getId());
                    if (CollUtil.isNotEmpty(memberIdsForRecord)) {
                        List<String> memberAvatars = memberIdsForRecord.stream()
                                .map(memberMap::get)
                                .filter(member -> member != null)
                                .map(MallMember::getAvatar)
                                .collect(Collectors.toList());
                        record.setMemberAvatars(memberAvatars);
                    }
                });
            }
                    // 查询成员信息,获取成员的ID和头像
                    List<MallMember> mallMembers = mallMemberMapper.selectList(
                            new LambdaQueryWrapper<MallMember>()
                                    .select(MallMember::getAvatar)
                                    .in(MallMember::getId, memberIds)
                    );
                    List<String> memberAvatars = mallMembers.stream().map(MallMember::getAvatar).collect(Collectors.toList());
                    record.setMemberAvatars(memberAvatars);
                }
            });
        }
        // 返回成功响应,包含活动分页数据
        return new FebsResponse().success().data(happyActivityPage);
@@ -512,9 +489,9 @@
            throw new FebsException("活动已结束");
        }
        Integer joinCnt = happyActivity.getJoinCnt();
        if(joinCnt < numCnt){
            throw new FebsException("报名额度剩下"+joinCnt+",请减少报名人数");
        Integer surplusCnt = happyActivity.getSurplusCnt();
        if(surplusCnt < numCnt){
            throw new FebsException("报名额度剩下"+surplusCnt+",请减少报名人数");
        }
        //支付总金额
        BigDecimal amount = happyActivity.getPayAmount().multiply(new BigDecimal(dto.getNumCnt())).setScale(2, RoundingMode.DOWN);
@@ -547,7 +524,8 @@
            happyActivityOrderItemMapper.insert(happyActivityOrderItem);
        }
        this.substructJoinCnt(activityId, happyActivityOrder.getNumCnt());
        this.baseMapper.updateHappyActivitySurplusCnt(activityId, happyActivityOrder.getNumCnt() * (-1));
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("orderId",happyActivityOrder.getId());
        stringObjectHashMap.put("amount",amount);
@@ -634,17 +612,6 @@
        happyActivityOption.setLikesCnt(happyActivityOption.getLikesCnt() + 1);
        happyActivityOptionMapper.updateById(happyActivityOption);
    }
    @Override
    public void substructJoinCnt(Long activityId, Integer numCnt) {
        HappyActivity happyActivity = this.baseMapper.selectById(activityId);
        if(ObjectUtil.isNotEmpty(happyActivity)){
            happyActivity.setJoinCnt(happyActivity.getJoinCnt() -numCnt);
            this.baseMapper.updateById(happyActivity);
        }
    }
    // 处理无需支付订单
    private void processNoPayOrder(HappyActivityOrder order, Long orderId) {
@@ -941,6 +908,24 @@
    }
    @Override
    public void overtimeJob() {
        List<HappyActivityOrder> happyActivityOrders = happyActivityOrderMapper.selectList(
                new LambdaQueryWrapper<HappyActivityOrder>()
                        .eq(HappyActivityOrder::getState, StateUpDownEnum.ORDER_STATE_WAIT_PAY.getCode())
                        .lt(HappyActivityOrder::getCreatedTime, DateUtil.offsetMinute(new Date(), -10))
        );
        if(CollUtil.isNotEmpty(happyActivityOrders)){
            happyActivityOrders.forEach(happyActivityOrder -> {
                Long activityId = happyActivityOrder.getActivityId();
                Integer numCnt = happyActivityOrder.getNumCnt();
                this.baseMapper.updateHappyActivitySurplusCnt(activityId,numCnt);
            });
        }
    }
    @Override
    public FebsResponse voteActivityHot(Long id) {
        ApiVoteActivityHotVo apiVoteActivityHotVo = new ApiVoteActivityHotVo();
src/main/resources/mapper/modules/HappyActivityOptionMapper.xml
@@ -55,6 +55,11 @@
        update happy_activity_option set likes_cnt = likes_cnt + 1 where id = #{id}
    </update>
    <update id="updateHappyActivitySurplusCnt" >
        update happy_activity set surplus_cnt = likes_cnt + #{cnt} where id = #{id}
    </update>
    <select id="getVoteOptionInPage" resultType="cc.mrbird.febs.mall.vo.ApiActivityOptionListVo">
        select
            a.id as id,