3个文件已添加
7个文件已修改
1 文件已复制
1 文件已重命名
| | |
| | | @GetMapping("/list") |
| | | public TableDataInfo list(VehicleGps vehicleGps) { |
| | | startPage(); |
| | | // 设置按时间倒序排序 |
| | | vehicleGps.setOrderByColumn("collect_time"); |
| | | vehicleGps.setIsAsc("desc"); |
| | | List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps); |
| | | return getDataTable(list); |
| | | } |
| | |
| | | @GetMapping("/anonymousList") |
| | | public TableDataInfo anonymousList(VehicleGps vehicleGps) { |
| | | startPage(); |
| | | // 设置按时间倒序排序 |
| | | vehicleGps.setOrderByColumn("collect_time"); |
| | | vehicleGps.setIsAsc("desc"); |
| | | List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps); |
| | | return getDataTable(list); |
| | | } |
| | |
| | | @Log(title = "车辆GPS坐标", businessType = BusinessType.EXPORT) |
| | | @GetMapping("/export") |
| | | public AjaxResult export(VehicleGps vehicleGps) { |
| | | // 设置按时间倒序排序 |
| | | vehicleGps.setOrderByColumn("collect_time"); |
| | | vehicleGps.setIsAsc("desc"); |
| | | List<VehicleGps> list = vehicleGpsService.selectVehicleGpsList(vehicleGps); |
| | | ExcelUtil<VehicleGps> util = new ExcelUtil<VehicleGps>(VehicleGps.class); |
| | | return util.exportExcel(list, "车辆GPS坐标数据"); |
copy from ruoyi-admin/src/main/resources/application-druid.yml
copy to ruoyi-admin/src/main/resources/application-dev.yml
File was copied from ruoyi-admin/src/main/resources/application-druid.yml |
| | |
| | | merge-sql: true |
| | | wall: |
| | | config: |
| | | multi-statement-allow: true |
| | | multi-statement-allow: true |
| | | # 定时任务配置 |
| | | quartz: |
| | | # 是否启用定时任务 |
| | | enabled: false |
| | | # 定时任务线程池配置 |
| | | properties: |
| | | org: |
| | | quartz: |
| | | threadPool: |
| | | threadCount: 5 |
| | | threadPriority: 5 |
| | | threadsInheritContextClassLoaderOfInitializingThread: true |
| | | jobStore: |
| | | class: org.quartz.simpl.RAMJobStore |
| | | scheduler: |
| | | instanceName: clusteredScheduler |
| | | instanceId: AUTO |
| | | # 民航接口地址 |
| | | min: |
| | | apiUrl: http://120.25.98.119:8084/v1/ #测试环境:localhost:8011 |
New file |
| | |
| | | # 生产环境配置 |
| | | server: |
| | | # 服务器的HTTP端口 |
| | | port: 8080 |
| | | servlet: |
| | | # 应用的访问路径 |
| | | context-path: / |
| | | tomcat: |
| | | # tomcat的URI编码 |
| | | uri-encoding: UTF-8 |
| | | # 连接数满后的排队数,默认值100 |
| | | accept-count: 1000 |
| | | threads: |
| | | # tomcat最大线程数,默认为200 |
| | | max: 800 |
| | | # Tomcat启动初始化的线程数,默认值25 |
| | | min-spare: 30 |
| | | |
| | | # Spring配置 |
| | | spring: |
| | | # 数据源配置 |
| | | datasource: |
| | | type: com.alibaba.druid.pool.DruidDataSource |
| | | driverClassName: com.mysql.cj.jdbc.Driver |
| | | druid: |
| | | # 主库数据源 |
| | | master: |
| | | url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | username: root |
| | | password: password |
| | | # 从库数据源 |
| | | slave: |
| | | # 从数据源开关/默认关闭 |
| | | enabled: false |
| | | url: |
| | | username: |
| | | password: |
| | | # 初始连接数 |
| | | initialSize: 5 |
| | | # 最小连接池数量 |
| | | minIdle: 10 |
| | | # 最大连接池数量 |
| | | maxActive: 20 |
| | | # 配置获取连接等待超时的时间 |
| | | maxWait: 60000 |
| | | # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 |
| | | timeBetweenEvictionRunsMillis: 60000 |
| | | # 配置一个连接在池中最小生存的时间,单位是毫秒 |
| | | minEvictableIdleTimeMillis: 300000 |
| | | # 配置一个连接在池中最大生存的时间,单位是毫秒 |
| | | maxEvictableIdleTimeMillis: 900000 |
| | | # 配置检测连接是否有效 |
| | | validationQuery: SELECT 1 FROM DUAL |
| | | testWhileIdle: true |
| | | testOnBorrow: false |
| | | testOnReturn: false |
| | | webStatFilter: |
| | | # 开启stat拦截 |
| | | enabled: true |
| | | statViewServlet: |
| | | # 开启druid监控 |
| | | enabled: true |
| | | # 访问路径为/druid/* |
| | | url-pattern: /druid/* |
| | | # 是否允许清空统计数据 |
| | | reset-enable: false |
| | | # 设置访问的用户名 |
| | | login-username: admin |
| | | # 设置访问的密码 |
| | | login-password: 123456 |
| | | filter: |
| | | stat: |
| | | # 开启慢sql记录 |
| | | slow-sql-enabled: true |
| | | # 慢sql时间 |
| | | log-slow-sql: true |
| | | # 合并sql |
| | | merge-sql: true |
| | | wall: |
| | | config: |
| | | # 不允许删除表 |
| | | drop-table-allow: false |
| | | # 不允许删除数据 |
| | | delete-allow: false |
| | | # 不允许删除数据库 |
| | | delete-allow: false |
| | | # 不允许删除数据库 |
| | | drop-table-allow: false |
| | | # 文件上传 配置 |
| | | servlet: |
| | | multipart: |
| | | # 单个文件大小 |
| | | max-file-size: 10MB |
| | | # 设置总上传的文件大小 |
| | | max-request-size: 20MB |
| | | # 服务模块 |
| | | devtools: |
| | | restart: |
| | | # 热部署开关 |
| | | enabled: false |
| | | |
| | | # 定时任务配置 |
| | | quartz: |
| | | # 是否启用定时任务 |
| | | enabled: true |
| | | # 定时任务线程池配置 |
| | | properties: |
| | | org: |
| | | quartz: |
| | | threadPool: |
| | | threadCount: 5 |
| | | threadPriority: 5 |
| | | threadsInheritContextClassLoaderOfInitializingThread: true |
| | | jobStore: |
| | | class: org.quartz.simpl.RAMJobStore |
| | | scheduler: |
| | | instanceName: clusteredScheduler |
| | | instanceId: AUTO |
| | | |
| | | # MyBatis Plus配置 |
| | | mybatis-plus: |
| | | # 搜索指定包别名 |
| | | typeAliasesPackage: com.ruoyi.**.domain |
| | | # 配置mapper的扫描,找到所有的mapper.xml映射文件 |
| | | mapperLocations: classpath*:mapper/**/*Mapper.xml |
| | | # 加载全局的配置文件 |
| | | configLocation: classpath:mybatis/mybatis-config.xml |
| | | |
| | | # PageHelper分页插件 |
| | | pagehelper: |
| | | pagehelper: |
| | | # 分页参数合理化 |
| | | reasonable: true |
| | | # 支持通过Mapper接口参数来传递分页参数 |
| | | supportMethodsArguments: true |
| | | # 分页插件会自动检测当前的数据库链接 |
| | | helperDialect: mysql |
| | | |
| | | # Swagger配置 |
| | | swagger: |
| | | # 是否开启swagger |
| | | enabled: false |
| | | # 请求前缀 |
| | | pathMapping: / |
| | | |
| | | # 防止XSS攻击 |
| | | xss: |
| | | # 过滤开关 |
| | | enabled: true |
| | | # 排除链接(多个用逗号分隔) |
| | | excludes: /system/notice |
| | | # 匹配链接 |
| | | urlPatterns: /system/*,/monitor/*,/tool/* |
| | | |
| | | # 日志配置 |
| | | logging: |
| | | level: |
| | | com.ruoyi: info |
| | | org.springframework: warn |
| | | |
| | | # 第三方接口配置 |
| | | min: |
| | | apiUrl: http://localhost:8080 |
File was renamed from ruoyi-admin/src/main/resources/application-druid.yml |
| | |
| | | druid: |
| | | # 主库数据源 |
| | | master: |
| | | url: jdbc:mysql://120.25.98.119:3307/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | url: jdbc:mysql://localhost:3307/ruoyi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 |
| | | username: root |
| | | password: abcd1234 |
| | | # 从库数据源 |
| | | # SQL Server数据源 |
| | | sqlserver: |
| | | url: jdbc:sqlserver://120.25.98.119:1432;databaseName=came |
| | | url: jdbc:sqlserver://127.0.0.1:1432;databaseName=came |
| | | username: camesa |
| | | password: camesa |
| | | driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver |
| | |
| | | merge-sql: true |
| | | wall: |
| | | config: |
| | | multi-statement-allow: true |
| | | multi-statement-allow: true |
| | | # 定时任务配置 |
| | | quartz: |
| | | enabled: false |
| | | # 民航接口地址 |
| | | min: |
| | | apiUrl: http://120.25.98.119:8084/v1/ #测试环境:localhost:8011 |
| | |
| | | # 名称 |
| | | name: RuoYi |
| | | # 版本 |
| | | version: 3.8.9 |
| | | version: ${revision} |
| | | # 版权年份 |
| | | copyrightYear: 2025 |
| | | # 实例演示开关 |
| | | demoEnabled: true |
| | | # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) |
| | | profile: D:/ruoyi/uploadPath |
| | | # 获取ip地址开关 |
| | |
| | | # 国际化资源文件路径 |
| | | basename: i18n/messages |
| | | profiles: |
| | | active: druid |
| | | # 环境 dev|test|prod |
| | | active: dev |
| | | # 文件上传 |
| | | servlet: |
| | | multipart: |
| | |
| | | max-active: 8 |
| | | # #连接池最大阻塞等待时间(使用负值表示没有限制) |
| | | max-wait: -1ms |
| | | |
| | | |
| | | # token配置 |
| | | token: |
| | |
| | | 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; |
| | |
| | | private IVehicleGpsService vehicleGpsService; |
| | | |
| | | /** |
| | | * 同步设备列表和GPS位置 |
| | | * 同步GPS位置 |
| | | */ |
| | | public void syncGpsData() { |
| | | try { |
| | | log.info("开始同步GPS数据..."); |
| | | |
| | | // 1. 获取设备列表,这会自动更新车辆信息中的设备ID |
| | | GpsDeviceListResponse response = gpsCollectService.getDeviceList(); |
| | | // 更新车辆设备ID |
| | | updateVehicleDeviceIds(response); |
| | | |
| | | // 2. 获取所有车辆信息 |
| | | // 1. 获取所有车辆信息 |
| | | List<VehicleInfo> vehicleList = vehicleInfoService.selectVehicleInfoList(new VehicleInfo()); |
| | | |
| | | //在这里获得所有车辆的GPS最后位置 |
| | | // 2. 获取所有车辆的GPS最后位置 |
| | | GpsLastPositionResponse gpsLastPositionResponse = gpsCollectService.getLastPosition(new GpsLastPositionRequest()); |
| | | |
| | | // 3. 遍历车辆列表,获取每个车辆的GPS位置 |
| | |
| | | if (vehicle.getDeviceId() != null && !vehicle.getDeviceId().isEmpty()) { |
| | | try { |
| | | // 获取车辆的最后位置 |
| | | gpsLastPositionResponse.getRecords().stream().filter(e->e.getDeviceid().equals(vehicle.getDeviceId())).forEach(record -> { |
| | | 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()); |
| | | } |
| | |
| | | } 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); |
| | | //获得数据字典中的平台编码 |
| | | |
| | | vehicleInfo.setPlatformCode("GPS51"); |
| | | vehicleInfoService.updateVehicleInfo(vehicleInfo); |
| | | } else { |
| | | VehicleInfo newVehicle = new VehicleInfo(); |
| | | newVehicle.setVehicleNo(plateNumber); |
| | | newVehicle.setDeviceId(deviceId); |
| | | newVehicle.setStatus("0"); |
| | | newVehicle.setPlatformCode("GPS51"); |
| | | 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.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"); |
| | | |
| | | //getArrivedtime 这个是一个linux时间戳,要转换成北京时间,再转成yyyy-MM-dd HH:mm:ss格式 |
| | | // 处理到达时间 |
| | | long arrivedTime = position.getArrivedtime(); |
| | | Date arrivedDate; |
| | | // 检查时间戳是否有效(大于0) |
| | | if (arrivedTime > 0) { |
| | | arrivedDate = new Date(arrivedTime); |
| | | // 减去8小时 |
| | | arrivedDate.setTime(arrivedDate.getTime() - 8 * 60 * 60 * 1000); |
| | | } else { |
| | | // 时间戳无效,使用当前时间 |
| | | arrivedDate = new Date(); |
| | | } |
| | | gps.setPlatformProcessTime(sdf.format(arrivedDate)); |
| | |
| | | // 设备上报时间 |
| | | long deviceTime = position.getDevicetime(); |
| | | Date date; |
| | | // 检查时间戳是否有效(大于0) |
| | | if (deviceTime > 0) { |
| | | date = new Date(deviceTime); |
| | | // 减去8小时 |
| | | date.setTime(date.getTime() - 8 * 60 * 60 * 1000); |
| | | } else { |
| | | // 时间戳无效,使用当前时间 |
| | | date = arrivedDate; |
| | | } |
| | | gps.setDeviceReportTime(sdf.format(date)); |
| | | |
| | | |
| | | |
| | | // 采集时间(使用设备上报时间) |
| | | gps.setCollectTime(sdf.format(new Date( ))); |
| | | gps.setCollectTime(sdf.format(new Date())); |
| | | |
| | | // 保存GPS位置信息 |
| | | vehicleGpsService.insertVehicleGps(gps); |
| | |
| | | log.error("更新车辆[{}]GPS位置失败: {}", vehicle.getVehicleNo(), e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package com.ruoyi.quartz.task; |
| | | |
| | | 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.VehicleInfo; |
| | | import com.ruoyi.system.service.IGpsCollectService; |
| | | import com.ruoyi.system.service.IVehicleInfoService; |
| | | |
| | | /** |
| | | * 车辆同步定时任务 |
| | | */ |
| | | @Component("vehicleSyncTask") |
| | | public class VehicleSyncTask { |
| | | |
| | | private static final Logger log = LoggerFactory.getLogger(VehicleSyncTask.class); |
| | | |
| | | @Autowired |
| | | private IGpsCollectService gpsCollectService; |
| | | |
| | | @Autowired |
| | | private IVehicleInfoService vehicleInfoService; |
| | | |
| | | /** |
| | | * 同步车辆信息 |
| | | */ |
| | | public void syncVehicleInfo() { |
| | | try { |
| | | log.info("开始同步车辆信息..."); |
| | | |
| | | // 获取设备列表,这会自动更新车辆信息中的设备ID |
| | | GpsDeviceListResponse response = gpsCollectService.getDeviceList(); |
| | | // 更新车辆设备ID |
| | | updateVehicleDeviceIds(response); |
| | | |
| | | log.info("车辆信息同步完成"); |
| | | } catch (Exception e) { |
| | | log.error("车辆信息同步失败: {}", 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); |
| | | vehicleInfo.setPlatformCode("GPS51"); |
| | | vehicleInfoService.updateVehicleInfo(vehicleInfo); |
| | | } else { |
| | | VehicleInfo newVehicle = new VehicleInfo(); |
| | | newVehicle.setVehicleNo(plateNumber); |
| | | newVehicle.setDeviceId(deviceId); |
| | | newVehicle.setStatus("0"); |
| | | newVehicle.setPlatformCode("GPS51"); |
| | | vehicleInfoService.insertVehicleInfo(newVehicle); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 从设备名称和备注中提取车牌号 |
| | | */ |
| | | private String extractPlateNumber(String deviceName, String remark) { |
| | | if (StringUtils.isNotEmpty(deviceName)) { |
| | | return deviceName; |
| | | } |
| | | if (StringUtils.isNotEmpty(remark)) { |
| | | return remark; |
| | | } |
| | | return null; |
| | | } |
| | | } |
New file |
| | |
| | | -- 车辆同步定时任务 |
| | | 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 ('车辆同步任务', 'DEFAULT', 'vehicleSyncTask.syncVehicleInfo()', '0 0 */1 * * ?', '3', '1', '1', 'admin', sysdate(), 'admin', sysdate(), '每小时同步一次车辆信息'); |
| | | |
| | | -- GPS同步定时任务 |
| | | 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', '1', 'admin', sysdate(), 'admin', sysdate(), '每5分钟同步一次GPS位置信息'); |
| | |
| | | /** 结束时间 */ |
| | | private String endTime; |
| | | |
| | | /** 排序列 */ |
| | | private String orderByColumn; |
| | | |
| | | /** 排序的方向desc或者asc */ |
| | | private String isAsc; |
| | | |
| | | public void setGpsId(Long gpsId) { |
| | | this.gpsId = gpsId; |
| | | } |
| | |
| | | this.endTime = endTime; |
| | | } |
| | | |
| | | public String getOrderByColumn() { |
| | | return orderByColumn; |
| | | } |
| | | |
| | | public void setOrderByColumn(String orderByColumn) { |
| | | this.orderByColumn = orderByColumn; |
| | | } |
| | | |
| | | public String getIsAsc() { |
| | | return isAsc; |
| | | } |
| | | |
| | | public void setIsAsc(String isAsc) { |
| | | this.isAsc = isAsc; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) |
| | |
| | | <select id="selectVehicleGpsList" parameterType="VehicleGps" resultMap="VehicleGpsResult"> |
| | | <include refid="selectVehicleGpsVo"/> |
| | | <where> |
| | | <if test="vehicleId != null "> and g.vehicle_id = #{vehicleId}</if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and v.vehicle_no like concat('%', #{vehicleNo}, '%')</if> |
| | | <if test="longitude != null "> and g.longitude = #{longitude}</if> |
| | | <if test="latitude != null "> and g.latitude = #{latitude}</if> |
| | | <if test="altitude != null "> and g.altitude = #{altitude}</if> |
| | | <if test="speed != null "> and g.speed = #{speed}</if> |
| | | <if test="direction != null "> and g.direction = #{direction}</if> |
| | | <if test="beginTime != null and beginTime != ''"> and g.collect_time >= #{beginTime}</if> |
| | | <if test="endTime != null and endTime != ''"> and g.collect_time <= #{endTime}</if> |
| | | <if test="vehicleNo != null and vehicleNo != ''"> and vehicle_no = #{vehicleNo}</if> |
| | | <if test="longitude != null "> and longitude = #{longitude}</if> |
| | | <if test="latitude != null "> and latitude = #{latitude}</if> |
| | | <if test="speed != null "> and speed = #{speed}</if> |
| | | <if test="direction != null "> and direction = #{direction}</if> |
| | | <if test="collectTime != null "> and collect_time = #{collectTime}</if> |
| | | <if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> |
| | | AND date_format(collect_time,'%y%m%d') >= date_format(#{beginTime},'%y%m%d') |
| | | </if> |
| | | <if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> |
| | | AND date_format(collect_time,'%y%m%d') <= date_format(#{endTime},'%y%m%d') |
| | | </if> |
| | | </where> |
| | | order by collect_time desc |
| | | </select> |
| | | |
| | | <select id="selectVehicleGpsById" parameterType="Long" resultMap="VehicleGpsResult"> |
| | |
| | | range-separator="-" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | :default-time="['00:00:00', '23:59:59']" |
| | | @change="handleDateRangeChange" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item> |
| | |
| | | > |
| | | <el-table-column label="时间" align="center" prop="collectTime" /> |
| | | <el-table-column label="速度(km/h)" align="center" prop="speed" /> |
| | | |
| | | <el-table-column label="经度" align="center" prop="longitude" /> |
| | | <el-table-column label="纬度" align="center" prop="latitude" /> |
| | | <el-table-column label="方向(°)" align="center" prop="direction" /> |
| | | </el-table> |
| | | </el-card> |
| | | </el-col> |
| | |
| | | // 查询参数 |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | pageSize: 1000, |
| | | deviceId: null, |
| | | appId: null, |
| | | sign: null, |
| | | timestamp: null |
| | | timestamp: null, |
| | | vehicleNo: null, |
| | | beginTime: null, |
| | | endTime: null |
| | | }, |
| | | // 表单参数 |
| | | form: { |
| | | vehicleNo: null |
| | | }, |
| | | // 表单校验 |
| | | rules: { |
| | | vehicleNo: [ |
| | | { required: true, message: "车牌号不能为空", trigger: "blur" } |
| | | ], |
| | | dateRange: [ |
| | | { required: true, message: "请选择时间范围", trigger: "change" } |
| | | ] |
| | | }, |
| | | // 地图对象 |
| | | map: null, |
| | |
| | | const query = this.$route.query; |
| | | if (query.vehicleNo) { |
| | | this.queryParams.vehicleNo = query.vehicleNo; |
| | | } else { |
| | | this.$message.error('缺少车牌号参数'); |
| | | return; |
| | | } |
| | | |
| | | // 检查时间参数 |
| | | if (query.beginTime && query.endTime) { |
| | | // 格式化时间 |
| | | this.dateRange = [ |
| | | this.formatDateTime(query.beginTime), |
| | | this.formatDateTime(query.endTime) |
| | | ]; |
| | | this.queryParams.beginTime = this.dateRange[0]; |
| | | this.queryParams.endTime = this.dateRange[1]; |
| | | } else { |
| | | this.$message.error('缺少时间范围参数'); |
| | | return; |
| | | } |
| | | |
| | | // 设置认证参数 |
| | | if (query.appId) { |
| | | this.queryParams.appId = query.appId; |
| | |
| | | this.queryParams.timestamp = query.timestamp; |
| | | } |
| | | |
| | | // 设置默认时间范围 |
| | | const today = new Date(); |
| | | const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0); |
| | | const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59); |
| | | this.dateRange = [this.parseTime(startTime), this.parseTime(endTime)]; |
| | | |
| | | // 如果URL中有时间参数,则使用URL中的时间 |
| | | if (query.beginTime && query.endTime) { |
| | | this.dateRange = [query.beginTime, query.endTime]; |
| | | } |
| | | |
| | | this.getList(); |
| | | }, |
| | | mounted() { |
| | | // 动态加载百度地图API |
| | | this.loadBMapScript().then(() => { |
| | | this.initMap(); |
| | | window.initMapFlag=true; |
| | | if(window.loadGpsList){ |
| | | this.drawTrack() |
| | | this.initMap().then(() => { |
| | | window.initMapFlag = true; |
| | | if (window.loadGpsList) { |
| | | this.drawTrack(); |
| | | } |
| | | }); |
| | | }, |
| | |
| | | resolve(window.BMap); |
| | | return; |
| | | } |
| | | |
| | | window.initBMap = () => { |
| | | console.log("百度地图API加载成功"); |
| | | resolve(window.BMap); |
| | | }; |
| | | |
| | | 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); |
| | | script.onerror = (error) => { |
| | | console.error("百度地图API加载失败", error); |
| | | reject(error); |
| | | }; |
| | | document.head.appendChild(script); |
| | | }); |
| | | }, |
| | | /** 格式化时间 */ |
| | |
| | | const seconds = String(time.getSeconds()).padStart(2, '0'); |
| | | return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; |
| | | }, |
| | | /** 处理时间格式 */ |
| | | formatDateTime(dateTimeStr) { |
| | | if (!dateTimeStr) return ''; |
| | | // 如果时间字符串不包含秒,添加秒 |
| | | if (dateTimeStr.length === 16) { // yyyy-MM-dd HH:mm |
| | | return dateTimeStr + ':00'; |
| | | } |
| | | return dateTimeStr; |
| | | }, |
| | | /** 查询GPS列表 */ |
| | | getList() { |
| | | this.loading = true; |
| | |
| | | ...this.queryParams |
| | | }; |
| | | |
| | | // 如果没有选择时间范围,则默认使用当天 |
| | | // 如果没有选择时间范围,则使用URL中的时间 |
| | | if (!this.dateRange || this.dateRange.length === 0) { |
| | | const today = new Date(); |
| | | const startTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0); |
| | | const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59); |
| | | params.beginTime = this.parseTime(startTime); |
| | | params.endTime = this.parseTime(endTime); |
| | | const query = this.$route.query; |
| | | if (query.beginTime && query.endTime) { |
| | | params.beginTime = query.beginTime; |
| | | params.endTime = query.endTime; |
| | | } else { |
| | | this.$message.error('请选择时间范围'); |
| | | this.loading = false; |
| | | return; |
| | | } |
| | | } else { |
| | | params.beginTime = this.dateRange[0]; |
| | | params.endTime = this.dateRange[1]; |
| | |
| | | } |
| | | }); |
| | | }, |
| | | async translatePoints(points) { |
| | | // 将WGS84坐标转换为百度坐标 |
| | | var translatePoints = []; |
| | | return new Promise((resolve, reject) => { |
| | | /** 坐标转换方法 */ |
| | | translatePoint(point) { |
| | | return new Promise((resolve) => { |
| | | // 使用百度地图API内置的坐标转换 |
| | | const convertor = new BMap.Convertor(); |
| | | convertor.translate(points, 1, 5, (data) => { |
| | | const pointArr = []; |
| | | pointArr.push(point); |
| | | convertor.translate(pointArr, 1, 5, (data) => { |
| | | if (data.status === 0) { |
| | | translatePoints = data.points; |
| | | resolve(translatePoints); |
| | | resolve(data.points[0]); |
| | | } else { |
| | | // 如果转换失败,返回原始坐标 |
| | | resolve(point); |
| | | } |
| | | }); |
| | | }); |
| | | }, |
| | | /** 批量坐标转换 */ |
| | | async translatePoints(points) { |
| | | const translatePoints = []; |
| | | for (const point of points) { |
| | | const translatedPoint = await this.translatePoint(point); |
| | | translatePoints.push(translatedPoint); |
| | | } |
| | | return translatePoints; |
| | | }, |
| | | /** 搜索按钮操作 */ |
| | | handleQuery() { |
| | | if (!this.queryParams.vehicleNo) { |
| | | this.$message.error('请输入车牌号'); |
| | | return; |
| | | } |
| | | if (!this.dateRange || this.dateRange.length !== 2) { |
| | | this.$message.error('请选择时间范围'); |
| | | return; |
| | | } |
| | | // 更新查询参数 |
| | | this.queryParams.beginTime = this.dateRange[0]; |
| | | this.queryParams.endTime = this.dateRange[1]; |
| | | this.getList(); |
| | | }, |
| | | /** 重置按钮操作 */ |
| | |
| | | const endTime = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59); |
| | | this.dateRange = [this.parseTime(startTime), this.parseTime(endTime)]; |
| | | this.resetForm("queryForm"); |
| | | // 保留车牌号 |
| | | this.queryParams.vehicleNo = this.$route.query.vehicleNo; |
| | | // 更新查询参数 |
| | | this.queryParams.beginTime = this.dateRange[0]; |
| | | this.queryParams.endTime = this.dateRange[1]; |
| | | this.handleQuery(); |
| | | }, |
| | | /** 初始化地图 */ |
| | | initMap() { |
| | | // 创建地图实例 |
| | | this.map = new BMap.Map("mapContainer"); |
| | | // 设置地图中心点和缩放级别 |
| | | this.map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); |
| | | // 启用滚轮放大缩小 |
| | | this.map.enableScrollWheelZoom(); |
| | | console.log("initMap 初始化地图") |
| | | async initMap() { |
| | | try { |
| | | await this.loadBMapScript(); |
| | | // 创建地图实例 |
| | | this.map = new BMap.Map("mapContainer"); |
| | | // 设置地图中心点和缩放级别 |
| | | this.map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); |
| | | // 启用滚轮放大缩小 |
| | | this.map.enableScrollWheelZoom(); |
| | | console.log("地图初始化成功"); |
| | | } catch (error) { |
| | | console.error("地图初始化失败", error); |
| | | this.$message.error("地图加载失败,请刷新页面重试"); |
| | | } |
| | | }, |
| | | /** 计算两点之间的距离(米) */ |
| | | getDistance(point1, point2) { |
| | |
| | | ); |
| | | 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; |
| | | item.speed = item.speed/1000; |
| | | }); |
| | | //批量转换坐标 |
| | | var translatePoints = await this.translatePoints(originPoints); |
| | | |
| | | // 批量转换坐标 |
| | | const translatePoints = await this.translatePoints(originPoints); |
| | | |
| | | // 创建轨迹点数组 |
| | | const points = translatePoints; |
| | |
| | | } |
| | | this.isPlaying = false; |
| | | }, |
| | | /** 处理时间范围变化 */ |
| | | handleDateRangeChange(val) { |
| | | if (val && val.length === 2) { |
| | | // 格式化时间 |
| | | this.dateRange = [ |
| | | this.formatDateTime(val[0]), |
| | | this.formatDateTime(val[1]) |
| | | ]; |
| | | |
| | | // 检查结束时间是否包含具体时间 |
| | | const endDate = new Date(this.dateRange[1]); |
| | | const hasSpecificTime = endDate.getHours() !== 0 || endDate.getMinutes() !== 0; |
| | | |
| | | if (!hasSpecificTime) { |
| | | // 如果没有具体时间,设置为23:59:59 |
| | | endDate.setHours(23, 59, 59); |
| | | this.dateRange[1] = this.parseTime(endDate); |
| | | } |
| | | |
| | | // 更新查询参数 |
| | | this.queryParams.beginTime = this.dateRange[0]; |
| | | this.queryParams.endTime = this.dateRange[1]; |
| | | } |
| | | }, |
| | | }, |
| | | beforeDestroy() { |
| | | this.stopPlayback(); |
| | |
| | | // 查询参数 |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | pageSize: 1000, |
| | | deviceId: null, |
| | | appId: null, |
| | | sign: null, |
| | |
| | | }, |
| | | mounted() { |
| | | // 动态加载百度地图API |
| | | this.loadBMapScript().then(() => { |
| | | this.initMap(); |
| | | window.initMapFlag=true; |
| | | if(window.loadGpsList){ |
| | | this.drawTrack() |
| | | this.initMap().then((success) => { |
| | | if (success) { |
| | | window.initMapFlag = true; |
| | | if (window.loadGpsList) { |
| | | this.drawTrack(); |
| | | } |
| | | } |
| | | }).catch(error => { |
| | | console.error("地图初始化失败", error); |
| | | this.$message.error("地图加载失败,请刷新页面重试"); |
| | | }); |
| | | }, |
| | | methods: { |
| | |
| | | resolve(window.BMap); |
| | | return; |
| | | } |
| | | |
| | | window.initBMap = () => { |
| | | console.log("百度地图API加载成功"); |
| | | // 确保BMap对象完全加载 |
| | | setTimeout(() => { |
| | | if (window.BMap && window.BMap.Map) { |
| | | resolve(window.BMap); |
| | | } else { |
| | | reject(new Error("百度地图API加载不完整")); |
| | | } |
| | | }, 100); |
| | | }; |
| | | |
| | | 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); |
| | | script.onerror = (error) => { |
| | | console.error("百度地图API加载失败", error); |
| | | reject(error); |
| | | }; |
| | | document.head.appendChild(script); |
| | | }); |
| | | }, |
| | | /** 查询GPS列表 */ |
| | |
| | | const seconds = String(time.getSeconds()).padStart(2, '0'); |
| | | return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; |
| | | }, |
| | | async translatePoints(points) { |
| | | // 将WGS84坐标转换为百度坐标 |
| | | var translatePoints = []; |
| | | return new Promise((resolve, reject) => { |
| | | /** 初始化地图 */ |
| | | async initMap() { |
| | | try { |
| | | await this.loadBMapScript(); |
| | | // 确保DOM元素已经准备好 |
| | | await this.$nextTick(); |
| | | // 确保BMap对象存在 |
| | | if (!window.BMap || !window.BMap.Map) { |
| | | throw new Error("百度地图API未正确加载"); |
| | | } |
| | | // 创建地图实例 |
| | | this.map = new BMap.Map("mapContainer"); |
| | | // 设置地图中心点和缩放级别 |
| | | this.map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); |
| | | // 启用滚轮放大缩小 |
| | | this.map.enableScrollWheelZoom(); |
| | | console.log("地图初始化成功"); |
| | | return true; |
| | | } catch (error) { |
| | | console.error("地图初始化失败", error); |
| | | this.$message.error("地图加载失败,请刷新页面重试"); |
| | | return false; |
| | | } |
| | | }, |
| | | /** 坐标转换方法 */ |
| | | translatePoint(point) { |
| | | return new Promise((resolve) => { |
| | | // 使用百度地图API内置的坐标转换 |
| | | const convertor = new BMap.Convertor(); |
| | | convertor.translate(points, 1, 5, (data) => { |
| | | const pointArr = []; |
| | | pointArr.push(point); |
| | | convertor.translate(pointArr, 1, 5, (data) => { |
| | | if (data.status === 0) { |
| | | translatePoints = data.points; |
| | | resolve(translatePoints); |
| | | resolve(data.points[0]); |
| | | } else { |
| | | // 如果转换失败,返回原始坐标 |
| | | resolve(point); |
| | | } |
| | | }); |
| | | }); |
| | | }, |
| | | /** 批量坐标转换 */ |
| | | async translatePoints(points) { |
| | | const translatePoints = []; |
| | | for (const point of points) { |
| | | const translatedPoint = await this.translatePoint(point); |
| | | translatePoints.push(translatedPoint); |
| | | } |
| | | return translatePoints; |
| | | }, |
| | | /** 搜索按钮操作 */ |
| | | handleQuery() { |
| | |
| | | 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(); |
| | | console.log("initMap 初始化地图") |
| | | /** 计算两点之间的距离(米) */ |
| | | getDistance(point1, point2) { |
| | | return this.map.getDistance(point1, point2); |
| | | }, |
| | | /** 计算两点之间的距离(米) */ |
| | | 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; |
| | | }, |
| | | |
| | | |
| | | |
| | | /** 计算两点之间的角度 */ |
| | | getAngle(point1, point2) { |
| | | const dx = point2.lng - point1.lng; |
| | | const dy = point2.lat - point1.lat; |
| | | return Math.atan2(dy, dx) * 180 / Math.PI; |
| | | }, |
| | | /** 绘制轨迹 */ |
| | | 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) { |
| | | // 确保地图实例存在 |
| | | if (!this.map) { |
| | | console.error("地图实例未初始化"); |
| | | return; |
| | | } |
| | | |
| | | // 按时间排序 |
| | | this.gpsList.sort((a, b) => { |
| | | return new Date(a.collectTime) - new Date(b.collectTime); |
| | | }); |
| | | try { |
| | | // 清除之前的轨迹 |
| | | if (this.polyline) { |
| | | this.map.removeOverlay(this.polyline); |
| | | } |
| | | this.markers.forEach((marker) => { |
| | | this.map.removeOverlay(marker); |
| | | }); |
| | | this.markers = []; |
| | | |
| | | // 计算当前段落的起始和结束索引 |
| | | const startIndex = this.segmentIndex * this.segmentSize; |
| | | const endIndex = Math.min( |
| | | startIndex + this.segmentSize, |
| | | this.gpsList.length |
| | | ); |
| | | const currentSegment = this.gpsList.slice(startIndex, endIndex); |
| | | if (this.gpsList.length === 0) { |
| | | return; |
| | | } |
| | | |
| | | //先获得所有坐标数组 |
| | | 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); |
| | | // 按时间排序 |
| | | this.gpsList.sort((a, b) => { |
| | | return new Date(a.collectTime) - new Date(b.collectTime); |
| | | }); |
| | | |
| | | // 创建轨迹点数组 |
| | | const points = translatePoints; |
| | | translatePoints.forEach((item, index) => { |
| | | const bdPoint = item; |
| | | // 计算当前段落的起始和结束索引 |
| | | const startIndex = this.segmentIndex * this.segmentSize; |
| | | const endIndex = Math.min( |
| | | startIndex + this.segmentSize, |
| | | this.gpsList.length |
| | | ); |
| | | const currentSegment = this.gpsList.slice(startIndex, endIndex); |
| | | |
| | | // 判断起点和终点是否相同 |
| | | const isStartPoint = index === 0; |
| | | const isEndPoint = index === translatePoints.length - 1; |
| | | const isStartEndSame = isStartPoint && isEndPoint && |
| | | translatePoints[0].lng === translatePoints[translatePoints.length - 1].lng && |
| | | translatePoints[0].lat === translatePoints[translatePoints.length - 1].lat; |
| | | // 获取所有坐标数组 |
| | | 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; |
| | | }); |
| | | |
| | | // 只在起点和终点创建标记,且起点和终点不同时才显示起点标记 |
| | | if ((isStartPoint && !isStartEndSame) || isEndPoint) { |
| | | let marker; |
| | | let direction=currentSegment[index].direction; |
| | | if (isStartPoint && !isStartEndSame) { |
| | | // 起点显示"起"字 |
| | | const label = new BMap.Label("起", { |
| | | offset: new BMap.Size(0, 0), |
| | | // 批量转换坐标 |
| | | const translatePoints = await this.translatePoints(originPoints); |
| | | |
| | | // 创建轨迹点数组 |
| | | const points = translatePoints; |
| | | for (let index = 0; index < translatePoints.length; index++) { |
| | | const bdPoint = translatePoints[index]; |
| | | |
| | | // 判断起点和终点是否相同 |
| | | const isStartPoint = index === 0; |
| | | const isEndPoint = index === translatePoints.length - 1; |
| | | const isStartEndSame = isStartPoint && isEndPoint && |
| | | translatePoints[0].lng === translatePoints[translatePoints.length - 1].lng && |
| | | translatePoints[0].lat === translatePoints[translatePoints.length - 1].lat; |
| | | |
| | | // 只在起点和终点创建标记,且起点和终点不同时才显示起点标记 |
| | | if ((isStartPoint && !isStartEndSame) || isEndPoint) { |
| | | let marker; |
| | | let direction = currentSegment[index].direction; |
| | | if (isStartPoint && !isStartEndSame) { |
| | | // 起点显示"起"字 |
| | | 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 label = new BMap.Label(currentSegment[index].vehicleNo, { |
| | | offset: new BMap.Size(0, -25), |
| | | position: bdPoint, |
| | | }); |
| | | label.setStyle({ |
| | |
| | | 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), |
| | | |
| | | // 获取地址信息 |
| | | const geoc = new BMap.Geocoder(); |
| | | geoc.getLocation(bdPoint, (rs) => { |
| | | if (rs && rs.addressComponents) { |
| | | const addComp = rs.addressComponents; |
| | | const address = |
| | | addComp.province + |
| | | addComp.city + |
| | | addComp.district + |
| | | addComp.street + |
| | | addComp.streetNumber; |
| | | |
| | | // 添加点击事件监听器 |
| | | marker.addEventListener("click", () => { |
| | | // 创建信息窗口 |
| | | const infoWindow = new BMap.InfoWindow( |
| | | `车牌号:${currentSegment[index].vehicleNo}<br/>时间:${currentSegment[index].collectTime}<br/>速度:${ |
| | | currentSegment[index].speed |
| | | }km/h<br/>方向:${currentSegment[index].direction}°<br/>地址:${address}` |
| | | ); |
| | | this.map.openInfoWindow(infoWindow, bdPoint); |
| | | }); |
| | | } |
| | | ); |
| | | marker = new BMap.Marker(bdPoint, { |
| | | icon: myIcon, |
| | | rotation: direction, |
| | | }); |
| | | |
| | | this.map.addOverlay(marker); |
| | | this.markers.push(marker); |
| | | } |
| | | //在车图标上显示车牌 |
| | | const label = new BMap.Label(currentSegment[index].vehicleNo, { |
| | | offset: new BMap.Size(0, -25), // 向上偏移25像素 |
| | | position: bdPoint, |
| | | }); |
| | | label.setStyle({ |
| | | color: "white", |
| | | fontSize: "12px", |
| | | backgroundColor: "#3388ff", |
| | | border: "none", |
| | | padding: "2px 6px", |
| | | borderRadius: "3px", |
| | | }); |
| | | marker.setLabel(label); |
| | | |
| | | // 获取地址信息 |
| | | 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; |
| | | |
| | | // 添加点击事件监听器 |
| | | marker.addEventListener("click", () => { |
| | | // 创建信息窗口 |
| | | const infoWindow = new BMap.InfoWindow( |
| | | `车牌号:${currentSegment[index].vehicleNo}<br/>时间:${currentSegment[index].collectTime}<br/>速度:${ |
| | | currentSegment[index].speed |
| | | }km/h<br/>方向:${currentSegment[index].direction}°<br/>地址:${address}` |
| | | ); |
| | | this.map.openInfoWindow(infoWindow, bdPoint); |
| | | // 如果是最后一个点,绘制轨迹线 |
| | | 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.addOverlay(marker); |
| | | this.markers.push(marker); |
| | | // 调整地图视野以显示完整轨迹 |
| | | this.map.setViewport(points); |
| | | } |
| | | } |
| | | |
| | | // 如果是最后一个点,绘制轨迹线 |
| | | 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); |
| | | } |
| | | }); |
| | | } catch (error) { |
| | | console.error("绘制轨迹失败", error); |
| | | this.$message.error("绘制轨迹失败,请刷新页面重试"); |
| | | } |
| | | }, |
| | | /** 点击表格行 */ |
| | | handleRowClick(row) { |