| New file |
| | |
| | | # GPSåæ®µéç¨è®¡ç®ä»»å¡è¶
æ¶é®é¢ä¿®å¤è¯´æ |
| | | |
| | | ## é®é¢æè¿° |
| | | |
| | | GPSåæ®µéç¨è®¡ç®å®æ¶ä»»å¡æ§è¡æ¶åºç°æ°æ®åºè¿æ¥è¶
æ¶éè¯¯ï¼ |
| | | |
| | | ``` |
| | | ERROR c.r.q.t.VehicleGpsSegmentMileageTask - GPSåæ®µéç¨è®¡ç®ä»»å¡æ§è¡å¤±è´¥ |
| | | java.lang.RuntimeException: æ¹é计ç®å¤±è´¥: |
| | | ### Error querying database. Cause: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure |
| | | The last packet successfully received from the server was 60,022 milliseconds ago. |
| | | ``` |
| | | |
| | | ## é®é¢åå |
| | | |
| | | 1. **æ°æ®åºSocketè¶
æ¶é
ç½®è¿ç**ï¼`socketTimeout: 60000`ï¼60ç§ï¼ï¼å¯¹äºå¤§æ°æ®éGPSæ¥è¯¢å¤çä¸è¶³ |
| | | 2. **æ¥è¯¢æ§è½ä¸ä½³**ï¼ç¼ºå°å¿
è¦çæ°æ®åºç´¢å¼ï¼å¯¼è´å¤§è¡¨æ«æèæ¶è¿é¿ |
| | | 3. **é误å¤çä¸å®å**ï¼å个车è¾è®¡ç®å¤±è´¥ä¼å½±åæ´ä¸ªæ¹å¤çæµç¨ |
| | | 4. **缺å°è¿åº¦æ¥å¿**ï¼æ æ³äºè§£æ¹éå¤çç宿¶è¿åº¦ |
| | | |
| | | ## è§£å³æ¹æ¡ |
| | | |
| | | ### 1. å¢å æ°æ®åºè¿æ¥è¶
æ¶æ¶é´ |
| | | |
| | | **ä¿®æ¹æä»¶**ï¼ |
| | | - `ruoyi-admin/src/main/resources/application-dev.yml` |
| | | - `ruoyi-admin/src/main/resources/application-test.yml` |
| | | - `ruoyi-admin/src/main/resources/application-prod.yml` |
| | | |
| | | **ä¿®æ¹å
容**ï¼ |
| | | ```yaml |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ï¼ä»60ç§å¢å å°5åéï¼ |
| | | socketTimeout: 300000 |
| | | ``` |
| | | |
| | | **åå **ï¼GPSåæ®µéç¨è®¡ç®éè¦å¤ç大鿰æ®ï¼60ç§çè¶
æ¶æ¶é´ä¸è¶³ä»¥å®ææ¥è¯¢æä½ãå¢å å°5åéï¼300ç§ï¼å¯ä»¥é¿å
æ£å¸¸æ¥è¯¢è¢«è¯¯å¤ä¸ºè¶
æ¶ã |
| | | |
| | | ### 2. ä¼åæ°æ®åºç´¢å¼ |
| | | |
| | | **æ§è¡SQLæä»¶**ï¼`sql/optimize_gps_query_performance.sql` |
| | | |
| | | **å
³é®ç´¢å¼**ï¼ |
| | | ```sql |
| | | -- ç»åç´¢å¼ï¼vehicle_id + collect_time |
| | | ALTER TABLE tb_vehicle_gps |
| | | ADD INDEX idx_vehicle_collect_time (vehicle_id, collect_time); |
| | | |
| | | -- ååç´¢å¼ï¼collect_time |
| | | ALTER TABLE tb_vehicle_gps |
| | | ADD INDEX idx_collect_time (collect_time); |
| | | |
| | | -- tb_vehicle_gps_calculatedè¡¨ç´¢å¼ |
| | | ALTER TABLE tb_vehicle_gps_calculated |
| | | ADD INDEX idx_gps_id (gps_id); |
| | | ADD INDEX idx_vehicle_id (vehicle_id); |
| | | ``` |
| | | |
| | | **ææ**ï¼ |
| | | - 大å¹
æåæè½¦è¾IDåæ¶é´èå´æ¥è¯¢çæ§è½ |
| | | - ä¼åæ´»è·è½¦è¾æ¥è¯¢é度 |
| | | - æ¹åLEFT JOINæ¥è¯¢æ§è½ |
| | | |
| | | ### 3. å¢å¼ºæ¹å¤çé误å¤ç |
| | | |
| | | **ä¿®æ¹æä»¶**ï¼`VehicleGpsSegmentMileageServiceImpl.java` |
| | | |
| | | **æ¹è¿ç¹**ï¼ |
| | | 1. **å车失败ä¸å½±åå
¨å±**ï¼å个车è¾è®¡ç®å¤±è´¥ä¸ä¼ä¸ææ´ä¸ªæ¹å¤ç |
| | | 2. **详ç»çè¿åº¦æ¥å¿**ï¼æ¯å¤ç10è¾è½¦è¾åºä¸æ¬¡è¿åº¦ |
| | | 3. **æå/失败ç»è®¡**ï¼è®°å½æåå失败çè½¦è¾æ°é |
| | | 4. **æ´è¯¦ç»çé误信æ¯**ï¼å
å«å æ è·è¸ªï¼ä¾¿äºé®é¢å®ä½ |
| | | |
| | | **ä»£ç æ¹è¿**ï¼ |
| | | ```java |
| | | int successCount = 0; |
| | | int failedCount = 0; |
| | | |
| | | for (int i = 0; i < vehicleIds.size(); i++) { |
| | | try { |
| | | // å¤çåä¸ªè½¦è¾ |
| | | int segmentCount = calculateVehicleSegmentMileage(vehicleId, startTime, endTime); |
| | | if (segmentCount > 0) { |
| | | successCount++; |
| | | } |
| | | } catch (Exception e) { |
| | | failedCount++; |
| | | logger.error("计ç®è½¦è¾å¤±è´¥ï¼ä½ç»§ç»å¤çä¸ä¸è¾", e); |
| | | // ä¸ä¸ææ¹å¤ç |
| | | } |
| | | |
| | | // è¿åº¦æ¥å¿ |
| | | if ((i + 1) % 10 == 0) { |
| | | logger.info("è¿åº¦: {}/{}, æå: {}, 失败: {}", ...); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## é¨ç½²æ¥éª¤ |
| | | |
| | | ### 1. æ°æ®åºä¼åï¼å¿
é¡»ï¼ |
| | | |
| | | ```bash |
| | | # è¿æ¥å°MySQLæ°æ®åº |
| | | mysql -u root -p |
| | | |
| | | # æ§è¡ç´¢å¼ä¼åSQL |
| | | source sql/optimize_gps_query_performance.sql |
| | | |
| | | # éªè¯ç´¢å¼å建æå |
| | | SHOW INDEX FROM tb_vehicle_gps; |
| | | SHOW INDEX FROM tb_vehicle_gps_calculated; |
| | | ``` |
| | | |
| | | ### 2. åºç¨é
ç½®æ´æ°ï¼å¿
é¡»ï¼ |
| | | |
| | | 1. å¤ä»½å½åé
ç½®æä»¶ |
| | | 2. æ´æ°é
ç½®æä»¶ä¸ç`socketTimeout`åæ° |
| | | 3. éå¯åºç¨æå¡ |
| | | |
| | | ```bash |
| | | # 忢æå¡ |
| | | ./ry.sh stop |
| | | |
| | | # å¯å¨æå¡ |
| | | ./ry.sh start |
| | | |
| | | # æ¥çæ¥å¿ |
| | | tail -f logs/sys-info.log |
| | | ``` |
| | | |
| | | ### 3. éªè¯ä¿®å¤ææ |
| | | |
| | | 1. **æå¨è§¦å宿¶ä»»å¡**ï¼ |
| | | - ç»å½åå°ç®¡çç³»ç» |
| | | - è¿å
¥ãç³»ç»çæ§ã->ã宿¶ä»»å¡ã |
| | | - æ¾å°"GPSåæ®µéç¨å®æ¶è®¡ç®"ä»»å¡ |
| | | - ç¹å»ãæ§è¡ä¸æ¬¡ãæé® |
| | | |
| | | 2. **æ¥çæ§è¡æ¥å¿**ï¼ |
| | | ```bash |
| | | # æ¥çGPSè®¡ç®æ¥å¿ |
| | | grep "VehicleGpsSegmentMileageTask" logs/sys-info.log |
| | | |
| | | # æ¥çæå/失败ç»è®¡ |
| | | grep "æ¹éåæ®µéç¨è®¡ç®å®æ" logs/sys-info.log |
| | | ``` |
| | | |
| | | 3. **æ£æ¥æ°æ®åº**ï¼ |
| | | ```sql |
| | | -- æ¥çææ°çåæ®µéç¨è®°å½ |
| | | SELECT * FROM tb_vehicle_gps_segment_mileage |
| | | ORDER BY create_time DESC |
| | | LIMIT 10; |
| | | |
| | | -- ç»è®¡ä»æ¥å¤ççè½¦è¾æ° |
| | | SELECT COUNT(DISTINCT vehicle_id) as vehicle_count |
| | | FROM tb_vehicle_gps_segment_mileage |
| | | WHERE DATE(create_time) = CURDATE(); |
| | | ``` |
| | | |
| | | ## æ§è½çæ§å»ºè®® |
| | | |
| | | ### 1. 宿¶ä»»å¡æ§è¡æ¶é´çæ§ |
| | | |
| | | å¨å®æ¶ä»»å¡ç®¡ç䏿¥çæ§è¡æ¶é¿ï¼ |
| | | - æ£å¸¸æ
åµï¼æ¯5åéæ§è¡ä¸æ¬¡ï¼å¤ç10åéæ°æ®ï¼åºå¨1-2åéå
宿 |
| | | - å¼å¸¸æ
åµï¼è¶
è¿3åééè¦å
³æ³¨ï¼å¯è½å卿§è½é®é¢ |
| | | |
| | | ### 2. æ°æ®åºæ
¢æ¥è¯¢æ¥å¿ |
| | | |
| | | æ£æ¥MySQLæ
¢æ¥è¯¢æ¥å¿ï¼ |
| | | ```sql |
| | | -- æ¥çæ
¢æ¥è¯¢é
ç½® |
| | | SHOW VARIABLES LIKE 'slow_query%'; |
| | | SHOW VARIABLES LIKE 'long_query_time'; |
| | | |
| | | -- å¯ç¨æ
¢æ¥è¯¢æ¥å¿ï¼å¦ææªå¯ç¨ï¼ |
| | | SET GLOBAL slow_query_log = 'ON'; |
| | | SET GLOBAL long_query_time = 2; |
| | | ``` |
| | | |
| | | ### 3. Druidçæ§ |
| | | |
| | | 访é®Druidçæ§é¡µé¢ï¼`http://your-domain/druid/` |
| | | - ç¨æ·åï¼ruoyi |
| | | - å¯ç ï¼123456 |
| | | |
| | | å
³æ³¨ææ ï¼ |
| | | - SQLæ§è¡æ¶é´ |
| | | - è¿æ¥æ± ä½¿ç¨æ
åµ |
| | | - æ
¢SQLå表 |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | ### 1. 宿æ¸
çå岿°æ® |
| | | |
| | | GPSæ°æ®é大ï¼å»ºè®®å®ææ¸
çå岿°æ®ï¼ |
| | | |
| | | ```sql |
| | | -- ä¿çæè¿90天çGPSåå§æ°æ® |
| | | DELETE FROM tb_vehicle_gps |
| | | WHERE collect_time < DATE_SUB(NOW(), INTERVAL 90 DAY); |
| | | |
| | | -- ä¼åè¡¨ç©ºé´ |
| | | OPTIMIZE TABLE tb_vehicle_gps; |
| | | ``` |
| | | |
| | | å¯ä»¥åå»ºå®æ¶ä»»å¡æ¯ææ§è¡ä¸æ¬¡ã |
| | | |
| | | ### 2. åæ¹å¤ç大éè½¦è¾ |
| | | |
| | | å¦æè½¦è¾æ°éè¶
è¿1000è¾ï¼å»ºè®®ä¿®æ¹æ¹å¤çé»è¾ï¼åæ¹å¤çï¼ |
| | | |
| | | ```java |
| | | // æ¯æ¹å¤ç100è¾è½¦è¾ |
| | | int batchSize = 100; |
| | | for (int i = 0; i < vehicleIds.size(); i += batchSize) { |
| | | List<Long> batchIds = vehicleIds.subList(i, |
| | | Math.min(i + batchSize, vehicleIds.size())); |
| | | processBatch(batchIds); |
| | | } |
| | | ``` |
| | | |
| | | ### 3. 使ç¨å¼æ¥å¤ç |
| | | |
| | | 对äºç¹å«èæ¶çæä½ï¼å¯ä»¥èè使ç¨å¼æ¥å¤çï¼ |
| | | |
| | | ```java |
| | | @Async |
| | | public CompletableFuture<Integer> calculateVehicleAsync(Long vehicleId) { |
| | | // 弿¥è®¡ç® |
| | | } |
| | | ``` |
| | | |
| | | ### 4. å¢å ç¼åæºå¶ |
| | | |
| | | 对äºé¢ç¹æ¥è¯¢ç车è¾ä¿¡æ¯ï¼å¯ä»¥ä½¿ç¨Redisç¼åï¼ |
| | | |
| | | ```java |
| | | @Cacheable(value = "vehicleInfo", key = "#vehicleId") |
| | | public VehicleInfo getVehicleInfo(Long vehicleId) { |
| | | return vehicleInfoMapper.selectVehicleInfoById(vehicleId); |
| | | } |
| | | ``` |
| | | |
| | | ## ç¸å
³æä»¶æ¸
å |
| | | |
| | | ### ä¿®æ¹çæä»¶ |
| | | 1. `ruoyi-admin/src/main/resources/application-dev.yml` - å¼åç¯å¢é
ç½® |
| | | 2. `ruoyi-admin/src/main/resources/application-test.yml` - æµè¯ç¯å¢é
ç½® |
| | | 3. `ruoyi-admin/src/main/resources/application-prod.yml` - ç产ç¯å¢é
ç½® |
| | | 4. `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsSegmentMileageServiceImpl.java` - æ¹å¤çé»è¾ä¼å |
| | | 5. `ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml` - æ·»å SQL注é |
| | | |
| | | ### æ°å¢çæä»¶ |
| | | 1. `sql/optimize_gps_query_performance.sql` - æ°æ®åºæ§è½ä¼åSQL |
| | | |
| | | ## æ
éææ¥ |
| | | |
| | | ### é®é¢1ï¼æ§è¡SQLæ¶æ¥é"ç´¢å¼å·²åå¨" |
| | | |
| | | **è§£å³æ¹æ¡**ï¼ |
| | | ```sql |
| | | -- å é¤å·²åå¨çç´¢å¼ |
| | | DROP INDEX idx_vehicle_collect_time ON tb_vehicle_gps; |
| | | DROP INDEX idx_collect_time ON tb_vehicle_gps; |
| | | |
| | | -- éæ°åå»ºç´¢å¼ |
| | | -- ç¶åæ§è¡optimize_gps_query_performance.sql |
| | | ``` |
| | | |
| | | ### é®é¢2ï¼ä¿®æ¹é
ç½®åä»ç¶è¶
æ¶ |
| | | |
| | | **æ£æ¥æ¥éª¤**ï¼ |
| | | 1. 确认é
ç½®æä»¶ä¿®æ¹çæï¼æ£æ¥å½åæ¿æ´»çprofileï¼dev/test/prodï¼ |
| | | 2. 确认åºç¨å·²éå¯ï¼`ps -ef | grep java` |
| | | 3. æ¥çDruidè¿æ¥æ± é
ç½®ï¼è®¿é® `/druid/` æ£æ¥socketTimeoutå¼ |
| | | 4. æ£æ¥æ°æ®åºæå¡å¨é
ç½®ï¼`SHOW VARIABLES LIKE 'wait_timeout';` |
| | | |
| | | ### é®é¢3ï¼ç´¢å¼åå»ºåæ§è½æªæ¹å |
| | | |
| | | **æ£æ¥æ¥éª¤**ï¼ |
| | | ```sql |
| | | -- 1. éªè¯ç´¢å¼æ¯å¦è¢«ä½¿ç¨ |
| | | EXPLAIN SELECT DISTINCT vehicle_id |
| | | FROM tb_vehicle_gps |
| | | WHERE collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY); |
| | | |
| | | -- 2. æ´æ°è¡¨ç»è®¡ä¿¡æ¯ |
| | | ANALYZE TABLE tb_vehicle_gps; |
| | | |
| | | -- 3. æ£æ¥è¡¨æ°æ®é |
| | | SELECT COUNT(*) FROM tb_vehicle_gps; |
| | | ``` |
| | | |
| | | ## æ»ç» |
| | | |
| | | æ¬æ¬¡ä¿®å¤ä¸»è¦è§£å³äºGPSåæ®µéç¨è®¡ç®ä»»å¡çè¶
æ¶é®é¢ï¼éè¿ä»¥ä¸æªæ½ï¼ |
| | | |
| | | 1. â
å¢å æ°æ®åºè¿æ¥è¶
æ¶æ¶é´ï¼60ç§ -> 300ç§ï¼ |
| | | 2. â
æ·»å æ°æ®åºç´¢å¼ä¼åæ¥è¯¢æ§è½ |
| | | 3. â
æ¹è¿æ¹å¤çé误å¤çæºå¶ |
| | | 4. â
å¢å¼ºæ¥å¿è¾åºï¼ä¾¿äºçæ§åé®é¢å®ä½ |
| | | |
| | | **颿ææ**ï¼ |
| | | - 任塿§è¡ä¸åè¶
æ¶ |
| | | - æ¥è¯¢æ§è½æå50%ä»¥ä¸ |
| | | - å个车è¾å¤±è´¥ä¸å½±åæ´ä½å¤ç |
| | | - 宿¶äºè§£å¤çè¿åº¦ |
| | | |
| | | **注æäºé¡¹**ï¼ |
| | | - å¿
é¡»æ§è¡æ°æ®åºç´¢å¼ä¼åSQL |
| | | - å¿
é¡»éå¯åºç¨ä½¿é
ç½®çæ |
| | | - å»ºè®®å®ææ¸
çåå²GPSæ°æ® |
| | | - æç»çæ§ä»»å¡æ§è¡æ
åµ |
| | |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/address/search', |
| | | // url: '/system/gps/address/search', |
| | | url: '/system/gps/tianditu/place/suggestion', |
| | | method: 'get', |
| | | params: { |
| | | keyword: keyword, |
| | |
| | | if (isNaN(lat) || isNaN(lng)) { |
| | | return Promise.reject(new Error('åæ°æ æï¼ç»çº¬åº¦åæ æ ¼å¼é误')) |
| | | } |
| | | |
| | | /** |
| | | * è¿éç¨å°å¤©å°å¾ |
| | | */ |
| | | return request({ |
| | | url: '/system/gps/address/geocoder', |
| | | // url: '/system/gps/address/geocoder', |
| | | url: '/system/gps/tianditu/reverseGeocoding', |
| | | method: 'get', |
| | | params: { |
| | | lat: lat, |
| | |
| | | }) |
| | | } |
| | | |
| | | export function calculateTianDiTuDistance(fromAddress, toAddress) { |
| | | // åæ°éªè¯ |
| | | if (!fromAddress || !toAddress) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´ï¼ç¼ºå°å°å')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/distance/byAddress', |
| | | method: 'get', |
| | | params: { |
| | | fromAddress: fromAddress, |
| | | toAddress: toAddress |
| | | } |
| | | }) |
| | | } |
| | | // å°å¾è·¯çº¿è§åAPIï¼è®¡ç®ä¸¤ç¹é´è·ç¦»ï¼ |
| | | export function calculateDistance(fromLat, fromLng, toLat, toLng) { |
| | | // åæ°éªè¯ |
| | |
| | | |
| | | return request({ |
| | | url: '/system/gps/route/distance', |
| | | // url: '/system/gps/tianditu/byAddress', |
| | | method: 'get', |
| | | params: { |
| | | fromLat: fromLat, |
| | |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // è·å微信é
ç½®ï¼å
æ¬è®¢é
æ¶æ¯æ¨¡æ¿IDçï¼ |
| | | export function getWechatConfig() { |
| | | return request({ |
| | | url: '/wechat/config', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | <view class="user-info-content"> |
| | | <view class="user-details"> |
| | | <view class="user-info-row"> |
| | | <text class="user-name">{{ userName || 'æªç»å½' }}</text> |
| | | <text class="separator" v-if="currentUser.branchCompanyName">|</text> |
| | | <text class="user-name">{{ userName || "æªç»å½" }}</text> |
| | | <text class="separator" v-if="currentUser.branchCompanyName" |
| | | >|</text |
| | | > |
| | | <view class="branch-company" v-if="currentUser.branchCompanyName"> |
| | | <uni-icons type="location" size="16" color="#666" style="margin-right: 4rpx;"></uni-icons> |
| | | <uni-icons |
| | | type="location" |
| | | size="16" |
| | | color="#666" |
| | | style="margin-right: 4rpx" |
| | | ></uni-icons> |
| | | <text>{{ currentUser.branchCompanyName }}</text> |
| | | </view> |
| | | <text class="separator" v-if="boundVehicle">|</text> |
| | | <view class="vehicle-info" @click.stop="goToBindVehicle" v-if="boundVehicle"> |
| | | <view |
| | | class="vehicle-info" |
| | | @click.stop="goToBindVehicle" |
| | | v-if="boundVehicle" |
| | | > |
| | | <text>{{ boundVehicle }}</text> |
| | | <uni-icons |
| | | type="loop" |
| | | size="16" |
| | | <uni-icons |
| | | type="loop" |
| | | size="16" |
| | | color="#007AFF" |
| | | style="margin-left: 4rpx;" |
| | | style="margin-left: 4rpx" |
| | | ></uni-icons> |
| | | </view> |
| | | </view> |
| | | <view class="bind-vehicle-btn" v-if="!boundVehicle" @click="goToBindVehicle"> |
| | | <uni-icons type="plus-filled" size="16" color="#007AFF" style="margin-right: 4rpx;"></uni-icons> |
| | | <view |
| | | class="bind-vehicle-btn" |
| | | v-if="!boundVehicle" |
| | | @click="goToBindVehicle" |
| | | > |
| | | <uni-icons |
| | | type="plus-filled" |
| | | size="16" |
| | | color="#007AFF" |
| | | style="margin-right: 4rpx" |
| | | ></uni-icons> |
| | | <text>ç»å®è½¦ç</text> |
| | | </view> |
| | | </view> |
| | |
| | | <uni-icons type="chat" size="24" color="#007AFF"></uni-icons> |
| | | </view> |
| | | <view class="message-text">æ¶æ¯ä¸å¿</view> |
| | | <view class="unread-dot" v-if="unreadMessageCount > 0">{{ unreadMessageCount }}</view> |
| | | <view class="unread-dot" v-if="unreadMessageCount > 0">{{ |
| | | unreadMessageCount |
| | | }}</view> |
| | | <view class="arrow"> |
| | | <uni-icons type="arrowright" size="16" color="#999"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 订é
éç¥æç¤ºå¡çï¼æªè®¢é
æ¶æ¾ç¤ºï¼ --> |
| | | <view |
| | | class="subscribe-banner" |
| | | v-if="!hasSubscribed" |
| | | @click="clickConfirmsubscribeTaskNotify" |
| | | > |
| | | <view class="banner-icon"> |
| | | <uni-icons type="bell" size="28" color="#ff9500"></uni-icons> |
| | | </view> |
| | | <view class="banner-content"> |
| | | <view class="banner-title">å¼å¯ä»»å¡éç¥</view> |
| | | <view class="banner-desc">åæ¶æ¥æ¶ä»»å¡åé
åç¶ææ´æ°æé</view> |
| | | </view> |
| | | <view class="banner-action"> |
| | | <text>ç«å³å¼å¯</text> |
| | | <uni-icons type="arrowright" size="16" color="#007AFF"></uni-icons> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | <view class="task-main" @click="viewTaskDetail(task)"> |
| | | <!-- ä»»å¡å¤´é¨ï¼æ é¢åç¶ææ ç¾ --> |
| | | <view class="task-header"> |
| | | <view class="task-title">{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view> |
| | | <view class="task-status" :class="task.taskStatus === 'PENDING' ? 'status-pending' : task.taskStatus === 'DEPARTING' ? 'status-departing' : task.taskStatus === 'ARRIVED' ? 'status-arrived' : task.taskStatus === 'RETURNING' ? 'status-returning' : task.taskStatus === 'COMPLETED' ? 'status-completed' : task.taskStatus === 'CANCELLED' ? 'status-cancelled' : task.taskStatus === 'IN_PROGRESS' ? 'status-in-progress' : 'status-default'"> |
| | | <view class="task-title" |
| | | >{{ getTaskTypeText(task.type) }} - {{ task.vehicle }}</view |
| | | > |
| | | <view |
| | | class="task-status" |
| | | :class=" |
| | | task.taskStatus === 'PENDING' |
| | | ? 'status-pending' |
| | | : task.taskStatus === 'DEPARTING' |
| | | ? 'status-departing' |
| | | : task.taskStatus === 'ARRIVED' |
| | | ? 'status-arrived' |
| | | : task.taskStatus === 'RETURNING' |
| | | ? 'status-returning' |
| | | : task.taskStatus === 'COMPLETED' |
| | | ? 'status-completed' |
| | | : task.taskStatus === 'CANCELLED' |
| | | ? 'status-cancelled' |
| | | : task.taskStatus === 'IN_PROGRESS' |
| | | ? 'status-in-progress' |
| | | : 'status-default' |
| | | " |
| | | > |
| | | {{ getStatusText(task.status) }} |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <!-- ä»»å¡ç¼å·åç¬ä¸è¡ --> |
| | | <view class="task-code-row"> |
| | | <text class="task-code">{{ task.taskNo }}</text> |
| | | </view> |
| | | |
| | | |
| | | <!-- ä»»å¡è¯¦ç»ä¿¡æ¯ --> |
| | | <view class="task-info"> |
| | | <view class="info-row"> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <!-- æä½æé® --> |
| | | <view class="task-actions"> |
| | | <!-- å¾
å¤çç¶æ: æ¾ç¤ºåºåãåæ¶ --> |
| | | <template v-if="task.taskStatus === 'PENDING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction(task, 'depart')" |
| | | > |
| | | åºå |
| | | </button> |
| | | <button |
| | | class="action-btn cancel" |
| | | <button |
| | | class="action-btn cancel" |
| | | @click="handleTaskAction(task, 'cancel')" |
| | | > |
| | | åæ¶ |
| | | </button> |
| | | </template> |
| | | |
| | | |
| | | <!-- åºåä¸ç¶æ: æ¾ç¤ºå·²å°è¾¾ã强å¶ç»æ --> |
| | | <template v-else-if="task.taskStatus === 'DEPARTING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction(task, 'arrive')" |
| | | > |
| | | å·²å°è¾¾ |
| | | </button> |
| | | <button |
| | | class="action-btn cancel" |
| | | <button |
| | | class="action-btn cancel" |
| | | @click="handleTaskAction(task, 'forceCancel')" |
| | | > |
| | | 强å¶ç»æ |
| | | </button> |
| | | </template> |
| | | |
| | | |
| | | <!-- å·²å°è¾¾ç¶æ: æ¾ç¤ºå·²è¿ç¨ --> |
| | | <template v-else-if="task.taskStatus === 'ARRIVED'"> |
| | | <button |
| | | class="action-btn primary" |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction(task, 'return')" |
| | | > |
| | | å·²è¿ç¨ |
| | | </button> |
| | | </template> |
| | | |
| | | |
| | | <!-- è¿ç¨ä¸ç¶æ: æ¾ç¤ºå·²å®æ --> |
| | | <template v-else-if="task.taskStatus === 'RETURNING'"> |
| | | <button |
| | | class="action-btn primary" |
| | | <button |
| | | class="action-btn primary" |
| | | @click="handleTaskAction(task, 'complete')" |
| | | > |
| | | 已宿 |
| | | </button> |
| | | </template> |
| | | |
| | | |
| | | <!-- 已宿/已忶: 䏿¾ç¤ºæé® --> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <view class="no-data" v-if="runningTasks.length === 0"> |
| | | <uni-icons type="info" size="40" color="#ccc"></uni-icons> |
| | | <text>ææ æ£å¨è¿è¡çä»»å¡</text> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | import { getMyTasks, changeTaskStatus } from '@/api/task' |
| | | import { getUserProfile } from '@/api/system/user' |
| | | import { getUserBoundVehicle } from '@/api/vehicle' |
| | | import { getUnreadCount } from '@/api/message' |
| | | import { formatDateTime } from '@/utils/common' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | // ç¨æ·ç»å®ç车è¾ä¿¡æ¯ |
| | | boundVehicle: '', |
| | | boundVehicleId: null, |
| | | |
| | | // æ¶æ¯æ°æ® |
| | | messages: [], |
| | | unreadMessageCount: 0, |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡å表 |
| | | taskList: [], |
| | | loading: false |
| | | } |
| | | import { mapState } from "vuex"; |
| | | import { getMyTasks, changeTaskStatus } from "@/api/task"; |
| | | import { getUserProfile } from "@/api/system/user"; |
| | | import { getUserBoundVehicle } from "@/api/vehicle"; |
| | | import { getUnreadCount } from "@/api/message"; |
| | | import { formatDateTime } from "@/utils/common"; |
| | | import subscribeManager from "@/utils/subscribe"; |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | // ç¨æ·ç»å®ç车è¾ä¿¡æ¯ |
| | | boundVehicle: "", |
| | | boundVehicleId: null, |
| | | |
| | | // æ¶æ¯æ°æ® |
| | | messages: [], |
| | | unreadMessageCount: 0, |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡å表 |
| | | taskList: [], |
| | | loading: false, |
| | | |
| | | // 订é
ç¶æ |
| | | hasSubscribed: true, |
| | | }; |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | userName: (state) => state.user.nickName, |
| | | currentUser: (state) => state.user, |
| | | }), |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡ï¼å¾
å¤çååç§å¤çä¸çä»»å¡ï¼ |
| | | runningTasks() { |
| | | return this.taskList.filter((task) => { |
| | | // å
å«å¾
å¤çãåºåä¸ãå·²å°è¾¾ãè¿ç¨ä¸çæææªå®æçç¶æ |
| | | return [ |
| | | "PENDING", |
| | | "DEPARTING", |
| | | "ARRIVED", |
| | | "RETURNING", |
| | | "IN_PROGRESS", |
| | | ].includes(task.taskStatus); |
| | | }); |
| | | }, |
| | | computed: { |
| | | ...mapState({ |
| | | userName: state => state.user.nickName, |
| | | currentUser: state => state.user |
| | | }), |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡ï¼å¾
å¤çååç§å¤çä¸çä»»å¡ï¼ |
| | | runningTasks() { |
| | | return this.taskList.filter(task => { |
| | | // å
å«å¾
å¤çãåºåä¸ãå·²å°è¾¾ãè¿ç¨ä¸çæææªå®æçç¶æ |
| | | return ['PENDING', 'DEPARTING', 'ARRIVED', 'RETURNING', 'IN_PROGRESS'].includes(task.taskStatus) |
| | | }, |
| | | onLoad() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.log("ç¨æ·æªç»å½ï¼è·³è¿å è½½æ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥è®¢é
ç¶æï¼å
æ£æ¥æ¬å°ï¼åé¢ä¼æ£æ¥å¾®ä¿¡å®æ¹ç¶æï¼ |
| | | this.hasSubscribed = subscribeManager.checkLocalSubscribeStatus(); |
| | | |
| | | // èªå¨è®¢é
ï¼å¦ææªè®¢é
åæ¾ç¤ºç¡®è®¤å¼¹çªï¼ |
| | | // this.autoSubscribeOnLaunch(); |
| | | |
| | | // å è½½ç¨æ·ç»å®è½¦è¾ä¿¡æ¯ |
| | | this.loadUserVehicle(); |
| | | // å è½½æ£å¨è¿è¡çä»»å¡ |
| | | this.loadRunningTasks(); |
| | | // å è½½æªè¯»æ¶æ¯æ°é |
| | | this.loadUnreadMessageCount(); |
| | | }, |
| | | onShow() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.log("ç¨æ·æªç»å½ï¼è·³è¿å è½½æ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | // æ¯æ¬¡æ¾ç¤ºé¡µé¢æ¶å·æ°ä»»å¡å表ãç»å®è½¦è¾åæ¶æ¯æ°é |
| | | this.loadUserVehicle(); |
| | | this.loadRunningTasks(); |
| | | this.loadUnreadMessageCount(); |
| | | }, |
| | | onPullDownRefresh() { |
| | | // 䏿巿° |
| | | this.loadRunningTasks(); |
| | | setTimeout(() => { |
| | | uni.stopPullDownRefresh(); |
| | | }, 1000); |
| | | }, |
| | | methods: { |
| | | // èªå¨è®¢é
ï¼å°ç¨åºå¯å¨æ¶è°ç¨ï¼ |
| | | autoSubscribeOnLaunch() { |
| | | subscribeManager.autoSubscribe() |
| | | .then((result) => { |
| | | if (result.skipped) { |
| | | console.log('ç¨æ·å·²è®¢é
ï¼æ ééå¤è®¢é
'); |
| | | this.hasSubscribed = true; |
| | | } else if (result.success) { |
| | | this.hasSubscribed = true; |
| | | console.log('èªå¨è®¢é
æå'); |
| | | } else { |
| | | // 订é
失败æè¢«æç»ï¼æ´æ°ç¶æ |
| | | this.hasSubscribed = false; |
| | | } |
| | | |
| | | // 妿è¿åäºç¶æä¿¡æ¯ï¼è¾åºè¯¦ç»ç¶æ |
| | | if (result.status) { |
| | | console.log('详ç»è®¢é
ç¶æï¼', result.status); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.log('èªå¨è®¢é
åæ¶æå¤±è´¥ï¼', error); |
| | | this.hasSubscribed = false; |
| | | }); |
| | | }, |
| | | |
| | | // å è½½ç¨æ·ç»å®ç车è¾ä¿¡æ¯ |
| | | loadUserVehicle() { |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.error("ç¨æ·æªç»å½ï¼æ æ³è·åç»å®è½¦è¾ä¿¡æ¯"); |
| | | this.boundVehicle = ""; |
| | | this.boundVehicleId = null; |
| | | return; |
| | | } |
| | | |
| | | getUserBoundVehicle(userId) |
| | | .then((response) => { |
| | | if (response.code === 200 && response.data) { |
| | | const vehicle = response.data; |
| | | this.boundVehicle = vehicle.vehicleNumber || "æªç¥è½¦ç"; |
| | | this.boundVehicleId = vehicle.vehicleId; |
| | | console.log("ç¨æ·ç»å®è½¦è¾:", this.boundVehicle); |
| | | } else { |
| | | this.boundVehicle = ""; |
| | | this.boundVehicleId = null; |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("è·åç»å®è½¦è¾ä¿¡æ¯å¤±è´¥:", error); |
| | | this.boundVehicle = ""; |
| | | this.boundVehicleId = null; |
| | | }); |
| | | }, |
| | | |
| | | // å è½½æªè¯»æ¶æ¯æ°é |
| | | loadUnreadMessageCount() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.log("ç¨æ·æªç»å½ï¼è·³è¿è·åæªè¯»æ¶æ¯æ°é"); |
| | | return; |
| | | } |
| | | |
| | | getUnreadCount() |
| | | .then((response) => { |
| | | if (response.code === 200) { |
| | | this.unreadMessageCount = response.data || 0; |
| | | // æ´æ°TabBarå¾½æ |
| | | this.updateTabBarBadge(this.unreadMessageCount); |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error("è·åæªè¯»æ¶æ¯æ°é失败:", error); |
| | | }); |
| | | }, |
| | | |
| | | // æ´æ°TabBarå¾½æ |
| | | updateTabBarBadge(count) { |
| | | if (count > 0) { |
| | | uni.setTabBarBadge({ |
| | | index: 3, // æ¶æ¯é¡µé¢å¨tabBarä¸çç´¢å¼ |
| | | text: count > 99 ? "99+" : count.toString(), |
| | | }); |
| | | } else { |
| | | uni.removeTabBarBadge({ |
| | | index: 3, |
| | | }); |
| | | } |
| | | }, |
| | | onLoad() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId |
| | | |
| | | // å è½½ç¨æ·ä¿¡æ¯ï¼ä¿ç以å
¼å®¹ä¹åç代ç ï¼ |
| | | loadUserProfile() { |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.log('ç¨æ·æªç»å½ï¼è·³è¿å è½½æ°æ®') |
| | | return |
| | | console.error("ç¨æ·æªç»å½ï¼æ æ³è·åç¨æ·ä¿¡æ¯"); |
| | | return; |
| | | } |
| | | |
| | | // å è½½ç¨æ·ç»å®è½¦è¾ä¿¡æ¯ |
| | | this.loadUserVehicle() |
| | | // å è½½æ£å¨è¿è¡çä»»å¡ |
| | | this.loadRunningTasks() |
| | | // å è½½æªè¯»æ¶æ¯æ°é |
| | | this.loadUnreadMessageCount() |
| | | }, |
| | | onShow() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId |
| | | if (!userId) { |
| | | console.log('ç¨æ·æªç»å½ï¼è·³è¿å è½½æ°æ®') |
| | | return |
| | | } |
| | | |
| | | // æ¯æ¬¡æ¾ç¤ºé¡µé¢æ¶å·æ°ä»»å¡å表ãç»å®è½¦è¾åæ¶æ¯æ°é |
| | | this.loadUserVehicle() |
| | | this.loadRunningTasks() |
| | | this.loadUnreadMessageCount() |
| | | }, |
| | | onPullDownRefresh() { |
| | | // 䏿巿° |
| | | this.loadRunningTasks() |
| | | setTimeout(() => { |
| | | uni.stopPullDownRefresh() |
| | | }, 1000) |
| | | }, |
| | | methods: { |
| | | // å è½½ç¨æ·ç»å®ç车è¾ä¿¡æ¯ |
| | | loadUserVehicle() { |
| | | const userId = this.currentUser.userId |
| | | if (!userId) { |
| | | console.error('ç¨æ·æªç»å½ï¼æ æ³è·åç»å®è½¦è¾ä¿¡æ¯') |
| | | this.boundVehicle = '' |
| | | this.boundVehicleId = null |
| | | return |
| | | } |
| | | |
| | | getUserBoundVehicle(userId).then(response => { |
| | | if (response.code === 200 && response.data) { |
| | | const vehicle = response.data |
| | | this.boundVehicle = vehicle.vehicleNumber || 'æªç¥è½¦ç' |
| | | this.boundVehicleId = vehicle.vehicleId |
| | | console.log('ç¨æ·ç»å®è½¦è¾:', this.boundVehicle) |
| | | } else { |
| | | this.boundVehicle = '' |
| | | this.boundVehicleId = null |
| | | } |
| | | }).catch(error => { |
| | | console.error('è·åç»å®è½¦è¾ä¿¡æ¯å¤±è´¥:', error) |
| | | this.boundVehicle = '' |
| | | this.boundVehicleId = null |
| | | }) |
| | | }, |
| | | |
| | | // å è½½æªè¯»æ¶æ¯æ°é |
| | | loadUnreadMessageCount() { |
| | | // æ£æ¥ç¨æ·æ¯å¦å·²ç»å½ |
| | | const userId = this.currentUser.userId |
| | | if (!userId) { |
| | | console.log('ç¨æ·æªç»å½ï¼è·³è¿è·åæªè¯»æ¶æ¯æ°é') |
| | | return |
| | | } |
| | | |
| | | getUnreadCount().then(response => { |
| | | if (response.code === 200) { |
| | | this.unreadMessageCount = response.data || 0 |
| | | // æ´æ°TabBarå¾½æ |
| | | this.updateTabBarBadge(this.unreadMessageCount) |
| | | } |
| | | }).catch(error => { |
| | | console.error('è·åæªè¯»æ¶æ¯æ°é失败:', error) |
| | | }) |
| | | }, |
| | | |
| | | // æ´æ°TabBarå¾½æ |
| | | updateTabBarBadge(count) { |
| | | if (count > 0) { |
| | | uni.setTabBarBadge({ |
| | | index: 3, // æ¶æ¯é¡µé¢å¨tabBarä¸çç´¢å¼ |
| | | text: count > 99 ? '99+' : count.toString() |
| | | }) |
| | | } else { |
| | | uni.removeTabBarBadge({ |
| | | index: 3 |
| | | }) |
| | | } |
| | | }, |
| | | |
| | | // å è½½ç¨æ·ä¿¡æ¯ï¼ä¿ç以å
¼å®¹ä¹åç代ç ï¼ |
| | | loadUserProfile() { |
| | | const userId = this.currentUser.userId |
| | | if (!userId) { |
| | | console.error('ç¨æ·æªç»å½ï¼æ æ³è·åç¨æ·ä¿¡æ¯') |
| | | return |
| | | } |
| | | |
| | | getUserProfile().then(response => { |
| | | const userInfo = response.data || response |
| | | |
| | | getUserProfile() |
| | | .then((response) => { |
| | | const userInfo = response.data || response; |
| | | // è·åç¨æ·ç»å®ç车è¾ä¿¡æ¯ |
| | | if (userInfo.boundVehicle) { |
| | | this.boundVehicle = userInfo.boundVehicle.vehicleNumber |
| | | this.boundVehicleId = userInfo.boundVehicle.vehicleId |
| | | this.boundVehicle = userInfo.boundVehicle.vehicleNumber; |
| | | this.boundVehicleId = userInfo.boundVehicle.vehicleId; |
| | | } |
| | | }).catch(error => { |
| | | console.error('è·åç¨æ·ä¿¡æ¯å¤±è´¥:', error) |
| | | }) |
| | | }, |
| | | |
| | | // å è½½æ£å¨è¿è¡çä»»å¡ |
| | | loadRunningTasks() { |
| | | const userId = this.currentUser.userId |
| | | if (!userId) { |
| | | console.error('ç¨æ·æªç»å½ï¼æ æ³å 载任å¡å表') |
| | | return |
| | | } |
| | | |
| | | this.loading = true |
| | | // ä½¿ç¨ /task/my æ¥å£è·åå½åç¨æ·ç¸å
³çææä»»å¡ï¼ç¨æ·å建ãåé
ç»ç¨æ·ãæ§è¡äººæ¯ç¨æ·ï¼ |
| | | getMyTasks().then(response => { |
| | | this.loading = false |
| | | .catch((error) => { |
| | | console.error("è·åç¨æ·ä¿¡æ¯å¤±è´¥:", error); |
| | | }); |
| | | }, |
| | | |
| | | // å è½½æ£å¨è¿è¡çä»»å¡ |
| | | loadRunningTasks() { |
| | | const userId = this.currentUser.userId; |
| | | if (!userId) { |
| | | console.error("ç¨æ·æªç»å½ï¼æ æ³å 载任å¡å表"); |
| | | return; |
| | | } |
| | | |
| | | this.loading = true; |
| | | // ä½¿ç¨ /task/my æ¥å£è·åå½åç¨æ·ç¸å
³çææä»»å¡ï¼ç¨æ·å建ãåé
ç»ç¨æ·ãæ§è¡äººæ¯ç¨æ·ï¼ |
| | | getMyTasks() |
| | | .then((response) => { |
| | | this.loading = false; |
| | | // æ ¹æ®å端è¿åçæ°æ®ç»æè¿è¡è§£æ |
| | | const data = response.data || response.rows || response || [] |
| | | const data = response.data || response.rows || response || []; |
| | | // è¿æ»¤åºæªå®æçä»»å¡ |
| | | const allTasks = Array.isArray(data) ? data : [] |
| | | const allTasks = Array.isArray(data) ? data : []; |
| | | this.taskList = allTasks |
| | | .filter(task => { |
| | | .filter((task) => { |
| | | // åªæ¾ç¤ºæªå®æåæªåæ¶çä»»å¡ |
| | | return task.taskStatus !== 'COMPLETED' && task.taskStatus !== 'CANCELLED' |
| | | return ( |
| | | task.taskStatus !== "COMPLETED" && |
| | | task.taskStatus !== "CANCELLED" |
| | | ); |
| | | }) |
| | | .map(task => { |
| | | .map((task) => { |
| | | // ä»assignedVehiclesæ°ç»ä¸è·å车è¾ä¿¡æ¯ |
| | | let vehicleInfo = 'æªåé
车è¾' |
| | | let vehicleInfo = "æªåé
车è¾"; |
| | | if (task.assignedVehicles && task.assignedVehicles.length > 0) { |
| | | const firstVehicle = task.assignedVehicles[0] |
| | | vehicleInfo = firstVehicle.vehicleNo || 'æªç¥è½¦ç' |
| | | const firstVehicle = task.assignedVehicles[0]; |
| | | vehicleInfo = firstVehicle.vehicleNo || "æªç¥è½¦ç"; |
| | | if (task.assignedVehicles.length > 1) { |
| | | vehicleInfo += ` ç${task.assignedVehicles.length}è¾` |
| | | vehicleInfo += ` ç${task.assignedVehicles.length}è¾`; |
| | | } |
| | | } |
| | | |
| | | |
| | | return { |
| | | ...task, |
| | | // æ ¼å¼åæ¾ç¤ºå段 |
| | |
| | | type: task.taskType, |
| | | vehicle: vehicleInfo, |
| | | vehicleList: task.assignedVehicles || [], |
| | | startLocation: this.formatAddress(task.departureAddress || task.startLocation || 'æªè®¾ç½®'), |
| | | endLocation: this.formatAddress(task.destinationAddress || task.endLocation || 'æªè®¾ç½®'), |
| | | startTime: task.plannedStartTime ? formatDateTime(task.plannedStartTime, 'YYYY-MM-DD HH:mm') : 'æªè®¾ç½®', |
| | | assignee: task.assigneeName || 'æªåé
', |
| | | taskNo: task.taskCode || 'æªç¥ç¼å·', |
| | | status: this.convertStatus(task.taskStatus) // 转æ¢ç¶ææ ¼å¼ä»¥å
¼å®¹æ§UI |
| | | } |
| | | }) |
| | | }).catch(error => { |
| | | this.loading = false |
| | | console.error('å 载任å¡å表失败:', error) |
| | | startLocation: this.formatAddress( |
| | | task.departureAddress || task.startLocation || "æªè®¾ç½®" |
| | | ), |
| | | endLocation: this.formatAddress( |
| | | task.destinationAddress || task.endLocation || "æªè®¾ç½®" |
| | | ), |
| | | startTime: task.plannedStartTime |
| | | ? formatDateTime(task.plannedStartTime, "YYYY-MM-DD HH:mm") |
| | | : "æªè®¾ç½®", |
| | | assignee: task.assigneeName || "æªåé
", |
| | | taskNo: task.taskCode || "æªç¥ç¼å·", |
| | | status: this.convertStatus(task.taskStatus), // 转æ¢ç¶ææ ¼å¼ä»¥å
¼å®¹æ§UI |
| | | }; |
| | | }); |
| | | }) |
| | | }, |
| | | |
| | | // æ ¼å¼åå°å - åªæ¾ç¤º-åé¢çé¨å |
| | | formatAddress(address) { |
| | | if (!address) return 'æªè®¾ç½®' |
| | | const dashIndex = address.indexOf('-') |
| | | if (dashIndex > 0) { |
| | | return address.substring(0, dashIndex) |
| | | } |
| | | return address |
| | | }, |
| | | |
| | | // 转æ¢ç¶ææ ¼å¼ï¼å°æ°æ®åºç¶æè½¬æ¢ä¸ºUI使ç¨çç¶æï¼ |
| | | convertStatus(dbStatus) { |
| | | const statusMap = { |
| | | 'PENDING': 'pending', |
| | | 'DEPARTING': 'processing', |
| | | 'ARRIVED': 'processing', |
| | | 'RETURNING': 'processing', |
| | | 'IN_PROGRESS': 'processing', |
| | | 'COMPLETED': 'completed', |
| | | 'CANCELLED': 'cancelled' |
| | | } |
| | | return statusMap[dbStatus] || 'pending' |
| | | }, |
| | | // 跳转å°ç»å®è½¦è¾é¡µé¢ |
| | | goToBindVehicle() { |
| | | // 跳转å°ç»å®è½¦è¾çé¡µé¢ |
| | | this.$tab.navigateTo('/pages/bind-vehicle'); |
| | | }, |
| | | |
| | | // è·³è½¬å°æ¶æ¯é¡µé¢ |
| | | goToMessages() { |
| | | this.$tab.switchTab('/pages/message/index'); |
| | | }, |
| | | |
| | | // æ¥çä»»å¡è¯¦æ
|
| | | viewTaskDetail(task) { |
| | | // 跳转å°ä»»å¡è¯¦æ
é¡µé¢ - 使ç¨taskId |
| | | this.$tab.navigateTo(`/pagesTask/detail?id=${task.taskId || task.id}`); |
| | | }, |
| | | |
| | | // å¤çä»»å¡æä½ |
| | | handleTaskAction(task, action) { |
| | | switch (action) { |
| | | case 'depart': |
| | | // åºå -> ç¶æå为åºåä¸ |
| | | this.$modal.confirm('ç¡®å®è¦åºååï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'DEPARTING', 'ä»»å¡å·²åºå') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'cancel': |
| | | // åæ¶ -> äºæ¬¡ç¡®è®¤åç¶æåä¸ºå·²åæ¶ |
| | | this.$modal.confirm('ç¡®å®è¦åæ¶æ¤ä»»å¡åï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'CANCELLED', 'ä»»å¡å·²åæ¶') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'arrive': |
| | | // å·²å°è¾¾ -> ç¶æå为已å°è¾¾ |
| | | this.$modal.confirm('确认已å°è¾¾ç®çå°ï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'ARRIVED', 'å·²å°è¾¾ç®çå°') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'forceCancel': |
| | | // 强å¶ç»æ -> ç¶æåä¸ºå·²åæ¶ |
| | | this.$modal.confirm('ç¡®å®è¦å¼ºå¶ç»ææ¤ä»»å¡åï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'CANCELLED', 'ä»»å¡å·²å¼ºå¶ç»æ') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'return': |
| | | // å·²è¿ç¨ -> ç¶æå为è¿ç¨ä¸ |
| | | this.$modal.confirm('确认å¼å§è¿ç¨ï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'RETURNING', 'å·²å¼å§è¿ç¨') |
| | | }).catch(() => {}); |
| | | break; |
| | | |
| | | case 'complete': |
| | | // 已宿 -> ç¶æåä¸ºå·²å®æ |
| | | this.$modal.confirm('确认任å¡å·²å®æï¼').then(() => { |
| | | this.updateTaskStatus(task.taskId, 'COMPLETED', 'ä»»å¡å·²å®æ') |
| | | }).catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | // æ´æ°ä»»å¡ç¶æ |
| | | updateTaskStatus(taskId, status, remark) { |
| | | // è·åGPSä½ç½®ä¿¡æ¯ |
| | | this.getLocationAndUpdateStatus(taskId, status, remark) |
| | | }, |
| | | |
| | | // è·åä½ç½®ä¿¡æ¯å¹¶æ´æ°ç¶æ |
| | | getLocationAndUpdateStatus(taskId, status, remark) { |
| | | const that = this |
| | | |
| | | // 使ç¨uni.getLocationè·åGPSä½ç½® |
| | | uni.getLocation({ |
| | | type: 'gcj02', |
| | | geocode: true, |
| | | altitude: true, |
| | | success: function(res) { |
| | | console.log('GPSå®ä½æå:', res) |
| | | |
| | | const statusData = { |
| | | taskStatus: status, |
| | | remark: remark, |
| | | latitude: res.latitude, |
| | | longitude: res.longitude, |
| | | locationAddress: res.address ? res.address.street || res.address.poiName || '' : '', |
| | | locationProvince: res.address ? res.address.province || '' : '', |
| | | locationCity: res.address ? res.address.city || '' : '', |
| | | locationDistrict: res.address ? res.address.district || '' : '', |
| | | gpsAccuracy: res.accuracy, |
| | | altitude: res.altitude, |
| | | speed: res.speed, |
| | | heading: res.direction || res.heading |
| | | } |
| | | |
| | | changeTaskStatus(taskId, statusData).then(response => { |
| | | that.$modal.showToast('ç¶ææ´æ°æå') |
| | | that.loadRunningTasks() |
| | | }).catch(error => { |
| | | console.error('æ´æ°ä»»å¡ç¶æå¤±è´¥:', error) |
| | | that.$modal.showToast('ç¶ææ´æ°å¤±è´¥ï¼è¯·éè¯') |
| | | .catch((error) => { |
| | | this.loading = false; |
| | | console.error("å 载任å¡å表失败:", error); |
| | | }); |
| | | }, |
| | | |
| | | // æ ¼å¼åå°å - åªæ¾ç¤º-åé¢çé¨å |
| | | formatAddress(address) { |
| | | if (!address) return "æªè®¾ç½®"; |
| | | const dashIndex = address.indexOf("-"); |
| | | if (dashIndex > 0) { |
| | | return address.substring(0, dashIndex); |
| | | } |
| | | return address; |
| | | }, |
| | | |
| | | // 转æ¢ç¶ææ ¼å¼ï¼å°æ°æ®åºç¶æè½¬æ¢ä¸ºUI使ç¨çç¶æï¼ |
| | | convertStatus(dbStatus) { |
| | | const statusMap = { |
| | | PENDING: "pending", |
| | | DEPARTING: "processing", |
| | | ARRIVED: "processing", |
| | | RETURNING: "processing", |
| | | IN_PROGRESS: "processing", |
| | | COMPLETED: "completed", |
| | | CANCELLED: "cancelled", |
| | | }; |
| | | return statusMap[dbStatus] || "pending"; |
| | | }, |
| | | // 跳转å°ç»å®è½¦è¾é¡µé¢ |
| | | goToBindVehicle() { |
| | | // 跳转å°ç»å®è½¦è¾çé¡µé¢ |
| | | this.$tab.navigateTo("/pages/bind-vehicle"); |
| | | }, |
| | | |
| | | // è·³è½¬å°æ¶æ¯é¡µé¢ |
| | | goToMessages() { |
| | | this.$tab.switchTab("/pages/message/index"); |
| | | }, |
| | | |
| | | // æ¥çä»»å¡è¯¦æ
|
| | | viewTaskDetail(task) { |
| | | // 跳转å°ä»»å¡è¯¦æ
é¡µé¢ - 使ç¨taskId |
| | | this.$tab.navigateTo(`/pagesTask/detail?id=${task.taskId || task.id}`); |
| | | }, |
| | | |
| | | // å¤çä»»å¡æä½ |
| | | handleTaskAction(task, action) { |
| | | switch (action) { |
| | | case "depart": |
| | | // åºå -> ç¶æå为åºåä¸ |
| | | this.$modal |
| | | .confirm("ç¡®å®è¦åºååï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "DEPARTING", "ä»»å¡å·²åºå"); |
| | | }) |
| | | }, |
| | | fail: function(err) { |
| | | console.error('GPSå®ä½å¤±è´¥:', err) |
| | | |
| | | that.$modal.confirm('GPSå®ä½å¤±è´¥ï¼æ¯å¦ç»§ç»æ´æ°ç¶æï¼').then(() => { |
| | | .catch(() => {}); |
| | | break; |
| | | |
| | | case "cancel": |
| | | // åæ¶ -> äºæ¬¡ç¡®è®¤åç¶æåä¸ºå·²åæ¶ |
| | | this.$modal |
| | | .confirm("ç¡®å®è¦åæ¶æ¤ä»»å¡åï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "CANCELLED", "ä»»å¡å·²åæ¶"); |
| | | }) |
| | | .catch(() => {}); |
| | | break; |
| | | |
| | | case "arrive": |
| | | // å·²å°è¾¾ -> ç¶æå为已å°è¾¾ |
| | | this.$modal |
| | | .confirm("确认已å°è¾¾ç®çå°ï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "ARRIVED", "å·²å°è¾¾ç®çå°"); |
| | | }) |
| | | .catch(() => {}); |
| | | break; |
| | | |
| | | case "forceCancel": |
| | | // 强å¶ç»æ -> ç¶æåä¸ºå·²åæ¶ |
| | | this.$modal |
| | | .confirm("ç¡®å®è¦å¼ºå¶ç»ææ¤ä»»å¡åï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "CANCELLED", "ä»»å¡å·²å¼ºå¶ç»æ"); |
| | | }) |
| | | .catch(() => {}); |
| | | break; |
| | | |
| | | case "return": |
| | | // å·²è¿ç¨ -> ç¶æå为è¿ç¨ä¸ |
| | | this.$modal |
| | | .confirm("确认å¼å§è¿ç¨ï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "RETURNING", "å·²å¼å§è¿ç¨"); |
| | | }) |
| | | .catch(() => {}); |
| | | break; |
| | | |
| | | case "complete": |
| | | // 已宿 -> ç¶æåä¸ºå·²å®æ |
| | | this.$modal |
| | | .confirm("确认任å¡å·²å®æï¼") |
| | | .then(() => { |
| | | this.updateTaskStatus(task.taskId, "COMPLETED", "ä»»å¡å·²å®æ"); |
| | | }) |
| | | .catch(() => {}); |
| | | break; |
| | | } |
| | | }, |
| | | |
| | | // æ´æ°ä»»å¡ç¶æ |
| | | updateTaskStatus(taskId, status, remark) { |
| | | // è·åGPSä½ç½®ä¿¡æ¯ |
| | | this.getLocationAndUpdateStatus(taskId, status, remark); |
| | | }, |
| | | |
| | | // è·åä½ç½®ä¿¡æ¯å¹¶æ´æ°ç¶æ |
| | | getLocationAndUpdateStatus(taskId, status, remark) { |
| | | const that = this; |
| | | |
| | | // 使ç¨uni.getLocationè·åGPSä½ç½® |
| | | uni.getLocation({ |
| | | type: "gcj02", |
| | | geocode: true, |
| | | altitude: true, |
| | | success: function (res) { |
| | | console.log("GPSå®ä½æå:", res); |
| | | |
| | | const statusData = { |
| | | taskStatus: status, |
| | | remark: remark, |
| | | latitude: res.latitude, |
| | | longitude: res.longitude, |
| | | locationAddress: res.address |
| | | ? res.address.street || res.address.poiName || "" |
| | | : "", |
| | | locationProvince: res.address ? res.address.province || "" : "", |
| | | locationCity: res.address ? res.address.city || "" : "", |
| | | locationDistrict: res.address ? res.address.district || "" : "", |
| | | gpsAccuracy: res.accuracy, |
| | | altitude: res.altitude, |
| | | speed: res.speed, |
| | | heading: res.direction || res.heading, |
| | | }; |
| | | |
| | | changeTaskStatus(taskId, statusData) |
| | | .then((response) => { |
| | | that.$modal.showToast("ç¶ææ´æ°æå"); |
| | | that.loadRunningTasks(); |
| | | }) |
| | | .catch((error) => { |
| | | console.error("æ´æ°ä»»å¡ç¶æå¤±è´¥:", error); |
| | | that.$modal.showToast("ç¶ææ´æ°å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }, |
| | | fail: function (err) { |
| | | console.error("GPSå®ä½å¤±è´¥:", err); |
| | | |
| | | that.$modal |
| | | .confirm("GPSå®ä½å¤±è´¥ï¼æ¯å¦ç»§ç»æ´æ°ç¶æï¼") |
| | | .then(() => { |
| | | const statusData = { |
| | | taskStatus: status, |
| | | remark: remark |
| | | } |
| | | |
| | | changeTaskStatus(taskId, statusData).then(response => { |
| | | that.$modal.showToast('ç¶ææ´æ°æå') |
| | | that.loadRunningTasks() |
| | | }).catch(error => { |
| | | console.error('æ´æ°ä»»å¡ç¶æå¤±è´¥:', error) |
| | | that.$modal.showToast('ç¶ææ´æ°å¤±è´¥ï¼è¯·éè¯') |
| | | }) |
| | | }).catch(() => {}) |
| | | remark: remark, |
| | | }; |
| | | |
| | | changeTaskStatus(taskId, statusData) |
| | | .then((response) => { |
| | | that.$modal.showToast("ç¶ææ´æ°æå"); |
| | | that.loadRunningTasks(); |
| | | }) |
| | | .catch((error) => { |
| | | console.error("æ´æ°ä»»å¡ç¶æå¤±è´¥:", error); |
| | | that.$modal.showToast("ç¶ææ´æ°å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }) |
| | | .catch(() => {}); |
| | | }, |
| | | }); |
| | | }, |
| | | |
| | | // è·åç¶ææ ·å¼ç±» |
| | | getStatusClass(status) { |
| | | const statusClassMap = { |
| | | PENDING: "status-pending", |
| | | DEPARTING: "status-departing", |
| | | ARRIVED: "status-arrived", |
| | | RETURNING: "status-returning", |
| | | COMPLETED: "status-completed", |
| | | CANCELLED: "status-cancelled", |
| | | IN_PROGRESS: "status-in-progress", |
| | | }; |
| | | return statusClassMap[status] || "status-default"; |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | | // æ¯ææ°æ§ä¸¤ç§ç¶ææ ¼å¼ |
| | | const statusMap = { |
| | | // æ°æ ¼å¼ï¼æ°æ®åºç¶æï¼ |
| | | PENDING: "å¾
å¤ç", |
| | | DEPARTING: "åºåä¸", |
| | | ARRIVED: "å·²å°è¾¾", |
| | | RETURNING: "è¿ç¨ä¸", |
| | | COMPLETED: "已宿", |
| | | CANCELLED: "已忶", |
| | | IN_PROGRESS: "å¤çä¸", |
| | | // æ§æ ¼å¼ï¼UIç¶æï¼ |
| | | pending: "å¾
å¤ç", |
| | | processing: "å¤çä¸", |
| | | completed: "已宿", |
| | | }; |
| | | return statusMap[status] || "æªç¥"; |
| | | }, |
| | | |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | // æ°æ ¼å¼ï¼æ°æ®åºç±»åï¼ |
| | | MAINTENANCE: "ç»´ä¿®ä¿å
»", |
| | | FUEL: "å æ²¹", |
| | | OTHER: "å
¶ä»", |
| | | EMERGENCY_TRANSFER: "转è¿ä»»å¡", |
| | | WELFARE: "ç¦ç¥è½¦", |
| | | // æ§æ ¼å¼ï¼UIç±»åï¼ |
| | | maintenance: "ç»´ä¿®ä¿å
»", |
| | | refuel: "å æ²¹", |
| | | inspection: "å·¡æ£", |
| | | emergency: "转è¿ä»»å¡", |
| | | welfare: "ç¦ç¥è½¦", |
| | | }; |
| | | return typeMap[type] || "æªç¥ç±»å"; |
| | | }, |
| | | |
| | | clickConfirmsubscribeTaskNotify() { |
| | | subscribeManager.subscribeWithConfirm() |
| | | .then((result) => { |
| | | if (result.success) { |
| | | this.hasSubscribed = true; |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | // è·åç¶ææ ·å¼ç±» |
| | | getStatusClass(status) { |
| | | const statusClassMap = { |
| | | 'PENDING': 'status-pending', |
| | | 'DEPARTING': 'status-departing', |
| | | 'ARRIVED': 'status-arrived', |
| | | 'RETURNING': 'status-returning', |
| | | 'COMPLETED': 'status-completed', |
| | | 'CANCELLED': 'status-cancelled', |
| | | 'IN_PROGRESS': 'status-in-progress' |
| | | } |
| | | return statusClassMap[status] || 'status-default' |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | | // æ¯ææ°æ§ä¸¤ç§ç¶ææ ¼å¼ |
| | | const statusMap = { |
| | | // æ°æ ¼å¼ï¼æ°æ®åºç¶æï¼ |
| | | 'PENDING': 'å¾
å¤ç', |
| | | 'DEPARTING': 'åºåä¸', |
| | | 'ARRIVED': 'å·²å°è¾¾', |
| | | 'RETURNING': 'è¿ç¨ä¸', |
| | | 'COMPLETED': '已宿', |
| | | 'CANCELLED': '已忶', |
| | | 'IN_PROGRESS': 'å¤çä¸', |
| | | // æ§æ ¼å¼ï¼UIç¶æï¼ |
| | | 'pending': 'å¾
å¤ç', |
| | | 'processing': 'å¤çä¸', |
| | | 'completed': '已宿' |
| | | } |
| | | return statusMap[status] || 'æªç¥' |
| | | }, |
| | | |
| | | getTaskTypeText(type) { |
| | | const typeMap = { |
| | | // æ°æ ¼å¼ï¼æ°æ®åºç±»åï¼ |
| | | 'MAINTENANCE': 'ç»´ä¿®ä¿å
»', |
| | | 'FUEL': 'å æ²¹', |
| | | 'OTHER': 'å
¶ä»', |
| | | 'EMERGENCY_TRANSFER': '转è¿ä»»å¡', |
| | | 'WELFARE': 'ç¦ç¥è½¦', |
| | | // æ§æ ¼å¼ï¼UIç±»åï¼ |
| | | 'maintenance': 'ç»´ä¿®ä¿å
»', |
| | | 'refuel': 'å æ²¹', |
| | | 'inspection': 'å·¡æ£', |
| | | 'emergency': '转è¿ä»»å¡', |
| | | 'welfare': 'ç¦ç¥è½¦' |
| | | } |
| | | return typeMap[type] || 'æªç¥ç±»å' |
| | | } |
| | | } |
| | | } |
| | | .catch((error) => { |
| | | console.log('订é
åæ¶æå¤±è´¥ï¼', error); |
| | | }); |
| | | }, |
| | | |
| | | // 订é
ä»»å¡éç¥ï¼ç´æ¥è°ç¨ï¼ä¸æ¾ç¤ºç¡®è®¤å¼¹çªï¼ |
| | | subscribeTaskNotify() { |
| | | subscribeManager.subscribeDirect() |
| | | .then((result) => { |
| | | if (result.success) { |
| | | this.hasSubscribed = true; |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.log('订é
失败ï¼', error); |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .home-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // éèæ»å¨æ¡ä½ä¿ææ»å¨åè½ |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefoxæ»å¨æ¡éè |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edgeæ»å¨æ¡éè |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | .home-container { |
| | | padding: 20rpx; |
| | | background-color: #f5f5f5; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | // éèæ»å¨æ¡ä½ä¿ææ»å¨åè½ |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // ç¨æ·ä¿¡æ¯åºå |
| | | .user-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | flex-shrink: 0; // 鲿¢æ¶ç¼© |
| | | |
| | | .user-info-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .user-details { |
| | | flex: 1; |
| | | |
| | | .user-info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 12rpx; |
| | | |
| | | .user-name { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .separator { |
| | | margin: 0 12rpx; |
| | | color: #ddd; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .branch-company { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .vehicle-info { |
| | | font-size: 26rpx; |
| | | color: #007AFF; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | // Firefoxæ»å¨æ¡éè |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edgeæ»å¨æ¡éè |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | } |
| | | |
| | | // ç¨æ·ä¿¡æ¯åºå |
| | | .user-info-section { |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | flex-shrink: 0; // 鲿¢æ¶ç¼© |
| | | |
| | | .user-info-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .user-details { |
| | | flex: 1; |
| | | |
| | | .user-info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 12rpx; |
| | | |
| | | .user-name { |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .bind-vehicle-btn { |
| | | |
| | | .separator { |
| | | margin: 0 12rpx; |
| | | color: #ddd; |
| | | font-size: 28rpx; |
| | | } |
| | | |
| | | .branch-company { |
| | | font-size: 26rpx; |
| | | color: #007AFF; |
| | | color: #666; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | &:active { |
| | | opacity: 0.7; |
| | | } |
| | | } |
| | | |
| | | .vehicle-info { |
| | | font-size: 26rpx; |
| | | color: #007aff; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | .bind-vehicle-btn { |
| | | font-size: 26rpx; |
| | | color: #007aff; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | &:active { |
| | | opacity: 0.7; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æ¶æ¯å
¥å£ |
| | | .message-entry { |
| | | } |
| | | |
| | | // æ¶æ¯å
¥å£ |
| | | .message-entry { |
| | | display: flex; |
| | | align-items: center; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | position: relative; |
| | | |
| | | .message-icon { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .message-text { |
| | | flex: 1; |
| | | font-size: 32rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .unread-dot { |
| | | position: absolute; |
| | | top: 15rpx; |
| | | right: 60rpx; |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | border-radius: 50%; |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | position: relative; |
| | | |
| | | .message-icon { |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .message-text { |
| | | flex: 1; |
| | | font-size: 32rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .unread-dot { |
| | | position: absolute; |
| | | top: 15rpx; |
| | | right: 60rpx; |
| | | background-color: #ff4d4f; |
| | | color: white; |
| | | border-radius: 50%; |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 20rpx; |
| | | } |
| | | |
| | | .arrow { |
| | | margin-left: 20rpx; |
| | | } |
| | | justify-content: center; |
| | | font-size: 20rpx; |
| | | } |
| | | |
| | | // æ£å¨è¿è¡ç任塿 é¢ |
| | | .running-tasks-header { |
| | | margin-bottom: 20rpx; |
| | | flex-shrink: 0; // 鲿¢æ¶ç¼© |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | |
| | | .arrow { |
| | | margin-left: 20rpx; |
| | | } |
| | | } |
| | | |
| | | // 订é
éç¥æ¨ªå¹
|
| | | .subscribe-banner { |
| | | display: flex; |
| | | align-items: center; |
| | | background: linear-gradient(135deg, #fff9e6 0%, #fff3e0 100%); |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | margin-bottom: 20rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(255, 149, 0, 0.1); |
| | | border: 1rpx solid #ffe0b2; |
| | | |
| | | .banner-icon { |
| | | margin-right: 20rpx; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .banner-content { |
| | | flex: 1; |
| | | |
| | | .banner-title { |
| | | font-size: 30rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .banner-desc { |
| | | font-size: 24rpx; |
| | | color: #666; |
| | | line-height: 1.4; |
| | | } |
| | | } |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡å表 |
| | | .running-tasks-section { |
| | | flex: 1; |
| | | |
| | | .banner-action { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 12rpx 24rpx; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | // éèæ»å¨æ¡ä½ä¿ææ»å¨åè½ |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | border-radius: 30rpx; |
| | | flex-shrink: 0; |
| | | |
| | | text { |
| | | font-size: 26rpx; |
| | | color: #007aff; |
| | | margin-right: 4rpx; |
| | | } |
| | | |
| | | // Firefoxæ»å¨æ¡éè |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edgeæ»å¨æ¡éè |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .task-list { |
| | | .task-item { |
| | | background-color: #fafafa; |
| | | border-radius: 15rpx; |
| | | margin-bottom: 30rpx; |
| | | overflow: hidden; |
| | | |
| | | .task-main { |
| | | padding: 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | // ä»»å¡å¤´é¨ï¼æ é¢åç¶æ |
| | | .task-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | margin-bottom: 15rpx; |
| | | |
| | | .task-title { |
| | | flex: 1; |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | padding-right: 20rpx; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | .task-status { |
| | | padding: 8rpx 20rpx; |
| | | border-radius: 30rpx; |
| | | font-size: 24rpx; |
| | | white-space: nowrap; |
| | | flex-shrink: 0; |
| | | |
| | | // å¾
å¤ç - æ©è² |
| | | &.status-pending { |
| | | background-color: #fff3e0; |
| | | color: #ff9500; |
| | | } |
| | | |
| | | // åºåä¸ - èè² |
| | | &.status-departing { |
| | | background-color: #e3f2fd; |
| | | color: #007AFF; |
| | | } |
| | | |
| | | // å·²å°è¾¾ - ç´«è² |
| | | &.status-arrived { |
| | | background-color: #f3e5f5; |
| | | color: #9c27b0; |
| | | } |
| | | |
| | | // è¿ç¨ä¸ - éè² |
| | | &.status-returning { |
| | | background-color: #e0f2f1; |
| | | color: #009688; |
| | | } |
| | | |
| | | // 已宿 - ç»¿è² |
| | | &.status-completed { |
| | | background-color: #e8f5e9; |
| | | color: #34C759; |
| | | } |
| | | |
| | | // 已忶 - ç°è² |
| | | &.status-cancelled { |
| | | background-color: #f5f5f5; |
| | | color: #999; |
| | | } |
| | | |
| | | // å¤çä¸ (å
¼å®¹æ§æ°æ®) - èè² |
| | | &.status-in-progress { |
| | | background-color: #e3f2fd; |
| | | color: #007AFF; |
| | | } |
| | | |
| | | // é»è®¤æ ·å¼ |
| | | &.status-default { |
| | | background-color: #f5f5f5; |
| | | color: #666; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &:active { |
| | | opacity: 0.9; |
| | | } |
| | | } |
| | | |
| | | // æ£å¨è¿è¡ç任塿 é¢ |
| | | .running-tasks-header { |
| | | margin-bottom: 20rpx; |
| | | flex-shrink: 0; // 鲿¢æ¶ç¼© |
| | | |
| | | .header-title { |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | |
| | | // æ£å¨è¿è¡çä»»å¡å表 |
| | | .running-tasks-section { |
| | | flex: 1; |
| | | background-color: white; |
| | | border-radius: 15rpx; |
| | | padding: 30rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | // éèæ»å¨æ¡ä½ä¿ææ»å¨åè½ |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | width: 0 !important; |
| | | height: 0 !important; |
| | | background: transparent; |
| | | } |
| | | |
| | | // Firefoxæ»å¨æ¡éè |
| | | * { |
| | | scrollbar-width: none; /* Firefox */ |
| | | } |
| | | |
| | | // IE/Edgeæ»å¨æ¡éè |
| | | * { |
| | | -ms-overflow-style: none; /* IE 10+ */ |
| | | } |
| | | |
| | | .task-list { |
| | | .task-item { |
| | | background-color: #fafafa; |
| | | border-radius: 15rpx; |
| | | margin-bottom: 30rpx; |
| | | overflow: hidden; |
| | | |
| | | .task-main { |
| | | padding: 30rpx; |
| | | border-bottom: 1rpx solid #f0f0f0; |
| | | |
| | | // ä»»å¡å¤´é¨ï¼æ é¢åç¶æ |
| | | .task-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | margin-bottom: 15rpx; |
| | | |
| | | .task-title { |
| | | flex: 1; |
| | | font-size: 32rpx; |
| | | font-weight: bold; |
| | | padding-right: 20rpx; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | // ä»»å¡ç¼å·åç¬ä¸è¡ |
| | | .task-code-row { |
| | | margin-bottom: 15rpx; |
| | | padding: 10rpx 0; |
| | | border-bottom: 1rpx dashed #e0e0e0; |
| | | |
| | | .task-code { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | font-weight: 500; |
| | | font-family: monospace; |
| | | |
| | | .task-status { |
| | | padding: 8rpx 20rpx; |
| | | border-radius: 30rpx; |
| | | font-size: 24rpx; |
| | | white-space: nowrap; |
| | | flex-shrink: 0; |
| | | |
| | | // å¾
å¤ç - æ©è² |
| | | &.status-pending { |
| | | background-color: #fff3e0; |
| | | color: #ff9500; |
| | | } |
| | | } |
| | | |
| | | .task-info { |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 15rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | display: flex; |
| | | |
| | | .label { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-right: 10rpx; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 26rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | |
| | | // åºåä¸ - èè² |
| | | &.status-departing { |
| | | background-color: #e3f2fd; |
| | | color: #007aff; |
| | | } |
| | | |
| | | // å·²å°è¾¾ - ç´«è² |
| | | &.status-arrived { |
| | | background-color: #f3e5f5; |
| | | color: #9c27b0; |
| | | } |
| | | |
| | | // è¿ç¨ä¸ - éè² |
| | | &.status-returning { |
| | | background-color: #e0f2f1; |
| | | color: #009688; |
| | | } |
| | | |
| | | // 已宿 - ç»¿è² |
| | | &.status-completed { |
| | | background-color: #e8f5e9; |
| | | color: #34c759; |
| | | } |
| | | |
| | | // 已忶 - ç°è² |
| | | &.status-cancelled { |
| | | background-color: #f5f5f5; |
| | | color: #999; |
| | | } |
| | | |
| | | // å¤çä¸ (å
¼å®¹æ§æ°æ®) - èè² |
| | | &.status-in-progress { |
| | | background-color: #e3f2fd; |
| | | color: #007aff; |
| | | } |
| | | |
| | | // é»è®¤æ ·å¼ |
| | | &.status-default { |
| | | background-color: #f5f5f5; |
| | | color: #666; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | padding: 20rpx; |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 0 5rpx; |
| | | background-color: #f0f0f0; |
| | | |
| | | // ä»»å¡ç¼å·åç¬ä¸è¡ |
| | | .task-code-row { |
| | | margin-bottom: 15rpx; |
| | | padding: 10rpx 0; |
| | | border-bottom: 1rpx dashed #e0e0e0; |
| | | |
| | | .task-code { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007AFF; |
| | | color: white; |
| | | } |
| | | |
| | | &.cancel { |
| | | background-color: #ff3b30; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | font-weight: 500; |
| | | font-family: monospace; |
| | | } |
| | | } |
| | | |
| | | .task-info { |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 15rpx; |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | display: flex; |
| | | |
| | | .label { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | margin-right: 10rpx; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 26rpx; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | |
| | | text { |
| | | display: block; |
| | | margin-top: 20rpx; |
| | | |
| | | .task-actions { |
| | | display: flex; |
| | | padding: 20rpx; |
| | | |
| | | .action-btn { |
| | | flex: 1; |
| | | height: 70rpx; |
| | | border-radius: 10rpx; |
| | | font-size: 26rpx; |
| | | margin: 0 5rpx; |
| | | background-color: #f0f0f0; |
| | | color: #333; |
| | | |
| | | &.primary { |
| | | background-color: #007aff; |
| | | color: white; |
| | | } |
| | | |
| | | &.cancel { |
| | | background-color: #ff3b30; |
| | | color: white; |
| | | } |
| | | |
| | | &.disabled { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | &:first-child { |
| | | margin-left: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .no-data { |
| | | text-align: center; |
| | | padding: 100rpx 0; |
| | | color: #999; |
| | | |
| | | text { |
| | | display: block; |
| | | margin-top: 20rpx; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <view class="message-container"> |
| | | <view class="message-header"> |
| | | <view class="header-title">æ¶æ¯ä¸å¿</view> |
| | | <view class="subscribe-btn" v-if="!subscribed" @click="subscribeMessage"> |
| | | <uni-icons type="bell" size="20" color="#007AFF"></uni-icons> |
| | | <text>订é
éç¥</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <scroll-view class="message-list-scroll" scroll-y="true"> |
| | |
| | | <script> |
| | | import { getMyMessages, markAsRead } from '@/api/message' |
| | | import { formatDateTime } from '@/utils/common' |
| | | import subscribeManager from '@/utils/subscribe' |
| | | |
| | | export default { |
| | | data() { |
| | | return { |
| | | // æ¶æ¯å表 |
| | | messages: [], |
| | | loading: false |
| | | loading: false, |
| | | subscribed: true, |
| | | } |
| | | }, |
| | | computed: { |
| | |
| | | }, |
| | | onLoad() { |
| | | this.loadMessages() |
| | | // èªå¨è®¢é
ï¼å¦ææªè®¢é
åæ¾ç¤ºç¡®è®¤å¼¹çªï¼ |
| | | // this.autoSubscribeOnLaunch() |
| | | }, |
| | | onShow() { |
| | | // æ¯æ¬¡æ¾ç¤ºé¡µé¢æ¶å·æ°æ¶æ¯ |
| | |
| | | }) |
| | | }, |
| | | methods: { |
| | | // èªå¨è®¢é
ï¼é¡µé¢å è½½æ¶è°ç¨ï¼ |
| | | autoSubscribeOnLaunch() { |
| | | subscribeManager.autoSubscribe() |
| | | .then((result) => { |
| | | if (result.skipped) { |
| | | console.log('ç¨æ·å·²è®¢é
ï¼æ ééå¤è®¢é
') |
| | | } else if (result.success) { |
| | | console.log('èªå¨è®¢é
æå') |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.log('èªå¨è®¢é
åæ¶æå¤±è´¥ï¼', error) |
| | | }) |
| | | }, |
| | | |
| | | // å è½½æ¶æ¯å表 |
| | | async loadMessages() { |
| | | try { |
| | |
| | | formatMessageTime(dateTime) { |
| | | if (!dateTime) return '' |
| | | return formatDateTime(dateTime, 'MM-DD HH:mm') |
| | | }, |
| | | |
| | | // 订é
ä»»å¡éç¥ |
| | | subscribeMessage() { |
| | | subscribeManager.subscribeWithConfirm() |
| | | .then((result) => { |
| | | if (result.success) { |
| | | uni.showToast({ |
| | | title: '订é
æåï¼æ¨å°æ¶å°ä»»å¡éç¥', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }) |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.log('订é
失败ï¼', error) |
| | | }) |
| | | } |
| | | } |
| | | } |
| | |
| | | font-size: 36rpx; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .subscribe-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 10rpx 20rpx; |
| | | background-color: #f0f9ff; |
| | | border-radius: 30rpx; |
| | | |
| | | text { |
| | | margin-left: 8rpx; |
| | | font-size: 26rpx; |
| | | color: #007AFF; |
| | | } |
| | | |
| | | &:active { |
| | | opacity: 0.7; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .message-list-scroll { |
| | |
| | | import { listAvailableVehicles, getUserBoundVehicle } from "@/api/vehicle" |
| | | import { searchHospitals, searchHospitalsByDeptRegion } from "@/api/hospital" |
| | | import DepartureSelector from './components/DepartureSelector.vue' |
| | | import { calculateDistance, baiduDistanceByAddress, baiduPlaceSuggestion } from "@/api/map" |
| | | import { calculateTianDiTuDistance } from "@/api/map" |
| | | import { listBranchUsers } from "@/api/system/user" |
| | | import { searchIcd10 } from "@/api/icd10" |
| | | import { calculateTransferPrice } from "@/api/price" |
| | |
| | | |
| | | // è°ç¨ç¾åº¦å°å¾API计ç®è·ç¦» |
| | | const region = this.selectedRegion || '广å·' |
| | | baiduDistanceByAddress(fromAddress, region, toAddress, region) |
| | | calculateTianDiTuDistance(fromAddress, toAddress) |
| | | .then(response => { |
| | | uni.hideLoading() |
| | | |
| | |
| | | |
| | | // 使ç¨uni-appçGPSå®ä½åè½ |
| | | uni.getLocation({ |
| | | type: 'gcj02', // è¿å彿µå±åæ ï¼éç¨äºå½å
å°å¾ |
| | | type: 'gcj02', // è¿å彿µå±åæ ï¼éç¨äºå½å
å°å¾ ç«æåæ |
| | | success: (res) => { |
| | | console.log('è·åå°GPSåæ :', res) |
| | | const latitude = res.latitude |
| | |
| | | }) |
| | | |
| | | // è°ç¨ç¾åº¦å°å¾API计ç®è·ç¦» |
| | | baiduDistanceByAddress(fromAddress, fromCity, toAddress, toCity) |
| | | calculateTianDiTuDistance(fromAddress, toAddress) |
| | | .then(response => { |
| | | uni.hideLoading() |
| | | |
| | |
| | | <view class="detail-section"> |
| | | <view class="section-title">æ¶é´ä¿¡æ¯</view> |
| | | <view class="info-item"> |
| | | <view class="label">计åå¼å§æ¶é´</view> |
| | | <view class="label">é¢çº¦æ¶é´</view> |
| | | <view class="value">{{ displayPlannedStartTime }}</view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-item" v-if="taskDetail.plannedEndTime"> |
| | | <view class="label">计åç»ææ¶é´</view> |
| | | <view class="value">{{ displayPlannedEndTime }}</view> |
| | | </view> |
| | |
| | | if (!this.taskDetail || !this.taskDetail.plannedStartTime) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatDateTime(this.taskDetail.plannedStartTime, 'YYYY-MM-DD HH:mm') |
| | | const formatted = formatDateTime(this.taskDetail.plannedStartTime, 'YYYY-MM-DD HH:mm') |
| | | // 妿年份æ¯1900,è¡¨ç¤ºæ ææ¥æ,æ¾ç¤ºä¸ºæªè®¾ç½® |
| | | if (formatted && formatted.startsWith('1900')) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatted |
| | | }, |
| | | // æ¾ç¤ºè®¡åç»ææ¶é´ |
| | | displayPlannedEndTime() { |
| | | if (!this.taskDetail || !this.taskDetail.plannedEndTime) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatDateTime(this.taskDetail.plannedEndTime, 'YYYY-MM-DD HH:mm') |
| | | const formatted = formatDateTime(this.taskDetail.plannedEndTime, 'YYYY-MM-DD HH:mm') |
| | | // 妿年份æ¯1900,è¡¨ç¤ºæ ææ¥æ,æ¾ç¤ºä¸ºæªè®¾ç½® |
| | | if (formatted && formatted.startsWith('1900')) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatted |
| | | }, |
| | | // æ¾ç¤ºå®é
å¼å§æ¶é´ |
| | | displayActualStartTime() { |
| | | if (!this.taskDetail || !this.taskDetail.actualStartTime) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatDateTime(this.taskDetail.actualStartTime, 'YYYY-MM-DD HH:mm') |
| | | const formatted = formatDateTime(this.taskDetail.actualStartTime, 'YYYY-MM-DD HH:mm') |
| | | // 妿年份æ¯1900,è¡¨ç¤ºæ ææ¥æ,æ¾ç¤ºä¸ºæªè®¾ç½® |
| | | if (formatted && formatted.startsWith('1900')) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatted |
| | | }, |
| | | // æ¾ç¤ºå®é
ç»ææ¶é´ |
| | | displayActualEndTime() { |
| | | if (!this.taskDetail || !this.taskDetail.actualEndTime) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatDateTime(this.taskDetail.actualEndTime, 'YYYY-MM-DD HH:mm') |
| | | const formatted = formatDateTime(this.taskDetail.actualEndTime, 'YYYY-MM-DD HH:mm') |
| | | // 妿年份æ¯1900,è¡¨ç¤ºæ ææ¥æ,æ¾ç¤ºä¸ºæªè®¾ç½® |
| | | if (formatted && formatted.startsWith('1900')) { |
| | | return 'æªè®¾ç½®' |
| | | } |
| | | return formatted |
| | | } |
| | | }, |
| | | onLoad(options) { |
| New file |
| | |
| | | import { getWechatConfig } from '@/api/wechat' |
| | | |
| | | /** |
| | | * 微信订é
æ¶æ¯å·¥å
·ç±» |
| | | * ç»ä¸ç®¡ç订é
æ¶æ¯ç¸å
³åè½ |
| | | */ |
| | | class SubscribeManager { |
| | | constructor() { |
| | | this.wechatConfig = { |
| | | taskNotifyTemplateId: '' |
| | | } |
| | | this.configLoaded = false |
| | | } |
| | | |
| | | /** |
| | | * å 载微信é
ç½® |
| | | * @returns {Promise} |
| | | */ |
| | | loadWechatConfig() { |
| | | return new Promise((resolve, reject) => { |
| | | if (this.configLoaded && this.wechatConfig.taskNotifyTemplateId) { |
| | | resolve(this.wechatConfig) |
| | | return |
| | | } |
| | | |
| | | getWechatConfig() |
| | | .then((response) => { |
| | | if (response.code === 200 && response.data) { |
| | | this.wechatConfig = response.data |
| | | this.configLoaded = true |
| | | console.log('微信é
ç½®å è½½æåï¼', this.wechatConfig) |
| | | resolve(this.wechatConfig) |
| | | } else { |
| | | console.warn('å 载微信é
置失败ï¼ä½¿ç¨é»è®¤é
ç½®') |
| | | reject(new Error('å 载微信é
置失败')) |
| | | } |
| | | }) |
| | | .catch((error) => { |
| | | console.error('å 载微信é
置失败ï¼', error) |
| | | reject(error) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥æ¬å°è®¢é
ç¶æï¼ä»ç¼å读åï¼ |
| | | * @returns {boolean} |
| | | */ |
| | | checkLocalSubscribeStatus() { |
| | | return true;// uni.getStorageSync('hasSubscribedTaskNotify') || false |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥å¾®ä¿¡å®æ¹è®¢é
ç¶æï¼çå®ç¶æï¼ |
| | | * @returns {Promise<boolean>} |
| | | */ |
| | | checkWechatSubscribeStatus() { |
| | | return new Promise((resolve) => { |
| | | // #ifdef MP-WEIXIN |
| | | // éè¦å
å è½½é
ç½®è·å模æ¿ID |
| | | this.loadWechatConfig() |
| | | .then(() => { |
| | | const templateId = this.wechatConfig.taskNotifyTemplateId |
| | | if (!templateId) { |
| | | console.warn('模æ¿IDæªé
ç½®ï¼æ æ³æ£æ¥è®¢é
ç¶æ') |
| | | resolve(false) |
| | | return |
| | | } |
| | | |
| | | wx.getSetting({ |
| | | withSubscriptions: true, |
| | | success: (res) => { |
| | | console.log('微信订é
ç¶ææ¥è¯¢ç»æï¼', res) |
| | | |
| | | // æ£æ¥subscriptionsSetting䏿¯å¦æè¯¥æ¨¡æ¿IDçè®°å½ |
| | | if (res.subscriptionsSetting && res.subscriptionsSetting.mainSwitch) { |
| | | const subscribeStatus = res.subscriptionsSetting.mainSwitch; |
| | | resolve(subscribeStatus) |
| | | // 'accept' è¡¨ç¤ºç¨æ·åæè®¢é
ï¼'reject' 表示æç»ï¼'ban' 表示被å°ç¦ |
| | | // const isSubscribed = subscribeStatus === 'accept' |
| | | // console.log(`模æ¿ID ${templateId} 订é
ç¶æï¼`, subscribeStatus, 'æ¯å¦å·²è®¢é
ï¼', isSubscribed) |
| | | // resolve(isSubscribed) |
| | | } else { |
| | | console.log('æªæ¾å°è®¢é
设置信æ¯ï¼è§ä¸ºæªè®¢é
') |
| | | resolve(false) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error('è·å微信设置失败ï¼', err) |
| | | resolve(false) |
| | | } |
| | | }) |
| | | }) |
| | | .catch((error) => { |
| | | console.error('å è½½é
ç½®å¤±è´¥ï¼æ æ³æ£æ¥è®¢é
ç¶æï¼', error) |
| | | resolve(false) |
| | | }) |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | console.log('é微信å°ç¨åºç¯å¢ï¼æ æ³æ£æ¥è®¢é
ç¶æ') |
| | | resolve(false) |
| | | // #endif |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * æ£æ¥è®¢é
ç¶æï¼ç»¼åæ£æ¥ï¼ |
| | | * å
æ£æ¥æ¬å°ç¶æï¼åæ£æ¥å¾®ä¿¡å®æ¹ç¶æ |
| | | * @returns {Promise<{local: boolean, wechat: boolean, needResubscribe: boolean}>} |
| | | */ |
| | | async checkSubscribeStatus() { |
| | | const localStatus = this.checkLocalSubscribeStatus() |
| | | const wechatStatus = await this.checkWechatSubscribeStatus() |
| | | |
| | | // 妿æ¬å°æ¾ç¤ºå·²è®¢é
ï¼ä½å¾®ä¿¡å®æ¹æ¾ç¤ºæªè®¢é
ï¼éè¦éæ°è®¢é
|
| | | const needResubscribe = wechatStatus |
| | | |
| | | if (needResubscribe) { |
| | | console.warn('æ¬å°ç¶æä¸å¾®ä¿¡å®æ¹ç¶æä¸ä¸è´ï¼éè¦éæ°è®¢é
') |
| | | // æ¸
餿¬å°è®°å½ |
| | | uni.removeStorageSync('hasSubscribedTaskNotify') |
| | | } |
| | | |
| | | return { |
| | | local: localStatus, |
| | | wechat: wechatStatus, |
| | | needResubscribe: needResubscribe, |
| | | isSubscribed: wechatStatus // ä»¥å¾®ä¿¡å®æ¹ç¶æä¸ºå |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¾ç¤ºè®¢é
ç¡®è®¤å¼¹çª |
| | | * @returns {Promise} |
| | | */ |
| | | showSubscribeConfirm() { |
| | | return new Promise((resolve, reject) => { |
| | | // #ifdef MP-WEIXIN |
| | | wx.showModal({ |
| | | title: 'å¼å¯ä»»å¡éç¥', |
| | | content: 'å¾éãæ»æ¯ä¿æä»¥ä¸éæ©ãï¼åç»æ°ä»»å¡å°èªå¨æ¨é~', |
| | | confirmText: 'å»å¼å¯', |
| | | cancelText: 'æä¸å¼å¯', |
| | | success(res) { |
| | | if (res.confirm) { |
| | | resolve() |
| | | } else { |
| | | reject(new Error('ç¨æ·åæ¶')) |
| | | } |
| | | }, |
| | | fail() { |
| | | reject(new Error('å¼¹çªå¤±è´¥')) |
| | | } |
| | | }) |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | uni.showToast({ |
| | | title: 'ä»
æ¯æå¾®ä¿¡å°ç¨åº', |
| | | icon: 'none' |
| | | }) |
| | | reject(new Error('ä»
æ¯æå¾®ä¿¡å°ç¨åº')) |
| | | // #endif |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * 订é
ä»»å¡éç¥ |
| | | * @param {Object} options é
ç½®é项 |
| | | * @param {boolean} options.showConfirm æ¯å¦æ¾ç¤ºç¡®è®¤å¼¹çªï¼é»è®¤true |
| | | * @param {Function} options.onSuccess æååè° |
| | | * @param {Function} options.onReject æç»åè° |
| | | * @param {Function} options.onFail 失败åè° |
| | | * @returns {Promise} |
| | | */ |
| | | async subscribeTaskNotify(options = {}) { |
| | | const { |
| | | showConfirm = true, |
| | | onSuccess, |
| | | onReject, |
| | | onFail |
| | | } = options |
| | | |
| | | try { |
| | | // å è½½é
ç½® |
| | | await this.loadWechatConfig() |
| | | |
| | | // æ£æ¥é
ç½®æ¯å¦å è½½ |
| | | if (!this.wechatConfig.taskNotifyTemplateId) { |
| | | uni.showToast({ |
| | | title: 'é
ç½®å è½½ä¸ï¼è¯·ç¨åéè¯', |
| | | icon: 'none' |
| | | }) |
| | | throw new Error('é
ç½®æªå è½½') |
| | | } |
| | | |
| | | // æ¾ç¤ºç¡®è®¤å¼¹çªï¼å¦æéè¦ï¼ |
| | | if (showConfirm) { |
| | | await this.showSubscribeConfirm() |
| | | } |
| | | |
| | | // å起订é
|
| | | return new Promise((resolve, reject) => { |
| | | // #ifdef MP-WEIXIN |
| | | wx.requestSubscribeMessage({ |
| | | tmplIds: [this.wechatConfig.taskNotifyTemplateId], |
| | | success: (res) => { |
| | | console.log('订é
æ¶æ¯ææç»æï¼', res) |
| | | const templateId = this.wechatConfig.taskNotifyTemplateId |
| | | |
| | | if (res[templateId] === 'accept') { |
| | | // è®°å½å·²è®¢é
|
| | | uni.setStorageSync('hasSubscribedTaskNotify', true) |
| | | uni.showToast({ |
| | | title: '订é
æå', |
| | | icon: 'success' |
| | | }) |
| | | |
| | | if (onSuccess) onSuccess() |
| | | resolve({ success: true, action: 'accept' }) |
| | | } else if (res[templateId] === 'reject') { |
| | | uni.showToast({ |
| | | title: 'æ¨æç»äºè®¢é
', |
| | | icon: 'none' |
| | | }) |
| | | |
| | | if (onReject) onReject() |
| | | resolve({ success: false, action: 'reject' }) |
| | | } else { |
| | | // å
¶ä»æ
åµï¼bançï¼ |
| | | resolve({ success: false, action: res[templateId] }) |
| | | } |
| | | }, |
| | | fail: (err) => { |
| | | console.error('订é
æ¶æ¯å¤±è´¥ï¼', err) |
| | | uni.showToast({ |
| | | title: '订é
失败', |
| | | icon: 'none' |
| | | }) |
| | | |
| | | if (onFail) onFail(err) |
| | | reject(err) |
| | | } |
| | | }) |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | uni.showToast({ |
| | | title: 'ä»
æ¯æå¾®ä¿¡å°ç¨åº', |
| | | icon: 'none' |
| | | }) |
| | | reject(new Error('ä»
æ¯æå¾®ä¿¡å°ç¨åº')) |
| | | // #endif |
| | | }) |
| | | } catch (error) { |
| | | console.error('订é
æµç¨å¼å¸¸ï¼', error) |
| | | throw error |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * å¿«é订é
ï¼å¸¦ç¡®è®¤å¼¹çªï¼ |
| | | * @returns {Promise} |
| | | */ |
| | | subscribeWithConfirm() { |
| | | return this.subscribeTaskNotify({ showConfirm: true }) |
| | | } |
| | | |
| | | /** |
| | | * ç´æ¥è®¢é
ï¼ä¸æ¾ç¤ºç¡®è®¤å¼¹çªï¼ |
| | | * @returns {Promise} |
| | | */ |
| | | subscribeDirect() { |
| | | return this.subscribeTaskNotify({ showConfirm: false }) |
| | | } |
| | | |
| | | /** |
| | | * èªå¨è®¢é
ï¼æºè½æ£æ¥ï¼ |
| | | * å¦æå·²è®¢é
åè·³è¿ï¼æªè®¢é
åæ¾ç¤ºç¡®è®¤å¼¹çª |
| | | * @param {Object} options é
ç½®é项 |
| | | * @param {boolean} options.force æ¯å¦å¼ºå¶æ¾ç¤ºè®¢é
å¼¹çªï¼é»è®¤false |
| | | * @returns {Promise} |
| | | */ |
| | | async autoSubscribe(options = {}) { |
| | | const { force = false } = options |
| | | |
| | | try { |
| | | // ç»¼åæ£æ¥è®¢é
ç¶æï¼æ¬å° + å¾®ä¿¡å®æ¹ï¼ |
| | | const status = await this.checkSubscribeStatus() |
| | | |
| | | console.log('订é
ç¶ææ£æ¥ç»æï¼', status) |
| | | |
| | | // å¦æå¾®ä¿¡å®æ¹ç¶ææ¾ç¤ºå·²è®¢é
ï¼ä¸ä¸å¼ºå¶è®¢é
|
| | | if (status.isSubscribed && !force) { |
| | | console.log('ç¨æ·å·²è®¢é
è¿ï¼å¾®ä¿¡å®æ¹ç¶æï¼ï¼è·³è¿èªå¨è®¢é
') |
| | | return { success: true, action: 'already_subscribed', skipped: true, status } |
| | | } |
| | | |
| | | // 妿éè¦éæ°è®¢é
ææªè®¢é
|
| | | if (status.needResubscribe) { |
| | | console.log('æ£æµå°è®¢é
ç¶æå¤±æï¼è§¦åéæ°è®¢é
æµç¨') |
| | | } else { |
| | | console.log('ç¨æ·æªè®¢é
ï¼è§¦åèªå¨è®¢é
æµç¨') |
| | | } |
| | | |
| | | // æ¾ç¤ºç¡®è®¤å¼¹çªå¹¶è®¢é
ç´æ¥é»è®¤è®¢é
|
| | | const result = await this.subscribeWithConfirm(); |
| | | return { ...result, status } |
| | | } catch (error) { |
| | | console.log('èªå¨è®¢é
æµç¨å¼å¸¸ï¼', error) |
| | | return { success: false, action: 'error', error } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * é置订é
ç¶æ |
| | | */ |
| | | resetSubscribeStatus() { |
| | | uni.removeStorageSync('hasSubscribedTaskNotify') |
| | | } |
| | | } |
| | | |
| | | // å建åä¾ |
| | | const subscribeManager = new SubscribeManager() |
| | | |
| | | export default subscribeManager |
| | |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-quartz</artifactId> |
| | | </dependency> |
| | | |
| | | <dependency> |
| | | <groupId>org.dom4j</groupId> |
| | | <artifactId>dom4j</artifactId> |
| | | <version>2.1.4</version> |
| | | </dependency> |
| | | <!-- 代ç çæ--> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-generator</artifactId> |
| | | </dependency> |
| | | |
| | | |
| | | <!-- æ¯ä»æ¨¡å --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | |
| | | package com.ruoyi.web.controller.system; |
| | | |
| | | import java.io.ByteArrayInputStream; |
| | | import java.util.*; |
| | | import java.text.SimpleDateFormat; |
| | | import java.text.ParseException; |
| | |
| | | import java.net.URLEncoder; |
| | | import java.nio.charset.StandardCharsets; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.ruoyi.system.domain.*; |
| | | import com.ruoyi.system.service.*; |
| | | import com.ruoyi.common.config.TencentMapConfig; |
| | | import com.ruoyi.common.config.BaiduMapConfig; |
| | | import com.ruoyi.common.config.TiandituMapConfig; |
| | | import org.dom4j.DocumentHelper; |
| | | import org.dom4j.Element; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.common.core.page.TableDataInfo; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | |
| | | |
| | | import javax.annotation.Resource; |
| | | |
| | | |
| | | /** |
| | | * 车è¾GPSåæ Controller |
| | |
| | | |
| | | @Autowired |
| | | private TiandituMapConfig tiandituMapConfig; |
| | | |
| | | |
| | | @Resource(name = "tiandituMapService") |
| | | private IMapService tiandituMapService; |
| | | |
| | | @Resource(name = "baiduMapService") |
| | | private IMapService baiduMapService; |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾GPSåæ å表 |
| | |
| | | return AjaxResult.error("è·ç¦»è®¡ç®å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * ç¾åº¦å°å¾éå°åè§£ææ¥å£ä»£ç |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/baidu/reverseGeocoding") |
| | | public AjaxResult baiduResolveAddress(Double lng, Double lat) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (lat == null || lng == null) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°ç»çº¬åº¦åæ "); |
| | | } |
| | | |
| | | String response= baiduMapService.reverseGeocoding(lng, lat); |
| | | // åéHTTPè¯·æ± |
| | | Map<String,String> objResult=new HashMap<>(); |
| | | objResult.put("address",response); |
| | | return AjaxResult.success("æ¥è¯¢æå", objResult); |
| | | }catch (Exception e){ |
| | | logger.error("ç¾åº¦éå°åè§£æå¤±è´¥: lat={}, lng={}", lat, lng, e); |
| | | return AjaxResult.error("ç¾åº¦éå°åè§£æå¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | /** |
| | | * ç¾åº¦å°å¾å°çç¼ç æ¥å£ä»£çï¼å°åè½¬åæ ï¼ |
| | | */ |
| | |
| | | if (address == null || address.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°å°åä¿¡æ¯"); |
| | | } |
| | | |
| | | // æå»ºç¾åº¦å°å¾å°çç¼ç API URL |
| | | String url = "https://api.map.baidu.com/geocoding/v3/"; |
| | | String params = "address=" + URLEncoder.encode(address, StandardCharsets.UTF_8.toString()) + |
| | | (city != null && !city.trim().isEmpty() ? |
| | | "&city=" + URLEncoder.encode(city, StandardCharsets.UTF_8.toString()) : "") + |
| | | "&output=json" + |
| | | "&ak=" + baiduMapConfig.getAk(); |
| | | |
| | | logger.info("ç¾åº¦å°å¾å°çç¼ç 请æ±: address={}, city={}", address, city); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | Map<String,Double> objResult=baiduMapService.geocoding(address, city); |
| | | |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | return AjaxResult.success("æ¥è¯¢æå", objResult); |
| | | } catch (Exception e) { |
| | | logger.error("ç¾åº¦å°å¾å°çç¼ç 失败", e); |
| | | return AjaxResult.error("å°çç¼ç 失败ï¼" + e.getMessage()); |
| | |
| | | if (address == null || address.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°å°åä¿¡æ¯"); |
| | | } |
| | | |
| | | // æå»ºå¤©å°å¾å°çç¼ç API URL |
| | | String url = "http://api.tianditu.gov.cn/geocoder"; |
| | | String params = "ds={\"keyWord\":\"" + address + "\"}&tk=" + tiandituMapConfig.getTk(); |
| | | |
| | | logger.info("天å°å¾å°çç¼ç 请æ±: address={}", address); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | |
| | | Map<String,Double> resultMap =tiandituMapService.geocoding(address,""); |
| | | |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | return AjaxResult.success("æ¥è¯¢æå", resultMap); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾å°çç¼ç 失败", e); |
| | | return AjaxResult.error("å°çç¼ç 失败ï¼" + e.getMessage()); |
| | |
| | | Double.isInfinite(lat) || Double.isInfinite(lon)) { |
| | | return AjaxResult.error("åæ°æ æï¼ç»çº¬åº¦åæ æ ¼å¼é误"); |
| | | } |
| | | String address=this.tiandituMapService.reverseGeocoding(lon, lat); |
| | | |
| | | |
| | | // æå»ºå¤©å°å¾éå°çç¼ç API URL |
| | | String url = "http://api.tianditu.gov.cn/geocoder"; |
| | | String params = "postStr={\"lon\":" + lon + ",\"lat\":" + lat + ",\"ver\":1}" + |
| | | "&type=geocode" + |
| | | "&tk=" + tiandituMapConfig.getTk(); |
| | | |
| | | logger.info("天å°å¾éå°çç¼ç 请æ±: lon={}, lat={}", lon, lat); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | |
| | | Map<String,String> resultMap = new HashMap<>(); |
| | | resultMap.put("address",address); |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | return AjaxResult.success("æ¥è¯¢æå",resultMap); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾éå°çç¼ç 失败: lon={}, lat={}", lon, lat, e); |
| | | return AjaxResult.error("éå°çç¼ç 失败ï¼" + e.getMessage()); |
| | |
| | | toAddress == null || toAddress.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°èµ·ç¹æç»ç¹å°å"); |
| | | } |
| | | |
| | | logger.info("å¼å§è®¡ç®å°åè·ç¦»: fromAddress={}, toAddress={}", fromAddress, toAddress); |
| | | |
| | | // ç¬¬ä¸æ¥ï¼èµ·ç¹å°åè½¬åæ |
| | | String geocodingUrl1 = "http://api.tianditu.gov.cn/geocoder"; |
| | | String geocodingParams1 = "ds={\"keyWord\":\"" + fromAddress + "\"}" + |
| | | "&tk=" + tiandituMapConfig.getTk(); |
| | | |
| | | String geocodingResponse1 = HttpUtils.sendGet(geocodingUrl1, geocodingParams1); |
| | | logger.info("èµ·ç¹å°çç¼ç ååº: {}", geocodingResponse1); |
| | | |
| | | // è§£æèµ·ç¹åæ |
| | | com.alibaba.fastjson2.JSONObject geocodingJson1 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse1); |
| | | if (!"0".equals(geocodingJson1.getString("status"))) { |
| | | logger.error("èµ·ç¹å°çç¼ç 失败: {}", geocodingResponse1); |
| | | return AjaxResult.error("èµ·ç¹å°åè§£æå¤±è´¥"); |
| | | } |
| | | com.alibaba.fastjson2.JSONObject location1 = geocodingJson1.getJSONObject("location"); |
| | | if (location1 == null) { |
| | | return AjaxResult.error("èµ·ç¹å°åæªæ¾å°å¯¹åºåæ "); |
| | | } |
| | | double fromLon = location1.getDouble("lon"); |
| | | double fromLat = location1.getDouble("lat"); |
| | | logger.info("èµ·ç¹åæ : lon={}, lat={}", fromLon, fromLat); |
| | | |
| | | // ç¬¬äºæ¥ï¼ç»ç¹å°åè½¬åæ |
| | | String geocodingUrl2 = "http://api.tianditu.gov.cn/geocoder"; |
| | | String geocodingParams2 = "ds={\"keyWord\":\"" + toAddress + "\"}" + |
| | | "&tk=" + tiandituMapConfig.getTk(); |
| | | |
| | | String geocodingResponse2 = HttpUtils.sendGet(geocodingUrl2, geocodingParams2); |
| | | logger.info("ç»ç¹å°çç¼ç ååº: {}", geocodingResponse2); |
| | | |
| | | // è§£æç»ç¹åæ |
| | | com.alibaba.fastjson2.JSONObject geocodingJson2 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse2); |
| | | if (!"0".equals(geocodingJson2.getString("status"))) { |
| | | logger.error("ç»ç¹å°çç¼ç 失败: {}", geocodingResponse2); |
| | | return AjaxResult.error("ç»ç¹å°åè§£æå¤±è´¥"); |
| | | } |
| | | com.alibaba.fastjson2.JSONObject location2 = geocodingJson2.getJSONObject("location"); |
| | | if (location2 == null) { |
| | | return AjaxResult.error("ç»ç¹å°åæªæ¾å°å¯¹åºåæ "); |
| | | } |
| | | double toLon = location2.getDouble("lon"); |
| | | double toLat = location2.getDouble("lat"); |
| | | |
| | | Map<String,Double> fromLngLat= tiandituMapService.geocoding(fromAddress, null); |
| | | |
| | | double fromLng = fromLngLat.get("lng"); |
| | | double fromLat = fromLngLat.get("lat"); |
| | | logger.info("èµ·ç¹åæ : lon={}, lat={}", fromLng, fromLat); |
| | | |
| | | Map<String,Double> toLngLat = tiandituMapService.geocoding(toAddress, null); |
| | | double toLon = toLngLat.get("lng"); |
| | | double toLat = toLngLat.get("lat"); |
| | | logger.info("ç»ç¹åæ : lon={}, lat={}", toLon, toLat); |
| | | |
| | | // ç¬¬ä¸æ¥ï¼è°ç¨è·¯å¾è§åæ¥å£è®¡ç®è·ç¦» |
| | | String routeUrl = "http://api.tianditu.gov.cn/drive"; |
| | | String orig = fromLon + "," + fromLat; |
| | | String orig = fromLng + "," + fromLat; |
| | | String dest = toLon + "," + toLat; |
| | | String routeParams = "postStr={\"orig\":\"" + orig + "\",\"dest\":\"" + dest + "\",\"style\":\"0\"}" + |
| | | "&tk=" + tiandituMapConfig.getTk(); |
| | |
| | | logger.info("è·¯å¾è§å请æ±: orig={}, dest={}", orig, dest); |
| | | String routeResponse = HttpUtils.sendGet(routeUrl, routeParams); |
| | | logger.info("è·¯å¾è§åååº: {}", routeResponse); |
| | | |
| | | // è§£æè·ç¦»ç»æ |
| | | com.alibaba.fastjson2.JSONObject routeJson = com.alibaba.fastjson2.JSONObject.parseObject(routeResponse); |
| | | if (!"0".equals(routeJson.getString("status"))) { |
| | | logger.error("è·¯å¾è§å失败: {}", routeResponse); |
| | | return AjaxResult.error("è·¯å¾è§å失败"); |
| | | //<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
| | | //<result dest="113.3472,23.16957" mid="" orig="113.373308,23.136699"> |
| | | // |
| | | // <parameters> |
| | | // |
| | | // <orig>113.373308,23.136699</orig> |
| | | // |
| | | // <dest>113.3472,23.16957</dest> |
| | | // |
| | | // <mid/> |
| | | // |
| | | // <key/> |
| | | // |
| | | // <width>600</width> |
| | | // |
| | | // <height>400</height> |
| | | // |
| | | // <style>0</style> |
| | | // |
| | | // <version/> |
| | | // |
| | | // <sort/> |
| | | // |
| | | // </parameters> |
| | | // |
| | | // <routes count="9" time="0.0"> |
| | | // |
| | | // <item id="0"> |
| | | // |
| | | // <strguide>仿£ å®è·¯å西åºå,æ²¿æ£ å®è·¯èµ°100米并左转,</strguide> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <streetName>æ£ å®è·¯</streetName> |
| | | // |
| | | // <nextStreetName/> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37323,23.13677</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="1"> |
| | | // |
| | | // <strguide>èµ°100米并å广åå¿«é/çé303/ååå¿«é/çé81/ç¯åé«é/åè§è·¯/岿/çé3/å¹¿æ·±æ²¿æ±æ¹åè¿å
¥ç§éµä¸è·¯,</strguide> |
| | | // |
| | | // <signage>广åå¿«é/çé303/ååå¿«é/çé81/ç¯åé«é/åè§è·¯/岿/çé3/广深沿æ±</signage> |
| | | // |
| | | // <streetName/> |
| | | // |
| | | // <nextStreetName>ç§éµä¸è·¯</nextStreetName> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37185,23.13699</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="2"> |
| | | // |
| | | // <strguide>沿ç§éµä¸è·¯èµ°0.6å
¬éå¹¶å广åå¿«é(西è¡)/çé303/ååå¿«éæ¹åè¿å
¥å¹¿åå¿«éè·¯,</strguide> |
| | | // |
| | | // <signage>广åå¿«é(西è¡)/çé303/ååå¿«é</signage> |
| | | // |
| | | // <streetName>ç§éµä¸è·¯</streetName> |
| | | // |
| | | // <nextStreetName>广åå¿«éè·¯</nextStreetName> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37107,23.13648</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="3"> |
| | | // |
| | | // <strguide>沿广åå¿«é路走1.9å
¬éå¹¶ä»ååå¿«é/广å·åç«/广å·åç«/ç¯åé«é(åç¯)/广å·é¿é/帽峰山/ååå¿«é(åè¡)/å½é4/广å·ç¯åé«é/ååå¿«é(西)/京港澳é«é/å¹¿å·æºåºé«é/广河é«é/é¶å
³/çé81/çé8æ¹ååéè¿å
¥ååç«äº¤æ¡¥,</strguide> |
| | | // |
| | | // <signage>ååå¿«é/广å·åç«/广å·åç«/ç¯åé«é(åç¯)/广å·é¿é/帽峰山/ååå¿«é(åè¡)/å½é4/广å·ç¯åé«é/ååå¿«é(西)/京港澳é«é/å¹¿å·æºåºé«é/广河é«é/é¶å
³/çé81/çé8æ¹ååé</signage> |
| | | // |
| | | // <streetName>广åå¿«éè·¯</streetName> |
| | | // |
| | | // <nextStreetName>ååç«äº¤æ¡¥</nextStreetName> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37139,23.14206</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="4"> |
| | | // |
| | | // <strguide>沿ååç«äº¤æ¡¥çæ¡¥ååèµ°0.6å
¬éå¹¶ç´è¡å°çé4/ååå¿«é,</strguide> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <streetName>ååç«äº¤æ¡¥</streetName> |
| | | // |
| | | // <nextStreetName>çé4/ååå¿«é</nextStreetName> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.35685,23.14669</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="5"> |
| | | // |
| | | // <strguide>沿çé4/ååå¿«éèµ°0.6å
¬éå¹¶ä»å¤©æ²³å®¢è¿ç«/çé15/å
å²/ä½å±±/æ·±å³/广å·ç¯åé«é/æ²æµ·é«éæ¯çº¿/ååå¿«é管çä¸å¿/岿ç«äº¤/çé81æ¹ååéè¿å
¥å²æç«äº¤,</strguide> |
| | | // |
| | | // <signage>天河客è¿ç«/çé15/å
å²/ä½å±±/æ·±å³/广å·ç¯åé«é/æ²æµ·é«éæ¯çº¿/ååå¿«é管çä¸å¿/岿ç«äº¤/çé81æ¹ååé</signage> |
| | | // |
| | | // <streetName>çé4/ååå¿«é</streetName> |
| | | // |
| | | // <nextStreetName>岿ç«äº¤</nextStreetName> |
| | | // |
| | | // <tollStatus>1</tollStatus> |
| | | // |
| | | // <turnlatlon>113.35518,23.15157</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="6"> |
| | | // |
| | | // <strguide>æ²¿å²æç«äº¤çæ¡¥å西åèµ°0.5å
¬éå¹¶ä»å¤©æ²³å®¢è¿ç«/å
å²/广æ±è·¯/å²æè·¯/å¸äº¤è¦æ¯éåºå£é©¶ç¦»å¹¶è¿å
¥é¿å
´è·¯,</strguide> |
| | | // |
| | | // <signage>天河客è¿ç«/å
å²/广æ±è·¯/å²æè·¯/å¸äº¤è¦æ¯éåºå£</signage> |
| | | // |
| | | // <streetName>岿ç«äº¤</streetName> |
| | | // |
| | | // <nextStreetName>é¿å
´è·¯</nextStreetName> |
| | | // |
| | | // <tollStatus>1</tollStatus> |
| | | // |
| | | // <turnlatlon>113.35731,23.15636</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="7"> |
| | | // |
| | | // <strguide>沿é¿å
´è·¯èµ°2.8å
¬éå¹¶å³è½¬å°é¿æ¹´ä¸è·¯,</strguide> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <streetName>é¿å
´è·¯</streetName> |
| | | // |
| | | // <nextStreetName>é¿æ¹´ä¸è·¯</nextStreetName> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.35829,23.16086</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="8"> |
| | | // |
| | | // <strguide>æ²¿é¿æ¹´ä¸è·¯èµ°100ç±³å°è¾¾ç®çå°ã</strguide> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <streetName>é¿æ¹´ä¸è·¯</streetName> |
| | | // |
| | | // <nextStreetName/> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.34714,23.17047</turnlatlon> |
| | | // |
| | | // </item> |
| | | // |
| | | // </routes> |
| | | // |
| | | // <simple> |
| | | // |
| | | // <item id="0"> |
| | | // |
| | | // <strguide>仿£ å®è·¯åºå,è¿å
¥ç§éµä¸è·¯ã</strguide> |
| | | // |
| | | // <streetNames>æ£ å®è·¯</streetNames> |
| | | // |
| | | // <lastStreetName/> |
| | | // |
| | | // <linkStreetName>ç§éµä¸è·¯</linkStreetName> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37323,23.13677</turnlatlon> |
| | | // |
| | | // <streetLatLon>113.37323,23.13677;113.37291,23.13683;113.37272,23.13687;113.37272,23.13687;113.37265,23.13688;113.37265,23.13688;113.37227,23.13696;113.37227,23.13696;113.37209,23.13699;113.37201,23.13696;113.37201,23.13696;113.37185,23.13699;</streetLatLon> |
| | | // |
| | | // <streetDistance>144.0</streetDistance> |
| | | // |
| | | // <segmentNumber>0</segmentNumber> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="1"> |
| | | // |
| | | // <strguide>沿ç§éµä¸è·¯è¡é©¶,å广åå¿«é(西è¡)/çé303/ååå¿«éæ¹å,è¿å
¥çé4/ååå¿«éã</strguide> |
| | | // |
| | | // <streetNames/> |
| | | // |
| | | // <lastStreetName>ç§éµä¸è·¯</lastStreetName> |
| | | // |
| | | // <linkStreetName>çé4/ååå¿«é</linkStreetName> |
| | | // |
| | | // <signage>广åå¿«é(西è¡)/çé303/ååå¿«é</signage> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.37107,23.13648</turnlatlon> |
| | | // |
| | | // <streetLatLon>113.37185,23.13699;113.37174,23.13683;113.3714,23.13649;113.37134,23.13645;113.37126,23.13643;113.37116,23.13644;113.37107,23.13648;113.37107,23.13648;113.37103,23.13657;113.37091,23.13683;113.37091,23.13683;113.37086,23.13693;113.3708,23.13705;113.3708,23.13705;113.37075,23.13717;113.37075,23.13717;113.37069,23.1373;113.37069,23.1373;113.37067,23.13735;113.37067,23.13735;113.3706,23.13755;113.37057,23.13765;113.37055,23.13779;113.37054,23.13794;113.37054,23.13804;113.37054,23.13814;113.37054,23.13831;113.37055,23.13844;113.37055,23.13844;113.37056,23.13855;113.37058,23.13865;113.3706,23.13878;113.37062,23.13884;113.37068,23.13911;113.37073,23.13935;113.37075,23.13944;113.37079,23.1396;113.3708,23.13964;113.37083,23.13975;113.37083,23.13975;113.37084,23.1398;113.37084,23.1398;113.37087,23.13998;113.3709,23.1401;113.37097,23.14039;113.371,23.14051;113.371,23.14051;113.3711,23.1409;113.37114,23.14105;113.37116,23.14115;113.3712,23.14127;113.37121,23.14135;113.37124,23.14146;113.37125,23.14153;113.37126,23.14155;113.37129,23.14167;113.37129,23.14167;113.37134,23.14187;113.37136,23.14194;113.37139,23.14206;</streetLatLon> |
| | | // |
| | | // <streetDistance>748.0</streetDistance> |
| | | // |
| | | // <segmentNumber>1-2</segmentNumber> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="2"> |
| | | // |
| | | // <strguide>沿çé4/ååå¿«é,岿ç«äº¤,è¡é©¶å°å¹¿åå¿«éè·¯,å¨å¤©æ²³å®¢è¿ç«/å
å²/广æ±è·¯/å²æè·¯/å¸äº¤è¦æ¯éåºå£é©¶ç¦»,è¿å
¥é¿æ¹´ä¸è·¯ã</strguide> |
| | | // |
| | | // <streetNames>çé4/ååå¿«é,岿ç«äº¤,</streetNames> |
| | | // |
| | | // <lastStreetName>广åå¿«éè·¯</lastStreetName> |
| | | // |
| | | // <linkStreetName>é¿æ¹´ä¸è·¯</linkStreetName> |
| | | // |
| | | // <signage>天河客è¿ç«/å
å²/广æ±è·¯/å²æè·¯/å¸äº¤è¦æ¯éåºå£</signage> |
| | | // |
| | | // <tollStatus>2</tollStatus> |
| | | // |
| | | // <turnlatlon>113.35731,23.15636</turnlatlon> |
| | | // |
| | | // <streetLatLon>113.37139,23.14206;113.37145,23.14219;113.37151,23.1423;113.37157,23.14241;113.37164,23.14249;113.37171,23.14256;113.37175,23.1426;113.37179,23.14263;113.37182,23.14265;113.37186,23.14267;113.37192,23.14269;113.37196,23.1427;113.37206,23.14271;113.37216,23.14269;113.37222,23.14267;113.37229,23.14264;113.37234,23.14261;113.37239,23.14257;113.37243,23.14251;113.37247,23.14246;113.3725,23.14237;113.37251,23.14231;113.37251,23.14226;113.37251,23.14222;113.37249,23.14215;113.37248,23.14212;113.37247,23.14208;113.37245,23.14203;113.37242,23.14198;113.37235,23.14191;113.37226,23.14182;113.37215,23.14174;113.37206,23.14169;113.37202,23.14167;113.37183,23.1416;113.37169,23.14157;113.37157,23.14155;113.37145,23.14153;113.37131,23.14151;113.37131,23.14151;113.37125,23.14153;113.37115,23.14156;113.37049,23.14178;113.37036,23.14183;113.37022,23.14188;113.37006,23.14194;113.36995,23.14197;113.36995,23.14197;113.36986,23.14199;113.36979,23.142;113.36956,23.14203;113.36956,23.14203;113.36949,23.14205;113.36949,23.14205;113.3693,23.14213;113.3693,23.14213;113.3692,23.14218;113.3692,23.14218;113.3691,23.14223;113.3691,23.14223;113.36837,23.1425;113.36837,23.1425;113.36735,23.14293;113.36735,23.14293;113.36683,23.14314;113.36683,23.14314;113.36454,23.14409;113.36454,23.14409;113.36432,23.14418;113.36413,23.14426;113.3637,23.14444;113.3637,23.14444;113.36214,23.14505;113.36138,23.14532;113.36138,23.14532;113.36131,23.14535;113.36131,23.14535;113.36113,23.14541;113.36113,23.14541;113.36101,23.14545;113.36089,23.1455;113.36071,23.14556;113.36071,23.14556;113.36062,23.14559;113.36052,23.14562;113.36052,23.14562;113.36024,23.1457;113.36015,23.14573;113.36015,23.14573;113.35987,23.14581;113.35969,23.14587;113.35818,23.1463;113.35818,23.1463;113.35777,23.14642;113.35777,23.14642;113.35766,23.14645;113.35766,23.14645;113.35762,23.14647;113.35762,23.14647;113.35736,23.14655;113.35736,23.14655;113.35685,23.14669;113.35685,23.14669;113.35657,23.14695;113.35642,23.14713;113.35642,23.14713;113.35637,23.14718;113.3562,23.14738;113.35586,23.14787;113.35582,23.14793;113.35572,23.14812;113.35572,23.14812;113.35557,23.14838;113.35554,23.14844;113.35554,23.14844;113.35545,23.14854;113.35533,23.14872;113.35533,23.14872;113.35529,23.14878;113.35529,23.14878;113.355,23.14912;113.35492,23.14923;113.35486,23.1493;113.35483,23.14936;113.3548,23.14942;113.3548,23.14942;113.35473,23.14964;113.35472,23.14973;113.35472,23.14973;113.35471,23.14981;113.35473,23.15003;113.35485,23.15044;113.35509,23.1512;113.35517,23.15145;113.35518,23.15151;113.35518,23.15157;113.35518,23.15157;113.35523,23.15169;113.35523,23.15169;113.35526,23.15178;113.35526,23.15178;113.35531,23.15192;113.35531,23.15192;113.35534,23.15199;113.35541,23.15216;113.35547,23.15233;113.35554,23.1525;113.35568,23.15287;113.35584,23.15323;113.35591,23.15342;113.35598,23.15358;113.35609,23.15379;113.35617,23.15394;113.35629,23.15421;113.35646,23.15457;113.35648,23.15461;113.35652,23.15471;113.35654,23.15475;113.35673,23.15515;113.35677,23.15524;113.35677,23.15524;113.35693,23.15556;113.35697,23.15564;113.35709,23.1559;113.35709,23.1559;113.35731,23.15636;113.35731,23.15636;113.35756,23.15669;113.35775,23.15697;113.3579,23.15725;113.35805,23.15752;113.35805,23.15752;113.35841,23.15824;113.35865,23.15872;113.3587,23.15889;113.3587,23.15889;113.35879,23.15912;113.35883,23.15927;113.35885,23.15938;113.35886,23.15948;113.35884,23.1596;113.35882,23.15978;113.35878,23.15994;113.35868,23.16016;113.35859,23.16034;113.35855,23.16041;113.35849,23.1605;113.35843,23.16062;113.35829,23.16086;</streetLatLon> |
| | | // |
| | | // <streetDistance>3669.0</streetDistance> |
| | | // |
| | | // <segmentNumber>3-6</segmentNumber> |
| | | // |
| | | // </item> |
| | | // |
| | | // <item id="3"> |
| | | // |
| | | // <strguide>æ²¿é¿æ¹´ä¸è·¯è¡é©¶å°ç®çå°ã</strguide> |
| | | // |
| | | // <streetNames>é¿æ¹´ä¸è·¯</streetNames> |
| | | // |
| | | // <lastStreetName/> |
| | | // |
| | | // <linkStreetName/> |
| | | // |
| | | // <signage/> |
| | | // |
| | | // <tollStatus>0</tollStatus> |
| | | // |
| | | // <turnlatlon>113.34714,23.17047</turnlatlon> |
| | | // |
| | | // <streetLatLon>113.34714,23.17047;113.34711,23.1703;113.34708,23.16988;113.34708,23.16988;113.34705,23.16957;</streetLatLon> |
| | | // |
| | | // <streetDistance>101.0</streetDistance> |
| | | // |
| | | // <segmentNumber>7-8</segmentNumber> |
| | | // |
| | | // </item> |
| | | // |
| | | // </simple> |
| | | // |
| | | // <distance>7.48</distance> |
| | | // |
| | | // <duration>548.0</duration> |
| | | // |
| | | // <routelatlon>113.373308,23.136699;113.37323,23.13677;113.37272,23.13687;113.37265,23.13688;113.37227,23.13696;113.37209,23.13699;113.37201,23.13696;113.37185,23.13699;113.37185,23.13699;113.3714,23.13649;113.37126,23.13643;113.37116,23.13644;113.37107,23.13648;113.37107,23.13648;113.37091,23.13683;113.37075,23.13717;113.37057,23.13765;113.37054,23.13794;113.37055,23.13844;113.3706,23.13878;113.3708,23.13964;113.37083,23.13975;113.371,23.14051;113.37125,23.14153;113.37129,23.14167;113.37139,23.14206;113.37139,23.14206;113.37164,23.14249;113.37182,23.14265;113.37206,23.14271;113.37222,23.14267;113.37234,23.14261;113.3725,23.14237;113.37249,23.14215;113.37242,23.14198;113.37206,23.14169;113.37183,23.1416;113.37131,23.14151;113.37049,23.14178;113.36995,23.14197;113.36956,23.14203;113.36949,23.14205;113.3693,23.14213;113.3692,23.14218;113.3691,23.14223;113.36837,23.1425;113.36735,23.14293;113.36683,23.14314;113.36454,23.14409;113.3637,23.14444;113.36138,23.14532;113.36113,23.14541;113.36052,23.14562;113.35818,23.1463;113.35766,23.14645;113.35762,23.14647;113.35685,23.14669;113.35685,23.14669;113.35642,23.14713;113.35637,23.14718;113.35572,23.14812;113.35554,23.14844;113.35533,23.14872;113.35529,23.14878;113.35486,23.1493;113.3548,23.14942;113.35473,23.14964;113.35473,23.15003;113.35518,23.15151;113.35518,23.15157;113.35518,23.15157;113.35526,23.15178;113.35554,23.1525;113.35598,23.15358;113.35652,23.15471;113.35731,23.15636;113.35731,23.15636;113.35805,23.15752;113.3587,23.15889;113.35885,23.15938;113.35878,23.15994;113.35855,23.16041;113.35829,23.16086;113.35829,23.16086;113.35774,23.16199;113.35695,23.16368;113.35625,23.1651;113.35567,23.16616;113.35546,23.16638;113.35484,23.1669;113.3547,23.16697;113.35444,23.1671;113.35392,23.16726;113.35328,23.16732;113.35126,23.16726;113.35046,23.16736;113.34949,23.16765;113.34651,23.16884;113.34571,23.16921;113.34393,23.17017;113.34387,23.17021;113.34252,23.17092;113.34213,23.17112;113.34192,23.17139;113.34177,23.17169;113.34261,23.17145;113.34427,23.17102;113.34559,23.17069;113.34714,23.17047;113.34714,23.17047;113.34708,23.16988;113.34708,23.16988;113.34705,23.16957;113.3472,23.16957;</routelatlon> |
| | | // |
| | | // <mapinfo> |
| | | // |
| | | // <center>113.35754,23.15406</center> |
| | | // |
| | | // <scale>10</scale> |
| | | // |
| | | // </mapinfo> |
| | | //</result> |
| | | //è§£æè¿ä¸ªxml æ¿å°distanceåduration |
| | | if(routeResponse!=null) { |
| | | org.dom4j.Document doc = DocumentHelper.parseText(routeResponse); |
| | | |
| | | // 2. è·åæ ¹èç¹ <result> |
| | | Element rootElement = doc.getRootElement(); |
| | | |
| | | // 3. ç´æ¥è·åæ ¹èç¹ä¸ç <distance> åèç¹ææ¬å¼ |
| | | String distance = rootElement.elementText("distance"); |
| | | |
| | | // å¯éï¼è½¬ä¸ºDoubleç±»åï¼è¥éæ°å¼è®¡ç®ï¼ |
| | | Double distanceValue = Double.parseDouble(distance); |
| | | Map<String, Double> resultMap = new HashMap<>(); |
| | | resultMap.put("distance", distanceValue*1000); |
| | | |
| | | // 4. ç´æ¥è·åæ ¹èç¹ä¸ç <duration> åèç¹ææ¬å¼ |
| | | return AjaxResult.success("è®¡ç®æå", resultMap); |
| | | } |
| | | |
| | | // æåè·ç¦»ä¿¡æ¯ |
| | | com.alibaba.fastjson2.JSONObject result = routeJson.getJSONObject("result"); |
| | | if (result == null) { |
| | | logger.error("è·¯å¾è§åç»æä¸ºç©º"); |
| | | return AjaxResult.error("è·¯å¾è§å失败"); |
| | | else{ |
| | | return AjaxResult.error("计ç®è·ç¦»å¤±è´¥ï¼æ è¿åç»æ"); |
| | | } |
| | | |
| | | com.alibaba.fastjson2.JSONArray routes = result.getJSONArray("routes"); |
| | | if (routes == null || routes.isEmpty()) { |
| | | logger.error("æªæ¾å°è·¯çº¿ä¿¡æ¯"); |
| | | return AjaxResult.error("æªæ¾å°è·¯çº¿ä¿¡æ¯"); |
| | | } |
| | | |
| | | com.alibaba.fastjson2.JSONObject route = routes.getJSONObject(0); |
| | | double distance = route.getDoubleValue("distance"); // è·ç¦»ï¼åä½ï¼ç±³ |
| | | double duration = route.getDoubleValue("duration"); // æ¶é¿ï¼åä½ï¼ç§ |
| | | |
| | | logger.info("è®¡ç®æå: è·ç¦»={}ç±³, æ¶é¿={}ç§", distance, duration); |
| | | |
| | | // æå»ºè¿åç»æ |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | resultMap.put("distance", (int)distance); // è·ç¦»ï¼ç±³ï¼ |
| | | resultMap.put("duration", (int)duration); // æ¶é¿ï¼ç§ï¼ |
| | | resultMap.put("distanceKm", String.format("%.1f", distance / 1000.0)); // è·ç¦»ï¼å
¬éï¼ |
| | | resultMap.put("durationMin", (int)(duration / 60)); // æ¶é¿ï¼åéï¼ |
| | | |
| | | // èµ·ç¹åæ |
| | | Map<String, Object> fromLocation = new HashMap<>(); |
| | | fromLocation.put("lon", fromLon); |
| | | fromLocation.put("lat", fromLat); |
| | | resultMap.put("fromLocation", fromLocation); |
| | | |
| | | // ç»ç¹åæ |
| | | Map<String, Object> toLocation = new HashMap<>(); |
| | | toLocation.put("lon", toLon); |
| | | toLocation.put("lat", toLat); |
| | | resultMap.put("toLocation", toLocation); |
| | | |
| | | return AjaxResult.success("è®¡ç®æå", resultMap); |
| | | } catch (Exception e) { |
| | | logger.error("计ç®å°åè·ç¦»å¤±è´¥", e); |
| | | return AjaxResult.error("计ç®è·ç¦»å¤±è´¥ï¼" + e.getMessage()); |
| | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | logger.debug("天å°å¾æ®éæç´¢ååº: {}", response); |
| | | |
| | | // è§£æååº |
| | | com.alibaba.fastjson2.JSONObject jsonResponse = com.alibaba.fastjson2.JSONObject.parseObject(response); |
| | | if (!"0".equals(jsonResponse.getString("status"))) { |
| | | logger.error("æ®éæç´¢å¤±è´¥: {}", response); |
| | | // {"count":27,"resultType":1,"prompt":[{"type":4,"admins":[{"adminName":"广å·å¸","adminCode":156440100}]}], |
| | | //"pois":[{"address":"广ä¸ç广å·å¸å¤©æ²³åºæ£ ä¸è¡éååé¦å¤©æ²³æ£ ä¸åº","phone":"","poiType":"101","name":"ååé¦(å¤©æ²³æ£ ä¸åº)","source":"0","hotPointID":"17163AD907B29F24","lonlat":"113.36952,23.134056"},{"address":"åæ±è¡6å·","phone":"","poiType":"101","name":"å¤©æ²³æ£ ä¸Â·æºæ±park","source":"0","hotPointID":"C2635A7054C1EBB7","lonlat":"113.37003,23.14308"},{"address":"ç§æ°è·¯143~147å·","phone":"020-88524715","poiType":"101","name":"éåºå¾·åºç«é
(å¤©æ²³æ£ ä¸åº)","source":"0","hotPointID":"6919E1CFA6F6EF20","lonlat":"113.37627,23.127416"},{"address":"åæ±è¡6å·","phone":"020-87085713","poiType":"101","name":"å¤©æ²³æ£ ä¸Â·æºæ±PAPKå车åº","source":"0","hotPointID":"4AC84F8E1CB34C4E","lonlat":"113.36925,23.14256"},{"address":"广åä¸è·¯åæ±è¡6å·å¤©æ²³æ£ ä¸Â·æºæ±PAPKå°ä¸å车åº","phone":"020-87085713","poiType":"101","name":"å¤©æ²³æ£ ä¸Â·æºæ±PAPKç¹æ¯æè¶
级å
çµç«","source":"0","hotPointID":"70FC2D0A2D061E4B","lonlat":"113.3705,23.14359"},{"address":"æ£ å¾·åè·¯321","phone":"","poiType":"101","name":"ç³åå¤©æ²³æ£ ä¸åº","source":"0","hotPointID":"B97F4B20719EEBD1","lonlat":"113.38009,23.13434"},{"address":"ä¸å±±å¤§éæ£ ä¸è·¯ä¸é¸å¤§è¡èªç¼98å·2å·åº","phone":"13590139682","poiType":"101","name":"è±ç²çå¤©æ²³æ£ ä¸åº","source":"0","hotPointID":"174C40E7FBAE1187","lonlat":"113.37556,23.12844"},{"address":"æ£ ä¸äºç¤¾æ¶è¾¹è·¯69å·å
è¾å¤§å¦","phone":"020-66351119","poiType":"101","name":"ç´¢ç¹æ¥æèºé
åºå¤©æ²³æ£ ä¸åº","source":"0","hotPointID":"362052A27B9A1AC8","lonlat":"113.37161,23.12794"},{"address":"ä¸å±±å¤§é西493å·","phone":"020-38288788","poiType":"101","name":"ä¸å½çµä¿¡å¤©æ²³æ£ ä¸ç¦åè¥ä¸å
","source":"0","hotPointID":"D50C7774CFC6AA09","lonlat":"113.37455,23.12855"},{"address":"广ä¸ç广å·å¸å¤©æ²³åºæ£ ä¸è¡éæ¿è¾¾è¯è¨å¹è®ä¸å¿å¤©æ²³æ£ 䏿 ¡åº","phone":"","poiType":"101","name":"æ¿è¾¾è¯è¨å¹è®ä¸å¿å¤©æ²³æ£ 䏿 ¡åº","source":"0","hotPointID":"3CEE80F76558BDE4","lonlat":"113.373743,23.128796"}],"lineData":[],"status":{"cndesc":"æå¡æ£å¸¸","infocode":1000},"keyWord":"广å·å¤©æ²³æ£ ä¸"} |
| | | com.alibaba.fastjson.JSONObject jsonResponse = com.alibaba.fastjson.JSONObject.parseObject(response); |
| | | JSONObject objStatus=jsonResponse.getJSONObject("status"); |
| | | if (objStatus == null || objStatus.getInteger("infocode") != 1000) { |
| | | logger.error("天å°å¾æ®éæç´¢å¤±è´¥: {}", response); |
| | | return AjaxResult.error("å°åæç´¢å¤±è´¥"); |
| | | } |
| | | |
| | | // æåæç´¢ç»æ |
| | | com.alibaba.fastjson2.JSONArray results = jsonResponse.getJSONArray("pois"); |
| | | if (results == null || results.isEmpty()) { |
| | | logger.info("æªæ¾å°å¹é
çå°å"); |
| | | return AjaxResult.success("æ¥è¯¢æå", new ArrayList<>()); |
| | | } |
| | | |
| | | JSONArray results = jsonResponse.getJSONArray("pois"); |
| | | |
| | | |
| | | // æå»ºè¿åç»æ |
| | | List<Map<String, Object>> suggestions = new ArrayList<>(); |
| | | for (int i = 0; i < results.size(); i++) { |
| | | com.alibaba.fastjson2.JSONObject item = results.getJSONObject(i); |
| | | JSONObject item = results.getJSONObject(i); |
| | | |
| | | Map<String, Object> suggestion = new HashMap<>(); |
| | | suggestion.put("name", item.getString("name")); // åç§° |
| | | suggestion.put("address", item.getString("addr")); // å°å |
| | | suggestion.put("address", item.getString("address")); // å°å |
| | | suggestion.put("province", item.getString("prov")); // ç |
| | | suggestion.put("city", item.getString("city")); // å¸ |
| | | suggestion.put("district", item.getString("county")); // åºå¿ |
| | |
| | | suggestion.put("type", item.getString("type")); // ç±»å |
| | | |
| | | // ç»çº¬åº¦ä¿¡æ¯ |
| | | com.alibaba.fastjson2.JSONObject location = item.getJSONObject("lonlat"); |
| | | String location = item.getString("lonlat"); |
| | | if (location != null) { |
| | | Map<String, Object> locationMap = new HashMap<>(); |
| | | locationMap.put("lon", location.getDouble("lon")); |
| | | locationMap.put("lat", location.getDouble("lat")); |
| | | String[] locationArray = location.split(","); |
| | | locationMap.put("lng",Double.parseDouble(locationArray[0])); |
| | | locationMap.put("lat",Double.parseDouble(locationArray[1])); |
| | | suggestion.put("location", locationMap); |
| | | } |
| | | |
| | |
| | | @PutMapping("/status/{id}") |
| | | public AjaxResult updateStatus(@PathVariable("id") Long id, @RequestParam String status) { |
| | | try { |
| | | int result = sysTaskVehicleService.updateTaskVehicleStatus(id, status); |
| | | int result = sysTaskVehicleService.updateSysTaskVehicleStatus(id, status); |
| | | if (result > 0) { |
| | | return success("ç¶ææ´æ°æå"); |
| | | } else { |
| | |
| | | } |
| | | |
| | | /** |
| | | * æ¹éè·å车è¾å½åä»»å¡ç¶æ |
| | | * ä¼åæ¥å£ï¼åå°HTTPè¯·æ±æ¬¡æ° |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('task:vehicle:query')") |
| | | @PostMapping("/currentStatus") |
| | | public AjaxResult batchGetCurrentTaskStatus(@RequestBody List<Long> vehicleIds) { |
| | | try { |
| | | java.util.Map<Long, java.util.Map<String, Object>> statusMap = sysTaskVehicleService.batchGetVehicleCurrentTaskStatus(vehicleIds); |
| | | return success(statusMap); |
| | | } catch (Exception e) { |
| | | logger.error("æ¹éè·å车è¾ä»»å¡ç¶æå¤±è´¥", e); |
| | | return error("è·åç¶æå¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * åé
车è¾è¯·æ±å¯¹è±¡ |
| | | */ |
| | | public static class AssignVehicleRequest { |
| | |
| | | |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RequestParam; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.config.WechatConfig; |
| | | import com.ruoyi.common.utils.WechatUtils; |
| | | import com.ruoyi.common.annotation.Anonymous; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.system.domain.SysTask; |
| | | import com.ruoyi.system.domain.SysTaskEmergency; |
| | | import com.ruoyi.system.mapper.SysTaskMapper; |
| | | import com.ruoyi.system.mapper.SysTaskEmergencyMapper; |
| | | import com.ruoyi.system.mapper.SysUserMapper; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.system.service.IWechatTaskNotifyService; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 微信æ¥å£Controller |
| | |
| | | |
| | | @Autowired |
| | | private WechatConfig wechatConfig; |
| | | |
| | | @Autowired |
| | | private SysTaskMapper sysTaskMapper; |
| | | |
| | | @Autowired |
| | | private SysTaskEmergencyMapper sysTaskEmergencyMapper; |
| | | |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | @Autowired |
| | | private IWechatTaskNotifyService wechatTaskNotifyService; |
| | | |
| | | /** |
| | | * è·å微信AccessToken |
| | |
| | | return error("è·å微信AccessTokenå¼å¸¸ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è·å微信é
置信æ¯ï¼å¿å访é®ï¼ |
| | | * è¿åå端éè¦çé
置信æ¯ï¼å¦è®¢é
æ¶æ¯æ¨¡æ¿IDç |
| | | */ |
| | | @Anonymous |
| | | @GetMapping("/config") |
| | | public AjaxResult getConfig() { |
| | | Map<String, String> config = new HashMap<>(); |
| | | config.put("taskNotifyTemplateId", wechatConfig.getTaskNotifyTemplateId()); |
| | | config.put("taskDetailPage", wechatConfig.getTaskDetailPage()); |
| | | return success(config); |
| | | } |
| | | |
| | | /** |
| | | * å¿åæ¥å£ï¼æ ¹æ®ä»»å¡IDæå¨è§¦å䏿¬¡ä»»å¡å¾®ä¿¡éç¥ |
| | | * æ¹ä¾¿éè¿Postmanè°è¯ï¼åææ¯ä»»å¡å·²ææ§è¡äºº/å建人并ç»å®äºopenId |
| | | */ |
| | | @Anonymous |
| | | @PostMapping("/task/notify") |
| | | public AjaxResult notifyTaskByWechat(@RequestParam("taskId") Long taskId) { |
| | | if (taskId == null) { |
| | | return error("ä»»å¡IDä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); |
| | | if (task == null) { |
| | | return error("ä»»å¡ä¸åå¨"); |
| | | } |
| | | |
| | | // ç®åï¼ç»ä»»å¡å建人å䏿¡ï¼å¦æç»å®äºopenIdï¼ï¼æ¹ä¾¿å¿«ééªè¯æ¨¡æ¿å跳转 |
| | | if (task.getCreatorId() == null) { |
| | | return error("任塿ªæå®å建人"); |
| | | } |
| | | |
| | | SysUser creator = sysUserMapper.selectUserById(task.getCreatorId()); |
| | | if (creator == null || StringUtils.isEmpty(creator.getOpenId())) { |
| | | return error("å建人æªç»å®å¾®ä¿¡openId"); |
| | | } |
| | | |
| | | // è°ç¨ç»ä¸ç微信éç¥æå¡ |
| | | List<Long> userIds = new ArrayList<>(); |
| | | userIds.add(task.getCreatorId()); |
| | | int successCount = wechatTaskNotifyService.sendTaskNotifyMessage(taskId, userIds); |
| | | |
| | | if (successCount == 0) { |
| | | return error("微信éç¥åé失败"); |
| | | } |
| | | |
| | | return success("已触å微信éç¥ï¼æååéæ¡æ°ï¼" + successCount); |
| | | } |
| | | } |
| | |
| | | maxWait: 60000 |
| | | # é
ç½®è¿æ¥è¶
æ¶æ¶é´ |
| | | connectTimeout: 30000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ |
| | | socketTimeout: 60000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ï¼å¢å å°5åéï¼é¿å
å¤§æ°æ®éæ¥è¯¢è¶
æ¶ï¼ |
| | | socketTimeout: 300000 |
| | | # é
ç½®é´éå¤ä¹
æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å
³éç空é²è¿æ¥ï¼å使¯æ¯«ç§ |
| | | timeBetweenEvictionRunsMillis: 60000 |
| | | # é
ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿å°çåçæ¶é´ï¼å使¯æ¯«ç§ |
| | |
| | | maxWait: 60000 |
| | | # é
ç½®è¿æ¥è¶
æ¶æ¶é´ |
| | | connectTimeout: 30000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ |
| | | socketTimeout: 60000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ï¼å¢å å°5åéï¼é¿å
å¤§æ°æ®éæ¥è¯¢è¶
æ¶ï¼ |
| | | socketTimeout: 300000 |
| | | # é
ç½®é´éå¤ä¹
æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å
³éç空é²è¿æ¥ï¼å使¯æ¯«ç§ |
| | | timeBetweenEvictionRunsMillis: 60000 |
| | | # é
ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿å°çåçæ¶é´ï¼å使¯æ¯«ç§ |
| | |
| | | maxWait: 60000 |
| | | # é
ç½®è¿æ¥è¶
æ¶æ¶é´ |
| | | connectTimeout: 30000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ |
| | | socketTimeout: 60000 |
| | | # é
ç½®ç½ç»è¶
æ¶æ¶é´ï¼å¢å å°5åéï¼é¿å
å¤§æ°æ®éæ¥è¯¢è¶
æ¶ï¼ |
| | | socketTimeout: 300000 |
| | | # é
ç½®é´éå¤ä¹
æè¿è¡ä¸æ¬¡æ£æµï¼æ£æµéè¦å
³éç空é²è¿æ¥ï¼å使¯æ¯«ç§ |
| | | timeBetweenEvictionRunsMillis: 60000 |
| | | # é
ç½®ä¸ä¸ªè¿æ¥å¨æ± 䏿å°çåçæ¶é´ï¼å使¯æ¯«ç§ |
| | |
| | | transferConfigWeixin: |
| | | appId: wx40692cc44953a8cb |
| | | appSecret: 9638b7d8bb988e4daaac7ac35457f296 |
| | | # ä»»å¡éç¥æ¨¡æ¿IDï¼ä½ ç»çé£ä¸ªæ¨¡åIDï¼ |
| | | taskNotifyTemplateId: 4mJGnvzjPpQednzNwVgghN5CZ_jSirZToisISOpLfMU |
| | | # ä»»å¡è¯¦æ
页é¢è·¯å¾ï¼ç¨äºæ¼æ¥ ?id=taskIdï¼ |
| | | # åå
页é¢è·¯å¾æ ¼å¼ï¼åå
æ ¹ç®å½/页é¢è·¯å¾ï¼ä¸è¦åå¯¼ææ ï¼ |
| | | taskDetailPage: pagesTask/detail |
| | | # è
¾è®¯å°å¾é
ç½® |
| | | tencent: |
| | | map: |
| | |
| | | # provider: å°å¾æå¡æä¾åï¼å¯éå¼ï¼baiduï¼ç¾åº¦å°å¾ï¼ãtiandituï¼å¤©å°å¾ï¼ |
| | | map: |
| | | service: |
| | | provider: baidu # é»è®¤ä½¿ç¨ç¾åº¦å°å¾ |
| | | provider: tianditu # é»è®¤ä½¿ç¨ç¾åº¦å°å¾ tianditu /baidu |
| | | |
| | | # æ¯ä»é
ç½® |
| | | payment: |
| | |
| | | * å¯éå¼: baidu, tianditu |
| | | * é»è®¤: baidu |
| | | */ |
| | | private String provider = "baidu"; |
| | | private String provider = "tianditu"; |
| | | |
| | | public String getProvider() { |
| | | return provider; |
| | |
| | | /** 微信å°ç¨åºAppSecret */ |
| | | private String appSecret; |
| | | |
| | | /** ä»»å¡éç¥æ¨¡æ¿ID */ |
| | | private String taskNotifyTemplateId; |
| | | |
| | | /** ä»»å¡è¯¦æ
页é¢è·¯å¾ */ |
| | | private String taskDetailPage; |
| | | |
| | | public String getAppId() { |
| | | return appId; |
| | | } |
| | |
| | | public void setAppSecret(String appSecret) { |
| | | this.appSecret = appSecret; |
| | | } |
| | | |
| | | public String getTaskNotifyTemplateId() { |
| | | return taskNotifyTemplateId; |
| | | } |
| | | |
| | | public void setTaskNotifyTemplateId(String taskNotifyTemplateId) { |
| | | this.taskNotifyTemplateId = taskNotifyTemplateId; |
| | | } |
| | | |
| | | public String getTaskDetailPage() { |
| | | return taskDetailPage; |
| | | } |
| | | |
| | | public void setTaskDetailPage(String taskDetailPage) { |
| | | this.taskDetailPage = taskDetailPage; |
| | | } |
| | | } |
| | |
| | | public static String YYYY = "yyyy"; |
| | | |
| | | public static String YYYY_MM = "yyyy-MM"; |
| | | public static String YYYYMMDD="yyyyMMdd"; |
| | | |
| | | public static String YYYY_MM_DD = "yyyy-MM-dd"; |
| | | |
| New file |
| | |
| | | package com.ruoyi.common.utils; |
| | | |
| | | |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | |
| | | public class PlateNumberExtractor { |
| | | // ç份ç®ç§°æ£åçæ®µ |
| | | private static final String PROVINCE_ABBRS = "京|æ´¥|沪|æ¸|å|æ|è¾½|å|é»|è|æµ|ç|é½|èµ£|é²|豫|é|æ¹|粤|ç¼|å·|è´µ|äº|é|ç|é|è|æ¡|å®|æ°|è|港|æ¾³|å°"; |
| | | // 车çå·æ£åï¼ç份ç®ç§° + A-Z忝 + 5-6ä½åæ¯/æ°åï¼å«æ°è½æºè½¦çï¼ |
| | | private static final String PLATE_REGEX = "([" + PROVINCE_ABBRS + "][A-Z][A-Z0-9]{5,6})"; |
| | | private static final Pattern PLATE_PATTERN = Pattern.compile(PLATE_REGEX); |
| | | |
| | | /** |
| | | * æååç¬¦ä¸²ä¸ææç¬¦åè§åç车çå· |
| | | * @param input è¾å
¥å符串 |
| | | * @return 车çå·åè¡¨ï¼æ å¹é
åè¿å空åè¡¨ï¼ |
| | | */ |
| | | public static List<String> extractPlateNumbers(String input) { |
| | | List<String> plateNumbers = new ArrayList<>(); |
| | | if (input == null || input.isEmpty()) { |
| | | return plateNumbers; |
| | | } |
| | | |
| | | Matcher matcher = PLATE_PATTERN.matcher(input); |
| | | while (matcher.find()) { |
| | | System.out.println(matcher.group(1)); |
| | | plateNumbers.add(matcher.group(1)); |
| | | } |
| | | return plateNumbers; |
| | | } |
| | | |
| | | public static String extractPlateNumber(String input) { |
| | | |
| | | |
| | | Matcher matcher = PLATE_PATTERN.matcher(input); |
| | | if (matcher.find()) { |
| | | |
| | | return matcher.group(1); |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | // public static void main(String[] args) { |
| | | // String input = "xxx粤VSX120ï¼æµè¯äº¬A88888ï¼æ²ªB123456ï¼æ°è½æºï¼"; |
| | | // String plates = extractPlateNumber(input); |
| | | // System.out.println("æåç车çå·ï¼" + plates); |
| | | // // è¾åºï¼[粤VSX120, 京A88888, 沪B123456] |
| | | // } |
| | | } |
| | |
| | | } |
| | | return userAgent.toLowerCase().contains("micromessenger"); |
| | | } |
| | | |
| | | /** |
| | | * æªæthingç±»ååæ®µï¼å¾®ä¿¡è®¢é
æ¶æ¯thingç±»åæé¿20个å符 |
| | | * |
| | | * @param value åå§å符串 |
| | | * @return æªæåçåç¬¦ä¸²ï¼æé¿20åç¬¦ï¼ |
| | | */ |
| | | public static String truncateThingValue(String value) { |
| | | if (StringUtils.isEmpty(value)) { |
| | | return value; |
| | | } |
| | | |
| | | // 微信thingç±»åæé¿20个å符 |
| | | final int MAX_THING_LENGTH = 20; |
| | | |
| | | if (value.length() <= MAX_THING_LENGTH) { |
| | | return value; |
| | | } |
| | | |
| | | // æªæå¹¶æ·»å çç¥å·ï¼ç¡®ä¿æ»é¿åº¦ä¸è¶
è¿20 |
| | | return value.substring(0, MAX_THING_LENGTH - 1) + "â¦"; |
| | | } |
| | | |
| | | /** |
| | | * åéå°ç¨åºè®¢é
æ¶æ¯ |
| | | * |
| | | * @param accessToken 微信æ¥å£è°ç¨åè¯ |
| | | * @param touser æ¥æ¶äººopenId |
| | | * @param templateId 模æ¿ID |
| | | * @param page å°ç¨åºè·³è½¬é¡µé¢ |
| | | * @param data æ¨¡æ¿æ°æ®ï¼keyä¸ºåæ®µå(å¦thing1ãtime27)ï¼valueä¸ºåæ®µå¼ |
| | | * @return 微信è¿åç»æJSON |
| | | */ |
| | | public static JSONObject sendSubscribeMessage(String accessToken, |
| | | String touser, |
| | | String templateId, |
| | | String page, |
| | | Map<String, String> data) { |
| | | try { |
| | | if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(touser) || StringUtils.isEmpty(templateId)) { |
| | | log.error("åé订é
æ¶æ¯åæ°ä¸å®æ´ï¼accessToken={}, touser={}, templateId={}", accessToken, touser, templateId); |
| | | return null; |
| | | } |
| | | |
| | | String url = WECHAT_API_BASE_URL_SERVER + "/cgi-bin/message/subscribe/send?access_token=" + accessToken; |
| | | |
| | | Map<String, Object> body = new HashMap<>(); |
| | | body.put("touser", touser); |
| | | body.put("template_id", templateId); |
| | | if (StringUtils.isNotEmpty(page)) { |
| | | body.put("page", page); |
| | | } |
| | | body.put("miniprogram_state", "formal"); |
| | | |
| | | Map<String, Object> dataNode = new HashMap<>(); |
| | | if (data != null && !data.isEmpty()) { |
| | | for (Map.Entry<String, String> entry : data.entrySet()) { |
| | | Map<String, String> valueNode = new HashMap<>(); |
| | | valueNode.put("value", entry.getValue()); |
| | | dataNode.put(entry.getKey(), valueNode); |
| | | } |
| | | } |
| | | body.put("data", dataNode); |
| | | |
| | | String jsonBody = JSON.toJSONString(body); |
| | | String response = HttpUtils.sendPost(url, jsonBody); |
| | | |
| | | JSONObject jsonObject = JSON.parseObject(response); |
| | | if (jsonObject == null) { |
| | | log.error("åé订é
æ¶æ¯è¿å为空"); |
| | | return null; |
| | | } |
| | | if (jsonObject.getIntValue("errcode") != 0) { |
| | | log.error("åé订é
æ¶æ¯å¤±è´¥: {}", jsonObject.toJSONString()); |
| | | } else { |
| | | log.info("åé订é
æ¶æ¯æåï¼touser={}, templateId={}", touser, templateId); |
| | | } |
| | | return jsonObject; |
| | | } catch (Exception e) { |
| | | log.error("åé订é
æ¶æ¯å¼å¸¸: {}", e.getMessage(), e); |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | |
| | | URLConnection connection = realUrl.openConnection(); |
| | | connection.setRequestProperty("accept", "*/*"); |
| | | connection.setRequestProperty("connection", "Keep-Alive"); |
| | | connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); |
| | | // connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"); |
| | | connection.connect(); |
| | | in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); |
| | | String line; |
| | |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | | import com.ruoyi.common.utils.PlateNumberExtractor; |
| | | import com.ruoyi.system.domain.*; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | |
| | | //对车çå¤ççéç¨æ¹æ³ |
| | | private String getPlateNo(String plateNo){ |
| | | |
| | | if (StringUtils.isNotEmpty(plateNo)) { |
| | | // ä»è½¦è¾åç§°ä¸æå车çå·ï¼åè®¾æ ¼å¼ä¸º"â
车çå·ï¼å°åºï¼"ï¼ |
| | | if(plateNo.contains("(")) { |
| | |
| | | plateNo = plateNo.replace("â
", "").replace("â", "").split("ï¼")[0]; |
| | | } |
| | | } |
| | | return plateNo; |
| | | //xxx粤VSX120 |
| | | plateNo = plateNo.replaceAll("[^a-zA-Z0-9]", ""); |
| | | return PlateNumberExtractor.extractPlateNumber(plateNo); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import javax.annotation.PostConstruct; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | private ISysConfigService configService; |
| | | |
| | | /** |
| | | * æå¡å¯å¨æ¶æ§è¡è¡¥å¿è®¡ç® |
| | | * æ£æ¥æè¿7天å
æªè¢«å¤ççGPSåæ å¹¶è¿è¡è¡¥å¿è®¡ç® |
| | | * æ§è¡GPSåæ®µéç¨è¡¥å¿è®¡ç® |
| | | * æ£æ¥æè¿N天å
æªè¢«å¤ççGPSåæ å¹¶è¿è¡è¡¥å¿è®¡ç® |
| | | * 建议é
置为æ¯å¤©æ§è¡ä¸æ¬¡,ä¾å¦åæ¨2ç¹ |
| | | */ |
| | | @PostConstruct |
| | | public void init() { |
| | | // å¯å¨åå»¶è¿æ§è¡ï¼é¿å
å½±åæå¡å¯å¨é度 |
| | | new Thread(() -> { |
| | | try { |
| | | // å»¶è¿30ç§å¯å¨ï¼ç¡®ä¿æææå¡å·²å°±ç»ª |
| | | Thread.sleep(30000); |
| | | |
| | | logger.info("========== å¼å§æ§è¡GPSåæ®µéç¨è¡¥å¿è®¡ç® =========="); |
| | | |
| | | // è·åé
ç½®çåæº¯å¤©æ°ï¼é»è®¤7天 |
| | | int lookbackDays = 7; |
| | | String lookbackConfig = configService.selectConfigByKey("gps.mileage.compensation.days"); |
| | | if (lookbackConfig != null && !lookbackConfig.isEmpty()) { |
| | | try { |
| | | lookbackDays = Integer.parseInt(lookbackConfig); |
| | | } catch (NumberFormatException e) { |
| | | logger.warn("è¡¥å¿å溯天æ°é
ç½®é误ï¼ä½¿ç¨é»è®¤å¼7天"); |
| | | } |
| | | public void executeCompensationCalculation() { |
| | | executeCompensationCalculation("7"); |
| | | } |
| | | |
| | | /** |
| | | * æ§è¡GPSåæ®µéç¨è¡¥å¿è®¡ç®(另忰) |
| | | * |
| | | * @param params åæ°å符串,æ ¼å¼:åæº¯å¤©æ°(å¦:7è¡¨ç¤ºåæº¯7天) |
| | | */ |
| | | public void executeCompensationCalculation(String params) { |
| | | try { |
| | | // è§£æåæ°:åæº¯å¤©æ° |
| | | int lookbackDays = 7; // é»è®¤7天 |
| | | if (params != null && !params.trim().isEmpty()) { |
| | | try { |
| | | lookbackDays = Integer.parseInt(params.trim()); |
| | | } catch (NumberFormatException e) { |
| | | logger.warn("åæ°æ ¼å¼é误,使ç¨é»è®¤å¼7天: {}", params); |
| | | } |
| | | |
| | | // æ§è¡è¡¥å¿è®¡ç® |
| | | int successCount = segmentMileageService.compensateCalculation(lookbackDays); |
| | | |
| | | logger.info("========== GPSåæ®µéç¨è¡¥å¿è®¡ç®å®æ - æåå¤ç {} è¾è½¦ ==========", successCount); |
| | | |
| | | } catch (InterruptedException e) { |
| | | logger.error("è¡¥å¿è®¡ç®çº¿ç¨è¢«ä¸æ", e); |
| | | Thread.currentThread().interrupt(); |
| | | } catch (Exception e) { |
| | | logger.error("GPSåæ®µéç¨è¡¥å¿è®¡ç®å¤±è´¥", e); |
| | | } |
| | | }, "GPS-Compensation-Thread").start(); |
| | | |
| | | logger.info("========== å¼å§æ§è¡GPSåæ®µéç¨è¡¥å¿è®¡ç® - åæº¯{}天 ==========", lookbackDays); |
| | | |
| | | // æ§è¡è¡¥å¿è®¡ç® |
| | | int successCount = segmentMileageService.compensateCalculation(lookbackDays); |
| | | |
| | | logger.info("========== GPSåæ®µéç¨è¡¥å¿è®¡ç®å®æ - æåå¤ç {} è¾è½¦ ==========", successCount); |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("GPSåæ®µéç¨è¡¥å¿è®¡ç®å¤±è´¥", e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | package com.ruoyi.quartz.task; |
| | | |
| | | import com.ruoyi.common.utils.PlateNumberExtractor; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | */ |
| | | private String extractPlateNumber(String deviceName, String remark) { |
| | | if (StringUtils.isNotEmpty(deviceName)) { |
| | | String plateNumber =PlateNumberExtractor.extractPlateNumber(deviceName); |
| | | if(StringUtils.isNotEmpty(plateNumber))return plateNumber; |
| | | return deviceName; |
| | | } |
| | | if (StringUtils.isNotEmpty(remark)) { |
| | | String plateNumber =PlateNumberExtractor.extractPlateNumber(remark); |
| | | if(StringUtils.isNotEmpty(plateNumber))return plateNumber; |
| | | return remark; |
| | | } |
| | | return null; |
| | |
| | | @Primary |
| | | public IMapService mapService() { |
| | | String provider = mapServiceConfig.getProvider(); |
| | | |
| | | logger.info("使ç¨çå°å¾æå¡è¿è¡å°çç¼ç :{}",provider); |
| | | if ("tianditu".equalsIgnoreCase(provider)) { |
| | | logger.info("使ç¨å¤©å°å¾æå¡è¿è¡å°çç¼ç "); |
| | | return tiandituMapService; |
| | |
| | | @Excel(name = "é¨é¨åç§°") |
| | | private String deptName; |
| | | |
| | | /** 车çå·(å表æ¾ç¤ºç¬¬ä¸è¾è½¦) */ |
| | | @Excel(name = "车çå·") |
| | | private String vehicleNo; |
| | | |
| | | /** å 餿 å¿ï¼0代表åå¨ 2代表å é¤ï¼ */ |
| | | private String delFlag; |
| | | |
| | |
| | | return deptName; |
| | | } |
| | | |
| | | public void setVehicleNo(String vehicleNo) { |
| | | this.vehicleNo = vehicleNo; |
| | | } |
| | | |
| | | public String getVehicleNo() { |
| | | return vehicleNo; |
| | | } |
| | | |
| | | public void setDelFlag(String delFlag) { |
| | | this.delFlag = delFlag; |
| | | } |
| | |
| | | /** æ¯å¦éè¦éæ°åæ¥ï¼0-ä¸éè¦ï¼1-éè¦éæ°åæ¥ï¼è½¦è¾æäººååæ´ï¼ */ |
| | | private Integer needResync; |
| | | |
| | | /** æ§ç³»ç»ServiceOrdNoï¼è½¬è¿åç¼å·ï¼ */ |
| | | private String legacyServiceOrdNo; |
| | | |
| | | |
| | | |
| | | public Long getId() { |
| | |
| | | this.needResync = needResync; |
| | | } |
| | | |
| | | public String getLegacyServiceOrdNo() { |
| | | return legacyServiceOrdNo; |
| | | } |
| | | |
| | | public void setLegacyServiceOrdNo(String legacyServiceOrdNo) { |
| | | this.legacyServiceOrdNo = legacyServiceOrdNo; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "SysTaskEmergency{" + |
| | |
| | | /** ä»»å¡ç¶æ */ |
| | | private String taskStatus; |
| | | |
| | | /** 车çå· */ |
| | | private String vehicleNo; |
| | | |
| | | /** å建人ID */ |
| | | private Long creatorId; |
| | | |
| | |
| | | this.taskStatus = taskStatus; |
| | | } |
| | | |
| | | public String getVehicleNo() { |
| | | return vehicleNo; |
| | | } |
| | | |
| | | public void setVehicleNo(String vehicleNo) { |
| | | this.vehicleNo = vehicleNo; |
| | | } |
| | | |
| | | public Long getCreatorId() { |
| | | return creatorId; |
| | | } |
| | |
| | | import org.springframework.scheduling.annotation.Async; |
| | | import org.springframework.stereotype.Component; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.system.domain.SysMessage; |
| | | import com.ruoyi.system.domain.SysTask; |
| | | import com.ruoyi.system.domain.SysTaskEmergency; |
| | | import com.ruoyi.system.event.TaskCreatedEvent; |
| | | import com.ruoyi.system.event.TaskAssignedEvent; |
| | | import com.ruoyi.system.event.TaskStatusChangedEvent; |
| | | import com.ruoyi.system.mapper.SysMessageMapper; |
| | | import com.ruoyi.system.mapper.SysUserMapper; |
| | | import com.ruoyi.system.mapper.SysTaskMapper; |
| | | import com.ruoyi.system.mapper.SysTaskEmergencyMapper; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.system.service.IWechatTaskNotifyService; |
| | | |
| | | import java.util.HashMap; |
| | | |
| | | /** |
| | | * 任塿¶æ¯çå¬å¨ |
| | |
| | | |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | @Autowired |
| | | private SysTaskMapper sysTaskMapper; |
| | | |
| | | @Autowired |
| | | private SysTaskEmergencyMapper sysTaskEmergencyMapper; |
| | | |
| | | @Autowired |
| | | private IWechatTaskNotifyService wechatTaskNotifyService; |
| | | |
| | | /** |
| | | * çå¬ä»»å¡å建äºä»¶ |
| | |
| | | return; |
| | | } |
| | | |
| | | // ç»æ¯ä¸ªæ§è¡äººåéæ¶æ¯ |
| | | // ç»æ¯ä¸ªæ§è¡äººåéç«å
æ¶æ¯ |
| | | for (int i = 0; i < event.getAssigneeIds().size(); i++) { |
| | | Long assigneeId = event.getAssigneeIds().get(i); |
| | | |
| | |
| | | continue; |
| | | } |
| | | |
| | | // åå»ºæ¶æ¯ |
| | | // å建ç«å
æ¶æ¯ |
| | | SysMessage message = new SysMessage(); |
| | | message.setMessageType("PUSH"); |
| | | message.setMessageTitle("任塿¨é"); |
| | |
| | | sysMessageMapper.insertSysMessage(message); |
| | | log.info("ä»»å¡åé
æ¶æ¯å·²ä¿åï¼æ¶æ¯IDï¼{}ï¼æ¥æ¶äººï¼{}", message.getMessageId(), assignee.getNickName()); |
| | | } |
| | | |
| | | // åé微信订é
æ¶æ¯ï¼æé¤åå»ºäººï¼ |
| | | try { |
| | | SysTask task = sysTaskMapper.selectSysTaskByTaskId(event.getTaskId()); |
| | | Long creatorId = task != null ? task.getCreatorId() : null; |
| | | wechatTaskNotifyService.sendTaskNotifyMessage(event.getTaskId(), event.getAssigneeIds(), creatorId); |
| | | } catch (Exception e) { |
| | | log.error("å¤çä»»å¡åé
äºä»¶æ¶åé微信订é
æ¶æ¯å¤±è´¥", e); |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | log.error("å¤çä»»å¡åé
äºä»¶å¤±è´¥", e); |
| | |
| | | */ |
| | | List<Map<String, Object>> selectTransferOrders(@Param("startDate") String startDate); |
| | | |
| | | /** |
| | | /**ServiceOrdNo |
| | | * æ ¹æ®æå¡åIDåè°åº¦åIDæ¥è¯¢è½¬è¿åæ°æ® |
| | | * |
| | | * @param serviceOrdID æå¡åID |
| | |
| | | @Param("endTime") Date endTime); |
| | | |
| | | /** |
| | | * æ¥è¯¢æææ´»è·è½¦è¾IDå表 |
| | | * æ¥è¯¢æ´»è·è½¦è¾IDå表 |
| | | * |
| | | * @param startTime èµ·å§æ¶é´ |
| | | * @return 车è¾IDå表 |
| | | */ |
| | | public List<Long> selectActiveVehicleIds(); |
| | | public List<Long> selectActiveVehicleIds(@Param("startTime") Date startTime); |
| | | |
| | | /** |
| | | * æ¥è¯¢æªè¢«è®¡ç®çGPSåæ ï¼ä¸å¨tb_vehicle_gps_calculated表ä¸çè®°å½ï¼ |
| | |
| | | * @return GPSåæ ï¼å
å«lngålatï¼å¦æè·å失败è¿ånull |
| | | */ |
| | | Map<String, Double> geocoding(String address, String city); |
| | | |
| | | /** |
| | | * GPSåæ è½¬å°åï¼éåå°çç¼ç ï¼ |
| | | * |
| | | * @param lng ç»åº¦ |
| | | * @param lat 纬度 |
| | | * @return å°åï¼å¦æè·å失败è¿ånull |
| | | */ |
| | | String reverseGeocoding(double lng, double lat); |
| | | } |
| | |
| | | * @param updateTime æ´æ°æ¶é´ |
| | | * @return ç»æ |
| | | */ |
| | | public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, Long userId,String userName, Long deptId, Date createTime, Date updateTime); |
| | | public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, String serviceOrdNo, Long userId,String userName, Long deptId, Date createTime, Date updateTime); |
| | | |
| | | /** |
| | | * ä¿®æ¹ä»»å¡ç®¡ç |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import com.ruoyi.system.domain.SysTaskVehicle; |
| | | |
| | | /** |
| | |
| | | * @return ç»æ |
| | | */ |
| | | public int updateTaskVehicleStatus(Long id, String status); |
| | | |
| | | /** |
| | | * æ¹éè·å车è¾å½åä»»å¡ç¶æ |
| | | * |
| | | * @param vehicleIds 车è¾IDå表 |
| | | * @return Map<车è¾ID, Map<"taskCode": ä»»å¡ç¼å·, "taskStatus": ä»»å¡ç¶æ>> |
| | | */ |
| | | public Map<Long, Map<String, Object>> batchGetVehicleCurrentTaskStatus(List<Long> vehicleIds); |
| | | |
| | | /** |
| | | * æ´æ°ä»»å¡è½¦è¾å
³èç¶æï¼æ°æ¹æ³ï¼ |
| | | * |
| | | * @param id å
³èID |
| | | * @param status æ°ç¶æ |
| | | * @return ç»æ |
| | | */ |
| | | public int updateSysTaskVehicleStatus(Long id, String status); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import com.ruoyi.system.domain.SysTask; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 微信任å¡éç¥æå¡æ¥å£ |
| | | * |
| | | * @author ruoyi |
| | | * @date 2025-11-30 |
| | | */ |
| | | public interface IWechatTaskNotifyService { |
| | | |
| | | /** |
| | | * åéä»»å¡éç¥æ¶æ¯ç»æå®ç¨æ·å表 |
| | | * |
| | | * @param taskId ä»»å¡ID |
| | | * @param userIds æ¥æ¶ç¨æ·IDå表 |
| | | * @param excludeUserId æé¤çç¨æ·IDï¼å¯éï¼å¦åå»ºäººï¼ |
| | | * @return æååéçæ¶æ¯æ°é |
| | | */ |
| | | int sendTaskNotifyMessage(Long taskId, List<Long> userIds, Long excludeUserId); |
| | | |
| | | /** |
| | | * åéä»»å¡éç¥æ¶æ¯ç»æå®ç¨æ·å表ï¼ä¸æé¤ä»»ä½ç¨æ·ï¼ |
| | | * |
| | | * @param taskId ä»»å¡ID |
| | | * @param userIds æ¥æ¶ç¨æ·IDå表 |
| | | * @return æååéçæ¶æ¯æ°é |
| | | */ |
| | | int sendTaskNotifyMessage(Long taskId, List<Long> userIds); |
| | | } |
| | |
| | | .orElse(null); |
| | | |
| | | if (fee == null) { |
| | | log.error("æ°ç³»ç»éå è´¹ç¨è®°å½ä¸åå¨ï¼feeId: {}", feeId); |
| | | log.info("æ°ç³»ç»éå è´¹ç¨è®°å½ä¸åå¨ï¼feeId: {}", feeId); |
| | | return false; |
| | | } |
| | | |
| | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public String reverseGeocoding(double lng, double lat) { |
| | | //è°ç¨ç¾åº¦å°åååè§£ææ¥å£ |
| | | String url = "https://api.map.baidu.com/reverse_geocoding/v3/"; |
| | | String params = "location=" + lat + "," + lng + |
| | | "&output=json" + |
| | | "&ak=" + baiduMapConfig.getAk(); |
| | | String response = HttpUtils.sendGet(url, params); |
| | | //"{\"status\":0,\"result\":{\"location\":{\"lng\":113.25330399999999,\"lat\":23.04668300960378},\"formatted_address\":\"广ä¸çä½å±±å¸åæµ·åºæ¡åè¡é\",\"edz\":{\"name\":\"\"},\"business\":\"\",\"business_info\":[],\"addressComponent\":{\"country\":\"ä¸å½\",\"country_code\":0,\"region_code_iso\":\"CHN\",\"country_code_iso\":\"CHN\",\"country_code_iso2\":\"CN\",\"province\":\"广ä¸ç\",\"city\":\"ä½å±±å¸\",\"city_level\":2,\"district\":\"åæµ·åº\",\"town\":\"æ¡åè¡é\",\"town_code\":\"440605011\",\"distance\":\"\",\"direction\":\"\",\"adcode\":\"440605\",\"street\":\"\",\"street_number\":\"\"},\"pois\":[],\"roads\":[],\"poiRegions\":[],\"sematic_description\":\"\",\"formatted_address_poi\":\"\",\"cityCode\":138}}" |
| | | JSONObject jsonObject = JSONObject.parseObject(response); |
| | | if (jsonObject.getInteger("status") != 0) { |
| | | logger.warn("ç¾åº¦å°å¾å°åååè§£æå¤±è´¥: lng={}, lat={}, status={}, message={}", |
| | | lng, lat, jsonObject.getInteger("status"), jsonObject.getString("message")); |
| | | return null; |
| | | } |
| | | String address = jsonObject.getJSONObject("result").getString("formatted_address"); |
| | | logger.info("ç¾åº¦å°å¾å°åååè§£ææå: lng={}, lat={}, address={}", lng, lat, address); |
| | | return address; |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.ruoyi.common.utils.PlateNumberExtractor; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.ruoyi.system.domain.*; |
| | | import com.ruoyi.system.service.IGpsCollectService; |
| | |
| | | private String extractPlateNumber(String deviceName, String remark) { |
| | | // è¿éå¯ä»¥æ ¹æ®å®é
æ
åµå®ç°è½¦çå·æåé»è¾ |
| | | // ä¾å¦ï¼ä»å符串ä¸å¹é
车çå·æ ¼å¼ |
| | | //aaxx粤VSX120 |
| | | //å¨è¿éæå 粤VSX120 |
| | | |
| | | if (StringUtils.isNotEmpty(deviceName)) { |
| | | String plateNo =PlateNumberExtractor.extractPlateNumber(deviceName); |
| | | if (plateNo != null) { |
| | | return plateNo; |
| | | } |
| | | return deviceName; |
| | | } |
| | | if (StringUtils.isNotEmpty(remark)) { |
| | | String plateNo =PlateNumberExtractor.extractPlateNumber(remark); |
| | | if (plateNo != null) { |
| | | return plateNo; |
| | | } |
| | | return remark; |
| | | } |
| | | return null; |
| | |
| | | import com.ruoyi.system.mapper.LegacyTransferSyncMapper; |
| | | import com.ruoyi.system.mapper.VehicleInfoMapper; |
| | | import com.ruoyi.system.service.ISysUserService; |
| | | import com.ruoyi.system.service.IWechatTaskNotifyService; |
| | | import org.apache.poi.ss.usermodel.DateUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.HashMap; |
| | | |
| | | /** |
| | | * æ§ç³»ç»è½¬è¿å忥Serviceä¸å¡å±å¤ç |
| | |
| | | |
| | | @Autowired |
| | | private ISysUserService sysUserService; |
| | | |
| | | @Autowired |
| | | private IWechatTaskNotifyService wechatTaskNotifyService; |
| | | |
| | | /** |
| | | * 忥æå®æ¥æèå´çæ§ç³»ç»è½¬è¿åå°æ°ç³»ç» |
| | |
| | | */ |
| | | private boolean syncSingleTransferOrder(String serviceOrdID, String dispatchOrdID, Map<String, Object> order) { |
| | | log.info("å¼å§åæ¥å个转è¿å: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID); |
| | | |
| | | String sysTaskCode=""; |
| | | try { |
| | | // æé TaskCreateVO对象 |
| | | TaskCreateVO createTaskVo = buildCreateTaskVo(serviceOrdID, dispatchOrdID, order); |
| | | |
| | | sysTaskCode = createTaskVo.getTaskCode(); |
| | | if (createTaskVo == null) { |
| | | log.error("æé TaskCreateVO失败: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID); |
| | | return false; |
| | |
| | | createTaskVo.getPatient() != null ? createTaskVo.getPatient().getName() : "æªç¥", |
| | | createTaskVo.getHospitalOut() != null ? createTaskVo.getHospitalOut().getName() : "æªç¥", |
| | | createTaskVo.getHospitalIn() != null ? createTaskVo.getHospitalIn().getName() : "æªç¥"); |
| | | |
| | | /** |
| | | * å¼åæ¶é´ |
| | | */ |
| | | Date ServiceOrd_CC_Time= getDateValue(order, "ServiceOrd_CC_Time"); |
| | | // è°ç¨sysTaskServiceåå»ºä»»å¡ |
| | | String serviceOrdClass = getStringValue(order,"ServiceOrdClass"); |
| | | String serviceOrdNo = getStringValue(order,"ServiceOrdNo"); |
| | | |
| | | Integer oauserId=getIntegerValue(order,"ServiceOrd_NS_ID"); |
| | | SysUser sysUser=sysUserService.selectUserByOaUserId(oauserId); |
| | |
| | | SysDept dept=sysDeptService.selectDeptByServiceClass(serviceOrdClass); |
| | | Long deptId=dept==null?null:dept.getDeptId(); |
| | | |
| | | int result = sysTaskService.insertTask(createTaskVo,serviceOrdID,dispatchOrdID, taskCreatorId,createUserName, deptId, ServiceOrd_CC_Time, ServiceOrd_CC_Time); |
| | | int result = sysTaskService.insertTask(createTaskVo,serviceOrdID,dispatchOrdID, serviceOrdNo, taskCreatorId,createUserName, deptId, ServiceOrd_CC_Time, ServiceOrd_CC_Time); |
| | | |
| | | if (result > 0) { |
| | | log.info("转è¿å忥æå: ServiceOrdID={}, DispatchOrdID={}, å建çä»»å¡ID={}", serviceOrdID, dispatchOrdID, result); |
| | | |
| | | try { |
| | | notifyTransferOrderByWechat((long) result, serviceOrdID, dispatchOrdID, serviceOrdNo, ServiceOrd_CC_Time, dept, order); |
| | | } catch (Exception e) { |
| | | log.error("转è¿å忥æåååé微信éç¥å¤±è´¥: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e); |
| | | } |
| | | |
| | | return true; |
| | | } else { |
| | | log.error("转è¿ååæ¥å¤±è´¥: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID); |
| | |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | log.error("忥å个转è¿åå¼å¸¸: ServiceOrdID={}, DispatchOrdID={}", serviceOrdID, dispatchOrdID, e); |
| | | log.error("忥å个转è¿åå¼å¸¸: ServiceOrdID={}, DispatchOrdID={},sysTaskCode:{}", serviceOrdID, dispatchOrdID,sysTaskCode, e); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | |
| | | private String getServiceOrdCode(Date ServiceOrd_CC_Time,String serviceOrdClass,String serviceOrdNo){ |
| | | //BF20251101-serviceOrdNo; |
| | | //å° ServiceOrd_CC_Time 转为 yyyyMMdd æ ¼å¼ |
| | | String ServiceOrd_CC_Time_Str= DateUtils.parseDateToStr(DateUtils.YYYYMMDD,ServiceOrd_CC_Time); |
| | | //serviceOrdNo è¿ä¸ªæ¯æ°åï¼åºå®3使° ï¼å°32ï¼è½¬æ032ï¼å°1转æ001 |
| | | Integer intServiceNo=Integer.valueOf(serviceOrdNo); |
| | | String ServiceOrdNo_Str=String.format("%03d", intServiceNo); |
| | | return serviceOrdClass+ServiceOrd_CC_Time_Str+"-"+ServiceOrdNo_Str; |
| | | } |
| | | /** |
| | | * æé TaskCreateVO对象ç¨äºåå»ºä»»å¡ |
| | | * |
| | |
| | | log.error("æå¡åIDä¸è½ä¸ºç©º"); |
| | | return null; |
| | | } |
| | | |
| | | String serviceOrdClass = getStringValue(order, "ServiceOrdClass"); |
| | | //TODO |
| | | TaskCreateVO createTaskVo = new TaskCreateVO(); |
| | | String Old_ServiceOrdID_TXT=getStringValue(order,"Old_ServiceOrdID_TXT"); |
| | | if(Old_ServiceOrdID_TXT!=null){ |
| | | createTaskVo.setTaskCode(Old_ServiceOrdID_TXT); |
| | | } |
| | | |
| | | String serviceOrdCode=this.getServiceOrdCode(getDateValue(order, "ServiceOrd_CC_Time"),serviceOrdClass,getStringValue(order, "ServiceOrdNo")); |
| | | createTaskVo.setTaskCode(serviceOrdCode); |
| | | log.info("æé TaskCreateVO: ServiceOrdID={}, DispatchOrdID={},taskCode:{}", serviceOrdID, dispatchOrdID,serviceOrdCode); |
| | | // è®¾ç½®åºæ¬ä¿¡æ¯ |
| | | createTaskVo.setTaskType("EMERGENCY_TRANSFER"); // æ¥æè½¬è¿ä»»å¡ |
| | | |
| | | // è®¾ç½®åæ®ç±»ååä»»å¡ç±»åIDï¼ä»æ§ç³»ç»å段æ å°ï¼ |
| | | String serviceOrdClass = getStringValue(order, "ServiceOrdClass"); |
| | | |
| | | if (StringUtils.isNotEmpty(serviceOrdClass)) { |
| | | createTaskVo.setDocumentTypeId(serviceOrdClass); |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | // 设置å建æ¶é´ |
| | | // 设置å建æ¶é´ å¼åæ¥æ |
| | | Date createTime = getDateValue(order, "ServiceOrd_CC_Time"); |
| | | if (createTime != null) { |
| | | createTaskVo.setCreateTime(createTime); |
| | |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void notifyTransferOrderByWechat(Long taskId, |
| | | String serviceOrdID, |
| | | String dispatchOrdID, |
| | | String serviceOrdNo, |
| | | Date serviceOrdCcTime, |
| | | SysDept dept, |
| | | Map<String, Object> order) { |
| | | try { |
| | | // è·åéç¥æ¥æ¶äººå表 |
| | | List<SysUser> receivers = getWechatNotifyUsers(dispatchOrdID, dept); |
| | | if (receivers == null || receivers.isEmpty()) { |
| | | log.info("æ§ç³»ç»åæ¥è½¬è¿åæ å¯ç¨å¾®ä¿¡æ¥æ¶äººï¼taskId={}", taskId); |
| | | return; |
| | | } |
| | | |
| | | // æåæ¥æ¶äºº ID å表 |
| | | List<Long> userIds = new ArrayList<>(); |
| | | for (SysUser user : receivers) { |
| | | if (user != null && user.getUserId() != null) { |
| | | userIds.add(user.getUserId()); |
| | | } |
| | | } |
| | | |
| | | // è°ç¨ç»ä¸ç微信éç¥æå¡ |
| | | int successCount = wechatTaskNotifyService.sendTaskNotifyMessage(taskId, userIds); |
| | | log.info("æ§ç³»ç»åæ¥è½¬è¿å微信éç¥åé宿ï¼taskId={}, æå={}", taskId, successCount); |
| | | } catch (Exception e) { |
| | | log.error("notifyTransferOrderByWechatåçå¼å¸¸, serviceOrdID={}, dispatchOrdID={}", serviceOrdID, dispatchOrdID, e); |
| | | } |
| | | } |
| | | |
| | | private List<SysUser> getWechatNotifyUsers(String dispatchOrdID, SysDept dept) { |
| | | try { |
| | | List<SysUser> result = new ArrayList<>(); |
| | | |
| | | List<TaskCreateVO.AssigneeInfo> assignees = queryAssignees(dispatchOrdID); |
| | | if (assignees != null && !assignees.isEmpty()) { |
| | | for (TaskCreateVO.AssigneeInfo assigneeInfo : assignees) { |
| | | if (assigneeInfo == null || assigneeInfo.getUserId() == null) { |
| | | continue; |
| | | } |
| | | SysUser user = sysUserService.selectUserById(assigneeInfo.getUserId()); |
| | | if (user != null && StringUtils.isNotEmpty(user.getOpenId())) { |
| | | result.add(user); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (!result.isEmpty()) { |
| | | return result; |
| | | } |
| | | |
| | | if (dept == null || StringUtils.isEmpty(dept.getPhone())) { |
| | | return result; |
| | | } |
| | | |
| | | SysUser leader = sysUserService.selectUserByPhonenumber(dept.getPhone()); |
| | | if (leader != null && StringUtils.isNotEmpty(leader.getOpenId())) { |
| | | result.add(leader); |
| | | } |
| | | |
| | | return result; |
| | | } catch (Exception e) { |
| | | log.error("è·åæ§ç³»ç»åæ¥è½¬è¿å微信éç¥æ¥æ¶äººå¤±è´¥, dispatchOrdID={}", dispatchOrdID, e); |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | // ä¿åæ¥æè½¬è¿æ©å±ä¿¡æ¯ |
| | | if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) { |
| | | saveEmergencyInfo(task.getTaskId(),username, createVO,null,null); |
| | | saveEmergencyInfo(task.getTaskId(),username, createVO,null,null,null); |
| | | } |
| | | |
| | | // ä¿åç¦ç¥è½¦æ©å±ä¿¡æ¯ |
| | |
| | | */ |
| | | @Override |
| | | @Transactional |
| | | public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, Long userId,String userName, Long deptId, Date createTime, Date updateTime) { |
| | | public int insertTask(TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, String serviceOrdNo, Long userId,String userName, Long deptId, Date createTime, Date updateTime) { |
| | | SysTask task = new SysTask(); |
| | | if(createVO.getTaskCode()!=null){ |
| | | task.setTaskCode(createVO.getTaskCode()); |
| | |
| | | |
| | | // ä¿åæ¥æè½¬è¿æ©å±ä¿¡æ¯ |
| | | if (result > 0 && "EMERGENCY_TRANSFER".equals(createVO.getTaskType())) { |
| | | saveEmergencyInfo(task.getTaskId(),userName, createVO, serviceOrderId, dispatchOrderId); |
| | | saveEmergencyInfo(task.getTaskId(),userName, createVO, serviceOrderId, dispatchOrderId, serviceOrdNo); |
| | | } |
| | | |
| | | // ä¿åç¦ç¥è½¦æ©å±ä¿¡æ¯ |
| | |
| | | * @param taskId ä»»å¡ID |
| | | * @param createVO ä»»å¡å建对象 |
| | | */ |
| | | private void saveEmergencyInfo(Long taskId,String createUserName, TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId) { |
| | | private void saveEmergencyInfo(Long taskId,String createUserName, TaskCreateVO createVO,String serviceOrderId,String dispatchOrderId, String serviceOrdNo) { |
| | | SysTaskEmergency emergencyInfo = new SysTaskEmergency(); |
| | | emergencyInfo.setTaskId(taskId); |
| | | |
| | |
| | | emergencyInfo.setDispatchSyncTime(new Date()); |
| | | emergencyInfo.setDispatchSyncErrorMsg("æ§ç³»ç»åæ¥è¿æ¥"); |
| | | } |
| | | if(serviceOrdNo!=null){ |
| | | emergencyInfo.setLegacyServiceOrdNo(serviceOrdNo); |
| | | } |
| | | // ç³»ç»å段 |
| | | emergencyInfo.setCreateTime(DateUtils.getNowDate()); |
| | | emergencyInfo.setUpdateTime(DateUtils.getNowDate()); |
| | |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.SecurityUtils; |
| | | import com.ruoyi.system.mapper.SysTaskVehicleMapper; |
| | | import com.ruoyi.system.mapper.SysTaskMapper; |
| | | import com.ruoyi.system.mapper.VehicleInfoMapper; |
| | | import com.ruoyi.system.domain.SysTask; |
| | | import com.ruoyi.system.domain.SysTaskVehicle; |
| | | import com.ruoyi.system.domain.VehicleInfo; |
| | | import com.ruoyi.system.service.ISysTaskVehicleService; |
| | |
| | | |
| | | @Autowired |
| | | private VehicleInfoMapper vehicleInfoMapper; |
| | | |
| | | @Autowired |
| | | private SysTaskMapper sysTaskMapper; |
| | | |
| | | /** |
| | | * æ¥è¯¢ä»»å¡è½¦è¾å
³è |
| | |
| | | taskVehicle.setUpdateTime(DateUtils.getNowDate()); |
| | | return sysTaskVehicleMapper.updateSysTaskVehicle(taskVehicle); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éè·å车è¾å½åä»»å¡ç¶æ |
| | | * |
| | | * @param vehicleIds 车è¾IDå表 |
| | | * @return Map<车è¾ID, Map<"taskCode": ä»»å¡ç¼å·, "taskStatus": ä»»å¡ç¶æ>> |
| | | */ |
| | | @Override |
| | | public Map<Long, Map<String, Object>> batchGetVehicleCurrentTaskStatus(List<Long> vehicleIds) { |
| | | Map<Long, Map<String, Object>> resultMap = new HashMap<>(); |
| | | |
| | | if (vehicleIds == null || vehicleIds.isEmpty()) { |
| | | return resultMap; |
| | | } |
| | | |
| | | try { |
| | | // 对æ¯ä¸ªè½¦è¾æ¥è¯¢å
¶å½åæ£å¨è¿è¡çä»»å¡ |
| | | for (Long vehicleId : vehicleIds) { |
| | | if (vehicleId == null) { |
| | | continue; |
| | | } |
| | | |
| | | // æ¥è¯¢è½¦è¾çæ´»è·ä»»å¡ï¼æªå®æãæªåæ¶çä»»å¡ï¼ |
| | | List<SysTask> activeTasks = sysTaskMapper.selectActiveTasksByVehicleId(vehicleId); |
| | | |
| | | if (activeTasks != null && !activeTasks.isEmpty()) { |
| | | // å第ä¸ä¸ªæ´»è·ä»»å¡ï¼ææ°çï¼ |
| | | SysTask currentTask = activeTasks.get(0); |
| | | |
| | | Map<String, Object> taskInfo = new HashMap<>(); |
| | | taskInfo.put("taskCode", currentTask.getTaskCode()); |
| | | taskInfo.put("taskStatus", currentTask.getTaskStatus()); |
| | | taskInfo.put("taskId", currentTask.getTaskId()); |
| | | |
| | | resultMap.put(vehicleId, taskInfo); |
| | | } else { |
| | | // æ²¡ææ´»è·ä»»å¡ |
| | | resultMap.put(vehicleId, null); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("æ¹éæ¥è¯¢è½¦è¾ä»»å¡ç¶æå¤±è´¥", e); |
| | | } |
| | | |
| | | return resultMap; |
| | | } |
| | | |
| | | /** |
| | | * æ´æ°ä»»å¡è½¦è¾å
³èç¶æï¼æ°æ¹æ³ï¼ |
| | | * |
| | | * @param id å
³èID |
| | | * @param status æ°ç¶æ |
| | | * @return ç»æ |
| | | */ |
| | | @Override |
| | | @Transactional |
| | | public int updateSysTaskVehicleStatus(Long id, String status) { |
| | | return updateTaskVehicleStatus(id, status); |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.ruoyi.common.config.TiandituMapConfig; |
| | | import com.ruoyi.system.service.IMapService; |
| | |
| | | return null; |
| | | } |
| | | |
| | | // æååæ |
| | | JSONObject result = jsonObject.getJSONObject("result"); |
| | | if (result == null) { |
| | | logger.warn("天å°å¾å°çç¼ç ååºæ result: address={}", address); |
| | | return null; |
| | | } |
| | | |
| | | |
| | | JSONObject location = result.getJSONObject("location"); |
| | | JSONObject location = jsonObject.getJSONObject("location"); |
| | | if (location == null) { |
| | | logger.warn("天å°å¾å°çç¼ç ååºæ location: address={}", address); |
| | | return null; |
| | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * ç´æ¥è¿åå°å |
| | | * @param lng ç»åº¦ |
| | | * @param lat 纬度 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public String reverseGeocoding(double lng, double lat) { |
| | | // æå»ºå¤©å°å¾éå°çç¼ç API URL |
| | | String url = "http://api.tianditu.gov.cn/geocoder"; |
| | | String params = "postStr={\"lon\":" + lng + ",\"lat\":" + lat + ",\"ver\":1}" + |
| | | "&type=geocode" + |
| | | "&tk=" + tiandituMapConfig.getTk(); |
| | | |
| | | logger.info("天å°å¾éå°çç¼ç 请æ±: lon={}, lat={}", lng, lat); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | |
| | | // "{\"msg\":\"ok\",\"location\":{\"score\":100,\"level\":\"é¨å\",\"lon\":\"116.290158\",\"lat\":\"39.894696\",\"keyWord\":\"åäº¬å¸æµ·æ·åºè²è±æ± 西路28å·\"},\"searchVersion\":\"7.4.3V\",\"status\":\"0\"}" |
| | | logger.info("天å°å¾éå°çç¼ç ååº: {}", response); |
| | | com.alibaba.fastjson.JSONObject obj= com.alibaba.fastjson.JSONObject.parseObject(response); |
| | | if (obj.getInteger("status") !=0) { |
| | | logger.error("天å°å¾éå°çç¼ç 失败: {}", response); |
| | | return null; |
| | | } |
| | | com.alibaba.fastjson.JSONObject location = obj.getJSONObject("result"); |
| | | if (location == null) { |
| | | logger.error("天å°å¾éå°çç¼ç ååºæ location: {}", response); |
| | | return null; |
| | | } |
| | | return location.getString("formatted_address"); |
| | | |
| | | } |
| | | } |
| | |
| | | @Override |
| | | public int batchCalculateSegmentMileage(Date startTime, Date endTime) { |
| | | try { |
| | | // æ¥è¯¢æææ´»è·è½¦è¾ |
| | | List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(); |
| | | logger.info("å¼å§æ¹é计ç®GPSåæ®µéç¨ - æ¶é´èå´: {} å° {}", startTime, endTime); |
| | | |
| | | // æ¥è¯¢å¨æå®æ¶é´èå´å
æGPSæ°æ®çææè½¦è¾ |
| | | List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTime); |
| | | |
| | | if (vehicleIds == null || vehicleIds.isEmpty()) { |
| | | logger.info("æ²¡ææ¾å°æ´»è·è½¦è¾"); |
| | | return 0; |
| | | } |
| | | |
| | | logger.info("æ¾å° {} è¾æ´»è·è½¦è¾ï¼å¼å§éè¾è®¡ç®...", vehicleIds.size()); |
| | | |
| | | int successCount = 0; |
| | | for (Long vehicleId : vehicleIds) { |
| | | int failedCount = 0; |
| | | |
| | | // éè¾è®¡ç®ï¼å
å«é误å¤çåéè¯æºå¶ |
| | | for (int i = 0; i < vehicleIds.size(); i++) { |
| | | Long vehicleId = vehicleIds.get(i); |
| | | try { |
| | | logger.info("æ£å¨å¤çè½¦è¾ {} ({}/{})", vehicleId, i + 1, vehicleIds.size()); |
| | | |
| | | int segmentCount = calculateVehicleSegmentMileage(vehicleId, startTime, endTime); |
| | | if (segmentCount > 0) { |
| | | successCount++; |
| | | logger.info("è½¦è¾ {} è®¡ç®æåï¼çæ {} ä¸ªåæ®µè®°å½", vehicleId, segmentCount); |
| | | } else { |
| | | logger.debug("è½¦è¾ {} æ ææ°çGPSåæ®µæ°æ®", vehicleId); |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("计ç®è½¦è¾ {} çåæ®µéç¨å¤±è´¥", vehicleId, e); |
| | | failedCount++; |
| | | logger.error("计ç®è½¦è¾ {} çåæ®µéç¨å¤±è´¥ ({}/{})", vehicleId, i + 1, vehicleIds.size(), e); |
| | | |
| | | // ä¸ä¸ææ´ä¸ªæ¹å¤çï¼ç»§ç»å¤çä¸ä¸è¾è½¦ |
| | | } |
| | | |
| | | // æ¯å¤ç10è¾è½¦è¾åºä¸æ¬¡è¿åº¦ |
| | | if ((i + 1) % 10 == 0) { |
| | | logger.info("æ¹é计ç®è¿åº¦: {}/{}, æå: {}, 失败: {}", |
| | | i + 1, vehicleIds.size(), successCount, failedCount); |
| | | } |
| | | } |
| | | |
| | | logger.info("æ¹éåæ®µéç¨è®¡ç®å®æ - æ¶é´èå´: {} å° {}, æ»è½¦è¾æ°: {}, æå: {}", |
| | | startTime, endTime, vehicleIds.size(), successCount); |
| | | logger.info("æ¹éåæ®µéç¨è®¡ç®å®æ - æ¶é´èå´: {} å° {}, æ»è½¦è¾æ°: {}, æå: {}, 失败: {}", |
| | | startTime, endTime, vehicleIds.size(), successCount, failedCount); |
| | | return successCount; |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("æ¹é计ç®å段éç¨å¤±è´¥", e); |
| | | throw new RuntimeException("æ¹é计ç®å¤±è´¥: " + e.getMessage()); |
| | | logger.error("æ¹é计ç®å段éç¨å¤±è´¥ - æ¶é´èå´: {} å° {}", startTime, endTime, e); |
| | | throw new RuntimeException("æ¹é计ç®å¤±è´¥: " + e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | logger.info("å¼å§è¡¥å¿è®¡ç® - åæº¯å¤©æ°: {}, æ¶é´èå´: {} å° {}", lookbackDays, startTime, endTime); |
| | | |
| | | // æ¥è¯¢æææ´»è·è½¦è¾ |
| | | List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(); |
| | | List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(startTime); |
| | | |
| | | if (vehicleIds == null || vehicleIds.isEmpty()) { |
| | | logger.info("æ²¡ææ¾å°æ´»è·è½¦è¾"); |
| | |
| | | @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("æ²¡ææ¾å°æ´»è·è½¦è¾"); |
| | |
| | | @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("æ²¡ææ¾å°æ´»è·è½¦è¾"); |
| New file |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import com.ruoyi.common.config.WechatConfig; |
| | | import com.ruoyi.common.core.domain.entity.SysUser; |
| | | import com.ruoyi.common.utils.DateUtils; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.WechatUtils; |
| | | import com.ruoyi.system.domain.SysTask; |
| | | import com.ruoyi.system.domain.SysTaskEmergency; |
| | | import com.ruoyi.system.mapper.SysTaskEmergencyMapper; |
| | | import com.ruoyi.system.mapper.SysTaskMapper; |
| | | import com.ruoyi.system.mapper.SysUserMapper; |
| | | import com.ruoyi.system.service.IWechatTaskNotifyService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 微信任å¡éç¥æå¡å®ç° |
| | | * ç»ä¸ç®¡çææä»»å¡ç¸å
³ç微信订é
æ¶æ¯åéé»è¾ |
| | | * |
| | | * @author ruoyi |
| | | * @date 2025-11-30 |
| | | */ |
| | | @Service |
| | | public class WechatTaskNotifyServiceImpl implements IWechatTaskNotifyService { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(WechatTaskNotifyServiceImpl.class); |
| | | |
| | | @Autowired |
| | | private SysTaskMapper sysTaskMapper; |
| | | |
| | | @Autowired |
| | | private SysTaskEmergencyMapper sysTaskEmergencyMapper; |
| | | |
| | | @Autowired |
| | | private SysUserMapper sysUserMapper; |
| | | |
| | | @Autowired |
| | | private WechatConfig wechatConfig; |
| | | |
| | | /** |
| | | * åéä»»å¡éç¥æ¶æ¯ç»æå®ç¨æ·å表 |
| | | * |
| | | * @param taskId ä»»å¡ID |
| | | * @param userIds æ¥æ¶ç¨æ·IDå表 |
| | | * @param excludeUserId æé¤çç¨æ·IDï¼å¯éï¼å¦åå»ºäººï¼ |
| | | * @return æååéçæ¶æ¯æ°é |
| | | */ |
| | | @Override |
| | | public int sendTaskNotifyMessage(Long taskId, List<Long> userIds, Long excludeUserId) { |
| | | if (taskId == null || userIds == null || userIds.isEmpty()) { |
| | | log.warn("åé微信任å¡éç¥åæ°ä¸å®æ´ï¼taskId={}, userIds={}", taskId, userIds); |
| | | return 0; |
| | | } |
| | | |
| | | // æ¥è¯¢ä»»å¡ä¿¡æ¯ |
| | | SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); |
| | | if (task == null) { |
| | | log.warn("微信éç¥å¤±è´¥ï¼ä»»å¡ä¸åå¨ï¼taskId={}", taskId); |
| | | return 0; |
| | | } |
| | | |
| | | // æ¥è¯¢æ¥æä¿¡æ¯ |
| | | SysTaskEmergency emergency = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId); |
| | | |
| | | // è·å微信AccessToken |
| | | String accessToken = WechatUtils.getAccessToken(wechatConfig.getAppId(), wechatConfig.getAppSecret()); |
| | | if (StringUtils.isEmpty(accessToken)) { |
| | | log.error("è·å微信AccessTokenå¤±è´¥ï¼æ æ³åéä»»å¡éç¥"); |
| | | return 0; |
| | | } |
| | | |
| | | // æé æ¶æ¯æ°æ® |
| | | Map<String, String> data = buildTaskNotifyData(task, emergency); |
| | | |
| | | // è·å模æ¿é
ç½® |
| | | String page = wechatConfig.getTaskDetailPage() + "?id=" + taskId; |
| | | String templateId = wechatConfig.getTaskNotifyTemplateId(); |
| | | |
| | | // åéæ¶æ¯ç»æ¯ä¸ªç¨æ· |
| | | int successCount = 0; |
| | | for (Long userId : userIds) { |
| | | // æé¤æå®ç¨æ· |
| | | if (excludeUserId != null && excludeUserId.equals(userId)) { |
| | | log.debug("è·³è¿æé¤ç¨æ·ï¼userId={}", userId); |
| | | continue; |
| | | } |
| | | |
| | | // æ¥è¯¢ç¨æ·ä¿¡æ¯ |
| | | SysUser user = sysUserMapper.selectUserById(userId); |
| | | if (user == null || StringUtils.isEmpty(user.getOpenId())) { |
| | | log.debug("ç¨æ·æªç»å®å¾®ä¿¡openIdï¼è·³è¿åéï¼userId={}", userId); |
| | | continue; |
| | | } |
| | | |
| | | // åé订é
æ¶æ¯ |
| | | try { |
| | | WechatUtils.sendSubscribeMessage(accessToken, user.getOpenId(), templateId, page, data); |
| | | successCount++; |
| | | log.info("微信任å¡éç¥åéæåï¼taskId={}, userId={}, userName={}", taskId, userId, user.getUserName()); |
| | | } catch (Exception e) { |
| | | log.error("微信任å¡éç¥åé失败ï¼taskId={}, userId={}", taskId, userId, e); |
| | | } |
| | | } |
| | | |
| | | log.info("微信任å¡éç¥æ¹éåé宿ï¼taskId={}, æ»æ°={}, æå={}", taskId, userIds.size(), successCount); |
| | | return successCount; |
| | | } |
| | | |
| | | /** |
| | | * åéä»»å¡éç¥æ¶æ¯ç»æå®ç¨æ·å表ï¼ä¸æé¤ä»»ä½ç¨æ·ï¼ |
| | | * |
| | | * @param taskId ä»»å¡ID |
| | | * @param userIds æ¥æ¶ç¨æ·IDå表 |
| | | * @return æååéçæ¶æ¯æ°é |
| | | */ |
| | | @Override |
| | | public int sendTaskNotifyMessage(Long taskId, List<Long> userIds) { |
| | | return sendTaskNotifyMessage(taskId, userIds, null); |
| | | } |
| | | |
| | | /** |
| | | * æé ä»»å¡éç¥çæ¶æ¯æ°æ® |
| | | * |
| | | * @param task ä»»å¡ä¿¡æ¯ |
| | | * @param emergency æ¥æä¿¡æ¯ï¼å¯éï¼ |
| | | * @return æ¶æ¯æ°æ®Map |
| | | */ |
| | | private Map<String, String> buildTaskNotifyData(SysTask task, SysTaskEmergency emergency) { |
| | | // äºé¡¹æè¿° |
| | | String problemDesc = "æ¨ææ°ç转è¿ä»»å¡ï¼è¯·åæ¶å¤ç"; |
| | | |
| | | // å°ç¹ä¿¡æ¯ |
| | | String location; |
| | | if (emergency != null && StringUtils.isNotEmpty(emergency.getHospitalOutName()) && StringUtils.isNotEmpty(emergency.getHospitalInName())) { |
| | | location = emergency.getHospitalOutName() + " â " + emergency.getHospitalInName(); |
| | | } else if (StringUtils.isNotEmpty(task.getDepartureAddress()) && StringUtils.isNotEmpty(task.getDestinationAddress())) { |
| | | location = task.getDepartureAddress() + " â " + task.getDestinationAddress(); |
| | | } else { |
| | | location = "æªç¥å°ç¹"; |
| | | } |
| | | |
| | | // æ¶é´ä¿¡æ¯ |
| | | String startTimeStr; |
| | | if (task.getPlannedStartTime() != null) { |
| | | startTimeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm", task.getPlannedStartTime()); |
| | | } else { |
| | | startTimeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm", new java.util.Date()); |
| | | } |
| | | |
| | | // è¿åå· |
| | | String waybillNo = StringUtils.isNotEmpty(task.getTaskCode()) ? task.getTaskCode() : String.valueOf(task.getTaskId()); |
| | | |
| | | // ç»è£
æ°æ®ï¼åºç¨thingç±»ååæ®µçé¿åº¦éå¶ï¼ |
| | | Map<String, String> data = new HashMap<>(); |
| | | // data.put("thing1", WechatUtils.truncateThingValue(problemDesc)); // æªæthingç±»ååæ®µ |
| | | // data.put("thing10", WechatUtils.truncateThingValue(location)); // æªæthingç±»ååæ®µ |
| | | data.put("time8", startTimeStr); |
| | | data.put("character_string1", waybillNo); |
| | | |
| | | return data; |
| | | } |
| | | } |
| | |
| | | <result property="ServiceOrdUserID" column="ServiceOrdUserID" /> |
| | | <result property="ServiceOrdAreaType" column="ServiceOrdAreaType" /> |
| | | <result property="ServiceOrdType" column="ServiceOrdType" /> |
| | | <result property="ServiceOrdNo" column="ServiceOrdNo" /> |
| | | <result property="ServiceOrdTraTxnPrice" column="ServiceOrdTraTxnPrice" /> |
| | | <result property="ServiceOrdPtOutHospID" column="ServiceOrdPtOutHospID" /> |
| | | <result property="ServiceOrdPtServicesID" column="ServiceOrdPtServicesID" /> |
| | |
| | | SELECT |
| | | a.ServiceOrdID, |
| | | a.Old_ServiceOrdID_TXT, |
| | | a.ServiceOrdNo, |
| | | a.ServiceOrdTraVia, |
| | | a.ServiceOrdApptDate, |
| | | a.ServiceOrd_NS_ID, |
| | |
| | | a.ServiceOrdID, |
| | | a.Old_ServiceOrdID_TXT, |
| | | a.ServiceOrdTraVia, |
| | | a.ServiceOrdNo, |
| | | a.ServiceOrdApptDate, |
| | | a.ServiceOrdUserID, |
| | | a.ServiceOrd_NS_ID, |
| | |
| | | <result property="dispatchSyncTime" column="dispatch_sync_time" /> |
| | | <result property="dispatchSyncErrorMsg" column="dispatch_sync_error_msg" /> |
| | | <result property="needResync" column="need_resync" /> |
| | | <result property="legacyServiceOrdNo" column="legacy_service_ord_no" /> |
| | | <result property="createTime" column="create_time" /> |
| | | <result property="updateTime" column="update_time" /> |
| | | <result property="createBy" column="create_by" /> |
| | |
| | | hospital_in_department_id, hospital_in_bed_number, hospital_in_address, hospital_in_longitude, |
| | | hospital_in_latitude, transfer_distance, transfer_price, passenger_contact, |
| | | passenger_phone, disease_ids, document_type_id, task_type_id, legacy_service_ord_id, legacy_dispatch_ord_id, |
| | | sync_status, sync_time, sync_error_msg, dispatch_sync_status, dispatch_sync_time, dispatch_sync_error_msg, need_resync, |
| | | sync_status, sync_time, sync_error_msg, dispatch_sync_status, dispatch_sync_time, dispatch_sync_error_msg, need_resync, legacy_service_ord_no, |
| | | create_time, update_time, create_by, update_by |
| | | from sys_task_emergency |
| | | </sql> |
| | |
| | | <if test="dispatchSyncTime != null">dispatch_sync_time,</if> |
| | | <if test="dispatchSyncErrorMsg != null">dispatch_sync_error_msg,</if> |
| | | <if test="needResync != null">need_resync,</if> |
| | | <if test="legacyServiceOrdNo != null">legacy_service_ord_no,</if> |
| | | <if test="createTime != null">create_time,</if> |
| | | <if test="updateTime != null">update_time,</if> |
| | | <if test="createBy != null">create_by,</if> |
| | |
| | | <if test="dispatchSyncTime != null">#{dispatchSyncTime},</if> |
| | | <if test="dispatchSyncErrorMsg != null">#{dispatchSyncErrorMsg},</if> |
| | | <if test="needResync != null">#{needResync},</if> |
| | | <if test="legacyServiceOrdNo != null">#{legacyServiceOrdNo},</if> |
| | | <if test="createTime != null">#{createTime},</if> |
| | | <if test="updateTime != null">#{updateTime},</if> |
| | | <if test="createBy != null">#{createBy},</if> |
| | |
| | | <if test="dispatchSyncTime != null">dispatch_sync_time = #{dispatchSyncTime},</if> |
| | | <if test="dispatchSyncErrorMsg != null">dispatch_sync_error_msg = #{dispatchSyncErrorMsg},</if> |
| | | <if test="needResync != null">need_resync = #{needResync},</if> |
| | | <if test="legacyServiceOrdNo != null">legacy_service_ord_no = #{legacyServiceOrdNo},</if> |
| | | <if test="updateTime != null">update_time = #{updateTime},</if> |
| | | <if test="updateBy != null">update_by = #{updateBy},</if> |
| | | </trim> |
| | |
| | | <result property="creatorName" column="creator_name" /> |
| | | <result property="assigneeName" column="assignee_name" /> |
| | | <result property="deptName" column="dept_name" /> |
| | | <result property="vehicleNo" column="vehicle_no" /> |
| | | <collection property="assignedVehicles" ofType="SysTaskVehicle"> |
| | | <result property="id" column="tv_id" /> |
| | | <result property="taskId" column="tv_task_id" /> |
| | |
| | | t.actual_start_time, t.actual_end_time, t.creator_id, t.assignee_id, t.dept_id, |
| | | t.create_time, t.update_time, t.create_by, t.update_by, t.remark, t.del_flag, t.legacy_synced, |
| | | u1.nick_name as creator_name, u2.nick_name as assignee_name, d.dept_name, |
| | | ( |
| | | select v2.vehicle_no |
| | | from sys_task_vehicle tv2 |
| | | left join tb_vehicle_info v2 on tv2.vehicle_id = v2.vehicle_id |
| | | where tv2.task_id = t.task_id |
| | | order by tv2.assign_time asc |
| | | limit 1 |
| | | ) as vehicle_no, |
| | | tv.id as tv_id, tv.task_id as tv_task_id, tv.vehicle_id as tv_vehicle_id, |
| | | v.vehicle_no as tv_vehicle_no, v.vehicle_type as tv_vehicle_type, |
| | | v.vehicle_brand as tv_vehicle_brand, v.vehicle_model as tv_vehicle_model, |
| | |
| | | <if test="taskCode != null and taskCode != ''"> and t.task_code like concat('%', #{taskCode}, '%')</if> |
| | | <if test="taskType != null and taskType != ''"> and t.task_type = #{taskType}</if> |
| | | <if test="taskStatus != null and taskStatus != ''"> and t.task_status = #{taskStatus}</if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no like concat('%', #{vehicleNo}, '%')</if> |
| | | <!-- ç»¼åæ¥è¯¢ï¼å½åç¨æ·æå¨æºæ OR å½åç¨æ·å建 OR åé
ç»å½åç¨æ· --> |
| | | <if test="(creatorId != null and creatorId != 0) or (assigneeId != null and assigneeId != 0) or (deptId != null and deptId != 0)"> |
| | | and ( |
| | |
| | | <include refid="selectSysTaskVehicleVo"/> |
| | | <where> |
| | | <if test="taskId != null "> and tv.task_id = #{taskId}</if> |
| | | <if test="taskCode != null and taskCode != ''"> and t.task_code like concat('%', #{taskCode}, '%')</if> |
| | | <if test="vehicleId != null "> and tv.vehicle_id = #{vehicleId}</if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no like concat('%', #{vehicleNo}, '%')</if> |
| | | <if test="status != null and status != ''"> and tv.status = #{status}</if> |
| | | <if test="assignBy != null and assignBy != ''"> and tv.assign_by like concat('%', #{assignBy}, '%')</if> |
| | | </where> |
| | |
| | | <result property="updateBy" column="update_by" /> |
| | | <result property="updateTime" column="update_time" /> |
| | | <result property="remark" column="remark" /> |
| | | <result property="openId" column="open_id" /> |
| | | <result property="unionId" column="union_id" /> |
| | | <result property="wechatNickname" column="wechat_nickname" /> |
| | | <association property="dept" javaType="SysDept" resultMap="deptResult" /> |
| | | <collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> |
| | | </resultMap> |
| | |
| | | </resultMap> |
| | | |
| | | <sql id="selectUserVo"> |
| | | select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.oa_user_id, u.create_by, u.create_time, u.remark, |
| | | select u.user_id, u.dept_id, u.user_name,u.oa_user_id, u.oa_order_class, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.oa_user_id, u.create_by, u.create_time, u.remark,u.open_id,u.union_id,u.wechat_nickname, |
| | | d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, |
| | | r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status |
| | | from sys_user u |
| | |
| | | <select id="selectVehicleGpsList" parameterType="VehicleGps" resultMap="VehicleGpsResult"> |
| | | <include refid="selectVehicleGpsVo"/> |
| | | <where> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no = #{vehicleNo}</if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no like concat('%', #{vehicleNo}, '%')</if> |
| | | <if test="longitude != null "> and longitude = #{longitude}</if> |
| | | <if test="latitude != null "> and latitude = #{latitude}</if> |
| | | <if test="speed != null "> and speed = #{speed}</if> |
| | |
| | | order by collect_time |
| | | </select> |
| | | |
| | | <!-- æ¥è¯¢æ´»è·è½¦è¾IDï¼ä¼åï¼æ·»å LIMITéå¶ï¼é¿å
å¤§è¡¨æ«æï¼ --> |
| | | <select id="selectActiveVehicleIds" resultType="Long"> |
| | | select distinct vehicle_id |
| | | from tb_vehicle_gps |
| | | where collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) |
| | | where collect_time >= #{startTime} |
| | | order by vehicle_id |
| | | </select> |
| | | |
| | |
| | | s.non_task_mileage, s.task_ratio, s.gps_point_count, s.task_count, s.segment_count, |
| | | s.data_source, s.create_time, s.update_time |
| | | from tb_vehicle_mileage_stats s |
| | | where s.vehicle_id = #{vehicleId} and s.stat_date = #{statDate} |
| | | where s.vehicle_id = #{vehicleId} and DATE(s.stat_date) = DATE(#{statDate}) |
| | | limit 1 |
| | | </select> |
| | | |
| | |
| | | <if test="dataSource != null">#{dataSource},</if> |
| | | NOW() |
| | | </trim> |
| | | ON DUPLICATE KEY UPDATE |
| | | vehicle_no = VALUES(vehicle_no), |
| | | total_mileage = VALUES(total_mileage), |
| | | task_mileage = VALUES(task_mileage), |
| | | non_task_mileage = VALUES(non_task_mileage), |
| | | task_ratio = VALUES(task_ratio), |
| | | gps_point_count = VALUES(gps_point_count), |
| | | task_count = VALUES(task_count), |
| | | segment_count = VALUES(segment_count), |
| | | data_source = VALUES(data_source), |
| | | update_time = NOW() |
| | | </insert> |
| | | |
| | | <update id="updateVehicleMileageStats" parameterType="VehicleMileageStats"> |
| | |
| | | }) |
| | | } |
| | | |
| | | // æ¹éè·å车è¾å½åä»»å¡ç¶æ |
| | | export function batchGetVehicleCurrentTaskStatus(vehicleIds) { |
| | | return request({ |
| | | url: '/task/vehicle/management/currentStatus', |
| | | method: 'post', |
| | | data: vehicleIds |
| | | }) |
| | | } |
| | | |
| | | // ========== 任塿¯ä»ç¸å
³API ========== |
| | | |
| | | // è·å任塿¯ä»ä¿¡æ¯ |
| | |
| | | <div class="app-container"> |
| | | <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> |
| | | <el-form-item label="车çå·" prop="vehicleNo"> |
| | | <el-select v-model="queryParams.vehicleNo" placeholder="è¯·éæ©è½¦çå·" clearable size="small"> |
| | | <el-option |
| | | v-for="item in vehicleOptions" |
| | | :key="item.vehicleId" |
| | | :label="item.vehicleNo" |
| | | :value="item.vehicleNo" |
| | | /> |
| | | </el-select> |
| | | <el-input |
| | | v-model="queryParams.vehicleNo" |
| | | placeholder="请è¾å
¥è½¦çå·" |
| | | clearable |
| | | size="small" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ééæ¶é´" prop="collectTime"> |
| | | <el-date-picker |
| | |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="车çå·" prop="vehicleNo"> |
| | | <el-input |
| | | v-model="queryParams.vehicleNo" |
| | | placeholder="请è¾å
¥è½¦çå·" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="计åå¼å§æ¶é´"> |
| | | <el-date-picker |
| | | v-model="dateRange" |
| | |
| | | <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="车çå·" align="center" prop="vehicleNo" width="120"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.vehicleNo">{{ scope.row.vehicleNo }}</span> |
| | | <span v-else style="color: #C0C4CC;">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºåå°å" align="center" prop="departureAddress" show-overflow-tooltip /> |
| | | <el-table-column label="ç®çå°å" align="center" prop="destinationAddress" show-overflow-tooltip /> |
| | | <el-table-column label="é¢è®¡å
¬éæ°" align="center" prop="estimatedDistance" width="120"> |
| | |
| | | <span v-else style="color: #C0C4CC;">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计åå¼å§æ¶é´" align="center" prop="plannedStartTime" width="180"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.plannedStartTime">{{ parseTime(scope.row.plannedStartTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span> |
| | | <span v-else style="color: #C0C4CC;">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | |
| | | <el-table-column label="å建人" align="center" prop="creatorName" /> |
| | | <el-table-column label="æ§è¡äºº" align="center" prop="assigneeName" /> |
| | |
| | | taskCode: null, |
| | | taskType: null, |
| | | taskStatus: null, |
| | | vehicleNo: null, |
| | | plannedStartTimeBegin: null, |
| | | plannedStartTimeEnd: null, |
| | | }, |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
| | | <el-form-item label="ä»»å¡" prop="taskId"> |
| | | <el-select v-model="queryParams.taskId" placeholder="è¯·éæ©ä»»å¡" clearable filterable style="width: 200px"> |
| | | <el-option |
| | | v-for="task in taskList" |
| | | :key="task.taskId" |
| | | :label="task.taskCode + ' - ' + getTaskTypeName(task.taskType)" |
| | | :value="task.taskId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="车è¾" prop="vehicleId"> |
| | | <el-select v-model="queryParams.vehicleId" placeholder="è¯·éæ©è½¦è¾" clearable filterable style="width: 200px"> |
| | | <el-option |
| | | v-for="vehicle in vehicleList" |
| | | :key="vehicle.vehicleId" |
| | | :label="vehicle.vehicleNo + ' - ' + vehicle.deptName" |
| | | :value="vehicle.vehicleId" |
| | | /> |
| | | </el-select> |
| | | <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px"> |
| | | <el-form-item label="ä»»å¡ç¼å·" prop="taskCode"> |
| | | <el-input |
| | | v-model="queryParams.taskCode" |
| | | placeholder="请è¾å
¥ä»»å¡ç¼å·" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="车çå·" prop="vehicleNo"> |
| | | <el-input |
| | |
| | | placeholder="请è¾å
¥è½¦çå·" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å
³èç¶æ" prop="status"> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="车çå·" align="center" prop="vehicleNo" /> |
| | | <el-table-column label="车è¾ç±»å" align="center" prop="vehicleType"> |
| | | |
| | | <el-table-column label="å½åä»»å¡ç¶æ" align="center" prop="currentTaskStatus" width="180"> |
| | | <template slot-scope="scope"> |
| | | <dict-tag :options="dict.type.sys_vehicle_type" :value="scope.row.vehicleType"/> |
| | | <div v-if="scope.row.currentTaskCode"> |
| | | <el-tag type="success" size="mini"> |
| | | <i class="el-icon-loading"></i> ä»»å¡ä¸ |
| | | </el-tag> |
| | | <div style="font-size: 12px; color: #409EFF; margin-top: 5px;"> |
| | | {{ scope.row.currentTaskCode }} |
| | | </div> |
| | | </div> |
| | | <el-tag v-else type="info" size="mini"> |
| | | <i class="el-icon-circle-check"></i> ç©ºé² |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | |
| | | @click="handleStatusChange(scope.row)" |
| | | v-hasPermi="['task:vehicle:edit']" |
| | | >ç¶æåæ´</el-button> |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-tickets" |
| | | @click="handleViewTaskList(scope.row)" |
| | | >任塿¸
å</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <el-button @click="cancelStatusChange">å æ¶</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <!-- 车è¾ä»»å¡æ¸
åå¯¹è¯æ¡ --> |
| | | <el-dialog :title="'车è¾ä»»å¡æ¸
å - ' + currentVehicleNo" :visible.sync="taskListOpen" width="1200px" append-to-body> |
| | | <el-table v-loading="taskListLoading" :data="vehicleTaskList" max-height="500"> |
| | | <el-table-column label="ä»»å¡ç¼å·" align="center" prop="taskCode" width="180"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | type="text" |
| | | @click="handleViewTaskDetail(scope.row.taskId)" |
| | | style="font-family: 'Courier New', monospace; font-size: 13px;" |
| | | >{{ scope.row.taskCode }}</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä»»å¡ç±»å" align="center" prop="taskType" width="120"> |
| | | <template slot-scope="scope"> |
| | | <dict-tag :options="dict.type.sys_task_type" :value="scope.row.taskType"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="计åå¼å§æ¶é´" align="center" prop="plannedStartTime" width="160"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.plannedStartTime">{{ parseTime(scope.row.plannedStartTime, '{y}-{m}-{d} {h}:{i}') }}</span> |
| | | <span v-else style="color: #C0C4CC;">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºåå°å" align="center" prop="departureAddress" show-overflow-tooltip min-width="150" /> |
| | | <el-table-column label="ç®æ å°å" align="center" prop="destinationAddress" show-overflow-tooltip min-width="150" /> |
| | | <el-table-column label="é¢è®¡å
¬éæ°" align="center" prop="estimatedDistance" width="110"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.estimatedDistance">{{ scope.row.estimatedDistance }} km</span> |
| | | <span v-else style="color: #C0C4CC;">--</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä»»å¡ç¶æ" align="center" prop="taskStatus" width="100"> |
| | | <template slot-scope="scope"> |
| | | <dict-tag :options="dict.type.sys_task_status" :value="scope.row.taskStatus"/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center" width="100"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-view" |
| | | @click="handleViewTaskDetail(scope.row.taskId)" |
| | | >æ¥ç</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="taskListOpen = false">å
³ é</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { listTaskVehicle, getTaskVehicle, delTaskVehicle, addTaskVehicle, updateTaskVehicle, updateTaskVehicleStatus, listTask } from "@/api/task"; |
| | | import { listTaskVehicle, getTaskVehicle, delTaskVehicle, addTaskVehicle, updateTaskVehicle, updateTaskVehicleStatus, listTask, getTask, batchGetVehicleCurrentTaskStatus } from "@/api/task"; |
| | | import { listVehicle } from "@/api/system/vehicle"; |
| | | |
| | | export default { |
| | | name: "TaskVehicle", |
| | | dicts: ['sys_task_vehicle_status', 'sys_vehicle_type', 'sys_task_type'], |
| | | dicts: ['sys_task_vehicle_status', 'sys_vehicle_type', 'sys_task_type', 'sys_task_status'], |
| | | data() { |
| | | return { |
| | | // é®ç½©å± |
| | |
| | | open: false, |
| | | // æ¯å¦æ¾ç¤ºç¶æåæ´å¼¹åºå± |
| | | statusOpen: false, |
| | | // æ¯å¦æ¾ç¤ºä»»å¡æ¸
åå¼¹åºå± |
| | | taskListOpen: false, |
| | | // 车è¾ä»»å¡å表 |
| | | vehicleTaskList: [], |
| | | // 车è¾ä»»å¡å表å è½½ç¶æ |
| | | taskListLoading: false, |
| | | // å½åæ¥çç车çå· |
| | | currentVehicleNo: '', |
| | | // æ¥è¯¢åæ° |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | taskId: null, |
| | | vehicleId: null, |
| | | taskCode: null, |
| | | vehicleNo: null, |
| | | status: null, |
| | | assignBy: null, |
| | |
| | | listTaskVehicle(this.queryParams).then(response => { |
| | | this.taskVehicleList = response.rows; |
| | | this.total = response.total; |
| | | // 为æ¯ä¸ªè½¦è¾å è½½å½åä»»å¡ç¶æ |
| | | this.loadCurrentTaskStatus(); |
| | | this.loading = false; |
| | | }); |
| | | }, |
| | | /** å 载车è¾å½åä»»å¡ç¶æï¼ä¼åï¼æ¹éæ¥è¯¢ï¼ */ |
| | | loadCurrentTaskStatus() { |
| | | // æåææè½¦è¾ID |
| | | const vehicleIds = this.taskVehicleList |
| | | .map(item => item.vehicleId) |
| | | .filter(id => id != null); |
| | | |
| | | if (vehicleIds.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | // æ¹éæ¥è¯¢è½¦è¾å½åä»»å¡ç¶æ |
| | | batchGetVehicleCurrentTaskStatus(vehicleIds).then(response => { |
| | | const statusMap = response.data || {}; |
| | | |
| | | // æ´æ°æ¯ä¸ªè½¦è¾çä»»å¡ç¶æ |
| | | this.taskVehicleList.forEach(item => { |
| | | if (item.vehicleId && statusMap[item.vehicleId]) { |
| | | const taskInfo = statusMap[item.vehicleId]; |
| | | this.$set(item, 'currentTaskCode', taskInfo.taskCode); |
| | | this.$set(item, 'currentTaskStatus', taskInfo.taskStatus); |
| | | } else { |
| | | this.$set(item, 'currentTaskCode', null); |
| | | this.$set(item, 'currentTaskStatus', null); |
| | | } |
| | | }); |
| | | }).catch(error => { |
| | | console.error('å 载车è¾ä»»å¡ç¶æå¤±è´¥:', error); |
| | | }); |
| | | }, |
| | | /** è·åä»»å¡å表 */ |
| | |
| | | this.statusOpen = false; |
| | | this.statusForm = {}; |
| | | }, |
| | | /** æ¥ç车è¾ä»»å¡æ¸
å */ |
| | | handleViewTaskList(row) { |
| | | this.currentVehicleNo = row.vehicleNo; |
| | | this.taskListOpen = true; |
| | | this.taskListLoading = true; |
| | | |
| | | // æ¥è¯¢è¯¥è½¦è¾çææä»»å¡å
³è |
| | | listTaskVehicle({ |
| | | vehicleId: row.vehicleId, |
| | | pageNum: 1, |
| | | pageSize: 1000 |
| | | }).then(response => { |
| | | const taskVehicles = response.rows || []; |
| | | |
| | | // è·åææä»»å¡ID |
| | | const taskIds = [...new Set(taskVehicles.map(item => item.taskId).filter(id => id))]; |
| | | |
| | | if (taskIds.length === 0) { |
| | | this.vehicleTaskList = []; |
| | | this.taskListLoading = false; |
| | | return; |
| | | } |
| | | |
| | | // æ¹éæ¥è¯¢ä»»å¡è¯¦æ
|
| | | const taskPromises = taskIds.map(taskId => |
| | | getTask(taskId).then(res => res.data).catch(() => null) |
| | | ); |
| | | |
| | | Promise.all(taskPromises).then(tasks => { |
| | | // è¿æ»¤æç©ºå¼å¹¶ææ¶é´æåº |
| | | this.vehicleTaskList = tasks |
| | | .filter(task => task !== null) |
| | | .sort((a, b) => { |
| | | const timeA = new Date(a.plannedStartTime || a.createTime).getTime(); |
| | | const timeB = new Date(b.plannedStartTime || b.createTime).getTime(); |
| | | return timeB - timeA; // éåºæå |
| | | }); |
| | | |
| | | this.taskListLoading = false; |
| | | }).catch(error => { |
| | | console.error('æ¥è¯¢ä»»å¡è¯¦æ
失败:', error); |
| | | this.$modal.msgError('å è½½ä»»å¡æ¸
å失败'); |
| | | this.taskListLoading = false; |
| | | }); |
| | | }).catch(error => { |
| | | console.error('æ¥è¯¢è½¦è¾ä»»å¡å
³è失败:', error); |
| | | this.$modal.msgError('å è½½ä»»å¡æ¸
å失败'); |
| | | this.taskListLoading = false; |
| | | }); |
| | | }, |
| | | /** æ¥çä»»å¡è¯¦æ
*/ |
| | | handleViewTaskDetail(taskId) { |
| | | // 跳转å°ä»»å¡è¯¦æ
é¡µé¢ |
| | | this.$router.push('/task/general-detail/index/' + taskId); |
| | | }, |
| | | /** ä»»å¡éæ©åå */ |
| | | handleTaskChange(taskId) { |
| | | if (taskId) { |
| New file |
| | |
| | | -- 为tb_vehicle_gps表çcollect_timeåæ®µæ·»å ç´¢å¼ |
| | | -- ç¨äºä¼åGPSåæ®µéç¨è®¡ç®æ¶çæ¥è¯¢æ§è½,é¿å
å
¨è¡¨æ«æå¯¼è´è¶
æ¶ |
| | | |
| | | -- æ£æ¥ç´¢å¼æ¯å¦å·²åå¨(MySQL 5.5å
¼å®¹è¯æ³) |
| | | -- å¦æç´¢å¼å·²åå¨,请忽ç¥ä¸é¢çCREATE INDEXè¯å¥ |
| | | |
| | | -- æ·»å collect_timeç´¢å¼(ç¨äºæ¶é´èå´æ¥è¯¢) |
| | | CREATE INDEX idx_collect_time ON tb_vehicle_gps(collect_time); |
| | | |
| | | -- æ·»å vehicle_idåcollect_timeçå¤åç´¢å¼(ç¨äºåè½¦è¾æ¶é´èå´æ¥è¯¢) |
| | | CREATE INDEX idx_vehicle_collect_time ON tb_vehicle_gps(vehicle_id, collect_time); |
| | | |
| | | -- ç´¢å¼è¯´æ: |
| | | -- 1. idx_collect_time: ç¨äºselectActiveVehicleIdsæ¥è¯¢,å éææ¶é´è¿æ»¤ |
| | | -- 2. idx_vehicle_collect_time: ç¨äºselectGpsDataByTimeRangeåselectUncalculatedGpsæ¥è¯¢ |
| | | -- æè½¦è¾ID+æ¶é´èå´æ¥è¯¢æ¶å¯æ¾èæåæ§è½ |
| | | |
| | | -- éªè¯ç´¢å¼å建æå |
| | | SHOW INDEX FROM tb_vehicle_gps WHERE Key_name IN ('idx_collect_time', 'idx_vehicle_collect_time'); |
| New file |
| | |
| | | -- ---------------------------- |
| | | -- æ·»å æ§ç³»ç»ServiceOrdNoåæ®µï¼ç¨äºä¿å仿§ç³»ç»åæ¥ç转è¿åç¼å· |
| | | -- ---------------------------- |
| | | |
| | | -- 卿¥æè½¬è¿æ©å±è¡¨ä¸æ·»å legacy_service_ord_noåæ®µ |
| | | ALTER TABLE sys_task_emergency |
| | | ADD COLUMN legacy_service_ord_no VARCHAR(50) NULL COMMENT 'æ§ç³»ç»ServiceOrdNoï¼è½¬è¿åç¼å·ï¼' AFTER need_resync; |
| | | |
| | | -- ä¸ºè¯¥åæ®µæ·»å ç´¢å¼ä»¥ä¾¿å¿«éæ¥è¯¢ |
| | | ALTER TABLE sys_task_emergency |
| | | ADD INDEX idx_legacy_service_ord_no (legacy_service_ord_no); |
| | | |
| | | -- æ¥è¯¢ç¤ºä¾ï¼ |
| | | -- SELECT task_id, legacy_service_ord_id, legacy_service_ord_no, legacy_dispatch_ord_id |
| | | -- FROM sys_task_emergency |
| | | -- WHERE legacy_service_ord_no IS NOT NULL |
| | | -- ORDER BY id DESC; |
| New file |
| | |
| | | -- ä¿®å¤è½¦è¾éç¨ç»è®¡è¡¨ä¸çé夿°æ® |
| | | -- æ§è¡å请å
å¤ä»½æ°æ®ï¼ |
| | | |
| | | -- 1. æ¥çé夿°æ® |
| | | SELECT vehicle_id, stat_date, COUNT(*) as count |
| | | FROM tb_vehicle_mileage_stats |
| | | GROUP BY vehicle_id, stat_date |
| | | HAVING COUNT(*) > 1; |
| | | |
| | | -- 2. å é¤éå¤è®°å½ï¼ä¿çææ°ç䏿¡ï¼æ ¹æ®stats_idæå¤§çä¿çï¼ |
| | | DELETE t1 FROM tb_vehicle_mileage_stats t1 |
| | | INNER JOIN ( |
| | | SELECT vehicle_id, stat_date, MAX(stats_id) as max_id |
| | | FROM tb_vehicle_mileage_stats |
| | | GROUP BY vehicle_id, stat_date |
| | | HAVING COUNT(*) > 1 |
| | | ) t2 ON t1.vehicle_id = t2.vehicle_id |
| | | AND t1.stat_date = t2.stat_date |
| | | AND t1.stats_id < t2.max_id; |
| | | |
| | | -- 3. éªè¯æ¯å¦è¿æé夿°æ® |
| | | SELECT vehicle_id, stat_date, COUNT(*) as count |
| | | FROM tb_vehicle_mileage_stats |
| | | GROUP BY vehicle_id, stat_date |
| | | HAVING COUNT(*) > 1; |
| | | |
| | | -- 4. 确认å¯ä¸ç´¢å¼æ¯å¦åå¨ |
| | | SHOW INDEX FROM tb_vehicle_mileage_stats WHERE Key_name = 'uk_vehicle_date'; |
| | | |
| | | -- 妿å¯ä¸ç´¢å¼ä¸åå¨ï¼éæ°å建 |
| | | -- ALTER TABLE tb_vehicle_mileage_stats |
| | | -- ADD UNIQUE KEY `uk_vehicle_date` (`vehicle_id`, `stat_date`); |
| New file |
| | |
| | | -- GPSåæ®µéç¨è¡¥å¿è®¡ç®å®æ¶ä»»å¡é
ç½® |
| | | -- ç¨äºè¡¥å¿å æå¡æ
éãéå¯çåå 导è´éæ¼çGPSæ°æ®è®¡ç® |
| | | |
| | | -- GPSåæ®µéç¨è¡¥å¿è®¡ç®ä»»å¡ï¼æ¯å¤©åæ¨2ç¹æ§è¡ï¼å溯7å¤©æ°æ®ï¼ |
| | | INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) |
| | | VALUES ( |
| | | 'GPSåæ®µéç¨è¡¥å¿è®¡ç®', |
| | | 'DEFAULT', |
| | | 'vehicleGpsSegmentMileageTask.executeCompensationCalculation(''7'')', |
| | | '0 0 2 * * ?', |
| | | '2', |
| | | '0', |
| | | '1', |
| | | 'admin', |
| | | NOW(), |
| | | 'æ¯å¤©åæ¨2ç¹æ§è¡ï¼æ£æ¥æè¿7天å
æªè¢«å¤ççGPSåæ å¹¶è¿è¡è¡¥å¿è®¡ç®ãåæ°7è¡¨ç¤ºåæº¯7天ï¼å¯æ ¹æ®éè¦è°æ´' |
| | | ); |
| | | |
| | | -- é
置说æ |
| | | -- 1. ä»»å¡é»è®¤ç¶æä¸º'1'ï¼æåï¼ï¼éè¦å¨åå°ç®¡çç³»ç»ä¸æå¨å¯å¨ |
| | | -- 2. 建议å¨åæ¨æ§è¡ï¼é¿å
å½±åç½å¤©ä¸å¡é«å³° |
| | | -- 3. åæº¯å¤©æ°å¯éè¿åæ°è°æ´ï¼å»ºè®®ä¸è¶
è¿30天ï¼é¿å
æ°æ®éè¿å¤§å½±åæ§è½ |
| | | -- 4. è¡¥å¿è®¡ç®é»è¾ï¼ |
| | | -- - æ¥è¯¢æå®æ¶é´èå´å
ææè½¦è¾ |
| | | -- - æ£æ¥æ¯è¾è½¦çGPSåæ æ¯å¦å·²è¢«å段å¤çï¼éè¿segment_idå¤æï¼ |
| | | -- - 对æªå¤ççGPSåæ æ§è¡å段éç¨è®¡ç® |
| | | -- - èªå¨å
³èä»»å¡IDåä»»å¡ç¼å· |
| | | -- 5. ä¸å®æ¶è®¡ç®ä»»å¡çåºå«ï¼ |
| | | -- - 宿¶è®¡ç®ï¼å¤çæè¿çGPSæ°æ®ï¼å¦æè¿10åéï¼ |
| | | -- - è¡¥å¿è®¡ç®ï¼åæº¯æ£æ¥å岿°æ®ï¼è¡¥å
éæ¼çè®¡ç® |
| | | -- 6. cron表达å¼è¯´æï¼ |
| | | -- - '0 0 2 * * ?' : æ¯å¤©åæ¨2ç¹æ§è¡ |
| | | -- - 坿 ¹æ®å®é
æ
åµè°æ´æ§è¡æ¶é´ |
| | | |
| | | -- 使ç¨ç¤ºä¾ |
| | | -- 1. é»è®¤å溯7天ï¼executeCompensationCalculation() æ executeCompensationCalculation('7') |
| | | -- 2. åæº¯3天ï¼executeCompensationCalculation('3') |
| | | -- 3. åæº¯30天ï¼executeCompensationCalculation('30') |
| New file |
| | |
| | | -- GPSæ¥è¯¢æ§è½ä¼åSQL |
| | | -- ç¨äºè§£å³GPSåæ®µéç¨è®¡ç®ä»»å¡æ¥è¯¢è¶
æ¶é®é¢ |
| | | |
| | | -- 1. æ£æ¥tb_vehicle_gps表çç´¢å¼ |
| | | SHOW INDEX FROM tb_vehicle_gps; |
| | | |
| | | -- 2. æ·»å ç»åç´¢å¼ï¼vehicle_id + collect_timeï¼å¦æä¸åå¨ï¼ |
| | | -- è¿ä¸ªç´¢å¼å¯ä»¥å¤§å¹
æåæè½¦è¾IDåæ¶é´èå´æ¥è¯¢çæ§è½ |
| | | ALTER TABLE tb_vehicle_gps |
| | | ADD INDEX idx_vehicle_collect_time (vehicle_id, collect_time); |
| | | |
| | | -- 3. æ·»å ååç´¢å¼ï¼collect_timeï¼å¦æä¸åå¨ï¼ |
| | | -- è¿ä¸ªç´¢å¼ç¨äºä¼åæ¥è¯¢æ´»è·è½¦è¾IDçæ¥è¯¢ |
| | | ALTER TABLE tb_vehicle_gps |
| | | ADD INDEX idx_collect_time (collect_time); |
| | | |
| | | -- 4. æ£æ¥tb_vehicle_gps_calculated表çç´¢å¼ |
| | | SHOW INDEX FROM tb_vehicle_gps_calculated; |
| | | |
| | | -- 5. ä¼åtb_vehicle_gps_calculatedè¡¨ç´¢å¼ |
| | | -- æ·»å gps_idç´¢å¼ï¼å¦æä¸åå¨ï¼ï¼ç¨äºLEFT JOINæ¥è¯¢ä¼å |
| | | ALTER TABLE tb_vehicle_gps_calculated |
| | | ADD INDEX idx_gps_id (gps_id); |
| | | |
| | | -- 6. æ·»å vehicle_idç´¢å¼ï¼ç¨äºæè½¦è¾æ¥è¯¢å·²è®¡ç®è®°å½ |
| | | ALTER TABLE tb_vehicle_gps_calculated |
| | | ADD INDEX idx_vehicle_id (vehicle_id); |
| | | |
| | | -- 7. æ¥ç表çç»è®¡ä¿¡æ¯ |
| | | ANALYZE TABLE tb_vehicle_gps; |
| | | ANALYZE TABLE tb_vehicle_gps_calculated; |
| | | |
| | | -- 8. æ¥çç´¢å¼ä½¿ç¨æ
åµ |
| | | -- æ§è¡ä»¥ä¸æ¥è¯¢æ¥éªè¯ç´¢å¼æ¯å¦è¢«æ£ç¡®ä½¿ç¨ |
| | | EXPLAIN SELECT DISTINCT vehicle_id |
| | | FROM tb_vehicle_gps |
| | | WHERE collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) |
| | | ORDER BY vehicle_id; |
| | | |
| | | EXPLAIN SELECT g.gps_id, g.vehicle_id, g.device_id, g.longitude, g.latitude, |
| | | g.altitude, g.speed, g.direction, g.collect_time |
| | | FROM tb_vehicle_gps g |
| | | LEFT JOIN tb_vehicle_gps_calculated c ON g.gps_id = c.gps_id |
| | | WHERE g.vehicle_id = 1 |
| | | AND g.collect_time >= DATE_SUB(NOW(), INTERVAL 1 DAY) |
| | | AND g.collect_time <= NOW() |
| | | AND c.gps_id IS NULL |
| | | ORDER BY g.collect_time; |
| | | |
| | | -- 9. æ§è½ä¼å建议 |
| | | /* |
| | | æ§è¡ç»æè¯´æï¼ |
| | | - typeåºè¯¥æ¯refærangeï¼ä¸åºè¯¥æ¯ALLï¼å
¨è¡¨æ«æï¼ |
| | | - keyåºè¯¥æ¾ç¤ºä½¿ç¨äºç¸åºçç´¢å¼ |
| | | - rowsåºè¯¥å°½å¯è½å° |
| | | |
| | | 妿åç°ç´¢å¼æªè¢«ä½¿ç¨ï¼å¯è½éè¦ï¼ |
| | | 1. æ´æ°è¡¨ç»è®¡ä¿¡æ¯ï¼ANALYZE TABLE |
| | | 2. æ£æ¥MySQLçæ¬æ¯å¦æ¯æç´¢å¼ä¼å |
| | | 3. èèå¢å MySQLçinnodb_buffer_pool_sizeé
ç½® |
| | | */ |
| | | |
| | | -- 10. æ¸
çåå²GPSæ°æ®ï¼å¯éï¼å®ææ§è¡ï¼ |
| | | -- 建议ä¿çæè¿30-90å¤©çæ°æ®ï¼é¿å
表è¿å¤§å½±åæ¥è¯¢æ§è½ |
| | | /* |
| | | DELETE FROM tb_vehicle_gps |
| | | WHERE collect_time < DATE_SUB(NOW(), INTERVAL 90 DAY); |
| | | |
| | | -- ä¼åè¡¨ç©ºé´ |
| | | OPTIMIZE TABLE tb_vehicle_gps; |
| | | */ |
| New file |
| | |
| | | # æ§ç³»ç»ServiceOrdNoåæ®µåæ¥åè½è¯´æ |
| | | |
| | | ## ä¸ãåè½æ¦è¿° |
| | | |
| | | å¨ä»æ§ç³»ç»åæ¥è½¬è¿åï¼ServiceOrderï¼å°æ°ç³»ç»æ¶ï¼é¤äºå·²æç`ServiceOrdID`ï¼æå¡åIDï¼å`DispatchOrdID`ï¼è°åº¦åIDï¼ï¼ç°å¨è¿ä¼åæ¥`ServiceOrdNo`ï¼è½¬è¿åç¼å·ï¼å段ï¼å¹¶ä¿åå°`sys_task_emergency`表ä¸ã |
| | | |
| | | ## äºãæ°æ®åºåæ´ |
| | | |
| | | ### æ°å¢å段 |
| | | |
| | | å¨`sys_task_emergency`è¡¨ä¸æ·»å 以ä¸åæ®µï¼ |
| | | |
| | | ```sql |
| | | -- æ§ç³»ç»ServiceOrdNoï¼è½¬è¿åç¼å·ï¼ |
| | | ALTER TABLE sys_task_emergency |
| | | ADD COLUMN legacy_service_ord_no VARCHAR(50) NULL COMMENT 'æ§ç³»ç»ServiceOrdNoï¼è½¬è¿åç¼å·ï¼' AFTER need_resync; |
| | | |
| | | -- æ·»å ç´¢å¼ |
| | | ALTER TABLE sys_task_emergency |
| | | ADD INDEX idx_legacy_service_ord_no (legacy_service_ord_no); |
| | | ``` |
| | | |
| | | ### åæ®µè¯´æ |
| | | |
| | | | åæ®µå | ç±»å | 说æ | ç¤ºä¾ | |
| | | |--------|------|------|------| |
| | | | legacy_service_ord_no | VARCHAR(50) | æ§ç³»ç»è½¬è¿åç¼å· | "123"ã"045"ç | |
| | | |
| | | **注æ**ï¼`ServiceOrdNo`åæ®µå¨æ§ç³»ç»ä¸æ¯æ°åç±»åï¼å¨çæä»»å¡ç¼å·æ¶ä¼è¢«æ ¼å¼å为3使°åå符串ï¼å¦ 32 â "032"ï¼1 â "001"ï¼ã |
| | | |
| | | ## ä¸ã代ç åæ´ |
| | | |
| | | ### 1. å®ä½ç±»ä¿®æ¹ |
| | | |
| | | **æä»¶**: `SysTaskEmergency.java` |
| | | |
| | | æ°å¢å±æ§ï¼ |
| | | ```java |
| | | /** æ§ç³»ç»ServiceOrdNoï¼è½¬è¿åç¼å·ï¼ */ |
| | | private String legacyServiceOrdNo; |
| | | ``` |
| | | |
| | | æ°å¢getter/setteræ¹æ³ã |
| | | |
| | | ### 2. Mapper XMLä¿®æ¹ |
| | | |
| | | **æä»¶**: `SysTaskEmergencyMapper.xml` |
| | | |
| | | - å¨`resultMap`䏿·»å åæ®µæ å° |
| | | - å¨`selectSysTaskEmergencyVo`䏿·»å æ¥è¯¢å段 |
| | | - å¨`insertSysTaskEmergency`䏿·»å æå
¥é»è¾ |
| | | - å¨`updateSysTaskEmergency`䏿·»å æ´æ°é»è¾ |
| | | |
| | | ### 3. Serviceæ¥å£ä¿®æ¹ |
| | | |
| | | **æä»¶**: `ISysTaskService.java` |
| | | |
| | | ä¿®æ¹æ¹æ³ç¾åï¼æ·»å `serviceOrdNo`åæ°ï¼ |
| | | ```java |
| | | public int insertTask(TaskCreateVO createVO, String serviceOrderId, |
| | | String dispatchOrderId, String serviceOrdNo, |
| | | Long userId, String userName, Long deptId, |
| | | Date createTime, Date updateTime); |
| | | ``` |
| | | |
| | | ### 4. Serviceå®ç°ä¿®æ¹ |
| | | |
| | | **æä»¶**: `SysTaskServiceImpl.java` |
| | | |
| | | 1. ä¿®æ¹`insertTask`æ¹æ³ç¾åï¼æ·»å `serviceOrdNo`åæ° |
| | | 2. ä¿®æ¹`saveEmergencyInfo`æ¹æ³ç¾åï¼æ·»å `serviceOrdNo`åæ° |
| | | 3. å¨`saveEmergencyInfo`æ¹æ³ä¸ä¿å`serviceOrdNo`ï¼ |
| | | |
| | | ```java |
| | | if(serviceOrdNo!=null){ |
| | | emergencyInfo.setLegacyServiceOrdNo(serviceOrdNo); |
| | | } |
| | | ``` |
| | | |
| | | ### 5. 忥æå¡ä¿®æ¹ |
| | | |
| | | **æä»¶**: `LegacyTransferSyncServiceImpl.java` |
| | | |
| | | å¨`syncSingleTransferOrder`æ¹æ³ä¸ï¼ |
| | | |
| | | 1. 仿§ç³»ç»æ¥è¯¢ç»æä¸æå`ServiceOrdNo`ï¼ |
| | | ```java |
| | | String serviceOrdNo = getStringValue(order, "ServiceOrdNo"); |
| | | ``` |
| | | |
| | | 2. è°ç¨`insertTask`æ¹æ³æ¶ä¼ é`serviceOrdNo`åæ°ï¼ |
| | | ```java |
| | | int result = sysTaskService.insertTask(createTaskVo, serviceOrdID, |
| | | dispatchOrdID, serviceOrdNo, |
| | | taskCreatorId, createUserName, |
| | | deptId, ServiceOrd_CC_Time, ServiceOrd_CC_Time); |
| | | ``` |
| | | |
| | | ## åãæ°æ®æµè½¬ |
| | | |
| | | ``` |
| | | æ§ç³»ç» ServiceOrder 表 |
| | | â (æ¥è¯¢) |
| | | LegacyTransferSyncServiceImpl |
| | | â (æå) |
| | | ServiceOrdNo åæ®µ |
| | | â (ä¼ é) |
| | | SysTaskService.insertTask() |
| | | â (ä¿å) |
| | | SysTaskEmergency.legacy_service_ord_no |
| | | ``` |
| | | |
| | | ## äºã使ç¨åºæ¯ |
| | | |
| | | ### 1. æ°æ®è¿½æº¯ |
| | | éè¿`legacy_service_ord_no`åæ®µå¯ä»¥å¿«é卿§ç³»ç»ä¸å®ä½åå§è½¬è¿åæ°æ®ã |
| | | |
| | | ### 2. ä»»å¡ç¼å·çæ |
| | | `ServiceOrdNo`åæ®µç¨äºçææ°ç³»ç»çä»»å¡ç¼å·ï¼`task_code`ï¼ï¼æ ¼å¼ä¸ºï¼ |
| | | ``` |
| | | {ServiceOrdClass}{YYYYMMDD}-{ServiceOrdNo(3ä½)} |
| | | ``` |
| | | ä¾å¦ï¼`BF20251101-032` |
| | | |
| | | ### 3. æ°æ®æ¥è¯¢ |
| | | |
| | | æ¥è¯¢å·²åæ¥ç转è¿ååå
¶ç¼å·ï¼ |
| | | ```sql |
| | | SELECT |
| | | t.task_id, |
| | | t.task_code, |
| | | e.legacy_service_ord_id, |
| | | e.legacy_service_ord_no, |
| | | e.legacy_dispatch_ord_id, |
| | | e.sync_status |
| | | FROM sys_task t |
| | | JOIN sys_task_emergency e ON t.task_id = e.task_id |
| | | WHERE e.legacy_service_ord_no IS NOT NULL |
| | | ORDER BY t.create_time DESC; |
| | | ``` |
| | | |
| | | æ`ServiceOrdNo`æ¥è¯¢ç¹å®è½¬è¿åï¼ |
| | | ```sql |
| | | SELECT |
| | | t.task_id, |
| | | t.task_code, |
| | | t.task_status, |
| | | e.patient_name, |
| | | e.hospital_out_name, |
| | | e.hospital_in_name |
| | | FROM sys_task t |
| | | JOIN sys_task_emergency e ON t.task_id = e.task_id |
| | | WHERE e.legacy_service_ord_no = '032'; |
| | | ``` |
| | | |
| | | ## å
ãæµè¯éªè¯ |
| | | |
| | | ### æµè¯æ¥éª¤ |
| | | |
| | | 1. **æ§è¡æ°æ®åºèæ¬** |
| | | ```bash |
| | | mysql -uç¨æ·å -pæ°æ®åºå < sql/add_legacy_service_ord_no.sql |
| | | ``` |
| | | |
| | | 2. **éå¯åºç¨** |
| | | ç¡®ä¿æ°ä»£ç çæã |
| | | |
| | | 3. **触å忥任å¡** |
| | | - æ¹å¼1ï¼æå¨è°ç¨å®æ¶ä»»å¡ |
| | | - æ¹å¼2ï¼çå¾
èªå¨å®æ¶ä»»å¡æ§è¡ |
| | | |
| | | 4. **éªè¯æ°æ®** |
| | | ```sql |
| | | SELECT task_id, legacy_service_ord_id, legacy_service_ord_no |
| | | FROM sys_task_emergency |
| | | WHERE sync_status = 2 |
| | | ORDER BY id DESC |
| | | LIMIT 10; |
| | | ``` |
| | | |
| | | ### é¢æç»æ |
| | | |
| | | - `legacy_service_ord_no`åæ®µåºå
å«ä»æ§ç³»ç»åæ¥ç`ServiceOrdNo`å¼ |
| | | - è¯¥åæ®µä¸ä¸ºç©ºä¸æ ¼å¼æ£ç¡®ï¼é常为1-3使°åï¼ |
| | | - ä¸`legacy_service_ord_id`ä¸ä¸å¯¹åº |
| | | |
| | | ## ä¸ã注æäºé¡¹ |
| | | |
| | | 1. **åæ®µå¯ç©ºæ§**ï¼`legacy_service_ord_no`åæ®µå
许为NULLï¼å ä¸ºï¼ |
| | | - æ§ä»»å¡å¯è½æ²¡æè¯¥å段 |
| | | - 仿°ç³»ç»å建çä»»å¡ä¸ä¼ææ¤å段 |
| | | |
| | | 2. **æ°æ®ç±»å**ï¼è½ç¶`ServiceOrdNo`卿§ç³»ç»ä¸æ¯æ°åï¼ä½å¨æ°ç³»ç»ä¸ä½¿ç¨VARCHARç±»ååå¨ï¼ä»¥ä¿æåå§æ ¼å¼ã |
| | | |
| | | 3. **ååå
¼å®¹**ï¼æ¤ä¿®æ¹ä¸å½±åå·²åå¨çæ°æ®ååè½ï¼åªå¯¹æ°åæ¥ç转è¿åææã |
| | | |
| | | 4. **ä»»å¡ç¼å·çæ**ï¼`ServiceOrdNo`ç¨äºçæä»»å¡ç¼å·ï¼ä½å¦æè¯¥å段为空ï¼ç³»ç»ä¼èªå¨çææ°çä»»å¡ç¼å·ã |
| | | |
| | | ## å
«ãç¸å
³æä»¶æ¸
å |
| | | |
| | | ### æ°æ®åºèæ¬ |
| | | - `sql/add_legacy_service_ord_no.sql` - æ·»å åæ®µçSQLèæ¬ |
| | | |
| | | ### Javaæä»¶ |
| | | - `ruoyi-system/src/main/java/com/ruoyi/system/domain/SysTaskEmergency.java` |
| | | - `ruoyi-system/src/main/java/com/ruoyi/system/service/ISysTaskService.java` |
| | | - `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysTaskServiceImpl.java` |
| | | - `ruoyi-system/src/main/java/com/ruoyi/system/service/impl/LegacyTransferSyncServiceImpl.java` |
| | | |
| | | ### Mapperæä»¶ |
| | | - `ruoyi-system/src/main/resources/mapper/system/SysTaskEmergencyMapper.xml` |
| | | |
| | | ### ææ¡£ |
| | | - `æ§ç³»ç»ServiceOrdNoåæ®µåæ¥åè½è¯´æ.md` - æ¬ææ¡£ |
| | | |
| | | ## ä¹ã常è§é®é¢ |
| | | |
| | | ### Q1: ServiceOrdNoåæ®µä¸ºä»ä¹æ¯VARCHARç±»åï¼ |
| | | **A**: è½ç¶å¨æ§ç³»ç»ä¸æ¯æ°åç±»åï¼ä½ä½¿ç¨VARCHARå¯ä»¥ï¼ |
| | | - ä¿çåå§æ ¼å¼ï¼å¦å导é¶ï¼ |
| | | - é¿å
ç±»å转æ¢é误 |
| | | - æ´çµæ´»å°å¤çç¹æ®æ
åµ |
| | | |
| | | ### Q2: 妿æ§ç³»ç»ä¸ServiceOrdNo为空æä¹åï¼ |
| | | **A**: 代ç 䏿NULLæ£æ¥ï¼å¦æ`ServiceOrdNo`为空ï¼è¯¥åæ®µå¨æ°ç³»ç»ä¸ä¹ä¸ºNULLï¼ä¸å½±åå
¶ä»ä¸å¡ã |
| | | |
| | | ### Q3: 已忥çå岿°æ®ä¼æ´æ°è¿ä¸ªå段åï¼ |
| | | **A**: ä¸ä¼ãæ¤åè½åªå¯¹æ°åæ¥ç转è¿åææãå¦éæ´æ°å岿°æ®ï¼éè¦ç¼åä¸é¨çæ°æ®è¿ç§»èæ¬ã |
| | | |
| | | ### Q4: è¿ä¸ªå段ä¼å½±åç°æåè½åï¼ |
| | | **A**: ä¸ä¼ãè¿æ¯ä¸ä¸ªæ°å¢å段ï¼ä¸å½±åä»»ä½ç°æä¸å¡é»è¾ï¼å®å
¨ååå
¼å®¹ã |
| | | |
| | | ## åãåç»ä¼å建议 |
| | | |
| | | 1. **å岿°æ®åå¡«**ï¼å¯ä»¥ç¼åèæ¬ä¸ºå·²åæ¥çåå²ä»»å¡åå¡«`legacy_service_ord_no`åæ®µã |
| | | |
| | | 2. **å端å±ç¤º**ï¼å¯ä»¥å¨ä»»å¡è¯¦æ
页é¢å±ç¤ºè¯¥åæ®µï¼æ¹ä¾¿ç¨æ·æ¥çåå§è½¬è¿åç¼å·ã |
| | | |
| | | 3. **æ°æ®æ ¡éª**ï¼å¯ä»¥æ·»å æ°æ®ä¸è´æ§æ ¡éªï¼ç¡®ä¿`legacy_service_ord_id`å`legacy_service_ord_no`ç对åºå
³ç³»æ£ç¡®ã |
| | | |
| | | --- |
| | | |
| | | **æ´æ°æ¥æ**: 2024-11-30 |
| | | **çæ¬**: v1.0 |