wanglizhong
2025-05-03 a296c6bfa83cd0a4bbc92d93c015a010248e8455
feat:增加gps显示
23个文件已修改
21个文件已添加
3614 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/GpsCollectController.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/pom.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/config/GpsServiceConfig.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java 660 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginRequest.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLoginResponse.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleGps.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/VehicleInfo.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/VehicleInfoMapper.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsCollectService.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/IVehicleInfoService.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsCollectServiceImpl.java 487 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleInfoServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/VehicleGpsMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/VehicleInfoMapper.xml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/public/car_blue.png 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/public/car_green.png 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/public/index.html 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/system/gps.js 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/api/system/gpsconfig.js 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/permission.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/router/index.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/gps/index.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/gps/map.vue 543 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/system/gpsconfig/index.vue 297 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/add_task.sql 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/sys_gps_config.sql 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/sys_menu.sql 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/vehicle_gps.sql 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/vehicle_info.sql 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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);
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysGpsConfigController.java
New file
@@ -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));
    }
    /**
     * 获取有效的token
     */
    @PreAuthorize("@ss.hasPermi('system:gpsconfig:query')")
    @GetMapping("/token/{configKey}")
    public AjaxResult getValidToken(@PathVariable("configKey") String configKey) {
        return success(gpsConfigService.getValidToken(configKey));
    }
}
ruoyi-quartz/pom.xml
@@ -38,7 +38,6 @@
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-system</artifactId>
        </dependency>
    </dependencies>
</project>
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/GpsSyncTask.java
New file
@@ -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;
    /**
     * 同步设备列表和GPS位置
     */
    public void syncGpsData() {
        try {
            log.info("开始同步GPS数据...");
            // 1. 获取设备列表,这会自动更新车辆信息中的设备ID
            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 这个是一个linux时间戳,要转换成北京时间,再转成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());
        }
    }
}
ruoyi-system/pom.xml
@@ -32,6 +32,7 @@
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- FastJSON -->
        <dependency>
            <groupId>com.alibaba</groupId>
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;
    }
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDevice.java
New file
@@ -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;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsDeviceListResponse.java
New file
@@ -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;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsGroup.java
New file
@@ -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;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPosition.java
New file
@@ -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;
    /** 正反转(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;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionRequest.java
New file
@@ -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;
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/GpsLastPositionResponse.java
New file
@@ -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;
    }
}
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;
    }
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;
    }
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysGpsConfig.java
New file
@@ -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();
    }
}
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();
    }
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())
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysGpsConfigMapper.java
New file
@@ -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);
}
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);
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);
ruoyi-system/src/main/java/com/ruoyi/system/service/IGpsConfigService.java
New file
@@ -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);
    /**
     * 获取有效的token
     *
     * @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);
}
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);
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);
        // 解析响应
        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);
            // 解析响应
            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("解析响应失败:" + e.getMessage());
            GpsLoginResponse response = new GpsLoginResponse();
            response.setSuccess(false);
            response.setStatus(-1);
            response.setMessage("登录失败:" + e.getMessage());
            return response;
        }
        return loginResponse;
    }
    /**
     * 获取有效的token,如果token无效则自动登录
     */
    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()) {
                //将token写入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) {
                            // 更新现有车辆的设备ID
                            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;
    }
    @Override
    public GpsDeviceListResponse getDeviceList() {
        // 获取GPS配置信息
        SysGpsConfig config = gpsConfigService.selectGpsConfigByKey("gps51");
        if (config == null) {
            GpsDeviceListResponse response = new GpsDeviceListResponse();
            response.setStatus(-1);
            response.setCause("未找到GPS配置信息");
            return response;
        }
        // 获取有效的token,如果无效则自动登录
        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 {
            // 发送HTTP请求
            String result = HttpUtil.post(url, params);
            JSONObject jsonResult = JSON.parseObject(result);
            // 解析响应
            GpsDeviceListResponse response = new GpsDeviceListResponse();
            response.setStatus(jsonResult.getInteger("status"));
            response.setCause(jsonResult.getString("cause"));
            if (response.getStatus() == 0) {
                // 解析分组列表
                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"));
                    // 解析设备列表
                    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("未找到GPS配置信息");
            return response;
        }
        // 获取有效的token,如果无效则自动登录
        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 {
            // 发送HTTP请求
            String result = HttpUtil.post(url, params);
            JSONObject jsonResult = JSON.parseObject(result);
            // 解析响应
            GpsLastPositionResponse response = new GpsLastPositionResponse();
            response.setStatus(jsonResult.getInteger("status"));
            response.setCause(jsonResult.getString("cause"));
            // 获取新的lastquerypositiontime
            Long newLastQueryTime = jsonResult.getLong("lastquerypositiontime");
            response.setLastquerypositiontime(newLastQueryTime);
            // 如果请求成功,更新配置中的lastquerypositiontime
            if (response.getStatus() == 0 && newLastQueryTime != null) {
                config.setLastquerypositiontime(newLastQueryTime);
                gpsConfigService.updateGpsConfig(config);
            }
            if (response.getStatus() == 0) {
                // 解析位置记录列表
                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;
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/GpsConfigServiceImpl.java
New file
@@ -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;
        }
        // 检查token是否有效(未过期)
        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);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VehicleGpsServiceImpl.java
@@ -38,11 +38,7 @@
    @Override
    public int insertVehicleGps(VehicleGps vehicleGps) {
        // 根据车牌号获取车辆ID
        Long vehicleId = vehicleGpsMapper.getVehicleIdByNo(vehicleGps.getVehicleNo());
        if (vehicleId == null) {
            throw new ServiceException("未找到对应的车辆信息");
        }
        vehicleGps.setVehicleId(vehicleId);
       ;
        return vehicleGpsMapper.insertVehicleGps(vehicleGps);
    }
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) {
ruoyi-system/src/main/resources/mapper/system/SysGpsConfigMapper.xml
New file
@@ -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>
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>
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>
ruoyi-ui/public/car_blue.png
ruoyi-ui/public/car_green.png
ruoyi-ui/public/index.html
@@ -204,5 +204,6 @@
            <div class="load_title">正在加载系统资源,请耐心等待</div>
        </div>
    </div>
  </body>
</html>
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) {
// 获取车辆最新GPS位置
export function getLastPosition(deviceId) {
  return request({
    url: '/system/gps/export',
    url: '/system/gps/lastPosition/' + deviceId,
    method: 'get'
  })
}
// 获取所有车辆GPS位置
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
    }
  })
