From fe33646ee6e2d1e57f2b51812e94983a0e9efb04 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期日, 14 十二月 2025 16:51:28 +0800
Subject: [PATCH] feat: 修复统计

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java |  394 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 342 insertions(+), 52 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java
index 4bd7aa3..2d1eeaf 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java
@@ -2,18 +2,30 @@
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.ruoyi.common.utils.DateUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.ruoyi.system.domain.VehicleGps;
 import com.ruoyi.system.domain.VehicleMileageStats;
+import com.ruoyi.system.domain.VehicleGpsSegmentMileage;
 import com.ruoyi.system.domain.TaskTimeInterval;
+import com.ruoyi.system.domain.VehicleInfo;
 import com.ruoyi.system.mapper.VehicleGpsMapper;
 import com.ruoyi.system.mapper.VehicleMileageStatsMapper;
+import com.ruoyi.system.mapper.VehicleGpsSegmentMileageMapper;
+import com.ruoyi.system.mapper.VehicleInfoMapper;
 import com.ruoyi.system.service.IVehicleMileageStatsService;
 
 /**
@@ -32,6 +44,12 @@
     
     @Autowired
     private VehicleGpsMapper vehicleGpsMapper;
+
+    @Autowired
+    private VehicleGpsSegmentMileageMapper segmentMileageMapper;
+    
+    @Autowired
+    private VehicleInfoMapper vehicleInfoMapper;
 
     /**
      * 鏌ヨ杞﹁締閲岀▼缁熻
@@ -98,21 +116,34 @@
             
             calendar.add(Calendar.DAY_OF_MONTH, 1);
             Date dayEnd = calendar.getTime();
-            
+
+            String dayStartStr=DateUtils.formatDate(dayStart, DateUtils.YYYY_MM_DD_HH_MM_SS);
+            String dayEndStr=DateUtils.formatDate(dayEnd, DateUtils.YYYY_MM_DD_HH_MM_SS);
             // 2. 鏌ヨ杞﹁締鍦ㄨ鏃ユ湡鐨凣PS鏁版嵁锛堟寜鏃堕棿鎺掑簭锛�
-            List<VehicleGps> gpsList = vehicleGpsMapper.selectGpsDataByTimeRange(vehicleId, dayStart, dayEnd);
+            List<VehicleGps> gpsList = vehicleGpsMapper.selectGpsDataByTimeRange(vehicleId, dayStartStr, dayEndStr);
             
             if (gpsList == null || gpsList.isEmpty()) {
-                logger.info("杞﹁締ID: {} 鍦ㄦ棩鏈�: {} 鏃燝PS鏁版嵁", vehicleId, statDate);
+                logger.info("---> 杞﹁締ID:{} 鍦ㄦ棩鏈�:{} 鏃燝PS鏁版嵁", vehicleId, statDate);
                 return null;
             }
-            
+//            logger.info("---> 杞﹁締ID:{} GPS鏁版嵁鏉℃暟:{}", vehicleId, gpsList.size());
             // 3. 鏌ヨ杞﹁締鍦ㄨ鏃ユ湡鐨勪换鍔℃椂闂村尯闂�
             List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd);
-            
-            // 4. 璁$畻閲岀▼
-            MileageCalculation calculation = calculateMileage(gpsList, taskIntervals);
-            
+//            logger.info("---> 杞﹁締ID:{} 浠诲姟鏃堕棿鍖洪棿鏁�:{}", vehicleId, taskIntervals.size());
+
+           List<VehicleGpsSegmentMileage> mileages = this.getTaskDistanceMileage(vehicleId, dayStart, dayEnd).stream().filter(e -> e.getSegmentDistance() != null && e.getSegmentDistance().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
+
+           int totalGpsPoints = mileages.stream()
+                .filter(segment -> segment.getGpsPointCount() != null)
+                .mapToInt(VehicleGpsSegmentMileage::getGpsPointCount)
+                .sum();
+//           logger.info("---> 杞﹁締ID:{} 浠诲姟鏃堕棿:{} 閲岀▼鏃堕棿:{}", vehicleId,
+//                   taskIntervals.stream().map(e->"寮�濮嬫椂闂�:"+DateUtils.formatDate(e.getStartTime())+",缁撴潫鏃堕棿:"+DateUtils.formatDate(e.getEndTime())).collect(Collectors.joining()),
+//                   mileages.stream().map(e->"寮�濮嬫椂闂�:"+DateUtils.formatDate(e.getSegmentStartTime())+",缁撴潫鏃堕棿:"+DateUtils.formatDate(e.getSegmentEndTime())).collect(Collectors.joining()));
+            BigDecimal taskDistance = getTaskDistance(taskIntervals,mileages);
+//            logger.info("---> 杞﹁締ID:{} 浠诲姟鎬婚噷绋�:{}", vehicleId, taskDistance);
+            MileageCalculation calculation = calculateMileage(gpsList, taskDistance);
+//            logger.info("---> 璁$畻鍑鸿溅杈嗗綋澶╂�婚噷绋嬶紝杞﹁締ID:{},鎬婚噷绋嬶細{},浠诲姟閲岀▼:{}",vehicleId,calculation.totalMileage,calculation.taskMileage);
             // 5. 鏌ヨ鎴栧垱寤虹粺璁¤褰�
             VehicleMileageStats stats = vehicleMileageStatsMapper.selectByVehicleIdAndDate(vehicleId, statDate);
             boolean isNew = (stats == null);
@@ -122,10 +153,18 @@
                 stats.setVehicleId(vehicleId);
                 stats.setStatDate(statDate);
                 
-                // 鑾峰彇杞︾墝鍙�
+                // 鑾峰彇杞︾墝鍙凤細浼樺厛浠嶨PS鏁版嵁锛屽鏋滄病鏈夊垯浠庤溅杈嗚〃鏌ヨ
+                String vehicleNo = null;
                 if (!gpsList.isEmpty() && gpsList.get(0).getVehicleNo() != null) {
-                    stats.setVehicleNo(gpsList.get(0).getVehicleNo());
+                    vehicleNo = gpsList.get(0).getVehicleNo();
                 }
+                if (vehicleNo == null || vehicleNo.trim().isEmpty()) {
+                    VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoById(vehicleId);
+                    if (vehicleInfo != null) {
+                        vehicleNo = vehicleInfo.getVehicleNo();
+                    }
+                }
+                stats.setVehicleNo(vehicleNo);
             }
             
             // 6. 璁剧疆缁熻鏁版嵁
@@ -133,8 +172,11 @@
             stats.setTaskMileage(calculation.taskMileage);
             stats.setNonTaskMileage(calculation.nonTaskMileage);
             stats.setTaskRatio(calculation.taskRatio);
-            stats.setGpsPointCount(gpsList.size());
+            stats.setGpsPointCount(totalGpsPoints);
             stats.setTaskCount(taskIntervals == null ? 0 : taskIntervals.size());
+
+//            logger.info("杞﹁締ID: {} 鏃ユ湡: {} 閲岀▼缁熻瀹屾垚 - 鎬婚噷绋�: {}km, 浠诲姟閲岀▼: {}km, 闈炰换鍔¢噷绋�: {}km, 鍗犳瘮: {}",
+//                    vehicleId, statDate, calculation.totalMileage, taskDistance, calculation.nonTaskMileage, calculation.taskRatio);
             
             // 7. 淇濆瓨鍒版暟鎹簱
             if (isNew) {
@@ -142,15 +184,17 @@
             } else {
                 vehicleMileageStatsMapper.updateVehicleMileageStats(stats);
             }
-            
-            logger.info("杞﹁締ID: {} 鏃ユ湡: {} 閲岀▼缁熻瀹屾垚 - 鎬婚噷绋�: {}km, 浠诲姟閲岀▼: {}km, 闈炰换鍔¢噷绋�: {}km, 鍗犳瘮: {}", 
-                       vehicleId, statDate, calculation.totalMileage, calculation.taskMileage, 
-                       calculation.nonTaskMileage, calculation.taskRatio);
-            
+
+//            if (taskIntervals != null) {
+//                logger.info("---> 鍚屾閲岀▼瀹屾垚,杞﹁締ID: {} 鏃ユ湡: {} 閲岀▼缁熻瀹屾垚 - 鎬婚噷绋�: {}km,浠诲姟鏁伴噺锛歿} 浠诲姟閲岀▼: {}km, 闈炰换鍔¢噷绋�: {}km, 鍗犳瘮: {}",
+//                           vehicleId, statDate, calculation.totalMileage,taskIntervals.size(), calculation.taskMileage,
+//                           calculation.nonTaskMileage, calculation.taskRatio);
+//            }
+
             return stats;
             
         } catch (Exception e) {
-            logger.error("璁$畻杞﹁締閲岀▼缁熻澶辫触 - 杞﹁締ID: {}, 鏃ユ湡: {}", vehicleId, statDate, e);
+            logger.error("---> 璁$畻杞﹁締閲岀▼缁熻澶辫触 - 杞﹁締ID: {}, 鏃ユ湡: {}", vehicleId, statDate, e);
             throw new RuntimeException("璁$畻閲岀▼缁熻澶辫触: " + e.getMessage());
         }
     }
@@ -161,8 +205,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();
+            String startTimeStr = DateUtils.formatDate(startTime,DateUtils.YYYY_MM_DD_HH_MM_SS);
             // 鏌ヨ鎵�鏈夋椿璺冭溅杈�
-            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds();
+            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTimeStr);
             
             if (vehicleIds == null || vehicleIds.isEmpty()) {
                 logger.info("娌℃湁鎵惧埌娲昏穬杞﹁締");
@@ -179,7 +229,7 @@
                 }
             }
             
-            logger.info("鎵归噺閲岀▼缁熻瀹屾垚 - 鏃ユ湡: {}, 鎬昏溅杈嗘暟: {}, 鎴愬姛: {}", statDate, vehicleIds.size(), successCount);
+//            logger.info("鎵归噺閲岀▼缁熻瀹屾垚 - 鏃ユ湡: {}, 鎬昏溅杈嗘暟: {}, 鎴愬姛: {}", statDate, vehicleIds.size(), successCount);
             return successCount;
             
         } catch (Exception e) {
@@ -188,10 +238,23 @@
         }
     }
 
+
+
+    private BigDecimal calculateTotalMileage(List<VehicleGpsSegmentMileage> mileages) {
+        if (mileages == null || mileages.isEmpty()) {
+            return BigDecimal.ZERO;
+        }
+        
+        return mileages.stream()
+            .filter(mileage -> mileage.getSegmentDistance() != null) // 杩囨护鎺夎窛绂讳负null鐨勫垎娈�
+            .map(mileage -> mileage.getSegmentDistance())
+            .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+    }
     /**
      * 璁$畻閲岀▼鐨勫唴閮ㄦ柟娉�
      */
