集成百度鹰眼服务AK

This commit is contained in:
xuqiuyun
2025-11-21 17:22:20 +08:00
parent 73051df002
commit 0f963bf535
57 changed files with 6036 additions and 685 deletions

View File

@@ -6,6 +6,20 @@
:close-on-click-modal="false"
@close="handleClose"
>
<!-- 轨迹定位按钮 -->
<template #header>
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>{{ dialogTitle }}</span>
<el-button
type="primary"
:icon="Location"
@click="handleTrackClick"
:disabled="!warningData.deliveryId"
>
轨迹定位
</el-button>
</div>
</template>
<!-- 温度预警 - 只显示设备信息不显示地图 -->
<div v-if="isTemperatureWarning" class="warning-content temperature-warning">
<!-- 预警基本信息 -->
@@ -54,6 +68,10 @@
<!-- 绑定设备列表 -->
<div v-if="deviceList.length > 0" class="device-list-section">
<!-- 调试信息开发环境可显示 -->
<div v-if="false" style="font-size: 12px; color: #909399; margin-bottom: 10px;">
调试设备数量={{ deviceList.length }}, deliveryId={{ warningData.deliveryId }}
</div>
<div class="section-header">
<h4>
<el-icon style="vertical-align: middle;"><Connection /></el-icon>
@@ -90,8 +108,16 @@
</el-table-column>
</el-table>
</div>
<div v-else class="no-data-tip">
<div v-else-if="!loadingDevices" class="no-data-tip">
<el-empty description="暂无绑定设备信息" :image-size="80" />
<div style="margin-top: 10px; font-size: 12px; color: #909399;">
<p v-if="!warningData.deliveryId">提示运单ID为空无法查询设备</p>
<p v-else>提示该运单可能没有绑定设备或设备已被删除</p>
</div>
</div>
<div v-else class="no-data-tip">
<el-icon class="is-loading"><Loading /></el-icon>
<span style="margin-left: 10px;">正在加载设备列表...</span>
</div>
<!-- 设备温度日志重点显示温度数据 -->
@@ -284,13 +310,118 @@
</span>
</template>
</el-dialog>
<!-- 轨迹定位对话框 -->
<el-dialog
v-model="trackDialogVisible"
title="轨迹定位"
width="1000px"
:close-on-click-modal="false"
@close="handleTrackDialogClose"
>
<div v-loading="trackLoading" style="min-height: 500px;">
<!-- 状态提示 -->
<div v-if="deliveryStatus === 1" class="status-tip">
<el-alert
title="运单尚未开始运输"
description="当前运单状态为准备中,暂无轨迹数据"
type="info"
:closable="false"
show-icon
/>
</div>
<!-- 轨迹地图容器 -->
<div v-else>
<!-- 控制按钮 -->
<div class="track-controls" style="margin-bottom: 15px;">
<el-button
type="primary"
:icon="VideoPlay"
@click="handlePlayTrack"
:disabled="!trackMapShow || trackPath.length === 0"
>
{{ isPlaying ? '暂停' : '播放' }}
</el-button>
<el-button
:icon="Refresh"
@click="handleResetTrack"
:disabled="!trackMapShow || trackPath.length === 0"
>
重置
</el-button>
<el-tag type="info" style="margin-left: 10px;">
轨迹点数{{ trackPath.length }}
</el-tag>
<el-tag type="info" style="margin-left: 10px;">
状态{{ getDeliveryStatusText(deliveryStatus) }}
</el-tag>
</div>
<!-- 地图容器 -->
<div
id="trackMap"
style="width: 100%; height: 500px; border: 1px solid #dcdfe6; border-radius: 4px;"
></div>
<!-- 无轨迹数据提示 -->
<div v-if="!trackMapShow && !trackLoading" class="no-track-tip">
<el-empty description="暂无轨迹数据" :image-size="100" />
</div>
<div v-if="yingyanMeta.entityName" class="track-meta-panel">
<el-descriptions :column="3" border>
<el-descriptions-item label="终端名称">{{ yingyanMeta.entityName }}</el-descriptions-item>
<el-descriptions-item label="查询开始">{{ formatTimestamp(yingyanMeta.startTime) }}</el-descriptions-item>
<el-descriptions-item label="查询结束">{{ formatTimestamp(yingyanMeta.endTime) }}</el-descriptions-item>
</el-descriptions>
</div>
<div v-if="stayPoints.length > 0" class="staypoint-section">
<h4>停留点分析15分钟</h4>
<el-table :data="stayPoints" border style="width: 100%;" size="small">
<el-table-column label="开始时间" min-width="160">
<template #default="scope">
{{ formatTimestamp(scope.row.startTime) }}
</template>
</el-table-column>
<el-table-column label="结束时间" min-width="160">
<template #default="scope">
{{ formatTimestamp(scope.row.endTime) }}
</template>
</el-table-column>
<el-table-column label="停留时长" width="120">
<template #default="scope">
{{ formatDuration(scope.row.duration) }}
</template>
</el-table-column>
<el-table-column label="位置" min-width="160">
<template #default="scope">
{{ `${scope.row.latitude || '--'}, ${scope.row.longitude || '--'}` }}
</template>
</el-table-column>
</el-table>
</div>
<div v-else-if="trackMapShow && !trackLoading" class="no-data-tip">
暂无满足 15 分钟的停留点数据
</div>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="trackDialogVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ref, reactive, computed, nextTick } from 'vue';
import { ref, reactive, computed, nextTick, onUnmounted } from 'vue';
import { ElMessage } from 'element-plus';
import { Location, VideoPlay, Refresh, InfoFilled, Connection, DataLine, Loading } from '@element-plus/icons-vue';
import { BMPGL } from '@/utils/loadBmap.js';
import { pageDeviceList, getCollarLogs, getEarTagLogs, getHostLogs } from '@/api/abroad.js';
import { pageDeviceList, getCollarLogs, getEarTagLogs, getHostLogs, getYingyanTrack, waybillDetail } from '@/api/abroad.js';
const dialogVisible = ref(false);
const warningData = reactive({
@@ -321,6 +452,28 @@ const loadingLogs = ref(false); // 新增:加载日志状态
let mapInstance = null;
let markerInstance = null;
// 轨迹定位相关
const trackDialogVisible = ref(false);
const trackLoading = ref(false);
const trackMapShow = ref(false);
const trackPath = ref([]); // 轨迹点数组
const trackMapInstance = ref(null); // 轨迹地图实例
const trackPolyline = ref(null); // 轨迹线条
const trackStartMarker = ref(null); // 起点标记
const trackEndMarker = ref(null); // 终点标记
const trackPlayMarker = ref(null); // 播放位置标记
const deliveryStatus = ref(null); // 运输状态1-准备中2-运输中3-已结束
const isPlaying = ref(false); // 是否正在播放
const playTimer = ref(null); // 播放定时器
const currentPlayIndex = ref(0); // 当前播放到的轨迹点索引
const trackBMapGL = ref(null); // 保存 BMapGL 实例,避免重复加载
const stayPoints = ref([]); // 停留点列表
const yingyanMeta = reactive({
entityName: '',
startTime: null,
endTime: null
});
// 计算属性:判断预警类型
const isTemperatureWarning = computed(() => {
// 5-高温预警6-低温预警
@@ -344,6 +497,7 @@ const dialogTitle = computed(() => {
// 打开对话框
const open = async (row) => {
console.log('[WARNING-DETAIL] 打开预警详情对话框,原始数据:', row);
// 填充数据
Object.keys(warningData).forEach(key => {
@@ -352,12 +506,18 @@ const open = async (row) => {
}
});
console.log('[WARNING-DETAIL] 填充后的 warningData:', warningData);
console.log('[WARNING-DETAIL] deliveryId:', warningData.deliveryId);
dialogVisible.value = true;
// ✅ 查询运单绑定的设备列表
if (warningData.deliveryId) {
console.log('[WARNING-DETAIL] 开始加载设备列表deliveryId:', warningData.deliveryId);
await loadDeviceList(warningData.deliveryId);
} else {
console.warn('[WARNING-DETAIL] 警告deliveryId 为空,无法加载设备列表');
console.warn('[WARNING-DETAIL] 请检查预警详情 API 是否返回了 deliveryId 字段');
}
// 如果是位置相关预警,加载地图
@@ -379,6 +539,11 @@ const loadDeviceList = async (deliveryId) => {
loadingDevices.value = true;
try {
console.log('[WARNING-DETAIL] 调用 pageDeviceList API参数:', {
deliveryId: deliveryId,
pageNum: 1,
pageSize: 100
});
const res = await pageDeviceList({
deliveryId: deliveryId,
@@ -386,22 +551,41 @@ const loadDeviceList = async (deliveryId) => {
pageSize: 100, // 一次性加载所有设备
});
console.log('[WARNING-DETAIL] pageDeviceList API 返回结果:', res);
if (res.code === 200 && res.data) {
// ✅ 修复:后端直接返回数组,不是嵌套在 list 或 rows 中
let devices = [];
if (Array.isArray(res.data)) {
deviceList.value = res.data;
devices = res.data;
} else {
deviceList.value = res.data.list || res.data.rows || [];
devices = res.data.list || res.data.rows || [];
}
console.log('[WARNING-DETAIL] 解析后的设备列表:', devices);
console.log('[WARNING-DETAIL] 设备数量:', devices.length);
deviceList.value = devices;
// 自动加载所有设备的日志
await loadAllDeviceLogs();
if (devices.length === 0) {
console.warn('[WARNING-DETAIL] 警告:设备列表为空');
console.warn('[WARNING-DETAIL] 可能原因:');
console.warn('[WARNING-DETAIL] 1. 该运单确实没有绑定设备');
console.warn('[WARNING-DETAIL] 2. 设备被标记为已删除is_delet=1');
console.warn('[WARNING-DETAIL] 3. 设备表中的 delivery_id 字段为空或不匹配');
ElMessage.warning('该运单暂无绑定设备');
} else {
console.log('[WARNING-DETAIL] 成功加载设备列表,设备数量:', devices.length);
// 自动加载所有设备的日志
await loadAllDeviceLogs();
}
} else {
console.error('[WARNING-DETAIL] API 返回错误:', res);
ElMessage.warning('加载设备列表失败:' + (res.msg || '未知错误'));
}
} catch (error) {
console.error('[WARNING-DETAIL] 加载设备列表失败:', error);
ElMessage.error('加载设备列表失败');
console.error('[WARNING-DETAIL] 加载设备列表异常:', error);
ElMessage.error('加载设备列表失败' + (error.message || '网络错误'));
} finally {
loadingDevices.value = false;
}
@@ -586,6 +770,52 @@ const getWarningTagType = (type) => {
}
};
const normalizeTimestamp = (value) => {
if (value === null || value === undefined || value === '') {
return null;
}
const num = Number(value);
if (Number.isNaN(num)) {
return null;
}
return num < 1e12 ? num * 1000 : num;
};
const formatTimestamp = (value) => {
const ms = normalizeTimestamp(value);
if (!ms) return '--';
const date = new Date(ms);
if (Number.isNaN(date.getTime())) {
return '--';
}
const pad = (num) => `${num}`.padStart(2, '0');
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
};
const formatDuration = (seconds) => {
if (seconds === null || seconds === undefined) {
return '--';
}
const total = Number(seconds);
if (Number.isNaN(total) || total <= 0) {
return '--';
}
const hours = Math.floor(total / 3600);
const minutes = Math.floor((total % 3600) / 60);
const sec = Math.floor(total % 60);
const parts = [];
if (hours > 0) {
parts.push(`${hours}小时`);
}
if (minutes > 0) {
parts.push(`${minutes}分钟`);
}
if (sec > 0 && hours === 0) {
parts.push(`${sec}`);
}
return parts.join('') || `${sec}`;
};
// 关闭对话框
const handleClose = () => {
// 清理地图实例
@@ -614,6 +844,436 @@ const handleClose = () => {
});
};
// 轨迹定位按钮点击
const handleTrackClick = async () => {
if (!warningData.deliveryId) {
ElMessage.warning('运单ID不存在无法查看轨迹');
return;
}
trackDialogVisible.value = true;
trackLoading.value = true;
trackMapShow.value = false;
trackPath.value = [];
isPlaying.value = false;
currentPlayIndex.value = 0;
// 获取运单运输状态
await getDeliveryStatus();
// 如果状态为准备中,直接返回
if (deliveryStatus.value === 1) {
trackLoading.value = false;
return;
}
await loadYingyanTrack();
if (trackPath.value.length === 0) {
trackLoading.value = false;
return;
}
// 初始化地图
await nextTick();
await initTrackMap();
};
// 获取运送清单运输状态
const getDeliveryStatus = async () => {
// 先检查 warningData 中是否包含 status
if (warningData.status !== undefined && warningData.status !== null) {
// 注意:这里的 status 可能是业务状态1-7需要判断是否是运输状态1-3
// 如果 status 在 1-3 范围内,可能是运输状态
const status = parseInt(warningData.status);
if (status >= 1 && status <= 3) {
deliveryStatus.value = status;
return;
}
}
// 如果没有,通过 API 获取运单详情
try {
const res = await waybillDetail(warningData.deliveryId);
if (res.code === 200 && res.data) {
const delivery = res.data.delivery || res.data;
// 注意Delivery 实体中的 status 是业务状态1-7不是运输状态
// 需要查看是否有专门的运输状态字段,或者根据业务状态推断
// 这里先假设 status 字段就是运输状态,如果不对需要调整
deliveryStatus.value = delivery.status || null;
}
} catch (error) {
console.error('[TRACK] 获取运单状态失败:', error);
// 默认设置为运输中,允许查看轨迹
deliveryStatus.value = 2;
}
};
// 加载百度鹰眼轨迹与停留点
const loadYingyanTrack = async () => {
stayPoints.value = [];
trackPath.value = [];
trackMapShow.value = false;
yingyanMeta.entityName = '';
yingyanMeta.startTime = null;
yingyanMeta.endTime = null;
if (!warningData.deliveryId) {
ElMessage.warning('运单ID缺失无法查询轨迹');
return;
}
try {
const res = await getYingyanTrack({ deliveryId: warningData.deliveryId });
if (res.code === 200 && res.data) {
const rawPoints = Array.isArray(res.data.trackPoints) ? res.data.trackPoints : [];
trackPath.value = rawPoints
.map(item => {
const lng = parseFloat(item.longitude ?? item.lng ?? 0);
const lat = parseFloat(item.latitude ?? item.lat ?? 0);
if (Number.isNaN(lng) || Number.isNaN(lat) || lng === 0 || lat === 0) {
return null;
}
return {
lng,
lat,
locTime: item.locTime
};
})
.filter(Boolean);
stayPoints.value = Array.isArray(res.data.stayPoints) ? res.data.stayPoints : [];
yingyanMeta.entityName = res.data.entityName || '';
yingyanMeta.startTime = res.data.startTime || null;
yingyanMeta.endTime = res.data.endTime || null;
if (trackPath.value.length > 0) {
trackMapShow.value = true;
} else {
ElMessage.warning('暂无有效轨迹点');
}
} else {
ElMessage.warning(res.msg || '暂无轨迹数据');
}
} catch (error) {
console.error('[TRACK] 加载百度鹰眼轨迹失败:', error);
ElMessage.error('加载轨迹数据失败');
}
};
// 初始化轨迹地图
const initTrackMap = async () => {
if (trackPath.value.length === 0) {
return;
}
try {
const BMapGL = await BMPGL('fLz8UwJSM3ayYl6dtsWYp7TQ8993R6kC');
trackBMapGL.value = BMapGL; // 保存 BMapGL 实例
// 创建地图实例
trackMapInstance.value = new BMapGL.Map('trackMap');
// 计算地图中心点和缩放级别
const bounds = calculateBounds(trackPath.value);
const centerPoint = new BMapGL.Point(bounds.center.lng, bounds.center.lat);
trackMapInstance.value.centerAndZoom(centerPoint, bounds.zoom);
trackMapInstance.value.enableScrollWheelZoom(true);
// 根据状态绘制轨迹
if (deliveryStatus.value === 3) {
// 已结束:静态轨迹
drawStaticTrack(BMapGL);
} else if (deliveryStatus.value === 2) {
// 运输中:动态轨迹(先绘制已有部分)
drawDynamicTrack(BMapGL);
}
trackLoading.value = false;
} catch (error) {
console.error('[TRACK] 地图初始化失败:', error);
ElMessage.error('地图加载失败');
trackLoading.value = false;
}
};
// 计算轨迹边界
const calculateBounds = (points) => {
if (points.length === 0) {
return { center: { lng: 116.404, lat: 39.915 }, zoom: 15 };
}
let minLng = points[0].lng;
let maxLng = points[0].lng;
let minLat = points[0].lat;
let maxLat = points[0].lat;
points.forEach(point => {
minLng = Math.min(minLng, point.lng);
maxLng = Math.max(maxLng, point.lng);
minLat = Math.min(minLat, point.lat);
maxLat = Math.max(maxLat, point.lat);
});
const center = {
lng: (minLng + maxLng) / 2,
lat: (minLat + maxLat) / 2
};
// 计算缩放级别(简单估算)
const lngDiff = maxLng - minLng;
const latDiff = maxLat - minLat;
const maxDiff = Math.max(lngDiff, latDiff);
let zoom = 15;
if (maxDiff > 0.1) zoom = 10;
else if (maxDiff > 0.05) zoom = 11;
else if (maxDiff > 0.02) zoom = 12;
else if (maxDiff > 0.01) zoom = 13;
else if (maxDiff > 0.005) zoom = 14;
return { center, zoom };
};
// 绘制静态轨迹(已结束)
const drawStaticTrack = (BMapGL) => {
if (!trackMapInstance.value || trackPath.value.length === 0) {
return;
}
// 清除之前的覆盖物
trackMapInstance.value.clearOverlays();
// 绘制轨迹线
const polyline = new BMapGL.Polyline(
trackPath.value.map(p => new BMapGL.Point(p.lng, p.lat)),
{
strokeColor: '#3388ff',
strokeWeight: 4,
strokeOpacity: 0.8
}
);
trackMapInstance.value.addOverlay(polyline);
trackPolyline.value = polyline;
// 添加起点标记
if (trackPath.value.length > 0) {
const startPoint = new BMapGL.Point(trackPath.value[0].lng, trackPath.value[0].lat);
// 使用简单的圆形标记作为起点(绿色)
const startMarker = new BMapGL.Marker(startPoint, {
icon: new BMapGL.Icon(
'http://api.map.baidu.com/images/marker_red.png',
new BMapGL.Size(32, 32),
{ anchor: new BMapGL.Size(16, 32) }
)
});
trackMapInstance.value.addOverlay(startMarker);
trackStartMarker.value = startMarker;
// 起点信息窗口
const startInfoWindow = new BMapGL.InfoWindow(
'<div style="padding: 5px;"><strong style="color: #67c23a;">起点</strong></div>',
{ width: 80, height: 30 }
);
startMarker.addEventListener('click', () => {
trackMapInstance.value.openInfoWindow(startInfoWindow, startPoint);
});
}
// 添加终点标记
if (trackPath.value.length > 1) {
const endPoint = new BMapGL.Point(
trackPath.value[trackPath.value.length - 1].lng,
trackPath.value[trackPath.value.length - 1].lat
);
// 使用红色标记作为终点
const endMarker = new BMapGL.Marker(endPoint, {
icon: new BMapGL.Icon(
'http://api.map.baidu.com/images/marker_red.png',
new BMapGL.Size(32, 32),
{ anchor: new BMapGL.Size(16, 32) }
)
});
trackMapInstance.value.addOverlay(endMarker);
trackEndMarker.value = endMarker;
// 终点信息窗口
const endInfoWindow = new BMapGL.InfoWindow(
'<div style="padding: 5px;"><strong style="color: #f56c6c;">终点</strong></div>',
{ width: 80, height: 30 }
);
endMarker.addEventListener('click', () => {
trackMapInstance.value.openInfoWindow(endInfoWindow, endPoint);
});
}
};
// 绘制动态轨迹(运输中)
const drawDynamicTrack = (BMapGL) => {
if (!trackMapInstance.value || trackPath.value.length === 0) {
return;
}
// 清除之前的覆盖物
trackMapInstance.value.clearOverlays();
// 绘制已有轨迹线
const polyline = new BMapGL.Polyline(
trackPath.value.map(p => new BMapGL.Point(p.lng, p.lat)),
{
strokeColor: '#3388ff',
strokeWeight: 4,
strokeOpacity: 0.6
}
);
trackMapInstance.value.addOverlay(polyline);
trackPolyline.value = polyline;
// 添加起点标记
if (trackPath.value.length > 0) {
const startPoint = new BMapGL.Point(trackPath.value[0].lng, trackPath.value[0].lat);
const startMarker = new BMapGL.Marker(startPoint, {
icon: new BMapGL.Icon(
'http://api.map.baidu.com/images/marker_red.png',
new BMapGL.Size(32, 32),
{ anchor: new BMapGL.Size(16, 32) }
)
});
trackMapInstance.value.addOverlay(startMarker);
trackStartMarker.value = startMarker;
}
// 添加当前位置标记(用于动画)
const currentPoint = new BMapGL.Point(trackPath.value[0].lng, trackPath.value[0].lat);
const playMarker = new BMapGL.Marker(currentPoint, {
icon: new BMapGL.Icon(
'http://api.map.baidu.com/images/marker_red.png',
new BMapGL.Size(20, 20),
{ anchor: new BMapGL.Size(10, 20) }
)
});
trackMapInstance.value.addOverlay(playMarker);
trackPlayMarker.value = playMarker;
currentPlayIndex.value = 0;
};
// 播放轨迹动画
const handlePlayTrack = () => {
if (trackPath.value.length === 0 || !trackMapInstance.value) {
return;
}
if (isPlaying.value) {
// 暂停
if (playTimer.value) {
clearInterval(playTimer.value);
playTimer.value = null;
}
isPlaying.value = false;
} else {
// 播放
if (currentPlayIndex.value >= trackPath.value.length - 1) {
// 如果已经播放完,重新开始
currentPlayIndex.value = 0;
}
isPlaying.value = true;
playTimer.value = setInterval(() => {
if (currentPlayIndex.value < trackPath.value.length - 1) {
currentPlayIndex.value++;
updatePlayMarker();
} else {
// 播放完成
if (playTimer.value) {
clearInterval(playTimer.value);
playTimer.value = null;
}
isPlaying.value = false;
}
}, 200); // 每200ms移动一次
}
};
// 更新播放位置标记
const updatePlayMarker = () => {
if (!trackMapInstance.value || !trackPlayMarker.value || !trackBMapGL.value || currentPlayIndex.value >= trackPath.value.length) {
return;
}
const point = trackPath.value[currentPlayIndex.value];
const bdPoint = new trackBMapGL.value.Point(point.lng, point.lat);
trackPlayMarker.value.setPosition(bdPoint);
// 地图跟随
trackMapInstance.value.panTo(bdPoint);
};
// 重置轨迹动画
const handleResetTrack = () => {
if (playTimer.value) {
clearInterval(playTimer.value);
playTimer.value = null;
}
isPlaying.value = false;
currentPlayIndex.value = 0;
if (trackPlayMarker.value && trackPath.value.length > 0 && trackMapInstance.value && trackBMapGL.value) {
const point = trackPath.value[0];
const bdPoint = new trackBMapGL.value.Point(point.lng, point.lat);
trackPlayMarker.value.setPosition(bdPoint);
trackMapInstance.value.panTo(bdPoint);
}
};
// 获取运输状态文本
const getDeliveryStatusText = (status) => {
const statusMap = {
1: '准备中',
2: '运输中',
3: '已结束'
};
return statusMap[status] || '未知';
};
// 关闭轨迹对话框
const handleTrackDialogClose = () => {
// 清理定时器
if (playTimer.value) {
clearInterval(playTimer.value);
playTimer.value = null;
}
// 清理地图实例
if (trackMapInstance.value) {
trackMapInstance.value.clearOverlays();
trackMapInstance.value = null;
}
trackPolyline.value = null;
trackStartMarker.value = null;
trackEndMarker.value = null;
trackPlayMarker.value = null;
trackBMapGL.value = null;
isPlaying.value = false;
currentPlayIndex.value = 0;
trackPath.value = [];
trackMapShow.value = false;
stayPoints.value = [];
yingyanMeta.entityName = '';
yingyanMeta.startTime = null;
yingyanMeta.endTime = null;
};
// 组件卸载时清理
onUnmounted(() => {
if (playTimer.value) {
clearInterval(playTimer.value);
}
if (trackMapInstance.value) {
trackMapInstance.value.clearOverlays();
}
});
// 导出方法
defineExpose({
open
@@ -676,6 +1336,21 @@ defineExpose({
}
}
.track-meta-panel {
margin-top: 20px;
}
.staypoint-section {
margin-top: 20px;
h4 {
margin: 0 0 10px 0;
font-size: 15px;
color: #303133;
font-weight: 600;
}
}
.map-container {
margin-top: 20px;
@@ -721,5 +1396,24 @@ defineExpose({
font-size: 12px;
}
}
// 轨迹对话框样式
.status-tip {
margin-bottom: 20px;
}
.track-controls {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.no-track-tip {
display: flex;
align-items: center;
justify-content: center;
height: 500px;
}
</style>