ruoyi-ui/src/api/system/gpsconfig.js
New file
@@ -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'
  })
}
ruoyi-ui/src/permission.js
@@ -47,7 +47,7 @@
      }
    }
  } else {
    debugger;
    // 没有token
    if (isWhiteList(to.path) || to.meta.anonymous) {
      // 在免登录白名单,直接进入
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}
  }
]
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
        }
      });
    }
  }
};
ruoyi-ui/src/views/system/gps/map.vue
New file
@@ -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() {
    // 动态加载百度地图API
    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) {
      // 将WGS84坐标转换为百度坐标
      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>
ruoyi-ui/src/views/system/gpsconfig/index.vue
New file
@@ -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"
    />
    <!-- 添加或修改GPS配置对话框 -->
    <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>
sql/add_task.sql
New file
@@ -0,0 +1,27 @@
INSERT INTO sys_job (
    job_name,
    job_group,
    invoke_target,
    cron_expression,
    misfire_policy,
    concurrent,
    status,
    create_by,
    create_time,
    update_by,
    update_time,
    remark
) VALUES (
    'GPS数据同步',
    'DEFAULT',
    'gpsSyncTask.syncGpsData()',
    '0 */5 * * * ?',
    '3',
    '1',
    '0',
    'admin',
    sysdate(),
    'admin',
    sysdate(),
    '每5分钟同步一次GPS数据'
);
sql/sys_gps_config.sql
New file
@@ -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服务配置表';
sql/sys_menu.sql
New file
@@ -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配置管理菜单');
-- 按钮父菜单ID
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, '');
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',
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 = '车辆信息表';
) engine=innodb auto_increment=100 comment = '车辆信息表';
-- 在tb_vehicle_info表中添加device_id字段
ALTER TABLE tb_vehicle_info ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '设备ID';
-- 在tb_vehicle_gps表中添加device_id字段
ALTER TABLE tb_vehicle_gps ADD COLUMN device_id VARCHAR(50) DEFAULT NULL COMMENT '设备ID';