huweili-cesium 1.3.5 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/js/groundLink.js +34 -3
- package/js/labelDiv.js +135 -29
- package/js/movePoint.js +82 -8
- package/js/setPath.js +22 -1
- package/js/setPoint.js +62 -7
- package/package.json +1 -1
package/js/groundLink.js
CHANGED
|
@@ -60,12 +60,16 @@ export function groundLinkConfig() {
|
|
|
60
60
|
|
|
61
61
|
// 检查是否已存在连接线
|
|
62
62
|
if (mapStore.hasGroundLink(pointId, mapId)) {
|
|
63
|
-
//
|
|
63
|
+
// 连接线已存在,同步地面点位经纬度与状态颜色
|
|
64
64
|
modelEntity.groundLinkPosition = {
|
|
65
65
|
lng: options.GROUND_LINK_LNG,
|
|
66
66
|
lat: options.GROUND_LINK_LAT
|
|
67
67
|
}
|
|
68
|
-
|
|
68
|
+
updateGroundLinkStatus({
|
|
69
|
+
pointId,
|
|
70
|
+
status: options.status ?? DroneStatus.WHITELIST,
|
|
71
|
+
mapId,
|
|
72
|
+
})
|
|
69
73
|
return
|
|
70
74
|
}
|
|
71
75
|
|
|
@@ -184,9 +188,36 @@ export function groundLinkConfig() {
|
|
|
184
188
|
}
|
|
185
189
|
}
|
|
186
190
|
|
|
191
|
+
/**
|
|
192
|
+
* 增量更新无人机与地面固定点连线颜色
|
|
193
|
+
* @param {Object} options
|
|
194
|
+
* @param {string} options.pointId 连接线 ID(如 drone-fly-line-${uavId})
|
|
195
|
+
* @param {number} options.status 无人机状态
|
|
196
|
+
* @param {string} [options.mapId] 地图 ID
|
|
197
|
+
*/
|
|
198
|
+
const updateGroundLinkStatus = (options = {}) => {
|
|
199
|
+
const { pointId, status, mapId } = options
|
|
200
|
+
if (!pointId) return false
|
|
201
|
+
|
|
202
|
+
const groundLinkEntity = mapStore.getGroundLink(pointId, mapId)
|
|
203
|
+
if (!groundLinkEntity?.polyline) return false
|
|
204
|
+
|
|
205
|
+
const statusConfig = DroneStatusMap[status] || DroneStatusMap[DroneStatus.WHITELIST]
|
|
206
|
+
const groundLinkColor = Cesium.Color.fromCssColorString(statusConfig.groundLinkColor)
|
|
207
|
+
|
|
208
|
+
groundLinkEntity.polyline.material = new Cesium.PolylineDashMaterialProperty({
|
|
209
|
+
color: groundLinkColor,
|
|
210
|
+
dashLength: 12,
|
|
211
|
+
gapColor: groundLinkColor.withAlpha(0.01),
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
return true
|
|
215
|
+
}
|
|
216
|
+
|
|
187
217
|
return {
|
|
188
218
|
createAndMoveGroundLink,
|
|
189
219
|
clearGroundLink,
|
|
190
|
-
toggleGroundLinkVisibility
|
|
220
|
+
toggleGroundLinkVisibility,
|
|
221
|
+
updateGroundLinkStatus
|
|
191
222
|
}
|
|
192
223
|
}
|
package/js/labelDiv.js
CHANGED
|
@@ -9,6 +9,8 @@ import { useMapStore } from './stores/mapStore.js'
|
|
|
9
9
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
10
10
|
// 详情面板文字刷新最小间隔(毫秒),避免每帧跑逻辑
|
|
11
11
|
const DRONE_INFO_UPDATE_MIN_MS = 1000;
|
|
12
|
+
// 接收时间单独快更新(与界面列表对齐,不拖累其它字段的节流)
|
|
13
|
+
const DRONE_RECEIVE_TIME_UPDATE_MIN_MS = 100;
|
|
12
14
|
|
|
13
15
|
/** @typedef {{ lng: string, lat: string, alt: string, speed: string, flyingHandName: string, flyingHandPhone: string, flyingHandPosition: string, frequencyBand: string, distance: string, receiveTime: string }} DroneInfoDisplay */
|
|
14
16
|
|
|
@@ -78,7 +80,16 @@ function formatDroneInfoDisplay(info) {
|
|
|
78
80
|
* @returns {string}
|
|
79
81
|
*/
|
|
80
82
|
function buildInfoFingerprint(display) {
|
|
81
|
-
return `${display
|
|
83
|
+
return `${buildInfoFingerprintWithoutTime(display)}|${display.receiveTime}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 详情面板指纹(不含接收时间,供慢更新通道比对)
|
|
88
|
+
* @param {DroneInfoDisplay} display
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
function buildInfoFingerprintWithoutTime(display) {
|
|
92
|
+
return `${display.lng}|${display.lat}|${display.alt}|${display.speed}|${display.flyingHandName}|${display.flyingHandPhone}|${display.frequencyBand}|${display.distance}|${display.flyingHandPosition}`;
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
/**
|
|
@@ -105,6 +116,23 @@ function resolveInfoDisplay(info, cached) {
|
|
|
105
116
|
return merged;
|
|
106
117
|
}
|
|
107
118
|
|
|
119
|
+
/**
|
|
120
|
+
* 根据状态生成无人机头顶标牌文案
|
|
121
|
+
* @param {number} status
|
|
122
|
+
* @param {string} uavName
|
|
123
|
+
* @returns {string}
|
|
124
|
+
*/
|
|
125
|
+
export function buildDroneLabelText(status, uavName) {
|
|
126
|
+
const statusConfig = DroneStatusMap[status] || DroneStatusMap[DroneStatus.WHITELIST]
|
|
127
|
+
if (status === DroneStatus.UNKNOWN) {
|
|
128
|
+
return statusConfig.description
|
|
129
|
+
}
|
|
130
|
+
if (status === DroneStatus.MACHINE_NEST) {
|
|
131
|
+
return '机巢无人机'
|
|
132
|
+
}
|
|
133
|
+
return `${statusConfig.description}: ${uavName || ''}`
|
|
134
|
+
}
|
|
135
|
+
|
|
108
136
|
/**
|
|
109
137
|
* 各种标签div合集
|
|
110
138
|
*/
|
|
@@ -152,7 +180,9 @@ export function labelDiv() {
|
|
|
152
180
|
let dragRafId = 0;
|
|
153
181
|
let rafId = 0; // 是用来存储 requestAnimationFrame 的返回ID,用于管理无人机信息的实时刷新
|
|
154
182
|
let lastInfoText = '';
|
|
183
|
+
let lastReceiveTimeText = '';
|
|
155
184
|
let lastInfoTick = 0;
|
|
185
|
+
let lastReceiveTimeTick = 0;
|
|
156
186
|
/** @type {DroneInfoDisplay|null} */
|
|
157
187
|
let cachedInfoDisplay = null;
|
|
158
188
|
let infoDiv = null;
|
|
@@ -214,37 +244,54 @@ export function labelDiv() {
|
|
|
214
244
|
document.removeEventListener('pointerup', onPointerEnd);
|
|
215
245
|
};
|
|
216
246
|
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
if (!
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
247
|
+
// 接收时间快通道:100ms 轮询,与界面列表更接近
|
|
248
|
+
const updateReceiveTime = (display, now) => {
|
|
249
|
+
if (!infoFieldEls?.receiveTimeEl) return;
|
|
250
|
+
if (now - lastReceiveTimeTick < DRONE_RECEIVE_TIME_UPDATE_MIN_MS) return;
|
|
251
|
+
|
|
252
|
+
lastReceiveTimeTick = now;
|
|
253
|
+
const nextReceiveTime = display.receiveTime;
|
|
254
|
+
if (nextReceiveTime === lastReceiveTimeText) return;
|
|
255
|
+
|
|
256
|
+
infoFieldEls.receiveTimeEl.textContent = nextReceiveTime;
|
|
257
|
+
lastReceiveTimeText = nextReceiveTime;
|
|
258
|
+
if (cachedInfoDisplay) {
|
|
259
|
+
cachedInfoDisplay.receiveTime = nextReceiveTime;
|
|
224
260
|
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// 其它字段慢通道:1s 节流,避免每帧跑逻辑
|
|
264
|
+
const updateOtherDroneInfo = (display, now) => {
|
|
265
|
+
if (!infoFieldEls || now - lastInfoTick < DRONE_INFO_UPDATE_MIN_MS) return;
|
|
225
266
|
|
|
226
267
|
lastInfoTick = now;
|
|
268
|
+
const nextInfoText = buildInfoFingerprintWithoutTime(display);
|
|
269
|
+
if (nextInfoText === lastInfoText) return;
|
|
270
|
+
|
|
271
|
+
const {
|
|
272
|
+
lngEl, latEl, altEl, speedEl, flyingHandNameEl, flyingHandPhoneEl, flyingHandPositionEl, distanceEl
|
|
273
|
+
} = infoFieldEls;
|
|
274
|
+
if (lngEl) lngEl.textContent = display.lng;
|
|
275
|
+
if (latEl) latEl.textContent = display.lat;
|
|
276
|
+
if (altEl) altEl.textContent = display.alt;
|
|
277
|
+
if (speedEl) speedEl.textContent = display.speed;
|
|
278
|
+
if (flyingHandNameEl) flyingHandNameEl.textContent = display.flyingHandName;
|
|
279
|
+
if (flyingHandPhoneEl) flyingHandPhoneEl.textContent = display.flyingHandPhone;
|
|
280
|
+
if (distanceEl) distanceEl.textContent = display.distance;
|
|
281
|
+
if (flyingHandPositionEl) flyingHandPositionEl.textContent = display.flyingHandPosition;
|
|
282
|
+
lastInfoText = nextInfoText;
|
|
283
|
+
cachedInfoDisplay = display;
|
|
284
|
+
lastReceiveTimeText = display.receiveTime;
|
|
285
|
+
};
|
|
227
286
|
|
|
287
|
+
function updateDroneInfo(ts) {
|
|
288
|
+
if (!infoDiv) return;
|
|
289
|
+
const now = ts ?? performance.now();
|
|
228
290
|
const info = labelItem.getInfo ? labelItem.getInfo() : null;
|
|
229
291
|
const display = resolveInfoDisplay(info, cachedInfoDisplay);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const {
|
|
234
|
-
lngEl, latEl, altEl, speedEl, flyingHandNameEl, flyingHandPhoneEl, flyingHandPositionEl, distanceEl, receiveTimeEl
|
|
235
|
-
} = infoFieldEls;
|
|
236
|
-
if (lngEl) lngEl.textContent = display.lng;
|
|
237
|
-
if (latEl) latEl.textContent = display.lat;
|
|
238
|
-
if (altEl) altEl.textContent = display.alt;
|
|
239
|
-
if (receiveTimeEl) receiveTimeEl.textContent = display.receiveTime;
|
|
240
|
-
if (speedEl) speedEl.textContent = display.speed;
|
|
241
|
-
if (flyingHandNameEl) flyingHandNameEl.textContent = display.flyingHandName;
|
|
242
|
-
if (flyingHandPhoneEl) flyingHandPhoneEl.textContent = display.flyingHandPhone;
|
|
243
|
-
if (distanceEl) distanceEl.textContent = display.distance;
|
|
244
|
-
if (flyingHandPositionEl) flyingHandPositionEl.textContent = display.flyingHandPosition;
|
|
245
|
-
lastInfoText = nextInfoText;
|
|
246
|
-
cachedInfoDisplay = display;
|
|
247
|
-
}
|
|
292
|
+
|
|
293
|
+
updateReceiveTime(display, now);
|
|
294
|
+
updateOtherDroneInfo(display, now);
|
|
248
295
|
|
|
249
296
|
rafId = requestAnimationFrame(updateDroneInfo);
|
|
250
297
|
}
|
|
@@ -375,9 +422,11 @@ export function labelDiv() {
|
|
|
375
422
|
};
|
|
376
423
|
}
|
|
377
424
|
|
|
378
|
-
lastInfoText =
|
|
425
|
+
lastInfoText = buildInfoFingerprintWithoutTime(initialDisplay);
|
|
426
|
+
lastReceiveTimeText = initialDisplay.receiveTime;
|
|
379
427
|
cachedInfoDisplay = initialDisplay;
|
|
380
428
|
lastInfoTick = 0;
|
|
429
|
+
lastReceiveTimeTick = 0;
|
|
381
430
|
updateDroneInfo();
|
|
382
431
|
|
|
383
432
|
// 关闭时移除动画帧
|
|
@@ -435,7 +484,63 @@ export function labelDiv() {
|
|
|
435
484
|
|
|
436
485
|
batchManager.container.appendChild(labelDiv);
|
|
437
486
|
|
|
487
|
+
const applyDetailStatusTheme = (nextStatus) => {
|
|
488
|
+
if (!detailDiv) return
|
|
489
|
+
|
|
490
|
+
const statusConfig = DroneStatusMap[nextStatus]
|
|
491
|
+
if (!statusConfig) return
|
|
492
|
+
|
|
493
|
+
detailDiv.style.setProperty('--drone-bg-color', statusConfig.backgroundColor)
|
|
494
|
+
detailDiv.style.setProperty('--drone-border-color', statusConfig.borderColor)
|
|
495
|
+
detailDiv.style.setProperty('--drone-text-color', statusConfig.textColor)
|
|
496
|
+
detailDiv.style.setProperty('--drone-detail-divider-color', statusConfig.detailDividerColor)
|
|
497
|
+
|
|
498
|
+
const badgeSpan = detailDiv.querySelector('.drone-badge')
|
|
499
|
+
if (badgeSpan) {
|
|
500
|
+
badgeSpan.style.backgroundImage = `url(${process.env.BASE_URL}${statusConfig.badgeImage})`
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (dragLineSvg) {
|
|
504
|
+
dragLineSvg.style.setProperty('--drone-drag-line-color', statusConfig.dragLineColor)
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const updateStatus = (nextStatus, nextUavName) => {
|
|
509
|
+
const resolvedStatus = nextStatus ?? DroneStatus.WHITELIST
|
|
510
|
+
const resolvedName = nextUavName ?? labelItem.uavName ?? ''
|
|
511
|
+
labelItem.status = resolvedStatus
|
|
512
|
+
labelItem.uavName = resolvedName
|
|
513
|
+
|
|
514
|
+
const statusConfig = DroneStatusMap[resolvedStatus]
|
|
515
|
+
if (!statusConfig) return
|
|
516
|
+
|
|
517
|
+
const newText = buildDroneLabelText(resolvedStatus, resolvedName)
|
|
518
|
+
labelDiv.style.setProperty('--drone-label-bg-color', statusConfig.labelBgColor)
|
|
519
|
+
|
|
520
|
+
const childrenToKeep = []
|
|
521
|
+
if (detailDiv?.parentElement === labelDiv) childrenToKeep.push(detailDiv)
|
|
522
|
+
if (dragLineSvg?.parentElement === labelDiv) childrenToKeep.push(dragLineSvg)
|
|
523
|
+
|
|
524
|
+
while (labelDiv.firstChild) {
|
|
525
|
+
labelDiv.removeChild(labelDiv.firstChild)
|
|
526
|
+
}
|
|
527
|
+
labelDiv.appendChild(document.createTextNode(newText))
|
|
528
|
+
for (const el of childrenToKeep) {
|
|
529
|
+
labelDiv.appendChild(el)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
applyDetailStatusTheme(resolvedStatus)
|
|
533
|
+
|
|
534
|
+
if (detailDiv) {
|
|
535
|
+
const titleEl = detailDiv.querySelector('.drone-detail-title')
|
|
536
|
+
if (titleEl) {
|
|
537
|
+
titleEl.textContent = resolvedName
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
438
542
|
const batchEntry = {
|
|
543
|
+
updateStatus,
|
|
439
544
|
updatePosition(hideByHeight) {
|
|
440
545
|
if (!labelItem.map || !labelItem.map.scene) {
|
|
441
546
|
labelDiv.style.display = 'none';
|
|
@@ -486,8 +591,7 @@ export function labelDiv() {
|
|
|
486
591
|
|
|
487
592
|
batchManager.add(batchEntry);
|
|
488
593
|
|
|
489
|
-
|
|
490
|
-
return () => {
|
|
594
|
+
const destroy = () => {
|
|
491
595
|
cancelAnimationFrame(rafId);
|
|
492
596
|
rafId = 0;
|
|
493
597
|
if (dragRafId) {
|
|
@@ -509,6 +613,8 @@ export function labelDiv() {
|
|
|
509
613
|
batchManager.remove(batchEntry);
|
|
510
614
|
labelDiv.remove();
|
|
511
615
|
};
|
|
616
|
+
|
|
617
|
+
return { destroy, updateStatus };
|
|
512
618
|
};
|
|
513
619
|
|
|
514
620
|
return {
|
package/js/movePoint.js
CHANGED
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
import * as Cesium from 'cesium'
|
|
11
11
|
import { useMapStore } from './stores/mapStore.js'
|
|
12
12
|
import { useEventBus } from './utils/useEventBus.js'
|
|
13
|
-
import { DroneStatus } from './config/index.js'
|
|
13
|
+
import { DroneStatus, DroneStatusMap } from './config/index.js'
|
|
14
14
|
import { setPoint } from './setPoint'
|
|
15
|
+
import { setPath } from './setPath'
|
|
15
16
|
import { getClickHandler } from './clickHandler'
|
|
16
17
|
import { movePathConfig } from './movePath'
|
|
17
|
-
import { setPath } from './setPath'
|
|
18
18
|
import { pointGetPool } from './cardPool'
|
|
19
19
|
import { scheduleRefreshFlyHandQRCode } from './qrCodeGenerator'
|
|
20
20
|
import { groundLinkConfig } from './groundLink'
|
|
@@ -26,22 +26,25 @@ export function movePointConfig(baseUrl) {
|
|
|
26
26
|
const mapStore = useMapStore()
|
|
27
27
|
const {
|
|
28
28
|
setDronePointByGlb,
|
|
29
|
+
updateFlyPointStatus,
|
|
29
30
|
} = setPoint(baseUrl)
|
|
30
31
|
|
|
31
32
|
const {
|
|
32
|
-
|
|
33
|
-
} = movePathConfig()
|
|
34
|
-
|
|
35
|
-
const {
|
|
33
|
+
updateDroneTrailStatus,
|
|
36
34
|
toggleDroneTrail,
|
|
37
|
-
clearDroneTrail
|
|
35
|
+
clearDroneTrail,
|
|
38
36
|
} = setPath()
|
|
39
37
|
|
|
40
38
|
const {
|
|
41
39
|
clearGroundLink,
|
|
42
|
-
toggleGroundLinkVisibility
|
|
40
|
+
toggleGroundLinkVisibility,
|
|
41
|
+
updateGroundLinkStatus,
|
|
43
42
|
} = groundLinkConfig()
|
|
44
43
|
|
|
44
|
+
const {
|
|
45
|
+
moveDroneTrail,
|
|
46
|
+
} = movePathConfig()
|
|
47
|
+
|
|
45
48
|
const clickHandler = getClickHandler() // 获取点击处理器实例
|
|
46
49
|
|
|
47
50
|
const { on } = useEventBus()
|
|
@@ -291,6 +294,61 @@ export function movePointConfig(baseUrl) {
|
|
|
291
294
|
modelEntity.entity.position = positionProperty
|
|
292
295
|
}
|
|
293
296
|
|
|
297
|
+
/**
|
|
298
|
+
* 增量更新无人机地图视觉状态(白名单/非白名单/未知切换)
|
|
299
|
+
* @param {Object} options
|
|
300
|
+
* @param {string} options.pointId 无人机 ID
|
|
301
|
+
* @param {string} [options.mapId] 地图 ID
|
|
302
|
+
* @param {number} options.status 无人机状态
|
|
303
|
+
* @param {string} [options.uavName] 无人机名称
|
|
304
|
+
* @param {string} [options.flyingHandName] 飞手姓名
|
|
305
|
+
* @param {string} [options.flyingHandPhone] 飞手电话
|
|
306
|
+
*/
|
|
307
|
+
const updateDronePointStatus = (options = {}) => {
|
|
308
|
+
const {
|
|
309
|
+
pointId,
|
|
310
|
+
mapId,
|
|
311
|
+
status = DroneStatus.WHITELIST,
|
|
312
|
+
uavName,
|
|
313
|
+
flyingHandName,
|
|
314
|
+
flyingHandPhone,
|
|
315
|
+
} = options
|
|
316
|
+
|
|
317
|
+
if (!pointId) return false
|
|
318
|
+
|
|
319
|
+
const modelEntity = mapStore.getGraphicMap(pointId, mapId)
|
|
320
|
+
if (!modelEntity) return false
|
|
321
|
+
|
|
322
|
+
const statusConfig = DroneStatusMap[status] || DroneStatusMap[DroneStatus.WHITELIST]
|
|
323
|
+
const resolvedUavName = uavName ?? modelEntity.uavName ?? modelEntity.info?.uavName ?? ''
|
|
324
|
+
|
|
325
|
+
if (modelEntity.entity?.billboard) {
|
|
326
|
+
modelEntity.entity.billboard.image = baseUrl + (statusConfig.droneImagePath || '/images/new/drone.png')
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (typeof modelEntity.updateLabelStatus === 'function') {
|
|
330
|
+
modelEntity.updateLabelStatus(status, resolvedUavName)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
updateDroneTrailStatus({ pointId, status, mapId })
|
|
334
|
+
updateGroundLinkStatus({
|
|
335
|
+
pointId: `drone-fly-line-${pointId}`,
|
|
336
|
+
status,
|
|
337
|
+
mapId,
|
|
338
|
+
})
|
|
339
|
+
updateFlyPointStatus({
|
|
340
|
+
id: `fly-${pointId}`,
|
|
341
|
+
status,
|
|
342
|
+
mapId,
|
|
343
|
+
name: flyingHandName ?? modelEntity.info?.flyingHandName,
|
|
344
|
+
phone: flyingHandPhone ?? modelEntity.info?.flyingHandPhone,
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
modelEntity.status = status
|
|
348
|
+
modelEntity.uavName = resolvedUavName
|
|
349
|
+
return true
|
|
350
|
+
}
|
|
351
|
+
|
|
294
352
|
const moveDronePoint = (options) => {
|
|
295
353
|
const { pointId, mapId, uavName } = options
|
|
296
354
|
const map = mapStore.getMap(mapId)
|
|
@@ -352,6 +410,21 @@ export function movePointConfig(baseUrl) {
|
|
|
352
410
|
info.distance = options.distance || ''
|
|
353
411
|
info.receiveTime = options.receiveTime || ''
|
|
354
412
|
|
|
413
|
+
const prevStatus = modelEntity.status
|
|
414
|
+
if (prevStatus !== undefined && prevStatus !== status) {
|
|
415
|
+
updateDronePointStatus({
|
|
416
|
+
pointId,
|
|
417
|
+
mapId,
|
|
418
|
+
status,
|
|
419
|
+
uavName,
|
|
420
|
+
flyingHandName: options.flyingHandName,
|
|
421
|
+
flyingHandPhone: options.flyingHandPhone,
|
|
422
|
+
})
|
|
423
|
+
} else if (prevStatus === undefined) {
|
|
424
|
+
modelEntity.status = status
|
|
425
|
+
modelEntity.uavName = uavName
|
|
426
|
+
}
|
|
427
|
+
|
|
355
428
|
const targetPosition = Cesium.Cartesian3.fromDegrees(lng, lat, height)
|
|
356
429
|
snapDronePosition(modelEntity, map, targetPosition, currentTime)
|
|
357
430
|
|
|
@@ -506,6 +579,7 @@ export function movePointConfig(baseUrl) {
|
|
|
506
579
|
movePointByGlb,
|
|
507
580
|
movePointByGlbInfo,
|
|
508
581
|
moveDronePoint,
|
|
582
|
+
updateDronePointStatus,
|
|
509
583
|
toggleDroneAndTrailVisibility,
|
|
510
584
|
destroyDroneTrail
|
|
511
585
|
}
|
package/js/setPath.js
CHANGED
|
@@ -118,9 +118,30 @@ export function setPath() {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* 增量更新无人机轨迹颜色
|
|
123
|
+
* @param {Object} options
|
|
124
|
+
* @param {string} options.pointId 无人机 ID
|
|
125
|
+
* @param {number} options.status 无人机状态
|
|
126
|
+
* @param {string} [options.mapId] 地图 ID
|
|
127
|
+
*/
|
|
128
|
+
const updateDroneTrailStatus = (options = {}) => {
|
|
129
|
+
const { pointId, status, mapId } = options
|
|
130
|
+
if (!pointId) return false
|
|
131
|
+
|
|
132
|
+
const trailData = mapStore.getDroneTrail(pointId, mapId)
|
|
133
|
+
if (!trailData?.entity?.polyline) return false
|
|
134
|
+
|
|
135
|
+
const statusConfig = DroneStatusMap[status] || DroneStatusMap[DroneStatus.WHITELIST]
|
|
136
|
+
trailData.entity.polyline.material = Cesium.Color.fromCssColorString(statusConfig.trailColor)
|
|
137
|
+
trailData.status = status
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
|
|
121
141
|
return {
|
|
122
142
|
setDroneTrail,
|
|
123
143
|
clearDroneTrail,
|
|
124
|
-
toggleDroneTrail
|
|
144
|
+
toggleDroneTrail,
|
|
145
|
+
updateDroneTrailStatus
|
|
125
146
|
}
|
|
126
147
|
}
|
package/js/setPoint.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import * as Cesium from 'cesium'
|
|
11
11
|
import { useMapStore } from './stores/mapStore.js'
|
|
12
12
|
import { setPath } from './setPath'
|
|
13
|
-
import { labelDiv } from './labelDiv'
|
|
13
|
+
import { labelDiv, buildDroneLabelText } from './labelDiv'
|
|
14
14
|
import { getClickHandler } from './clickHandler'
|
|
15
15
|
import { DroneStatus, DroneStatusMap, MapInstanceIds } from './config/index.js'
|
|
16
16
|
import { pointGetPool, PonitInfoCardPool } from './cardPool'
|
|
@@ -142,6 +142,9 @@ export function setPoint(baseUrl) {
|
|
|
142
142
|
|
|
143
143
|
const result = {
|
|
144
144
|
id,
|
|
145
|
+
status,
|
|
146
|
+
flyName: options.name || '--',
|
|
147
|
+
flyPhone: options.phone || '--',
|
|
145
148
|
billboardCollection,
|
|
146
149
|
billboard,
|
|
147
150
|
show: showCard,
|
|
@@ -160,6 +163,57 @@ export function setPoint(baseUrl) {
|
|
|
160
163
|
return result
|
|
161
164
|
}
|
|
162
165
|
|
|
166
|
+
/**
|
|
167
|
+
* 增量更新飞手点位图标与信息牌主题色(白名单/非白名单切换)
|
|
168
|
+
* @param {Object} options
|
|
169
|
+
* @param {string} options.id 飞手点位 ID(如 fly-${uavId})
|
|
170
|
+
* @param {number} options.status 无人机状态
|
|
171
|
+
* @param {string} [options.mapId] 地图 ID
|
|
172
|
+
* @param {string} [options.name] 飞手姓名
|
|
173
|
+
* @param {string} [options.phone] 飞手电话
|
|
174
|
+
*/
|
|
175
|
+
const updateFlyPointStatus = (options = {}) => {
|
|
176
|
+
const { id, status, mapId, name, phone } = options
|
|
177
|
+
if (!id) return false
|
|
178
|
+
|
|
179
|
+
const point = mapStore.getGraphicMap(id, mapId)
|
|
180
|
+
if (!point?.billboard) return false
|
|
181
|
+
|
|
182
|
+
const resolvedStatus = status ?? DroneStatus.WHITELIST
|
|
183
|
+
const statusConfig = DroneStatusMap[resolvedStatus] || DroneStatusMap[DroneStatus.WHITELIST]
|
|
184
|
+
|
|
185
|
+
point.status = resolvedStatus
|
|
186
|
+
if (name !== undefined) point.flyName = name
|
|
187
|
+
if (phone !== undefined) point.flyPhone = phone
|
|
188
|
+
|
|
189
|
+
point.billboard.image = new URL(
|
|
190
|
+
`${process.env.BASE_URL}${statusConfig.flyingHandImagePath}`,
|
|
191
|
+
import.meta.url
|
|
192
|
+
).href
|
|
193
|
+
|
|
194
|
+
const map = mapStore.getMap(mapId)
|
|
195
|
+
if (!map) return true
|
|
196
|
+
|
|
197
|
+
const pool = pointGetPool(map, mapId)
|
|
198
|
+
const card = pool.getActiveCard(id)
|
|
199
|
+
if (card) {
|
|
200
|
+
const infoCard = card.querySelector('.info-card')
|
|
201
|
+
if (infoCard) {
|
|
202
|
+
infoCard.style.setProperty('--flying-hand-bg-color', statusConfig.flyingHandInfoBoardColor)
|
|
203
|
+
}
|
|
204
|
+
const nameEl = card.querySelector('.fly-name')
|
|
205
|
+
const phoneEl = card.querySelector('.fly-phone')
|
|
206
|
+
if (nameEl && name !== undefined) {
|
|
207
|
+
nameEl.textContent = `姓名:${name || '--'}`
|
|
208
|
+
}
|
|
209
|
+
if (phoneEl && phone !== undefined) {
|
|
210
|
+
phoneEl.textContent = `电话:${phone || '--'}`
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return true
|
|
215
|
+
}
|
|
216
|
+
|
|
163
217
|
/**
|
|
164
218
|
* 设置点位 (通过提供的glb模型设置点位)
|
|
165
219
|
* @param options 配置选项
|
|
@@ -439,16 +493,16 @@ export function setPoint(baseUrl) {
|
|
|
439
493
|
getPosition: () => modelEntity.positionProperty.getValue(map.clock.currentTime),
|
|
440
494
|
getInfo: () => modelEntity.info, // 后续移动时,真正把业务字段写进去, 在 @js/movePoint.js 里,移动无人机时会执行:
|
|
441
495
|
getVisible: () => modelEntity.entity.show,
|
|
442
|
-
text: status
|
|
443
|
-
? statusConfig.description
|
|
444
|
-
: status === DroneStatus.MACHINE_NEST
|
|
445
|
-
? '机巢无人机'
|
|
446
|
-
: `${statusConfig.description}: ${uavName}`,
|
|
496
|
+
text: buildDroneLabelText(status, uavName),
|
|
447
497
|
status,
|
|
448
498
|
map,
|
|
449
499
|
mapId
|
|
450
500
|
})
|
|
451
501
|
|
|
502
|
+
modelEntity.status = status
|
|
503
|
+
modelEntity.uavName = uavName
|
|
504
|
+
modelEntity.updateLabelStatus = destroyDroneLabelDiv?.updateStatus
|
|
505
|
+
|
|
452
506
|
if (type === 'png') {
|
|
453
507
|
modelEntity.rippleEffect = createDroneRippleDom({
|
|
454
508
|
map,
|
|
@@ -459,7 +513,7 @@ export function setPoint(baseUrl) {
|
|
|
459
513
|
}
|
|
460
514
|
|
|
461
515
|
modelEntity.destroy = () => {
|
|
462
|
-
destroyDroneLabelDiv?.()
|
|
516
|
+
destroyDroneLabelDiv?.destroy?.()
|
|
463
517
|
modelEntity.rippleEffect?.destroy?.()
|
|
464
518
|
map.entities.remove(modelEntity.entity)
|
|
465
519
|
}
|
|
@@ -652,6 +706,7 @@ export function setPoint(baseUrl) {
|
|
|
652
706
|
setPointByGlb,
|
|
653
707
|
setPointByGlbInfo,
|
|
654
708
|
setDronePointByGlb,
|
|
709
|
+
updateFlyPointStatus,
|
|
655
710
|
pickMapPointByClick,
|
|
656
711
|
createPickedImagePoint,
|
|
657
712
|
destroyPickedImagePoint
|