diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 48d3bcd..2690139 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -201,7 +201,7 @@ packages:
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
- vite: ^5.0.0 || ^6.0.0 || ^7.0.0
+ vite: npm:rolldown-vite@7.2.5
vue: ^3.2.25
'@vue/compiler-core@3.5.25':
diff --git a/src/App.vue b/src/App.vue
index bee00b7..cad9d01 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -88,8 +88,7 @@
class="fence-item"
>
- {{ getTypeName(fence.type) }}
- #{{ fence.id.slice(0, 8) }}
+ {{ fence.name || '未命名围栏' }}
{
AMap = await AMapLoader.load({
key: mapKey,
version: '2.0',
- plugins: ['AMap.MouseTool', 'AMap.Polygon', 'AMap.Rectangle', 'AMap.Circle', 'AMap.Marker', 'AMap.Icon']
+ plugins: ['AMap.MouseTool', 'AMap.Polygon', 'AMap.Rectangle', 'AMap.Circle', 'AMap.Marker', 'AMap.Icon', 'AMap.Text']
})
// 创建地图实例
@@ -520,25 +519,17 @@ const handleDrawComplete = (event) => {
}
if (fence) {
- // 设置围栏样式
- if (fence.shape.setOptions) {
- fence.shape.setOptions({
- strokeColor: '#0066FF',
- strokeWeight: 2,
- strokeOpacity: 0.8,
- fillColor: '#0066FF',
- fillOpacity: 0.15,
- zIndex: 50
- })
- }
-
// 注意:使用MouseTool绘制的对象已经自动添加到地图上
// 如果对象还没有添加到地图,则添加它
if (!fence.shape.getMap()) {
map.add(fence.shape)
}
- // 保存围栏
+ // 先设置默认名称,确保列表能立即显示
+ const defaultName = `${getTypeName(fence.type)}_${fences.value.length + 1}`
+ fence.name = defaultName
+
+ // 保存围栏到列表(立即显示)
fences.value.push(fence)
// 关闭绘制工具,确保不能再继续绘制
@@ -547,25 +538,36 @@ const handleDrawComplete = (event) => {
mouseTool.close() // 关闭绘制工具,但不删除已绘制的图形
}
- // 确保图形显示(延迟设置,确保mouseTool关闭后图形仍然存在)
- setTimeout(() => {
- if (fence.shape && fence.shape.getMap()) {
- // 重新设置样式确保显示
- fence.shape.setOptions({
- strokeColor: '#0066FF',
- strokeWeight: 2,
- strokeOpacity: 0.8,
- fillColor: '#0066FF',
- fillOpacity: 0.15,
- zIndex: 50,
- visible: true // 确保可见
- })
- // 确保在地图上
- if (!fence.shape.getMap()) {
- map.add(fence.shape)
+ // 先更新样式和标签(使用默认名称)
+ updateFenceStyleAndLabel(fence)
+
+ // 获取当前围栏在数组中的索引,用于后续更新
+ const fenceIndex = fences.value.length - 1
+
+ // 弹出输入框让用户输入围栏名称(异步,不阻塞列表显示)
+ ElMessageBox.prompt('请输入围栏名称', '围栏命名', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ inputPlaceholder: '请输入围栏名称',
+ inputValue: defaultName,
+ inputValidator: (value) => {
+ if (!value || value.trim() === '') {
+ return '围栏名称不能为空'
}
+ return true
}
- }, 50)
+ }).then(({ value }) => {
+ // 用户输入了名称,通过数组索引更新,确保Vue响应式系统能检测到变化
+ const newName = value.trim()
+ if (fences.value[fenceIndex]) {
+ fences.value[fenceIndex].name = newName
+ // 更新标签
+ addFenceLabel(fences.value[fenceIndex])
+ }
+ }).catch(() => {
+ // 用户取消,保持默认名称(已经在上面设置了)
+ // 不需要额外操作,标签已经用默认名称创建了
+ })
// 重置绘制状态
isDrawing.value = false
@@ -575,6 +577,112 @@ const handleDrawComplete = (event) => {
}
}
+// 更新围栏样式和标签
+const updateFenceStyleAndLabel = (fence) => {
+ // 设置围栏样式
+ if (fence.shape.setOptions) {
+ fence.shape.setOptions({
+ strokeColor: '#0066FF',
+ strokeWeight: 2,
+ strokeOpacity: 0.8,
+ fillColor: '#0066FF',
+ fillOpacity: 0.15,
+ zIndex: 50,
+ visible: true
+ })
+ }
+
+ // 确保在地图上
+ if (!fence.shape.getMap()) {
+ map.add(fence.shape)
+ }
+
+ // 添加围栏名称标签到地图上
+ addFenceLabel(fence)
+}
+
+// 添加围栏名称标签
+const addFenceLabel = (fence) => {
+ if (!map || !AMap || !fence.name) return
+
+ // 移除旧的标签(如果存在)
+ if (fence.label) {
+ map.remove(fence.label)
+ }
+
+ // 计算标签位置
+ let labelPosition = null
+
+ if (fence.type === 'polygon') {
+ // 多边形:使用bounds的右上角(东北角)
+ const bounds = fence.shape.getBounds ? fence.shape.getBounds() : null
+ if (bounds) {
+ const ne = bounds.getNorthEast()
+ labelPosition = [ne.getLng(), ne.getLat()]
+ } else {
+ // 如果没有bounds,使用第一个顶点
+ const path = fence.shape.getPath ? fence.shape.getPath() : fence.path
+ if (path && path.length > 0) {
+ const firstPoint = path[0]
+ if (Array.isArray(firstPoint)) {
+ labelPosition = firstPoint
+ } else if (firstPoint.getLng && firstPoint.getLat) {
+ labelPosition = [firstPoint.getLng(), firstPoint.getLat()]
+ } else {
+ labelPosition = [firstPoint.lng || firstPoint[0], firstPoint.lat || firstPoint[1]]
+ }
+ }
+ }
+ } else if (fence.type === 'rectangle') {
+ // 矩形:使用bounds的右上角(东北角)
+ const bounds = fence.shape.getBounds ? fence.shape.getBounds() : fence.bounds
+ if (bounds) {
+ const ne = bounds.getNorthEast()
+ labelPosition = [ne.getLng(), ne.getLat()]
+ }
+ } else if (fence.type === 'circle') {
+ // 圆形:使用圆心,然后向上偏移到右上角位置
+ const center = fence.shape.getCenter ? fence.shape.getCenter() : fence.center
+ const radius = fence.shape.getRadius ? fence.shape.getRadius() : fence.radius
+ if (center) {
+ let centerLng, centerLat
+ if (center.getLng && center.getLat) {
+ centerLng = center.getLng()
+ centerLat = center.getLat()
+ } else {
+ centerLng = center.lng || center[0]
+ centerLat = center.lat || center[1]
+ }
+ // 计算右上角位置(圆心 + 半径的偏移)
+ const offset = radius / 111320 // 转换为经纬度偏移
+ labelPosition = [centerLng + offset, centerLat + offset]
+ }
+ }
+
+ if (labelPosition) {
+ // 创建文本标签,位置在右上角
+ const label = new AMap.Text({
+ text: fence.name,
+ position: labelPosition,
+ offset: new AMap.Pixel(-10, -10), // 偏移到右上角
+ style: {
+ padding: '4px 8px',
+ backgroundColor: 'rgba(0, 102, 255, 0.6)', // 半透明背景
+ border: '1px solid rgba(0, 102, 255, 0.8)',
+ borderRadius: '4px',
+ fontSize: '12px',
+ color: '#fff',
+ fontWeight: 'bold',
+ whiteSpace: 'nowrap'
+ },
+ zIndex: 100
+ })
+
+ map.add(label)
+ fence.label = label
+ }
+}
+
// 开始绘制多边形
const startDrawPolygon = () => {
if (!mouseTool) return
@@ -803,6 +911,10 @@ const removeFence = (fenceId) => {
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
if (currentMap) {
currentMap.remove(fence.shape)
+ // 同时移除标签
+ if (fence.label) {
+ currentMap.remove(fence.label)
+ }
}
} catch (error) {
console.error('删除围栏时出错:', error)
@@ -854,6 +966,10 @@ const clearAllFences = async () => {
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
if (currentMap) {
currentMap.remove(fence.shape)
+ // 同时移除标签
+ if (fence.label) {
+ currentMap.remove(fence.label)
+ }
}
} catch (error) {
console.error('清除围栏时出错:', error)
@@ -1025,6 +1141,13 @@ onUnmounted(() => {
font-weight: 500;
}
+.fence-name {
+ font-size: 12px;
+ color: #333;
+ font-weight: 500;
+ margin-left: 4px;
+}
+
.drone-status-panel {
margin-top: 16px;
margin-bottom: 16px;