| | |
| | | // 查询参数 |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | pageSize: 1000, |
| | | deviceId: null, |
| | | appId: null, |
| | | sign: null, |
| | |
| | | this.queryParams.vehicleNo = query.vehicleNo; |
| | | } |
| | | |
| | | // 设置时间范围 |
| | | // 设置默认时间范围 |
| | | 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((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列表 */ |
| | | getList() { |
| | | this.loading = true; |
| | | listGps(this.addDateRange(this.queryParams, this.dateRange)).then(response => { |
| | | // 构建查询参数 |
| | | const params = { |
| | | ...this.queryParams |
| | | }; |
| | | |
| | | // 如果没有选择时间范围,则默认使用当天 |
| | | 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); |
| | | } else { |
| | | params.beginTime = this.dateRange[0]; |
| | | params.endTime = this.dateRange[1]; |
| | | } |
| | | |
| | | listGps(params).then(response => { |
| | | this.gpsList = response.rows; |
| | | this.total = response.total; |
| | | this.loading = false; |
| | |
| | | } |
| | | }); |
| | | }, |
| | | async translatePoints(points) { |
| | | // 将WGS84坐标转换为百度坐标 |
| | | var translatePoints = []; |
| | | return new Promise((resolve, reject) => { |
| | | /** 格式化时间 */ |
| | | parseTime(time) { |
| | | const year = time.getFullYear(); |
| | | const month = String(time.getMonth() + 1).padStart(2, '0'); |
| | | const day = String(time.getDate()).padStart(2, '0'); |
| | | const hours = String(time.getHours()).padStart(2, '0'); |
| | | const minutes = String(time.getMinutes()).padStart(2, '0'); |
| | | const seconds = String(time.getSeconds()).padStart(2, '0'); |
| | | return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; |
| | | }, |
| | | /** 初始化地图 */ |
| | | 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() { |
| | |
| | | }, |
| | | /** 重置按钮操作 */ |
| | | resetQuery() { |
| | | this.dateRange = []; |
| | | // 重置为当天时间范围 |
| | | 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)]; |
| | | 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) { |