无人机管理后台前端(已迁走)
张含笑
2025-10-28 0f16db42e4e331bfaf084c27ca602c275e87668d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
<template>
  <basic-container>
    <div class="layerContainer">
      <div>
        <el-tabs v-model="activeType" @tab-click="handleClick">
          <el-tab-pane v-for="tab in tabData" :key="tab.type" :label="tab.name" :name="tab.type">
          </el-tab-pane>
        </el-tabs>
      </div>
      <!-- 地图 -->
      <div class="mapContainer">
        <div id="layMap" class="ztzf-cesium"></div>
        <leftList @update:coverData="handleCoverDataUpdate" :activeName="activeName"></leftList>
        <rightEdit></rightEdit>
      </div>
    </div>
  </basic-container>
</template>
 
<script setup>
import { flyVisual } from '@/utils/cesium/mapUtil'
import rightEdit from '@/views/layerManagement/components/rightEdit.vue';
import leftList from '@/views/layerManagement/components/leftList.vue';
import { DrawPolygon } from '@/views/layerManagement/components/utils';
import * as Cesium from 'cesium';
import { PublicCesium } from '@/utils/cesium/publicCesium';
import _, { cloneDeep, throttle } from 'lodash';
import { ElButton } from 'element-plus';
const activeName = ref('电子围栏');
const activeType = ref('0');
const tabData = ref([
  {
    name: '电子围栏',
    type: '0',
  },
  {
    name: '自定义禁飞区',
    type: '1',
  },
  {
    name: '国土空间规划',
    type: '2',
  },
]);
 
const handleClick = tab => {
  const clickedTab = tabData.value.find(item => item.type === tab.paneName);
  activeType.value = clickedTab.type;
  activeName.value = clickedTab.name;
};
// 解析 geo_data 并转换为 DrawPolygon 所需的坐标格式
const parseGeoDataToPositions = (geoDataStr, altitude) => {
  try {
    // 解析 JSON 字符串为 GeoJSON 对象
    const geoData = JSON.parse(geoDataStr);
    // 仅处理 Polygon 类型的地理数据
    if (geoData.type !== 'Polygon') return [];
 
    // 提取 coordinates(取第一个面,忽略孔洞),并补充高度
    const coordinates = geoData.coordinates[0];
    return coordinates.map(([lng, lat]) => ({
      lng: Number(lng),
      lat: Number(lat),
      height: Number(altitude) || 0, // 高度默认取数据中的 altitude,无则为 0
    }));
  } catch (error) {
    console.error('解析 geo_data 失败:', error);
    return [];
  }
};
 
const selectDataList = ref([]);
// 提取图斑坐标
function polygonWktToTargetArray(wktPolygon, defaultHeight = 140.6) {
  try {
    if (!/^POLYGON\(\([\d\s,.]+\)\)$/.test(wktPolygon)) {
      throw new Error('输入不是有效的 WKT POLYGON 格式');
    }
 
    const coordStr = wktPolygon
      .replace(/^POLYGON\(\(/, '')
      .replace(/\)\)$/, '')
      .trim();
 
    const coordPairs = coordStr.split(/,\s*/).filter(pair => pair.trim() !== '');
 
    const result = coordPairs.map(pair => {
      const [lng, lat] = pair
        .split(/\s+/)
        .map(Number)
        .filter(num => !isNaN(num));
 
      if (
        lng === undefined ||
        lat === undefined ||
        lng < -180 ||
        lng > 180 ||
        lat < -90 ||
        lat > 90
      ) {
        throw new Error(`无效的经纬度对:${pair}`);
      }
 
      return {
        lng: lng,
        lat: lat,
        longitude: lng, // 与 lng 一致
        latitude: lat, // 与 lat 一致
      };
    });
 
    const uniqueResult = Array.from(
      new Map(result.map(item => [`${item.lng}-${item.lat}`, item])).values()
    );
 
    return uniqueResult;
  } catch (error) {
    return []; // 异常时返回空数组
  }
}
 