-    private MileageCalculation calculateMileage(List<VehicleGps> gpsList, List<TaskTimeInterval> taskIntervals) {
+    private MileageCalculation calculateMileage(List<VehicleGps> gpsList, BigDecimal taskDistance) {
         MileageCalculation result = new MileageCalculation();
         
         // 閬嶅巻GPS鐐癸紝璁$畻鐩搁偦鐐逛箣闂寸殑璺濈
@@ -206,26 +269,25 @@
                 p2.getLatitude().doubleValue(), 
                 p2.getLongitude().doubleValue()
             );
-            
-            // 鑾峰彇杩欐璺濈鐨勬椂闂村尯闂�
-            Date segmentStart = p1.getCollectTime();
-            Date segmentEnd = p2.getCollectTime();
-            
-            // 璁$畻杩欐璺濈鍦ㄤ换鍔℃椂娈电殑鍗犳瘮
-            double taskRatio = calculateTaskOverlapRatio(segmentStart, segmentEnd, taskIntervals);
-            
-            // 鍒嗘憡閲岀▼
-            double taskDistance = distance * taskRatio;
-            double nonTaskDistance = distance * (1 - taskRatio);
-            
+
             result.totalMileage = result.totalMileage.add(BigDecimal.valueOf(distance));
-            result.taskMileage = result.taskMileage.add(BigDecimal.valueOf(taskDistance));
-            result.nonTaskMileage = result.nonTaskMileage.add(BigDecimal.valueOf(nonTaskDistance));
         }
