wlzboy
2025-12-06 847a7773ef1a8ad418c6934d35b5f205a97c04d0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java
@@ -6,7 +6,9 @@
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -181,8 +183,14 @@
    @Override
    public int batchCalculateMileageStats(Date statDate) {
        try {
            // 计算查询开始时间(7天前)
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(statDate);
            calendar.add(Calendar.DAY_OF_MONTH, -7);
            Date startTime = calendar.getTime();
            // 查询所有活跃车辆
            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds();
            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTime);
            
            if (vehicleIds == null || vehicleIds.isEmpty()) {
                logger.info("没有找到活跃车辆");
@@ -246,6 +254,16 @@
        // 计算任务里程占比
        if (result.totalMileage.compareTo(BigDecimal.ZERO) > 0) {
            result.taskRatio = result.taskMileage.divide(result.totalMileage, 4, RoundingMode.HALF_UP);
            // 数据校验:占比应在0-1之间
            if (result.taskRatio.compareTo(BigDecimal.ONE) > 0) {
                logger.warn("任务里程占比异常: {} (任务里程:{}, 总里程:{}), 强制设为1.0",
                           result.taskRatio, result.taskMileage, result.totalMileage);
                result.taskRatio = BigDecimal.ONE;
            } else if (result.taskRatio.compareTo(BigDecimal.ZERO) < 0) {
                logger.warn("任务里程占比为负: {}, 强制设为0", result.taskRatio);
                result.taskRatio = BigDecimal.ZERO;
            }
        }
        
        // 保留两位小数
@@ -379,32 +397,86 @@
                }
            }
            
            // 4. 查询该日期的任务时间区间,计算任务里程和非任务里程
            List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd);
            // 4. 计算任务里程和非任务里程(优化:优先使用task_id直接聚合)
            BigDecimal taskMileage = BigDecimal.ZERO;
            BigDecimal nonTaskMileage = BigDecimal.ZERO;
            int taskCount = 0;  // 任务数量
            
            // 4.1 统计有task_id的分段数量
            int segmentsWithTask = 0;
            for (VehicleGpsSegmentMileage segment : segments) {
                Date segStart = segment.getSegmentStartTime();
                Date segEnd = segment.getSegmentEndTime();
                BigDecimal segDistance = segment.getSegmentDistance() != null ? segment.getSegmentDistance() : BigDecimal.ZERO;
                if (segment.getTaskId() != null) {
                    segmentsWithTask++;
                }
            }
            // 4.2 如果大部分分段都有task_id,使用优化方案(直接按task_id聚合)
            if (segmentsWithTask > segments.size() * 0.8) {
                logger.debug("车辆ID: {} 日期: {} 使用优化方案:直接按task_id聚合({}个分段有task_id,占比{}%)",
                           vehicleId, statDate, segmentsWithTask, (segmentsWithTask * 100.0 / segments.size()));
                
                // 计算该分段与任务时段的重叠比例
                double taskRatio = calculateTaskOverlapRatio(segStart, segEnd, taskIntervals);
                // 使用Set统计去重的任务ID数量
                Set<Long> uniqueTaskIds = new HashSet<>();
                
                // 分摇里程
                BigDecimal taskDist = segDistance.multiply(BigDecimal.valueOf(taskRatio));
                BigDecimal nonTaskDist = segDistance.multiply(BigDecimal.valueOf(1 - taskRatio));
                // 直接按task_id分组聚合
                for (VehicleGpsSegmentMileage segment : segments) {
                    BigDecimal segDistance = segment.getSegmentDistance() != null ? segment.getSegmentDistance() : BigDecimal.ZERO;
                    if (segment.getTaskId() != null) {
                        // 有任务ID,计入任务里程
                        taskMileage = taskMileage.add(segDistance);
                        uniqueTaskIds.add(segment.getTaskId());
                    } else {
                        // 没有任务ID,计入非任务里程
                        nonTaskMileage = nonTaskMileage.add(segDistance);
                    }
                }
                
                taskMileage = taskMileage.add(taskDist);
                nonTaskMileage = nonTaskMileage.add(nonTaskDist);
                // 设置去重后的任务数量
                taskCount = uniqueTaskIds.size();
            } else {
                // 4.3 降级方案:使用原有的时间重叠计算方式
                logger.debug("车辆ID: {} 日期: {} 使用降级方案:时间重叠计算(只有{}个分段有task_id,占比{}%)",
                           vehicleId, statDate, segmentsWithTask, (segmentsWithTask * 100.0 / segments.size()));
                List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd);
                for (VehicleGpsSegmentMileage segment : segments) {
                    Date segStart = segment.getSegmentStartTime();
                    Date segEnd = segment.getSegmentEndTime();
                    BigDecimal segDistance = segment.getSegmentDistance() != null ? segment.getSegmentDistance() : BigDecimal.ZERO;
                    // 计算该分段与任务时段的重叠比例
                    double taskRatio = calculateTaskOverlapRatio(segStart, segEnd, taskIntervals);
                    // 分摊里程
                    BigDecimal taskDist = segDistance.multiply(BigDecimal.valueOf(taskRatio));
                    BigDecimal nonTaskDist = segDistance.multiply(BigDecimal.valueOf(1 - taskRatio));
                    taskMileage = taskMileage.add(taskDist);
                    nonTaskMileage = nonTaskMileage.add(nonTaskDist);
                }
                // 设置任务数量
                taskCount = taskIntervals == null ? 0 : taskIntervals.size();
            }
            
            // 计算任务里程占比
            BigDecimal taskRatio = BigDecimal.ZERO;
            if (totalMileage.compareTo(BigDecimal.ZERO) > 0) {
                taskRatio = taskMileage.divide(totalMileage, 4, RoundingMode.HALF_UP);
                // 数据校验:占比应在0-1之间,如果超出说明数据异常
                if (taskRatio.compareTo(BigDecimal.ONE) > 0) {
                    logger.warn("车辆ID: {} 日期: {} 任务里程占比异常: {} (任务里程:{}, 总里程:{}), 强制设为1.0",
                               vehicleId, statDate, taskRatio, taskMileage, totalMileage);
                    taskRatio = BigDecimal.ONE;
                } else if (taskRatio.compareTo(BigDecimal.ZERO) < 0) {
                    logger.warn("车辆ID: {} 日期: {} 任务里程占比为负: {}, 强制设为0",
                               vehicleId, statDate, taskRatio);
                    taskRatio = BigDecimal.ZERO;
                }
            }
            
            // 5. 查询或创建统计记录
@@ -436,7 +508,7 @@
            stats.setNonTaskMileage(nonTaskMileage.setScale(2, RoundingMode.HALF_UP));
            stats.setTaskRatio(taskRatio);
            stats.setGpsPointCount(totalGpsPoints);
            stats.setTaskCount(taskIntervals == null ? 0 : taskIntervals.size());
            stats.setTaskCount(taskCount);
            stats.setSegmentCount(segments.size());
            stats.setDataSource("segment"); // 标记数据来源为分段汇总
            
@@ -464,8 +536,14 @@
    @Override
    public int batchAggregateFromSegmentMileage(Date statDate) {
        try {
            // 计算查询开始时间(7天前)
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(statDate);
            calendar.add(Calendar.DAY_OF_MONTH, -7);
            Date startTime = calendar.getTime();
            // 查询所有活跃车辆
            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds();
            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTime);
            
            if (vehicleIds == null || vehicleIds.isEmpty()) {
                logger.info("没有找到活跃车辆");