diff --git a/src/components/device/TrajectoryDialog.vue b/src/components/device/TrajectoryDialog.vue index fe16e38..07be56d 100644 --- a/src/components/device/TrajectoryDialog.vue +++ b/src/components/device/TrajectoryDialog.vue @@ -84,12 +84,12 @@ /> - + - + @@ -116,19 +116,27 @@ import { loadAMap } from "@/utils/loadAMap"; import { loadGoogleMaps } from "@/utils/loadGoogleMaps"; import { loadLeaflet } from "@/utils/loadLeaflet"; +// 轨迹点未加载前,各地图默认中心点。 const AMAP_DEFAULT_CENTER = [121.4737, 31.2304]; const GOOGLE_DEFAULT_CENTER = { lat: 31.2304, lng: 121.4737 }; const LEAFLET_DEFAULT_CENTER = [31.2304, 121.4737]; -const AMAP_FALLBACK_MAX_ZOOM = 20; -const GOOGLE_DETAIL_ZOOM = 21; -const LEAFLET_MAX_ZOOM = 22; -const LEAFLET_GOOGLE_MAX_ZOOM = 20; + +// 各地图默认/详情缩放级别。 +const AMAP_FALLBACK_MAX_ZOOM = 17; +const GOOGLE_DETAIL_ZOOM = 16; +const LEAFLET_MAX_ZOOM = 16; +const LEAFLET_GOOGLE_MAX_ZOOM = 17; + +// Leaflet + Google 瓦片地址与轨迹线样式。 const LEAFLET_GOOGLE_TILE_URL = "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}"; const LEAFLET_LINE_ARROW_MAX = 36; const LEAFLET_SHOW_LINE_ARROWS = false; const LEAFLET_TRAJECTORY_LINE_COLOR = "#1a73e8"; -const CONVERT_BATCH_SIZE = 40; -const MAX_TRAJECTORY_POINTS = 100; + +// 坐标转换与渲染数量上限。 +const CONVERT_BATCH_SIZE = 500; + +// 轨迹压缩阈值(用于减少长时间停留产生的密集点)。 export default { name: "DeviceTrajectoryDialog", @@ -300,22 +308,17 @@ export default { try { const response = await getDeviceTrajectory(this.device.id, this.buildTrajectoryQuery()); const data = Array.isArray(response.data) ? response.data : []; - const validPoints = data - .map((item) => { - const latNum = this.normalizeCoordinate(item.lat, "lat"); - const lngNum = this.normalizeCoordinate(item.lng, "lng"); - return { - ...item, - latNum, - lngNum, - }; - }) - .filter((item) => item.latNum !== null && item.lngNum !== null); - const sortedPoints = validPoints.slice().sort((left, right) => { - return this.getTrackTimestamp(left) - this.getTrackTimestamp(right); + const normalizedPoints = data.map((item) => { + const latNum = this.normalizeCoordinate(item.lat, "lat"); + const lngNum = this.normalizeCoordinate(item.lng, "lng"); + return { + ...item, + latNum, + lngNum, + }; }); - this.totalTrajectoryCount = sortedPoints.length; - this.trajectoryPoints = sortedPoints.slice(-MAX_TRAJECTORY_POINTS); + this.totalTrajectoryCount = normalizedPoints.length; + this.trajectoryPoints = normalizedPoints; } catch (error) { this.trajectoryPoints = []; this.totalTrajectoryCount = 0; @@ -802,8 +805,13 @@ export default { this.map.add(this.polyline); this.map.add(this.markers); - const detailZoom = this.getAmapMaxZoom(); - this.map.setZoomAndCenter(detailZoom, endPoint); + // 多点:自动适配全貌 +if (path.length > 1) { + this.map.setFitView([this.polyline].concat(this.markers), false, [60, 60, 60, 60]); +} else { + // 单点:给一个适中的细节级别 + this.map.setZoomAndCenter(16, startPoint); +} }, renderGoogleTrajectory() { if (!this.map || !this.mapsApi || !this.trajectoryPoints.length) { @@ -1038,26 +1046,34 @@ export default { if (!Array.isArray(this.trajectoryPoints) || !this.trajectoryPoints.length) { return []; } - if (this.trajectoryPoints.length < 2) { - return this.trajectoryPoints.slice(); + const mapPoints = this.trajectoryPoints.filter((item) => item.latNum !== null && item.lngNum !== null); + if (mapPoints.length < 2) { + return mapPoints; } - const firstTs = this.getTrackTimestamp(this.trajectoryPoints[0]); - const lastTs = this.getTrackTimestamp(this.trajectoryPoints[this.trajectoryPoints.length - 1]); - if (firstTs > 0 && lastTs > 0 && firstTs > lastTs) { - return this.trajectoryPoints.slice().reverse(); + const firstTime = this.getTrackTimestamp(mapPoints[0]); + const lastTime = this.getTrackTimestamp(mapPoints[mapPoints.length - 1]); + if (firstTime > 0 && lastTime > 0 && firstTime > lastTime) { + return mapPoints.slice().reverse(); } - return this.trajectoryPoints.slice(); + return mapPoints; }, getTrackTimestamp(point) { if (!point) { return 0; } - const value = point.locationTime || point.reportedTime || point.createTime; - if (!value) { + const rawValue = point.locationTime || point.reportedTime || point.createTime; + if (rawValue === undefined || rawValue === null || rawValue === "") { + return 0; + } + if (typeof rawValue === "number") { + return Number.isFinite(rawValue) ? rawValue : 0; + } + const text = String(rawValue).trim(); + if (!text) { return 0; } - const timestamp = new Date(value).getTime(); - return Number.isFinite(timestamp) ? timestamp : 0; + const parsed = new Date(text.replace(/-/g, "/")).getTime(); + return Number.isFinite(parsed) ? parsed : 0; }, escapeHtml(value) { return String(value) diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 50898b4..cd83ed5 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -271,17 +271,12 @@ - - - +