-        
+
+        result.taskMileage=taskDistance;
+        result.nonTaskMileage=result.totalMileage.subtract(result.taskMileage);
         // 璁$畻浠诲姟閲岀▼鍗犳瘮
         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;
+            }
         }
         
         // 淇濈暀涓や綅灏忔暟
@@ -240,6 +302,11 @@
      * 浣跨敤Haversine鍏紡璁$畻涓や釜GPS鍧愭爣涔嬮棿鐨勮窛绂伙紙鍏噷锛�
      */
     private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
+        // 濡傛灉璧风偣鍜岀粓鐐圭粡绾害鐩稿悓锛岀洿鎺ヨ繑鍥�0锛岄伩鍏嶄笉蹇呰鐨勮绠�
+        if (lat1 == lat2 && lon1 == lon2) {
+            return 0.0;
+        }
+        
         // 灏嗚搴﹁浆鎹负寮у害
         double dLat = Math.toRadians(lat2 - lat1);
         double dLon = Math.toRadians(lon2 - lon1);
@@ -256,32 +323,95 @@
         return EARTH_RADIUS_KM * c;
     }
 
+    //璁$畻浠诲姟鏃堕棿娈靛唴鐨勯噷绋嬶紝搴旇鎷垮埌璇ヤ换鍔″湪宸ヤ綔鏃堕棿娈甸噷鐨勫垎娈佃窛绂荤劧鍚庣浉鍔�
+    private List<VehicleGpsSegmentMileage> getTaskDistanceMileage(Long vehicleId, Date segmentStart, Date segmentEnd) {
+        List<VehicleGpsSegmentMileage> mileages = segmentMileageMapper.selectSegmentsByDateRange(vehicleId, segmentStart, segmentEnd);
+        return mileages != null ? mileages : new ArrayList<>();
+    }
+
     /**
-     * 璁$畻鏃堕棿娈典笌浠诲姟鏃舵鐨勯噸鍙犳瘮渚�
+     * 璁$畻鍦ㄤ换鍔℃椂闂存鍐呯殑瀹為檯浠诲姟閲岀▼
+     * 閫氳繃妫�鏌ュ垎娈甸噷绋嬫暟鎹槸鍚︿笌浠诲姟鏃堕棿娈甸噸鍙狅紝绱姞杩欎簺閲嶅彔鍒嗘鐨勫疄闄呴噷绋�
+     * 
+     * @param taskTimeIntervals 浠诲姟鏃堕棿娈靛垪琛�
+     * @param segmentMileages 鍒嗘閲岀▼鏁版嵁鍒楄〃
+     * @return 鍦ㄤ换鍔℃椂闂存鍐呯殑鎬婚噷绋�
      */
