Administrator
9 days ago fd2e2482770479c41bb2cf61b019cc86eb65e077
feat(mall): 添加活动订单管理功能

- 新增活动订单列表页面和相关API接口
- 实现订单查询、手动核销和删除功能
- 添加订单状态、支付状态和支付方式的展示
- 优化活动选择下拉框,支持动态加载活动数据
4 files added
17 files modified
802 ■■■■■ changed files
src/main/java/cc/mrbird/febs/common/enumerates/StateUpDownEnum.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/CommonController.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/activity/AdminVotesActivityCategoryController.java 46 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/activity/ApiHappyActivityController.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/activity/ApiHappyActivityOrderController.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/controller/activity/ViewHappyActivityController.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/ApiActivityDto.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/activity/AdminHappyActivityCheckOrderDto.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/dto/activity/AdminHappyActivityOrderDto.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/entity/HappyActivityOrder.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/mapper/HappyActivityMapper.java 4 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/quartz/ProfitJob.java 68 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/HappyActivityService.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/IAdminHappyActivityService.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/AdminHappyActivityServiceImpl.java 67 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/service/impl/HappyActivityServiceImpl.java 146 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/ApiActivityInfoVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/mall/vo/activity/ApiVoteActivityHotVo.java 30 ●●●●● patch | view | raw | blame | history
src/main/resources/application-test.yml 2 ●●● patch | view | raw | blame | history
src/main/resources/mapper/modules/HappyActivityOptionMapper.xml 26 ●●●●● patch | view | raw | blame | history
src/main/resources/templates/febs/views/modules/votesActivity/orderList.html 287 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/common/enumerates/StateUpDownEnum.java
@@ -69,6 +69,7 @@
    ACTIVITY_STATE_ENROLLING(1),
    ACTIVITY_STATE_END(2),
    /**
     * 是否允许报名 0-不允许 1-允许
     * 状态 0-未开启 1-已开启
     * 是否推荐到首页 0-不推荐 1-推荐
     * 删除标识 0-未删除 1-已删除
src/main/java/cc/mrbird/febs/mall/controller/CommonController.java
@@ -189,6 +189,37 @@
        return new FebsResponse().success().data(dic);
    }
    @ApiOperation(value = "base64FileUpload上传")
    @PostMapping(value = "/base64FileUpload")
    public Map<String,Object> base64FileUpload(@RequestBody @Validated MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            return new FebsResponse().message("上传文件为空").fail();
        }
        try {
            byte[] fileBytes = file.getBytes();
            String base64Str = java.util.Base64.getEncoder().encodeToString(fileBytes);
            String imageSuffix = "." + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
            String imageNames = System.currentTimeMillis() + IdUtil.simpleUUID() + imageSuffix;
            String imageName = "hc/" + imageNames;
            OssUtils.uploadFileWithBase64(base64Str, imageName);
            String bucket_name = "https://excoin.oss-cn-hangzhou.aliyuncs.com";
            String url = bucket_name + "/" + imageName;
            Map<String,Object> map = new HashMap<String,Object>();
            Map<String,Object> map2 = new HashMap<String,Object>();
            map2.put("src",url);//图片url
            map2.put("title",imageNames);//图片名称,这个会显示在输入框里
            map.put("code",0);//0表示成功,1失败
            map.put("msg","上传成功");//提示消息
            map.put("data",map2);
            return map;
        } catch (IOException e) {
            log.error("上传失败: {}", e.getMessage());
            return new FebsResponse().message("上传失败").fail();
        }
    }
    @ApiOperation(value = "base64上传")
    @PostMapping(value = "/base64Upload")
    public FebsResponse base64Upload(@RequestBody @Validated Base64UploadDto base64UploadDto) {
src/main/java/cc/mrbird/febs/mall/controller/activity/AdminVotesActivityCategoryController.java
@@ -6,9 +6,7 @@
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.utils.RedisUtils;
import cc.mrbird.febs.mall.dto.AdminHappyActivityCategoryDto;
import cc.mrbird.febs.mall.dto.activity.AdminActivityOptionAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryUpdateDto;
import cc.mrbird.febs.mall.dto.activity.*;
import cc.mrbird.febs.mall.entity.HappyActivity;
import cc.mrbird.febs.mall.entity.HappyActivityOption;
import cc.mrbird.febs.mall.service.IAdminHappyActivityService;
@@ -142,12 +140,21 @@
    }
    /**
     * 获取全部活动
     * 获取全部投票活动
     * @return
     */
    @GetMapping(value = "/allActivities")
    public FebsResponse allActivities() {
        return new FebsResponse().success().data(adminHappyActivityService.allActivities());
    }
    /**
     * 获取全部众筹活动
     * @return
     */
    @GetMapping(value = "/allOrderActivities")
    public FebsResponse allOrderActivities() {
        return new FebsResponse().success().data(adminHappyActivityService.allOrderActivities());
    }
    /**
@@ -205,4 +212,35 @@
        return new FebsResponse().success().data(data);
    }
    /**
     * 订单
     * @return
     */
    @GetMapping("activityOrderList")
    public FebsResponse activityOrderList(AdminHappyActivityOrderDto dto, QueryRequest request) {
        Map<String, Object> data = getDataTable(adminHappyActivityService.activityOrderList(dto, request));
        return new FebsResponse().success().data(data);
    }
    /**
     * 订单-手动核销
     */
    @PostMapping("checkOrder")
    @ControllerEndpoint(operation = "订单-手动核销", exceptionMessage = "操作失败")
    public FebsResponse checkOrder(@RequestBody AdminHappyActivityCheckOrderDto dto) {
        return adminHappyActivityService.checkOrder(dto);
    }
    /**
     * 订单-删除
     */
    @GetMapping("activityOrderDel/{id}")
    @ControllerEndpoint(operation = "订单-删除", exceptionMessage = "操作失败")
    public FebsResponse activityOrderDel(@NotNull(message = "{required}") @PathVariable Long id) {
        return adminHappyActivityService.activityOrderDel(id);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/activity/ApiHappyActivityController.java
@@ -6,6 +6,7 @@
import cc.mrbird.febs.mall.dto.activity.ApiVoteOptionInPageDto;
import cc.mrbird.febs.mall.service.HappyActivityService;
import cc.mrbird.febs.mall.vo.*;
import cc.mrbird.febs.mall.vo.activity.ApiVoteActivityHotVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
@@ -63,6 +64,16 @@
        return happyActivityService.voteOptionInPage(dto);
    }
    @ApiOperation(value = "投票活动-活动热度", notes = "投票活动-活动热度")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiVoteActivityHotVo.class)
    })
    @GetMapping(value = "/voteActivityHot/{id}")
    public FebsResponse voteActivityHot(@PathVariable("id") Long id) {
        return happyActivityService.voteActivityHot(id);
    }
    @ApiOperation(value = "投票活动-选项详情", notes = "投票活动-选项详情")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ApiActivityOptionVo.class)
