wanglizhong
2025-05-14 f1ba120c486048373505acfa74c3943c19be55ca
feat:优化查看历史轨迹
6个文件已添加
13个文件已修改
841 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java 243 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CmsVehicleSyncTask.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/resources/sql/vehicle_gps_job.sql 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/CmsTrackDetailResponse.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/CmsVehicleDeviceListResponse.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackPoint.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackQueryRequest.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackQueryResponse.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ICmsGpsCollectService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CmsGpsCollectServiceImpl.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/clean_gps.sql 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/VehicleGpsController.java
@@ -1,13 +1,11 @@
package com.ruoyi.web.controller.system;
import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import com.ruoyi.system.domain.DispatchOrd;
import com.ruoyi.system.domain.TbOrders;
import com.ruoyi.system.domain.TbVehicleOrder;
import com.ruoyi.system.service.IDispatchOrdService;
import com.ruoyi.system.service.ITbOrdersService;
import com.ruoyi.system.service.ITbVehicleOrderService;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -24,8 +22,6 @@
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.VehicleGps;
import com.ruoyi.system.service.IVehicleGpsService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -47,6 +43,15 @@
    @Autowired
    private ITbOrdersService tbOrdersService;
    @Autowired
    private IGpsCollectService gpsCollectService;
    @Autowired
    private IVehicleInfoService vehicleInfoService;
    @Autowired
    private ICmsGpsCollectService cmsGpsCollectService;
   /**
     * 查询车辆GPS坐标列表
     */  
@@ -55,7 +60,12 @@
    public TableDataInfo list(VehicleGps vehicleGps) {
        startPage();
        // 设置按时间倒序排序
//        String vehicleNo=vehicleGps.getVehicleNo();
//        String beginTime=vehicleGps.getBeginTime();
//        String endTime=vehicleGps.getEndTime();
//        return this.getAnonymousTracks(vehicleNo,beginTime,endTime);
//
//        // 设置按时间倒序排序
        vehicleGps.setOrderByColumn("collect_time");
        vehicleGps.setIsAsc("desc");
        List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps);
@@ -92,32 +102,53 @@
                    return getDataTable(new ArrayList<>());
                }
                Map<String, Object> params = new HashMap<>();
                params.put("beginTime", dispatchOrd.getDispatchOrdStartDate());
                params.put("endTime", dispatchOrd.getDispatchOrdUpdateTime());
                String vehicleNo = tbVehicleOrder.getVehicle();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String beginTime= sdf.format(dispatchOrd.getDispatchOrdStartDate());
                String endTime=  sdf.format(dispatchOrd.getDispatchOrdUpdateTime());
                //如果订单没完成, endTime为当前时间;如何订单已经完成了,用订单的结束时间。
                vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle());
                startPage();
                // 设置按时间倒序排序
                vehicleGps.setOrderByColumn("collect_time");
                vehicleGps.setIsAsc("desc");
                List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps);
                return getDataTable(list);
                return this.getAnonymousTracks(vehicleNo,beginTime,endTime);
//                Map<String, Object> params = new HashMap<>();
//                params.put("beginTime", dispatchOrd.getDispatchOrdStartDate());
//                params.put("endTime", dispatchOrd.getDispatchOrdUpdateTime());
//
//                vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle());
//                startPage();
//                // 设置按时间倒序排序
//                vehicleGps.setOrderByColumn("collect_time");
//                vehicleGps.setIsAsc("desc");
//                List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps);
//                return getDataTable(list);
            }
            catch (Exception ex)
            {
                logger.error("已完成的订单查询地图异常:{}",ex.getMessage());
                return getDataTable(new ArrayList<>());
            }
        }else{
            TbOrders tbOrders = tbOrdersService.selectTbOrdersByOrderID(vehicleGps.getOrderId());
            if (tbOrders == null) {
                return getDataTable(new ArrayList<>());
        }
        vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle());
        startPage();
        // 设置按时间倒序排序
        vehicleGps.setOrderByColumn("collect_time");
        vehicleGps.setIsAsc("desc");
        List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps);
        return getDataTable(list);
            DispatchOrd dispatchOrd = dispatchOrdService.selectDispatchOrdByServiceOrdIDDt(tbOrders.getServiceOrdID());
            if (dispatchOrd == null) {
                return getDataTable(new ArrayList<>());
            }
            String vehicleNo = tbVehicleOrder.getVehicle();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String beginTime= sdf.format(dispatchOrd.getDispatchOrdStartDate());
            String endTime=  sdf.format(new Date());
            return this.getAnonymousTracks(vehicleNo,beginTime,endTime);
