| | |
| | | region: region || '广å·' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // ==================== 天å°å¾æ¥å£ ==================== |
| | | |
| | | // 天å°å¾å°çç¼ç APIï¼å°åè½¬åæ ï¼ |
| | | export function tiandituGeocoding(address) { |
| | | // åæ°éªè¯ |
| | | if (!address) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´,缺å°å°åä¿¡æ¯')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/geocoding', |
| | | method: 'get', |
| | | params: { |
| | | address: address |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 天å°å¾éå°çç¼ç APIï¼åæ 转å°åï¼ |
| | | export function tiandituReverseGeocoding(lon, lat) { |
| | | // åæ°éªè¯ |
| | | if (lat === undefined || lat === null || lon === undefined || lon === null) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´,缺å°ç»çº¬åº¦åæ ')) |
| | | } |
| | | |
| | | // æ£æ¥åæ°æææ§ |
| | | if (isNaN(lat) || isNaN(lon)) { |
| | | return Promise.reject(new Error('åæ°æ æ,ç»çº¬åº¦åæ æ ¼å¼é误')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/reverseGeocoding', |
| | | method: 'get', |
| | | params: { |
| | | lon: lon, |
| | | lat: lat |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 天å°å¾POIæç´¢API |
| | | export function tiandituPlaceSearch(keyWord, queryType, level, mapBound, start, count) { |
| | | // åæ°éªè¯ |
| | | if (!keyWord) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´,ç¼ºå°æç´¢å
³é®è¯')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/place/search', |
| | | method: 'get', |
| | | params: { |
| | | keyWord: keyWord, |
| | | queryType: queryType || '1', |
| | | level: level, |
| | | mapBound: mapBound, |
| | | start: start || 0, |
| | | count: count || 10 |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 天å°å¾é©¾è½¦è·¯å¾è§åAPI |
| | | export function tiandituRouteDriving(orig, dest, mid, style) { |
| | | // åæ°éªè¯ |
| | | if (!orig || !dest) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´,缺å°èµ·ç¹æç»ç¹åæ ')) |
| | | } |
| | | |
| | | // éªè¯åæ æ ¼å¼ï¼ç»åº¦,çº¬åº¦ï¼ |
| | | const origParts = orig.split(',') |
| | | const destParts = dest.split(',') |
| | | if (origParts.length !== 2 || destParts.length !== 2) { |
| | | return Promise.reject(new Error('åæ æ ¼å¼é误,åºä¸º:ç»åº¦,纬度')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/route/driving', |
| | | method: 'get', |
| | | params: { |
| | | orig: orig, |
| | | dest: dest, |
| | | mid: mid, |
| | | style: style || '0' |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 天å°å¾è®¡ç®ä¸¤ä¸ªå°åä¹é´çè·ç¦»ï¼ç»åæ¥å£ï¼å°åè½¬åæ + è·¯å¾è§åï¼ |
| | | export function tiandituDistanceByAddress(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 tiandituPlaceSuggestion(keyWord, region, city, count) { |
| | | // åæ°éªè¯ |
| | | if (!keyWord) { |
| | | return Promise.reject(new Error('åæ°ä¸å®æ´,ç¼ºå°æç´¢å
³é®è¯')) |
| | | } |
| | | |
| | | return request({ |
| | | url: '/system/gps/tianditu/place/suggestion', |
| | | method: 'get', |
| | | params: { |
| | | keyWord: keyWord, |
| | | region: region, |
| | | city: city, |
| | | count: count || 10 |
| | | } |
| | | }) |
| | | } |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // æ¥è¯¢è½¦è¾éç¨ç»è®¡å表 |
| | | export function listMileageStats(query) { |
| | | return request({ |
| | | url: '/system/mileageStats/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | | } |
| | | |
| | | // æ¥è¯¢è½¦è¾éç¨ç»è®¡è¯¦ç» |
| | | export function getMileageStats(statsId) { |
| | | return request({ |
| | | url: '/system/mileageStats/' + statsId, |
| | | method: 'get' |
| | | }) |
| | | } |
| | | |
| | | // æ°å¢è½¦è¾éç¨ç»è®¡ |
| | | export function addMileageStats(data) { |
| | | return request({ |
| | | url: '/system/mileageStats', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // ä¿®æ¹è½¦è¾éç¨ç»è®¡ |
| | | export function updateMileageStats(data) { |
| | | return request({ |
| | | url: '/system/mileageStats', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // å é¤è½¦è¾éç¨ç»è®¡ |
| | | export function delMileageStats(statsIds) { |
| | | return request({ |
| | | url: '/system/mileageStats/' + statsIds, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | | |
| | | // æå¨è®¡ç®æå®è½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | export function calculateMileage(vehicleId, statDate) { |
| | | return request({ |
| | | url: '/system/mileageStats/calculate', |
| | | method: 'post', |
| | | params: { |
| | | vehicleId: vehicleId, |
| | | statDate: statDate |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // æ¹éè®¡ç®æå®æ¥æææè½¦è¾çéç¨ç»è®¡ |
| | | export function batchCalculateMileage(statDate) { |
| | | return request({ |
| | | url: '/system/mileageStats/batchCalculate', |
| | | method: 'post', |
| | | params: { |
| | | statDate: statDate |
| | | } |
| | | }) |
| | | } |
| | |
| | | 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.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | |
| | | |
| | | @Autowired |
| | | private BaiduMapConfig baiduMapConfig; |
| | | |
| | | @Autowired |
| | | private TiandituMapConfig tiandituMapConfig; |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾GPSåæ å表 |
| | |
| | | return AjaxResult.error("å°åæç´¢å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | // ==================== 天å°å¾æ¥å£ ==================== |
| | | |
| | | /** |
| | | * 天å°å¾å°çç¼ç æ¥å£ä»£çï¼å°åè½¬åæ ï¼ |
| | | * ææ¡£ï¼https://lbs.tianditu.gov.cn/server/geocoding.html |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/geocoding") |
| | | public AjaxResult tiandituGeocoding(String address) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | 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); |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾å°çç¼ç 失败", e); |
| | | return AjaxResult.error("å°çç¼ç 失败ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 天å°å¾éå°çç¼ç æ¥å£ä»£çï¼åæ 转å°åï¼ |
| | | * ææ¡£ï¼https://lbs.tianditu.gov.cn/server/geocoding.html |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/reverseGeocoding") |
| | | public AjaxResult tiandituReverseGeocoding(Double lon, Double lat) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (lat == null || lon == null) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°ç»çº¬åº¦åæ "); |
| | | } |
| | | |
| | | // æ£æ¥åæ°æææ§ |
| | | if (Double.isNaN(lat) || Double.isNaN(lon) || |
| | | Double.isInfinite(lat) || Double.isInfinite(lon)) { |
| | | return AjaxResult.error("åæ°æ æï¼ç»çº¬åº¦åæ æ ¼å¼é误"); |
| | | } |
| | | |
| | | // æå»ºå¤©å°å¾éå°çç¼ç 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); |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾éå°çç¼ç 失败: lon={}, lat={}", lon, lat, e); |
| | | return AjaxResult.error("éå°çç¼ç 失败ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 天å°å¾å°ç¹æç´¢æ¥å£ä»£çï¼POIæç´¢ï¼ |
| | | * ææ¡£ï¼https://lbs.tianditu.gov.cn/server/search.html |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/place/search") |
| | | public AjaxResult tiandituPlaceSearch(String keyWord, String queryType, String level, |
| | | String mapBound, Integer start, Integer count) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (keyWord == null || keyWord.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°æç´¢å
³é®è¯"); |
| | | } |
| | | |
| | | // 设置é»è®¤å¼ |
| | | if (queryType == null || queryType.trim().isEmpty()) { |
| | | queryType = "1"; // 1-æ®éæç´¢ï¼7-å¨è¾¹æç´¢ |
| | | } |
| | | if (start == null) { |
| | | start = 0; |
| | | } |
| | | if (count == null) { |
| | | count = 10; |
| | | } |
| | | |
| | | // æå»ºå¤©å°å¾POIæç´¢API URL |
| | | String url = "http://api.tianditu.gov.cn/search"; |
| | | StringBuilder paramsBuilder = new StringBuilder(); |
| | | paramsBuilder.append("postStr={\"keyWord\":\"").append(keyWord).append("\""); |
| | | paramsBuilder.append(",\"queryType\":\"").append(queryType).append("\""); |
| | | if (level != null && !level.trim().isEmpty()) { |
| | | paramsBuilder.append(",\"level\":\"").append(level).append("\""); |
| | | } |
| | | if (mapBound != null && !mapBound.trim().isEmpty()) { |
| | | paramsBuilder.append(",\"mapBound\":\"").append(mapBound).append("\""); |
| | | } |
| | | paramsBuilder.append(",\"start\":\"").append(start).append("\""); |
| | | paramsBuilder.append(",\"count\":\"").append(count).append("\""); |
| | | paramsBuilder.append("}" ); |
| | | paramsBuilder.append("&type=query"); |
| | | paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); |
| | | |
| | | String params = paramsBuilder.toString(); |
| | | |
| | | logger.info("天å°å¾POIæç´¢è¯·æ±: keyWord={}, queryType={}", keyWord, queryType); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("æ¥è¯¢æå", response); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾POIæç´¢å¤±è´¥", e); |
| | | return AjaxResult.error("POIæç´¢å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 天å°å¾è·¯çº¿è§åæ¥å£ä»£çï¼é©¾è½¦è·¯å¾è§åï¼ |
| | | * ææ¡£ï¼https://lbs.tianditu.gov.cn/server/drive.html |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/route/driving") |
| | | public AjaxResult tiandituRouteDriving(String orig, String dest, String mid, String style) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (orig == null || orig.trim().isEmpty() || |
| | | dest == null || dest.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°èµ·ç¹æç»ç¹åæ "); |
| | | } |
| | | |
| | | // éªè¯åæ æ ¼å¼ï¼ç»åº¦,çº¬åº¦ï¼ |
| | | String[] origParts = orig.split(","); |
| | | String[] destParts = dest.split(","); |
| | | if (origParts.length != 2 || destParts.length != 2) { |
| | | return AjaxResult.error("åæ æ ¼å¼é误ï¼åºä¸ºï¼ç»åº¦,纬度"); |
| | | } |
| | | |
| | | // 设置é»è®¤å¼ |
| | | if (style == null || style.trim().isEmpty()) { |
| | | style = "0"; // 0-æ¨èï¼1-é¿å¼é«é |
| | | } |
| | | |
| | | // æå»ºå¤©å°å¾é©¾è½¦è·¯å¾è§åAPI URL |
| | | String url = "http://api.tianditu.gov.cn/drive"; |
| | | StringBuilder paramsBuilder = new StringBuilder(); |
| | | paramsBuilder.append("postStr={\"orig\":\"").append(orig).append("\""); |
| | | paramsBuilder.append(",\"dest\":\"").append(dest).append("\""); |
| | | if (mid != null && !mid.trim().isEmpty()) { |
| | | paramsBuilder.append(",\"mid\":\"").append(mid).append("\""); |
| | | } |
| | | paramsBuilder.append(",\"style\":\"").append(style).append("\""); |
| | | paramsBuilder.append("}" ); |
| | | paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); |
| | | |
| | | String params = paramsBuilder.toString(); |
| | | |
| | | logger.info("天å°å¾é©¾è½¦è·¯å¾è§å请æ±: orig={}, dest={}", orig, dest); |
| | | |
| | | // åéHTTPè¯·æ± |
| | | String response = HttpUtils.sendGet(url, params); |
| | | |
| | | // è¿åç»æ |
| | | return AjaxResult.success("è®¡ç®æå", response); |
| | | } catch (Exception e) { |
| | | logger.error("天å°å¾é©¾è½¦è·¯å¾è§å失败", e); |
| | | return AjaxResult.error("è·¯å¾è§å失败ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 天å°å¾è®¡ç®ä¸¤ä¸ªå°åä¹é´çè·ç¦»ï¼ç»åæ¥å£ï¼å°åè½¬åæ + è·¯å¾è§åï¼ |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/distance/byAddress") |
| | | public AjaxResult tiandituDistanceByAddress(String fromAddress, String toAddress) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (fromAddress == null || fromAddress.trim().isEmpty() || |
| | | 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"); |
| | | logger.info("ç»ç¹åæ : lon={}, lat={}", toLon, toLat); |
| | | |
| | | // ç¬¬ä¸æ¥ï¼è°ç¨è·¯å¾è§åæ¥å£è®¡ç®è·ç¦» |
| | | String routeUrl = "http://api.tianditu.gov.cn/drive"; |
| | | String orig = fromLon + "," + 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("è·¯å¾è§å失败"); |
| | | } |
| | | |
| | | // æåè·ç¦»ä¿¡æ¯ |
| | | com.alibaba.fastjson2.JSONObject result = routeJson.getJSONObject("result"); |
| | | if (result == null) { |
| | | logger.error("è·¯å¾è§åç»æä¸ºç©º"); |
| | | 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()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 天å°å¾è¾å
¥æç¤ºæ¥å£ä»£çï¼å°åèæ³ï¼ |
| | | * ææ¡£ï¼https://lbs.tianditu.gov.cn/server/suggestion.html |
| | | */ |
| | | @Anonymous() |
| | | @GetMapping("/tianditu/place/suggestion") |
| | | public AjaxResult tiandituPlaceSuggestion(String keyWord, String region, String city, Integer count) { |
| | | try { |
| | | // æ£æ¥åæ° |
| | | if (keyWord == null || keyWord.trim().isEmpty()) { |
| | | return AjaxResult.error("åæ°ä¸å®æ´ï¼ç¼ºå°æç´¢å
³é®è¯"); |
| | | } |
| | | |
| | | // 设置é»è®¤å¼ |
| | | if (count == null) { |
| | | count = 10; |
| | | } |
| | | |
| | | // æå»ºå¤©å°å¾è¾å
¥æç¤ºAPI URL |
| | | String url = "http://api.tianditu.gov.cn/search"; |
| | | StringBuilder paramsBuilder = new StringBuilder(); |
| | | paramsBuilder.append("postStr={\"keyWord\":\"").append(keyWord).append("\""); |
| | | if (region != null && !region.trim().isEmpty()) { |
| | | paramsBuilder.append(",\"region\":\"").append(region).append("\""); |
| | | } |
| | | if (city != null && !city.trim().isEmpty()) { |
| | | paramsBuilder.append(",\"city\":\"").append(city).append("\""); |
| | | } |
| | | paramsBuilder.append(",\"count\":\"").append(count).append("\""); |
| | | paramsBuilder.append("}" ); |
| | | paramsBuilder.append("&type=suggest"); |
| | | paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); |
| | | |
| | | String params = paramsBuilder.toString(); |
| | | |
| | | logger.info("天å°å¾è¾å
¥æç¤ºè¯·æ±: keyWord={}, region={}", keyWord, region); |
| | | |
| | | // åé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); |
| | | return AjaxResult.error("å°åæç´¢å¤±è´¥"); |
| | | } |
| | | |
| | | // æåæç¤ºå表 |
| | | com.alibaba.fastjson2.JSONArray results = jsonResponse.getJSONArray("suggests"); |
| | | if (results == null || results.isEmpty()) { |
| | | logger.info("æªæ¾å°å¹é
çå°å"); |
| | | return AjaxResult.success("æ¥è¯¢æå", new ArrayList<>()); |
| | | } |
| | | |
| | | // æå»ºè¿åç»æ |
| | | List<Map<String, Object>> suggestions = new ArrayList<>(); |
| | | for (int i = 0; i < results.size(); i++) { |
| | | com.alibaba.fastjson2.JSONObject item = results.getJSONObject(i); |
| | | |
| | | Map<String, Object> suggestion = new HashMap<>(); |
| | | suggestion.put("name", item.getString("name")); // åç§° |
| | | suggestion.put("address", item.getString("address")); // å°å |
| | | suggestion.put("province", item.getString("province")); // ç |
| | | suggestion.put("city", item.getString("city")); // å¸ |
| | | suggestion.put("district", item.getString("district")); // åº |
| | | |
| | | // ç»çº¬åº¦ä¿¡æ¯ |
| | | com.alibaba.fastjson2.JSONObject location = item.getJSONObject("location"); |
| | | if (location != null) { |
| | | Map<String, Object> locationMap = new HashMap<>(); |
| | | locationMap.put("lon", location.getDouble("lon")); |
| | | locationMap.put("lat", location.getDouble("lat")); |
| | | suggestion.put("location", locationMap); |
| | | } |
| | | |
| | | suggestions.add(suggestion); |
| | | } |
| | | |
| | | logger.info("å°åæç´¢æç¤ºæå: æ¾å°{}æ¡ç»æ", suggestions.size()); |
| | | return AjaxResult.success("æ¥è¯¢æå", suggestions); |
| | | } catch (Exception e) { |
| | | logger.error("å°åæç´¢æç¤ºå¤±è´¥", e); |
| | | return AjaxResult.error("å°åæç´¢å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.web.controller.system; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import com.ruoyi.common.annotation.Log; |
| | | import com.ruoyi.common.core.controller.BaseController; |
| | | import com.ruoyi.common.core.domain.AjaxResult; |
| | | import com.ruoyi.common.core.page.TableDataInfo; |
| | | import com.ruoyi.common.enums.BusinessType; |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.ruoyi.system.domain.VehicleMileageStats; |
| | | import com.ruoyi.system.service.IVehicleMileageStatsService; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡Controller |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/system/mileageStats") |
| | | public class VehicleMileageStatsController extends BaseController { |
| | | |
| | | @Autowired |
| | | private IVehicleMileageStatsService vehicleMileageStatsService; |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡å表 |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:list')") |
| | | @GetMapping("/list") |
| | | public TableDataInfo list(VehicleMileageStats vehicleMileageStats) { |
| | | startPage(); |
| | | List<VehicleMileageStats> list = vehicleMileageStatsService.selectVehicleMileageStatsList(vehicleMileageStats); |
| | | return getDataTable(list); |
| | | } |
| | | |
| | | /** |
| | | * 导åºè½¦è¾éç¨ç»è®¡å表 |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:export')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.EXPORT) |
| | | @PostMapping("/export") |
| | | public void export(HttpServletResponse response, VehicleMileageStats vehicleMileageStats) { |
| | | List<VehicleMileageStats> list = vehicleMileageStatsService.selectVehicleMileageStatsList(vehicleMileageStats); |
| | | ExcelUtil<VehicleMileageStats> util = new ExcelUtil<VehicleMileageStats>(VehicleMileageStats.class); |
| | | util.exportExcel(response, list, "车è¾éç¨ç»è®¡æ°æ®"); |
| | | } |
| | | |
| | | /** |
| | | * è·å车è¾éç¨ç»è®¡è¯¦ç»ä¿¡æ¯ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:query')") |
| | | @GetMapping(value = "/{statsId}") |
| | | public AjaxResult getInfo(@PathVariable("statsId") Long statsId) { |
| | | return success(vehicleMileageStatsService.selectVehicleMileageStatsById(statsId)); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:add')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.INSERT) |
| | | @PostMapping |
| | | public AjaxResult add(@RequestBody VehicleMileageStats vehicleMileageStats) { |
| | | return toAjax(vehicleMileageStatsService.insertVehicleMileageStats(vehicleMileageStats)); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:edit')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.UPDATE) |
| | | @PutMapping |
| | | public AjaxResult edit(@RequestBody VehicleMileageStats vehicleMileageStats) { |
| | | return toAjax(vehicleMileageStatsService.updateVehicleMileageStats(vehicleMileageStats)); |
| | | } |
| | | |
| | | /** |
| | | * å é¤è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:remove')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.DELETE) |
| | | @DeleteMapping("/{statsIds}") |
| | | public AjaxResult remove(@PathVariable Long[] statsIds) { |
| | | return toAjax(vehicleMileageStatsService.deleteVehicleMileageStatsByIds(statsIds)); |
| | | } |
| | | |
| | | /** |
| | | * æå¨è§¦åè®¡ç®æå®è½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:calculate')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.OTHER) |
| | | @PostMapping("/calculate") |
| | | public AjaxResult calculate(Long vehicleId, String statDate) { |
| | | try { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Date date = sdf.parse(statDate); |
| | | VehicleMileageStats stats = vehicleMileageStatsService.calculateAndSaveMileageStats(vehicleId, date); |
| | | if (stats != null) { |
| | | return success("éç¨ç»è®¡è®¡ç®æå", stats); |
| | | } else { |
| | | return error("该车è¾å¨æå®æ¥ææ GPSæ°æ®"); |
| | | } |
| | | } catch (Exception e) { |
| | | return error("éç¨ç»è®¡è®¡ç®å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¹éè®¡ç®æå®æ¥æææè½¦è¾çéç¨ç»è®¡ |
| | | */ |
| | | @PreAuthorize("@ss.hasPermi('system:mileageStats:batch')") |
| | | @Log(title = "车è¾éç¨ç»è®¡", businessType = BusinessType.OTHER) |
| | | @PostMapping("/batchCalculate") |
| | | public AjaxResult batchCalculate(String statDate) { |
| | | try { |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); |
| | | Date date = sdf.parse(statDate); |
| | | int count = vehicleMileageStatsService.batchCalculateMileageStats(date); |
| | | return success("æ¹ééç¨ç»è®¡å®æï¼æåç»è®¡ " + count + " è¾è½¦"); |
| | | } catch (Exception e) { |
| | | return error("æ¹ééç¨ç»è®¡å¤±è´¥ï¼" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | |
| | | baidu: |
| | | map: |
| | | ak: GX7G1RmAbTEQHor9NKpzRiB2jerqaY1E # è¯·æ¿æ¢ä¸ºæ¨çç¾åº¦å°å¾API Key |
| | | |
| | | # 天å°å¾é
ç½® |
| | | tianditu: |
| | | map: |
| | | tk: 4d1d0b3a4a03b9c5099c0e25ab1b23f3 # è¯·æ¿æ¢ä¸ºæ¨ç天å°å¾API Key |
| New file |
| | |
| | | package com.ruoyi.common.config; |
| | | |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | /** |
| | | * 天å°å¾é
置类 |
| | | */ |
| | | @Configuration |
| | | @ConfigurationProperties(prefix = "tianditu.map") |
| | | public class TiandituMapConfig { |
| | | |
| | | /** |
| | | * 天å°å¾API Key (tkåæ°) |
| | | */ |
| | | private String tk; |
| | | |
| | | public String getTk() { |
| | | return tk; |
| | | } |
| | | |
| | | public void setTk(String tk) { |
| | | this.tk = tk; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.quartz.task; |
| | | |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | import com.ruoyi.system.service.IVehicleMileageStatsService; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡å®æ¶ä»»å¡ |
| | | */ |
| | | @Component("vehicleMileageStatsTask") |
| | | public class VehicleMileageStatsTask { |
| | | |
| | | private static final Logger logger = LoggerFactory.getLogger(VehicleMileageStatsTask.class); |
| | | |
| | | @Autowired |
| | | private IVehicleMileageStatsService vehicleMileageStatsService; |
| | | |
| | | /** |
| | | * è®¡ç®æ¨æ¥ææè½¦è¾çéç¨ç»è®¡ |
| | | */ |
| | | public void calculateYesterdayMileage() { |
| | | logger.info("å¼å§æ§è¡è½¦è¾éç¨ç»è®¡å®æ¶ä»»å¡ - ç»è®¡æ¨æ¥éç¨"); |
| | | |
| | | try { |
| | | // è·åæ¨å¤©çæ¥æ |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.add(Calendar.DAY_OF_MONTH, -1); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | calendar.set(Calendar.MILLISECOND, 0); |
| | | Date yesterday = calendar.getTime(); |
| | | |
| | | // æ¹é计ç®éç¨ç»è®¡ |
| | | int successCount = vehicleMileageStatsService.batchCalculateMileageStats(yesterday); |
| | | |
| | | logger.info("车è¾éç¨ç»è®¡å®æ¶ä»»å¡æ§è¡å®æ - æåç»è®¡: {} è¾è½¦", successCount); |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("车è¾éç¨ç»è®¡å®æ¶ä»»å¡æ§è¡å¤±è´¥", e); |
| | | throw new RuntimeException("宿¶ä»»å¡æ§è¡å¤±è´¥: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * è®¡ç®æå®æ¥æçéç¨ç»è®¡ï¼ç¨äºæå¨è§¦åæè¡¥ç®å岿°æ®ï¼ |
| | | * |
| | | * @param dateStr æ¥æåç¬¦ä¸²ï¼æ ¼å¼ï¼yyyy-MM-dd |
| | | */ |
| | | public void calculateMileageByDate(String dateStr) { |
| | | logger.info("å¼å§æ§è¡è½¦è¾éç¨ç»è®¡å®æ¶ä»»å¡ - ç»è®¡æ¥æ: {}", dateStr); |
| | | |
| | | try { |
| | | // è§£ææ¥æå符串 |
| | | String[] parts = dateStr.split("-"); |
| | | if (parts.length != 3) { |
| | | throw new IllegalArgumentException("æ¥ææ ¼å¼é误ï¼åºä¸º: yyyy-MM-dd"); |
| | | } |
| | | |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.set(Calendar.YEAR, Integer.parseInt(parts[0])); |
| | | calendar.set(Calendar.MONTH, Integer.parseInt(parts[1]) - 1); // æä»½ä»0å¼å§ |
| | | calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(parts[2])); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | calendar.set(Calendar.MILLISECOND, 0); |
| | | Date targetDate = calendar.getTime(); |
| | | |
| | | // æ¹é计ç®éç¨ç»è®¡ |
| | | int successCount = vehicleMileageStatsService.batchCalculateMileageStats(targetDate); |
| | | |
| | | logger.info("车è¾éç¨ç»è®¡å®æ¶ä»»å¡æ§è¡å®æ - æ¥æ: {}, æåç»è®¡: {} è¾è½¦", dateStr, successCount); |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("车è¾éç¨ç»è®¡å®æ¶ä»»å¡æ§è¡å¤±è´¥ - æ¥æ: {}", dateStr, e); |
| | | throw new RuntimeException("宿¶ä»»å¡æ§è¡å¤±è´¥: " + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.domain; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 任塿¶é´åºé´ |
| | | */ |
| | | public class TaskTimeInterval { |
| | | |
| | | /** ä»»å¡ID */ |
| | | private Long taskId; |
| | | |
| | | /** å¼å§æ¶é´ */ |
| | | private Date startTime; |
| | | |
| | | /** ç»ææ¶é´ */ |
| | | private Date endTime; |
| | | |
| | | public TaskTimeInterval() { |
| | | } |
| | | |
| | | public TaskTimeInterval(Long taskId, Date startTime, Date endTime) { |
| | | this.taskId = taskId; |
| | | this.startTime = startTime; |
| | | this.endTime = endTime; |
| | | } |
| | | |
| | | public Long getTaskId() { |
| | | return taskId; |
| | | } |
| | | |
| | | public void setTaskId(Long taskId) { |
| | | this.taskId = taskId; |
| | | } |
| | | |
| | | public Date getStartTime() { |
| | | return startTime; |
| | | } |
| | | |
| | | public void setStartTime(Date startTime) { |
| | | this.startTime = startTime; |
| | | } |
| | | |
| | | public Date getEndTime() { |
| | | return endTime; |
| | | } |
| | | |
| | | public void setEndTime(Date endTime) { |
| | | this.endTime = endTime; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.domain; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Date; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.ruoyi.common.annotation.Excel; |
| | | import com.ruoyi.common.core.domain.BaseEntity; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡å¯¹è±¡ tb_vehicle_mileage_stats |
| | | */ |
| | | public class VehicleMileageStats extends BaseEntity { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** ç»è®¡ID */ |
| | | private Long statsId; |
| | | |
| | | /** 车è¾ID */ |
| | | @Excel(name = "车è¾ID") |
| | | private Long vehicleId; |
| | | |
| | | /** 车çå· */ |
| | | @Excel(name = "车çå·") |
| | | private String vehicleNo; |
| | | |
| | | /** ç»è®¡æ¥æ */ |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @Excel(name = "ç»è®¡æ¥æ", width = 30, dateFormat = "yyyy-MM-dd") |
| | | private Date statDate; |
| | | |
| | | /** æ»éç¨(å
Ž) */ |
| | | @Excel(name = "æ»éç¨(å
Ž)") |
| | | private BigDecimal totalMileage; |
| | | |
| | | /** 任塿¶æ®µéç¨(å
Ž) */ |
| | | @Excel(name = "任塿¶æ®µéç¨(å
Ž)") |
| | | private BigDecimal taskMileage; |
| | | |
| | | /** é任塿¶æ®µéç¨(å
Ž) */ |
| | | @Excel(name = "é任塿¶æ®µéç¨(å
Ž)") |
| | | private BigDecimal nonTaskMileage; |
| | | |
| | | /** ä»»å¡éç¨å æ¯(0-1) */ |
| | | @Excel(name = "ä»»å¡éç¨å æ¯") |
| | | private BigDecimal taskRatio; |
| | | |
| | | /** GPSç¹æ°é */ |
| | | @Excel(name = "GPSç¹æ°é") |
| | | private Integer gpsPointCount; |
| | | |
| | | /** 任塿°é */ |
| | | @Excel(name = "任塿°é") |
| | | private Integer taskCount; |
| | | |
| | | public Long getStatsId() { |
| | | return statsId; |
| | | } |
| | | |
| | | public void setStatsId(Long statsId) { |
| | | this.statsId = statsId; |
| | | } |
| | | |
| | | public Long getVehicleId() { |
| | | return vehicleId; |
| | | } |
| | | |
| | | public void setVehicleId(Long vehicleId) { |
| | | this.vehicleId = vehicleId; |
| | | } |
| | | |
| | | public String getVehicleNo() { |
| | | return vehicleNo; |
| | | } |
| | | |
| | | public void setVehicleNo(String vehicleNo) { |
| | | this.vehicleNo = vehicleNo; |
| | | } |
| | | |
| | | public Date getStatDate() { |
| | | return statDate; |
| | | } |
| | | |
| | | public void setStatDate(Date statDate) { |
| | | this.statDate = statDate; |
| | | } |
| | | |
| | | public BigDecimal getTotalMileage() { |
| | | return totalMileage; |
| | | } |
| | | |
| | | public void setTotalMileage(BigDecimal totalMileage) { |
| | | this.totalMileage = totalMileage; |
| | | } |
| | | |
| | | public BigDecimal getTaskMileage() { |
| | | return taskMileage; |
| | | } |
| | | |
| | | public void setTaskMileage(BigDecimal taskMileage) { |
| | | this.taskMileage = taskMileage; |
| | | } |
| | | |
| | | public BigDecimal getNonTaskMileage() { |
| | | return nonTaskMileage; |
| | | } |
| | | |
| | | public void setNonTaskMileage(BigDecimal nonTaskMileage) { |
| | | this.nonTaskMileage = nonTaskMileage; |
| | | } |
| | | |
| | | public BigDecimal getTaskRatio() { |
| | | return taskRatio; |
| | | } |
| | | |
| | | public void setTaskRatio(BigDecimal taskRatio) { |
| | | this.taskRatio = taskRatio; |
| | | } |
| | | |
| | | public Integer getGpsPointCount() { |
| | | return gpsPointCount; |
| | | } |
| | | |
| | | public void setGpsPointCount(Integer gpsPointCount) { |
| | | this.gpsPointCount = gpsPointCount; |
| | | } |
| | | |
| | | public Integer getTaskCount() { |
| | | return taskCount; |
| | | } |
| | | |
| | | public void setTaskCount(Integer taskCount) { |
| | | this.taskCount = taskCount; |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.system.mapper; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import com.ruoyi.system.domain.VehicleGps; |
| | | |
| | | /** |
| | |
| | | * @return å é¤çè®°å½æ° |
| | | */ |
| | | public int deleteVehicleGpsBeforeDate(); |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾å¨æå®æ¶é´èå´å
çGPSæ°æ®ï¼æééæ¶é´æåºï¼ |
| | | * |
| | | * @param vehicleId 车è¾ID |
| | | * @param startTime å¼å§æ¶é´ |
| | | * @param endTime ç»ææ¶é´ |
| | | * @return GPSåæ å表 |
| | | */ |
| | | public List<VehicleGps> selectGpsDataByTimeRange(@Param("vehicleId") Long vehicleId, |
| | | @Param("startTime") Date startTime, |
| | | @Param("endTime") Date endTime); |
| | | |
| | | /** |
| | | * æ¥è¯¢æææ´»è·è½¦è¾IDå表 |
| | | * |
| | | * @return 车è¾IDå表 |
| | | */ |
| | | public List<Long> selectActiveVehicleIds(); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.mapper; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import org.apache.ibatis.annotations.Param; |
| | | import com.ruoyi.system.domain.VehicleMileageStats; |
| | | import com.ruoyi.system.domain.TaskTimeInterval; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡Mapperæ¥å£ |
| | | */ |
| | | public interface VehicleMileageStatsMapper { |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param statsId ç»è®¡ID |
| | | * @return 车è¾éç¨ç»è®¡ |
| | | */ |
| | | public VehicleMileageStats selectVehicleMileageStatsById(Long statsId); |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡å表 |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return 车è¾éç¨ç»è®¡éå |
| | | */ |
| | | public List<VehicleMileageStats> selectVehicleMileageStatsList(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * æ°å¢è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return ç»æ |
| | | */ |
| | | public int insertVehicleMileageStats(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * ä¿®æ¹è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return ç»æ |
| | | */ |
| | | public int updateVehicleMileageStats(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * å é¤è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param statsId ç»è®¡ID |
| | | * @return ç»æ |
| | | */ |
| | | public int deleteVehicleMileageStatsById(Long statsId); |
| | | |
| | | /** |
| | | * æ¹éå é¤è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param statsIds éè¦å é¤çæ°æ®ID |
| | | * @return ç»æ |
| | | */ |
| | | public int deleteVehicleMileageStatsByIds(Long[] statsIds); |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾å¨æå®æ¥æçç»è®¡è®°å½ |
| | | * |
| | | * @param vehicleId 车è¾ID |
| | | * @param statDate ç»è®¡æ¥æ |
| | | * @return ç»è®¡è®°å½ |
| | | */ |
| | | public VehicleMileageStats selectByVehicleIdAndDate(@Param("vehicleId") Long vehicleId, |
| | | @Param("statDate") Date statDate); |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾å¨æå®æ¶é´èå´å
ç任塿¶é´åºé´ |
| | | * |
| | | * @param vehicleId 车è¾ID |
| | | * @param startTime å¼å§æ¶é´ |
| | | * @param endTime ç»ææ¶é´ |
| | | * @return 任塿¶é´åºé´å表 |
| | | */ |
| | | public List<TaskTimeInterval> selectTaskTimeIntervals(@Param("vehicleId") Long vehicleId, |
| | | @Param("startTime") Date startTime, |
| | | @Param("endTime") Date endTime); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.service; |
| | | |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import com.ruoyi.system.domain.VehicleMileageStats; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡Serviceæ¥å£ |
| | | */ |
| | | public interface IVehicleMileageStatsService { |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param statsId ç»è®¡ID |
| | | * @return 车è¾éç¨ç»è®¡ |
| | | */ |
| | | public VehicleMileageStats selectVehicleMileageStatsById(Long statsId); |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡å表 |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return 车è¾éç¨ç»è®¡éå |
| | | */ |
| | | public List<VehicleMileageStats> selectVehicleMileageStatsList(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * æ°å¢è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return ç»æ |
| | | */ |
| | | public int insertVehicleMileageStats(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * ä¿®æ¹è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param vehicleMileageStats 车è¾éç¨ç»è®¡ |
| | | * @return ç»æ |
| | | */ |
| | | public int updateVehicleMileageStats(VehicleMileageStats vehicleMileageStats); |
| | | |
| | | /** |
| | | * æ¹éå é¤è½¦è¾éç¨ç»è®¡ |
| | | * |
| | | * @param statsIds éè¦å é¤çæ°æ®ID |
| | | * @return ç»æ |
| | | */ |
| | | public int deleteVehicleMileageStatsByIds(Long[] statsIds); |
| | | |
| | | /** |
| | | * å é¤è½¦è¾éç¨ç»è®¡ä¿¡æ¯ |
| | | * |
| | | * @param statsId ç»è®¡ID |
| | | * @return ç»æ |
| | | */ |
| | | public int deleteVehicleMileageStatsById(Long statsId); |
| | | |
| | | /** |
| | | * 计ç®å¹¶ä¿åæå®è½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | * |
| | | * @param vehicleId 车è¾ID |
| | | * @param statDate ç»è®¡æ¥æ |
| | | * @return ç»è®¡ç»æ |
| | | */ |
| | | public VehicleMileageStats calculateAndSaveMileageStats(Long vehicleId, Date statDate); |
| | | |
| | | /** |
| | | * æ¹éè®¡ç®ææè½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | * |
| | | * @param statDate ç»è®¡æ¥æ |
| | | * @return æåç»è®¡çè½¦è¾æ°é |
| | | */ |
| | | public int batchCalculateMileageStats(Date statDate); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.service.impl; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import com.ruoyi.system.domain.VehicleGps; |
| | | import com.ruoyi.system.domain.VehicleMileageStats; |
| | | import com.ruoyi.system.domain.TaskTimeInterval; |
| | | import com.ruoyi.system.mapper.VehicleGpsMapper; |
| | | import com.ruoyi.system.mapper.VehicleMileageStatsMapper; |
| | | import com.ruoyi.system.service.IVehicleMileageStatsService; |
| | | |
| | | /** |
| | | * 车è¾éç¨ç»è®¡Serviceä¸å¡å±å¤ç |
| | | */ |
| | | @Service |
| | | public class VehicleMileageStatsServiceImpl implements IVehicleMileageStatsService { |
| | | |
| | | private static final Logger logger = LoggerFactory.getLogger(VehicleMileageStatsServiceImpl.class); |
| | | |
| | | /** å°çåå¾ï¼å
¬éï¼ */ |
| | | private static final double EARTH_RADIUS_KM = 6371.0; |
| | | |
| | | @Autowired |
| | | private VehicleMileageStatsMapper vehicleMileageStatsMapper; |
| | | |
| | | @Autowired |
| | | private VehicleGpsMapper vehicleGpsMapper; |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public VehicleMileageStats selectVehicleMileageStatsById(Long statsId) { |
| | | return vehicleMileageStatsMapper.selectVehicleMileageStatsById(statsId); |
| | | } |
| | | |
| | | /** |
| | | * æ¥è¯¢è½¦è¾éç¨ç»è®¡å表 |
| | | */ |
| | | @Override |
| | | public List<VehicleMileageStats> selectVehicleMileageStatsList(VehicleMileageStats vehicleMileageStats) { |
| | | return vehicleMileageStatsMapper.selectVehicleMileageStatsList(vehicleMileageStats); |
| | | } |
| | | |
| | | /** |
| | | * æ°å¢è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public int insertVehicleMileageStats(VehicleMileageStats vehicleMileageStats) { |
| | | return vehicleMileageStatsMapper.insertVehicleMileageStats(vehicleMileageStats); |
| | | } |
| | | |
| | | /** |
| | | * ä¿®æ¹è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public int updateVehicleMileageStats(VehicleMileageStats vehicleMileageStats) { |
| | | return vehicleMileageStatsMapper.updateVehicleMileageStats(vehicleMileageStats); |
| | | } |
| | | |
| | | /** |
| | | * æ¹éå é¤è½¦è¾éç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public int deleteVehicleMileageStatsByIds(Long[] statsIds) { |
| | | return vehicleMileageStatsMapper.deleteVehicleMileageStatsByIds(statsIds); |
| | | } |
| | | |
| | | /** |
| | | * å é¤è½¦è¾éç¨ç»è®¡ä¿¡æ¯ |
| | | */ |
| | | @Override |
| | | public int deleteVehicleMileageStatsById(Long statsId) { |
| | | return vehicleMileageStatsMapper.deleteVehicleMileageStatsById(statsId); |
| | | } |
| | | |
| | | /** |
| | | * 计ç®å¹¶ä¿åæå®è½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public VehicleMileageStats calculateAndSaveMileageStats(Long vehicleId, Date statDate) { |
| | | try { |
| | | // 1. è·åç»è®¡æ¥æçå¼å§åç»ææ¶é´ |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(statDate); |
| | | calendar.set(Calendar.HOUR_OF_DAY, 0); |
| | | calendar.set(Calendar.MINUTE, 0); |
| | | calendar.set(Calendar.SECOND, 0); |
| | | calendar.set(Calendar.MILLISECOND, 0); |
| | | Date dayStart = calendar.getTime(); |
| | | |
| | | calendar.add(Calendar.DAY_OF_MONTH, 1); |
| | | Date dayEnd = calendar.getTime(); |
| | | |
| | | // 2. æ¥è¯¢è½¦è¾å¨è¯¥æ¥æçGPSæ°æ®ï¼ææ¶é´æåºï¼ |
| | | List<VehicleGps> gpsList = vehicleGpsMapper.selectGpsDataByTimeRange(vehicleId, dayStart, dayEnd); |
| | | |
| | | if (gpsList == null || gpsList.isEmpty()) { |
| | | logger.info("车è¾ID: {} 卿¥æ: {} æ GPSæ°æ®", vehicleId, statDate); |
| | | return null; |
| | | } |
| | | |
| | | // 3. æ¥è¯¢è½¦è¾å¨è¯¥æ¥æç任塿¶é´åºé´ |
| | | List<TaskTimeInterval> taskIntervals = vehicleMileageStatsMapper.selectTaskTimeIntervals(vehicleId, dayStart, dayEnd); |
| | | |
| | | // 4. 计ç®éç¨ |
| | | MileageCalculation calculation = calculateMileage(gpsList, taskIntervals); |
| | | |
| | | // 5. æ¥è¯¢æå建ç»è®¡è®°å½ |
| | | VehicleMileageStats stats = vehicleMileageStatsMapper.selectByVehicleIdAndDate(vehicleId, statDate); |
| | | boolean isNew = (stats == null); |
| | | |
| | | if (isNew) { |
| | | stats = new VehicleMileageStats(); |
| | | stats.setVehicleId(vehicleId); |
| | | stats.setStatDate(statDate); |
| | | |
| | | // è·å车çå· |
| | | if (!gpsList.isEmpty() && gpsList.get(0).getVehicleNo() != null) { |
| | | stats.setVehicleNo(gpsList.get(0).getVehicleNo()); |
| | | } |
| | | } |
| | | |
| | | // 6. 设置ç»è®¡æ°æ® |
| | | stats.setTotalMileage(calculation.totalMileage); |
| | | stats.setTaskMileage(calculation.taskMileage); |
| | | stats.setNonTaskMileage(calculation.nonTaskMileage); |
| | | stats.setTaskRatio(calculation.taskRatio); |
| | | stats.setGpsPointCount(gpsList.size()); |
| | | stats.setTaskCount(taskIntervals == null ? 0 : taskIntervals.size()); |
| | | |
| | | // 7. ä¿åå°æ°æ®åº |
| | | if (isNew) { |
| | | vehicleMileageStatsMapper.insertVehicleMileageStats(stats); |
| | | } else { |
| | | vehicleMileageStatsMapper.updateVehicleMileageStats(stats); |
| | | } |
| | | |
| | | logger.info("车è¾ID: {} æ¥æ: {} éç¨ç»è®¡å®æ - æ»éç¨: {}km, ä»»å¡éç¨: {}km, éä»»å¡éç¨: {}km, å æ¯: {}", |
| | | vehicleId, statDate, calculation.totalMileage, calculation.taskMileage, |
| | | calculation.nonTaskMileage, calculation.taskRatio); |
| | | |
| | | return stats; |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("计ç®è½¦è¾éç¨ç»è®¡å¤±è´¥ - 车è¾ID: {}, æ¥æ: {}", vehicleId, statDate, e); |
| | | throw new RuntimeException("计ç®éç¨ç»è®¡å¤±è´¥: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æ¹éè®¡ç®ææè½¦è¾æå®æ¥æçéç¨ç»è®¡ |
| | | */ |
| | | @Override |
| | | public int batchCalculateMileageStats(Date statDate) { |
| | | try { |
| | | // æ¥è¯¢æææ´»è·è½¦è¾ |
| | | List<Long> vehicleIds = vehicleGpsMapper.selectActiveVehicleIds(); |
| | | |
| | | if (vehicleIds == null || vehicleIds.isEmpty()) { |
| | | logger.info("æ²¡ææ¾å°æ´»è·è½¦è¾"); |
| | | return 0; |
| | | } |
| | | |
| | | int successCount = 0; |
| | | for (Long vehicleId : vehicleIds) { |
| | | try { |
| | | calculateAndSaveMileageStats(vehicleId, statDate); |
| | | successCount++; |
| | | } catch (Exception e) { |
| | | logger.error("计ç®è½¦è¾ {} çéç¨ç»è®¡å¤±è´¥", vehicleId, e); |
| | | } |
| | | } |
| | | |
| | | logger.info("æ¹ééç¨ç»è®¡å®æ - æ¥æ: {}, æ»è½¦è¾æ°: {}, æå: {}", statDate, vehicleIds.size(), successCount); |
| | | return successCount; |
| | | |
| | | } catch (Exception e) { |
| | | logger.error("æ¹é计ç®éç¨ç»è®¡å¤±è´¥ - æ¥æ: {}", statDate, e); |
| | | throw new RuntimeException("æ¹é计ç®å¤±è´¥: " + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 计ç®éç¨çå
鍿¹æ³ |
| | | */ |
| | | private MileageCalculation calculateMileage(List<VehicleGps> gpsList, List<TaskTimeInterval> taskIntervals) { |
| | | MileageCalculation result = new MileageCalculation(); |
| | | |
| | | // éåGPSç¹ï¼è®¡ç®ç¸é»ç¹ä¹é´çè·ç¦» |
| | | for (int i = 0; i < gpsList.size() - 1; i++) { |
| | | VehicleGps p1 = gpsList.get(i); |
| | | VehicleGps p2 = gpsList.get(i + 1); |
| | | |
| | | // 计ç®ä¸¤ç¹é´è·ç¦»ï¼ä½¿ç¨Haversineå
¬å¼ï¼ |
| | | double distance = calculateDistance( |
| | | p1.getLatitude().doubleValue(), |
| | | p1.getLongitude().doubleValue(), |
| | | p2.getLatitude().doubleValue(), |
| | | p2.getLongitude().doubleValue() |
| | | ); |
| | | |
| | | // è·åè¿æ®µè·ç¦»çæ¶é´åºé´ |
| | | Date segmentStart = p1.getCollectTime(); |
| | | Date segmentEnd = p2.getCollectTime(); |
| | | |
| | | // 计ç®è¿æ®µè·ç¦»å¨ä»»å¡æ¶æ®µçå æ¯ |
| | | double taskRatio = calculateTaskOverlapRatio(segmentStart, segmentEnd, taskIntervals); |
| | | |
| | | // åæéç¨ |
| | | double taskDistance = distance * taskRatio; |
| | | double nonTaskDistance = distance * (1 - taskRatio); |
| | | |
| | | result.totalMileage = result.totalMileage.add(BigDecimal.valueOf(distance)); |
| | | result.taskMileage = result.taskMileage.add(BigDecimal.valueOf(taskDistance)); |
| | | result.nonTaskMileage = result.nonTaskMileage.add(BigDecimal.valueOf(nonTaskDistance)); |
| | | } |
| | | |
| | | // 计ç®ä»»å¡éç¨å æ¯ |
| | | if (result.totalMileage.compareTo(BigDecimal.ZERO) > 0) { |
| | | result.taskRatio = result.taskMileage.divide(result.totalMileage, 4, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | // ä¿ç两ä½å°æ° |
| | | result.totalMileage = result.totalMileage.setScale(2, RoundingMode.HALF_UP); |
| | | result.taskMileage = result.taskMileage.setScale(2, RoundingMode.HALF_UP); |
| | | result.nonTaskMileage = result.nonTaskMileage.setScale(2, RoundingMode.HALF_UP); |
| | | |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 使ç¨Haversineå
¬å¼è®¡ç®ä¸¤ä¸ªGPSåæ ä¹é´çè·ç¦»ï¼å
¬éï¼ |
| | | */ |
| | | private double calculateDistance(double lat1, double lon1, double lat2, double lon2) { |
| | | // å°è§åº¦è½¬æ¢ä¸ºå¼§åº¦ |
| | | double dLat = Math.toRadians(lat2 - lat1); |
| | | double dLon = Math.toRadians(lon2 - lon1); |
| | | double rLat1 = Math.toRadians(lat1); |
| | | double rLat2 = Math.toRadians(lat2); |
| | | |
| | | // Haversineå
¬å¼ |
| | | double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
| | | Math.cos(rLat1) * Math.cos(rLat2) * |
| | | Math.sin(dLon / 2) * Math.sin(dLon / 2); |
| | | |
| | | double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
| | | |
| | | return EARTH_RADIUS_KM * c; |
| | | } |
| | | |
| | | /** |
| | | * è®¡ç®æ¶é´æ®µä¸ä»»å¡æ¶æ®µçéå æ¯ä¾ |
| | | */ |
| | | private double calculateTaskOverlapRatio(Date segmentStart, Date segmentEnd, List<TaskTimeInterval> taskIntervals) { |
| | | if (taskIntervals == null || taskIntervals.isEmpty()) { |
| | | return 0.0; |
| | | } |
| | | |
| | | long segmentDuration = segmentEnd.getTime() - segmentStart.getTime(); |
| | | if (segmentDuration <= 0) { |
| | | return 0.0; |
| | | } |
| | | |
| | | long totalOverlap = 0; |
| | | |
| | | for (TaskTimeInterval task : taskIntervals) { |
| | | // 计ç®éå æ¶é´ |
| | | long overlapStart = Math.max(segmentStart.getTime(), task.getStartTime().getTime()); |
| | | long overlapEnd = Math.min(segmentEnd.getTime(), task.getEndTime().getTime()); |
| | | |
| | | if (overlapEnd > overlapStart) { |
| | | totalOverlap += (overlapEnd - overlapStart); |
| | | } |
| | | } |
| | | |
| | | return (double) totalOverlap / segmentDuration; |
| | | } |
| | | |
| | | /** |
| | | * éç¨è®¡ç®ç»æå
é¨ç±» |
| | | */ |
| | | private static class MileageCalculation { |
| | | BigDecimal totalMileage = BigDecimal.ZERO; |
| | | BigDecimal taskMileage = BigDecimal.ZERO; |
| | | BigDecimal nonTaskMileage = BigDecimal.ZERO; |
| | | BigDecimal taskRatio = BigDecimal.ZERO; |
| | | } |
| | | } |
| | |
| | | where g2.vehicle_id = g.vehicle_id |
| | | ) |
| | | </delete> |
| | | |
| | | <select id="selectGpsDataByTimeRange" resultMap="VehicleGpsResult"> |
| | | select gps_id, vehicle_id, device_id, longitude, latitude, altitude, speed, direction, |
| | | collect_time, device_report_time, platform_process_time, create_time |
| | | from tb_vehicle_gps |
| | | where vehicle_id = #{vehicleId} |
| | | and collect_time >= #{startTime} |
| | | and collect_time <= #{endTime} |
| | | order by collect_time |
| | | </select> |
| | | |
| | | <select id="selectActiveVehicleIds" resultType="Long"> |
| | | select distinct vehicle_id |
| | | from tb_vehicle_gps |
| | | where collect_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) |
| | | order by vehicle_id |
| | | </select> |
| | | </mapper> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper |
| | | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
| | | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.system.mapper.VehicleMileageStatsMapper"> |
| | | |
| | | <resultMap type="VehicleMileageStats" id="VehicleMileageStatsResult"> |
| | | <id property="statsId" column="stats_id" /> |
| | | <result property="vehicleId" column="vehicle_id" /> |
| | | <result property="vehicleNo" column="vehicle_no" /> |
| | | <result property="statDate" column="stat_date" /> |
| | | <result property="totalMileage" column="total_mileage" /> |
| | | <result property="taskMileage" column="task_mileage" /> |
| | | <result property="nonTaskMileage" column="non_task_mileage" /> |
| | | <result property="taskRatio" column="task_ratio" /> |
| | | <result property="gpsPointCount" column="gps_point_count" /> |
| | | <result property="taskCount" column="task_count" /> |
| | | <result property="createTime" column="create_time" /> |
| | | <result property="updateTime" column="update_time" /> |
| | | </resultMap> |
| | | |
| | | <resultMap type="TaskTimeInterval" id="TaskTimeIntervalResult"> |
| | | <result property="taskId" column="task_id" /> |
| | | <result property="startTime" column="start_time" /> |
| | | <result property="endTime" column="end_time" /> |
| | | </resultMap> |
| | | |
| | | <sql id="selectVehicleMileageStatsVo"> |
| | | select stats_id, vehicle_id, vehicle_no, stat_date, total_mileage, task_mileage, |
| | | non_task_mileage, task_ratio, gps_point_count, task_count, create_time, update_time |
| | | from tb_vehicle_mileage_stats |
| | | </sql> |
| | | |
| | | <select id="selectVehicleMileageStatsList" parameterType="VehicleMileageStats" resultMap="VehicleMileageStatsResult"> |
| | | <include refid="selectVehicleMileageStatsVo"/> |
| | | <where> |
| | | <if test="vehicleId != null"> |
| | | and vehicle_id = #{vehicleId} |
| | | </if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> |
| | | and vehicle_no = #{vehicleNo} |
| | | </if> |
| | | <if test="statDate != null"> |
| | | and stat_date = #{statDate} |
| | | </if> |
| | | <if test="params.beginStatDate != null and params.beginStatDate != ''"> |
| | | and stat_date >= #{params.beginStatDate} |
| | | </if> |
| | | <if test="params.endStatDate != null and params.endStatDate != ''"> |
| | | and stat_date <= #{params.endStatDate} |
| | | </if> |
| | | </where> |
| | | order by stat_date desc, vehicle_id |
| | | </select> |
| | | |
| | | <select id="selectVehicleMileageStatsById" parameterType="Long" resultMap="VehicleMileageStatsResult"> |
| | | <include refid="selectVehicleMileageStatsVo"/> |
| | | where stats_id = #{statsId} |
| | | </select> |
| | | |
| | | <select id="selectByVehicleIdAndDate" resultMap="VehicleMileageStatsResult"> |
| | | <include refid="selectVehicleMileageStatsVo"/> |
| | | where vehicle_id = #{vehicleId} and stat_date = #{statDate} |
| | | </select> |
| | | |
| | | <select id="selectTaskTimeIntervals" resultMap="TaskTimeIntervalResult"> |
| | | select tv.task_id, t.create_time as start_time, |
| | | IFNULL(t.actual_end_time, NOW()) as end_time |
| | | from sys_task_vehicle tv |
| | | inner join sys_task t on tv.task_id = t.task_id |
| | | where tv.vehicle_id = #{vehicleId} |
| | | and t.del_flag = '0' |
| | | and t.actual_end_time is not null |
| | | and t.create_time < #{endTime} |
| | | and t.actual_end_time > #{startTime} |
| | | order by t.create_time |
| | | </select> |
| | | |
| | | <insert id="insertVehicleMileageStats" parameterType="VehicleMileageStats" useGeneratedKeys="true" keyProperty="statsId"> |
| | | insert into tb_vehicle_mileage_stats |
| | | <trim prefix="(" suffix=")" suffixOverrides=","> |
| | | <if test="vehicleId != null">vehicle_id,</if> |
| | | <if test="vehicleNo != null">vehicle_no,</if> |
| | | <if test="statDate != null">stat_date,</if> |
| | | <if test="totalMileage != null">total_mileage,</if> |
| | | <if test="taskMileage != null">task_mileage,</if> |
| | | <if test="nonTaskMileage != null">non_task_mileage,</if> |
| | | <if test="taskRatio != null">task_ratio,</if> |
| | | <if test="gpsPointCount != null">gps_point_count,</if> |
| | | <if test="taskCount != null">task_count,</if> |
| | | create_time |
| | | </trim> |
| | | <trim prefix="values (" suffix=")" suffixOverrides=","> |
| | | <if test="vehicleId != null">#{vehicleId},</if> |
| | | <if test="vehicleNo != null">#{vehicleNo},</if> |
| | | <if test="statDate != null">#{statDate},</if> |
| | | <if test="totalMileage != null">#{totalMileage},</if> |
| | | <if test="taskMileage != null">#{taskMileage},</if> |
| | | <if test="nonTaskMileage != null">#{nonTaskMileage},</if> |
| | | <if test="taskRatio != null">#{taskRatio},</if> |
| | | <if test="gpsPointCount != null">#{gpsPointCount},</if> |
| | | <if test="taskCount != null">#{taskCount},</if> |
| | | NOW() |
| | | </trim> |
| | | </insert> |
| | | |
| | | <update id="updateVehicleMileageStats" parameterType="VehicleMileageStats"> |
| | | update tb_vehicle_mileage_stats |
| | | <trim prefix="SET" suffixOverrides=","> |
| | | <if test="vehicleNo != null">vehicle_no = #{vehicleNo},</if> |
| | | <if test="totalMileage != null">total_mileage = #{totalMileage},</if> |
| | | <if test="taskMileage != null">task_mileage = #{taskMileage},</if> |
| | | <if test="nonTaskMileage != null">non_task_mileage = #{nonTaskMileage},</if> |
| | | <if test="taskRatio != null">task_ratio = #{taskRatio},</if> |
| | | <if test="gpsPointCount != null">gps_point_count = #{gpsPointCount},</if> |
| | | <if test="taskCount != null">task_count = #{taskCount},</if> |
| | | update_time = NOW() |
| | | </trim> |
| | | where stats_id = #{statsId} |
| | | </update> |
| | | |
| | | <delete id="deleteVehicleMileageStatsById" parameterType="Long"> |
| | | delete from tb_vehicle_mileage_stats where stats_id = #{statsId} |
| | | </delete> |
| | | |
| | | <delete id="deleteVehicleMileageStatsByIds" parameterType="Long"> |
| | | delete from tb_vehicle_mileage_stats where stats_id in |
| | | <foreach item="statsId" collection="array" open="(" separator="," close=")"> |
| | | #{statsId} |
| | | </foreach> |
| | | </delete> |
| | | </mapper> |
| New file |
| | |
| | | -- 车è¾éç¨ç»è®¡è¡¨ |
| | | CREATE TABLE `tb_vehicle_mileage_stats` ( |
| | | `stats_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ç»è®¡ID', |
| | | `vehicle_id` bigint(20) NOT NULL COMMENT '车è¾ID', |
| | | `vehicle_no` varchar(20) DEFAULT NULL COMMENT '车çå·', |
| | | `stat_date` date NOT NULL COMMENT 'ç»è®¡æ¥æ', |
| | | `total_mileage` decimal(10,2) DEFAULT 0.00 COMMENT 'æ»éç¨(å
Ž)', |
| | | `task_mileage` decimal(10,2) DEFAULT 0.00 COMMENT '任塿¶æ®µéç¨(å
Ž)', |
| | | `non_task_mileage` decimal(10,2) DEFAULT 0.00 COMMENT 'é任塿¶æ®µéç¨(å
Ž)', |
| | | `task_ratio` decimal(5,4) DEFAULT 0.0000 COMMENT 'ä»»å¡éç¨å æ¯(0-1)', |
| | | `gps_point_count` int(11) DEFAULT 0 COMMENT 'GPSç¹æ°é', |
| | | `task_count` int(11) DEFAULT 0 COMMENT '任塿°é', |
| | | `create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´', |
| | | `update_time` datetime DEFAULT NULL COMMENT 'æ´æ°æ¶é´', |
| | | PRIMARY KEY (`stats_id`), |
| | | UNIQUE KEY `uk_vehicle_date` (`vehicle_id`, `stat_date`), |
| | | KEY `idx_vehicle_id` (`vehicle_id`), |
| | | KEY `idx_stat_date` (`stat_date`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车è¾éç¨ç»è®¡è¡¨'; |
| | | |
| | | -- 车è¾éç¨ç»è®¡æç»è¡¨ï¼å¯éï¼ç¨äºè°è¯åè¿½æº¯ï¼ |
| | | CREATE TABLE `tb_vehicle_mileage_detail` ( |
| | | `detail_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'æç»ID', |
| | | `stats_id` bigint(20) NOT NULL COMMENT 'ç»è®¡ID', |
| | | `vehicle_id` bigint(20) NOT NULL COMMENT '车è¾ID', |
| | | `segment_start_time` datetime NOT NULL COMMENT 'æ®µèµ·å§æ¶é´', |
| | | `segment_end_time` datetime NOT NULL COMMENT 'æ®µç»ææ¶é´', |
| | | `start_longitude` decimal(10,7) DEFAULT NULL COMMENT 'èµ·ç¹ç»åº¦', |
| | | `start_latitude` decimal(10,7) DEFAULT NULL COMMENT 'èµ·ç¹çº¬åº¦', |
| | | `end_longitude` decimal(10,7) DEFAULT NULL COMMENT 'ç»ç¹ç»åº¦', |
| | | `end_latitude` decimal(10,7) DEFAULT NULL COMMENT 'ç»ç¹çº¬åº¦', |
| | | `segment_distance` decimal(10,3) DEFAULT 0.000 COMMENT '段è·ç¦»(å
Ž)', |
| | | `task_distance` decimal(10,3) DEFAULT 0.000 COMMENT 'ä»»å¡å
è·ç¦»(å
Ž)', |
| | | `non_task_distance` decimal(10,3) DEFAULT 0.000 COMMENT 'ä»»å¡å¤è·ç¦»(å
Ž)', |
| | | `is_in_task` tinyint(1) DEFAULT 0 COMMENT 'æ¯å¦å®å
¨å¨ä»»å¡æ¶æ®µå
(0-å¦,1-æ¯,2-é¨å)', |
| | | `create_time` datetime DEFAULT NULL COMMENT 'å建æ¶é´', |
| | | PRIMARY KEY (`detail_id`), |
| | | KEY `idx_stats_id` (`stats_id`), |
| | | KEY `idx_vehicle_id` (`vehicle_id`) |
| | | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车è¾éç¨ç»è®¡æç»è¡¨'; |
| New file |
| | |
| | | -- æ·»å 车è¾éç¨ç»è®¡å®æ¶ä»»å¡ |
| | | INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ( |
| | | (SELECT IFNULL(MAX(job_id), 0) + 1 FROM sys_job t), |
| | | '车è¾éç¨ç»è®¡ä»»å¡', |
| | | 'DEFAULT', |
| | | 'vehicleMileageStatsTask.calculateYesterdayMileage', |
| | | '0 30 1 * * ?', |
| | | '3', |
| | | '1', |
| | | '0', |
| | | 'admin', |
| | | NOW(), |
| | | '', |
| | | NULL, |
| | | 'æ¯å¤©åæ¨1:30æ§è¡ï¼ç»è®¡æ¨æ¥ææè½¦è¾çè¡é©¶éç¨' |
| | | ); |
| New file |
| | |
| | | -- 车è¾éç¨ç»è®¡èåæé |
| | | -- ç¶èåIDéè¦æ ¹æ®å®é
ç³»ç»ä¸ç"ç³»ç»ç®¡ç"æ"车è¾ç®¡ç"èåIDè¿è¡è°æ´ |
| | | |
| | | -- 1. æ·»å 车è¾éç¨ç»è®¡èå |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ( |
| | | (SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), |
| | | '车è¾éç¨ç»è®¡', |
| | | 3, -- ç³»ç»å·¥å
·ï¼è¯·æ ¹æ®å®é
æ
åµä¿®æ¹parent_id |
| | | 6, |
| | | 'mileageStats', |
| | | 'system/mileageStats/index', |
| | | 1, |
| | | 0, |
| | | 'C', |
| | | '0', |
| | | '0', |
| | | 'system:mileageStats:list', |
| | | 'chart', |
| | | 'admin', |
| | | NOW(), |
| | | '', |
| | | NULL, |
| | | '车è¾éç¨ç»è®¡èå' |
| | | ); |
| | | |
| | | -- è·ååæå
¥çèåIDï¼ç¨äºåç»æé®æéï¼ |
| | | SET @menuId = (SELECT MAX(menu_id) FROM sys_menu WHERE menu_name = '车è¾éç¨ç»è®¡'); |
| | | |
| | | -- 2. æ·»å æ¥è¯¢æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡æ¥è¯¢', @menuId, 1, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:query', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 3. æ·»å æ°å¢æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡æ°å¢', @menuId, 2, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:add', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 4. æ·»å ä¿®æ¹æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡ä¿®æ¹', @menuId, 3, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:edit', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 5. æ·»å å é¤æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡å é¤', @menuId, 4, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:remove', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 6. æ·»å å¯¼åºæé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡å¯¼åº', @menuId, 5, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:export', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 7. æ·»å è®¡ç®æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡è®¡ç®', @menuId, 6, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:calculate', '#', 'admin', NOW(), '', NULL, ''); |
| | | |
| | | -- 8. æ·»å æ¹éè®¡ç®æé® |
| | | INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) |
| | | VALUES ((SELECT IFNULL(MAX(menu_id), 0) + 1 FROM sys_menu t), '车è¾éç¨ç»è®¡æ¹é计ç®', @menuId, 7, '#', '', 1, 0, 'F', '0', '0', 'system:mileageStats:batch', '#', 'admin', NOW(), '', NULL, ''); |
| New file |
| | |
| | | # 车è¾GPSéç¨ç»è®¡åè½ä½¿ç¨è¯´æ |
| | | |
| | | ## åè½æ¦è¿° |
| | | |
| | | æ¬åè½å®ç°äºè½¦è¾GPSè¡é©¶éç¨çèªå¨ç»è®¡ï¼å
æ¬ï¼ |
| | | 1. **æ»éç¨ç»è®¡**ï¼åºäºGPSç¹è®¡ç®è½¦è¾æ¯æ¥æ»è¡é©¶éç¨ |
| | | 2. **任塿¶æ®µéç¨**ï¼è®¡ç®è½¦è¾å¨æ§è¡ä»»å¡æé´çè¡é©¶éç¨ |
| | | 3. **é任塿¶æ®µéç¨**ï¼è®¡ç®è½¦è¾éæ§è¡ä»»å¡æé´çè¡é©¶éç¨ |
| | | 4. **ä»»å¡éç¨å æ¯**ï¼è®¡ç®ä»»å¡éç¨å æ»éç¨çæ¯ä¾ |
| | | |
| | | ## æ ¸å¿ç®æ³ |
| | | |
| | | ### 1. è·ç¦»è®¡ç® |
| | | ä½¿ç¨ **Haversineå
¬å¼** 计ç®ç¸é»GPSç¹ä¹é´çå®é
è·ç¦»ï¼èèå°çæ²çï¼ |
| | | |
| | | ### 2. éç¨åæç®æ³ |
| | | æ ¹æ®GPSè®°å½çæ¶é´åºé´ä¸ä»»å¡æ¶é´åºé´ç**éå æ¯ä¾**ï¼å°æ¯æ®µè·ç¦»åæå°ä»»å¡éç¨åéä»»å¡éç¨ï¼ |
| | | |
| | | ``` |
| | | æ¶é´éå æ¯ä¾ = éå æ¶é¿ / æ»æ¶é¿ |
| | | ä»»å¡éç¨ = 段è·ç¦» à æ¶é´éå æ¯ä¾ |
| | | éä»»å¡éç¨ = 段è·ç¦» à (1 - æ¶é´éå æ¯ä¾) |
| | | ``` |
| | | |
| | | ## é¨ç½²æ¥éª¤ |
| | | |
| | | ### 1. æ§è¡æ°æ®åºèæ¬ |
| | | |
| | | æé¡ºåºæ§è¡ä»¥ä¸SQLæä»¶ï¼ |
| | | |
| | | ```bash |
| | | # 1. å建ç»è®¡è¡¨ |
| | | sql/vehicle_mileage_stats.sql |
| | | |
| | | # 2. æ·»å 宿¶ä»»å¡ |
| | | sql/vehicle_mileage_stats_job.sql |
| | | |
| | | # 3. æ·»å èåæé |
| | | sql/vehicle_mileage_stats_menu.sql |
| | | ``` |
| | | |
| | | ### 2. 代ç å·²èªå¨é¨ç½² |
| | | |
| | | 以ä¸ä»£ç æä»¶å·²åå»ºï¼ |
| | | |
| | | **å®ä½ç±»ï¼** |
| | | - `VehicleMileageStats.java` - éç¨ç»è®¡å®ä½ |
| | | - `TaskTimeInterval.java` - 任塿¶é´åºé´ |
| | | |
| | | **æ°æ®è®¿é®å±ï¼** |
| | | - `VehicleMileageStatsMapper.java` - éç¨ç»è®¡Mapperæ¥å£ |
| | | - `VehicleMileageStatsMapper.xml` - MyBatisæ å°æä»¶ |
| | | - `VehicleGpsMapper.java` - æ©å±GPSæ¥è¯¢æ¹æ³ |
| | | |
| | | **ä¸å¡å±ï¼** |
| | | - `IVehicleMileageStatsService.java` - Serviceæ¥å£ |
| | | - `VehicleMileageStatsServiceImpl.java` - Serviceå®ç°ï¼æ ¸å¿ç®æ³ï¼ |
| | | |
| | | **æ§å¶å±ï¼** |
| | | - `VehicleMileageStatsController.java` - REST APIæ¥å£ |
| | | |
| | | **宿¶ä»»å¡ï¼** |
| | | - `VehicleMileageStatsTask.java` - 宿¶ç»è®¡ä»»å¡ |
| | | |
| | | ### 3. å¯å¨å®æ¶ä»»å¡ |
| | | |
| | | ç³»ç»ä¼èªå¨æ·»å 宿¶ä»»å¡ï¼é»è®¤é
ç½®ï¼ |
| | | - **æ§è¡æ¶é´**ï¼æ¯å¤©åæ¨ 1:30 |
| | | - **ç»è®¡èå´**ï¼åä¸å¤©çææè½¦è¾GPSæ°æ® |
| | | - **Cron表达å¼**ï¼`0 30 1 * * ?` |
| | | |
| | | å¨ç³»ç»ç®¡ç -> 宿¶ä»»å¡ä¸å¯ä»¥æ¥çå管ç该任å¡ã |
| | | |
| | | ## ä½¿ç¨æ¹å¼ |
| | | |
| | | ### 1. èªå¨ç»è®¡ï¼æ¨èï¼ |
| | | |
| | | 宿¶ä»»å¡æ¯å¤©åæ¨èªå¨æ§è¡ï¼æ é人工干é¢ã |
| | | |
| | | ### 2. æå¨è§¦åç»è®¡ |
| | | |
| | | #### 2.1 å车è¾ç»è®¡ |
| | | |
| | | è°ç¨æ¥å£ï¼ |
| | | ``` |
| | | POST /system/mileageStats/calculate |
| | | åæ°ï¼ |
| | | - vehicleId: 车è¾ID |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ï¼yyyy-MM-ddï¼ |
| | | ``` |
| | | |
| | | #### 2.2 æ¹éç»è®¡ |
| | | |
| | | è°ç¨æ¥å£ï¼ |
| | | ``` |
| | | POST /system/mileageStats/batchCalculate |
| | | åæ°ï¼ |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ï¼yyyy-MM-ddï¼ |
| | | ``` |
| | | |
| | | #### 2.3 éè¿å®æ¶ä»»å¡è¡¥ç®å岿°æ® |
| | | |
| | | å¨å®æ¶ä»»å¡ç®¡çä¸ï¼æ§è¡ï¼ |
| | | ``` |
| | | vehicleMileageStatsTask.calculateMileageByDate('2025-11-09') |
| | | ``` |
| | | |
| | | ### 3. æ¥è¯¢ç»è®¡ç»æ |
| | | |
| | | ``` |
| | | GET /system/mileageStats/list |
| | | åæ°ï¼å¯éï¼ï¼ |
| | | - vehicleId: 车è¾ID |
| | | - vehicleNo: 车çå· |
| | | - statDate: ç»è®¡æ¥æ |
| | | - beginStatDate: å¼å§æ¥æ |
| | | - endStatDate: ç»ææ¥æ |
| | | ``` |
| | | |
| | | ### 4. 导åºç»è®¡æ°æ® |
| | | |
| | | ``` |
| | | POST /system/mileageStats/export |
| | | åæ°ï¼åæ¥è¯¢æ¥å£ |
| | | ``` |
| | | |
| | | ## æ°æ®è¡¨ç»æ |
| | | |
| | | ### tb_vehicle_mileage_statsï¼éç¨ç»è®¡è¡¨ï¼ |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | stats_id | bigint | ç»è®¡IDï¼ä¸»é®ï¼ | |
| | | | vehicle_id | bigint | 车è¾ID | |
| | | | vehicle_no | varchar(20) | 车çå· | |
| | | | stat_date | date | ç»è®¡æ¥æ | |
| | | | total_mileage | decimal(10,2) | æ»éç¨ï¼å
¬éï¼ | |
| | | | task_mileage | decimal(10,2) | 任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | non_task_mileage | decimal(10,2) | é任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | task_ratio | decimal(5,4) | ä»»å¡éç¨å æ¯ï¼0-1ï¼ | |
| | | | gps_point_count | int | GPSç¹æ°é | |
| | | | task_count | int | 任塿°é | |
| | | |
| | | ### tb_vehicle_mileage_detailï¼éç¨æç»è¡¨ï¼ |
| | | |
| | | ç¨äºè°è¯å追溯ï¼è®°å½æ¯æ®µGPS轨迹çéç¨åææç»ã |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | ### 1. GPSæ°æ®è´¨é |
| | | |
| | | - GPSééé´éå»ºè®®å¨ 30-60ç§ |
| | | - è¿çï¼è®¡ç®éå¤§ï¼æ§è½å½±å |
| | | - è¿é¿ï¼éç¨ç²¾åº¦éä½ |
| | | |
| | | ### 2. 任塿¶é´å®ä¹ |
| | | |
| | | 任塿¶æ®µ = ä»ä»»å¡å建æ¶é´ï¼`create_time`ï¼å°ä»»å¡å®ææ¶é´ï¼`actual_end_time`ï¼ |
| | | |
| | | ç¡®ä¿ä»»å¡è¡¨ä¸è¿ä¸¤ä¸ªå段å确记å½ã |
| | | |
| | | ### 3. æ§è½ä¼å |
| | | |
| | | - ç»è®¡æ°æ®ææ¥ææ±æ»ï¼é¿å
宿¶è®¡ç® |
| | | - 建议ä¿ç3-6个æçç»è®¡æ°æ®ï¼å®æå½æ¡£å岿°æ® |
| | | - GPSåå§æ°æ®å»ºè®®ä¿ç7-30天ï¼ç±æ¸
ç任塿§å¶ï¼ |
| | | |
| | | ### 4. æ°æ®è¡¥ç® |
| | | |
| | | å¦éè¡¥ç®å岿°æ®ï¼å¯ä»¥éè¿å®æ¶ä»»å¡æAPIæ¥å£æ¹éæ§è¡ï¼ |
| | | |
| | | ```java |
| | | // è¡¥ç®æè¿7å¤©çæ°æ®ç¤ºä¾ |
| | | for (int i = 1; i <= 7; i++) { |
| | | String date = "2025-11-" + String.format("%02d", i); |
| | | vehicleMileageStatsTask.calculateMileageByDate(date); |
| | | } |
| | | ``` |
| | | |
| | | ## æ©å±è¯´æ |
| | | |
| | | ### 天å°å¾æ¥å£éæ |
| | | |
| | | è½ç¶æ ¸å¿ç®æ³ä½¿ç¨Haversineå
¬å¼è®¡ç®è·ç¦»ï¼ä½ç³»ç»å·²éæå¤©å°å¾æ¥å£ï¼å¯ç¨äºï¼ |
| | | |
| | | 1. **å°åè§£æ**ï¼å°GPSåæ è½¬æ¢ä¸ºå°åä¿¡æ¯ |
| | | 2. **è·¯å¾è§å**ï¼è®¡ç®å®é
éè·¯è·ç¦»ï¼æ¯ç´çº¿è·ç¦»æ´åç¡®ï¼ |
| | | 3. **POIæ¥è¯¢**ï¼æ¥è¯¢æ²¿éå
´è¶£ç¹ |
| | | |
| | | å¦é使ç¨å¤©å°å¾APIè¿è¡è·¯å¾è·ç¦»è®¡ç®ï¼å¯åè `VehicleGpsController` ä¸ç天å°å¾æ¥å£ã |
| | | |
| | | ## ææ¯æ¯æ |
| | | |
| | | 妿é®é¢ï¼è¯·æ£æ¥ï¼ |
| | | 1. æ°æ®åºè¡¨æ¯å¦æ£ç¡®å建 |
| | | 2. 宿¶ä»»å¡æ¯å¦æ£å¸¸å¯å¨ |
| | | 3. GPSæ°æ®æ¯å¦æ£å¸¸éé |
| | | 4. ä»»å¡è¡¨çæ¶é´å段æ¯å¦åç¡® |
| | | |
| | | æ¥å¿ä½ç½®ï¼ |
| | | - Service屿¥å¿ï¼æç´¢ `VehicleMileageStatsServiceImpl` |
| | | - 宿¶ä»»å¡æ¥å¿ï¼æç´¢ `VehicleMileageStatsTask` |
| New file |
| | |
| | | # 车è¾GPSéç¨ç»è®¡åè½å®ç°æ»ç» |
| | | |
| | | ## ä¸ãåè½å®ç°æ¸
å |
| | | |
| | | ### â
1. æ°æ®åºå± |
| | | - [x] `vehicle_mileage_stats.sql` - å建éç¨ç»è®¡è¡¨åæç»è¡¨ |
| | | - [x] `vehicle_mileage_stats_job.sql` - åå»ºå®æ¶ä»»å¡é
ç½® |
| | | - [x] `vehicle_mileage_stats_menu.sql` - å建èåæéé
ç½® |
| | | |
| | | ### â
2. å®ä½ç±»ï¼Domainï¼ |
| | | - [x] `VehicleMileageStats.java` - éç¨ç»è®¡å®ä½ |
| | | - [x] `TaskTimeInterval.java` - 任塿¶é´åºé´è¾
å©ç±» |
| | | |
| | | ### â
3. æ°æ®è®¿é®å±ï¼Mapperï¼ |
| | | - [x] `VehicleMileageStatsMapper.java` - éç¨ç»è®¡Mapperæ¥å£ |
| | | - [x] `VehicleMileageStatsMapper.xml` - MyBatisæ å°é
ç½® |
| | | - [x] `VehicleGpsMapper.java` - æ©å±GPSæ¥è¯¢æ¹æ³ï¼æ°å¢2ä¸ªæ¹æ³ï¼ |
| | | - [x] `VehicleGpsMapper.xml` - æ©å±GPSæ¥è¯¢SQL |
| | | |
| | | ### â
4. ä¸å¡é»è¾å±ï¼Serviceï¼ |
| | | - [x] `IVehicleMileageStatsService.java` - Serviceæ¥å£ |
| | | - [x] `VehicleMileageStatsServiceImpl.java` - Serviceå®ç°ï¼æ ¸å¿ç®æ³ï¼ |
| | | |
| | | ### â
5. æ§å¶å±ï¼Controllerï¼ |
| | | - [x] `VehicleMileageStatsController.java` - REST APIæ¥å£ |
| | | |
| | | ### â
6. 宿¶ä»»å¡ï¼Taskï¼ |
| | | - [x] `VehicleMileageStatsTask.java` - èªå¨ç»è®¡å®æ¶ä»»å¡ |
| | | |
| | | ### â
7. å端API |
| | | - [x] `mileageStats.js` - å端æ¥å£å°è£
|
| | | |
| | | ### â
8. ææ¡£ |
| | | - [x] `车è¾éç¨ç»è®¡ä½¿ç¨è¯´æ.md` - 详ç»ä½¿ç¨ææ¡£ |
| | | |
| | | ## äºãæ ¸å¿ææ¯å®ç° |
| | | |
| | | ### 1. éç¨è®¡ç®ç®æ³ |
| | | |
| | | #### Haversineå
¬å¼ï¼è®¡ç®GPSç¹é´è·ç¦»ï¼ |
| | | ```java |
| | | private double calculateDistance(double lat1, double lon1, double lat2, double lon2) { |
| | | double dLat = Math.toRadians(lat2 - lat1); |
| | | double dLon = Math.toRadians(lon2 - lon1); |
| | | double rLat1 = Math.toRadians(lat1); |
| | | double rLat2 = Math.toRadians(lat2); |
| | | |
| | | double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + |
| | | Math.cos(rLat1) * Math.cos(rLat2) * |
| | | Math.sin(dLon / 2) * Math.sin(dLon / 2); |
| | | |
| | | double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
| | | |
| | | return EARTH_RADIUS_KM * c; |
| | | } |
| | | ``` |
| | | |
| | | #### æ¶é´éå æ¯ä¾è®¡ç®ï¼ä»»å¡éç¨åæï¼ |
| | | ```java |
| | | private double calculateTaskOverlapRatio(Date segmentStart, Date segmentEnd, |
| | | List<TaskTimeInterval> taskIntervals) { |
| | | long segmentDuration = segmentEnd.getTime() - segmentStart.getTime(); |
| | | long totalOverlap = 0; |
| | | |
| | | for (TaskTimeInterval task : taskIntervals) { |
| | | long overlapStart = Math.max(segmentStart.getTime(), task.getStartTime().getTime()); |
| | | long overlapEnd = Math.min(segmentEnd.getTime(), task.getEndTime().getTime()); |
| | | |
| | | if (overlapEnd > overlapStart) { |
| | | totalOverlap += (overlapEnd - overlapStart); |
| | | } |
| | | } |
| | | |
| | | return (double) totalOverlap / segmentDuration; |
| | | } |
| | | ``` |
| | | |
| | | ### 2. 任塿¶æ®µå®ä¹ |
| | | |
| | | 任塿¶æ®µ = ä»ä»»å¡å建æ¶é´ï¼`sys_task.create_time`ï¼å°ä»»å¡å®ææ¶é´ï¼`sys_task.actual_end_time`ï¼ |
| | | |
| | | SQLæ¥è¯¢ï¼ |
| | | ```sql |
| | | select tv.task_id, t.create_time as start_time, |
| | | IFNULL(t.actual_end_time, NOW()) as end_time |
| | | from sys_task_vehicle tv |
| | | inner join sys_task t on tv.task_id = t.task_id |
| | | where tv.vehicle_id = #{vehicleId} |
| | | and t.del_flag = '0' |
| | | and t.actual_end_time is not null |
| | | and t.create_time < #{endTime} |
| | | and t.actual_end_time > #{startTime} |
| | | ``` |
| | | |
| | | ### 3. ç»è®¡æ°æ®ç¼å |
| | | |
| | | - æ¯æ¥å®æ¶ä»»å¡èªå¨ç»è®¡åä¸å¤©çæ°æ® |
| | | - ç»è®¡ç»æåå¨å¨ `tb_vehicle_mileage_stats` è¡¨ä¸ |
| | | - æ¯æéå¤è®¡ç®ï¼æ´æ°å·²æè®°å½ï¼ |
| | | - å¯ä¸ç´¢å¼ï¼`uk_vehicle_date (vehicle_id, stat_date)` |
| | | |
| | | ## ä¸ãAPIæ¥å£è¯´æ |
| | | |
| | | ### 1. æ¥è¯¢ç»è®¡å表 |
| | | ``` |
| | | GET /system/mileageStats/list |
| | | åæ°ï¼ |
| | | - vehicleId: 车è¾IDï¼å¯éï¼ |
| | | - vehicleNo: 车çå·ï¼å¯éï¼ |
| | | - statDate: ç»è®¡æ¥æï¼å¯éï¼ |
| | | - beginStatDate: å¼å§æ¥æï¼å¯éï¼ |
| | | - endStatDate: ç»ææ¥æï¼å¯éï¼ |
| | | - pageNum: 页ç |
| | | - pageSize: æ¯é¡µæ°é |
| | | ``` |
| | | |
| | | ### 2. æå¨è®¡ç®å车è¾éç¨ |
| | | ``` |
| | | POST /system/mileageStats/calculate |
| | | åæ°ï¼ |
| | | - vehicleId: 车è¾IDï¼å¿
å¡«ï¼ |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ yyyy-MM-ddï¼å¿
å¡«ï¼ |
| | | è¿åï¼VehicleMileageStats对象 |
| | | ``` |
| | | |
| | | ### 3. æ¹éè®¡ç®ææè½¦è¾éç¨ |
| | | ``` |
| | | POST /system/mileageStats/batchCalculate |
| | | åæ°ï¼ |
| | | - statDate: ç»è®¡æ¥æï¼æ ¼å¼ yyyy-MM-ddï¼å¿
å¡«ï¼ |
| | | è¿åï¼æåç»è®¡çè½¦è¾æ°é |
| | | ``` |
| | | |
| | | ### 4. 导åºç»è®¡æ°æ® |
| | | ``` |
| | | POST /system/mileageStats/export |
| | | åæ°ï¼åæ¥è¯¢å表æ¥å£ |
| | | è¿åï¼Excelæä»¶ |
| | | ``` |
| | | |
| | | ## åã宿¶ä»»å¡é
ç½® |
| | | |
| | | ### é»è®¤é
ç½® |
| | | - **ä»»å¡åç§°**ï¼è½¦è¾éç¨ç»è®¡ä»»å¡ |
| | | - **Beanåç§°**ï¼vehicleMileageStatsTask |
| | | - **æ¹æ³è°ç¨**ï¼calculateYesterdayMileage |
| | | - **Cron表达å¼**ï¼`0 30 1 * * ?`ï¼æ¯å¤©åæ¨1:30æ§è¡ï¼ |
| | | - **æ§è¡çç¥**ï¼ç«å³æ§è¡ |
| | | - **å¹¶åæ§è¡**ï¼ç¦æ¢ |
| | | - **ç¶æ**ï¼å¯ç¨ |
| | | |
| | | ### æå¨è§¦åæ¹å¼ |
| | | å¨ç³»ç»ç®¡ç -> 宿¶ä»»å¡ä¸ï¼å¯ä»¥æå¨æ§è¡ï¼ |
| | | |
| | | 1. **ç»è®¡æ¨æ¥æ°æ®**ï¼ |
| | | ``` |
| | | vehicleMileageStatsTask.calculateYesterdayMileage |
| | | ``` |
| | | |
| | | 2. **ç»è®¡æå®æ¥æ**ï¼ |
| | | ``` |
| | | vehicleMileageStatsTask.calculateMileageByDate('2025-11-09') |
| | | ``` |
| | | |
| | | ## äºãæ°æ®è¡¨ç»æ |
| | | |
| | | ### tb_vehicle_mileage_stats |
| | | | åæ®µå | ç±»å | 说æ | |
| | | |--------|------|------| |
| | | | stats_id | bigint(20) | ç»è®¡IDï¼ä¸»é® | |
| | | | vehicle_id | bigint(20) | 车è¾ID | |
| | | | vehicle_no | varchar(20) | 车çå· | |
| | | | stat_date | date | ç»è®¡æ¥æ | |
| | | | total_mileage | decimal(10,2) | æ»éç¨ï¼å
¬éï¼ | |
| | | | task_mileage | decimal(10,2) | 任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | non_task_mileage | decimal(10,2) | é任塿¶æ®µéç¨ï¼å
¬éï¼ | |
| | | | task_ratio | decimal(5,4) | ä»»å¡éç¨å æ¯ï¼0-1ï¼ | |
| | | | gps_point_count | int(11) | GPSç¹æ°é | |
| | | | task_count | int(11) | 任塿°é | |
| | | | create_time | datetime | å建æ¶é´ | |
| | | | update_time | datetime | æ´æ°æ¶é´ | |
| | | |
| | | **ç´¢å¼ï¼** |
| | | - PRIMARY KEY: stats_id |
| | | - UNIQUE KEY: uk_vehicle_date (vehicle_id, stat_date) |
| | | - KEY: idx_vehicle_id (vehicle_id) |
| | | - KEY: idx_stat_date (stat_date) |
| | | |
| | | ### tb_vehicle_mileage_detailï¼å¯éï¼ |
| | | ç¨äºåå¨éç¨è®¡ç®æç»ï¼æ¹ä¾¿è°è¯å追溯ã |
| | | |
| | | ## å
ãé¨ç½²æ¥éª¤ |
| | | |
| | | ### 1. æ§è¡æ°æ®åºèæ¬ï¼æé¡ºåºï¼ |
| | | ```bash |
| | | 1. sql/vehicle_mileage_stats.sql |
| | | 2. sql/vehicle_mileage_stats_job.sql |
| | | 3. sql/vehicle_mileage_stats_menu.sql |
| | | ``` |
| | | |
| | | ### 2. éå¯åºç¨ |
| | | ä»£ç æä»¶å·²èªå¨å建ï¼éå¯åºç¨å³å¯çæã |
| | | |
| | | ### 3. éªè¯é¨ç½² |
| | | 1. ç»å½ç³»ç»ï¼æ£æ¥è忝妿¾ç¤º"车è¾éç¨ç»è®¡" |
| | | 2. è¿å
¥ç³»ç»ç®¡ç -> 宿¶ä»»å¡ï¼æ£æ¥æ¯å¦æ"车è¾éç¨ç»è®¡ä»»å¡" |
| | | 3. æå¨æ§è¡å®æ¶ä»»å¡æè°ç¨APIæ¥å£æµè¯åè½ |
| | | |
| | | ## ä¸ã使ç¨ç¤ºä¾ |
| | | |
| | | ### 示ä¾1ï¼æå¨è®¡ç®æè½¦è¾æ¨æ¥éç¨ |
| | | ```javascript |
| | | import { calculateMileage } from '@/api/mileageStats' |
| | | |
| | | calculateMileage(1001, '2025-11-09').then(response => { |
| | | console.log('ç»è®¡ç»æï¼', response.data) |
| | | // è¾åºç¤ºä¾ï¼ |
| | | // { |
| | | // vehicleNo: '粤A12345', |
| | | // statDate: '2025-11-09', |
| | | // totalMileage: 285.67, |
| | | // taskMileage: 198.43, |
| | | // nonTaskMileage: 87.24, |
| | | // taskRatio: 0.6948, |
| | | // gpsPointCount: 1205, |
| | | // taskCount: 8 |
| | | // } |
| | | }) |
| | | ``` |
| | | |
| | | ### 示ä¾2ï¼æ¹éè®¡ç®ææè½¦è¾æå®æ¥æéç¨ |
| | | ```javascript |
| | | import { batchCalculateMileage } from '@/api/mileageStats' |
| | | |
| | | batchCalculateMileage('2025-11-09').then(response => { |
| | | console.log(response.msg) // è¾åºï¼æ¹ééç¨ç»è®¡å®æï¼æåç»è®¡ 45 è¾è½¦ |
| | | }) |
| | | ``` |
| | | |
| | | ### 示ä¾3ï¼æ¥è¯¢è½¦è¾éç¨ç»è®¡æ¥è¡¨ |
| | | ```javascript |
| | | import { listMileageStats } from '@/api/mileageStats' |
| | | |
| | | const query = { |
| | | vehicleNo: '粤A12345', |
| | | beginStatDate: '2025-11-01', |
| | | endStatDate: '2025-11-09', |
| | | pageNum: 1, |
| | | pageSize: 10 |
| | | } |
| | | |
| | | listMileageStats(query).then(response => { |
| | | console.log('ç»è®¡å表ï¼', response.rows) |
| | | }) |
| | | ``` |
| | | |
| | | ## å
«ã注æäºé¡¹ |
| | | |
| | | ### 1. GPSæ°æ®è¦æ± |
| | | - GPSééé´éï¼å»ºè®®30-60ç§ |
| | | - æ°æ®å段å¿
å¡«ï¼vehicle_id, longitude, latitude, collect_time |
| | | - åæ ç³»ç»ï¼æ¯æWGS84ãGCJ02ç常ç¨åæ ç³» |
| | | |
| | | ### 2. 任塿°æ®è¦æ± |
| | | - ä»»å¡è¡¨ï¼sys_task |
| | | - 车è¾ä»»å¡å
³è表ï¼sys_task_vehicle |
| | | - å¿
å¡«åæ®µï¼task_id, vehicle_id, create_time, actual_end_time |
| | | |
| | | ### 3. æ§è½ä¼å建议 |
| | | - 宿¶ä»»å¡é¿å¼ä¸å¡é«å³°æï¼å»ºè®®åæ¨æ§è¡ï¼ |
| | | - GPSåå§æ°æ®å®ææ¸
çï¼å»ºè®®ä¿ç7-30å¤©ï¼ |
| | | - ç»è®¡æ°æ®å®æå½æ¡£ï¼å»ºè®®ä¿ç3-6个æï¼ |
| | | |
| | | ### 4. æ°æ®åç¡®æ§ |
| | | - éç¨è®¡ç®åºäºGPS轨迹ï¼ç²¾åº¦åGPSä¿¡å·è´¨éå½±å |
| | | - Haversineå
¬å¼è®¡ç®çæ¯ç´çº¿è·ç¦»ï¼å®é
éè·¯è·ç¦»å¯è½æ´é¿ |
| | | - å¯ç»å天å°å¾è·¯å¾è§åAPIè·åæ´åç¡®çéè·¯è·ç¦» |
| | | |
| | | ## ä¹ãæ©å±åè½å»ºè®® |
| | | |
| | | ### 1. éæå¤©å°å¾è·¯å¾è·ç¦»ï¼æ´åç¡®ï¼ |
| | | å½å使ç¨Haversineå
¬å¼è®¡ç®ç´çº¿è·ç¦»ï¼å¯åçº§ä¸ºï¼ |
| | | - å°GPS轨迹ç¹åéå°å¤©å°å¾è·¯å¾è§åAPI |
| | | - è·åå®é
éè·¯è·ç¦» |
| | | - æé«éç¨ç»è®¡ç²¾åº¦ |
| | | |
| | | ### 2. 宿¶éç¨ç»è®¡ |
| | | - å¨GPSæ°æ®å
¥åºæ¶å®æ¶è®¡ç® |
| | | - 使ç¨Redisç¼å彿¥ç´¯è®¡éç¨ |
| | | - 忍宿¶ä»»å¡ä»
åæ°æ®åºå |
| | | |
| | | ### 3. éç¨å¼å¸¸åè¦ |
| | | - 忥éç¨è¶
è¿éå¼åè¦ |
| | | - é¿æ¶é´æ GPSæ°æ®åè¦ |
| | | - éç¨çªåå¼å¸¸åè¦ |
| | | |
| | | ### 4. æ°æ®å¯è§å |
| | | - æ¯æ¥éç¨è¶å¿å¾ |
| | | - ä»»å¡éç¨å æ¯é¥¼å¾ |
| | | - 车è¾éç¨æåæ¦ |
| | | |
| | | ## åãæ
éææ¥ |
| | | |
| | | ### é®é¢1ï¼å®æ¶ä»»å¡æªæ§è¡ |
| | | - æ£æ¥å®æ¶ä»»å¡ç¶ææ¯å¦ä¸º"å¯ç¨" |
| | | - æ£æ¥Cronè¡¨è¾¾å¼æ¯å¦æ£ç¡® |
| | | - æ¥ç宿¶ä»»å¡æ¥å¿ |
| | | |
| | | ### é®é¢2ï¼ç»è®¡ç»æä¸º0 |
| | | - æ£æ¥GPSæ°æ®æ¯å¦åå¨ |
| | | - æ£æ¥GPSæ°æ®çcollect_timeåæ®µæ¯å¦æ£ç¡® |
| | | - æ£æ¥ä»»å¡æ°æ®æ¯å¦åå¨ |
| | | |
| | | ### é®é¢3ï¼éç¨æ°æ®å¼å¸¸ |
| | | - æ£æ¥GPSåæ æ¯å¦åæ³ï¼ç»çº¬åº¦èå´ï¼ |
| | | - æ£æ¥æ¯å¦åå¨GPSæ¼ç§»ç¹ |
| | | - å¯ç¨æç»è¡¨åææ¯æ®µè·ç¦» |
| | | |
| | | ### æ¥çæ¥å¿ |
| | | ```bash |
| | | # Service屿¥å¿ |
| | | grep "VehicleMileageStatsServiceImpl" logs/ruoyi-*.log |
| | | |
| | | # 宿¶ä»»å¡æ¥å¿ |
| | | grep "VehicleMileageStatsTask" logs/ruoyi-*.log |
| | | ``` |
| | | |
| | | ## åä¸ãæ»ç» |
| | | |
| | | â
æ¬åè½å·²å®æ´å®ç°è½¦è¾GPSéç¨ç»è®¡çææéæ±ï¼ |
| | | - â
æ¯æ¥èªå¨ç»è®¡è½¦è¾è¡é©¶éç¨ |
| | | - â
åºå任塿¶æ®µåé任塿¶æ®µéç¨ |
| | | - â
计ç®ä»»å¡éç¨å æ¯ |
| | | - â
ç»è®¡æ°æ®ç¼åå°æ°æ®åºè¡¨ |
| | | - â
æ¯ææå¨è§¦ååæ¹éè®¡ç® |
| | | - â
æä¾å®æ´çæ¥è¯¢å导åºåè½ |
| | | - â
éæå®æ¶ä»»å¡èªå¨åæ§è¡ |
| | | |
| | | æ ¸å¿ç®æ³éç¨Haversineå
¬å¼è®¡ç®GPSç¹é´è·ç¦»ï¼ææ¶é´éå æ¯ä¾åæéç¨å°ä»»å¡åé任塿¶æ®µï¼ç¡®ä¿ç»è®¡åç¡®æ§ãæææ°æ®ç¼åå¨ä¸ç¨ç»è®¡è¡¨ä¸ï¼æ¯æé«ææ¥è¯¢ååæã |