-    private double calculateTaskOverlapRatio(Date segmentStart, Date segmentEnd, List<TaskTimeInterval> taskIntervals) {
-        if (taskIntervals == null || taskIntervals.isEmpty()) {
-            return 0.0;
+    private BigDecimal getTaskDistance(List<TaskTimeInterval> taskTimeIntervals, List<VehicleGpsSegmentMileage> segmentMileages) {
+        if (taskTimeIntervals == null || taskTimeIntervals.isEmpty() || 
+            segmentMileages == null || segmentMileages.isEmpty()) {
+            return BigDecimal.ZERO;
         }
         
-        long segmentDuration = segmentEnd.getTime() - segmentStart.getTime();
-        if (segmentDuration <= 0) {
-            return 0.0;
-        }
+        BigDecimal totalTaskDistance = BigDecimal.ZERO;
         
-        long totalOverlap = 0;
-        
-        for (TaskTimeInterval task : taskIntervals) {
-            // 璁$畻閲嶅彔鏃堕棿
-            long overlapStart = Math.max(segmentStart.getTime(), task.getStartTime().getTime());
-            long overlapEnd = Math.min(segmentEnd.getTime(), task.getEndTime().getTime());
+        // 閬嶅巻鎵�鏈夊垎娈甸噷绋嬫暟鎹�
+        for (VehicleGpsSegmentMileage segment : segmentMileages) {
+            // 鍙鐞嗘湁鍏宠仈浠诲姟ID涓旀湁璺濈鏁版嵁鐨勫垎娈�
+//            if (segment.getTaskId() == null || segment.getSegmentDistance() == null) {
+//                continue;
+//            }
+
+            // 妫�鏌ヨ鍒嗘鏄惁涓庝换浣曚换鍔℃椂闂存閲嶅彔
+            Date segmentStart = segment.getSegmentStartTime();
+            Date segmentEnd = segment.getSegmentEndTime();
             
-            if (overlapEnd > overlapStart) {
-                totalOverlap += (overlapEnd - overlapStart);
+            boolean isInTaskPeriod = false;
+            for (TaskTimeInterval taskInterval : taskTimeIntervals) {
+                // 璁$畻鏃堕棿閲嶅彔 --浠诲姟鏃堕棿娈�
+                long overlapStart = Math.max(segmentStart.getTime(), taskInterval.getStartTime().getTime());
+                long overlapEnd = Math.min(segmentEnd.getTime(), taskInterval.getEndTime().getTime());
+                
+                // 濡傛灉鏈夋椂闂撮噸鍙狅紝鍒欒鍒嗘灞炰簬浠诲姟閲岀▼
+                if (overlapEnd > overlapStart) {
+                    isInTaskPeriod = true;
+                    break;
+                }
+            }
+            
+            // 濡傛灉鍒嗘鍦ㄤ换鍔℃椂闂存鍐咃紝鍒欑疮鍔犲叾閲岀▼
+            if (isInTaskPeriod) {
+                totalTaskDistance = totalTaskDistance.add(segment.getSegmentDistance());
             }
         }
         
-        return (double) totalOverlap / segmentDuration;
+        return totalTaskDistance;
+    }
+    /**
+     * 璁$畻鎸囧畾鏃堕棿娈靛唴鐨勫疄闄呬换鍔¢噷绋�
+     * 閫氳繃鏌ユ壘涓庤鏃堕棿娈甸噸鍙犵殑浠诲姟锛屽苟绱姞杩欎簺浠诲姟鍦ㄨ鏃堕棿娈靛唴鐨勫疄闄呴噷绋�
+     */
+    private double calculateActualTaskMileage(Date segmentStart, Date segmentEnd, List<VehicleGpsSegmentMileage> segmentMileages) {
+        if (segmentMileages == null || segmentMileages.isEmpty()) {
+            return 0.0;
+        }
+        
+        double totalTaskMileage = 0.0;
+        
+        // 閬嶅巻鎵�鏈夊垎娈甸噷绋嬫暟鎹紝鎵惧嚭涓庢寚瀹氭椂闂存閲嶅彔涓旀湁鍏宠仈浠诲姟鐨勫垎娈�
+        for (VehicleGpsSegmentMileage segment : segmentMileages) {
+            // 鍙鐞嗘湁鍏宠仈浠诲姟鐨勫垎娈�
+            if (segment.getTaskId() == null) {
+                continue;
+            }
+            
+            // 妫�鏌ュ垎娈垫椂闂翠笌鎸囧畾鏃堕棿娈垫槸鍚︽湁閲嶅彔
+            Date segStart = segment.getSegmentStartTime();
+            Date segEnd = segment.getSegmentEndTime();
+            
+            // 璁$畻閲嶅彔鏃堕棿
+            long overlapStart = Math.max(segmentStart.getTime(), segStart.getTime());
+            long overlapEnd = Math.min(segmentEnd.getTime(), segEnd.getTime());
+            
+            // 濡傛灉鏈夋椂闂撮噸鍙狅紝鍒欏皢璇ュ垎娈电殑璺濈鍔犲叆浠诲姟閲岀▼
+            if (overlapEnd > overlapStart) {
+                if (segment.getSegmentDistance() != null) {
+                    totalTaskMileage += segment.getSegmentDistance().doubleValue();
+                }
+            }
+        }
+        
+        return totalTaskMileage;
     }
 
     /**
@@ -293,4 +423,164 @@
         BigDecimal nonTaskMileage = BigDecimal.ZERO;
         BigDecimal taskRatio = BigDecimal.ZERO;
     }
+    
+    /**
+     * 瑙f瀽鏃ユ湡鏃堕棿瀛楃涓�
+     * 
+     * @param dateTimeStr 鏃ユ湡鏃堕棿瀛楃涓诧紝鏍煎紡锛歽yyy-MM-dd HH:mm:ss
+     * @return Date瀵硅薄
+     * @throws RuntimeException 濡傛灉瑙f瀽澶辫触
+     */
+    private Date parseDateTime(String dateTimeStr) {
+        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
+            throw new RuntimeException("鏃ユ湡鏃堕棿瀛楃涓蹭笉鑳戒负绌�");
+        }
+        
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            sdf.setLenient(false);
+            return sdf.parse(dateTimeStr.trim());
+        } catch (ParseException e) {
+            throw new RuntimeException("鏃ユ湡鏃堕棿鏍煎紡閿欒: " + dateTimeStr + ", 搴斾负 yyyy-MM-dd HH:mm:ss", e);
+        }
+    }
+
+    /**
+     * 浠庡垎娈甸噷绋嬫暟鎹眹鎬荤敓鎴愭寜鏃ョ粺璁�
+     */
+    @Override
+    public VehicleMileageStats aggregateFromSegmentMileage(Long vehicleId, Date statDate) {
+        try {
+            // 1. 鑾峰彇缁熻鏃ユ湡鐨勫紑濮嬪拰缁撴潫鏃堕棿
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(statDate);
+            calendar.set(Calendar.HOUR_OF_DAY, 0);
+            calendar.set(Calendar.MINUTE, 0);
+            calendar.set(Calendar.SECOND, 0);
+            calendar.set(Calendar.MILLISECOND, 0);
+            Date dayStart = calendar.getTime();
+            
+            calendar.add(Calendar.DAY_OF_MONTH, 1);
+            Date dayEnd = calendar.getTime();
+            
+            // 2. 鏌ヨ璇ユ棩鏈熻寖鍥村唴鐨勬墍鏈夊垎娈甸噷绋嬫暟鎹�
+            List<VehicleGpsSegmentMileage> segments = segmentMileageMapper.selectSegmentsByDateRange(vehicleId, dayStart, dayEnd);
+            
+            if (segments == null || segments.isEmpty()) {
+                logger.info("杞﹁締ID: {} 鍦ㄦ棩鏈�: {} 鏃犲垎娈甸噷绋嬫暟鎹�", vehicleId, statDate);
+                return null;
+            }
+
+            List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd);
+            Integer taskCount = taskIntervals != null ? taskIntervals.size() : 0;
+            logger.info("杞﹁締ID: {} 鍦ㄦ棩鏈�: {} 鏈� {} 涓换鍔�", vehicleId, statDate, taskCount);
+            List<VehicleGpsSegmentMileage> mileages = this.getTaskDistanceMileage(vehicleId, dayStart, dayEnd).stream().filter(e -> e.getSegmentDistance() != null && e.getSegmentDistance().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
+            logger.info("杞﹁締ID: {} 鍦ㄦ棩鏈�: {} 鏈� {} 涓垎娈甸噷绋嬫暟鎹�", vehicleId, statDate, mileages.size());
+            Integer totalGpsPoints = mileages != null ? mileages.stream()
+                .filter(segment -> segment.getGpsPointCount() != null)
+                .mapToInt(VehicleGpsSegmentMileage::getGpsPointCount)
+                .sum() : 0;
+            BigDecimal taskDistance = getTaskDistance(taskIntervals, mileages);
+            BigDecimal totalDistance = calculateTotalMileage(segments);
+            BigDecimal nonTaskDistance = totalDistance.subtract(taskDistance);
+            
+            // 闃叉闄ら浂閿欒
+            BigDecimal taskRatio = BigDecimal.ZERO;
+            if (totalDistance != null && totalDistance.compareTo(BigDecimal.ZERO) > 0) {
+                taskRatio = taskDistance.divide(totalDistance, 4, RoundingMode.HALF_UP);
+            }
+            // 3. 姹囨�婚噷绋嬫暟鎹�
+
+
+            // 5. 鏌ヨ鎴栧垱寤虹粺璁¤褰�
+            VehicleMileageStats stats = vehicleMileageStatsMapper.selectByVehicleIdAndDate(vehicleId, statDate);
+            boolean isNew = (stats == null);
+            
+            if (isNew) {
+                stats = new VehicleMileageStats();
+                stats.setVehicleId(vehicleId);
+                stats.setStatDate(statDate);
+                
+                // 鑾峰彇杞︾墝鍙凤細浼樺厛浠庡垎娈垫暟鎹紝濡傛灉娌℃湁鍒欎粠杞﹁締琛ㄦ煡璇�
+                String vehicleNo = null;
+                if (!segments.isEmpty() && segments.get(0).getVehicleNo() != null) {
+                    vehicleNo = segments.get(0).getVehicleNo();
+                }
+                if (vehicleNo == null || vehicleNo.trim().isEmpty()) {
+                    VehicleInfo vehicleInfo = vehicleInfoMapper.selectVehicleInfoById(vehicleId);
+                    if (vehicleInfo != null) {
+                        vehicleNo = vehicleInfo.getVehicleNo();
+                    }
+                }
+                stats.setVehicleNo(vehicleNo);
+            }
+            
+            // 6. 璁剧疆缁熻鏁版嵁
+            stats.setTotalMileage(totalDistance.setScale(2, RoundingMode.HALF_UP));
+            stats.setTaskMileage(taskDistance.setScale(2, RoundingMode.HALF_UP));
+            stats.setNonTaskMileage(nonTaskDistance.setScale(2, RoundingMode.HALF_UP));
+            stats.setTaskRatio(taskRatio);
+            stats.setGpsPointCount(totalGpsPoints);
+            stats.setTaskCount(taskCount);
+            stats.setSegmentCount(segments.size());
+            stats.setDataSource("segment"); // 鏍囪鏁版嵁鏉ユ簮涓哄垎娈垫眹鎬�
+            
+            // 7. 淇濆瓨鍒版暟鎹簱
+            if (isNew) {
+                vehicleMileageStatsMapper.insertVehicleMileageStats(stats);
+            } else {
+                vehicleMileageStatsMapper.updateVehicleMileageStats(stats);
+            }
+            
+//            logger.info("杞﹁締ID: {} 鏃ユ湡: {} 浠庡垎娈垫眹鎬诲畬鎴� - 鎬婚噷绋�: {}km, 浠诲姟閲岀▼: {}km, 闈炰换鍔¢噷绋�: {}km, 鍒嗘鏁�: {}",
+//                       vehicleId, statDate, totalMileage, taskMileage, nonTaskMileage, segments.size());
+            
+            return stats;
+            
+        } catch (Exception e) {
+            logger.error("浠庡垎娈垫眹鎬婚噷绋嬬粺璁″け璐� - 杞﹁締ID: {}, 鏃ユ湡: {}", vehicleId, statDate, e);
+            throw new RuntimeException("姹囨�婚噷绋嬬粺璁″け璐�: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 鎵归噺浠庡垎娈甸噷绋嬫眹鎬荤敓鎴愭寜鏃ョ粺璁�
+     */
+    @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();
+
+            String startTimeStr = DateUtils.formatDate(startTime, DateUtils.YYYY_MM_DD_HH_MM_SS);
+            
+            // 鏌ヨ鎵�鏈夋椿璺冭溅杈�
+            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTimeStr);
+            
+            if (vehicleIds == null || vehicleIds.isEmpty()) {
+                logger.info("娌℃湁鎵惧埌娲昏穬杞﹁締");
+                return 0;
+            }
+            
+            int successCount = 0;
+            for (Long vehicleId : vehicleIds) {
+                try {
+                    aggregateFromSegmentMileage(vehicleId, statDate);
+                    successCount++;
+                } catch (Exception e) {
+                    logger.error("姹囨�昏溅杈� {} 鐨勯噷绋嬬粺璁″け璐�", vehicleId, e);
+                }
+            }
+            
+            logger.info("鎵归噺閲岀▼姹囨�诲畬鎴� - 鏃ユ湡: {}, 鎬昏溅杈嗘暟: {}, 鎴愬姛: {}", statDate, vehicleIds.size(), successCount);
+            return successCount;
+            
+        } catch (Exception e) {
+            logger.error("鎵归噺姹囨�婚噷绋嬬粺璁″け璐� - 鏃ユ湡: {}", statDate, e);
+            throw new RuntimeException("鎵归噺姹囨�诲け璐�: " + e.getMessage());
+        }
+    }
 }

--
Gitblit v1.9.1