//
//        vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle());
//        startPage();
//        // 设置按时间倒序排序
//        vehicleGps.setOrderByColumn("collect_time");
//        vehicleGps.setIsAsc("desc");
//        List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps);
//        return getDataTable(list);
        }
    }
    /**
@@ -173,4 +204,162 @@
    public AjaxResult remove(@PathVariable Long[] gpsIds) {
        return toAjax(vehicleGpsService.deleteVehicleGpsByIds(gpsIds));
    }
    /**
     * 查询车辆历史轨迹
     */
    @PreAuthorize("@ss.hasPermi('system:gps:query')")
    @GetMapping("/tracks")
    public TableDataInfo getTracks(String vehicleNo, String beginTime, String endTime) {
        return getAnonymousTracks(vehicleNo, beginTime, endTime);
    }
    /**
     * 匿名查询车辆历史轨迹
     */
    @Anonymous()
    @GetMapping("/anonymousTracks")
    public TableDataInfo getAnonymousTracks(String vehicleNo, String beginTime, String endTime) {
        try {
            // 通过车牌号获取设备ID
            VehicleInfo vehicleInfo = vehicleInfoService.selectVehicleInfoByPlateNumber(vehicleNo);
            if (vehicleInfo == null) {
                throw new Error("未找到该车辆对应的GPS设备");
            }
            // 处理开始时间
                beginTime = beginTime.replace("T", " ").replace(" ","%20");
                if (beginTime.split(":").length == 2) { // 只有小时和分钟
                    beginTime += ":00";
                }
                // 处理结束时间
                endTime = endTime.replace("T", " ").replace(" ","%20");
                if (endTime.split(":").length == 2) { // 只有小时和分钟
                    endTime += ":59";
                }
            List<GpsTrackPoint> trackPoints = new ArrayList<>();
            //如果平台是cms,则调用cms的接口
            if(vehicleInfo.getPlatformCode().equals("CMS"))
            {
                CmsTrackDetailResponse response = cmsGpsCollectService.queryTrackDetail(
                    vehicleInfo.getDeviceId(),  // 设备号
                    beginTime,                  // 开始时间
                    endTime,                    // 结束时间
                    null,                       // 距离(可选)
                    null,                       // 停车时长(可选)
                    1,                          // 解析地理位置
                    null,                       // 当前页码(可选)
                    null,                       // 每页记录数(可选)
                    2                           // 地图类型(2:百度地图)
                );
                if (response.getResult() != 0) {
                    throw new Error("查询CMS轨迹失败");
                }
                // 转换CMS轨迹点为统一格式
                if (response.getTracks() != null) {
                    for (CmsTrackDetailResponse.CmsTrackPoint point : response.getTracks()) {
                        GpsTrackPoint trackPoint = new GpsTrackPoint();
                        trackPoint.setVehicleNo(point.getVid());
                        trackPoint.setDeviceId(point.getId());
                        //经度纬度为空时,跳过
                        if(point.getMlng()==null || point.getMlat()==null)
                        {
                            continue;
                        }
                        // 经度,使用三元运算符
                        trackPoint.setLongitude(point.getMlng() != null ? Double.parseDouble(point.getMlng()) : 0.0);
                        // 纬度,使用三元运算符
                        trackPoint.setLatitude(point.getMlat() != null ? Double.parseDouble(point.getMlat()) : 0.0);
                        // 速度,直接使用int转double
                        trackPoint.setSpeed(point.getSp() > 0 ? (double)point.getSp() : 0.0);
                        // 方向,使用三元运算符处理
                        trackPoint.setCourse(point.getFt() > 0 ? point.getFt() : 0);
                        // ACC状态,使用三元运算符处理
                        trackPoint.setAccStatus(point.getAc() > 0 ? point.getAc() : 0);
                        // 在线状态,使用三元运算符处理
                        trackPoint.setOnlineStatus(point.getNet() > 0 ? point.getNet() : 0);
                        trackPoint.setAddress(point.getPs());
                        // 上报时间,直接使用字符串
                        trackPoint.setReportTime(point.getGt() != null ? point.getGt() : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                        trackPoints.add(trackPoint);
                    }
                }
            }
            else {
                // 构建查询请求
                GpsTrackQueryRequest request = new GpsTrackQueryRequest();
                request.setDeviceid(vehicleInfo.getDeviceId());
                request.setBegintime(beginTime);
                request.setEndtime(endTime);
                request.setTimezone(8); // 中国时区
                // 查询轨迹
                GpsTrackQueryResponse response = gpsCollectService.queryTracks(request);
                if (response.getStatus() != 0) {
                    throw new Error("查询轨迹失败:" + response.getCause());
                }
                // 转换GPS51轨迹点为统一格式
                if (response.getRecords() != null) {
                    for (GpsTrackPoint point : response.getRecords()) {
                        GpsTrackPoint trackPoint = new GpsTrackPoint();
                        trackPoint.setVehicleNo(vehicleNo);
                        trackPoint.setDeviceId(vehicleInfo.getDeviceId());
                        trackPoint.setLongitude(point.getLongitude());    // 经度
                        trackPoint.setLatitude(point.getLatitude());    // 纬度
                        trackPoint.setSpeed(point.getSpeed());      // 速度
                        trackPoint.setCourse(point.getCourse());    // 方向
                        trackPoint.setReportTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(point.getUpdatetime()))); // 上报时间
                        trackPoints.add(trackPoint);
                    }
                }
            }
            //转换成List<VehicleGps>
            List<VehicleGps> vehicleGpsList = new ArrayList<>();
            for(GpsTrackPoint trackPoint : trackPoints)
            {
                VehicleGps vehicleGps = new VehicleGps();
                vehicleGps.setVehicleNo(trackPoint.getVehicleNo());
                vehicleGps.setDeviceId(trackPoint.getDeviceId());
                vehicleGps.setLongitude(trackPoint.getLongitude());
                vehicleGps.setLatitude(trackPoint.getLatitude());
                vehicleGps.setSpeed(trackPoint.getSpeed());
                //方向
                vehicleGps.setDirection(Double.valueOf(trackPoint.getCourse()));
                //地址
                vehicleGps.setAddress(trackPoint.getAddress());
                vehicleGps.setCollectTime(trackPoint.getReportTime());
                //GPS平台处理时间
                vehicleGps.setPlatformProcessTime(trackPoint.getReportTime());
                vehicleGps.setDeviceReportTime(trackPoint.getReportTime());
                vehicleGpsList.add(vehicleGps);
            }
            //时间倒序排序
            vehicleGpsList.sort(Comparator.comparing(VehicleGps::getDeviceReportTime).reversed());
            //返回车辆Gps列表
            return getDataTable(vehicleGpsList);
            // return success(vehicleGpsList);
        } catch (Exception e) {
            logger.error("查询车辆轨迹异常", e);
            throw new Error("查询车辆轨迹失败:" + e.getMessage());
        }
    }
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CleanVehicleGpsTask.java
New file
@@ -0,0 +1,31 @@
package com.ruoyi.quartz.task;
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.IVehicleGpsService;
/**
 * 清理车辆GPS历史数据任务
 */
