From fb0e22c8f74ed0e3c337afa60075579a151b53eb Mon Sep 17 00:00:00 2001
From: wangrong <wangrong@shsening.com>
Date: 星期五, 09 十月 2026 09:40:38 +0800
Subject: [PATCH] 修复车辆行驶数据汇总统计report

---
 src/modules/report/service/taskservicevehicle.ts |   54 +++++++++++++++++++++++++++++++++---------------------
 1 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/src/modules/report/service/taskservicevehicle.ts b/src/modules/report/service/taskservicevehicle.ts
index 7d392c0..949aeca 100644
--- a/src/modules/report/service/taskservicevehicle.ts
+++ b/src/modules/report/service/taskservicevehicle.ts
@@ -28,12 +28,13 @@
         let THRESHOLD_MOVING = parseInt(await this.baseSysParamService.dataByKey('vehicle.speed.threshold.moving')); //'2.0 km/h';
         let THRESHOLD_SPEEDING = parseInt(await this.baseSysParamService.dataByKey('vehicle.speed.threshold.speeding')); //'30 km/h';
         let THRESHOLD_DISPLACEMENT = parseInt(await this.baseSysParamService.dataByKey('vehicle.threshold.displacement')); //'30 km/h';
+        let VEHICLE_GPS_MAX_INTERVAL_SEC = parseInt(await this.baseSysParamService.dataByKey('vehicle.gps.max.interval.sec')); //'900';
         HOUR_STARTWORK = Number.isNaN(HOUR_STARTWORK) ? 6 : HOUR_STARTWORK;
         HOUR_OFFWORK = Number.isNaN(HOUR_OFFWORK) ? 22 : HOUR_OFFWORK;
         THRESHOLD_MOVING = Number.isNaN(THRESHOLD_MOVING) ? 2 : THRESHOLD_MOVING;
         THRESHOLD_SPEEDING = Number.isNaN(THRESHOLD_SPEEDING) ? 30 : THRESHOLD_SPEEDING;
         THRESHOLD_DISPLACEMENT = Number.isNaN(THRESHOLD_DISPLACEMENT) ? 10 : THRESHOLD_DISPLACEMENT;
-
+        VEHICLE_GPS_MAX_INTERVAL_SEC = Number.isNaN(VEHICLE_GPS_MAX_INTERVAL_SEC) ? 900 : VEHICLE_GPS_MAX_INTERVAL_SEC;
 
 
         const rawGpsList = await this.pushVehicleGpsEntity.createQueryBuilder('gps')
@@ -87,7 +88,8 @@
                 HOUR_OFFWORK,
                 THRESHOLD_MOVING,
                 THRESHOLD_SPEEDING,
-                THRESHOLD_DISPLACEMENT
+                THRESHOLD_DISPLACEMENT,
+                VEHICLE_GPS_MAX_INTERVAL_SEC
             );
             summariesToUpsert.push(summary);
         }
@@ -112,7 +114,8 @@
         HOUR_OFFWORK: number,
         HHRESHOLD_MOVING: number,
         THRESHOLD_SPEEDING: number,
