From f67945d53b20f6a45ae50b27d74c966eb1355bb4 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期日, 16 十一月 2025 22:53:54 +0800
Subject: [PATCH] feat: 增加分段GPS计算行程距离

---
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleMileageStatsServiceImpl.java |  205 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 201 insertions(+), 4 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..3cf88f0 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,6 +2,8 @@
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
@@ -11,9 +13,13 @@
 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 +38,12 @@
     
     @Autowired
     private VehicleGpsMapper vehicleGpsMapper;
+
+    @Autowired
+    private VehicleGpsSegmentMileageMapper segmentMileageMapper;
+    
+    @Autowired
+    private VehicleInfoMapper vehicleInfoMapper;
 
     /**
      * 鏌ヨ杞﹁締閲岀▼缁熻
@@ -122,10 +134,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. 璁剧疆缁熻鏁版嵁
@@ -208,8 +228,8 @@
             );
             
             // 鑾峰彇杩欐璺濈鐨勬椂闂村尯闂�
-            Date segmentStart = p1.getCollectTime();
-            Date segmentEnd = p2.getCollectTime();
+            Date segmentStart = parseDateTime(p1.getCollectTime());
+            Date segmentEnd = parseDateTime(p2.getCollectTime());
             
             // 璁$畻杩欐璺濈鍦ㄤ换鍔℃椂娈电殑鍗犳瘮
             double taskRatio = calculateTaskOverlapRatio(segmentStart, segmentEnd, taskIntervals);
@@ -240,6 +260,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);
@@ -293,4 +318,176 @@
         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;
+            }
+            
+            // 3. 姹囨�婚噷绋嬫暟鎹�
+            BigDecimal totalMileage = BigDecimal.ZERO;
+            int totalGpsPoints = 0;
+            
+            for (VehicleGpsSegmentMileage segment : segments) {
+                if (segment.getSegmentDistance() != null) {
+                    totalMileage = totalMileage.add(segment.getSegmentDistance());
+                }
+                if (segment.getGpsPointCount() != null) {
+                    totalGpsPoints += segment.getGpsPointCount();
+                }
+            }
+            
+            // 4. 鏌ヨ璇ユ棩鏈熺殑浠诲姟鏃堕棿鍖洪棿锛岃绠椾换鍔¢噷绋嬪拰闈炰换鍔¢噷绋�
+            List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd);
+            
+            BigDecimal taskMileage = BigDecimal.ZERO;
+            BigDecimal nonTaskMileage = BigDecimal.ZERO;
+            
+            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);
+            }
+            
+            // 璁$畻浠诲姟閲岀▼鍗犳瘮
+            BigDecimal taskRatio = BigDecimal.ZERO;
+            if (totalMileage.compareTo(BigDecimal.ZERO) > 0) {
+                taskRatio = taskMileage.divide(totalMileage, 4, RoundingMode.HALF_UP);
+            }
+            
+            // 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(totalMileage.setScale(2, RoundingMode.HALF_UP));
+            stats.setTaskMileage(taskMileage.setScale(2, RoundingMode.HALF_UP));
+            stats.setNonTaskMileage(nonTaskMileage.setScale(2, RoundingMode.HALF_UP));
+            stats.setTaskRatio(taskRatio);
+            stats.setGpsPointCount(totalGpsPoints);
+            stats.setTaskCount(taskIntervals == null ? 0 : taskIntervals.size());
+            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 {
+            // 鏌ヨ鎵�鏈夋椿璺冭溅杈�
+            List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds();
+            
+            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