seatonwan9
2025-08-15 c28a6afe1f87acecbe7aad4559a3842b1e3d5acb
积分管理
7个文件已删除
1个文件已添加
13个文件已修改
804 ■■■■■ 已修改文件
src/main/java/com/webmanage/controller/PointsController.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/AddPointsFlowDTO.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/PointsFlowQueryDTO.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/PointsRuleDTO.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/dto/PointsRuleDetailDTO.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/emun/RuleTypeEnum.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/PointsFlow.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/PointsRule.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/PointsRuleDetail.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/entity/PointsRuleEntity.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/mapper/PointsFlowMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/mapper/PointsRuleDetailMapper.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/mapper/PointsRuleMapper.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/PointsFlowService.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/PointsRuleDetailService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/PointsRuleService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/PointsFlowServiceImpl.java 219 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/PointsRuleDetailServiceImpl.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/service/impl/PointsRuleServiceImpl.java 86 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/vo/PointsRuleVO.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/PointsFlowMapper.xml 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/webmanage/controller/PointsController.java
@@ -2,12 +2,10 @@
import com.webmanage.common.PageResult;
import com.webmanage.common.Result;
import com.webmanage.dto.AddPointsFlowDTO;
import com.webmanage.dto.PointsFlowQueryDTO;
import com.webmanage.dto.PointsMainQueryDTO;
import com.webmanage.dto.PointsRuleDTO;
import com.webmanage.dto.*;
import com.webmanage.entity.Points;
import com.webmanage.entity.PointsRule;
import com.webmanage.entity.UserPoints;
import com.webmanage.service.PointsFlowService;
import com.webmanage.service.PointsRuleService;
import com.webmanage.service.PointsService;
@@ -91,7 +89,7 @@
    @PostMapping("/rule/update")
    @ApiOperation("修改积分规则")
    public Result<Object> updatePointsRule(@Valid @RequestBody PointsRuleDTO pointsRuleDTO) {
    public Result<Object> updatePointsRule(@Valid @RequestBody List<PointsRuleDTO> pointsRuleDTO) {
        try {
            boolean result = pointsRuleService.updatePointsRule(pointsRuleDTO);
            if (result) {
@@ -252,10 +250,10 @@
    @GetMapping("/total/user/{userId}")
    @ApiOperation("获取用户积分统计")
    public Result<Object> getUserPointsTotal(@ApiParam("用户ID") @PathVariable Long userId) {
    public Result<UserPoints> getUserPointsTotal(@ApiParam("用户ID") @PathVariable Long userId) {
        try {
            Integer total = pointsFlowService.getUserPointsTotal(userId);
            return Result.success(total);
            UserPoints userPoints = pointsFlowService.getUserPointsTotal(userId);
            return Result.success(userPoints);
        } catch (Exception e) {
            log.error("获取用户积分统计失败", e);
            return Result.error("获取用户积分统计失败:" + e.getMessage());
@@ -264,13 +262,27 @@
    @GetMapping("/total/unit/{unitId}")
    @ApiOperation("获取单位积分统计")
    public Result<Object> getUnitPointsTotal(@ApiParam("单位ID") @PathVariable Long unitId) {
    public Result<UserPoints> getUnitPointsTotal(@ApiParam("单位ID") @PathVariable Long unitId) {
        try {
            Integer total = pointsFlowService.getUnitPointsTotal(unitId);
            UserPoints total = pointsFlowService.getUnitPointsTotal(unitId);
            return Result.success(total);
        } catch (Exception e) {
            log.error("获取单位积分统计失败", e);
            return Result.error("获取单位积分统计失败:" + e.getMessage());
        }
    }
    // ==================== 积分流水数据类目 ====================
    @GetMapping("/flow/categories")
    @ApiOperation("获取积分流水数据类目列表")
    public Result<Object> getPointsFlowCategories() {
        try {
            List<String> categories = pointsFlowService.getPointsFlowCategories();
            return Result.success(categories);
        } catch (Exception e) {
            log.error("获取积分流水数据类目失败", e);
            return Result.error("获取积分流水数据类目失败:" + e.getMessage());
        }
    }
}
src/main/java/com/webmanage/dto/AddPointsFlowDTO.java
@@ -22,20 +22,28 @@
    @NotNull(message = "单位ID不能为空")
    private Long unitId;
    @ApiModelProperty("规则类型(获得/消费)")
    @NotBlank(message = "规则类型不能为空")
    private String ruleType;
    @ApiModelProperty("规则类型(0获得/1消费)")
    @NotNull(message = "规则类型不能为空")
    private Integer ruleType;
    @ApiModelProperty("规则名称")
    @NotBlank(message = "规则名称不能为空")
    private String ruleName;
    @ApiModelProperty("积分规则类别(资源贡献、资源传播、资源交易、交流社区互动)")
    @NotBlank(message = "规则类别不能为空")
    private String category;
    @ApiModelProperty("积分规则类别(资源贡献、资源传播、资源交易、交流社区互动)")
    @NotBlank(message = "积分规则编码")
    private String ruleNameCode;
    @ApiModelProperty("数据类目)")
    @NotBlank(message = "数据类目不能为空")
    private String dataCategoty;
    @ApiModelProperty("关联订单ID")
    private String orderId;
    @ApiModelProperty("积分流水描述")
    private String description;
    @ApiModelProperty("触发次数(默认为1)")
    private Integer count = 1;
    @ApiModelProperty("流水描述(可选,不填则使用规则描述)")
    private String description;
}
src/main/java/com/webmanage/dto/PointsFlowQueryDTO.java
@@ -25,20 +25,23 @@
    @ApiModelProperty("单位ID")
    private Long unitId;
    @ApiModelProperty("流水类型(获得/消费)")
    private String flowType;
    @ApiModelProperty("流水类型(0获得1/消费)")
    private Integer dataType;
    @ApiModelProperty("积分来源")
    private String pointsSource;
    @ApiModelProperty("数据类目")
    private String dataCategory;
    @ApiModelProperty("关联订单ID")
    private String orderId;
    @ApiModelProperty("开始时间")
    private LocalDateTime startTime;
    private LocalDateTime flowStartTime;
    @ApiModelProperty("结束时间")
    private LocalDateTime endTime;
    private LocalDateTime flowEndTime;
    @ApiModelProperty("排序字段")
    private String orderBy = "created_at";
src/main/java/com/webmanage/dto/PointsRuleDTO.java
@@ -1,5 +1,6 @@
package com.webmanage.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -16,39 +17,44 @@
public class PointsRuleDTO {
    @ApiModelProperty("主键ID")
    private Long id;
    private Long pointsId;
    @ApiModelProperty("规则名称")
    @NotBlank(message = "规则名称不能为空")
    private String ruleName;
    @ApiModelProperty("规则编码")
    @NotBlank(message = "规则编码不能为空")
    private String ruleNameCode;
    @ApiModelProperty("规则类型(获得/消费)")
    @NotBlank(message = "规则类型不能为空")
    private String ruleType;
    @NotNull(message = "规则类型不能为空")
    private Integer ruleType;
    @ApiModelProperty("规则类别")
    private String category;
    @ApiModelProperty("积分值")
    @NotNull(message = "积分值不能为空")
    private Integer pointsValue;
    @ApiModelProperty("触发条件")
    @NotBlank(message = "触发条件不能为空")
    private String triggerCondition;
    @ApiModelProperty("触发金额")
    private BigDecimal triggerAmount;
    @ApiModelProperty("规则描述")
    private String description;
    private String ruleDescription;
    @ApiModelProperty("是否启用")
    private Boolean isEnabled = true;
    @ApiModelProperty("优先级")
    private Integer priority = 1;
    @ApiModelProperty("每日上限")
    private Integer dailyLimit;
    @ApiModelProperty("有效期开始时间")
    private String validStartTime;
    @ApiModelProperty("积分拥有者(0贡献值1用户)")
    private Integer pointsWinner;
    @ApiModelProperty("有效期结束时间")
    private String validEndTime;
    @ApiModelProperty("积分是否有上限(0有1没有)")
    private Integer isLimit;
    @ApiModelProperty("排序")
    private Integer ruleOrder;
}
src/main/java/com/webmanage/dto/PointsRuleDetailDTO.java
File was deleted
src/main/java/com/webmanage/emun/RuleTypeEnum.java
@@ -9,16 +9,16 @@
 */
public enum RuleTypeEnum {
    GET(0L,"获取"),CONSUME(1L,"消费");
    private Long code;
    GET(0,"获取"),CONSUME(1,"消费");
    private Integer code;
    private String name;
    RuleTypeEnum(Long code, String name) {
    RuleTypeEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
    public Long getCode() {
    public Integer getCode() {
        return code;
    }
src/main/java/com/webmanage/entity/PointsFlow.java
@@ -48,7 +48,7 @@
     * 数据类型
     */
    @TableField("data_type")
    private String dataType;
    private Integer dataType;
    /**
     * 名称/描述
@@ -86,4 +86,10 @@
    @TableLogic
    @TableField("deleted")
    private Integer deleted;
    /**
     * 规则ID
     */
    @TableField("rule_id")
    private Long rlueId;
}
src/main/java/com/webmanage/entity/PointsRule.java
@@ -28,9 +28,13 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("points_id")
    @TableField("points_id")
    private Long pointsId;
    @ApiModelProperty("规则类型(0获得/1消费)")
    @TableField("rule_type")
    private Long ruleType;
    private Integer ruleType;
    @ApiModelProperty("规则类别")
    @TableField("category")
@@ -40,13 +44,17 @@
    @TableField("rule_name")
    private String ruleName;
    @ApiModelProperty("规则编码")
    @TableField("rule_name_code")
    private String ruleNameCode;
    @ApiModelProperty("规则描述")
    @TableField("rule_description")
    private String ruleDescription;
    @ApiModelProperty("是否启用")
    @TableField("is_enabled")
    private Boolean isEnabled;
    private Integer isEnabled;
    @ApiModelProperty("创建时间")
    @TableField(value = "created_at", fill = FieldFill.INSERT)
@@ -69,4 +77,17 @@
    @ApiModelProperty("积分是否有上限(0有1没有)")
    @TableField("is_limit")
    private Integer isLimit;
    @ApiModelProperty("排序")
    @TableField("rule_order")
    private Integer ruleOrder;
    @ApiModelProperty("积分值")
    @TableField("points_value")
    private Integer pointsValue;
    @ApiModelProperty("每日上限")
    @TableField("daily_limit")
    private Integer dailyLimit;
}
src/main/java/com/webmanage/entity/PointsRuleDetail.java
File was deleted
src/main/java/com/webmanage/entity/PointsRuleEntity.java
File was deleted
src/main/java/com/webmanage/mapper/PointsFlowMapper.java
@@ -15,18 +15,5 @@
 */
@Mapper
public interface PointsFlowMapper extends BaseMapper<PointsFlow> {
    /**
     * 分页查询积分流水
     */
    IPage<PointsFlow> selectPage(Page<PointsFlow> page,
                                @Param("userId") Long userId,
                                @Param("unitId") Long unitId,
                                @Param("dataCategory") String dataCategory,
                                @Param("dataType") String dataType,
                                @Param("startTime") String startTime,
                                @Param("endTime") String endTime,
                                @Param("year") String year,
                                @Param("month") String month,
                                @Param("day") String day);
}
src/main/java/com/webmanage/mapper/PointsRuleDetailMapper.java
File was deleted
src/main/java/com/webmanage/mapper/PointsRuleMapper.java
@@ -3,6 +3,10 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.webmanage.entity.PointsRule;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
 * 积分规则Mapper接口
@@ -12,4 +16,5 @@
 */
@Mapper
public interface PointsRuleMapper extends BaseMapper<PointsRule> {
}
src/main/java/com/webmanage/service/PointsFlowService.java
@@ -5,6 +5,7 @@
import com.webmanage.dto.AddPointsFlowDTO;
import com.webmanage.dto.PointsFlowQueryDTO;
import com.webmanage.entity.PointsFlow;
import com.webmanage.entity.UserPoints;
import java.util.List;
@@ -33,11 +34,6 @@
     */
    List<PointsFlow> getPointsFlowByUnitId(Long unitId);
    /**
     * 记录积分流水
     */
    boolean recordPointsFlow(Long userId, Long unitId, String flowType, String pointsSource,
                           Integer pointsValue, String orderId, String description);
    /**
     * 新增积分流水(根据规则自动计算)
@@ -47,10 +43,15 @@
    /**
     * 获取用户积分统计
     */
    Integer getUserPointsTotal(Long userId);
    UserPoints getUserPointsTotal(Long userId);
    /**
     * 获取单位积分统计
     */
    Integer getUnitPointsTotal(Long unitId);
    UserPoints getUnitPointsTotal(Long unitId);
    /**
     * 获取积分流水数据类目列表
     */
    List<String> getPointsFlowCategories();
}
src/main/java/com/webmanage/service/PointsRuleDetailService.java
File was deleted
src/main/java/com/webmanage/service/PointsRuleService.java
@@ -27,7 +27,7 @@
    /**
     * 修改积分规则
     */
    boolean updatePointsRule(PointsRuleDTO pointsRuleDTO);
    boolean updatePointsRule(List<PointsRuleDTO> pointsRuleDetailsVOS);
    /**
     * 删除积分规则
src/main/java/com/webmanage/service/impl/PointsFlowServiceImpl.java
@@ -8,6 +8,7 @@
import com.webmanage.common.PageResult;
import com.webmanage.dto.AddPointsFlowDTO;
import com.webmanage.dto.PointsFlowQueryDTO;
import com.webmanage.emun.RuleTypeEnum;
import com.webmanage.entity.PointsFlow;
import com.webmanage.entity.PointsRule;
import com.webmanage.entity.UserPoints;
@@ -24,6 +25,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
 * 积分流水Service实现类
@@ -47,8 +49,7 @@
        Page<PointsFlow> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("user_id", queryDTO.getUserId());
        wrapper.eq("user_id", queryDTO.getUserId());
        
        buildQueryWrapper(wrapper, queryDTO);
        
@@ -72,8 +73,7 @@
        Page<PointsFlow> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("unit_id", queryDTO.getUnitId());
        wrapper.eq("unit_id", queryDTO.getUnitId());
        
        buildQueryWrapper(wrapper, queryDTO);
        
@@ -118,36 +118,6 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean recordPointsFlow(Long userId, Long unitId, String flowType, String pointsSource,
                                  Integer pointsValue, String orderId, String description) {
        if (userId == null || unitId == null || !StringUtils.hasText(flowType) ||
            !StringUtils.hasText(pointsSource) || pointsValue == null) {
            throw new BusinessException("参数不完整");
        }
        // 创建积分流水记录
        PointsFlow pointsFlow = new PointsFlow();
        pointsFlow.setUserId(userId);
        pointsFlow.setUnitId(unitId);
        pointsFlow.setDataType(flowType);
        pointsFlow.setDataCategory(pointsSource);
        pointsFlow.setPoints(pointsValue);
        pointsFlow.setName(description);
        pointsFlow.setFlowTime(LocalDateTime.now());
        boolean saved = save(pointsFlow);
        if (!saved) {
            throw new BusinessException("保存积分流水失败");
        }
        // 更新用户积分
        updateUserPoints(userId, unitId, pointsValue);
        return true;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addPointsFlowByRule(AddPointsFlowDTO addPointsFlowDTO) {
        if (addPointsFlowDTO == null) {
            throw new BusinessException("参数不能为空");
@@ -155,14 +125,15 @@
        Long userId = addPointsFlowDTO.getUserId();
        Long unitId = addPointsFlowDTO.getUnitId();
        String ruleType = addPointsFlowDTO.getRuleType();
        String ruleName = addPointsFlowDTO.getRuleName();
        Integer ruleType = addPointsFlowDTO.getRuleType();
        String category = addPointsFlowDTO.getCategory();
        String ruleNameCode = addPointsFlowDTO.getRuleNameCode();
        Integer count = addPointsFlowDTO.getCount() != null ? addPointsFlowDTO.getCount() : 1;
        // 查询积分规则
        PointsRule pointsRule = pointsRuleService.getRuleByTriggerCondition(ruleName);
        // 根据ruleType、ruleNameCode、category查询生效时间最新的积分规则
        PointsRule pointsRule = getLatestEffectiveRule(ruleType, ruleNameCode, category);
        if (pointsRule == null) {
            throw new BusinessException("积分规则不存在或未启用: " + ruleName);
            throw new BusinessException("积分规则不存在或未启用: ruleType=" + ruleType + ", ruleNameCode=" + ruleNameCode + ", category=" + category);
        }
        // 验证规则类型是否匹配
@@ -171,17 +142,22 @@
        }
        // 计算积分值
        Integer basePoints = 0; //pointsRule.getPointsValue() != null ? pointsRule.getPointsValue() : 0;
        Integer basePoints = pointsRule.getPointsValue() != null ? pointsRule.getPointsValue() : 0;
        Integer totalPoints = basePoints * count;
        // 如果是消费类型,积分为负数
        if ("消费".equals(ruleType)) {
        if (ruleType == RuleTypeEnum.CONSUME.getCode()) { // 1表示消费类型
            totalPoints = -totalPoints;
        }
        // 检查每日积分上限
        if (basePoints > 0) {
            checkDailyLimit(userId, unitId, ruleName, totalPoints, 0);
        if (pointsRule.getIsLimit() != null && pointsRule.getIsLimit() == 0) { // 0表示有每日上限
            checkDailyLimitByRule(userId, unitId, pointsRule, totalPoints);
        }
        // 如果是扣积分操作,先检查余额是否足够
        if (totalPoints < 0) {
            checkBalanceSufficient(userId, unitId, Math.abs(totalPoints));
        }
        // 创建积分流水记录
@@ -189,10 +165,11 @@
        pointsFlow.setUserId(userId);
        pointsFlow.setUnitId(unitId);
        pointsFlow.setDataType(ruleType);
        pointsFlow.setDataCategory(ruleName);
        pointsFlow.setDataCategory(addPointsFlowDTO.getCategory());
        pointsFlow.setPoints(totalPoints);
        pointsFlow.setName(addPointsFlowDTO.getDescription() != null ? addPointsFlowDTO.getDescription() : pointsRule.getRuleDescription());
        pointsFlow.setFlowTime(LocalDateTime.now());
        pointsFlow.setRlueId(pointsRule.getId());
        boolean saved = save(pointsFlow);
        if (!saved) {
@@ -200,15 +177,15 @@
        }
        // 更新用户积分账户
        updateUserPointsByRule(userId, unitId, totalPoints, ruleType);
        updateUserPointsByRule(userId, unitId, totalPoints);
        return true;
    }
    @Override
    public Integer getUserPointsTotal(Long userId) {
    public UserPoints getUserPointsTotal(Long userId) {
        if (userId == null) {
            return 0;
            throw new BusinessException("用户ID不能为null");
        }
        
        QueryWrapper<UserPoints> wrapper = new QueryWrapper<>();
@@ -216,13 +193,13 @@
               .eq("user_id", userId);
        
        UserPoints userPoints = userPointsMapper.selectOne(wrapper);
        return userPoints != null ? userPoints.getBalance() : 0;
        return userPoints ;
    }
    @Override
    public Integer getUnitPointsTotal(Long unitId) {
    public UserPoints getUnitPointsTotal(Long unitId) {
        if (unitId == null) {
            return 0;
            throw new BusinessException("用户ID不能为null");
        }
        
        QueryWrapper<UserPoints> wrapper = new QueryWrapper<>();
@@ -230,15 +207,37 @@
               .eq("unit_id", unitId);
        
        UserPoints userPoints = userPointsMapper.selectOne(wrapper);
        return userPoints != null ? userPoints.getBalance() : 0;
        return userPoints;
    }
    @Override
    public List<String> getPointsFlowCategories() {
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.select("DISTINCT data_category")
               .isNotNull("data_category")
               .ne("data_category", "")
               .ne("data_category", "null")
               .eq("deleted", 0)
               .orderByAsc("data_category");
        List<PointsFlow> flows = list(wrapper);
        return flows.stream()
                .map(PointsFlow::getDataCategory)
                .filter(category -> category != null && !category.trim().isEmpty())
                .distinct()
                .sorted()
                .collect(Collectors.toList());
    }
    /**
     * 构建查询条件
     */
    private void buildQueryWrapper(QueryWrapper<PointsFlow> wrapper, PointsFlowQueryDTO queryDTO) {
        if (StringUtils.hasText(queryDTO.getFlowType())) {
            wrapper.eq("flow_type", queryDTO.getFlowType());
        if(StringUtils.hasText(queryDTO.getDataCategory())){
            wrapper.eq("data_category", queryDTO.getDataCategory());
        }
        if (queryDTO.getDataType()!=null) {
            wrapper.eq("data_type", queryDTO.getDataType());
        }
        if (StringUtils.hasText(queryDTO.getPointsSource())) {
            wrapper.eq("points_source", queryDTO.getPointsSource());
@@ -246,18 +245,100 @@
        if (StringUtils.hasText(queryDTO.getOrderId())) {
            wrapper.eq("order_id", queryDTO.getOrderId());
        }
        if (queryDTO.getStartTime() != null) {
            wrapper.ge("flow_time", queryDTO.getStartTime());
        if (queryDTO.getFlowEndTime() != null) {
            wrapper.ge("flow_time", queryDTO.getFlowStartTime());
        }
        if (queryDTO.getEndTime() != null) {
            wrapper.le("flow_time", queryDTO.getEndTime());
        if (queryDTO.getFlowEndTime() != null) {
            wrapper.le("flow_time", queryDTO.getFlowEndTime());
        }
        
        wrapper.orderByDesc("flow_time");
    }
    /**
     * 检查每日积分上限
     * 根据ruleType、ruleNameCode、category查询生效时间最新的积分规则
     */
    private PointsRule getLatestEffectiveRule(Integer ruleType, String ruleNameCode, String category) {
        QueryWrapper<PointsRule> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("is_enabled", 0) // 0表示启用
               .eq("rule_type", ruleType)
               .eq("rule_name_code", ruleNameCode)
               .eq("category", category)
               .orderByDesc("created_at") // 按创建时间倒序,获取最新的规则
               .last("LIMIT 1");
        return pointsRuleService.getOne(wrapper);
    }
    /**
     * 检查每日积分上限(基于规则)
     */
    private void checkDailyLimitByRule(Long userId, Long unitId, PointsRule pointsRule, Integer currentPoints) {
        // 获取今日开始和结束时间
        LocalDate today = LocalDate.now();
        LocalDateTime startOfDay = today.atStartOfDay();
        LocalDateTime endOfDay = today.atTime(23, 59, 59);
        // 查询今日该规则的积分流水
        QueryWrapper<PointsFlow> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0)
               .eq("user_id", userId)
               .eq("unit_id", unitId)
//               .eq("data_category", pointsRule.getRuleName())
                .eq("rule_id",pointsRule.getId())
               .ge("flow_time", startOfDay)
               .le("flow_time", endOfDay);
        List<PointsFlow> todayFlows = list(wrapper);
        // 计算今日累计积分
        int todayTotal = todayFlows.stream()
                .mapToInt(flow -> flow.getPoints() != null ? flow.getPoints() : 0)
                .sum();
        // 获取规则的每日积分上限
        Integer dailyLimit = pointsRule.getDailyLimit();
        if (dailyLimit != null && dailyLimit > 0) {
            // 如果今日累计积分超过每日上限,则抛出异常
            if (Math.abs(todayTotal) >= dailyLimit) {
                throw new BusinessException("今日该规则积分已达上限: " + dailyLimit);
            }
            // 如果加上当前积分会超过每日上限,则抛出异常
            if (Math.abs(todayTotal + currentPoints) > dailyLimit) {
                throw new BusinessException("本次积分操作将超过每日上限: " + dailyLimit + ",当前已累计: " + Math.abs(todayTotal));
            }
        }
    }
    /**
     * 检查积分余额是否足够
     */
    private void checkBalanceSufficient(Long userId, Long unitId, Integer requiredPoints) {
        // 检查个人积分余额
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
                  .eq("user_id", userId);
        UserPoints userPoints = userPointsMapper.selectOne(userWrapper);
        if (userPoints == null || userPoints.getBalance() < requiredPoints) {
            throw new BusinessException("个人积分余额不足,当前余额: " + (userPoints != null ? userPoints.getBalance() : 0) + ",需要扣除: " + requiredPoints);
        }
        // 检查单位积分余额
        QueryWrapper<UserPoints> unitWrapper = new QueryWrapper<>();
        unitWrapper.eq("deleted", 0)
                  .eq("unit_id", unitId);
        UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper);
        if (unitPoints == null || unitPoints.getBalance() < requiredPoints) {
            throw new BusinessException("单位积分余额不足,当前余额: " + (unitPoints != null ? unitPoints.getBalance() : 0) + ",需要扣除: " + requiredPoints);
        }
    }
    /**
     * 检查每日积分上限(旧方法,保留兼容性)
     */
    private void checkDailyLimit(Long userId, Long unitId, String ruleName, Integer currentPoints, Integer priority) {
        // 获取今日开始和结束时间
@@ -331,7 +412,7 @@
    /**
     * 根据规则更新用户积分账户
     */
    private void updateUserPointsByRule(Long userId, Long unitId, Integer pointsValue, String ruleType) {
    private void updateUserPointsByRule(Long userId, Long unitId, Integer pointsValue) {
        // 更新个人积分账户
        QueryWrapper<UserPoints> userWrapper = new QueryWrapper<>();
        userWrapper.eq("deleted", 0)
@@ -339,6 +420,11 @@
        
        UserPoints userPoints = userPointsMapper.selectOne(userWrapper);
        if (userPoints == null) {
            // 如果是新用户且是扣积分操作,余额不足
            if (pointsValue < 0) {
                throw new BusinessException("积分余额不足,无法扣除积分");
            }
            userPoints = new UserPoints();
            userPoints.setUserId(userId);
            userPoints.setUnitId(unitId);
@@ -347,6 +433,11 @@
            userPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(userPoints);
        } else {
            // 检查扣积分时余额是否足够
            if (pointsValue < 0 && userPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("积分余额不足,当前余额: " + userPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            userPoints.setBalance(userPoints.getBalance() + pointsValue);
            
            // 更新累计获取积分
@@ -372,6 +463,11 @@
        
        UserPoints unitPoints = userPointsMapper.selectOne(unitWrapper);
        if (unitPoints == null) {
            // 如果是新单位且是扣积分操作,余额不足
            if (pointsValue < 0) {
                throw new BusinessException("单位积分余额不足,无法扣除积分");
            }
            unitPoints = new UserPoints();
            unitPoints.setUserId(userId);
            unitPoints.setUnitId(unitId);
@@ -380,6 +476,11 @@
            unitPoints.setTotalConsumed(pointsValue < 0 ? Math.abs(pointsValue) : 0);
            userPointsMapper.insert(unitPoints);
        } else {
            // 检查扣积分时余额是否足够
            if (pointsValue < 0 && unitPoints.getBalance() + pointsValue < 0) {
                throw new BusinessException("单位积分余额不足,当前余额: " + unitPoints.getBalance() + ",需要扣除: " + Math.abs(pointsValue));
            }
            unitPoints.setBalance(unitPoints.getBalance() + pointsValue);
            
            // 更新累计获取积分
src/main/java/com/webmanage/service/impl/PointsRuleDetailServiceImpl.java
File was deleted
src/main/java/com/webmanage/service/impl/PointsRuleServiceImpl.java
@@ -5,24 +5,30 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.webmanage.common.BusinessException;
import com.webmanage.dto.PointsRuleDTO;
import com.webmanage.emun.RuleTypeEnum;
import com.webmanage.entity.Points;
import com.webmanage.entity.PointsRule;
import com.webmanage.entity.PointsRuleDetail;
import com.webmanage.mapper.PointsRuleMapper;
import com.webmanage.service.PointsRuleService;
import com.webmanage.service.PointsService;
import com.webmanage.service.PointsRuleDetailService;
import com.webmanage.vo.PointsRuleResultVO;
import com.webmanage.vo.PointsRuleVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.beans.Transient;
import java.text.DateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -36,9 +42,7 @@
    
    @Autowired
    private PointsService pointsService;
    @Autowired
    private PointsRuleDetailService pointsRuleDetailService;
    @Override
    public PointsRuleResultVO getPointsRuleList(Long ruleId) {
@@ -46,7 +50,7 @@
        QueryWrapper<PointsRule> wrapper = new QueryWrapper<>();
        wrapper.eq("deleted", 0).eq("is_enabled",0);
        if(ruleId != null){
        wrapper.eq("points_id", ruleId);
        }
@@ -54,7 +58,7 @@
        List<PointsRule> list = list(wrapper);
        PointsRuleResultVO pointsRuleResultVO = new PointsRuleResultVO();
        if (!CollectionUtil.isEmpty(list)) {
            Map<Long, List<PointsRule>> collect = list.stream().collect(Collectors.groupingBy(PointsRule::getRuleType));
            Map<Integer, List<PointsRule>> collect = list.stream().collect(Collectors.groupingBy(PointsRule::getRuleType));
            Map<String, List<PointsRule>> getRules = collect.get(RuleTypeEnum.GET.getCode()).stream().collect(Collectors.groupingBy(PointsRule::getCategory));
            Map<String, List<PointsRule>> consumeRules = collect.get(RuleTypeEnum.CONSUME.getCode()).stream().collect(Collectors.groupingBy(PointsRule::getCategory));
@@ -62,6 +66,7 @@
            List<PointsRuleVO> consumePointsRuleVOList = new ArrayList<>();
            getRules.forEach((k,v)->{
                PointsRuleVO pointsRuleVO = new PointsRuleVO();
                pointsRuleVO.setRlueSort(v.get(0).getRuleOrder());
                pointsRuleVO.setCategory(k);
                pointsRuleVO.setPointsRules(v);
                getPointsRuleVOList.add(pointsRuleVO);
@@ -69,11 +74,14 @@
            });
            consumeRules.forEach((k,v)->{
                PointsRuleVO pointsRuleVO = new PointsRuleVO();
                pointsRuleVO.setRlueSort(v.get(0).getRuleOrder());
                pointsRuleVO.setCategory(k);
                pointsRuleVO.setPointsRules(v);
                consumePointsRuleVOList.add(pointsRuleVO);
            });
            getPointsRuleVOList.sort(Comparator.comparing(PointsRuleVO::getRlueSort));
            consumePointsRuleVOList.sort(Comparator.comparing(PointsRuleVO::getRlueSort));
            pointsRuleResultVO.setGetPointsRuleList(getPointsRuleVOList);
            pointsRuleResultVO.setConsumePointsRuleList(consumePointsRuleVOList);
        }
@@ -99,48 +107,42 @@
    }
    @Override
    public boolean updatePointsRule(PointsRuleDTO pointsRuleDTO) {
        if (pointsRuleDTO.getId() == null) {
            throw new BusinessException("规则ID不能为空");
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePointsRule(List<PointsRuleDTO> pointsRuleDTO) {
        if (CollectionUtils.isEmpty(pointsRuleDTO)){
            return false;
        }
        PointsRule existingRule = getById(pointsRuleDTO.getId());
        if (existingRule == null) {
            throw new BusinessException("积分规则不存在");
        }
        // 验证规则名称是否重复(排除自身)
        QueryWrapper<PointsRule> wrapper = new QueryWrapper<>();
        wrapper.eq("rule_name", pointsRuleDTO.getRuleName())
               .eq("deleted", 0)
               .ne("id", pointsRuleDTO.getId());
        if (count(wrapper) > 0) {
            throw new BusinessException("规则名称已存在");
        }
        // 查询规则名称
         Points pointsOld = pointsService.query().eq("id", pointsRuleDTO.get(0).getPointsId())
                 .eq("deleted", 0).one();
        // 查询当天是否有版本更新记录
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:mm:ss");
        LocalDateTime nowDatetime = LocalDateTime.now();
        LocalDateTime localDateTimeStart = nowDatetime.toLocalDate().atStartOfDay();
        LocalDateTime localDateTimeEnd = nowDatetime.toLocalDate().atStartOfDay();
        // dateTimeFormatter.format(localDateTimeStart), dateTimeFormatter.format(localDateTimeEnd)
        Long counts = pointsService.query().between("created_at", localDateTimeStart, localDateTimeEnd).count();
        // 创建新的积分主表记录
        Points points = new Points();
        points.setPointsName(pointsRuleDTO.getRuleName() + "_" + System.currentTimeMillis());
        points.setPointsName(pointsOld.getPointsName());
        points.setEffectiveStart(LocalDateTime.now());
        points.setModifierId(1L); // 这里应该从上下文中获取当前用户ID
        points.setModifierId(pointsOld.getModifierId()); // 这里应该从上下文中获取当前用户ID
        points.setModifierName("admin"); // 这里应该从上下文中获取当前用户名
        points.setVersion(1.0f);
        points.setVersion(counts>0 ? pointsOld.getVersion() + 0.1f: 1.0f);
        points.setStatus(0);
        pointsService.save(points);
        
        // 创建积分规则详情记录
        PointsRuleDetail pointsRuleDetail = new PointsRuleDetail();
        pointsRuleDetail.setRuleId(pointsRuleDTO.getId());
        pointsRuleDetail.setPointsId(points.getId());
        pointsRuleDetail.setPointsValue(pointsRuleDTO.getPointsValue());
        pointsRuleDetail.setEffectiveStart(LocalDateTime.now());
        pointsRuleDetailService.save(pointsRuleDetail);
        BeanUtils.copyProperties(pointsRuleDTO, existingRule);
        existingRule.setUpdatedAt(LocalDateTime.now());
        return updateById(existingRule);
        // 创建积分规则记录
        for (PointsRuleDTO ruleDTO : pointsRuleDTO) {
            PointsRule pointsRule = new PointsRule();
            BeanUtils.copyProperties(ruleDTO,pointsRule);
            pointsRule.setPointsId(points.getId());
            pointsRule.setUpdatedAt(LocalDateTime.now());
            save(pointsRule);
        }
        return true;
    }
    @Override
@@ -168,7 +170,7 @@
            throw new BusinessException("积分规则不存在");
        }
        
        pointsRule.setIsEnabled(isEnabled);
        pointsRule.setIsEnabled(isEnabled ? 0: 1);
        pointsRule.setUpdatedAt(LocalDateTime.now());
        
        return updateById(pointsRule);
src/main/java/com/webmanage/vo/PointsRuleVO.java
New file
@@ -0,0 +1,20 @@
package com.webmanage.vo;
import com.webmanage.entity.PointsRule;
import lombok.Data;
import java.util.List;
/**
 * @ClassName PointsRuleVO
 * @Description TODO
 * @Author wangxudong
 * @Date 2025/8/14 21:05
 * @Version 1.0
 **/
@Data
public class PointsRuleVO {
    private String category;
    List<PointsRule> pointsRules;
    private Integer rlueSort;
}
src/main/resources/mapper/PointsFlowMapper.xml
File was deleted