| | |
| | | # 车è¾GPSéç¨ç»è®¡åè½å®ç°æ»ç» |
| | | |
| | | ## ä¸ãåè½å®ç°æ¸
å |
| | | |
| | | ### â
1. æ°æ®åºå± |
| | | - [x] `vehicle_mileage_stats.sql` - å建éç¨ç»è®¡è¡¨åæç»è¡¨ |
| | | - [x] `vehicle_mileage_stats_job.sql` - åå»ºå®æ¶ä»»å¡é
ç½® |
| | | - [x] `vehicle_mileage_stats_menu.sql` - å建èåæéé
ç½® |
| | | |
| | | ### â
2. å®ä½ç±»ï¼Domainï¼ |
| | | - [x] `VehicleMileageStats.java` - éç¨ç»è®¡å®ä½ |
| | | - [x] `TaskTimeInterval.java` - 任塿¶é´åºé´è¾
å©ç±» |
| | | |
| | | ### â
3. æ°æ®è®¿é®å±ï¼Mapperï¼ |
| | | - [x] `VehicleMileageStatsMapper.java` - éç¨ç»è®¡Mapperæ¥å£ |
| | | - [x] `VehicleMileageStatsMapper.xml` - MyBatisæ å°é
ç½® |
| | | - [x] `VehicleGpsMapper.java` - æ©å±GPSæ¥è¯¢æ¹æ³ï¼æ°å¢2ä¸ªæ¹æ³ï¼ |
| | | - [x] `VehicleGpsMapper.xml` - æ©å±GPSæ¥è¯¢SQL |
| | | |
| | | ### â
4. ä¸å¡é»è¾å±ï¼Serviceï¼ |
| | | - [x] `IVehicleMileageStatsService.java` - Serviceæ¥å£ |
| | | - [x] `VehicleMileageStatsServiceImpl.java` - Serviceå®ç°ï¼æ ¸å¿ç®æ³ï¼ |
| | | |
| | | ### â
5. æ§å¶å±ï¼Controllerï¼ |
| | | - [x] `VehicleMileageStatsController.java` - REST APIæ¥å£ |
| | | |
| | | ### â
6. 宿¶ä»»å¡ï¼Taskï¼ |
| | | - [x] `VehicleMileageStatsTask.java` - èªå¨ç»è®¡å®æ¶ä»»å¡ |
| | | |
| | | ### â
7. å端API |
| | | - [x] `mileageStats.js` - å端æ¥å£å°è£
|
| | | |
| | | ### â
8. ææ¡£ |
| | | - [x] `车è¾éç¨ç»è®¡ä½¿ç¨è¯´æ.md` - 详ç»ä½¿ç¨ææ¡£ |
| | | |
| | | ## äºãæ ¸å¿ææ¯å®ç° |
| | | |
| | | ### 1. éç¨è®¡ç®ç®æ³ |
| | | |
| | | #### Haversineå
¬å¼ï¼è®¡ç®GPSç¹é´è·ç¦»ï¼ |
| | | ```java |
| | | private double calculateDistance(double lat1, double lon1, double lat2, double lon2) { |
| | | double dLat = Math.toRadians(lat2 - lat1); |
| | | double dLon = Math.toRadians(lon2 - lon1); |
| | | double rLat1 = Math.toRadians(lat1); |
| | | double rLat2 = Math.toRadians(lat2); |
| | | |
| | | double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
| | | Math.cos(rLat1) * Math.cos(rLat2) * |
| | | Math.sin(dLon / 2) * Math.sin(dLon / 2); |
| | | |
| | | double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
| | | |
| | | return EARTH_RADIUS_KM * c; |
| | | } |
| | | ``` |
| | | |
| | | #### æ¶é´éå æ¯ä¾è®¡ç®ï¼ä»»å¡éç¨åæï¼ |
| | | ```java |
| | | private double calculateTaskOverlapRatio(Date segmentStart, Date segmentEnd, |
| | | List<TaskTimeInterval> taskIntervals) { |
| | | long segmentDuration = segmentEnd.getTime() - segmentStart.getTime(); |
| | | 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()); |
| | | |
| | | if (overlapEnd > overlapStart) { |
| | | totalOverlap += (overlapEnd - overlapStart); |
| | | } |
| | | } |
| | | |
| | | return (double) totalOverlap / segmentDuration; |
| | | } |
| | | ``` |
| | | |
| | | ### 2. 任塿¶æ®µå®ä¹ |
| | | |
| | | 任塿¶æ®µ = ä»ä»»å¡å建æ¶é´ï¼`sys_task.create_time`ï¼å°ä»»å¡å®ææ¶é´ï¼`sys_task.actual_end_time`ï¼ |
| | | |
| | | SQLæ¥è¯¢ï¼ |
| | | ```sql |
| | | select tv.task_id, t.create_time as start_time, |
| | | IFNULL(t.actual_end_time, NOW()) as end_time |
| | | from sys_task_vehicle tv |
| | | inner join sys_task t on tv.task_id = t.task_id |
| | | where tv.vehicle_id = #{vehicleId} |
| | | and t.del_flag = '0' |
| | | and t.actual_end_time is not null |
| | | and t.create_time < #{endTime} |
| | | and t.actual_end_time > #{startTime} |
| | | ``` |
| | | |
| | | ### 3. ç»è®¡æ°æ®ç¼å |
| | | |
| | | - æ¯æ¥å®æ¶ä»»å¡èªå¨ç»è®¡åä¸å¤©çæ°æ® |
| | | - ç»è®¡ç»æåå¨å¨ `tb_vehicle_mileage_stats` è¡¨ä¸ |
| | | - æ¯æéå¤è®¡ç®ï¼æ´æ°å·²æè®°å½ï¼ |
| | | - å¯ä¸ç´¢å¼ï¼`uk_vehicle_date (vehicle_id, stat_date)` |
| | | |
| | | ## ä¸ãAPIæ¥å£è¯´æ |
| | | |
| | | ### 1. æ¥è¯¢ç»è®¡å表 |
| | | ``` |
| | | GET /system/mileageStats/list |
| | | åæ°ï¼ |
| | | - vehicleId: 车è¾IDï¼å¯éï¼ |
| | | - vehicleNo: 车çå·ï¼å¯éï¼ |
| | | - statDate: ç»è®¡æ¥æï¼å¯éï¼ |
| | | - beginStatDate: å¼å§æ¥æï¼å¯éï¼ |
| | | - endStatDate: ç»ææ¥æï¼å¯éï¼ |
| | | - pageNum: 页ç |
| | | - pageSize: æ¯é¡µæ°é |
| | | ``` |
| | | |
| | | ### 2. æå¨è®¡ç®å车è¾éç¨ |
| | | ``` |
| | | POST /system/mileageStats/calculate |
| | | åæ°ï¼ |
| | | - vehicleId: 车è¾IDï¼å¿
å¡«ï¼ |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ yyyy-MM-ddï¼å¿
å¡«ï¼ |
| | | è¿åï¼VehicleMileageStats对象 |
| | | ``` |
| | | |
| | | ### 3. æ¹éè®¡ç®ææè½¦è¾éç¨ |
| | | ``` |
| | | POST /system/mileageStats/batchCalculate |
| | | åæ°ï¼ |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ yyyy-MM-ddï¼å¿
å¡«ï¼ |
| | | è¿åï¼æåç»è®¡çè½¦è¾æ°é |
| | | ``` |
| | | |
| | | ### 4. 导åºç»è®¡æ°æ® |
| | | ``` |
| | | POST /system/mileageStats/export |
| | | åæ°ï¼åæ¥è¯¢å表æ¥å£ |
| | | è¿åï¼Excelæä»¶ |
| | | ``` |
| | | |
| | | ## åã宿¶ä»»å¡é
ç½® |
| | | |
| | | ### é»è®¤é
ç½® |
| | | - **ä»»å¡åç§°**ï¼è½¦è¾éç¨ç»è®¡ä»»å¡ |
| | | - **Beanåç§°**ï¼vehicleMileageStatsTask |
| | | - **æ¹æ³è°ç¨**ï¼calculateYesterdayMileage |
| | | - **Cron表达å¼**ï¼`0 30 1 * * ?`ï¼æ¯å¤©åæ¨1:30æ§è¡ï¼ |
| | | - **æ§è¡çç¥**ï¼ç«å³æ§è¡ |
| | | - **å¹¶åæ§è¡**ï¼ç¦æ¢ |
| | | - **ç¶æ**ï¼å¯ç¨ |
| | | |
| | | ### æå¨è§¦åæ¹å¼ |
| | | å¨ç³»ç»ç®¡ç -> 宿¶ä»»å¡ä¸ï¼å¯ä»¥æå¨æ§è¡ï¼ |
| | | |
| | | 1. **ç»è®¡æ¨æ¥æ°æ®**ï¼ |
| | | ``` |
| | | vehicleMileageStatsTask.calculateYesterdayMileage |
| | | ``` |
| | | |
| | | 2. **ç»è®¡æå®æ¥æ**ï¼ |
| | | ``` |
| | | vehicleMileageStatsTask.calculateMileageByDate('2025-11-09') |
| | | ``` |
| | | |
| | | ## äºãæ°æ®è¡¨ç»æ |
| | | |
| | | ### tb_vehicle_mileage_stats |
| | | | åæ®µå | ç±»å | 说æ | |
| | | |--------|------|------| |
| | | | stats_id | bigint(20) | ç»è®¡IDï¼ä¸»é® | |
| | | | vehicle_id | bigint(20) | 车è¾ID | |
| | | | vehicle_no | varchar(20) | 车çå· | |
| | | | stat_date | date | ç»è®¡æ¥æ | |
| | | | total_mileage | decimal(10,2) | æ»éç¨ï¼å
¬éï¼ | |
| | | | task_mileage | decimal(10,2) | 任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | non_task_mileage | decimal(10,2) | é任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | task_ratio | decimal(5,4) | ä»»å¡éç¨å æ¯ï¼0-1ï¼ | |
| | | | gps_point_count | int(11) | GPSç¹æ°é | |
| | | | task_count | int(11) | 任塿°é | |
| | | | create_time | datetime | å建æ¶é´ | |
| | | | update_time | datetime | æ´æ°æ¶é´ | |
| | | |
| | | **ç´¢å¼ï¼** |
| | | - PRIMARY KEY: stats_id |
| | | - UNIQUE KEY: uk_vehicle_date (vehicle_id, stat_date) |
| | | - KEY: idx_vehicle_id (vehicle_id) |
| | | - KEY: idx_stat_date (stat_date) |
| | | |
| | | ### tb_vehicle_mileage_detailï¼å¯éï¼ |
| | | ç¨äºåå¨éç¨è®¡ç®æç»ï¼æ¹ä¾¿è°è¯å追溯ã |
| | | |
| | | ## å
ãé¨ç½²æ¥éª¤ |
| | | |
| | | ### 1. æ§è¡æ°æ®åºèæ¬ï¼æé¡ºåºï¼ |
| | | ```bash |
| | | 1. sql/vehicle_mileage_stats.sql |
| | | 2. sql/vehicle_mileage_stats_job.sql |
| | | 3. sql/vehicle_mileage_stats_menu.sql |
| | | ``` |
| | | |
| | | ### 2. éå¯åºç¨ |
| | | ä»£ç æä»¶å·²èªå¨å建ï¼éå¯åºç¨å³å¯çæã |
| | | |
| | | ### 3. éªè¯é¨ç½² |
| | | 1. ç»å½ç³»ç»ï¼æ£æ¥è忝妿¾ç¤º"车è¾éç¨ç»è®¡" |
| | | 2. è¿å
¥ç³»ç»ç®¡ç -> 宿¶ä»»å¡ï¼æ£æ¥æ¯å¦æ"车è¾éç¨ç»è®¡ä»»å¡" |
| | | 3. æå¨æ§è¡å®æ¶ä»»å¡æè°ç¨APIæ¥å£æµè¯åè½ |
| | | |
| | | ## ä¸ã使ç¨ç¤ºä¾ |
| | | |
| | | ### 示ä¾1ï¼æå¨è®¡ç®æè½¦è¾æ¨æ¥éç¨ |
| | | ```javascript |
| | | import { calculateMileage } from '@/api/mileageStats' |
| | | |
| | | calculateMileage(1001, '2025-11-09').then(response => { |
| | | console.log('ç»è®¡ç»æï¼', response.data) |
| | | // è¾åºç¤ºä¾ï¼ |
| | | // { |
| | | // vehicleNo: '粤A12345', |
| | | // statDate: '2025-11-09', |
| | | // totalMileage: 285.67, |
| | | // taskMileage: 198.43, |
| | | // nonTaskMileage: 87.24, |
| | | // taskRatio: 0.6948, |
| | | // gpsPointCount: 1205, |
| | | // taskCount: 8 |
| | | // } |
| | | }) |
| | | ``` |
| | | |
| | | ### 示ä¾2ï¼æ¹éè®¡ç®ææè½¦è¾æå®æ¥æéç¨ |
| | | ```javascript |
| | | import { batchCalculateMileage } from '@/api/mileageStats' |
| | | |
| | | batchCalculateMileage('2025-11-09').then(response => { |
| | | console.log(response.msg) // è¾åºï¼æ¹ééç¨ç»è®¡å®æï¼æåç»è®¡ 45 è¾è½¦ |
| | | }) |
| | | ``` |
| | | |
| | | ### 示ä¾3ï¼æ¥è¯¢è½¦è¾éç¨ç»è®¡æ¥è¡¨ |
| | | ```javascript |
| | | import { listMileageStats } from '@/api/mileageStats' |
| | | |
| | | const query = { |
| | | vehicleNo: '粤A12345', |
| | | beginStatDate: '2025-11-01', |
| | | endStatDate: '2025-11-09', |
| | | pageNum: 1, |
| | | pageSize: 10 |
| | | } |
| | | |
| | | listMileageStats(query).then(response => { |
| | | console.log('ç»è®¡å表ï¼', response.rows) |
| | | }) |
| | | ``` |
| | | |
| | | ## å
«ã注æäºé¡¹ |
| | | |
| | | ### 1. GPSæ°æ®è¦æ± |
| | | - GPSééé´éï¼å»ºè®®30-60ç§ |
| | | - æ°æ®å段å¿
å¡«ï¼vehicle_id, longitude, latitude, collect_time |
| | | - åæ ç³»ç»ï¼æ¯æWGS84ãGCJ02ç常ç¨åæ ç³» |
| | | |
| | | ### 2. 任塿°æ®è¦æ± |
| | | - ä»»å¡è¡¨ï¼sys_task |
| | | - 车è¾ä»»å¡å
³è表ï¼sys_task_vehicle |
| | | - å¿
å¡«åæ®µï¼task_id, vehicle_id, create_time, actual_end_time |
| | | |
| | | ### 3. æ§è½ä¼å建议 |
| | | - 宿¶ä»»å¡é¿å¼ä¸å¡é«å³°æï¼å»ºè®®åæ¨æ§è¡ï¼ |
| | | - GPSåå§æ°æ®å®ææ¸
çï¼å»ºè®®ä¿ç7-30å¤©ï¼ |
| | | - ç»è®¡æ°æ®å®æå½æ¡£ï¼å»ºè®®ä¿ç3-6个æï¼ |
| | | |
| | | ### 4. æ°æ®åç¡®æ§ |
| | | - éç¨è®¡ç®åºäºGPS轨迹ï¼ç²¾åº¦åGPSä¿¡å·è´¨éå½±å |
| | | - Haversineå
¬å¼è®¡ç®çæ¯ç´çº¿è·ç¦»ï¼å®é
éè·¯è·ç¦»å¯è½æ´é¿ |
| | | - å¯ç»å天å°å¾è·¯å¾è§åAPIè·åæ´åç¡®çéè·¯è·ç¦» |
| | | |
| | | ## ä¹ãæ©å±åè½å»ºè®® |
| | | |
| | | ### 1. éæå¤©å°å¾è·¯å¾è·ç¦»ï¼æ´åç¡®ï¼ |
| | | å½å使ç¨Haversineå
¬å¼è®¡ç®ç´çº¿è·ç¦»ï¼å¯åçº§ä¸ºï¼ |
| | | - å°GPS轨迹ç¹åéå°å¤©å°å¾è·¯å¾è§åAPI |
| | | - è·åå®é
éè·¯è·ç¦» |
| | | - æé«éç¨ç»è®¡ç²¾åº¦ |
| | | |
| | | ### 2. 宿¶éç¨ç»è®¡ |
| | | - å¨GPSæ°æ®å
¥åºæ¶å®æ¶è®¡ç® |
| | | - 使ç¨Redisç¼å彿¥ç´¯è®¡éç¨ |
| | | - 忍宿¶ä»»å¡ä»
åæ°æ®åºå |
| | | |
| | | ### 3. éç¨å¼å¸¸åè¦ |
| | | - 忥éç¨è¶
è¿éå¼åè¦ |
| | | - é¿æ¶é´æ GPSæ°æ®åè¦ |
| | | - éç¨çªåå¼å¸¸åè¦ |
| | | |
| | | ### 4. æ°æ®å¯è§å |
| | | - æ¯æ¥éç¨è¶å¿å¾ |
| | | - ä»»å¡éç¨å æ¯é¥¼å¾ |
| | | - 车è¾éç¨æåæ¦ |
| | | |
| | | ## åãæ
éææ¥ |
| | | |
| | | ### é®é¢1ï¼å®æ¶ä»»å¡æªæ§è¡ |
| | | - æ£æ¥å®æ¶ä»»å¡ç¶ææ¯å¦ä¸º"å¯ç¨" |
| | | - æ£æ¥Cronè¡¨è¾¾å¼æ¯å¦æ£ç¡® |
| | | - æ¥ç宿¶ä»»å¡æ¥å¿ |
| | | |
| | | ### é®é¢2ï¼ç»è®¡ç»æä¸º0 |
| | | - æ£æ¥GPSæ°æ®æ¯å¦åå¨ |
| | | - æ£æ¥GPSæ°æ®çcollect_timeåæ®µæ¯å¦æ£ç¡® |
| | | - æ£æ¥ä»»å¡æ°æ®æ¯å¦åå¨ |
| | | |
| | | ### é®é¢3ï¼éç¨æ°æ®å¼å¸¸ |
| | | - æ£æ¥GPSåæ æ¯å¦åæ³ï¼ç»çº¬åº¦èå´ï¼ |
| | | - æ£æ¥æ¯å¦åå¨GPSæ¼ç§»ç¹ |
| | | - å¯ç¨æç»è¡¨åææ¯æ®µè·ç¦» |
| | | |
| | | ### æ¥çæ¥å¿ |
| | | ```bash |
| | | # Service屿¥å¿ |
| | | grep "VehicleMileageStatsServiceImpl" logs/ruoyi-*.log |
| | | |
| | | # 宿¶ä»»å¡æ¥å¿ |
| | | grep "VehicleMileageStatsTask" logs/ruoyi-*.log |
| | | ``` |
| | | |
| | | ## åä¸ãæ»ç» |
| | | |
| | | â
æ¬åè½å·²å®æ´å®ç°è½¦è¾GPSéç¨ç»è®¡çææéæ±ï¼ |
| | | - â
æ¯æ¥èªå¨ç»è®¡è½¦è¾è¡é©¶éç¨ |
| | | - â
åºå任塿¶æ®µåé任塿¶æ®µéç¨ |
| | | - â
计ç®ä»»å¡éç¨å æ¯ |
| | | - â
ç»è®¡æ°æ®ç¼åå°æ°æ®åºè¡¨ |
| | | - â
æ¯ææå¨è§¦ååæ¹éè®¡ç® |
| | | - â
æä¾å®æ´çæ¥è¯¢å导åºåè½ |
| | | - â
éæå®æ¶ä»»å¡èªå¨åæ§è¡ |
| | | |
| | | æ ¸å¿ç®æ³éç¨Haversineå
¬å¼è®¡ç®GPSç¹é´è·ç¦»ï¼ææ¶é´éå æ¯ä¾åæéç¨å°ä»»å¡åé任塿¶æ®µï¼ç¡®ä¿ç»è®¡åç¡®æ§ãæææ°æ®ç¼åå¨ä¸ç¨ç»è®¡è¡¨ä¸ï¼æ¯æé«ææ¥è¯¢ååæã |