@@ -91,4 +102,11 @@
        return happyActivityService.voteRecordInPage(dto);
    }
    @ApiOperation(value = "投票活动-报名", notes = "投票活动-报名")
    @PostMapping(value = "/operateRegister")
    public FebsResponse operateRegister(@RequestBody @Validated ApiOperateRegisterActivityDto dto) {
        return happyActivityService.operateRegister(dto);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/activity/ApiHappyActivityOrderController.java
@@ -105,4 +105,11 @@
        return happyActivityService.orderInfo(id);
    }
    @ApiOperation(value = "我的报名-删除", notes = "我的报名-删除")
    @GetMapping(value = "/orderDelete/{id}")
    public FebsResponse orderDelete(@PathVariable("id") Long id) {
        return happyActivityService.orderDelete(id);
    }
}
src/main/java/cc/mrbird/febs/mall/controller/activity/ViewHappyActivityController.java
@@ -138,4 +138,13 @@
        redisUtils.set("voteRecord", id, -1);
        return FebsUtil.view("modules/votesActivity/voteRecord");
    }
    /**
     * 活动-订单列表
     */
    @GetMapping("orderList")
    @RequiresPermissions("orderList:view")
    public String orderList() {
        return FebsUtil.view("modules/votesActivity/orderList");
    }
}
src/main/java/cc/mrbird/febs/mall/dto/ApiActivityDto.java
@@ -14,7 +14,4 @@
    @ApiModelProperty(value = "ID")
    private Long id;
    @NotNull(message = "活动类型不能为空")
    @ApiModelProperty(value = "活动类型 1-普通活动 2-众筹活动 3-投票活动")
    private Integer type;
}
src/main/java/cc/mrbird/febs/mall/dto/activity/AdminHappyActivityCheckOrderDto.java
New file
@@ -0,0 +1,11 @@
package cc.mrbird.febs.mall.dto.activity;
import lombok.Data;
import java.util.List;
@Data
public class AdminHappyActivityCheckOrderDto {
    private List<Long> ids;
}
src/main/java/cc/mrbird/febs/mall/dto/activity/AdminHappyActivityOrderDto.java
New file
@@ -0,0 +1,10 @@
package cc.mrbird.febs.mall.dto.activity;
import lombok.Data;
@Data
public class AdminHappyActivityOrderDto {
    private String name;
    private Integer state;
    private Long activityId;
}
src/main/java/cc/mrbird/febs/mall/entity/HappyActivityOrder.java
@@ -1,6 +1,7 @@
package cc.mrbird.febs.mall.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@@ -42,4 +43,11 @@
    private String payOrderNo;
    private String wxOrderNo;
    private Integer state;
    @TableField(exist = false)
    private String name;//
    @TableField(exist = false)
    private String activityName;//
}
src/main/java/cc/mrbird/febs/mall/mapper/HappyActivityMapper.java
@@ -1,8 +1,10 @@
package cc.mrbird.febs.mall.mapper;
import cc.mrbird.febs.mall.dto.activity.AdminHappyActivityOrderDto;
import cc.mrbird.febs.mall.dto.activity.ApiVoteOptionInPageDto;
import cc.mrbird.febs.mall.entity.HappyActivity;
import cc.mrbird.febs.mall.dto.ApiActivityInfoDto;
import cc.mrbird.febs.mall.entity.HappyActivityOrder;
import cc.mrbird.febs.mall.vo.ApiActivityInfoVo;
import cc.mrbird.febs.mall.dto.ApiVoteRecordInPageDto;
import cc.mrbird.febs.mall.vo.ApiActivityOptionListVo;
@@ -20,4 +22,6 @@
    void updateHappyActivityOptionLikeCnt(@Param("id")Long sourceOptionId);
    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
