feat:增加围栏名称
This commit is contained in:
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@@ -201,7 +201,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
|
resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
|
||||||
engines: {node: ^20.19.0 || >=22.12.0}
|
engines: {node: ^20.19.0 || >=22.12.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
|
vite: npm:rolldown-vite@7.2.5
|
||||||
vue: ^3.2.25
|
vue: ^3.2.25
|
||||||
|
|
||||||
'@vue/compiler-core@3.5.25':
|
'@vue/compiler-core@3.5.25':
|
||||||
|
|||||||
189
src/App.vue
189
src/App.vue
@@ -88,8 +88,7 @@
|
|||||||
class="fence-item"
|
class="fence-item"
|
||||||
>
|
>
|
||||||
<span class="fence-info">
|
<span class="fence-info">
|
||||||
<span class="fence-type">{{ getTypeName(fence.type) }}</span>
|
<span class="fence-name">{{ fence.name || '未命名围栏' }}</span>
|
||||||
#{{ fence.id.slice(0, 8) }}
|
|
||||||
</span>
|
</span>
|
||||||
<div class="fence-actions">
|
<div class="fence-actions">
|
||||||
<el-button
|
<el-button
|
||||||
@@ -164,7 +163,7 @@ const initMap = async () => {
|
|||||||
AMap = await AMapLoader.load({
|
AMap = await AMapLoader.load({
|
||||||
key: mapKey,
|
key: mapKey,
|
||||||
version: '2.0',
|
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']
|
||||||
})
|
})
|
||||||
|
|
||||||
// 创建地图实例
|
// 创建地图实例
|
||||||
@@ -498,25 +497,17 @@ const handleDrawComplete = (event) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fence) {
|
if (fence) {
|
||||||
// 设置围栏样式
|
|
||||||
if (fence.shape.setOptions) {
|
|
||||||
fence.shape.setOptions({
|
|
||||||
strokeColor: '#0066FF',
|
|
||||||
strokeWeight: 2,
|
|
||||||
strokeOpacity: 0.8,
|
|
||||||
fillColor: '#0066FF',
|
|
||||||
fillOpacity: 0.15,
|
|
||||||
zIndex: 50
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注意:使用MouseTool绘制的对象已经自动添加到地图上
|
// 注意:使用MouseTool绘制的对象已经自动添加到地图上
|
||||||
// 如果对象还没有添加到地图,则添加它
|
// 如果对象还没有添加到地图,则添加它
|
||||||
if (!fence.shape.getMap()) {
|
if (!fence.shape.getMap()) {
|
||||||
map.add(fence.shape)
|
map.add(fence.shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存围栏
|
// 先设置默认名称,确保列表能立即显示
|
||||||
|
const defaultName = `${getTypeName(fence.type)}_${fences.value.length + 1}`
|
||||||
|
fence.name = defaultName
|
||||||
|
|
||||||
|
// 保存围栏到列表(立即显示)
|
||||||
fences.value.push(fence)
|
fences.value.push(fence)
|
||||||
|
|
||||||
// 关闭绘制工具,确保不能再继续绘制
|
// 关闭绘制工具,确保不能再继续绘制
|
||||||
@@ -525,25 +516,36 @@ const handleDrawComplete = (event) => {
|
|||||||
mouseTool.close() // 关闭绘制工具,但不删除已绘制的图形
|
mouseTool.close() // 关闭绘制工具,但不删除已绘制的图形
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保图形显示(延迟设置,确保mouseTool关闭后图形仍然存在)
|
// 先更新样式和标签(使用默认名称)
|
||||||
setTimeout(() => {
|
updateFenceStyleAndLabel(fence)
|
||||||
if (fence.shape && fence.shape.getMap()) {
|
|
||||||
// 重新设置样式确保显示
|
// 获取当前围栏在数组中的索引,用于后续更新
|
||||||
fence.shape.setOptions({
|
const fenceIndex = fences.value.length - 1
|
||||||
strokeColor: '#0066FF',
|
|
||||||
strokeWeight: 2,
|
// 弹出输入框让用户输入围栏名称(异步,不阻塞列表显示)
|
||||||
strokeOpacity: 0.8,
|
ElMessageBox.prompt('请输入围栏名称', '围栏命名', {
|
||||||
fillColor: '#0066FF',
|
confirmButtonText: '确定',
|
||||||
fillOpacity: 0.15,
|
cancelButtonText: '取消',
|
||||||
zIndex: 50,
|
inputPlaceholder: '请输入围栏名称',
|
||||||
visible: true // 确保可见
|
inputValue: defaultName,
|
||||||
})
|
inputValidator: (value) => {
|
||||||
// 确保在地图上
|
if (!value || value.trim() === '') {
|
||||||
if (!fence.shape.getMap()) {
|
return '围栏名称不能为空'
|
||||||
map.add(fence.shape)
|
|
||||||
}
|
}
|
||||||
|
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
|
isDrawing.value = false
|
||||||
@@ -553,6 +555,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 = () => {
|
const startDrawPolygon = () => {
|
||||||
if (!mouseTool) return
|
if (!mouseTool) return
|
||||||
@@ -781,6 +889,10 @@ const removeFence = (fenceId) => {
|
|||||||
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
|
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
|
||||||
if (currentMap) {
|
if (currentMap) {
|
||||||
currentMap.remove(fence.shape)
|
currentMap.remove(fence.shape)
|
||||||
|
// 同时移除标签
|
||||||
|
if (fence.label) {
|
||||||
|
currentMap.remove(fence.label)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('删除围栏时出错:', error)
|
console.error('删除围栏时出错:', error)
|
||||||
@@ -832,6 +944,10 @@ const clearAllFences = async () => {
|
|||||||
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
|
const currentMap = fence.shape.getMap ? fence.shape.getMap() : null
|
||||||
if (currentMap) {
|
if (currentMap) {
|
||||||
currentMap.remove(fence.shape)
|
currentMap.remove(fence.shape)
|
||||||
|
// 同时移除标签
|
||||||
|
if (fence.label) {
|
||||||
|
currentMap.remove(fence.label)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('清除围栏时出错:', error)
|
console.error('清除围栏时出错:', error)
|
||||||
@@ -1003,6 +1119,13 @@ onUnmounted(() => {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fence-name {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.drone-status-panel {
|
.drone-status-panel {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|||||||
Reference in New Issue
Block a user