From a296c6bfa83cd0a4bbc92d93c015a010248e8455 Mon Sep 17 00:00:00 2001
From: wanglizhong <wlz>
Date: 星期六, 03 五月 2025 19:49:45 +0800
Subject: [PATCH] feat:增加gps显示

---
 ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java                    |   41 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java                  |  127 ++
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java   |  487 +++++++
 ruoyi-ui/src/api/system/gpsconfig.js                                                  |   61 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java               |   12 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java                     |  172 ++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java              |   46 
 sql/sys_gps_config.sql                                                                |   19 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java   |    6 
 ruoyi-ui/public/car_blue.png                                                          |    0 
 ruoyi-quartz/pom.xml                                                                  |    1 
 sql/add_task.sql                                                                      |   27 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java               |  660 ++++++++++
 ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml                  |  105 +
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java                     |  175 ++
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java             |   26 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java |  107 +
 ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java            |   84 +
 ruoyi-ui/src/views/system/gps/index.vue                                               |   15 
 ruoyi-ui/src/views/system/gps/map.vue                                                 |  543 ++++++++
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java                      |   55 
 ruoyi-ui/src/router/index.js                                                          |    5 
 ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java           |   23 
 ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml                    |   12 
 ruoyi-ui/src/permission.js                                                            |    2 
 ruoyi-ui/public/car_green.png                                                         |    0 
 ruoyi-ui/public/index.html                                                            |    1 
 ruoyi-system/pom.xml                                                                  |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java  |   29 
 sql/sys_menu.sql                                                                      |   22 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java    |   89 +
 ruoyi-ui/src/api/system/gps.js                                                        |   38 
 ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java          |   26 
 ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java              |   18 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java                   |   13 
 sql/vehicle_gps.sql                                                                   |    3 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java        |   33 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java   |   23 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java            |   65 +
 ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml                   |   38 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java         |   44 
 sql/vehicle_info.sql                                                                  |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java       |   55 
 ruoyi-ui/src/views/system/gpsconfig/index.vue                                         |  297 ++++
 44 files changed, 3,513 insertions(+), 101 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java
index ec7d4d0..659d991 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java
@@ -3,8 +3,7 @@
 import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.system.domain.GpsLoginRequest;
-import com.ruoyi.system.domain.GpsLoginResponse;
+import com.ruoyi.system.domain.*;
 import com.ruoyi.system.service.IGpsCollectService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
@@ -33,4 +32,24 @@
         GpsLoginResponse response = gpsCollectService.login(request);
         return success(response);
     }