@@ -7,6 +7,7 @@
import cc.mrbird.febs.mall.entity.MallMoneyFlow;
import cc.mrbird.febs.mall.mapper.MallMemberMapper;
import cc.mrbird.febs.mall.mapper.MallMoneyFlowMapper;
import cc.mrbird.febs.mall.service.HappyActivityService;
import cc.mrbird.febs.mall.service.IApiMallMemberService;
import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
import cc.mrbird.febs.mall.service.IMemberProfitService;
@@ -15,6 +16,7 @@
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -22,58 +24,38 @@
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
/**
 * @author wzy
 * @date 2021-09-28
 **/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "system", name = "job", havingValue = "true")
public class ProfitJob {
    @Autowired
    private IMemberProfitService memberProfitService;
    @Resource
    private HappyActivityService happyActivityService;
//    /**
//     * 代理分红
//     */
//    @Scheduled(cron = "0 30 0 * * ?")
//    public void profitJob() {
//        memberProfitService.agentProfit(null);
//    }
//
//    @Scheduled(cron = "0 30 1 * * ?")
//    public void storeAndDirectorJob() {
//        memberProfitService.storeAndDirectorProfit(null);
//    }
//
//    /**
//     * 感恩奖
//     */
//    @Scheduled(cron = "0 0 1 * * ?")
//    public void thankfulJob() {
//        memberProfitService.thankfulProfit(null);
//    }
//
//
//    /**
//     * 静态分红
//     */
//    @Scheduled(cron = "0 0 0 * * ?")
//    public void staticProfitJob() {
//        memberProfitService.staticProfit(null);
//    }
//
//    /**
//     * 排名奖 每月1号
//     */
//    @Scheduled(cron = "0 30 0 1 * ?")
//    public void rankJob() {
//        memberProfitService.rankProfit();
//    }
    /**
     * 活动时间结束更新
     *          一分钟运行一次
     */
    @Scheduled(cron = "0 0/1 * * * ? ")
    public void activityEnd() {
        happyActivityService.activityEnd();
    }
    /**
     * 活动时间开始更新
     *          一分钟运行一次
     */
    @Scheduled(cron = "0 0/1 * * * ? ")
    public void activityStart() {
        happyActivityService.activityStart();
    }
}
src/main/java/cc/mrbird/febs/mall/service/HappyActivityService.java
@@ -18,6 +18,8 @@
    FebsResponse voteOptionInPage(ApiVoteOptionInPageDto dto);
    FebsResponse voteActivityHot(Long id);
    FebsResponse voteOption(Long id);
    FebsResponse operateDo(ApiOperateDoDto dto);
@@ -53,4 +55,10 @@
    FebsResponse orderList(ApiActivityOrderListDto dto);
    FebsResponse orderInfo(Long id);
    FebsResponse orderDelete(Long id);
    void activityEnd();
    void activityStart();
}
src/main/java/cc/mrbird/febs/mall/service/IAdminHappyActivityService.java
@@ -3,13 +3,8 @@
import cc.mrbird.febs.common.entity.FebsResponse;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.mall.dto.AdminHappyActivityCategoryDto;
import cc.mrbird.febs.mall.dto.activity.AdminActivityOptionAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryUpdateDto;
import cc.mrbird.febs.mall.entity.HappyActivity;
import cc.mrbird.febs.mall.entity.HappyActivityCategory;
import cc.mrbird.febs.mall.entity.HappyActivityOption;
import cc.mrbird.febs.mall.entity.HappyFollow;
import cc.mrbird.febs.mall.dto.activity.*;
import cc.mrbird.febs.mall.entity.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -46,6 +41,8 @@
    List<HappyActivity> allActivities();
    List<HappyActivity> allOrderActivities();
    FebsResponse addOption(AdminActivityOptionAddDto dto);
    FebsResponse optionUpdate(HappyActivityOption dto);
@@ -53,4 +50,10 @@
    FebsResponse optionDelete(Long id);
    IPage<HappyFollow> getFollowVoteInPage(HappyActivityOption voteRecord, QueryRequest request);
    IPage<HappyActivityOrder> activityOrderList(AdminHappyActivityOrderDto dto, QueryRequest request);
    FebsResponse checkOrder(AdminHappyActivityCheckOrderDto dto);
    FebsResponse activityOrderDel(Long id);
}
src/main/java/cc/mrbird/febs/mall/service/impl/AdminHappyActivityServiceImpl.java
@@ -5,9 +5,7 @@
import cc.mrbird.febs.common.enumerates.StateUpDownEnum;
import cc.mrbird.febs.common.utils.MallUtils;
import cc.mrbird.febs.mall.dto.AdminHappyActivityCategoryDto;
import cc.mrbird.febs.mall.dto.activity.AdminActivityOptionAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryAddDto;
import cc.mrbird.febs.mall.dto.activity.AdminCategoryUpdateDto;
import cc.mrbird.febs.mall.dto.activity.*;
import cc.mrbird.febs.mall.entity.*;
import cc.mrbird.febs.mall.mapper.*;
import cc.mrbird.febs.mall.service.IAdminHappyActivityService;
@@ -38,6 +36,8 @@
    private final HappyActivityCategoryMapper happyActivityCategoryMapper;
    private final HappyActivityOptionMapper happyActivityOptionMapper;
    private final HappyActivityOrderMapper happyActivityOrderMapper;
    private final HappyActivityOrderItemMapper happyActivityOrderItemMapper;
    private final HappyFollowMapper happyFollowMapper;
    private final MallMemberMapper mallMemberMapper;