const handleCoverDataUpdate = data => {
  selectDataList.value = data;
console.log('获取的',selectDataList.value);
 
  if (selectDataList.value.length > 0) {
    loadDataToMap(selectDataList.value);
  } else {
    drawPolygonExample.removeEntities();
  }
};
const loadDataToMap = (dataList) => {
  if (!viewer) return; 
  viewer.entities.removeAll();
    // 存储所有有效坐标,用于后续定位
  const allCoordinates = [];
  dataList.forEach(item => {
    // 解析 geo_data 为经纬度坐标数组(使用已有的 parseGeoDataToPositions 方法)
    const positions = parseGeoDataToPositions(item.geo_data, item.altitude);
    if (positions.length < 3) {
      console.warn(`数据 ${item.name} 坐标点不足,无法绘制`);
      return;
    }
console.log('positions',positions);
 
    //  转换为 Cesium 所需的 [lng, lat, lng, lat, ...] 扁平数组格式
    let degreesArray = [];
    positions.forEach(pos => {
      degreesArray.push(pos.lng, pos.lat, pos.height);   
      
    });   
    viewer.entities.add({
      id: `polygon_${item.id}`, 
      customType: 'fence_polygon', 
      customInfo: item,
      polygon: {
        hierarchy: new Cesium.PolygonHierarchy(
          Cesium.Cartesian3.fromDegreesArrayHeights(degreesArray)
        ),
        material: Cesium.Color.YELLOW.withAlpha(0.5), // 填充色
        outline: true, // 显示边框
        outlineColor: Cesium.Color.YELLOW, // 边框色
        outlineWidth: 2, // 边框宽度
        clampToGround: true, // 贴地显示
       
      },
    
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(degreesArray),
        width: 2,
        material: Cesium.Color.YELLOW,
        clampToGround: true,
      },
      zIndex: 99, // 层级,确保在其他图层上方显示
    });
  });
 
  //  添加点击事件(参考 entitiesAddSpot 的 spotHighlighting 逻辑)
  // 移除已有点击事件,避免重复绑定
  // viewInstance.value?.removeLeftClickEvent('fenceHighlighting');
  // 绑定新的点击事件,用于高亮选中的围栏
  // viewInstance.value?.addLeftClickEvent(null, handleFenceClick, 'fenceHighlighting');
};
// 围栏点击处理函数(高亮选中项 + 可联动右侧编辑组件)
const handleFenceClick = (movement) => {
  if (!viewer) return;
 
  // 拾取点击的实体
  const pickedObject = viewer.scene.pick(movement.position);
  if (Cesium.defined(pickedObject) && pickedObject.id?.customType === 'fence_polygon') {
    const selectedEntity = pickedObject.id;
    console.log('选中的围栏数据:', selectedEntity.customInfo);
 
    // 1. 高亮处理(清除其他实体高亮,仅高亮当前选中)
    viewer.entities.values.forEach(entity => {
      if (entity.customType === 'fence_polygon') {
        // 恢复默认样式
        entity.polygon.material = entity === selectedEntity 
          ? selectedEntity.polygon.material.color.withAlpha(0.8) // 选中时加深透明度
          : selectedEntity.polygon.material.color.withAlpha(0.5); // 未选中恢复默认
      }
    });
 
    // 2. 联动右侧编辑组件(假设 rightEdit 有接收数据的方法)
    // 例如:通过 ref 调用 rightEdit 的 setData 方法
    // rightEditRef.value?.setData(selectedEntity.customInfo);
  }
};
let publicCesiumInstance = null;
let viewer = null;
const viewInstance = shallowRef(null);
const homeViewer = shallowRef(null);
 
// 初始化绘制工具实例
const drawPolygonExample = new DrawPolygon();
 
// 地图初始化
const initMap = () => {
  publicCesiumInstance = new PublicCesium({
    dom: 'layMap',
    flatMode: false,
    terrain: true,
    layerMode: 4,
    contour: false,
  });
 
  viewer = publicCesiumInstance.getViewer();
  viewInstance.value = publicCesiumInstance;
  drawPolygonExample.initHandler(viewer);
};
 
// 处理绘制完成后的多边形坐标(示例)
const loadPlanarRoute = async (positions = null, save = false) => {
  if (!positions || positions.length < 3) return;
  // console.log('绘制的多边形顶点坐标(Cartesian3):', positions);
  //坐标转换
  const cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray(positions);
  const latLngPositions = cartographics.map(cartographic => ({
    lng: Cesium.Math.toDegrees(cartographic.longitude),
    lat: Cesium.Math.toDegrees(cartographic.latitude),
    height: cartographic.height || 0,
  }));
  // console.log('转换后的经纬度坐标:', latLngPositions);
};
 
const throttleLoadPlanarRoute = throttle(loadPlanarRoute, 200);
drawPolygonExample.subscribe('getPolygonPositions', data => {
console.log('绘制的数据',data);
 
  throttleLoadPlanarRoute(data);
});
 
// 地图销毁
const destroyMap = () => {
  drawPolygonExample.destroy();
 
  if (viewer) {
    viewer.destroy();
    viewer = null;
  }
  publicCesiumInstance = null;
};
// 阻止浏览器默认
const preventDefault = event => {
  event.preventDefault();
  return;
};
const cesiumContextMenu = (isAdd = true) => {
  let cesium = document.getElementById('layMap');
  if (!cesium) return;
  if (isAdd) {
    cesium.addEventListener('contextmenu', preventDefault);
  } else {
    cesium.removeEventListener('contextmenu', preventDefault);
  }
};
onMounted(() => {
  initMap();
  cesiumContextMenu();
});
 
onBeforeUnmount(() => {
  destroyMap();
  cesiumContextMenu(false);
});
</script>
 
<style scoped lang="scss">
.layerContainer {
  width: 100%;
  height: 90vh;
}
.mapContainer {
  position: relative;
  width: 100%;
  height: 80vh;
  #layMap {
    width: 100%;
    height: 100%;
  }
}
</style>