@Component("cleanVehicleGpsTask")
public class CleanVehicleGpsTask {
    private static final Logger log = LoggerFactory.getLogger(CleanVehicleGpsTask.class);
    @Autowired
    private IVehicleGpsService vehicleGpsService;
    /**
     * 清理车辆GPS历史数据
     */
    public void cleanVehicleGpsData() {
        try {
            log.info("开始清理车辆GPS历史数据");
            int count = vehicleGpsService.deleteVehicleGpsBeforeDate();
            log.info("清理车辆GPS历史数据完成,共清理{}条记录", count);
        } catch (Exception e) {
            log.error("清理车辆GPS历史数据异常", e);
        }
    }
}
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/CmsVehicleSyncTask.java
@@ -6,16 +6,13 @@
import java.util.List;
import java.util.stream.Collectors;
import com.ruoyi.system.domain.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.CmsVehicleDeviceResponse;
import com.ruoyi.system.domain.CmsVehicleLocationResponse;
import com.ruoyi.system.domain.VehicleGps;
import com.ruoyi.system.domain.VehicleInfo;
import com.ruoyi.system.service.ICmsGpsCollectService;
import com.ruoyi.system.service.IVehicleGpsService;
import com.ruoyi.system.service.IVehicleInfoService;
@@ -42,7 +39,7 @@
        log.info("开始同步CMS车辆信息");
        try {
            // 获取CMS所有车辆信息
            CmsVehicleDeviceResponse response = cmsGpsCollectService.queryVehicleDevices();
            CmsVehicleDeviceListResponse response = cmsGpsCollectService.getDeviceByVehicle(null);
            if (response.getResult() != 0) {
                log.error("获取CMS车辆信息失败");
                return;
@@ -50,10 +47,10 @@
            // 获取所有CMS车辆的车牌号
            List<String> cmsPlateNos = new ArrayList<>();
            response.getVehicles().forEach(vehicle -> {
                if (StringUtils.isNotEmpty(vehicle.getNm())) {
            response.getDevices().forEach(vehicle -> {
                if (StringUtils.isNotEmpty(vehicle.getVid())) {
                    // 从车辆名称中提取车牌号(假设格式为"★车牌号(地区)")
                    String plateNo =this.getPlateNo(vehicle.getNm());
                    String plateNo =this.getPlateNo(vehicle.getVid());
                    cmsPlateNos.add(plateNo);
                }
            });
@@ -70,18 +67,30 @@
            List<String> onlyCms=cmsPlateNos.stream().filter(e->!notCmsVehicles.contains(e)).collect((Collectors.toList()));
            Integer syncCarCount=0;
            for(String e:onlyCms){
                VehicleInfo vehicleInfo = new VehicleInfo();
                vehicleInfo.setVehicleNo(e);
            response.getDevices().stream().filter(e->onlyCms.contains(this.getPlateNo(e.getVid()))).forEach(vehicle->{
                String plateNo =this.getPlateNo(vehicle.getVid());
                VehicleInfo vehicleInfo= vehicleInfoService.selectVehicleInfoByPlateNumber(plateNo);
                if (vehicleInfo==null) {
                    vehicleInfo = new VehicleInfo();
                    vehicleInfo.setVehicleNo(plateNo);
                    vehicleInfo.setDeviceId(vehicle.getDid());
                vehicleInfo.setPlatformCode("CMS");
                vehicleInfo.setStatus("0");
                //如果车辆不存在,则插入
                if (vehicleInfoService.selectVehicleInfoList(vehicleInfo).size()==0) {
                    vehicleInfoService.insertVehicleInfo(vehicleInfo);
                    syncCarCount++;
                }
                else{
                    vehicleInfo.setVehicleNo(plateNo);
                    vehicleInfo.setDeviceId(vehicle.getDid());
                    vehicleInfo.setPlatformCode("CMS");
                    vehicleInfo.setStatus("0");
                    vehicleInfoService.updateVehicleInfo(vehicleInfo);
            }
            });
            log.info("成功同步{}个CMS车辆信息", syncCarCount);
            log.info("CMS车辆信息同步完成");
ruoyi-quartz/src/main/resources/sql/vehicle_gps_job.sql
ruoyi-system/src/main/java/com/ruoyi/system/domain/CmsTrackDetailResponse.java
New file
@@ -0,0 +1,74 @@
package com.ruoyi.system.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
 * CMS轨迹查询响应
 */
@Data
public class CmsTrackDetailResponse implements Serializable{
    private int result;
    private List<CmsTrackPoint> tracks;
    private CmsPagination pagination;
    /**
     * CMS轨迹点
     */
    @Data
    public static class CmsTrackPoint implements Serializable{
        private String id;        // 设备ID
        private int lng;         // 经度
        private int lat;         // 纬度
        private int ft;          // 方向
        private int sp;          // 速度
        private String ol;       // 油量
        private String gt;       // GPS时间
        private int pt;          // 定位类型
        private int dt;          // 数据类型
        private int ac;          // ACC状态
        private int fdt;         // 疲劳驾驶
        private int net;         // 网络类型
        private String gw;       // 网关
        private String vid;      // 车辆车牌
        private long s1;         // 状态1
        private int s2;          // 状态2
        private int s3;          // 状态3
        private int s4;          // 状态4
        private int t1;          // 温度1
        private int t2;          // 温度2
        private int t3;          // 温度3
        private int t4;          // 温度4
        private int hx;          // 湿度
        private String mlng;     // 地图经度
        private String mlat;     // 地图纬度
        private int pk;          // 停车状态
        private long lc;         // 里程
        private int yl;          // 油量
        private String ps;       // 位置
    }
    /**
     * CMS分页信息
     */
    @Data
    public static class CmsPagination implements Serializable {
        private int totalPages;      // 总页数
        private int currentPage;     // 当前页
        private int pageRecords;     // 每页记录数
        private int totalRecords;    // 总记录数
        private String sortParams;   // 排序参数
        private boolean hasNextPage; // 是否有下一页
        private boolean hasPreviousPage; // 是否有上一页
        private int nextPage;        // 下一页
        private int previousPage;    // 上一页
        private int startRecord;     // 开始记录
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/CmsVehicleDeviceListResponse.java
@@ -1,74 +1,60 @@
package com.ruoyi.system.domain;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import java.util.List;
/**
 * CMS车辆设备列表查询响应
 * CMS车辆设备列表响应
 */
public class CmsVehicleDeviceListResponse implements Serializable {
    private static final long serialVersionUID = 1L;
public class CmsVehicleDeviceListResponse {
    private int result;
    private List<CmsVehicleDevice> devices;
    /** 结果码 */
    @JsonProperty("result")
    private Integer result;
    /** 设备列表 */
    @JsonProperty("devices")
    private List<VehicleDevice> devices;
    public Integer getResult() {
    public int getResult() {
        return result;
    }
    public void setResult(Integer result) {
    public void setResult(int result) {
        this.result = result;
    }
    public List<VehicleDevice> getDevices() {
    public List<CmsVehicleDevice> getDevices() {
        return devices;
    }
    public void setDevices(List<VehicleDevice> devices) {
    public void setDevices(List<CmsVehicleDevice> devices) {
        this.devices = devices;
    }
    public static class VehicleDevice {
        /** 车牌号 */
        @JsonProperty("vid")
        private String vehicleId;
    /**
     * CMS车辆设备信息
     */
    public static class CmsVehicleDevice {
        private String vid;    // 车牌号
        private int type;      // 设备类型(1:视频设备,0:GPS设备)
        private String did;    // 设备号
        /** 设备类型 */
        @JsonProperty("type")
        private Integer type;
        /** 设备号 */
        @JsonProperty("did")
        private String deviceId;
        public String getVehicleId() {
            return vehicleId;
        public String getVid() {
            return vid;
        }
        public void setVehicleId(String vehicleId) {
            this.vehicleId = vehicleId;
        public void setVid(String vid) {
            this.vid = vid;
        }
        public Integer getType() {
        public int getType() {
            return type;
        }
        public void setType(Integer type) {
        public void setType(int type) {
            this.type = type;
        }
        public String getDeviceId() {
            return deviceId;
        public String getDid() {
            return did;
        }
        public void setDeviceId(String deviceId) {
            this.deviceId = deviceId;
        public void setDid(String did) {
            this.did = did;
        }
    }
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackPoint.java
New file
@@ -0,0 +1,45 @@
package com.ruoyi.system.domain;
import lombok.Data;
import java.io.Serializable;
/**
 * GPS轨迹点统一响应格式
 */
@Data
public class GpsTrackPoint implements Serializable {
    private String vehicleNo;      // 车牌号
    private Double longitude;      // 经度
    private Double latitude;       // 纬度
    private Double speed;          // 速度
    private Integer direction;     // 方向
    private String address;        // 地理位置
    private String reportTime;     // 上报时间
    private String deviceId;       // 设备ID
    private Integer accStatus;     // ACC状态
    private Integer onlineStatus;  // 在线状态
    private Integer powerStatus;   // 电源状态
    private Integer signalStrength;// 信号强度
    private Integer trackCount;    // 轨迹点数量
    private Long starttime;        // 开始时间
    private Long endtime;          // 结束时间
    private Integer trackid;       // 轨迹ID
    private Long arrivedtime;      // 到达时间
    private Long updatetime;       // 更新时间
    private Double altitude;       // 海拔
    private Integer radius;        // 半径
    private Double recorderspeed;  // 记录仪速度
    private Integer totaldistance; // 总距离
    private Integer course;        // 方向
    private Long status;           // 状态
    private String strstatus;      // 状态描述
    private String strstatusen;    // 状态英文描述
    private String gotsrc;         // 数据来源
    private Integer rxlevel;       // 信号强度
    private Integer gpsvalidnum;   // GPS有效卫星数
    private Short reportmode;      // 上报模式
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackQueryRequest.java
New file
@@ -0,0 +1,40 @@
package com.ruoyi.system.domain;
public class GpsTrackQueryRequest {
    private String deviceid;
    private String begintime;
    private String endtime;
    private Integer timezone;
    public String getDeviceid() {
        return deviceid;
    }
    public void setDeviceid(String deviceid) {
        this.deviceid = deviceid;
    }
    public String getBegintime() {
        return begintime;
    }
    public void setBegintime(String begintime) {
        this.begintime = begintime;
    }
    public String getEndtime() {
        return endtime;
    }
    public void setEndtime(String endtime) {
        this.endtime = endtime;
    }
    public Integer getTimezone() {
        return timezone;
    }
    public void setTimezone(Integer timezone) {
        this.timezone = timezone;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsTrackQueryResponse.java
New file
@@ -0,0 +1,42 @@
package com.ruoyi.system.domain;
import java.util.List;
public class GpsTrackQueryResponse {
    private int status;
    private String cause;
    private String deviceid;
    private List<GpsTrackPoint> records;
    public int getStatus() {
        return status;
    }
    public void setStatus(int status) {
        this.status = status;
    }
    public String getCause() {
        return cause;
    }
    public void setCause(String cause) {
        this.cause = cause;
    }
    public String getDeviceid() {
        return deviceid;
    }
    public void setDeviceid(String deviceid) {
        this.deviceid = deviceid;
    }
    public List<GpsTrackPoint> getRecords() {
        return records;
    }
    public void setRecords(List<GpsTrackPoint> records) {
        this.records = records;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java
@@ -67,6 +67,9 @@
    /** 排序列 */
    private String orderByColumn;
    /** 地址 */
    private String address;
    /** 排序的方向desc或者asc */
    private String isAsc;
@@ -211,6 +214,14 @@
        return  this.orderId;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getAddress() {
        return address;
    }
    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@@ -227,6 +238,7 @@
                .append("deviceReportTime", getDeviceReportTime())
                .append("platformProcessTime", getPlatformProcessTime())
                .append("createTime", getCreateTime())
                .append("address", getAddress())
                .toString();
    }
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleGpsMapper.java
@@ -41,4 +41,11 @@
     * 根据车牌号获取车辆ID
     */
    public Long getVehicleIdByNo(String vehicleNo);
    /**
     * 删除指定日期之前的车辆GPS数据
     *
     * @return 删除的记录数
     */
    public int deleteVehicleGpsBeforeDate();
ruoyi-system/src/main/java/com/ruoyi/system/service/ICmsGpsCollectService.java
@@ -4,6 +4,7 @@
import com.ruoyi.system.domain.CmsVehicleDeviceResponse;
import com.ruoyi.system.domain.CmsVehicleDeviceListResponse;
import com.ruoyi.system.domain.CmsVehicleLocationResponse;
import com.ruoyi.system.domain.CmsTrackDetailResponse;
/**
 * CMS GPS采集服务接口
@@ -44,4 +45,22 @@
     * @return 车辆位置信息响应
     */
    CmsVehicleLocationResponse getVehicleLocation(String vehicleId, Integer toMap, Integer geoAddress, Integer currentPage, Integer pageRecords);
    /**
     * 获取设备历史轨迹
     *
     * @param devIdno 设备号
     * @param begintime 开始时间(格式:yyyy-MM-dd HH:mm:ss)
     * @param endtime 结束时间(格式:yyyy-MM-dd HH:mm:ss)
     * @param distance 距离(单位:KM,可选)
     * @param parkTime 停车时长(单位:秒,可选)
     * @param geoaddress 是否解析地理位置(1:是,可选)
     * @param currentPage 当前查询页码(可选)
     * @param pageRecords 每页条数(可选)
     * @param toMap 地图经纬度转换(1:谷歌地图,2:百度地图,可选)
     * @return 历史轨迹响应
     */
    CmsTrackDetailResponse queryTrackDetail(String devIdno, String begintime, String endtime,
            Double distance, Integer parkTime, Integer geoaddress, Integer currentPage,
            Integer pageRecords, Integer toMap);
ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java
@@ -32,4 +32,12 @@
     * @return 设备号,如果未找到则返回null
     */
    String getDeviceIdByPlateNumber(String plateNumber);
    /**
     * 按时间查询历史轨迹
     *
     * @param request 查询请求
     * @return 轨迹查询响应
     */
    GpsTrackQueryResponse queryTracks(GpsTrackQueryRequest request);
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleGpsService.java
@@ -36,4 +36,11 @@
     * 删除车辆GPS坐标信息
     */
    public int deleteVehicleGpsById(Long gpsId);
    /**
     * 删除指定日期之前的车辆GPS数据
     *
     * @return 删除的记录数
     */
    public int deleteVehicleGpsBeforeDate();
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CmsGpsCollectServiceImpl.java
@@ -6,6 +6,7 @@
import com.ruoyi.system.domain.CmsVehicleDeviceResponse;
import com.ruoyi.system.domain.CmsVehicleDeviceListResponse;
import com.ruoyi.system.domain.CmsVehicleLocationResponse;
import com.ruoyi.system.domain.CmsTrackDetailResponse;
import com.ruoyi.system.domain.SysGpsConfig;
import com.ruoyi.system.service.ICmsGpsCollectService;
import com.ruoyi.system.service.IGpsConfigService;
@@ -15,6 +16,8 @@
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONObject;
import java.util.Date;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
 * CMS GPS采集服务实现
@@ -115,13 +118,17 @@
            }
            // 构建请求URL
            String url = baseUrlConfig.getDomain() + "/StandardApiAction_getDeviceByVehicle.action?jsession=" + baseUrlConfig.getToken();
            StringBuilder url = new StringBuilder();
            url.append(baseUrlConfig.getDomain())
               .append("/StandardApiAction_getDeviceByVehicle.action?jsession=")
               .append(baseUrlConfig.getToken());
            if (vehicleId != null && !vehicleId.isEmpty()) {
                url += "&vehiIdno=" + vehicleId;
                url.append("&vehiIdno=").append(vehicleId);
            }
            // 发送查询请求
            String response = HttpUtil.get(url,null);
            String response = HttpUtils.sendGet(url.toString());
            
            // 解析响应
            CmsVehicleDeviceListResponse deviceListResponse = JSONObject.parseObject(response, CmsVehicleDeviceListResponse.class);
@@ -196,4 +203,71 @@
            throw new RuntimeException("获取车辆位置信息异常:" + e.getMessage());
        }
    }
    @Override
    public CmsTrackDetailResponse queryTrackDetail(String devIdno, String begintime, String endtime,
            Double distance, Integer parkTime, Integer geoaddress, Integer currentPage,
            Integer pageRecords, Integer toMap) {
        try {
            // 从数据库获取CMS配置
            SysGpsConfig baseUrlConfig = gpsConfigService.selectGpsConfigByKey("gpscms");
            if (baseUrlConfig == null) {
                throw new RuntimeException("未配置CMS系统地址");
            }
            // 检查token是否过期
            if (baseUrlConfig.getTokenExpireTime() == null ||
                baseUrlConfig.getTokenExpireTime().before(new Date())) {
                // token过期,重新登录
                login(baseUrlConfig.getUsername(), baseUrlConfig.getPassword());
                baseUrlConfig = gpsConfigService.selectGpsConfigByKey("gpscms");
            }
            // 构建请求URL
            StringBuilder url = new StringBuilder(baseUrlConfig.getDomain())
               .append("/StandardApiAction_queryTrackDetail.action?jsession=")
               .append(baseUrlConfig.getToken())
               .append("&devIdno=").append(devIdno)
               .append("&begintime=").append(begintime)
               .append("&endtime=").append(endtime);
            // 添加可选参数
            if (distance != null) {
                url.append("&distance=").append(distance);
            }
            if (parkTime != null) {
                url.append("&parkTime=").append(parkTime);
            }
            if (geoaddress != null) {
                url.append("&geoaddress=").append(geoaddress);
            }
            if (currentPage != null) {
                url.append("&currentPage=").append(currentPage);
            }
            if (pageRecords != null) {
                url.append("&pageRecords=").append(pageRecords);
            }
            if (toMap != null) {
                url.append("&toMap=").append(toMap);
            }
            // 发送查询请求
            String response = HttpUtils.sendGet(url.toString());
            // 解析响应
            CmsTrackDetailResponse trackResponse = JSONObject.parseObject(response, CmsTrackDetailResponse.class);
            if (trackResponse.getResult() == 0) {
                log.info("获取设备历史轨迹成功,设备号:{}", devIdno);
            } else {
                log.error("获取设备历史轨迹失败,设备号:{}", devIdno);
            }
            return trackResponse;
        } catch (Exception e) {
            log.error("获取设备历史轨迹异常,设备号:{}", devIdno, e);
            throw new RuntimeException("获取设备历史轨迹异常:" + e.getMessage());
        }
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java
@@ -510,4 +510,92 @@
        return null;
    }
    @Override
    public GpsTrackQueryResponse queryTracks(GpsTrackQueryRequest request) {
        // 获取GPS配置信息
        SysGpsConfig config = gpsConfigService.selectGpsConfigByKey("gps51");
        if (config == null) {
            GpsTrackQueryResponse response = new GpsTrackQueryResponse();
            response.setStatus(-1);
            response.setCause("未找到GPS配置信息");
            return response;
        }
        // 获取有效的token,如果无效则自动登录
        String token = getValidTokenWithAutoLogin();
        if (token == null) {
            GpsTrackQueryResponse response = new GpsTrackQueryResponse();
            response.setStatus(-1);
            response.setCause("获取token失败");
            return response;
        }
        // 构建请求URL
        String url = config.getDomain() + "/webapi?action=querytracks&token=" + token;
        // 构建请求参数
        Map<String, String> params = new HashMap<>();
        params.put("deviceid", request.getDeviceid());
        params.put("begintime", request.getBegintime());
        params.put("endtime", request.getEndtime());
        if (request.getTimezone() != null) {
            params.put("timezone", String.valueOf(request.getTimezone()));
        }
        try {
            // 发送HTTP请求
            String result = HttpUtil.post(url, params);
            JSONObject jsonResult = JSON.parseObject(result);
            // 解析响应
            GpsTrackQueryResponse response = new GpsTrackQueryResponse();
            response.setStatus(jsonResult.getInteger("status"));
            response.setCause(jsonResult.getString("cause"));
            response.setDeviceid(jsonResult.getString("deviceid"));
            if (response.getStatus() == 0) {
                // 解析轨迹记录列表
                JSONArray recordsArray = jsonResult.getJSONArray("records");
                List<GpsTrackPoint> records = new ArrayList<>();
                for (int i = 0; i < recordsArray.size(); i++) {
                    JSONObject recordJson = recordsArray.getJSONObject(i);
                    GpsTrackPoint record = new GpsTrackPoint();
                    record.setTrackCount(recordJson.getInteger("trackCount"));
                    record.setStarttime(recordJson.getLong("starttime"));
                    record.setEndtime(recordJson.getLong("endtime"));
                    record.setTrackid(recordJson.getInteger("trackid"));
                    record.setArrivedtime(recordJson.getLong("arrivedtime"));
                    record.setUpdatetime(recordJson.getLong("updatetime"));
                    record.setLatitude(recordJson.getDouble("callat"));
                    record.setLongitude(recordJson.getDouble("callon"));
                    record.setAltitude(recordJson.getDouble("altitude"));
                    record.setRadius(recordJson.getInteger("radius"));
                    record.setSpeed(recordJson.getDouble("speed"));
                    record.setRecorderspeed(recordJson.getDouble("recorderspeed"));
                    record.setTotaldistance(recordJson.getInteger("totaldistance"));
                    record.setCourse(recordJson.getInteger("course"));
                    record.setStatus(recordJson.getLong("status"));
                    record.setStrstatus(recordJson.getString("strstatus"));
                    record.setStrstatusen(recordJson.getString("strstatusen"));
                    record.setGotsrc(recordJson.getString("gotsrc"));
                    record.setRxlevel(recordJson.getInteger("rxlevel"));
                    record.setGpsvalidnum(recordJson.getInteger("gpsvalidnum"));
                    record.setReportmode(recordJson.getShort("reportmode"));
                    records.add(record);
                }
                response.setRecords(records);
            }
            return response;
        } catch (Exception e) {
            GpsTrackQueryResponse response = new GpsTrackQueryResponse();
            response.setStatus(-1);
            response.setCause("查询历史轨迹失败:" + e.getMessage());
            return response;
        }
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
@@ -71,4 +71,12 @@
    public int deleteVehicleGpsById(Long gpsId) {
        return vehicleGpsMapper.deleteVehicleGpsById(gpsId);
    }
    /**
     * 删除指定日期之前的车辆GPS数据
     */
    @Override
    public int deleteVehicleGpsBeforeDate() {
        return vehicleGpsMapper.deleteVehicleGpsBeforeDate();
    }
ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
@@ -110,4 +110,13 @@
    <select id="getVehicleIdByNo" parameterType="String" resultType="Long">
        select vehicle_id from tb_vehicle_info where vehicle_no = #{vehicleNo}
    </select>
    <delete id="deleteVehicleGpsBeforeDate">
        delete g from tb_vehicle_gps g
        where g.collect_time &lt; (
            select date_sub(max(collect_time), interval 2 day)
            from tb_vehicle_gps g2
            where g2.vehicle_id = g.vehicle_id
        )
    </delete>
</mapper> 
sql/clean_gps.sql
New file
@@ -0,0 +1,27 @@
INSERT INTO sys_job (
    job_name,
    job_group,
    invoke_target,
    cron_expression,
    misfire_policy,
    concurrent,
    status,
    create_by,
    create_time,
    update_by,
    update_time,
    remark
) VALUES (
    '清理车辆GPS历史数据',
    'DEFAULT',
    'cleanVehicleGpsTask.cleanVehicleGpsData()',
    '0 0 1 * * ?',
    '1',
    '1',
    '0',
    'admin',
    sysdate(),
    'admin',
    sysdate(),
    '每天凌晨1点清理车辆GPS历史数据,只保留每台车最后2天的数据'
);