@@ -264,6 +264,17 @@
    }
    @Override
    public List<HappyActivity> allOrderActivities() {
        List<HappyActivity> happyActivities = this.baseMapper.selectList(
                new LambdaQueryWrapper<HappyActivity>()
                        .select(HappyActivity::getId, HappyActivity::getName)
                        .eq(HappyActivity::getType, StateUpDownEnum.ACTIVITY_TYPE_CROWDFUNDING.getCode())
                        .eq(HappyActivity::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
        );
        return happyActivities;
    }
    @Override
    public FebsResponse addOption(AdminActivityOptionAddDto dto) {
@@ -271,7 +282,7 @@
            return new FebsResponse().fail().message("请选择投票活动");
        }
        List<HappyActivityOption> happyActivityOptions = happyActivityOptionMapper.selectList(
        Integer optionCnt = happyActivityOptionMapper.selectCount(
                new LambdaQueryWrapper<HappyActivityOption>()
                        .eq(HappyActivityOption::getActivityId, dto.getActivityId())
                        .eq(HappyActivityOption::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
@@ -280,7 +291,7 @@
        HappyActivityOption happyActivityOption = new HappyActivityOption();
        BeanUtil.copyProperties(dto, happyActivityOption);
        happyActivityOption.setOrderCnt(CollUtil.isEmpty(happyActivityOptions) ? 1 : happyActivityOptions.size() + 1);
        happyActivityOption.setOrderCnt(optionCnt + 1);
        happyActivityOptionMapper.insert(happyActivityOption);
        return new FebsResponse().success().message("操作成功");
    }
@@ -343,4 +354,50 @@
        }
        return adminIPage;
    }
    @Override
    public IPage<HappyActivityOrder> activityOrderList(AdminHappyActivityOrderDto dto, QueryRequest request) {
        Page<HappyActivityOrder> page = new Page<>(request.getPageNum(), request.getPageSize());
        Page<HappyActivityOrder> adminOptionVoIPage = this.baseMapper.selectOrderInPage(page, dto);
        return adminOptionVoIPage;
    }
    @Override
    public FebsResponse checkOrder(AdminHappyActivityCheckOrderDto dto) {
        List<Long> ids = dto.getIds();
        if (CollUtil.isEmpty(ids)){
            return new FebsResponse().fail().message("请选择需要核销的订单");
        }
        for(Long id : ids){
            HappyActivityOrder happyActivityOrder = happyActivityOrderMapper.selectById(id);
            happyActivityOrder.setState(StateUpDownEnum.ORDER_STATE_USED.getCode());
            happyActivityOrderMapper.updateById(happyActivityOrder);
            List<HappyActivityOrderItem> happyActivityOrderItems = happyActivityOrderItemMapper.selectList(
                    new LambdaQueryWrapper<HappyActivityOrderItem>()
                            .eq(HappyActivityOrderItem::getOrderId, id)
            );
            if(CollUtil.isNotEmpty(happyActivityOrderItems)){
                happyActivityOrderItems.forEach(happyActivityOrderItem -> {
                    happyActivityOrderItem.setState(StateUpDownEnum.ORDER_STATE_USED.getCode());
                    happyActivityOrderItemMapper.updateById(happyActivityOrderItem);
                });
            }
        }
        return new FebsResponse().success().message("操作成功");
    }
    @Override
    public FebsResponse activityOrderDel(Long id) {
        HappyActivityOrder happyActivityOrder = happyActivityOrderMapper.selectById(id);
        if(ObjectUtil.isNotEmpty(happyActivityOrder)){
            happyActivityOrder.setDeleteFlag(StateUpDownEnum.UP.getCode());
            happyActivityOrderMapper.updateById(happyActivityOrder);
        }
        return new FebsResponse().success().message("操作成功");
    }
}
src/main/java/cc/mrbird/febs/mall/service/impl/HappyActivityServiceImpl.java
@@ -17,6 +17,7 @@
import cc.mrbird.febs.mall.dto.ApiOperateDoDto;
import cc.mrbird.febs.mall.vo.activity.ApiActivityOrderInfoVo;
import cc.mrbird.febs.mall.vo.activity.ApiActivityOrderListVo;
import cc.mrbird.febs.mall.vo.activity.ApiVoteActivityHotVo;
import cc.mrbird.febs.pay.model.BrandWCPayRequestData;
import cc.mrbird.febs.pay.service.IXcxPayService;
import cn.hutool.core.bean.BeanUtil;
@@ -130,7 +131,6 @@
        HappyActivity happyActivity = this.baseMapper.selectOne(
                new LambdaQueryWrapper<HappyActivity>()
                        .eq(HappyActivity::getId, dto.getId())
                        .eq(HappyActivity::getType, dto.getType())
                        .eq(HappyActivity::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
                        .ne(HappyActivity::getState, StateUpDownEnum.ACTIVITY_STATE_NOT_START.getCode())
        );
@@ -231,6 +231,12 @@
        if(StateUpDownEnum.ACTIVITY_TYPE_VOTE.getCode() != happyActivity.getType()){
            throw new FebsException("当前活动无法投票");
        }
        if (StateUpDownEnum.ACTIVITY_STATE_NOT_START.getCode() == happyActivity.getState()) {
            throw new FebsException("活动尚未开始");
        }
        if (StateUpDownEnum.ACTIVITY_STATE_END.getCode() == happyActivity.getState()) {
            throw new FebsException("活动已结束");
        }
        HappyActivityOption happyActivityOption = happyActivityOptionMapper.selectById(sourceOptionId);
        if (null == happyActivityOption) {
@@ -290,12 +296,54 @@
    @Override
    public FebsResponse operateRegister(ApiOperateRegisterActivityDto dto) {
        Long memberId = LoginUserUtil.getLoginUser().getId();
        return null;
        HappyActivity happyActivity = this.baseMapper.selectById(dto.getActivityId());
        if (StateUpDownEnum.ACTIVITY_STATE_END.getCode() == happyActivity.getState()) {
            throw new FebsException("活动已结束");
        }
        if (StateUpDownEnum.DOWN.getCode() == happyActivity.getAddState()) {
            throw new FebsException("活动尚未开启报名");
        }
        //判断用户是否重复报名
        Integer registerCnt = happyActivityOptionMapper.selectCount(
                new LambdaQueryWrapper<HappyActivityOption>()
                        .eq(HappyActivityOption::getMemberId, memberId)
                        .eq(HappyActivityOption::getActivityId, dto.getActivityId())
                        .ne(HappyActivityOption::getState, StateUpDownEnum.VOTE_OPTION_STATE_AUDIT_REFUSE.getCode())
                        .eq(HappyActivityOption::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
        );
        if (registerCnt > 0) {
            throw new FebsException("您已经报名过了");
        }
        Integer optionCnt = happyActivityOptionMapper.selectCount(
                new LambdaQueryWrapper<HappyActivityOption>()
                        .eq(HappyActivityOption::getActivityId, dto.getActivityId())
                        .eq(HappyActivityOption::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
        );
        HappyActivityOption happyActivityOption = new HappyActivityOption();
        BeanUtil.copyProperties(dto, happyActivityOption);
        happyActivityOption.setOrderCnt(optionCnt + 1);
        happyActivityOption.setMemberId(memberId);
        happyActivityOption.setOptionName(dto.getRealName());
        happyActivityOptionMapper.insert(happyActivityOption);
        return new FebsResponse().success().message("报名成功");
    }
    @Override
    public FebsResponse addConnect(ApiOperateRegisterUserDto dto) {
        Long memberId = LoginUserUtil.getLoginUser().getId();
        List<HappyActivityConnect> happyActivityConnects = happyActivityConnectMapper.selectList(
                new LambdaQueryWrapper<HappyActivityConnect>()
                        .eq(HappyActivityConnect::getMemberId, memberId)
                        .eq(HappyActivityConnect::getName, dto.getName())
        );
        if(CollUtil.isNotEmpty(happyActivityConnects)){
            throw new FebsException("已经添加过该联系人");
        }
        HappyActivityConnect happyActivityConnect = new HappyActivityConnect();
        happyActivityConnect.setMemberId(memberId);
@@ -573,6 +621,7 @@
        if(ObjectUtil.isNotEmpty(dto.getState())){
            happyActivityOrderLambdaQueryWrapper.eq(HappyActivityOrder::getState, dto.getState());
        }
        happyActivityOrderLambdaQueryWrapper.eq(HappyActivityOrder::getDeleteFlag, StateUpDownEnum.DOWN.getCode());
        happyActivityOrderLambdaQueryWrapper.orderByDesc(HappyActivityOrder::getCreatedTime);
        Page<HappyActivityOrder> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        Page<HappyActivityOrder> voteActivityPage = happyActivityOrderMapper.selectPage(page, happyActivityOrderLambdaQueryWrapper);
@@ -655,6 +704,99 @@
        return new FebsResponse().success().data(apiActivityOrderInfoVos);
    }
    @Override
    public FebsResponse orderDelete(Long id) {
        // 获取当前登录用户的ID
        Long memberId = LoginUserUtil.getLoginUser().getId();
        List<HappyActivityOrder> happyActivityOrders = happyActivityOrderMapper.selectList(
                new LambdaQueryWrapper<HappyActivityOrder>()
                        .eq(HappyActivityOrder::getId, id)
                        .eq(HappyActivityOrder::getMemberId, memberId)
        );
        if(CollUtil.isNotEmpty(happyActivityOrders)){
            happyActivityOrders.forEach(happyActivityOrder -> {
                happyActivityOrder.setDeleteFlag(StateUpDownEnum.UP.getCode());
                happyActivityOrderMapper.updateById(happyActivityOrder);
            });
        }
        return new FebsResponse().success();
    }
    @Override
    public void activityEnd() {
        Date date = new Date();
        List<HappyActivity> happyActivities = this.baseMapper.selectList(
                new LambdaQueryWrapper<HappyActivity>()
                        .eq(HappyActivity::getState, StateUpDownEnum.ACTIVITY_STATE_ENROLLING.getCode())
                        .le(HappyActivity::getEndTime, date)
        );
        if(CollUtil.isEmpty(happyActivities)){
            return;
        }
        happyActivities.forEach(happyActivity -> {
            happyActivity.setState(StateUpDownEnum.ACTIVITY_STATE_END.getCode());
            this.baseMapper.updateById(happyActivity);
        });
    }
    /**
     * 当活动即将开始时自动更新活动状态
     * 此方法旨在查询所有即将开始的活动,并将它们的状态更新为报名进行中
     */
    @Override
    public void activityStart() {
        // 获取当前日期和时间
        DateTime date = DateUtil.date();
        // 查询所有状态为未开始且当前时间在活动开始时间结束时间之间的活动
        List<HappyActivity> happyActivities = this.baseMapper.selectList(
                new LambdaQueryWrapper<HappyActivity>()
                        .eq(HappyActivity::getState, StateUpDownEnum.ACTIVITY_STATE_NOT_START.getCode())
                        .le(HappyActivity::getStartTime, date)
                        .ge(HappyActivity::getEndTime, date)
        );
        // 如果没有找到任何符合条件的活动,则直接返回
        if(CollUtil.isEmpty(happyActivities)){
            return;
        }
        // 遍历每个符合条件的活动,将其状态更新为报名进行中,并保存更新
        happyActivities.forEach(happyActivity -> {
            happyActivity.setState(StateUpDownEnum.ACTIVITY_STATE_ENROLLING.getCode());
            this.baseMapper.updateById(happyActivity);
        });
    }
    @Override
    public FebsResponse voteActivityHot(Long id) {
        ApiVoteActivityHotVo apiVoteActivityHotVo = new ApiVoteActivityHotVo();
        HappyActivity happyActivity = this.baseMapper.selectById(id);
        apiVoteActivityHotVo.setStartTime(happyActivity.getStartTime());
        apiVoteActivityHotVo.setEndTime(happyActivity.getEndTime());
        Integer optionCnt = happyActivityOptionMapper.selectCount(
                new LambdaQueryWrapper<HappyActivityOption>()
                        .eq(HappyActivityOption::getActivityId, id)
                        .eq(HappyActivityOption::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
                        .eq(HappyActivityOption::getState, StateUpDownEnum.VOTE_OPTION_STATE_AUDIT_SUCCESS.getCode())
        );
        apiVoteActivityHotVo.setOptionCnt(optionCnt);
        Integer followVoteCnt = happyFollowMapper.selectCount(
                new LambdaQueryWrapper<HappyFollow>()
                        .eq(HappyFollow::getSourceType, StateUpDownEnum.SOURCE_TYPE_ACTIVITY.getCode())
                        .eq(HappyFollow::getSourceId, id)
                        .eq(HappyFollow::getType, StateUpDownEnum.VOTE.getCode())
                        .eq(HappyFollow::getDeleteFlag, StateUpDownEnum.DOWN.getCode())
        );
        apiVoteActivityHotVo.setFollowVoteCnt(followVoteCnt);
        return new FebsResponse().success().data(apiVoteActivityHotVo);
    }
    public static void main(String[] args) {
        Date date = new Date();
src/main/java/cc/mrbird/febs/mall/vo/ApiActivityInfoVo.java
@@ -27,6 +27,9 @@
    @ApiModelProperty(value = "地点")
    private String address;
    @ApiModelProperty(value = "活动类型 1-普通活动 2-众筹活动 3-投票活动")
    private Integer type;
    @ApiModelProperty(value = "状态 0-未开始 1-报名中(进行中) 2-已结束")
    private Integer state;
src/main/java/cc/mrbird/febs/mall/vo/activity/ApiVoteActivityHotVo.java
New file
@@ -0,0 +1,30 @@
package cc.mrbird.febs.mall.vo.activity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "ApiVoteActivityHotVo", description = "参数")
public class ApiVoteActivityHotVo {
    @ApiModelProperty(value = "参与选手数量")
    private Integer optionCnt;
    @ApiModelProperty(value = "累计总票数")
    private Integer followVoteCnt;
    @ApiModelProperty(value = "活动开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date startTime;
    @ApiModelProperty(value = "活动结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date endTime;
}
src/main/resources/application-test.yml
@@ -40,7 +40,7 @@
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 10000
    # 连接超时时间(毫秒)
    timeout: 5000
    timeout: 5000000
  rabbitmq:
    host: 120.27.238.55
    port: 5672
src/main/resources/mapper/modules/HappyActivityOptionMapper.xml
@@ -8,6 +8,7 @@
            a.address,
            a.index_img,
            a.code,
            a.type,
            a.name,
            a.state,
            a.join_cnt,
@@ -62,4 +63,29 @@
        order by a.order_cnt asc
    </select>
    <select id="selectOrderInPage" resultType="cc.mrbird.febs.mall.entity.HappyActivityOrder">
        select
        a.*,
               b.name as name,
               c.name as activityName
        from happy_activity_order a
        left join mall_member b on a.member_id = b.id
        left join happy_activity c on a.activity_id = c.id
        <where>
            and a.DELETE_FLAG = 0
            <if test="record != null">
                <if test="record.name != null and record.name != ''">
                    and b.name like CONCAT('%', CONCAT(#{record.name}, '%'))
                </if>
                <if test="record.state != null">
                    and a.state=#{record.state}
                </if>
                <if test="record.activityId != null">
                    and a.activity_id=#{record.activityId}
                </if>
            </if>
        </where>
        order by a.id desc
    </select>
</mapper>
src/main/resources/templates/febs/views/modules/votesActivity/orderList.html
New file
@@ -0,0 +1,287 @@
<div class="layui-fluid layui-anim febs-anim" id="febs-activity-order" lay-title="活动订单管理">
    <div class="layui-row febs-container">
        <div class="layui-col-md12">
            <div class="layui-card">
                <div class="layui-card-body febs-table-full">
                    <form class="layui-form layui-table-form" lay-filter="activity-order-table-form">
                        <div class="layui-row">
                            <div class="layui-col-md10">
                                <div class="layui-form-item">
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">名称</label>
                                        <div class="layui-input-inline">
                                            <input type="text" placeholder="名称" name="name" autocomplete="off" class="layui-input">
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">状态</label>
                                        <div class="layui-input-inline">
                                            <select name="status">
                                                <option value="">请选择</option>
                                                <option value="1">待支付</option>
                                                <option value="2">待使用</option>
                                                <option value="3">已使用</option>
                                                <option value="4">售后</option>
                                            </select>
                                        </div>
                                    </div>
                                    <div class="layui-inline">
                                        <label class="layui-form-label layui-form-label-sm">活动</label>
                                        <div class="layui-input-inline">
                                            <select name="activityId" class="activity-type">
                                                <option value="">请选择</option>
                                            </select>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area">
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query">
                                    <i class="layui-icon">&#xe848;</i>
                                </div>
                                <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset">
                                    <i class="layui-icon">&#xe79b;</i>
                                </div>
                            </div>
                        </div>
                    </form>
                    <table lay-filter="orderActivityTable" lay-data="{id: 'orderActivityTable'}"></table>
                </div>
            </div>
        </div>
    </div>
</div>
<!-- 表格操作栏 start -->
<script type="text/html" id="user-option">
    <span shiro:lacksPermission="list:view,add:add,votesActivityUpdate:update">
        <span class="layui-badge-dot febs-bg-orange"></span> 无权限
    </span>
    <a lay-event="edit" shiro:hasPermission="votesActivityUpdate:update"><i
            class="layui-icon febs-edit-area febs-blue">&#xe7a5;</i></a>
</script>
<script type="text/html" id="orderActivityToolbar">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" shiro:hasPermission="orderActivity:update" lay-event="checkOrder">手动核销</button>
    </div>
</script>
<script type="text/html" id="orderActivityOption">
<!--    <button class="layui-btn layui-btn-normal layui-btn-sm" type="button" shiro:hasPermission="orderActivity:info" lay-event="orderActivity">详情</button>-->
    <button class="layui-btn layui-btn-danger layui-btn-sm" type="button" shiro:hasPermission="orderActivity:info" lay-event="groupDelete">删除</button>
<!--    <button class="layui-btn layui-btn-danger layui-btn-sm" type="button" shiro:hasPermission="orderActivity:returnOrder" lay-event="returnOrder">售后退款</button>-->
</script>
<script type="text/html" id="orderStateOption">
    {{#
    var state = {
    1: {title: '待支付', color: 'blue'},
    2: {title: '待使用', color: 'orange'},
    3: {title: '已使用', color: 'green'},
    4: {title: '售后', color: 'red'},
    }[d.state];
    }}
    <span class="layui-badge febs-bg-{{state.color}}">{{ state.title }}</span>
</script>
<script type="text/html" id="payStateOption">
    {{#
    var payState = {
    0: {title: '待支付', color: 'blue'},
    1: {title: '成功', color: 'green'},
    2: {title: '失败', color: 'red'},
    }[d.payState];
    }}
    <span class="layui-badge febs-bg-{{payState.color}}">{{ payState.title }}</span>
</script>
<script type="text/html" id="payTypeOption">
    {{#
    var payType = {
    1: {title: '余额', color: 'blue'},
    2: {title: '微信', color: 'green'},
    3: {title: '积分', color: 'orange'},
    4: {title: '免费', color: 'red'},
    }[d.payType];
    }}
    <span class="layui-badge febs-bg-{{payType.color}}">{{ payType.title }}</span>
</script>
<style>
    .layui-form-onswitch {
        background-color: #5FB878 !important;
    }
</style>
<!-- 表格操作栏 end -->
<script data-th-inline="none" type="text/javascript">
    // 引入组件并初始化
    layui.use([ 'jquery', 'form', 'table', 'febs'], function () {
        var $ = layui.jquery,
            febs = layui.febs,
            form = layui.form,
            table = layui.table,
            $view = $('#febs-activity-order'),
            $query = $view.find('#query'),
            $reset = $view.find('#reset'),
            $searchForm = $view.find('form'),
            sortObject = {field: 'phone', type: null},
            tableIns;
        form.render();
        //(下拉框)
        $.get(ctx + 'admin/happyActivity/allOrderActivities', function (res) {
            var data = res.data;
            for (let k in data)
            {
                $(".activity-type").append("<option value='" + data[k].id + "'>" + data[k].name + "</option>");
            }
            layui.use('form', function () {
                var form = layui.form;
                form.render();
            });
        });
        // 表格初始化
        initorderActivityTable();
        // 初始化表格操作栏各个按钮功能
        table.on('tool(orderActivityTable)', function (obj) {
            var data = obj.data,
                layEvent = obj.event;
            if (layEvent === 'groupDelete') {
                febs.modal.confirm('删除', '确认删除?', function () {
                    groupDelete(data.id);
                });
            }
            if (layEvent === 'groupInfo') {
                febs.modal.open('编辑','modules/votesActivity/groupInfo/' + data.id, {
                    btn: ['提交', '取消'],
                    area: ['100%', '100%'],
                    yes: function (index, layero) {
                        $('#febs-group-info').find('#submit').trigger('click');
                    },
                    btn2: function () {
                        layer.closeAll();
                    }
                });
            }
        });
        function groupDelete(id) {
            febs.get(ctx + 'admin/happyActivity/activityOrderDel/' + id, null, function (data) {
                febs.alert.success(data.message);
                $query.click();
            });
        }
        // 初始化表格操作栏各个按钮功能
        table.on('toolbar(orderActivityTable)', function (obj) {
            console.log("触发事件:", obj.event); // 调试信息
            let event = obj.event;
            let id = obj.config.id;
            let checkStatus = table.checkStatus(id);
            if(event === 'checkOrder'){
                let data = checkStatus.data;
                let ids = [];
                for(let i = 0;i < data.length;i++){
                    if(data[i].state != 2){
                        febs.alert.warn('请选择待使用的订单');
                        return;
                    }else{
                        ids.push(data[i].id);
                    }
                }
                console.log(ids);
                if(ids == null || ids == ""){
                    febs.alert.warn('请选择需要核销的订单');
                    return;
                }
                $.ajax({
                    'url':ctx + 'admin/happyActivity/checkOrder',
                    'type':'post',
                    'dataType':'json',
                    'headers' : {'Content-Type' : 'application/json;charset=utf-8'}, //接口json格式
                    'traditional': true,//ajax传递数组必须添加属性
                    'data':ids,
                    'success':function (data) {
                        if(data.code==200){
                            febs.alert.success('操作成功');
                            $query.click();
                        }else{
                            febs.alert.warn(data.message);
                        }
                    },
                    'error':function () {
                        febs.alert.warn('服务器繁忙');
                    }
                })
            }
        });
        function initorderActivityTable() {
            tableIns = febs.table.init({
                elem: $view.find('table'),
                id: 'orderActivityTable',
                url: ctx + 'admin/happyActivity/activityOrderList',
                toolbar:"#orderActivityToolbar",
                defaultToolbar:[],
                cols: [[
                    {type: 'numbers', title: '', width: 80},
                    {title: '操作', toolbar: '#orderActivityOption', minWidth: 200, align: 'center'},
                    {field: 'name', title: '名称', minWidth: 100,align:'center'},
                    {field: 'orderNo', title: '订单编号', minWidth: 100,align:'center'},
                    {field: 'activityName', title: '活动名称', minWidth: 100,align:'center'},
                    {field: 'price', title: '单价', minWidth: 100,align:'center'},
                    {field: 'numCnt', title: '数量', minWidth: 100,align:'center'},
                    {field: 'amount', title: '总价', minWidth: 100,align:'center'},
                    {title: '订单状态', templet: '#orderStateOption', minWidth: 100,align:'center'},
                    {title: '支付状态', templet: '#payStateOption', minWidth: 100,align:'center'},
                    {title: '支付方式', templet: '#payTypeOption', minWidth: 100,align:'center'},
                    {field: 'createdTime', title: '创建时间', minWidth: 150,align:'left'}
                ]]
            });
        }
        form.on('switch(hotStateSwitch)', function (data) {
            if (data.elem.checked) {
                groupState(data.value,1);
            } else {
                groupState(data.value,1);
            }
        })
        form.on('switch(groupStatusSwitch)', function (data) {
            if (data.elem.checked) {
                groupState(data.value,2);
            } else {
                groupState(data.value,2);
            }
        })
        function groupState(id,type) {
            febs.get(ctx + 'admin/happyActivity/groupState/' + id+'/' + type, null, function (data) {
                febs.alert.success(data.message);
                $query.click();
            });
        }
        // 查询按钮
        $query.on('click', function () {
            var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type});
            tableIns.reload({where: params, page: {curr: 1}});
        });
        // 刷新按钮
        $reset.on('click', function () {
            $searchForm[0].reset();
            sortObject.type = 'null';
            tableIns.reload({where: getQueryParams(), page: {curr: 1}, initSort: sortObject});
        });
        // 获取查询参数
        function getQueryParams() {
            return {
                name: $searchForm.find('input[name="name"]').val().trim(),
                state: $searchForm.find("select[name='state']").val(),
                activityId: $searchForm.find("select[name='activityId']").val(),
            };
        }
    })
</script>