+
+    @Anonymous()
+    @GetMapping("/testGetDevices")
+    public AjaxResult testGetDevices() {
+
+
+        GpsDeviceListResponse response = gpsCollectService.getDeviceList();
+        return success(response);
+    }
+
+    @Anonymous()
+    @GetMapping("/testGetLastPosition")
+    public AjaxResult testGetLastPosition() {
+        GpsLastPositionRequest request = new GpsLastPositionRequest();
+        // request.setDeviceids(Arrays.asList("1234567890"));
+        GpsLastPositionResponse response = gpsCollectService.getLastPosition(request);
+        return success(response);
+    }
+    
+
 } 
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java
new file mode 100644
index 0000000..8616fdc
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java
@@ -0,0 +1,107 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.enums.BusinessType;
+import com.ruoyi.system.domain.SysGpsConfig;
+import com.ruoyi.system.service.IGpsConfigService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.SecurityUtils;
+
+/**
+ * GPS閰嶇疆Controller
+ */
+@RestController
+@RequestMapping("/system/gpsconfig")
+public class SysGpsConfigController extends BaseController {
+    @Autowired
+    private IGpsConfigService gpsConfigService;
+
+    /**
+     * 鏌ヨGPS閰嶇疆鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysGpsConfig gpsConfig) {
+        startPage();
+        List<SysGpsConfig> list = gpsConfigService.selectGpsConfigList(gpsConfig);
+        return getDataTable(list);
+    }
+
+    /**
+     * 瀵煎嚭GPS閰嶇疆鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:export')")
+    @Log(title = "GPS閰嶇疆", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysGpsConfig gpsConfig) {
+        List<SysGpsConfig> list = gpsConfigService.selectGpsConfigList(gpsConfig);
+        ExcelUtil<SysGpsConfig> util = new ExcelUtil<SysGpsConfig>(SysGpsConfig.class);
+        util.exportExcel(response, list, "GPS閰嶇疆鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇GPS閰嶇疆璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable("configId") Long configId) {
+        return success(gpsConfigService.selectGpsConfigById(configId));
+    }
+
+    /**
+     * 鏂板GPS閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:add')")
+    @Log(title = "GPS閰嶇疆", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysGpsConfig gpsConfig) {
+        gpsConfig.setCreateBy(SecurityUtils.getUsername());
+        gpsConfig.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(gpsConfigService.insertGpsConfig(gpsConfig));
+    }
+
+    /**
+     * 淇敼GPS閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:edit')")
+    @Log(title = "GPS閰嶇疆", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysGpsConfig gpsConfig) {
+        gpsConfig.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(gpsConfigService.updateGpsConfig(gpsConfig));
+    }
+
+    /**
+     * 鍒犻櫎GPS閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:remove')")
+    @Log(title = "GPS閰嶇疆", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds) {
+        return toAjax(gpsConfigService.deleteGpsConfigByIds(configIds));
+    }
+
+    /**
+     * 鑾峰彇鏈夋晥鐨則oken
+     */
+    @PreAuthorize("@ss.hasPermi('system:gpsconfig:query')")
+    @GetMapping("/token/{configKey}")
+    public AjaxResult getValidToken(@PathVariable("configKey") String configKey) {
+        return success(gpsConfigService.getValidToken(configKey));
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-quartz/pom.xml b/ruoyi-quartz/pom.xml
index df98f98..4b194ba 100644
--- a/ruoyi-quartz/pom.xml
+++ b/ruoyi-quartz/pom.xml
@@ -38,7 +38,6 @@
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-system</artifactId>
         </dependency>
-
     </dependencies>
 
 </project>
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java
new file mode 100644
index 0000000..8c7c1ee
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java
@@ -0,0 +1,172 @@
+package com.ruoyi.quartz.task;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.ruoyi.system.domain.GpsDevice;
+import com.ruoyi.system.domain.GpsDeviceListResponse;
+import com.ruoyi.system.domain.GpsGroup;
+import com.ruoyi.system.domain.GpsLastPosition;
+import com.ruoyi.system.domain.GpsLastPositionRequest;
+import com.ruoyi.system.domain.GpsLastPositionResponse;
+import com.ruoyi.system.domain.VehicleGps;
+import com.ruoyi.system.domain.VehicleInfo;
+import com.ruoyi.system.service.IGpsCollectService;
+import com.ruoyi.system.service.IVehicleGpsService;
+import com.ruoyi.system.service.IVehicleInfoService;
+
+/**
+ * GPS鍚屾瀹氭椂浠诲姟
+ */
+@Component("gpsSyncTask")
+public class GpsSyncTask {
+
+    private static final Logger log = LoggerFactory.getLogger(GpsSyncTask.class);
+
+    @Autowired
+    private IGpsCollectService gpsCollectService;
+
+    @Autowired
+    private IVehicleInfoService vehicleInfoService;
+
+    @Autowired
+    private IVehicleGpsService vehicleGpsService;
+
+    /**
+     * 鍚屾璁惧鍒楄〃鍜孏PS浣嶇疆
+     */
+    public void syncGpsData() {
+        try {
+            log.info("寮�濮嬪悓姝PS鏁版嵁...");
+
+            // 1. 鑾峰彇璁惧鍒楄〃锛岃繖浼氳嚜鍔ㄦ洿鏂拌溅杈嗕俊鎭腑鐨勮澶嘔D
+            GpsDeviceListResponse response = gpsCollectService.getDeviceList();
+            // 鏇存柊杞﹁締璁惧ID
+            updateVehicleDeviceIds(response);
+
+            // 2. 鑾峰彇鎵�鏈夎溅杈嗕俊鎭�
+            List<VehicleInfo> vehicleList = vehicleInfoService.selectVehicleInfoList(new VehicleInfo());
+
+            //鍦ㄨ繖閲岃幏寰楁墍鏈夎溅杈嗙殑GPS鏈�鍚庝綅缃�
+            GpsLastPositionResponse gpsLastPositionResponse = gpsCollectService.getLastPosition(new GpsLastPositionRequest());
+
+            // 3. 閬嶅巻杞﹁締鍒楄〃锛岃幏鍙栨瘡涓溅杈嗙殑GPS浣嶇疆
+            for (VehicleInfo vehicle : vehicleList) {
+                if (vehicle.getDeviceId() != null && !vehicle.getDeviceId().isEmpty()) {
+                    try {
+                        // 鑾峰彇杞﹁締鐨勬渶鍚庝綅缃�
+                        gpsLastPositionResponse.getRecords().stream().filter(e->e.getDeviceid().equals(vehicle.getDeviceId())).forEach(record -> {
+                                updateVehicleGpsPositions(vehicle, record);
+
+                        });
+
+                    } catch (Exception e) {
+                        log.error("鑾峰彇杞﹁締[{}]GPS浣嶇疆澶辫触: {}", vehicle.getVehicleNo(), e.getMessage());
+                    }
+                }
+            }
+
+            log.info("GPS鏁版嵁鍚屾瀹屾垚");
+        } catch (Exception e) {
+            log.error("GPS鏁版嵁鍚屾澶辫触: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 鏇存柊杞﹁締璁惧ID
+     */
+    private void updateVehicleDeviceIds(GpsDeviceListResponse response) {
+        if (response.getStatus() != 0 || response.getGroups() == null) {
+            return;
+        }
+
+        for (GpsGroup group : response.getGroups()) {
+            for (GpsDevice device : group.getDevices()) {
+                String deviceName = device.getDevicename();
+                String remark = device.getRemark();
+                String deviceId = device.getDeviceid();
+
+                if (StringUtils.isNotEmpty(deviceName) || StringUtils.isNotEmpty(remark)) {
+                    String plateNumber = extractPlateNumber(deviceName, remark);
+                    if (StringUtils.isNotEmpty(plateNumber)) {
+                        VehicleInfo vehicleInfo = vehicleInfoService.selectVehicleInfoByPlateNumber(plateNumber);
+                        if (vehicleInfo != null) {
+                            vehicleInfo.setDeviceId(deviceId);
+                            vehicleInfoService.updateVehicleInfo(vehicleInfo);
+                        } else {
+                            VehicleInfo newVehicle = new VehicleInfo();
+                            newVehicle.setVehicleNo(plateNumber);
+                            newVehicle.setDeviceId(deviceId);
+                            newVehicle.setStatus("0");
+                            vehicleInfoService.insertVehicleInfo(newVehicle);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 浠庤澶囧悕绉板拰澶囨敞涓彁鍙栬溅鐗屽彿
+     */
+    private String extractPlateNumber(String deviceName, String remark) {
+        if (StringUtils.isNotEmpty(deviceName)) {
+            return deviceName;
+        }
+        if (StringUtils.isNotEmpty(remark)) {
+            return remark;
+        }
+        return null;
+    }
+
+    /**
+     * 鏇存柊杞﹁締GPS浣嶇疆淇℃伅
+     */
+    private void updateVehicleGpsPositions(VehicleInfo vehicle, GpsLastPosition position) {
+        try {
+            VehicleGps gps = new VehicleGps();
+            gps.setVehicleId(vehicle.getVehicleId());
+            gps.setDeviceId(vehicle.getDeviceId());
+            gps.setLongitude(position.getCallon());
+            gps.setLatitude(position.getCallat());
+            gps.setAltitude(position.getAltitude());
+            gps.setSpeed(position.getSpeed());
+            gps.setDirection(Double.valueOf(position.getCourse()));
+            
+            //devicetime 杩欎釜鏄竴涓猯inux鏃堕棿鎴筹紝瑕佽浆鎹㈡垚鍖椾含鏃堕棿锛屽啀杞垚yyyy-MM-dd HH:mm:ss鏍煎紡
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            
+            // 璁惧涓婃姤鏃堕棿
+            long deviceTime = position.getDevicetime();
+            if (deviceTime > 0 && deviceTime < 4102444800L) { // 2100-01-01 00:00:00
+                gps.setDeviceReportTime(sdf.format(new Date(deviceTime * 1000L)));
+            } else {
+                log.warn("杞﹁締[{}]鐨勮澶囨椂闂存埑[{}]鏃犳晥锛屼娇鐢ㄥ綋鍓嶆椂闂�", vehicle.getVehicleNo(), deviceTime);
+                gps.setDeviceReportTime(sdf.format(new Date()));
+            }
+            
+            // 骞冲彴澶勭悊鏃堕棿锛堝綋鍓嶆椂闂达級
+            gps.setPlatformProcessTime(sdf.format(new Date()));
+            
+            // 閲囬泦鏃堕棿锛堜娇鐢ㄨ澶囦笂鎶ユ椂闂达級
+            gps.setCollectTime(gps.getDeviceReportTime());
+
+            // 淇濆瓨GPS浣嶇疆淇℃伅
+            vehicleGpsService.insertVehicleGps(gps);
+
+            log.info("杞﹁締[{}]GPS浣嶇疆宸叉洿鏂�: 缁忓害={}, 绾害={}, 璁惧鏃堕棿={}, 澶勭悊鏃堕棿={}",
+                    vehicle.getVehicleNo(), position.getCallon(), position.getCallat(), 
+                    gps.getDeviceReportTime(), gps.getPlatformProcessTime());
+        } catch (Exception e) {
+            log.error("鏇存柊杞﹁締[{}]GPS浣嶇疆澶辫触: {}", vehicle.getVehicleNo(), e.getMessage());
+        }
+    }
+
+}
diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml
index f38f016..1b2a373 100644
--- a/ruoyi-system/pom.xml
+++ b/ruoyi-system/pom.xml
@@ -32,6 +32,7 @@
             <artifactId>lombok</artifactId>
             <scope>provided</scope>
         </dependency>
+       
         <!-- FastJSON -->
         <dependency>
             <groupId>com.alibaba</groupId>
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java
index 9b708f9..0a43d81 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java
@@ -12,6 +12,8 @@
     private String domain;
     private String username;
     private String password;
+    private String token;
+    private Long tokenExpireTime;
 
     public String getDomain() {
         return domain;
@@ -36,4 +38,20 @@
     public void setPassword(String password) {
         this.password = password;
     }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public Long getTokenExpireTime() {
+        return tokenExpireTime;
+    }
+
+    public void setTokenExpireTime(Long tokenExpireTime) {
+        this.tokenExpireTime = tokenExpireTime;
+    }
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java
new file mode 100644
index 0000000..6ccbfb7
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java
@@ -0,0 +1,175 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+
+/**
+ * GPS璁惧淇℃伅
+ */
+public class GpsDevice implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 璁惧搴忓垪鍙� */
+    private String deviceid;
+
+    /** 璁惧鍚嶇О */
+    private String devicename;
+
+    /** 璁惧绫诲瀷 */
+    private Integer devicetype;
+
+    /** SIM鍙风爜 */
+    private String simnum;
+
+    /** 杩囨湡鏃堕棿 */
+    private Long overduetime;
+
+    /** 鍒版湡閫氱煡鏃堕棿 */
+    private Long expirenotifytime;
+
+    /** 澶囨敞 */
+    private String remark;
+
+    /** 鍒涘缓鑰� */
+    private String creater;
+
+    /** 瑙嗛閫氶亾鏁� */
+    private Integer videochannelcount;
+
+    /** 鏈�鍚庢椿鍔ㄦ椂闂� */
+    private Long lastactivetime;
+
+    /** 浣跨敤鐘舵�� */
+    private Integer isfree;
+
+    /** 鏄惁鍏佽缂栬緫 */
+    private Integer allowedit;
+
+    /** 鍥炬爣 */
+    private Integer icon;
+
+    /** 鏄惁鍏虫敞 */
+    private Integer stared;
+
+    /** 鐧诲綍鍚嶇О */
+    private String loginname;
+
+    public String getDeviceid() {
+        return deviceid;
+    }
+
+    public void setDeviceid(String deviceid) {
+        this.deviceid = deviceid;
+    }
+
+    public String getDevicename() {
+        return devicename;
+    }
+
+    public void setDevicename(String devicename) {
+        this.devicename = devicename;
+    }
+
+    public Integer getDevicetype() {
+        return devicetype;
+    }
+
+    public void setDevicetype(Integer devicetype) {
+        this.devicetype = devicetype;
+    }
+
+    public String getSimnum() {
+        return simnum;
+    }
+
+    public void setSimnum(String simnum) {
+        this.simnum = simnum;
+    }
+
+    public Long getOverduetime() {
+        return overduetime;
+    }
+
+    public void setOverduetime(Long overduetime) {
+        this.overduetime = overduetime;
+    }
+
+    public Long getExpirenotifytime() {
+        return expirenotifytime;
+    }
+
+    public void setExpirenotifytime(Long expirenotifytime) {
+        this.expirenotifytime = expirenotifytime;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getCreater() {
+        return creater;
+    }
+
+    public void setCreater(String creater) {
+        this.creater = creater;
+    }
+
+    public Integer getVideochannelcount() {
+        return videochannelcount;
+    }
+
+    public void setVideochannelcount(Integer videochannelcount) {
+        this.videochannelcount = videochannelcount;
+    }
+
+    public Long getLastactivetime() {
+        return lastactivetime;
+    }
+
+    public void setLastactivetime(Long lastactivetime) {
+        this.lastactivetime = lastactivetime;
+    }
+
+    public Integer getIsfree() {
+        return isfree;
+    }
+
+    public void setIsfree(Integer isfree) {
+        this.isfree = isfree;
+    }
+
+    public Integer getAllowedit() {
+        return allowedit;
+    }
+
+    public void setAllowedit(Integer allowedit) {
+        this.allowedit = allowedit;
+    }
+
+    public Integer getIcon() {
+        return icon;
+    }
+
+    public void setIcon(Integer icon) {
+        this.icon = icon;
+    }
+
+    public Integer getStared() {
+        return stared;
+    }
+
+    public void setStared(Integer stared) {
+        this.stared = stared;
+    }
+
+    public String getLoginname() {
+        return loginname;
+    }
+
+    public void setLoginname(String loginname) {
+        this.loginname = loginname;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java
new file mode 100644
index 0000000..a2dcd83
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java
@@ -0,0 +1,44 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * GPS璁惧鍒楄〃鍝嶅簲
+ */
+public class GpsDeviceListResponse implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 鐘舵�� */
+    private Integer status;
+
+    /** 鐘舵�佹弿杩� */
+    private String cause;
+
+    /** 鍒嗙粍鍒楄〃 */
+    private List<GpsGroup> groups;
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getCause() {
+        return cause;
+    }
+
+    public void setCause(String cause) {
+        this.cause = cause;
+    }
+
+    public List<GpsGroup> getGroups() {
+        return groups;
+    }
+
+    public void setGroups(List<GpsGroup> groups) {
+        this.groups = groups;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java
new file mode 100644
index 0000000..c2a34b8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java
@@ -0,0 +1,55 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * GPS鍒嗙粍淇℃伅
+ */
+public class GpsGroup implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 鍒嗙粍ID */
+    private Integer groupid;
+
+    /** 鍒嗙粍鍚嶇О */
+    private String groupname;
+
+    /** 鍒嗙粍澶囨敞 */
+    private String remark;
+
+    /** 璁惧鍒楄〃 */
+    private List<GpsDevice> devices;
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getGroupname() {
+        return groupname;
+    }
+
+    public void setGroupname(String groupname) {
+        this.groupname = groupname;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public List<GpsDevice> getDevices() {
+        return devices;
+    }
+
+    public void setDevices(List<GpsDevice> devices) {
+        this.devices = devices;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java
new file mode 100644
index 0000000..6569b8c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java
@@ -0,0 +1,660 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+
+/**
+ * GPS璁惧鏈�鍚庝綅缃俊鎭�
+ */
+public class GpsLastPosition implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 璁惧搴忓垪鍙� */
+    private String deviceid;
+
+    /** GPS璁惧涓婃姤鏃堕棿 */
+    private Long devicetime;
+
+    /** 鍒拌揪鏈嶅姟鍣ㄦ椂闂� */
+    private Long arrivedtime;
+
+    /** 缁煎悎璁$畻鍚庝綅缃洿鏂版椂闂� */
+    private Long updatetime;
+
+    /** 鏈�鍚庝綅缃畾浣嶆椂闂� */
+    private Long validpoistiontime;
+
+    /** 绾害 */
+    private Double callat;
+
+    /** 缁忓害 */
+    private Double callon;
+
+    /** 楂樺害(绫�) */
+    private Double altitude;
+
+    /** 瀹氫綅绮惧害绫� */
+    private Integer radius;
+
+    /** 閫熷害锛堢背锛� */
+    private Double speed;
+
+    /** 鏂瑰悜锛�0-360锛� */
+    private Integer course;
+
+    /** 鎬婚噷绋嬬背 */
+    private Integer totaldistance;
+
+    /** 鎬绘补閲忥紙姣崌锛� */
+    private Integer totaloil;
+
+    /** 鎬婚潪琛岄┒娌硅�楋紙姣崌锛� */
+    private Integer totalnotrunningad;
+
+    /** 绗�1涓补绠憋紙姣崌锛� */
+    private Integer masteroil;
+
+    /** 绗�2涓补绠憋紙姣崌锛� */
+    private Integer auxoil;
+
+    /** 绗�3涓补绠憋紙姣崌锛� */
+    private Integer thirdoil;
+
+    /** 绗�4涓补绠憋紙姣崌锛� */
+    private Integer fourthoil;
+
+    /** 娌归噺妯℃嫙閲�1 */
+    private Integer srcad0;
+
+    /** 娌归噺妯℃嫙閲�2 */
+    private Integer srcad1;
+
+    /** 娌归噺妯℃嫙閲�3 */
+    private Integer srcad2;
+
+    /** 娌归噺妯℃嫙閲�4 */
+    private Integer srcad3;
+
+    /** 閮ㄦ爣鐘舵�佸�� */
+    private Long status;
+
+    /** 閮ㄦ爣鐘舵�佹枃瀛楁弿杩� */
+    private String strstatus;
+
+    /** 閮ㄦ爣鐘舵�佽嫳鏂囨枃瀛楁弿杩� */
+    private String strstatusen;
+
+    /** 閮ㄦ爣鎶ヨ鍊� */
+    private Long alarm;
+
+    /** 閮ㄦ爣鎶ヨ鏂囧瓧鎻忚堪 */
+    private String stralarm;
+
+    /** 閮ㄦ爣鎶ヨ鑻辨枃鏂囧瓧鎻忚堪 */
+    private String stralarmsen;
+
+    /** 閮ㄦ爣瑙嗛鎶ヨ鍊� */
+    private Long videoalarm;
+
+    /** 閮ㄦ爣瑙嗛鎶ヨ鏂囧瓧鎻忚堪 */
+    private String strvideoalarm;
+
+    /** 閮ㄦ爣瑙嗛鎶ヨ鑻辨枃鏂囧瓧鎻忚堪 */
+    private String strvideoalarmen;
+
+    /** 瑙嗛淇″彿涓㈠け鐘舵�� */
+    private Long videosignalloststatus;
+
+    /** 瑙嗛閬尅鐘舵�� */
+    private Long videosignalcoverstatus;
+
+    /** 瑙嗛寮傚父椹鹃┒琛屼负鐘舵�� */
+    private Long videobehavior;
+
+    /** 瑙嗛鐤插姵绋嬪害 */
+    private Long videofatiguedegree;
+
+    /** 浣嶇疆淇℃伅鏉ユ簮瀹氫綅绫诲瀷 (gps,wifi,cell) */
+    private String gotsrc;
+
+    /** 鍩虹珯淇″彿寮哄害 */
+    private Integer rxlevel;
+
+    /** gps鏈夋晥鏁� */
+    private Integer gpsvalidnum;
+
+    /** 澶栭儴鐢靛帇锛�0.01V锛� */
+    private Double exvoltage;
+
+    /** 鐢靛帇锛�0.01V锛� */
+    private Double voltagev;
+
+    /** 鐢甸噺鐧惧垎姣� */
+    private Double voltagepercent;
+
+    /** 鏄惁绉诲姩锛�0锛氭病杩愬姩锛�1锛氬湪杩愬姩锛� */
+    private Integer moving;
+
+    /** 鏈�鍚庡仠鐣欑殑绾害 */
+    private Double parklat;
+
+    /** 鏈�鍚庡仠鐣欑殑缁忓害 */
+    private Double parklon;
+
+    /** 鏈�鍚庡仠鐣欐椂闂� */
+    private Long parktime;
+
+    /** 鍋滅暀鏃堕暱 */
+    private Long parkduration;
+
+    /** 娓╁害1锛�1/100搴︼級 */
+    private Integer temp1;
+
+    /** 娓╁害2锛�1/100搴︼級 */
+    private Integer temp2;
+
+    /** 娓╁害3锛�1/100搴︼級 */
+    private Integer temp3;
+
+    /** 娓╁害4锛�1/100搴︼級 */
+    private Integer temp4;
+
+    /** 婀垮害1 */
+    private Integer humi1;
+
+    /** 婀垮害2 */
+    private Integer humi2;
+
+    /** IO鐘舵�佷綅 */
+    private Integer iostatus;
+
+    /** 瓒呴�熺姸鎬侊紙1锛氭鍦ㄨ秴閫燂紝2锛氭湭瓒呴�燂級 */
+    private Integer currentoverspeedstate;
+
+    /** 姝e弽杞紙0锛氭湭鐭ワ紝1锛氭杞紝2锛氬弽杞紝3锛氬仠杞級 */
+    private Short rotatestatus;
+
+    /** 杞介噸鐘舵�侊紙0x00锛氱┖杞︼紝0x01锛氬崐杞斤紝0x02锛氳秴杞斤紝0x03锛氭弧杞斤紝0x04锛氳杞斤紝0x05锛氬嵏杞斤級 */
+    private Short loadstatus;
+
+    /** 閲嶉噺锛�0.1kg锛� */
+    private Long weight;
+
+    /** 杞介噸AD0 */
+    private Integer srcweightad0;
+
+    /** 涓婃姤绫诲瀷 */
+    private Short reportmode;
+
+    // Getters and Setters
+    public String getDeviceid() {
+        return deviceid;
+    }
+
+    public void setDeviceid(String deviceid) {
+        this.deviceid = deviceid;
+    }
+
+    public Long getDevicetime() {
+        return devicetime;
+    }
+
+    public void setDevicetime(Long devicetime) {
+        this.devicetime = devicetime;
+    }
+
+    public Long getArrivedtime() {
+        return arrivedtime;
+    }
+
+    public void setArrivedtime(Long arrivedtime) {
+        this.arrivedtime = arrivedtime;
+    }
+
+    public Long getUpdatetime() {
+        return updatetime;
+    }
+
+    public void setUpdatetime(Long updatetime) {
+        this.updatetime = updatetime;
+    }
+
+    public Long getValidpoistiontime() {
+        return validpoistiontime;
+    }
+
+    public void setValidpoistiontime(Long validpoistiontime) {
+        this.validpoistiontime = validpoistiontime;
+    }
+
+    public Double getCallat() {
+        return callat;
+    }
+
+    public void setCallat(Double callat) {
+        this.callat = callat;
+    }
+
+    public Double getCallon() {
+        return callon;
+    }
+
+    public void setCallon(Double callon) {
+        this.callon = callon;
+    }
+
+    public Double getAltitude() {
+        return altitude;
+    }
+
+    public void setAltitude(Double altitude) {
+        this.altitude = altitude;
+    }
+
+    public Integer getRadius() {
+        return radius;
+    }
+
+    public void setRadius(Integer radius) {
+        this.radius = radius;
+    }
+
+    public Double getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(Double speed) {
+        this.speed = speed;
+    }
+
+    public Integer getCourse() {
+        return course;
+    }
+
+    public void setCourse(Integer course) {
+        this.course = course;
+    }
+
+    public Integer getTotaldistance() {
+        return totaldistance;
+    }
+
+    public void setTotaldistance(Integer totaldistance) {
+        this.totaldistance = totaldistance;
+    }
+
+    public Integer getTotaloil() {
+        return totaloil;
+    }
+
+    public void setTotaloil(Integer totaloil) {
+        this.totaloil = totaloil;
+    }
+
+    public Integer getTotalnotrunningad() {
+        return totalnotrunningad;
+    }
+
+    public void setTotalnotrunningad(Integer totalnotrunningad) {
+        this.totalnotrunningad = totalnotrunningad;
+    }
+
+    public Integer getMasteroil() {
+        return masteroil;
+    }
+
+    public void setMasteroil(Integer masteroil) {
+        this.masteroil = masteroil;
+    }
+
+    public Integer getAuxoil() {
+        return auxoil;
+    }
+
+    public void setAuxoil(Integer auxoil) {
+        this.auxoil = auxoil;
+    }
+
+    public Integer getThirdoil() {
+        return thirdoil;
+    }
+
+    public void setThirdoil(Integer thirdoil) {
+        this.thirdoil = thirdoil;
+    }
+
+    public Integer getFourthoil() {
+        return fourthoil;
+    }
+
+    public void setFourthoil(Integer fourthoil) {
+        this.fourthoil = fourthoil;
+    }
+
+    public Integer getSrcad0() {
+        return srcad0;
+    }
+
+    public void setSrcad0(Integer srcad0) {
+        this.srcad0 = srcad0;
+    }
+
+    public Integer getSrcad1() {
+        return srcad1;
+    }
+
+    public void setSrcad1(Integer srcad1) {
+        this.srcad1 = srcad1;
+    }
+
+    public Integer getSrcad2() {
+        return srcad2;
+    }
+
+    public void setSrcad2(Integer srcad2) {
+        this.srcad2 = srcad2;
+    }
+
+    public Integer getSrcad3() {
+        return srcad3;
+    }
+
+    public void setSrcad3(Integer srcad3) {
+        this.srcad3 = srcad3;
+    }
+
+    public Long getStatus() {
+        return status;
+    }
+
+    public void setStatus(Long status) {
+        this.status = status;
+    }
+
+    public String getStrstatus() {
+        return strstatus;
+    }
+
+    public void setStrstatus(String strstatus) {
+        this.strstatus = strstatus;
+    }
+
+    public String getStrstatusen() {
+        return strstatusen;
+    }
+
+    public void setStrstatusen(String strstatusen) {
+        this.strstatusen = strstatusen;
+    }
+
+    public Long getAlarm() {
+        return alarm;
+    }
+
+    public void setAlarm(Long alarm) {
+        this.alarm = alarm;
+    }
+
+    public String getStralarm() {
+        return stralarm;
+    }
+
+    public void setStralarm(String stralarm) {
+        this.stralarm = stralarm;
+    }
+
+    public String getStralarmsen() {
+        return stralarmsen;
+    }
+
+    public void setStralarmsen(String stralarmsen) {
+        this.stralarmsen = stralarmsen;
+    }
+
+    public Long getVideoalarm() {
+        return videoalarm;
+    }
+
+    public void setVideoalarm(Long videoalarm) {
+        this.videoalarm = videoalarm;
+    }
+
+    public String getStrvideoalarm() {
+        return strvideoalarm;
+    }
+
+    public void setStrvideoalarm(String strvideoalarm) {
+        this.strvideoalarm = strvideoalarm;
+    }
+
+    public String getStrvideoalarmen() {
+        return strvideoalarmen;
+    }
+
+    public void setStrvideoalarmen(String strvideoalarmen) {
+        this.strvideoalarmen = strvideoalarmen;
+    }
+
+    public Long getVideosignalloststatus() {
+        return videosignalloststatus;
+    }
+
+    public void setVideosignalloststatus(Long videosignalloststatus) {
+        this.videosignalloststatus = videosignalloststatus;
+    }
+
+    public Long getVideosignalcoverstatus() {
+        return videosignalcoverstatus;
+    }
+
+    public void setVideosignalcoverstatus(Long videosignalcoverstatus) {
+        this.videosignalcoverstatus = videosignalcoverstatus;
+    }
+
+    public Long getVideobehavior() {
+        return videobehavior;
+    }
+
+    public void setVideobehavior(Long videobehavior) {
+        this.videobehavior = videobehavior;
+    }
+
+    public Long getVideofatiguedegree() {
+        return videofatiguedegree;
+    }
+
+    public void setVideofatiguedegree(Long videofatiguedegree) {
+        this.videofatiguedegree = videofatiguedegree;
+    }
+
+    public String getGotsrc() {
+        return gotsrc;
+    }
+
+    public void setGotsrc(String gotsrc) {
+        this.gotsrc = gotsrc;
+    }
+
+    public Integer getRxlevel() {
+        return rxlevel;
+    }
+
+    public void setRxlevel(Integer rxlevel) {
+        this.rxlevel = rxlevel;
+    }
+
+    public Integer getGpsvalidnum() {
+        return gpsvalidnum;
+    }
+
+    public void setGpsvalidnum(Integer gpsvalidnum) {
+        this.gpsvalidnum = gpsvalidnum;
+    }
+
+    public Double getExvoltage() {
+        return exvoltage;
+    }
+
+    public void setExvoltage(Double exvoltage) {
+        this.exvoltage = exvoltage;
+    }
+
+    public Double getVoltagev() {
+        return voltagev;
+    }
+
+    public void setVoltagev(Double voltagev) {
+        this.voltagev = voltagev;
+    }
+
+    public Double getVoltagepercent() {
+        return voltagepercent;
+    }
+
+    public void setVoltagepercent(Double voltagepercent) {
+        this.voltagepercent = voltagepercent;
+    }
+
+    public Integer getMoving() {
+        return moving;
+    }
+
+    public void setMoving(Integer moving) {
+        this.moving = moving;
+    }
+
+    public Double getParklat() {
+        return parklat;
+    }
+
+    public void setParklat(Double parklat) {
+        this.parklat = parklat;
+    }
+
+    public Double getParklon() {
+        return parklon;
+    }
+
+    public void setParklon(Double parklon) {
+        this.parklon = parklon;
+    }
+
+    public Long getParktime() {
+        return parktime;
+    }
+
+    public void setParktime(Long parktime) {
+        this.parktime = parktime;
+    }
+
+    public Long getParkduration() {
+        return parkduration;
+    }
+
+    public void setParkduration(Long parkduration) {
+        this.parkduration = parkduration;
+    }
+
+    public Integer getTemp1() {
+        return temp1;
+    }
+
+    public void setTemp1(Integer temp1) {
+        this.temp1 = temp1;
+    }
+
+    public Integer getTemp2() {
+        return temp2;
+    }
+
+    public void setTemp2(Integer temp2) {
+        this.temp2 = temp2;
+    }
+
+    public Integer getTemp3() {
+        return temp3;
+    }
+
+    public void setTemp3(Integer temp3) {
+        this.temp3 = temp3;
+    }
+
+    public Integer getTemp4() {
+        return temp4;
+    }
+
+    public void setTemp4(Integer temp4) {
+        this.temp4 = temp4;
+    }
+
+    public Integer getHumi1() {
+        return humi1;
+    }
+
+    public void setHumi1(Integer humi1) {
+        this.humi1 = humi1;
+    }
+
+    public Integer getHumi2() {
+        return humi2;
+    }
+
+    public void setHumi2(Integer humi2) {
+        this.humi2 = humi2;
+    }
+
+    public Integer getIostatus() {
+        return iostatus;
+    }
+
+    public void setIostatus(Integer iostatus) {
+        this.iostatus = iostatus;
+    }
+
+    public Integer getCurrentoverspeedstate() {
+        return currentoverspeedstate;
+    }
+
+    public void setCurrentoverspeedstate(Integer currentoverspeedstate) {
+        this.currentoverspeedstate = currentoverspeedstate;
+    }
+
+    public Short getRotatestatus() {
+        return rotatestatus;
+    }
+
+    public void setRotatestatus(Short rotatestatus) {
+        this.rotatestatus = rotatestatus;
+    }
+
+    public Short getLoadstatus() {
+        return loadstatus;
+    }
+
+    public void setLoadstatus(Short loadstatus) {
+        this.loadstatus = loadstatus;
+    }
+
+    public Long getWeight() {
+        return weight;
+    }
+
+    public void setWeight(Long weight) {
+        this.weight = weight;
+    }
+
+    public Integer getSrcweightad0() {
+        return srcweightad0;
+    }
+
+    public void setSrcweightad0(Integer srcweightad0) {
+        this.srcweightad0 = srcweightad0;
+    }
+
+    public Short getReportmode() {
+        return reportmode;
+    }
+
+    public void setReportmode(Short reportmode) {
+        this.reportmode = reportmode;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java
new file mode 100644
index 0000000..383294b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java
@@ -0,0 +1,33 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * GPS璁惧鏈�鍚庝綅缃姹�
+ */
+public class GpsLastPositionRequest implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 璁惧搴忓垪鍙峰垪琛� */
+    private List<String> deviceids;
+
+    /** 涓婁竴娆℃煡璇綅缃椂闂� */
+    private Long lastquerypositiontime;
+
+    public List<String> getDeviceids() {
+        return deviceids;
+    }
+
+    public void setDeviceids(List<String> deviceids) {
+        this.deviceids = deviceids;
+    }
+
+    public Long getLastquerypositiontime() {
+        return lastquerypositiontime;
+    }
+
+    public void setLastquerypositiontime(Long lastquerypositiontime) {
+        this.lastquerypositiontime = lastquerypositiontime;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java
new file mode 100644
index 0000000..ca11e65
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java
@@ -0,0 +1,55 @@
+package com.ruoyi.system.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * GPS璁惧鏈�鍚庝綅缃搷搴�
+ */
+public class GpsLastPositionResponse implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 鐘舵�� */
+    private Integer status;
+
+    /** 鐘舵�佹弿杩� */
+    private String cause;
+
+    /** 褰撳墠鏌ヨ浣嶇疆鏃堕棿 */
+    private Long lastquerypositiontime;
+
+    /** 鏈�鍚庝綅缃垪琛� */
+    private List<GpsLastPosition> records;
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getCause() {
+        return cause;
+    }
+
+    public void setCause(String cause) {
+        this.cause = cause;
+    }
+
+    public Long getLastquerypositiontime() {
+        return lastquerypositiontime;
+    }
+
+    public void setLastquerypositiontime(Long lastquerypositiontime) {
+        this.lastquerypositiontime = lastquerypositiontime;
+    }
+
+    public List<GpsLastPosition> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<GpsLastPosition> records) {
+        this.records = records;
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java
index 55097cb..028e1ca 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java
@@ -21,6 +21,15 @@
     @JsonProperty("browser")
     private String browser;
 
+    @JsonProperty("domain")
+    private String domain;
+
+    public String getDomain() {
+        return domain;
+    }
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
     public String getUsername() {
         return username;
     }
@@ -54,6 +63,9 @@
     }
 
     public String getBrowser() {
+        if(browser == null){
+            browser="Chrome/104.0.0.0";
+        }
         return browser;
     }
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java
index 14c66b3..06df1d9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java
@@ -1,12 +1,18 @@
 package com.ruoyi.system.domain;
 
-import lombok.Data;
+import java.io.Serializable;
 
 /**
- * GPS鐧诲綍鍝嶅簲
+ * GPS鐧诲綍鍝嶅簲瀹炰綋绫�
  */
-@Data
-public class GpsLoginResponse {
+public class GpsLoginResponse implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐘舵�佺爜
+     */
+    private Integer status;
+
     /**
      * 鏄惁鎴愬姛
      */
@@ -21,4 +27,36 @@
      * Token
      */
     private String token;
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java
new file mode 100644
index 0000000..9073e84
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java
@@ -0,0 +1,127 @@
+package com.ruoyi.system.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+
+/**
+ * GPS閰嶇疆瀵硅薄 sys_gps_config
+ */
+public class SysGpsConfig extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 閰嶇疆ID */
+    private Long configId;
+
+    /** 閰嶇疆閿�� */
+    @Excel(name = "閰嶇疆閿��")
+    private String configKey;
+
+    /** 鏈嶅姟鍩熷悕 */
+    @Excel(name = "鏈嶅姟鍩熷悕")
+    private String domain;
+
+    /** 鐢ㄦ埛鍚� */
+    @Excel(name = "鐢ㄦ埛鍚�")
+    private String username;
+
+    /** 瀵嗙爜 */
+    @Excel(name = "瀵嗙爜")
+    private String password;
+
+    /** 璁块棶浠ょ墝 */
+    private String token;
+
+    /** 浠ょ墝杩囨湡鏃堕棿 */
+    private Date tokenExpireTime;
+
+    /** 鏈�鍚庢煡璇綅缃椂闂� */
+    @Excel(name = "鏈�鍚庢煡璇綅缃椂闂�")
+    private Long lastquerypositiontime;
+
+    public void setConfigId(Long configId) {
+        this.configId = configId;
+    }
+
+    public Long getConfigId() {
+        return configId;
+    }
+
+    public void setConfigKey(String configKey) {
+        this.configKey = configKey;
+    }
+
+    public String getConfigKey() {
+        return configKey;
+    }
+
+    public void setDomain(String domain) {
+        this.domain = domain;
+    }
+
+    public String getDomain() {
+        return domain;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setTokenExpireTime(Date tokenExpireTime) {
+        this.tokenExpireTime = tokenExpireTime;
+    }
+
+    public Date getTokenExpireTime() {
+        return tokenExpireTime;
+    }
+
+    public Long getLastquerypositiontime() {
+        return lastquerypositiontime;
+    }
+
+    public void setLastquerypositiontime(Long lastquerypositiontime) {
+        this.lastquerypositiontime = lastquerypositiontime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("configId", getConfigId())
+                .append("configKey", getConfigKey())
+                .append("domain", getDomain())
+                .append("username", getUsername())
+                .append("password", getPassword())
+                .append("token", getToken())
+                .append("tokenExpireTime", getTokenExpireTime())
+                .append("lastquerypositiontime", getLastquerypositiontime())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java
index 9f16903..b786ad2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java
@@ -18,6 +18,10 @@
     @Excel(name = "杞﹁締ID")
     private Long vehicleId;
 
+    /** 璁惧ID */
+    @Excel(name = "璁惧ID")
+    private String deviceId;
+
     /** 杞︾墝鍙� */
     @Excel(name = "杞︾墝鍙�")
     private String vehicleNo;
@@ -43,8 +47,16 @@
     private Double direction;
 
     /** 閲囬泦鏃堕棿 */
-    @Excel(name = "閲囬泦鏃堕棿", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "閲囬泦鏃堕棿")
     private String collectTime;
+
+    /** GPS涓婃姤璁惧鏃堕棿 */
+    @Excel(name = "GPS涓婃姤璁惧鏃堕棿")
+    private String deviceReportTime;
+
+    /** GPS骞冲彴澶勭悊鏃堕棿 */
+    @Excel(name = "GPS骞冲彴澶勭悊鏃堕棿")
+    private String platformProcessTime;
 
     public void setGpsId(Long gpsId) {
         this.gpsId = gpsId;
@@ -60,6 +72,14 @@
 
     public Long getVehicleId() {
         return vehicleId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
     }
 
     public void setVehicleNo(String vehicleNo) {
@@ -118,11 +138,28 @@
         return collectTime;
     }
 
+    public void setDeviceReportTime(String deviceReportTime) {
+        this.deviceReportTime = deviceReportTime;
+    }
+
+    public String getDeviceReportTime() {
+        return deviceReportTime;
+    }
+
+    public void setPlatformProcessTime(String platformProcessTime) {
+        this.platformProcessTime = platformProcessTime;
+    }
+
+    public String getPlatformProcessTime() {
+        return platformProcessTime;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                 .append("gpsId", getGpsId())
                 .append("vehicleId", getVehicleId())
+                .append("deviceId", getDeviceId())
                 .append("vehicleNo", getVehicleNo())
                 .append("longitude", getLongitude())
                 .append("latitude", getLatitude())
@@ -130,6 +167,8 @@
                 .append("speed", getSpeed())
                 .append("direction", getDirection())
                 .append("collectTime", getCollectTime())
+                .append("deviceReportTime", getDeviceReportTime())
+                .append("platformProcessTime", getPlatformProcessTime())
                 .append("createTime", getCreateTime())
                 .toString();
     }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
index 359b3c1..ad3a522 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java
@@ -14,6 +14,10 @@
     /** 杞﹁締ID */
     private Long vehicleId;
 
+    /** 璁惧ID */
+    @Excel(name = "璁惧ID")
+    private String deviceId;
+
     /** 杞︾墝鍙� */
     @Excel(name = "杞︾墝鍙�")
     private String vehicleNo;
@@ -40,6 +44,14 @@
 
     public Long getVehicleId() {
         return vehicleId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
     }
 
     public void setVehicleNo(String vehicleNo) {
@@ -86,6 +98,7 @@
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
                 .append("vehicleId", getVehicleId())
+                .append("deviceId", getDeviceId())
                 .append("vehicleNo", getVehicleNo())
                 .append("vehicleType", getVehicleType())
                 .append("vehicleBrand", getVehicleBrand())
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java
new file mode 100644
index 0000000..5887f2b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java
@@ -0,0 +1,65 @@
+package com.ruoyi.system.mapper;
+
+import com.ruoyi.system.domain.SysGpsConfig;
+import java.util.List;
+
+/**
+ * GPS閰嶇疆Mapper鎺ュ彛
+ */
+public interface SysGpsConfigMapper {
+    /**
+     * 鏌ヨGPS閰嶇疆
+     * 
+     * @param configId 閰嶇疆ID
+     * @return GPS閰嶇疆
+     */
+    public SysGpsConfig selectGpsConfigById(Long configId);
+
+    /**
+     * 鏌ヨGPS閰嶇疆鍒楄〃
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return GPS閰嶇疆闆嗗悎
+     */
+    public List<SysGpsConfig> selectGpsConfigList(SysGpsConfig gpsConfig);
+
+    /**
+     * 鏂板GPS閰嶇疆
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return 缁撴灉
+     */
+    public int insertGpsConfig(SysGpsConfig gpsConfig);
+
+    /**
+     * 淇敼GPS閰嶇疆
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return 缁撴灉
+     */
+    public int updateGpsConfig(SysGpsConfig gpsConfig);
+
+    /**
+     * 鍒犻櫎GPS閰嶇疆
+     * 
+     * @param configId 閰嶇疆ID
+     * @return 缁撴灉
+     */
+    public int deleteGpsConfigById(Long configId);
+
+    /**
+     * 鎵归噺鍒犻櫎GPS閰嶇疆
+     * 
+     * @param configIds 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteGpsConfigByIds(Long[] configIds);
+
+    /**
+     * 鏍规嵁key鏌ヨ閰嶇疆
+     * 
+     * @param configKey 閰嶇疆閿��
+     * @return GPS閰嶇疆
+     */
+    public SysGpsConfig selectGpsConfigByKey(String configKey);
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
index 8af5386..f688808 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java
@@ -9,31 +9,57 @@
 public interface VehicleInfoMapper {
     /**
      * 鏌ヨ杞﹁締淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 杞﹁締淇℃伅
      */
     public VehicleInfo selectVehicleInfoById(Long vehicleId);
 
     /**
+     * 閫氳繃杞︾墝鍙锋煡璇㈣溅杈嗕俊鎭�
+     * 
+     * @param plateNumber 杞︾墝鍙�
+     * @return 杞﹁締淇℃伅
+     */
+    public VehicleInfo selectVehicleInfoByPlateNumber(String plateNumber);
+
+    /**
      * 鏌ヨ杞﹁締淇℃伅鍒楄〃
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 杞﹁締淇℃伅闆嗗悎
      */
     public List<VehicleInfo> selectVehicleInfoList(VehicleInfo vehicleInfo);
 
     /**
      * 鏂板杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     public int insertVehicleInfo(VehicleInfo vehicleInfo);
 
     /**
      * 淇敼杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     public int updateVehicleInfo(VehicleInfo vehicleInfo);
 
     /**
      * 鍒犻櫎杞﹁締淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 缁撴灉
      */
     public int deleteVehicleInfoById(Long vehicleId);
 
     /**
      * 鎵归噺鍒犻櫎杞﹁締淇℃伅
+     * 
+     * @param vehicleIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
      */
     public int deleteVehicleInfoByIds(Long[] vehicleIds);
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java
index 33359e8..f89c320 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java
@@ -1,7 +1,6 @@
 package com.ruoyi.system.service;
 
-import com.ruoyi.system.domain.GpsLoginRequest;
-import com.ruoyi.system.domain.GpsLoginResponse;
+import com.ruoyi.system.domain.*;
 
 /**
  * GPS閲囬泦鏈嶅姟鎺ュ彛
@@ -13,4 +12,24 @@
      * @return 鐧诲綍鍝嶅簲
      */
     GpsLoginResponse login(GpsLoginRequest request);
+
+    /**
+     * 鑾峰彇璁惧鍒楄〃
+
+     * @return 璁惧鍒楄〃鍝嶅簲
+     */
+    GpsDeviceListResponse getDeviceList();
+
+    /**
+     * 鑾峰彇璁惧鏈�鍚庝綅缃�
+     */
+    GpsLastPositionResponse getLastPosition(GpsLastPositionRequest request);
+
+    /**
+     * 閫氳繃杞︾墝鍙锋煡璇㈣澶囧彿
+     * 
+     * @param plateNumber 杞︾墝鍙�
+     * @return 璁惧鍙凤紝濡傛灉鏈壘鍒板垯杩斿洖null
+     */
+    String getDeviceIdByPlateNumber(String plateNumber);
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java
new file mode 100644
index 0000000..ed52202
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java
@@ -0,0 +1,84 @@
+package com.ruoyi.system.service;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysGpsConfig;
+import java.util.Date;
+
+/**
+ * GPS閰嶇疆Service鎺ュ彛
+ */
+public interface IGpsConfigService {
+    /**
+     * 鏌ヨGPS閰嶇疆
+     * 
+     * @param configId GPS閰嶇疆涓婚敭
+     * @return GPS閰嶇疆
+     */
+    public SysGpsConfig selectGpsConfigById(Long configId);
+
+    /**
+     * 鏌ヨGPS閰嶇疆鍒楄〃
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return GPS閰嶇疆闆嗗悎
+     */
+    public List<SysGpsConfig> selectGpsConfigList(SysGpsConfig gpsConfig);
+
+    /**
+     * 鏂板GPS閰嶇疆
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return 缁撴灉
+     */
+    public int insertGpsConfig(SysGpsConfig gpsConfig);
+
+    /**
+     * 淇敼GPS閰嶇疆
+     * 
+     * @param gpsConfig GPS閰嶇疆
+     * @return 缁撴灉
+     */
+    public int updateGpsConfig(SysGpsConfig gpsConfig);
+
+    /**
+     * 鎵归噺鍒犻櫎GPS閰嶇疆
+     * 
+     * @param configIds 闇�瑕佸垹闄ょ殑GPS閰嶇疆涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteGpsConfigByIds(Long[] configIds);
+
+    /**
+     * 鍒犻櫎GPS閰嶇疆淇℃伅
+     * 
+     * @param configId GPS閰嶇疆涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteGpsConfigById(Long configId);
+
+    /**
+     * 鏍规嵁key鏌ヨ閰嶇疆
+     * 
+     * @param configKey 閰嶇疆閿��
+     * @return GPS閰嶇疆
+     */
+    public SysGpsConfig selectGpsConfigByKey(String configKey);
+
+    /**
+     * 鑾峰彇鏈夋晥鐨則oken
+     * 
+     * @param configKey 閰嶇疆閿��
+     * @return token
+     */
+    public String getValidToken(String configKey);
+
+    /**
+     * 鏇存柊token鍜屾湁鏁堟湡
+     * 
+     * @param configKey 閰嶇疆閿��
+     * @param token 鏂扮殑token
+     * @param expireTime token杩囨湡鏃堕棿
+     * @return 鏇存柊缁撴灉
+     */
+    public int updateToken(String configKey, String token, Date expireTime);
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
index d2f5927..49da046 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java
@@ -9,31 +9,57 @@
 public interface IVehicleInfoService {
     /**
      * 鏌ヨ杞﹁締淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 杞﹁締淇℃伅
      */
     public VehicleInfo selectVehicleInfoById(Long vehicleId);
 
     /**
+     * 閫氳繃杞︾墝鍙锋煡璇㈣溅杈嗕俊鎭�
+     * 
+     * @param plateNumber 杞︾墝鍙�
+     * @return 杞﹁締淇℃伅
+     */
+    public VehicleInfo selectVehicleInfoByPlateNumber(String plateNumber);
+
+    /**
      * 鏌ヨ杞﹁締淇℃伅鍒楄〃
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 杞﹁締淇℃伅闆嗗悎
      */
     public List<VehicleInfo> selectVehicleInfoList(VehicleInfo vehicleInfo);
 
     /**
      * 鏂板杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     public int insertVehicleInfo(VehicleInfo vehicleInfo);
 
     /**
      * 淇敼杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     public int updateVehicleInfo(VehicleInfo vehicleInfo);
 
     /**
      * 鎵归噺鍒犻櫎杞﹁締淇℃伅
+     * 
+     * @param vehicleIds 闇�瑕佸垹闄ょ殑杞﹁締淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
      */
     public int deleteVehicleInfoByIds(Long[] vehicleIds);
 
     /**
      * 鍒犻櫎杞﹁締淇℃伅淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 缁撴灉
      */
     public int deleteVehicleInfoById(Long vehicleId);
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java
index 9cc92ea..f456c36 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java
@@ -1,8 +1,7 @@
 package com.ruoyi.system.service.impl;
 
 import com.ruoyi.common.utils.http.HttpUtils;
-import com.ruoyi.system.domain.GpsLoginRequest;
-import com.ruoyi.system.domain.GpsLoginResponse;
+import com.ruoyi.system.domain.*;
 import com.ruoyi.system.service.IGpsCollectService;
 import com.ruoyi.system.config.GpsServiceConfig;
 import com.ruoyi.common.utils.MD5Util;
@@ -14,10 +13,19 @@
 import org.springframework.http.ResponseEntity;
 import java.util.HashMap;
 import java.util.Map;
-import org.springframework.util.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import com.ruoyi.common.utils.HttpUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.common.exception.ServiceException;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.ruoyi.system.service.IGpsConfigService;
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import com.ruoyi.common.utils.DateUtils;
+import java.util.Date;
+import com.ruoyi.system.service.IVehicleInfoService;
 
 /**
  * GPS閲囬泦鏈嶅姟瀹炵幇
@@ -27,98 +35,132 @@
 
     private final RestTemplate restTemplate;
     private final GpsServiceConfig gpsServiceConfig;
+    @Autowired
+    private IGpsConfigService gpsConfigService;
+
+    @Autowired
+    private IVehicleInfoService vehicleInfoService;
 
     public GpsCollectServiceImpl(GpsServiceConfig gpsServiceConfig) {
         this.restTemplate = new RestTemplate();
         this.gpsServiceConfig = gpsServiceConfig;
     }
 
+
+
     @Override
     public GpsLoginResponse login(GpsLoginRequest request) {
-        // 鍙傛暟鏍¢獙
-        if (StringUtils.isEmpty(request.getType()) || StringUtils.isEmpty(request.getFrom())) {
-            throw new ServiceException("鍙傛暟涓嶈兘涓虹┖");
-        }
-
         // 鏋勫缓璇锋眰URL
-        String url = gpsServiceConfig.getDomain() + "/webapi?action=login";
-        
-        // 璁剧疆璇锋眰鍙傛暟
-        Map<String, String> params = new HashMap<>();
-        params.put("username", gpsServiceConfig.getUsername());
-        params.put("password", MD5Util.md5(gpsServiceConfig.getPassword()));
-        params.put("type", request.getType());
-        params.put("from", request.getFrom());
-        params.put("browser", request.getBrowser());
+        String url = request.getDomain() + "/webapi?action=login";
 
-        StringBuilder paramStr = new StringBuilder();
-        for (Map.Entry<String, String> entry : params.entrySet()) {
-            if (paramStr.length() > 0) {
-                paramStr.append("&");
-            }
-            paramStr.append(entry.getKey()).append("=").append(entry.getValue());
-        }
-
-        // 鍙戦�佽姹�
-        String response = HttpUtil.post(url,params);
-        
-        // 瑙f瀽鍝嶅簲
-        GpsLoginResponse loginResponse = new GpsLoginResponse();
         try {
-            JSONObject jsonResponse = JSONObject.parseObject(response);
-            int status = jsonResponse.getIntValue("status");
-            String username = jsonResponse.getString("username");
+            // 璁剧疆璇锋眰鍙傛暟
+            Map<String, String> params = new HashMap<>();
+            params.put("username", request.getUsername());
+            params.put("password", MD5Util.md5(request.getPassword()));
+            params.put("type", request.getType());
+            params.put("from", request.getFrom());
+            params.put("browser", request.getBrowser());
+
+          
+            // 鍙戦�佽姹�
+            String result = HttpUtil.post(url, params);
+            JSONObject jsonResult = JSON.parseObject(result);
+
+            // 瑙f瀽鍝嶅簲
+            GpsLoginResponse response = new GpsLoginResponse();
+            int status = jsonResult.getInteger("status");
+            response.setStatus(status);
             
-            // 鏍规嵁杩斿洖鐮佽缃搷搴斾俊鎭�
+            // 鏍规嵁鐘舵�佺爜璁剧疆鍝嶅簲淇℃伅
             switch (status) {
                 case 0:
-                    loginResponse.setSuccess(true);
-                    loginResponse.setMessage("鐧诲綍鎴愬姛");
-                    loginResponse.setToken(jsonResponse.getString("token"));
+                    response.setSuccess(true);
+                    response.setMessage("鐧诲綍鎴愬姛");
+                    response.setToken(jsonResult.getString("token"));
                     break;
                 case -1:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("鐧诲綍澶辫触");
+                    response.setSuccess(false);
+                    response.setMessage("鐧诲綍澶辫触");
                     break;
                 case 1:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("瀵嗙爜閿欒");
+                    response.setSuccess(false);
+                    response.setMessage("瀵嗙爜閿欒");
                     break;
                 case 2:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("绂佹鐧诲綍");
+                    response.setSuccess(false);
+                    response.setMessage("绂佹鐧诲綍");
                     break;
                 case 3:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("璐﹀彿宸茬鐢�");
+                    response.setSuccess(false);
+                    response.setMessage("璐﹀彿宸茬鐢�");
                     break;
                 case 4:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("璁惧鍒版湡");
+                    response.setSuccess(false);
+                    response.setMessage("璁惧鍒版湡");
                     break;
                 case 5:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("璁惧杩囨湡");
+                    response.setSuccess(false);
+                    response.setMessage("璁惧杩囨湡");
                     break;
                 case 9903:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("Token杩囨湡");
+                    response.setSuccess(false);
+                    response.setMessage("Token杩囨湡");
                     break;
                 case 9906:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("璐﹀彿鍦ㄥ叾浠栧湴鏂圭櫥褰�");
+                    response.setSuccess(false);
+                    response.setMessage("璐﹀彿鍦ㄥ叾浠栧湴鏂圭櫥褰�");
                     break;
                 default:
-                    loginResponse.setSuccess(false);
-                    loginResponse.setMessage("鏈煡閿欒");
+                    response.setSuccess(false);
+                    response.setMessage("鏈煡閿欒");
                     break;
             }
+
+            return response;
         } catch (Exception e) {
-            loginResponse.setSuccess(false);
-            loginResponse.setMessage("瑙f瀽鍝嶅簲澶辫触锛�" + e.getMessage());
+            GpsLoginResponse response = new GpsLoginResponse();
+            response.setSuccess(false);
+            response.setStatus(-1);
+            response.setMessage("鐧诲綍澶辫触锛�" + e.getMessage());
+            return response;
         }
-        
-        return loginResponse;
+    }
+
+    /**
+     * 鑾峰彇鏈夋晥鐨則oken锛屽鏋渢oken鏃犳晥鍒欒嚜鍔ㄧ櫥褰�
+     */
+    private String getValidTokenWithAutoLogin() {
+        // 鑾峰彇褰撳墠token
+        String token = gpsConfigService.getValidToken("gps51");
+        if (token == null || token.isEmpty()) {
+            //璇诲彇gspconfig涓殑鍩熷悕锛岀敤鎴峰悕锛屽瘑鐮�
+            SysGpsConfig config = gpsConfigService.selectGpsConfigByKey("gps51");
+            if (config == null) {
+                return null;
+            }
+            String username = config.getUsername();
+            String password = config.getPassword();
+            String domain = config.getDomain();
+            // token鏃犳晥锛屽皾璇曠櫥褰�
+            GpsLoginRequest loginRequest = new GpsLoginRequest();
+            loginRequest.setType("USER");
+            loginRequest.setFrom("WEB");
+            loginRequest.setUsername(username);
+            loginRequest.setPassword(password);
+            loginRequest.setDomain(domain);
+            GpsLoginResponse loginResponse = login(loginRequest);
+            
+            if (loginResponse.isSuccess()) {
+                //灏唗oken鍐欏叆gspconfig
+                token = loginResponse.getToken();
+                //getTokenExpireTime 杩欎釜鏄病鏈夌殑 闇�瑕佽嚜宸辫绠楋紝褰撳墠鏃堕棿+23灏忔椂
+                Date expireTime = DateUtils.addHours(new Date(), 23);
+                gpsConfigService.updateToken("gps51", token, expireTime);
+                return token;
+            }
+        }
+        return token;
     }
 
     /**
@@ -141,4 +183,331 @@
         }
         return "USER".equals(type) || "DEVICE".equals(type);
     }
+
+    /**
+     * 鏇存柊杞﹁締璁惧ID
+     * 鏍规嵁璁惧鍒楄〃涓殑杞︾墝鍙锋洿鏂版垨鏂板杞﹁締淇℃伅
+     */
+    private void updateVehicleDeviceIds(GpsDeviceListResponse response) {
+        if (response.getStatus() != 0 || response.getGroups() == null) {
+            return;
+        }
+
+        // 閬嶅巻鎵�鏈夊垎缁勫拰璁惧
+        for (GpsGroup group : response.getGroups()) {
+            for (GpsDevice device : group.getDevices()) {
+                // 妫�鏌ヨ澶囧悕绉板拰澶囨敞涓槸鍚﹀寘鍚溅鐗屽彿
+                String deviceName = device.getDevicename();
+                String remark = device.getRemark();
+                String deviceId = device.getDeviceid();
+
+                if (StringUtils.isNotEmpty(deviceName) || StringUtils.isNotEmpty(remark)) {
+                    // 灏濊瘯浠庤澶囧悕绉板拰澶囨敞涓彁鍙栬溅鐗屽彿
+                    String plateNumber = extractPlateNumber(deviceName, remark);
+                    if (StringUtils.isNotEmpty(plateNumber)) {
+                        // 鏌ヨ杞﹁締淇℃伅
+                        VehicleInfo vehicleInfo = vehicleInfoService.selectVehicleInfoByPlateNumber(plateNumber);
+                        if (vehicleInfo != null) {
+                            // 鏇存柊鐜版湁杞﹁締鐨勮澶嘔D
+                            vehicleInfo.setDeviceId(deviceId);
+                            vehicleInfoService.updateVehicleInfo(vehicleInfo);
+                        } else {
+                            // 鍒涘缓鏂扮殑杞﹁締淇℃伅
+                            VehicleInfo newVehicle = new VehicleInfo();
+                            newVehicle.setVehicleNo(plateNumber);
+                            newVehicle.setDeviceId(deviceId);
+                            newVehicle.setStatus("0"); // 姝e父鐘舵��
+                            vehicleInfoService.insertVehicleInfo(newVehicle);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 浠庤澶囧悕绉板拰澶囨敞涓彁鍙栬溅鐗屽彿
+     */
+    private String extractPlateNumber(String deviceName, String remark) {
+        // 杩欓噷鍙互鏍规嵁瀹為檯鎯呭喌瀹炵幇杞︾墝鍙锋彁鍙栭�昏緫
+        // 渚嬪锛氫粠瀛楃涓蹭腑鍖归厤杞︾墝鍙锋牸寮�
+        if (StringUtils.isNotEmpty(deviceName)) {
+            return deviceName;
+        }
+        if (StringUtils.isNotEmpty(remark)) {
+            return remark;
+        }
+        return null;
+    }
+
+    @Override
+    public GpsDeviceListResponse getDeviceList() {
+        // 鑾峰彇GPS閰嶇疆淇℃伅
+        SysGpsConfig config = gpsConfigService.selectGpsConfigByKey("gps51");
+        if (config == null) {
+            GpsDeviceListResponse response = new GpsDeviceListResponse();
+            response.setStatus(-1);
+            response.setCause("鏈壘鍒癎PS閰嶇疆淇℃伅");
+            return response;
+        }
+
+        // 鑾峰彇鏈夋晥鐨則oken锛屽鏋滄棤鏁堝垯鑷姩鐧诲綍
+        String token = getValidTokenWithAutoLogin();
+        if (token == null) {
+            GpsDeviceListResponse response = new GpsDeviceListResponse();
+            response.setStatus(-1);
+            response.setCause("鑾峰彇token澶辫触");
+            return response;
+        }
+        
+        String username = config.getUsername();
+        // 鏋勫缓璇锋眰URL
+        String url = config.getDomain() + "/webapi?action=querymonitorlist&token=" + token;
+        Map<String, String> params = new HashMap<>();
+        params.put("username", username);
+        
+
+        try {
+
+            // 鍙戦�丠TTP璇锋眰
+            String result = HttpUtil.post(url, params);
+            JSONObject jsonResult = JSON.parseObject(result);
+
+            // 瑙f瀽鍝嶅簲
+            GpsDeviceListResponse response = new GpsDeviceListResponse();
+            response.setStatus(jsonResult.getInteger("status"));
+            response.setCause(jsonResult.getString("cause"));
+
+            if (response.getStatus() == 0) {
+                // 瑙f瀽鍒嗙粍鍒楄〃
+                JSONArray groupsArray = jsonResult.getJSONArray("groups");
+                List<GpsGroup> groups = new ArrayList<>();
+                
+                for (int i = 0; i < groupsArray.size(); i++) {
+                    JSONObject groupJson = groupsArray.getJSONObject(i);
+                    GpsGroup group = new GpsGroup();
+                    group.setGroupid(groupJson.getInteger("groupid"));
+                    group.setGroupname(groupJson.getString("groupname"));
+                    group.setRemark(groupJson.getString("remark"));
+
+                    // 瑙f瀽璁惧鍒楄〃
+                    JSONArray devicesArray = groupJson.getJSONArray("devices");
+                    List<GpsDevice> devices = new ArrayList<>();
+                    
+                    for (int j = 0; j < devicesArray.size(); j++) {
+                        JSONObject deviceJson = devicesArray.getJSONObject(j);
+                        GpsDevice device = new GpsDevice();
+                        device.setDeviceid(deviceJson.getString("deviceid"));
+                        device.setDevicename(deviceJson.getString("devicename"));
+                        device.setDevicetype(deviceJson.getInteger("devicetype"));
+                        device.setSimnum(deviceJson.getString("simnum"));
+                        device.setOverduetime(deviceJson.getLong("overduetime"));
+                        device.setExpirenotifytime(deviceJson.getLong("expirenotifytime"));
+                        device.setRemark(deviceJson.getString("remark"));
+                        device.setCreater(deviceJson.getString("creater"));
+                        device.setVideochannelcount(deviceJson.getInteger("videochannelcount"));
+                        device.setLastactivetime(deviceJson.getLong("lastactivetime"));
+                        device.setIsfree(deviceJson.getInteger("isfree"));
+                        device.setAllowedit(deviceJson.getInteger("allowedit"));
+                        device.setIcon(deviceJson.getInteger("icon"));
+                        device.setStared(deviceJson.getInteger("stared"));
+                        device.setLoginname(deviceJson.getString("loginname"));
+                        
+                        devices.add(device);
+                    }
+                    
+                    group.setDevices(devices);
+                    groups.add(group);
+                }
+                
+                response.setGroups(groups);
+
+               
+            }
+
+            return response;
+        } catch (Exception e) {
+            GpsDeviceListResponse response = new GpsDeviceListResponse();
+            response.setStatus(-1);
+            response.setCause("璇锋眰璁惧鍒楄〃澶辫触锛�" + e.getMessage());
+            return response;
+        }
+    }
+
+    @Override
+    public GpsLastPositionResponse getLastPosition(GpsLastPositionRequest request) {
+        // 鑾峰彇GPS閰嶇疆淇℃伅
+        SysGpsConfig config = gpsConfigService.selectGpsConfigByKey("gps51");
+        if (config == null) {
+            GpsLastPositionResponse response = new GpsLastPositionResponse();
+            response.setStatus(-1);
+            response.setCause("鏈壘鍒癎PS閰嶇疆淇℃伅");
+            return response;
+        }
+
+        // 鑾峰彇鏈夋晥鐨則oken锛屽鏋滄棤鏁堝垯鑷姩鐧诲綍
+        String token = getValidTokenWithAutoLogin();
+        if (token == null) {
+            GpsLastPositionResponse response = new GpsLastPositionResponse();
+            response.setStatus(-1);
+            response.setCause("鑾峰彇token澶辫触");
+            return response;
+        }
+
+        // 鏋勫缓璇锋眰URL
+        String url = config.getDomain() + "/webapi?action=lastposition&token="+token;
+        
+        // 鏋勫缓璇锋眰鍙傛暟
+        Map<String, String> params = new HashMap<>();
+            
+        
+        // 浣跨敤閰嶇疆涓殑lastquerypositiontime浣滀负鏌ヨ鏃堕棿
+        Long lastQueryTime = config.getLastquerypositiontime();
+        if (lastQueryTime == null) {
+            lastQueryTime = 0L; // 濡傛灉浠庢湭鏌ヨ杩囷紝鍒欎粠0寮�濮�
+        }
+        params.put("lastquerypositiontime", String.valueOf(lastQueryTime));
+        
+        // 娣诲姞璁惧ID鍒楄〃
+        if (request.getDeviceids() != null && !request.getDeviceids().isEmpty()) {
+            params.put("deviceids", JSON.toJSONString(request.getDeviceids()));
+        }
+
+        try {
+            
+
+            // 鍙戦�丠TTP璇锋眰
+            String result = HttpUtil.post(url, params);
+            JSONObject jsonResult = JSON.parseObject(result);
+
+            // 瑙f瀽鍝嶅簲
+            GpsLastPositionResponse response = new GpsLastPositionResponse();
+            response.setStatus(jsonResult.getInteger("status"));
+            response.setCause(jsonResult.getString("cause"));
+            
+            // 鑾峰彇鏂扮殑lastquerypositiontime
+            Long newLastQueryTime = jsonResult.getLong("lastquerypositiontime");
+            response.setLastquerypositiontime(newLastQueryTime);
+
+            // 濡傛灉璇锋眰鎴愬姛锛屾洿鏂伴厤缃腑鐨刲astquerypositiontime
+            if (response.getStatus() == 0 && newLastQueryTime != null) {
+                config.setLastquerypositiontime(newLastQueryTime);
+                gpsConfigService.updateGpsConfig(config);
+            }
+
+            if (response.getStatus() == 0) {
+                // 瑙f瀽浣嶇疆璁板綍鍒楄〃
+                JSONArray recordsArray = jsonResult.getJSONArray("records");
+                List<GpsLastPosition> records = new ArrayList<>();
+                
+                for (int i = 0; i < recordsArray.size(); i++) {
+                    JSONObject recordJson = recordsArray.getJSONObject(i);
+                    GpsLastPosition record = new GpsLastPosition();
+                    record.setDeviceid(recordJson.getString("deviceid"));
+                    record.setDevicetime(recordJson.getLong("devicetime"));
+                    record.setArrivedtime(recordJson.getLong("arrivedtime"));
+                    record.setUpdatetime(recordJson.getLong("updatetime"));
+                    record.setValidpoistiontime(recordJson.getLong("validpoistiontime"));
+                    record.setCallat(recordJson.getDouble("callat"));
+                    record.setCallon(recordJson.getDouble("callon"));
+                    record.setAltitude(recordJson.getDouble("altitude"));
+                    record.setRadius(recordJson.getInteger("radius"));
+                    record.setSpeed(recordJson.getDouble("speed"));
+                    record.setCourse(recordJson.getInteger("course"));
+                    record.setTotaldistance(recordJson.getInteger("totaldistance"));
+                    record.setTotaloil(recordJson.getInteger("totaloil"));
+                    record.setTotalnotrunningad(recordJson.getInteger("totalnotrunningad"));
+                    record.setMasteroil(recordJson.getInteger("masteroil"));
+                    record.setAuxoil(recordJson.getInteger("auxoil"));
+                    record.setThirdoil(recordJson.getInteger("thirdoil"));
+                    record.setFourthoil(recordJson.getInteger("fourthoil"));
+                    record.setSrcad0(recordJson.getInteger("srcad0"));
+                    record.setSrcad1(recordJson.getInteger("srcad1"));
+                    record.setSrcad2(recordJson.getInteger("srcad2"));
+                    record.setSrcad3(recordJson.getInteger("srcad3"));
+                    record.setStatus(recordJson.getLong("status"));
+                    record.setStrstatus(recordJson.getString("strstatus"));
+                    record.setStrstatusen(recordJson.getString("strstatusen"));
+                    record.setAlarm(recordJson.getLong("alarm"));
+                    record.setStralarm(recordJson.getString("stralarm"));
+                    record.setStralarmsen(recordJson.getString("stralarmsen"));
+                    record.setVideoalarm(recordJson.getLong("videoalarm"));
+                    record.setStrvideoalarm(recordJson.getString("strvideoalarm"));
+                    record.setStrvideoalarmen(recordJson.getString("strvideoalarmen"));
+                    record.setVideosignalloststatus(recordJson.getLong("videosignalloststatus"));
+                    record.setVideosignalcoverstatus(recordJson.getLong("videosignalcoverstatus"));
+                    record.setVideobehavior(recordJson.getLong("videobehavior"));
+                    record.setVideofatiguedegree(recordJson.getLong("videofatiguedegree"));
+                    record.setGotsrc(recordJson.getString("gotsrc"));
+                    record.setRxlevel(recordJson.getInteger("rxlevel"));
+                    record.setGpsvalidnum(recordJson.getInteger("gpsvalidnum"));
+                    record.setExvoltage(recordJson.getDouble("exvoltage"));
+                    record.setVoltagev(recordJson.getDouble("voltagev"));
+                    record.setVoltagepercent(recordJson.getDouble("voltagepercent"));
+                    record.setMoving(recordJson.getInteger("moving"));
+                    record.setParklat(recordJson.getDouble("parklat"));
+                    record.setParklon(recordJson.getDouble("parklon"));
+                    record.setParktime(recordJson.getLong("parktime"));
+                    record.setParkduration(recordJson.getLong("parkduration"));
+                    record.setTemp1(recordJson.getInteger("temp1"));
+                    record.setTemp2(recordJson.getInteger("temp2"));
+                    record.setTemp3(recordJson.getInteger("temp3"));
+                    record.setTemp4(recordJson.getInteger("temp4"));
+                    record.setHumi1(recordJson.getInteger("humi1"));
+                    record.setHumi2(recordJson.getInteger("humi2"));
+                    record.setIostatus(recordJson.getInteger("iostatus"));
+                    record.setCurrentoverspeedstate(recordJson.getInteger("currentoverspeedstate"));
+                    record.setRotatestatus(recordJson.getShort("rotatestatus"));
+                    record.setLoadstatus(recordJson.getShort("loadstatus"));
+                    record.setWeight(recordJson.getLong("weight"));
+                    record.setSrcweightad0(recordJson.getInteger("srcweightad0"));
+                    record.setReportmode(recordJson.getShort("reportmode"));
+                    
+                    records.add(record);
+                }
+                
+                response.setRecords(records);
+            }
+
+            return response;
+        } catch (Exception e) {
+            GpsLastPositionResponse response = new GpsLastPositionResponse();
+            response.setStatus(-1);
+            response.setCause("璇锋眰璁惧鏈�鍚庝綅缃け璐ワ細" + e.getMessage());
+            return response;
+        }
+    }
+
+    @Override
+    public String getDeviceIdByPlateNumber(String plateNumber) {
+        if (StringUtils.isEmpty(plateNumber)) {
+            return null;
+        }
+
+        try {
+            // 鑾峰彇璁惧鍒楄〃
+            GpsDeviceListResponse response = getDeviceList();
+            if (response.getStatus() != 0) {
+                return null;
+            }
+
+            // 閬嶅巻鎵�鏈夊垎缁勫拰璁惧
+            for (GpsGroup group : response.getGroups()) {
+                for (GpsDevice device : group.getDevices()) {
+                    // 妫�鏌ヨ澶囧娉ㄤ腑鏄惁鍖呭惈杞︾墝鍙�
+                    if (device.getDevicename() != null && device.getDevicename().contains(plateNumber)) {
+                        return device.getDeviceid();
+                    }
+                    if(device.getRemark()!=null && device.getRemark().contains(plateNumber)){
+                        return device.getDeviceid();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            // 璁板綍閿欒鏃ュ織
+            System.err.println("閫氳繃杞︾墝鍙锋煡璇㈣澶囧彿澶辫触锛�" + e.getMessage());
+        }
+
+        return null;
+    }
 } 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java
new file mode 100644
index 0000000..f5c2f16
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java
@@ -0,0 +1,89 @@
+package com.ruoyi.system.service.impl;
+
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.system.domain.SysGpsConfig;
+import com.ruoyi.system.mapper.SysGpsConfigMapper;
+import com.ruoyi.system.service.IGpsConfigService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * GPS閰嶇疆鏈嶅姟瀹炵幇绫�
+ */
+@Service
+public class GpsConfigServiceImpl implements IGpsConfigService {
+    @Autowired
+    private SysGpsConfigMapper gpsConfigMapper;
+
+    @Override
+    public SysGpsConfig selectGpsConfigById(Long configId) {
+        return gpsConfigMapper.selectGpsConfigById(configId);
+    }
+
+    @Override
+    public List<SysGpsConfig> selectGpsConfigList(SysGpsConfig gpsConfig) {
+        return gpsConfigMapper.selectGpsConfigList(gpsConfig);
+    }
+
+    @Override
+    @Transactional
+    public int insertGpsConfig(SysGpsConfig gpsConfig) {
+        gpsConfig.setCreateTime(DateUtils.getNowDate());
+        gpsConfig.setUpdateTime(DateUtils.getNowDate());
+        return gpsConfigMapper.insertGpsConfig(gpsConfig);
+    }
+
+    @Override
+    @Transactional
+    public int updateGpsConfig(SysGpsConfig gpsConfig) {
+        gpsConfig.setUpdateTime(DateUtils.getNowDate());
+        return gpsConfigMapper.updateGpsConfig(gpsConfig);
+    }
+
+    @Override
+    @Transactional
+    public int deleteGpsConfigByIds(Long[] configIds) {
+        return gpsConfigMapper.deleteGpsConfigByIds(configIds);
+    }
+
+    @Override
+    @Transactional
+    public int deleteGpsConfigById(Long configId) {
+        return gpsConfigMapper.deleteGpsConfigById(configId);
+    }
+
+    @Override
+    public SysGpsConfig selectGpsConfigByKey(String configKey) {
+        return gpsConfigMapper.selectGpsConfigByKey(configKey);
+    }
+
+    @Override
+    public String getValidToken(String configKey) {
+        SysGpsConfig config = selectGpsConfigByKey(configKey);
+        if (config == null) {
+            return null;
+        }
+        
+        // 妫�鏌oken鏄惁鏈夋晥锛堟湭杩囨湡锛�
+        if (config.getTokenExpireTime() != null && config.getTokenExpireTime().after(new Date())) {
+            return config.getToken();
+        }
+        
+        return null;
+    }
+
+    @Override
+    public int updateToken(String configKey, String token, Date expireTime) {
+        SysGpsConfig config = new SysGpsConfig();
+        config.setConfigKey(configKey);
+        config.setToken(token);
+        config.setTokenExpireTime(expireTime);
+        config.setUpdateTime(new Date());
+        
+        return gpsConfigMapper.updateGpsConfig(config);
+    }
+} 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
index 7dcfb56..8697cbe 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
@@ -38,11 +38,7 @@
     @Override
     public int insertVehicleGps(VehicleGps vehicleGps) {
         // 鏍规嵁杞︾墝鍙疯幏鍙栬溅杈咺D
-        Long vehicleId = vehicleGpsMapper.getVehicleIdByNo(vehicleGps.getVehicleNo());
-        if (vehicleId == null) {
-            throw new ServiceException("鏈壘鍒板搴旂殑杞﹁締淇℃伅");
-        }
-        vehicleGps.setVehicleId(vehicleId);
+       ;
         return vehicleGpsMapper.insertVehicleGps(vehicleGps);
     }
 
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
index c40b283..42a8c82 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java
@@ -17,6 +17,9 @@
 
     /**
      * 鏌ヨ杞﹁締淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 杞﹁締淇℃伅
      */
     @Override
     public VehicleInfo selectVehicleInfoById(Long vehicleId) {
@@ -24,7 +27,21 @@
     }
 
     /**
+     * 閫氳繃杞︾墝鍙锋煡璇㈣溅杈嗕俊鎭�
+     * 
+     * @param plateNumber 杞︾墝鍙�
+     * @return 杞﹁締淇℃伅
+     */
+    @Override
+    public VehicleInfo selectVehicleInfoByPlateNumber(String plateNumber) {
+        return vehicleInfoMapper.selectVehicleInfoByPlateNumber(plateNumber);
+    }
+
+    /**
      * 鏌ヨ杞﹁締淇℃伅鍒楄〃
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 杞﹁締淇℃伅
      */
     @Override
     public List<VehicleInfo> selectVehicleInfoList(VehicleInfo vehicleInfo) {
@@ -33,6 +50,9 @@
 
     /**
      * 鏂板杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     @Override
     public int insertVehicleInfo(VehicleInfo vehicleInfo) {
@@ -41,6 +61,9 @@
 
     /**
      * 淇敼杞﹁締淇℃伅
+     * 
+     * @param vehicleInfo 杞﹁締淇℃伅
+     * @return 缁撴灉
      */
     @Override
     public int updateVehicleInfo(VehicleInfo vehicleInfo) {
@@ -49,6 +72,9 @@
 
     /**
      * 鎵归噺鍒犻櫎杞﹁締淇℃伅
+     * 
+     * @param vehicleIds 闇�瑕佸垹闄ょ殑杞﹁締淇℃伅涓婚敭
+     * @return 缁撴灉
      */
     @Override
     public int deleteVehicleInfoByIds(Long[] vehicleIds) {
@@ -57,6 +83,9 @@
 
     /**
      * 鍒犻櫎杞﹁締淇℃伅淇℃伅
+     * 
+     * @param vehicleId 杞﹁締淇℃伅涓婚敭
+     * @return 缁撴灉
      */
     @Override
     public int deleteVehicleInfoById(Long vehicleId) {
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml
new file mode 100644
index 0000000..f6568c6
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml
@@ -0,0 +1,105 @@
+<?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.SysGpsConfigMapper">
+    
+    <resultMap type="SysGpsConfig" id="SysGpsConfigResult">
+        <result property="configId"    column="config_id"    />
+        <result property="configKey"   column="config_key"   />
+        <result property="domain"      column="domain"       />
+        <result property="username"    column="username"     />
+        <result property="password"    column="password"     />
+        <result property="token"       column="token"        />
+        <result property="tokenExpireTime" column="token_expire_time" />
+        <result property="lastquerypositiontime" column="lastquerypositiontime" />
+        <result property="createBy"    column="create_by"    />
+        <result property="createTime"  column="create_time"  />
+        <result property="updateBy"    column="update_by"    />
+        <result property="updateTime"  column="update_time"  />
+        <result property="remark"      column="remark"       />
+    </resultMap>
+
+    <sql id="selectSysGpsConfigVo">
+        select config_id, config_key, domain, username, password, token, token_expire_time, lastquerypositiontime, create_by, create_time, update_by, update_time, remark
+        from sys_gps_config
+    </sql>
+
+    <select id="selectGpsConfigList" parameterType="SysGpsConfig" resultMap="SysGpsConfigResult">
+        <include refid="selectSysGpsConfigVo"/>
+        <where>  
+            <if test="configKey != null  and configKey != ''"> and config_key = #{configKey}</if>
+            <if test="domain != null  and domain != ''"> and domain like concat('%', #{domain}, '%')</if>
+            <if test="username != null  and username != ''"> and username like concat('%', #{username}, '%')</if>
+        </where>
+    </select>
+    
+    <select id="selectGpsConfigById" parameterType="Long" resultMap="SysGpsConfigResult">
+        <include refid="selectSysGpsConfigVo"/>
+        where config_id = #{configId}
+    </select>
+    
+    <select id="selectGpsConfigByKey" parameterType="String" resultMap="SysGpsConfigResult">
+        <include refid="selectSysGpsConfigVo"/>
+        where config_key = #{configKey}
+    </select>
+        
+    <insert id="insertGpsConfig" parameterType="SysGpsConfig" useGeneratedKeys="true" keyProperty="configId">
+        insert into sys_gps_config
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="configKey != null">config_key,</if>
+            <if test="domain != null">domain,</if>
+            <if test="username != null">username,</if>
+            <if test="password != null">password,</if>
+            <if test="token != null">token,</if>
+            <if test="tokenExpireTime != null">token_expire_time,</if>
+            <if test="lastquerypositiontime != null">lastquerypositiontime,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="remark != null">remark,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="configKey != null">#{configKey},</if>
+            <if test="domain != null">#{domain},</if>
+            <if test="username != null">#{username},</if>
+            <if test="password != null">#{password},</if>
+            <if test="token != null">#{token},</if>
+            <if test="tokenExpireTime != null">#{tokenExpireTime},</if>
+            <if test="lastquerypositiontime != null">#{lastquerypositiontime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{remark},</if>
+         </trim>
+    </insert>
+
+    <update id="updateGpsConfig" parameterType="SysGpsConfig">
+        update sys_gps_config
+        <set>
+            <if test="configKey != null and configKey != ''">config_key = #{configKey},</if>
+            <if test="domain != null and domain != ''">domain = #{domain},</if>
+            <if test="username != null and username != ''">username = #{username},</if>
+            <if test="password != null and password != ''">password = #{password},</if>
+            <if test="token != null and token != ''">token = #{token},</if>
+            <if test="tokenExpireTime != null">token_expire_time = #{tokenExpireTime},</if>
+            <if test="lastquerypositiontime != null">lastquerypositiontime = #{lastquerypositiontime},</if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+            update_time = sysdate()
+        </set>
+        where config_key = #{configKey}
+    </update>
+
+    <delete id="deleteGpsConfigById" parameterType="Long">
+        delete from sys_gps_config where config_id = #{configId}
+    </delete>
+
+    <delete id="deleteGpsConfigByIds" parameterType="String">
+        delete from sys_gps_config where config_id in 
+        <foreach item="configId" collection="array" open="(" separator="," close=")">
+            #{configId}
+        </foreach>
+    </delete>
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
index e899130..e4c2477 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml
@@ -7,6 +7,7 @@
     <resultMap type="VehicleGps" id="VehicleGpsResult">
         <result property="gpsId"    column="gps_id"    />
         <result property="vehicleId"    column="vehicle_id"    />
+        <result property="deviceId"    column="device_id"    />
         <result property="vehicleNo"    column="vehicle_no"    />
         <result property="longitude"    column="longitude"    />
         <result property="latitude"    column="latitude"    />
@@ -14,11 +15,14 @@
         <result property="speed"    column="speed"    />
         <result property="direction"    column="direction"    />
         <result property="collectTime"    column="collect_time"    />
+        <result property="deviceReportTime"    column="device_report_time"    />
+        <result property="platformProcessTime"    column="platform_process_time"    />
         <result property="createTime"    column="create_time"    />
     </resultMap>
 
     <sql id="selectVehicleGpsVo">
-        select g.gps_id, g.vehicle_id, v.vehicle_no, g.longitude, g.latitude, g.altitude, g.speed, g.direction, g.collect_time, g.create_time 
+        select g.gps_id, g.vehicle_id, g.device_id, v.vehicle_no, g.longitude, g.latitude, g.altitude, g.speed, g.direction, 
+        g.collect_time, g.device_report_time, g.platform_process_time, g.create_time
         from tb_vehicle_gps g
         left join tb_vehicle_info v on g.vehicle_id = v.vehicle_id
     </sql>
@@ -46,22 +50,28 @@
         insert into tb_vehicle_gps
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="vehicleId != null">vehicle_id,</if>
+            <if test="deviceId != null">device_id,</if>
             <if test="longitude != null">longitude,</if>
             <if test="latitude != null">latitude,</if>
             <if test="altitude != null">altitude,</if>
             <if test="speed != null">speed,</if>
             <if test="direction != null">direction,</if>
             <if test="collectTime != null">collect_time,</if>
+            <if test="deviceReportTime != null">device_report_time,</if>
+            <if test="platformProcessTime != null">platform_process_time,</if>
             <if test="createTime != null">create_time,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="vehicleId != null">#{vehicleId},</if>
+            <if test="deviceId != null">#{deviceId},</if>
             <if test="longitude != null">#{longitude},</if>
             <if test="latitude != null">#{latitude},</if>
             <if test="altitude != null">#{altitude},</if>
             <if test="speed != null">#{speed},</if>
             <if test="direction != null">#{direction},</if>
             <if test="collectTime != null">#{collectTime},</if>
+            <if test="deviceReportTime != null">#{deviceReportTime},</if>
+            <if test="platformProcessTime != null">#{platformProcessTime},</if>
             <if test="createTime != null">#{createTime},</if>
          </trim>
     </insert>
diff --git a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
index 844a0f5..fada6a4 100644
--- a/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml
@@ -6,26 +6,29 @@
     
     <resultMap type="VehicleInfo" id="VehicleInfoResult">
         <result property="vehicleId"    column="vehicle_id"    />
+        <result property="deviceId"     column="device_id"     />
         <result property="vehicleNo"    column="vehicle_no"    />
-        <result property="vehicleType"    column="vehicle_type"    />
-        <result property="vehicleBrand"    column="vehicle_brand"    />
-        <result property="vehicleModel"    column="vehicle_model"    />
-        <result property="status"    column="status"    />
-        <result property="createBy"    column="create_by"    />
-        <result property="createTime"    column="create_time"    />
-        <result property="updateBy"    column="update_by"    />
-        <result property="updateTime"    column="update_time"    />
-        <result property="remark"    column="remark"    />
+        <result property="vehicleType"  column="vehicle_type"  />
+        <result property="vehicleBrand" column="vehicle_brand" />
+        <result property="vehicleModel" column="vehicle_model" />
+        <result property="status"       column="status"        />
+        <result property="createBy"     column="create_by"     />
+        <result property="createTime"   column="create_time"   />
+        <result property="updateBy"     column="update_by"     />
+        <result property="updateTime"   column="update_time"   />
+        <result property="remark"       column="remark"        />
     </resultMap>
 
     <sql id="selectVehicleInfoVo">
-        select vehicle_id, vehicle_no, vehicle_type, vehicle_brand, vehicle_model, status, create_by, create_time, update_by, update_time, remark from tb_vehicle_info
+        select vehicle_id, device_id, vehicle_no, vehicle_type, vehicle_brand, vehicle_model, status, create_by, create_time, update_by, update_time, remark
+        from tb_vehicle_info
     </sql>
 
     <select id="selectVehicleInfoList" parameterType="VehicleInfo" resultMap="VehicleInfoResult">
         <include refid="selectVehicleInfoVo"/>
         <where>  
-            <if test="vehicleNo != null  and vehicleNo != ''"> and vehicle_no like concat('%', #{vehicleNo}, '%')</if>
+            <if test="vehicleNo != null  and vehicleNo != ''"> and vehicle_no = #{vehicleNo}</if>
+            <if test="deviceId != null  and deviceId != ''"> and device_id = #{deviceId}</if>
             <if test="vehicleType != null  and vehicleType != ''"> and vehicle_type = #{vehicleType}</if>
             <if test="vehicleBrand != null  and vehicleBrand != ''"> and vehicle_brand = #{vehicleBrand}</if>
             <if test="vehicleModel != null  and vehicleModel != ''"> and vehicle_model = #{vehicleModel}</if>
@@ -37,10 +40,16 @@
         <include refid="selectVehicleInfoVo"/>
         where vehicle_id = #{vehicleId}
     </select>
+
+    <select id="selectVehicleInfoByPlateNumber" parameterType="String" resultMap="VehicleInfoResult">
+        <include refid="selectVehicleInfoVo"/>
+        where vehicle_no = #{plateNumber}
+    </select>
         
     <insert id="insertVehicleInfo" parameterType="VehicleInfo" useGeneratedKeys="true" keyProperty="vehicleId">
         insert into tb_vehicle_info
         <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="deviceId != null">device_id,</if>
             <if test="vehicleNo != null">vehicle_no,</if>
             <if test="vehicleType != null">vehicle_type,</if>
             <if test="vehicleBrand != null">vehicle_brand,</if>
@@ -53,6 +62,7 @@
             <if test="remark != null">remark,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="deviceId != null">#{deviceId},</if>
             <if test="vehicleNo != null">#{vehicleNo},</if>
             <if test="vehicleType != null">#{vehicleType},</if>
             <if test="vehicleBrand != null">#{vehicleBrand},</if>
@@ -69,16 +79,14 @@
     <update id="updateVehicleInfo" parameterType="VehicleInfo">
         update tb_vehicle_info
         <trim prefix="SET" suffixOverrides=",">
+            <if test="deviceId != null">device_id = #{deviceId},</if>
             <if test="vehicleNo != null">vehicle_no = #{vehicleNo},</if>
             <if test="vehicleType != null">vehicle_type = #{vehicleType},</if>
             <if test="vehicleBrand != null">vehicle_brand = #{vehicleBrand},</if>
             <if test="vehicleModel != null">vehicle_model = #{vehicleModel},</if>
             <if test="status != null">status = #{status},</if>
-            <if test="createBy != null">create_by = #{createBy},</if>
-            <if test="createTime != null">create_time = #{createTime},</if>
             <if test="updateBy != null">update_by = #{updateBy},</if>
-            <if test="updateTime != null">update_time = #{updateTime},</if>
-            <if test="remark != null">remark = #{remark},</if>
+            update_time = sysdate()
         </trim>
         where vehicle_id = #{vehicleId}
     </update>
diff --git a/ruoyi-ui/public/car_blue.png b/ruoyi-ui/public/car_blue.png
new file mode 100644
index 0000000..e392014
--- /dev/null
+++ b/ruoyi-ui/public/car_blue.png
Binary files differ
diff --git a/ruoyi-ui/public/car_green.png b/ruoyi-ui/public/car_green.png
new file mode 100644
index 0000000..939ae77
--- /dev/null
+++ b/ruoyi-ui/public/car_green.png
Binary files differ
diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html
index 925455c..c35f03a 100644
--- a/ruoyi-ui/public/index.html
+++ b/ruoyi-ui/public/index.html
@@ -204,5 +204,6 @@
 		    <div class="load_title">姝e湪鍔犺浇绯荤粺璧勬簮锛岃鑰愬績绛夊緟</div>
         </div>
 	</div>
+    
   </body>
 </html>
diff --git a/ruoyi-ui/src/api/system/gps.js b/ruoyi-ui/src/api/system/gps.js
index 20ec35a..e57aa18 100644
--- a/ruoyi-ui/src/api/system/gps.js
+++ b/ruoyi-ui/src/api/system/gps.js
@@ -1,6 +1,6 @@
 import request from '@/utils/request'
 
-// 鏌ヨGPS鍧愭爣鍒楄〃
+// 鏌ヨGPS浣嶇疆鍒楄〃
 export function listGps(query) {
   return request({
     url: '/system/gps/list',
@@ -9,7 +9,7 @@
   })
 }
 
-// 鏌ヨGPS鍧愭爣璇︾粏
+// 鏌ヨGPS浣嶇疆璇︾粏
 export function getGps(gpsId) {
   return request({
     url: '/system/gps/' + gpsId,
@@ -17,7 +17,7 @@
   })
 }
 
-// 鏂板GPS鍧愭爣
+// 鏂板GPS浣嶇疆
 export function addGps(data) {
   return request({
     url: '/system/gps',
@@ -26,7 +26,7 @@
   })
 }
 
-// 淇敼GPS鍧愭爣
+// 淇敼GPS浣嶇疆
 export function updateGps(data) {
   return request({
     url: '/system/gps',
@@ -35,7 +35,7 @@
   })
 }
 
-// 鍒犻櫎GPS鍧愭爣
+// 鍒犻櫎GPS浣嶇疆
 export function delGps(gpsId) {
   return request({
     url: '/system/gps/' + gpsId,
@@ -43,11 +43,31 @@
   })
 }
 
-// 瀵煎嚭GPS鍧愭爣
-export function exportGps(query) {
+// 鑾峰彇杞﹁締鏈�鏂癎PS浣嶇疆
+export function getLastPosition(deviceId) {
   return request({
-    url: '/system/gps/export',
+    url: '/system/gps/lastPosition/' + deviceId,
+    method: 'get'
+  })
+}
+
+// 鑾峰彇鎵�鏈夎溅杈咷PS浣嶇疆
+export function getAllPositions() {
+  return request({
+    url: '/system/gps/allPositions',
+    method: 'get'
+  })
+}
+
+// 鑾峰彇杞﹁締鍘嗗彶杞ㄨ抗
+export function getTrackHistory(deviceId, startTime, endTime) {
+  return request({
+    url: '/system/gps/trackHistory',
     method: 'get',
-    params: query
+    params: {
+      deviceId,
+      startTime,
+      endTime
+    }
   })
 } 
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/gpsconfig.js b/ruoyi-ui/src/api/system/gpsconfig.js
new file mode 100644
index 0000000..227d99f
--- /dev/null
+++ b/ruoyi-ui/src/api/system/gpsconfig.js
@@ -0,0 +1,61 @@
+import request from '@/utils/request'
+
+// 鏌ヨGPS閰嶇疆鍒楄〃
+export function listGpsConfig(query) {
+  return request({
+    url: '/system/gpsconfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨGPS閰嶇疆璇︾粏
+export function getGpsConfig(configId) {
+  return request({
+    url: '/system/gpsconfig/' + configId,
+    method: 'get'
+  })
+}
+
+// 鏂板GPS閰嶇疆
+export function addGpsConfig(data) {
+  return request({
+    url: '/system/gpsconfig',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼GPS閰嶇疆
+export function updateGpsConfig(data) {
+  return request({
+    url: '/system/gpsconfig',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎GPS閰嶇疆
+export function delGpsConfig(configId) {
+  return request({
+    url: '/system/gpsconfig/' + configId,
+    method: 'delete'
+  })
+}
+
+// 瀵煎嚭GPS閰嶇疆
+export function exportGpsConfig(query) {
+  return request({
+    url: '/system/gpsconfig/export',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鑾峰彇鏈夋晥token
+export function getValidToken(configKey) {
+  return request({
+    url: '/system/gpsconfig/token/' + configKey,
+    method: 'get'
+  })
+} 
\ No newline at end of file
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
index 5256c2c..7ab950d 100644
--- a/ruoyi-ui/src/permission.js
+++ b/ruoyi-ui/src/permission.js
@@ -47,7 +47,7 @@
       }
     }
   } else {
-    debugger;
+    
     // 娌℃湁token
     if (isWhiteList(to.path) || to.meta.anonymous) {
       // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index 635a020..3826ac3 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -106,6 +106,11 @@
     component: () => import('@/views/anonymous/test'),
     hidden: true,
     meta: { title: '鍖垮悕璁块棶娴嬭瘯', anonymous: true }
+  },{
+    path: '/system/gps/map',
+    component: () => import('@/views/system/gps/map'),
+    name: 'GpsMap',
+    meta: { title: '杞﹁締杞ㄨ抗', icon: 'map' ,anonymous: true}
   }
 ]
 
diff --git a/ruoyi-ui/src/views/system/gps/index.vue b/ruoyi-ui/src/views/system/gps/index.vue
index e36349a..c019c5e 100644
--- a/ruoyi-ui/src/views/system/gps/index.vue
+++ b/ruoyi-ui/src/views/system/gps/index.vue
@@ -101,6 +101,12 @@
             @click="handleDelete(scope.row)"
             v-hasPermi="['system:gps:remove']"
           >鍒犻櫎</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-map-location"
+            @click="handleMap(scope.row)"
+          >鏌ョ湅杞ㄨ抗</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -323,6 +329,15 @@
       this.download('system/gps/export', {
         ...this.queryParams
       }, `gps_${new Date().getTime()}.xlsx`)
+    },
+    /** 鏌ョ湅杞ㄨ抗鎸夐挳鎿嶄綔 */
+    handleMap(row) {
+      this.$router.push({
+        path: '/system/gps/map',
+        query: {
+          vehicleNo: row.vehicleNo
+        }
+      });
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/gps/map.vue b/ruoyi-ui/src/views/system/gps/map.vue
new file mode 100644
index 0000000..2e93143
--- /dev/null
+++ b/ruoyi-ui/src/views/system/gps/map.vue
@@ -0,0 +1,543 @@
+<template>
+  <div class="app-container">
+    <el-form
+      :model="queryParams"
+      ref="queryForm"
+      :inline="true"
+      v-show="showSearch"
+      label-width="68px"
+    >
+      <el-form-item label="杞︾墝鍙�" prop="vehicleNo">
+        <el-input
+          v-model="queryParams.vehicleNo"
+          placeholder="璇疯緭鍏ヨ溅鐗屽彿"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鏃堕棿鑼冨洿">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetimerange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+          >鎼滅储</el-button
+        >
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
+          >閲嶇疆</el-button
+        >
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="20">
+      <el-col :span="6">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>杞ㄨ抗鍒楄〃</span>
+          </div>
+          <el-table
+            v-loading="loading"
+            :data="gpsList"
+            height="600"
+            @row-click="handleRowClick"
+          >
+            <el-table-column label="鏃堕棿" align="center" prop="collectTime" />
+            <el-table-column label="閫熷害(km/h)" align="center" prop="speed" />
+            
+          </el-table>
+        </el-card>
+      </el-col>
+      <el-col :span="18">
+        <div id="mapContainer" style="height: 600px"></div>
+        <div class="track-controls">
+          <el-button-group>
+            <el-button
+              size="small"
+              @click="showPreviousSegment"
+              :disabled="segmentIndex === 0"
+            >
+              <i class="el-icon-arrow-left"></i> 涓婁竴娈�
+            </el-button>
+            <el-button
+              size="small"
+              @click="showNextSegment"
+              :disabled="(segmentIndex + 1) * segmentSize >= gpsList.length"
+            >
+              涓嬩竴娈� <i class="el-icon-arrow-right"></i>
+            </el-button>
+          </el-button-group>
+          <el-button-group style="margin-left: 10px">
+            <el-button
+              size="small"
+              type="primary"
+              @click="startPlayback"
+              :disabled="isPlaying"
+            >
+              <i class="el-icon-video-play"></i> 寮�濮嬪洖鏀�
+            </el-button>
+            <el-button
+              size="small"
+              type="danger"
+              @click="stopPlayback"
+              :disabled="!isPlaying"
+            >
+              <i class="el-icon-video-pause"></i> 鍋滄鍥炴斁
+            </el-button>
+          </el-button-group>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { listGps } from "@/api/system/gps";
+
+export default {
+  name: "GpsMap",
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // GPS鏁版嵁琛ㄦ牸鏁版嵁
+      gpsList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        vehicleNo: undefined,
+        orderByColumn: "collect_time",
+        isAsc: "desc",
+      },
+      // 鍦板浘瀵硅薄
+      map: null,
+      // 杞ㄨ抗绾�
+      polyline: null,
+      // 鏍囪鐐规暟缁�
+      markers: [],
+      // 杞ㄨ抗鍒嗘鏄剧ず
+      segmentIndex: 0,
+      segmentSize: 50, // 姣忔鏄剧ず鐨勭偣鏁�
+      // 杞ㄨ抗鍥炴斁
+      isPlaying: false,
+      playInterval: null,
+      smoothFactor: 0.3, // 骞虫粦鍥犲瓙锛屽�艰秺澶ц秺骞虫粦
+      minDistance: 50, // 鏈�灏忔彃鍊艰窛绂伙紙绫筹級
+
+      currentPlayIndex: 0,
+      playSpeed: 1000, // 鍥炴斁閫熷害锛堟绉掞級
+      currentMarker: null,
+    };
+  },
+  created() {
+    // 鑾峰彇URL鍙傛暟涓殑杞︾墝鍙�
+    const vehicleNo = this.$route.query.vehicleNo;
+    if (vehicleNo) {
+      this.queryParams.vehicleNo = vehicleNo;
+    }
+    this.getList();
+  },
+  mounted() {
+    // 鍔ㄦ�佸姞杞界櫨搴﹀湴鍥続PI
+    this.loadBMapScript().then(() => {
+      this.initMap();
+    });
+  },
+  methods: {
+    /** 鍔犺浇鐧惧害鍦板浘API */
+    loadBMapScript() {
+      return new Promise((resolve, reject) => {
+        if (window.BMap) {
+          resolve(window.BMap);
+          return;
+        }
+        const script = document.createElement("script");
+        script.type = "text/javascript";
+        script.src =
+          "https://api.map.baidu.com/api?v=3.0&ak=n5z5pKfAnaP3fYMR4RJOAQsR1wQ2avAn&callback=initBMap";
+        script.onerror = reject;
+        document.head.appendChild(script);
+        window.initBMap = () => {
+          // 鍔犺浇鍧愭爣杞崲搴�
+          const convertorScript = document.createElement("script");
+          convertorScript.type = "text/javascript";
+          convertorScript.src =
+            "https://api.map.baidu.com/getscript?v=3.0&ak=n5z5pKfAnaP3fYMR4RJOAQsR1wQ2avAn&services=&t=20230101100000";
+          convertorScript.onload = () => {
+            // 鍔犺浇鍧愭爣杞崲宸ュ叿
+            const toolsScript = document.createElement("script");
+            toolsScript.type = "text/javascript";
+            toolsScript.src =
+              "https://api.map.baidu.com/library/Convertor/1.4/src/Convertor_min.js";
+            toolsScript.onload = () => {
+              resolve(window.BMap);
+            };
+            document.head.appendChild(toolsScript);
+          };
+          document.head.appendChild(convertorScript);
+        };
+      });
+    },
+    /** 鏌ヨGPS鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listGps(this.addDateRange(this.queryParams, this.dateRange)).then(
+        (response) => {
+          this.gpsList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+          this.drawTrack();
+        }
+      );
+    },
+    async translatePoints(points) {
+      // 灏哤GS84鍧愭爣杞崲涓虹櫨搴﹀潗鏍�
+      var translatePoints = [];
+      return new Promise((resolve, reject) => {
+        const convertor = new BMap.Convertor();
+        convertor.translate(points, 1, 5, (data) => {
+          if (data.status === 0) {
+            translatePoints = data.points;
+            resolve(translatePoints);
+          }
+        });
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鍒濆鍖栧湴鍥� */
+    initMap() {
+      // 鍒涘缓鍦板浘瀹炰緥
+      this.map = new BMap.Map("mapContainer");
+      // 璁剧疆鍦板浘涓績鐐瑰拰缂╂斁绾у埆
+      this.map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
+      // 鍚敤婊氳疆鏀惧ぇ缂╁皬
+      this.map.enableScrollWheelZoom();
+    },
+     /** 璁$畻涓ょ偣涔嬮棿鐨勮窛绂伙紙绫筹級 */
+     getDistance(point1, point2) {
+        return this.map.getDistance(point1, point2);
+      },
+      /** 璁$畻涓ょ偣涔嬮棿鐨勮搴� */
+      getAngle(point1, point2) {
+        const dx = point2.lng - point1.lng;
+        const dy = point2.lat - point1.lat;
+        return Math.atan2(dy, dx) * 180 / Math.PI;
+      },
+
+     /** 鍦ㄤ袱鐐逛箣闂存彃鍏ュ钩婊戠偣 */
+     getSmoothPoints(point1, point2) {
+        const distance = this.getDistance(point1, point2);
+        if (distance < this.minDistance) {
+          return [point1, point2];
+        }
+        
+        const angle = this.getAngle(point1, point2);
+        const midPoint = new BMap.Point(
+          (point1.lng + point2.lng) / 2,
+          (point1.lat + point2.lat) / 2
+        );
+        
+        // 璁$畻鎺у埗鐐�
+        const controlPoint = new BMap.Point(
+          midPoint.lng + this.smoothFactor * distance * Math.cos((angle + 90) * Math.PI / 180),
+          midPoint.lat + this.smoothFactor * distance * Math.sin((angle + 90) * Math.PI / 180)
+        );
+        
+        // 浣跨敤浜屾璐濆灏旀洸绾跨敓鎴愬钩婊戠偣
+        const points = [];
+        for (let t = 0; t <= 1; t += 0.1) {
+          const x = Math.pow(1 - t, 2) * point1.lng + 2 * (1 - t) * t * controlPoint.lng + Math.pow(t, 2) * point2.lng;
+          const y = Math.pow(1 - t, 2) * point1.lat + 2 * (1 - t) * t * controlPoint.lat + Math.pow(t, 2) * point2.lat;
+          points.push(new BMap.Point(x, y));
+        }
+        return points;
+      },
+
+    /** 缁樺埗杞ㄨ抗 */
+    async drawTrack() {
+      // 娓呴櫎涔嬪墠鐨勮建杩�
+      if (this.polyline) {
+        this.map.removeOverlay(this.polyline);
+      }
+      this.markers.forEach((marker) => {
+        this.map.removeOverlay(marker);
+      });
+      this.markers = [];
+
+      if (this.gpsList.length === 0) {
+        return;
+      }
+
+      // 鎸夋椂闂存帓搴�
+      this.gpsList.sort((a, b) => {
+        return new Date(a.collectTime) - new Date(b.collectTime);
+      });
+
+      // 璁$畻褰撳墠娈佃惤鐨勮捣濮嬪拰缁撴潫绱㈠紩
+      const startIndex = this.segmentIndex * this.segmentSize;
+      const endIndex = Math.min(
+        startIndex + this.segmentSize,
+        this.gpsList.length
+      );
+      const currentSegment = this.gpsList.slice(startIndex, endIndex);
+
+      //鍏堣幏寰楁墍鏈夊潗鏍囨暟缁�
+      const originPoints = currentSegment.map(
+        (item) => new BMap.Point(item.longitude, item.latitude)
+      );
+    
+      this.gpsList.sort((a, b) => {
+        return new Date(b.collectTime) - new Date(a.collectTime);
+      }).forEach(item => {
+       item.speed=item.speed/1000;
+      });
+      //鎵归噺杞崲鍧愭爣
+      var translatePoints = await this.translatePoints(originPoints);
+
+      // 鍒涘缓杞ㄨ抗鐐规暟缁�
+      const points = translatePoints;
+      translatePoints.forEach((item, index) => {
+        const bdPoint = item;
+
+        // 鍙湪璧风偣鍜岀粓鐐瑰垱寤烘爣璁�
+        if (index === 0 || index === translatePoints.length - 1) {
+          let marker;
+          let direction=currentSegment[index].direction;
+          if (index === 0) {
+            // 璧风偣鏄剧ず"璧�"瀛�
+            const label = new BMap.Label("璧�", {
+              offset: new BMap.Size(0, 0),
+              position: bdPoint,
+            });
+            label.setStyle({
+              color: "white",
+              fontSize: "12px",
+              backgroundColor: "#3388ff",
+              border: "none",
+              padding: "2px 6px",
+              borderRadius: "3px",
+            });
+            marker = new BMap.Marker(bdPoint,{rotation:direction});
+            marker.setLabel(label);
+          } else {
+            // 缁堢偣鏄剧ず杞﹁締鍥炬爣
+           
+            const myIcon = new BMap.Icon(
+              "/car_blue.png",
+              new BMap.Size(20, 20),
+              {
+                imageSize: new BMap.Size(20, 20),
+                anchor: new BMap.Size(10, 10),
+              }
+            );
+            marker = new BMap.Marker(bdPoint, {
+              icon: myIcon,
+              rotation: direction,
+            });
+          }
+
+          // 鑾峰彇鍦板潃淇℃伅
+          const geoc = new BMap.Geocoder();
+          geoc.getLocation(bdPoint, (rs) => {
+            const addComp = rs.addressComponents;
+            const address =
+              addComp.province +
+              addComp.city +
+              addComp.district +
+              addComp.street +
+              addComp.streetNumber;
+
+            // 娣诲姞淇℃伅绐楀彛
+            const infoWindow = new BMap.InfoWindow(
+              `鏃堕棿锛�${item.collectTime}<br/>閫熷害锛�${
+                item.speed
+              }km/h<br/>鏂瑰悜锛�${item.direction}掳<br/>鍦板潃锛�${address}`
+            );
+            marker.addEventListener("click", () => {
+              this.map.openInfoWindow(infoWindow, bdPoint);
+            });
+          });
+
+          this.map.addOverlay(marker);
+          this.markers.push(marker);
+        }
+        // const smoothPoints = [];
+        // for (let i = 0; i < points.length - 1; i++) {
+        //   const segmentPoints = this.getSmoothPoints(points[i], points[i + 1]);
+        //   smoothPoints.push(...segmentPoints);
+        // }
+        // smoothPoints.push(points[points.length - 1]);
+
+        // 濡傛灉鏄渶鍚庝竴涓偣锛岀粯鍒惰建杩圭嚎
+        if (index === currentSegment.length - 1) {
+          // 鍒涘缓杞ㄨ抗绾�
+          this.polyline = new BMap.Polyline(points, {
+            strokeColor: "#3388ff",
+            strokeWeight: 5,
+            strokeOpacity: 0.8,
+            strokeStyle: "solid",
+          });
+          this.map.addOverlay(this.polyline);
+
+          // 璋冩暣鍦板浘瑙嗛噹浠ユ樉绀哄畬鏁磋建杩�
+          this.map.setViewport(points);
+        }
+      });
+    },
+    /** 鐐瑰嚮琛ㄦ牸琛� */
+    handleRowClick(row) {
+      const point = new BMap.Point(row.longitude, row.latitude);
+      const convertor = new BMap.Convertor();
+      convertor.translate([point], 1, 5, (data) => {
+        if (data.status === 0) {
+          // 绉婚櫎涔嬪墠鐨勬爣璁扮偣
+          if (this.currentMarker) {
+            this.map.removeOverlay(this.currentMarker);
+          }
+          
+          // 鍒涘缓鏂扮殑鏍囪鐐�
+          const myIcon = new BMap.Icon(
+            "/car_blue.png",
+            new BMap.Size(20, 20),
+            {
+              imageSize: new BMap.Size(20, 20),
+              anchor: new BMap.Size(10, 10),
+            }
+          );
+          const marker = new BMap.Marker(data.points[0], {
+            icon: myIcon,
+            rotation: row.direction,
+          });
+          
+          // 鏄剧ず杞︾墝
+          const label = new BMap.Label(row.vehicleNo, {
+            offset: new BMap.Size(0, -25), // 鍚戜笂鍋忕Щ25鍍忕礌
+            position: data.points[0],
+          });
+          label.setStyle({
+            color: "white",
+            fontSize: "12px",
+            backgroundColor: "#3388ff",
+            border: "none",
+            padding: "2px 6px",
+            borderRadius: "3px",
+            whiteSpace: "nowrap", // 闃叉鏂囧瓧鎹㈣
+          });
+          marker.setLabel(label);
+          
+          // 娣诲姞淇℃伅绐楀彛
+          const infoWindow = new BMap.InfoWindow(
+            `鏃堕棿锛�${row.collectTime}<br/>閫熷害锛�${row.speed}km/h<br/>鏂瑰悜锛�${row.direction}掳<br/>鍦板潃锛�${row.address}`
+          );
+          marker.addEventListener("click", () => {
+            this.map.openInfoWindow(infoWindow, data.points[0]);
+          });
+          
+          // 淇濆瓨褰撳墠鏍囪鐐瑰紩鐢�
+          this.currentMarker = marker;
+          
+          // 娣诲姞鍒板湴鍥惧苟灞呬腑鏄剧ず
+          this.map.addOverlay(marker);
+          this.map.setCenter(data.points[0]);
+          this.map.setZoom(15);
+        }
+      });
+    },
+    /** 鏄剧ず涓婁竴娈佃建杩� */
+    showPreviousSegment() {
+      if (this.segmentIndex > 0) {
+        this.segmentIndex--;
+        this.drawTrack();
+      }
+    },
+    /** 鏄剧ず涓嬩竴娈佃建杩� */
+    showNextSegment() {
+      if ((this.segmentIndex + 1) * this.segmentSize < this.gpsList.length) {
+        this.segmentIndex++;
+        this.drawTrack();
+      }
+    },
+    /** 寮�濮嬭建杩瑰洖鏀� */
+    startPlayback() {
+      if (this.isPlaying) return;
+      this.isPlaying = true;
+      this.currentPlayIndex = 0;
+      this.playInterval = setInterval(() => {
+        if (this.currentPlayIndex < this.gpsList.length) {
+          const item = this.gpsList[this.currentPlayIndex];
+          const point = new BMap.Point(item.longitude, item.latitude);
+          const convertor = new BMap.Convertor();
+          convertor.translate([point], 1, 5, (data) => {
+            if (data.status === 0) {
+              const bdPoint = data.points[0];
+              this.map.setCenter(bdPoint);
+              this.map.setZoom(15);
+            }
+          });
+          this.currentPlayIndex++;
+        } else {
+          this.stopPlayback();
+        }
+      }, this.playSpeed);
+    },
+    /** 鍋滄杞ㄨ抗鍥炴斁 */
+    stopPlayback() {
+      if (this.playInterval) {
+        clearInterval(this.playInterval);
+        this.playInterval = null;
+      }
+      this.isPlaying = false;
+    },
+  },
+  beforeDestroy() {
+    this.stopPlayback();
+  },
+};
+</script>
+
+<style scoped>
+.box-card {
+  margin-bottom: 20px;
+}
+.track-controls {
+  position: absolute;
+  bottom: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+  z-index: 1000;
+  background: rgba(255, 255, 255, 0.9);
+  padding: 10px;
+  border-radius: 4px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+</style> 
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/gpsconfig/index.vue b/ruoyi-ui/src/views/system/gpsconfig/index.vue
new file mode 100644
index 0000000..b1cbd84
--- /dev/null
+++ b/ruoyi-ui/src/views/system/gpsconfig/index.vue
@@ -0,0 +1,297 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="閰嶇疆閿�" prop="configKey">
+        <el-input
+          v-model="queryParams.configKey"
+          placeholder="璇疯緭鍏ラ厤缃敭"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍩熷悕" prop="domain">
+        <el-input
+          v-model="queryParams.domain"
+          placeholder="璇疯緭鍏ュ煙鍚�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐢ㄦ埛鍚�" prop="username">
+        <el-input
+          v-model="queryParams.username"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:gpsconfig:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:gpsconfig:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:gpsconfig:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:gpsconfig:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="gpsConfigList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="閰嶇疆ID" align="center" prop="configId" />
+      <el-table-column label="閰嶇疆閿�" align="center" prop="configKey" />
+      <el-table-column label="鍩熷悕" align="center" prop="domain" />
+      <el-table-column label="鐢ㄦ埛鍚�" align="center" prop="username" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:gpsconfig:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:gpsconfig:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀笹PS閰嶇疆瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="閰嶇疆閿�" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="璇疯緭鍏ラ厤缃敭" />
+        </el-form-item>
+        <el-form-item label="鍩熷悕" prop="domain">
+          <el-input v-model="form.domain" placeholder="璇疯緭鍏ュ煙鍚�" />
+        </el-form-item>
+        <el-form-item label="鐢ㄦ埛鍚�" prop="username">
+          <el-input v-model="form.username" placeholder="璇疯緭鍏ョ敤鎴峰悕" />
+        </el-form-item>
+        <el-form-item label="瀵嗙爜" prop="password">
+          <el-input v-model="form.password" type="password" placeholder="璇疯緭鍏ュ瘑鐮�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listGpsConfig, getGpsConfig, delGpsConfig, addGpsConfig, updateGpsConfig, exportGpsConfig } from "@/api/system/gpsconfig";
+
+export default {
+  name: "GpsConfig",
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // GPS閰嶇疆琛ㄦ牸鏁版嵁
+      gpsConfigList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        configKey: null,
+        domain: null,
+        username: null
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        configKey: [
+          { required: true, message: "閰嶇疆閿笉鑳戒负绌�", trigger: "blur" }
+        ],
+        domain: [
+          { required: true, message: "鍩熷悕涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        username: [
+          { required: true, message: "鐢ㄦ埛鍚嶄笉鑳戒负绌�", trigger: "blur" }
+        ],
+        password: [
+          { required: true, message: "瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨGPS閰嶇疆鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listGpsConfig(this.queryParams).then(response => {
+        this.gpsConfigList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        configId: null,
+        configKey: null,
+        domain: null,
+        username: null,
+        password: null
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.configId)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞GPS閰嶇疆";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const configId = row.configId || this.ids
+      getGpsConfig(configId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼GPS閰嶇疆";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.configId != null) {
+            updateGpsConfig(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addGpsConfig(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const configIds = row.configId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎GPS閰嶇疆缂栧彿涓�"' + configIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delGpsConfig(configIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/gpsconfig/export', {
+        ...this.queryParams
+      }, `gpsconfig_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script> 
\ No newline at end of file
diff --git a/sql/add_task.sql b/sql/add_task.sql
new file mode 100644
index 0000000..a33b3ce
--- /dev/null
+++ b/sql/add_task.sql
@@ -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', 
+    'gpsSyncTask.syncGpsData()', 
+    '0 */5 * * * ?', 
+    '3', 
+    '1', 
+    '0', 
+    'admin', 
+    sysdate(), 
+    'admin', 
+    sysdate(), 
+    '姣�5鍒嗛挓鍚屾涓�娆PS鏁版嵁'
+);
\ No newline at end of file
diff --git a/sql/sys_gps_config.sql b/sql/sys_gps_config.sql
new file mode 100644
index 0000000..3820cb7
--- /dev/null
+++ b/sql/sys_gps_config.sql
@@ -0,0 +1,19 @@
+-- GPS鏈嶅姟閰嶇疆琛�
+drop table if exists sys_gps_config;
+create table sys_gps_config (
+  config_id        bigint(20)      not null auto_increment    comment '閰嶇疆ID',
+  config_key       varchar(50)     not null                   comment '閰嶇疆閿��',
+  lastquerypositiontime BIGINT     DEFAULT NULL               COMMENT '鏈�鍚庢煡璇綅缃椂闂�',
+  domain           varchar(255)    default ''                 comment '鏈嶅姟鍩熷悕',
+  username         varchar(50)     default ''                 comment '鐢ㄦ埛鍚�',
+  password         varchar(50)     default ''                 comment '瀵嗙爜',
+  token            varchar(500)    default ''                 comment '璁块棶浠ょ墝',
+  token_expire_time datetime                                 comment '浠ょ墝杩囨湡鏃堕棿',
+  create_by        varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by        varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time      datetime                                   comment '鏇存柊鏃堕棿',
+  remark           varchar(500)    default null               comment '澶囨敞',
+  primary key (config_id),
+  unique key (config_key)
+) engine=innodb auto_increment=100 comment = 'GPS鏈嶅姟閰嶇疆琛�'; 
\ No newline at end of file
diff --git a/sql/sys_menu.sql b/sql/sys_menu.sql
new file mode 100644
index 0000000..04c1886
--- /dev/null
+++ b/sql/sys_menu.sql
@@ -0,0 +1,22 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (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('GPS閰嶇疆绠$悊', '3', '1', 'gpsconfig', 'system/gpsconfig/index', 1, 0, 'C', '0', '0', 'system:gpsconfig:list', 'gps', 'admin', sysdate(), '', null, 'GPS閰嶇疆绠$悊鑿滃崟');
+
+-- 鎸夐挳鐖惰彍鍗旾D
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 鎸夐挳 SQL
+insert into sys_menu (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('GPS閰嶇疆鏌ヨ', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', 'system:gpsconfig:query',        '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (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('GPS閰嶇疆鏂板', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', 'system:gpsconfig:add',          '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (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('GPS閰嶇疆淇敼', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', 'system:gpsconfig:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (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('GPS閰嶇疆鍒犻櫎', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', 'system:gpsconfig:remove',       '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (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('GPS閰嶇疆瀵煎嚭', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', 'system:gpsconfig:export',       '#', 'admin', sysdate(), '', null, ''); 
\ No newline at end of file
diff --git a/sql/vehicle_gps.sql b/sql/vehicle_gps.sql
index 87630d7..04e296c 100644
--- a/sql/vehicle_gps.sql
+++ b/sql/vehicle_gps.sql
@@ -26,11 +26,14 @@
   `direction` decimal(10,2) DEFAULT NULL COMMENT '鏂瑰悜(搴�)',
   `collect_time` datetime NOT NULL COMMENT '閲囬泦鏃堕棿',
   `create_time` datetime DEFAULT NULL COMMENT '鍒涘缓鏃堕棿',
+  `device_report_time` datetime DEFAULT NULL COMMENT '璁惧涓婃姤鏃堕棿',
+  `platform_process_time` datetime DEFAULT NULL COMMENT '骞冲彴澶勭悊鏃堕棿',
   PRIMARY KEY (`gps_id`),
   KEY `idx_vehicle_id` (`vehicle_id`),
   KEY `idx_collect_time` (`collect_time`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='杞﹁締GPS鍧愭爣琛�';
 
+
 -- GPS閲囬泦鏃ュ織琛�
 CREATE TABLE `tb_gps_collect_log` (
   `log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '鏃ュ織ID',
diff --git a/sql/vehicle_info.sql b/sql/vehicle_info.sql
index bf73724..6434538 100644
--- a/sql/vehicle_info.sql
+++ b/sql/vehicle_info.sql
@@ -14,4 +14,10 @@
   update_time          datetime                                   comment '鏇存柊鏃堕棿',
   remark               varchar(500)    default null               comment '澶囨敞',
   primary key (vehicle_id)
-) engine=innodb auto_increment=100 comment = '杞﹁締淇℃伅琛�'; 
\ No newline at end of file
+) engine=innodb auto_increment=100 comment = '杞﹁締淇℃伅琛�'; 
+
+-- 鍦╰b_vehicle_info琛ㄤ腑娣诲姞device_id瀛楁
+ALTER TABLE tb_vehicle_info ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
+
+-- 鍦╰b_vehicle_gps琛ㄤ腑娣诲姞device_id瀛楁
+ALTER TABLE tb_vehicle_gps ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '璁惧ID';
\ No newline at end of file

--
Gitblit v1.9.1