-        THRESHOLD_DISPLACEMENT: number
+        THRESHOLD_DISPLACEMENT: number,
+        VEHICLE_GPS_MAX_INTERVAL_SEC: number
     ): Partial<ReportDailyVehicleEntity> {
         const departmentId = points[0]?.departmentId ?? null;
 
@@ -131,11 +134,14 @@
         let offHoursMoveCount = 0; // 闈炲伐浣滄椂娈靛紓鍔ㄦ鏁�
 
         let isOverspeeding = false; // 瓒呴�熺姸鎬佹爣璁�
+        // 鐗╃悊閲忓彧鍦ㄣ�屼笂涓�鏈夋晥鍧愭爣鐐广�嶄笌褰撳墠鏈夋晥鐐逛箣闂磋绠楋紝绌哄潗鏍囦笉鍙備笌
+        let lastValidIdx = -1;
 
         for (let i = 0; i < points.length; i++) {
             const curr = points[i];
             const speed = Number(curr.speed) || 0;
             const currDate = new Date(curr.gpsTime);
+            const currValid = this.isValidGpsPoint(curr);
 
             // ====================================================
             // 椤哄簭 1锛氬崟鐐圭姸鎬佸垽鏂紙鍙緷璧栧綋鍓嶇偣鐨勬暟鎹級
@@ -159,18 +165,23 @@
             }
 
             // ====================================================
-            // 椤哄簭 2锛氱浉閭荤偣寰垎涓庣墿鐞嗛噺璁$畻锛堝繀椤讳緷璧栧墠涓�鐐� i-1锛�
+            // 椤哄簭 2锛氱浉閭绘湁鏁堢偣寰垎涓庣墿鐞嗛噺璁$畻
             // ====================================================
-            if (i > 0) {
-                const prev = points[i - 1];
+            if (!currValid) {
+                continue;
+            }
+            if (lastValidIdx >= 0) {
+                const prev = points[lastValidIdx];
                 const prevDate = new Date(prev.gpsTime);
 
                 // 璁$畻鐩搁偦涓ょ偣鏃堕棿宸紙绉掞級
                 const timeDiffSec = Math.floor((currDate.getTime() - prevDate.getTime()) / 1000);
-
-                // 杩囨护缃戠粶鏂繛/鍏虫満锛堟椂闂村樊 > 120 绉� 瑙嗕负鎺夌嚎锛屼笉鍙備笌鐗╃悊寰垎璁$畻锛�
-                if (timeDiffSec > 0 && timeDiffSec <= 120) {
-
+                // 3.4 闈欐鍋滈潬杈惧埌 15 鍒嗛挓锛�900绉掞級绠椾綔寮傚父鎬犻��
+                if (timeDiffSec >= 900) {
+                    secondsAbnormalIdle += timeDiffSec;
+                }
+                // 瓒呰繃閰嶇疆闂撮殧瑙嗕负鎺夌嚎锛屼笉鍙備笌鐗╃悊寰垎璁$畻
+                if (timeDiffSec > 0 && timeDiffSec <= VEHICLE_GPS_MAX_INTERVAL_SEC) {
                     // ================================================
                     // 椤哄簭 3锛氬熀浜庡潗鏍囦綅绉诲垝鍒嗕负銆愯椹躲�戞垨銆愰潤姝㈠仠闈犮��
                     // ================================================
@@ -185,20 +196,10 @@
                         secondsMoving += timeDiffSec;
 
                         // 3.2 绱姞鐞冮潰鐪熷疄浣嶇Щ璺濈
-                        totalMeter += this.getHaversineDistance(
-                            Number(prev.latitude),
-                            Number(prev.longitude),
-                            Number(curr.latitude),
-                            Number(curr.longitude),
-                        );
+                        totalMeter += distance;
                     } else {
                         // 3.3 绱姞闈欐鍋滈潬鏃堕暱
                         secondsParked += timeDiffSec;
-
-                        // 3.4 闈欐鍋滈潬瓒呰繃 15 鍒嗛挓锛�900绉掞級绠椾綔寮傚父鎬犻��
-                        if (timeDiffSec > 900) {
-                            secondsAbnormalIdle += timeDiffSec;
-                        }
                     }
 
                     // ================================================
@@ -227,6 +228,7 @@
                     }
                 }
             }
+            lastValidIdx = i;
         }
 
         // ====================================================
@@ -296,6 +298,16 @@
 
     }
 
+    /** 缁忕含搴︾己澶便�侀潪鏁板瓧鎴� (0,0) 涓嶅弬涓庨噷绋�/鏃堕暱 */
+    private isValidGpsPoint(point: { latitude?: any; longitude?: any }): boolean {
+        const lat = Number(point?.latitude);
+        const lon = Number(point?.longitude);
+        if (!Number.isFinite(lat) || !Number.isFinite(lon)) return false;
+        if (lat === 0 && lon === 0) return false;
+        if (Math.abs(lat) > 90 || Math.abs(lon) > 180) return false;
+        return true;
+    }
+
     /**
      * 绾� JS 鍘熺敓璁$畻涓ょ偣涔嬮棿鐨勭悆闈㈣窛绂� (鍗曚綅: 绫�)
      */

--
Gitblit v1.9.1