|
@@ -221,7 +221,7 @@ let viewMode = VIEW_MODES.GROUND
|
|
|
let markerPlan = { markers: [], blocked: [], byStatus: {}, total: 0 }
|
|
let markerPlan = { markers: [], blocked: [], byStatus: {}, total: 0 }
|
|
|
// 票 45:摘要标记(监测点/未关联设备)的动效计划(planDeviceEffects 的输出,形状同设备动效计划)。
|
|
// 票 45:摘要标记(监测点/未关联设备)的动效计划(planDeviceEffects 的输出,形状同设备动效计划)。
|
|
|
let markerEffectsPlan = null
|
|
let markerEffectsPlan = null
|
|
|
-// 票 85:跨图层合计降级状态(三类对象合计计数;两张计划共用同一个阈值与收敛系数)。
|
|
|
|
|
|
|
+// 票 85:跨图层合计降级状态;摘要、关联设备和设施共用阈值与收敛系数。
|
|
|
let combinedEffectState = { enabled: false, limit: 30, abnormalCount: 0, animatedCount: 0, degraded: false, converge: null }
|
|
let combinedEffectState = { enabled: false, limit: 30, abnormalCount: 0, animatedCount: 0, degraded: false, converge: null }
|
|
|
let markerRendered = 0
|
|
let markerRendered = 0
|
|
|
let markerSkipped = 0
|
|
let markerSkipped = 0
|
|
@@ -229,8 +229,11 @@ let markerSkipped = 0
|
|
|
let deviceRows = []
|
|
let deviceRows = []
|
|
|
|
|
|
|
|
// 票 68:设施点(水厂/泵站/水源地/用水户)的最近一次计划行。与摘要标记/关联设备**分开**持有:
|
|
// 票 68:设施点(水厂/泵站/水源地/用水户)的最近一次计划行。与摘要标记/关联设备**分开**持有:
|
|
|
-// 设施点不进摘要序列、不进设备图例,也不参与设备的动效/重叠判定。
|
|
|
|
|
|
|
+// 设施点不进摘要序列、不进设备图例,也不参与设备的重叠判定;但状态特效与设备**同一套**
|
|
|
|
|
+// (维护者 2026-11-06:预警/报警/工单的特效设施点也要有,视觉与设备一致)。
|
|
|
let facilityMarkerRows = []
|
|
let facilityMarkerRows = []
|
|
|
|
|
+// 设施点动效计划:与设备动效**同一份** `planDeviceEffects()` 输出(开关/降级/工单不计异常同一条纪律)。
|
|
|
|
|
+let facilityEffectsPlan = null
|
|
|
let selectedFacilityKey = ''
|
|
let selectedFacilityKey = ''
|
|
|
let facilitySelectionIdentity = null
|
|
let facilitySelectionIdentity = null
|
|
|
|
|
|
|
@@ -251,6 +254,8 @@ const overlayFrameCache = {
|
|
|
rect: null, rectKey: '', rectAt: 0,
|
|
rect: null, rectKey: '', rectAt: 0,
|
|
|
// 票 84:关联设备层的门控查询(与摘要标记同一条门控;三类对象都按自身状态挂环)。
|
|
// 票 84:关联设备层的门控查询(与摘要标记同一条门控;三类对象都按自身状态挂环)。
|
|
|
deviceEffectOf: () => '',
|
|
deviceEffectOf: () => '',
|
|
|
|
|
+ // 维护者 2026-11-06:设施点与设备同一套状态特效,门控查询按设施点 key 建表。
|
|
|
|
|
+ facilityEffectOf: () => '',
|
|
|
// 票 85:跨图层合计门控与收敛系数(降级时环仍画,只是更小更淡)。
|
|
// 票 85:跨图层合计门控与收敛系数(降级时环仍画,只是更小更淡)。
|
|
|
combinedRef: null, converge: null,
|
|
combinedRef: null, converge: null,
|
|
|
// 静态帧闸门:镜头位姿/宿主矩形/输入计划都没变时,66ms 内的重复帧直接跳过。
|
|
// 静态帧闸门:镜头位姿/宿主矩形/输入计划都没变时,66ms 内的重复帧直接跳过。
|
|
@@ -281,7 +286,7 @@ function overlayComponentPlanMarkerCached(marker) {
|
|
|
* 后者把「非监测点」强转成监测设备,设施点会丢设施类型图标并被降成设备档。
|
|
* 后者把「非监测点」强转成监测设备,设施点会丢设施类型图标并被降成设备档。
|
|
|
*/
|
|
*/
|
|
|
function overlayFacilityPlanMarkerCached(marker) {
|
|
function overlayFacilityPlanMarkerCached(marker) {
|
|
|
- const key = `${marker.type || ''}|${marker.status || ''}|${marker.tone || ''}`
|
|
|
|
|
|
|
+ const key = `${marker.type || ''}|${marker.status ?? ''}|${marker.tone || ''}`
|
|
|
let plan = overlayFacilityPlanCache.get(key)
|
|
let plan = overlayFacilityPlanCache.get(key)
|
|
|
if (!plan) {
|
|
if (!plan) {
|
|
|
plan = planMarker({ kind: 'facility-point', status: marker.status, facilityType: marker.type, tone: marker.tone })
|
|
plan = planMarker({ kind: 'facility-point', status: marker.status, facilityType: marker.type, tone: marker.tone })
|
|
@@ -1289,8 +1294,13 @@ async function bootEngine(record) {
|
|
|
const deviceAnimated = gated && deviceEffectsPlan
|
|
const deviceAnimated = gated && deviceEffectsPlan
|
|
|
? new Map((deviceEffectsPlan.animated || []).map((row) => [row.code, row.effect]))
|
|
? new Map((deviceEffectsPlan.animated || []).map((row) => [row.code, row.effect]))
|
|
|
: new Map()
|
|
: new Map()
|
|
|
|
|
+ // 维护者 2026-11-06:设施点动效键也按同一条门控建表(行键=设施点 key)。
|
|
|
|
|
+ const facilityAnimated = gated && facilityEffectsPlan
|
|
|
|
|
+ ? new Map((facilityEffectsPlan.animated || []).map((row) => [row.code, row.effect]))
|
|
|
|
|
+ : new Map()
|
|
|
overlayFrameCache.effectOf = (marker) => markerAnimated.get(`${marker.kind}|${marker.code}`) || ''
|
|
overlayFrameCache.effectOf = (marker) => markerAnimated.get(`${marker.kind}|${marker.code}`) || ''
|
|
|
overlayFrameCache.deviceEffectOf = (device) => deviceAnimated.get(device.code) || ''
|
|
overlayFrameCache.deviceEffectOf = (device) => deviceAnimated.get(device.code) || ''
|
|
|
|
|
+ overlayFrameCache.facilityEffectOf = (facility) => facilityAnimated.get(facility.key || `facility-point|${facility.code}`) || ''
|
|
|
overlayFrameCache.converge = combinedEffectState.converge
|
|
overlayFrameCache.converge = combinedEffectState.converge
|
|
|
}
|
|
}
|
|
|
return {
|
|
return {
|
|
@@ -1331,6 +1341,7 @@ async function bootEngine(record) {
|
|
|
// 降级时键仍在,只把收敛系数下传,环不消失)。
|
|
// 降级时键仍在,只把收敛系数下传,环不消失)。
|
|
|
effectOf: overlayFrameCache.effectOf,
|
|
effectOf: overlayFrameCache.effectOf,
|
|
|
deviceEffectOf: overlayFrameCache.deviceEffectOf,
|
|
deviceEffectOf: overlayFrameCache.deviceEffectOf,
|
|
|
|
|
+ facilityEffectOf: overlayFrameCache.facilityEffectOf,
|
|
|
converge: overlayFrameCache.converge,
|
|
converge: overlayFrameCache.converge,
|
|
|
planOf: overlayPlanMarkerCached,
|
|
planOf: overlayPlanMarkerCached,
|
|
|
// 贴地定位与 billboard `CLAMP_TO_GROUND` 同口径(票 47 维护者反馈①根因):
|
|
// 贴地定位与 billboard `CLAMP_TO_GROUND` 同口径(票 47 维护者反馈①根因):
|
|
@@ -1443,6 +1454,9 @@ export function unmountMap() {
|
|
|
pendingPipeLayerPlan = null
|
|
pendingPipeLayerPlan = null
|
|
|
lastPipeLayerRefs = { pipes: null, components: null, viewMode: null, viewer: null, overlayActive: null }
|
|
lastPipeLayerRefs = { pipes: null, components: null, viewMode: null, viewer: null, overlayActive: null }
|
|
|
facilityMarkerRows = []
|
|
facilityMarkerRows = []
|
|
|
|
|
+ // 设施点动效计划随行清空(否则卸载后仍按旧行放行/计数)。
|
|
|
|
|
+ facilityEffectsPlan = null
|
|
|
|
|
+ refreshCombinedEffectState()
|
|
|
selectedFacilityKey = ''
|
|
selectedFacilityKey = ''
|
|
|
facilitySelectionIdentity = null
|
|
facilitySelectionIdentity = null
|
|
|
pipeComponentRows = []
|
|
pipeComponentRows = []
|
|
@@ -3125,19 +3139,23 @@ function flushSceneApply() {
|
|
|
* @returns {boolean} 是否已画到地图上
|
|
* @returns {boolean} 是否已画到地图上
|
|
|
*/
|
|
*/
|
|
|
/**
|
|
/**
|
|
|
- * 票 85:刷新跨图层合计降级状态。两处调用(摘要标记计划/关联设备计划变化)——
|
|
|
|
|
- * 阈值按三类对象合计判定,收敛系数共享同一份,避免两张计划一个降级一个不降。
|
|
|
|
|
|
|
+ * 票 85:刷新摘要标记、关联设备、设施点的合计状态。
|
|
|
|
|
+ * 所有参与图层共享阈值与收敛系数,计划更新或清层后立即重算。
|
|
|
*/
|
|
*/
|
|
|
function refreshCombinedEffectState() {
|
|
function refreshCombinedEffectState() {
|
|
|
- combinedEffectState = combineEffectPlans([markerEffectsPlan, deviceEffectsPlan], resolveDeviceEffectsOptions())
|
|
|
|
|
|
|
+ combinedEffectState = combineEffectPlans([markerEffectsPlan, deviceEffectsPlan, facilityEffectsPlan], resolveDeviceEffectsOptions())
|
|
|
|
|
+ paintMarkerEffects()
|
|
|
|
|
+ paintDeviceEffects()
|
|
|
return combinedEffectState
|
|
return combinedEffectState
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 票 85:给设备图层计划提供「另外两类对象」的异常数,让 store 侧的降级判定与视觉门控同源。
|
|
* 票 85:给设备图层计划提供「另外两类对象」的异常数,让 store 侧的降级判定与视觉门控同源。
|
|
|
|
|
+ * 维护者 2026-11-06:设施点报警也计在同屏异常里(设施特效与设备同一套门控,不能各算各的)。
|
|
|
*/
|
|
*/
|
|
|
export function getEffectsAbnormalBase() {
|
|
export function getEffectsAbnormalBase() {
|
|
|
- return abnormalObjectCount(markerPlan.markers || [])
|
|
|
|
|
|
|
+ const facilityAbnormal = facilityEffectsPlan ? facilityEffectsPlan.ownAbnormalCount : 0
|
|
|
|
|
+ return abnormalObjectCount(markerPlan.markers || []) + facilityAbnormal
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
export function syncPointMarkersForPlan(plan, legendSource) {
|
|
export function syncPointMarkersForPlan(plan, legendSource) {
|
|
@@ -3307,8 +3325,8 @@ export async function syncPipeLayerForPlan(plan) {
|
|
|
* 同步**设施点图层**(票 68)。
|
|
* 同步**设施点图层**(票 68)。
|
|
|
*
|
|
*
|
|
|
* 与摘要标记/关联设备分开是结构性的:设施点不是监测点、也不是设备,不进摘要序列、
|
|
* 与摘要标记/关联设备分开是结构性的:设施点不是监测点、也不是设备,不进摘要序列、
|
|
|
- * 不进设备图例与动效/重叠判定。渲染由 DOM overlay 的设施点循环承担;本函数只持有本轮
|
|
|
|
|
- * 计划行并写宿主读数(计数口径与图例的「可上图 N」同源,都是本轮可画的行数)。
|
|
|
|
|
|
|
+ * 不进设备图例或重叠判定;状态特效共享设备的门控与参数。DOM overlay 负责渲染,
|
|
|
|
|
+ * 本函数持有本轮计划并发布计数(与设施图例的「可上图 N」口径一致)。
|
|
|
*
|
|
*
|
|
|
* `rows` 已由 store 按设施类型 + 全局行业/片区筛好,计划层只按一级模式显隐,这里不再过滤。
|
|
* `rows` 已由 store 按设施类型 + 全局行业/片区筛好,计划层只按一级模式显隐,这里不再过滤。
|
|
|
*
|
|
*
|
|
@@ -3317,6 +3335,15 @@ export async function syncPipeLayerForPlan(plan) {
|
|
|
*/
|
|
*/
|
|
|
export function syncFacilityMarkersForPlan(rows) {
|
|
export function syncFacilityMarkersForPlan(rows) {
|
|
|
facilityMarkerRows = Array.isArray(rows) ? rows : []
|
|
facilityMarkerRows = Array.isArray(rows) ? rows : []
|
|
|
|
|
+ // 状态归一来自设施合成计划;复用设备的开关、异常计数与降级,不拿色键猜状态。
|
|
|
|
|
+ facilityEffectsPlan = planDeviceEffects({
|
|
|
|
|
+ devices: facilityMarkerRows.filter(Boolean).map((row) => ({
|
|
|
|
|
+ code: row.key || (row.code ? `facility-point|${row.code}` : ''),
|
|
|
|
|
+ status: overlayFacilityPlanMarkerCached(row).effectStatus,
|
|
|
|
|
+ })),
|
|
|
|
|
+ ...resolveDeviceEffectsOptions(),
|
|
|
|
|
+ })
|
|
|
|
|
+ refreshCombinedEffectState()
|
|
|
// watcher 可能早于合并后的 marker 同步;以新行重算可见选择,避免保留已筛掉的高亮。
|
|
// watcher 可能早于合并后的 marker 同步;以新行重算可见选择,避免保留已筛掉的高亮。
|
|
|
setFacilitySelection(facilitySelectionIdentity)
|
|
setFacilitySelection(facilitySelectionIdentity)
|
|
|
const host = instance && isDomHost(instance.host) ? instance.host : null
|
|
const host = instance && isDomHost(instance.host) ? instance.host : null
|
|
@@ -3328,6 +3355,10 @@ export function syncFacilityMarkersForPlan(rows) {
|
|
|
byType[row.type] = (byType[row.type] || 0) + 1
|
|
byType[row.type] = (byType[row.type] || 0) + 1
|
|
|
}
|
|
}
|
|
|
host.dataset.mapFacilityTypes = Object.entries(byType).map(([type, count]) => `${type}:${count}`).join(',')
|
|
host.dataset.mapFacilityTypes = Object.entries(byType).map(([type, count]) => `${type}:${count}`).join(',')
|
|
|
|
|
+ // 特效读数面(走查直接读,不必翻 DOM):本轮放行的设施点动效条数 + 计入异常的条数。
|
|
|
|
|
+ const facilityEffects = facilityEffectsPlan || { animated: [], ownAbnormalCount: 0 }
|
|
|
|
|
+ host.dataset.mapFacilityEffectsAnimated = String((facilityEffects.animated || []).length)
|
|
|
|
|
+ host.dataset.mapFacilityEffectsAbnormal = String(facilityEffects.ownAbnormalCount || 0)
|
|
|
}
|
|
}
|
|
|
return facilityMarkerRows.length
|
|
return facilityMarkerRows.length
|
|
|
}
|
|
}
|
|
@@ -3701,7 +3732,7 @@ export function clearAssociatedDevices() {
|
|
|
hoveredDeviceCode = ''
|
|
hoveredDeviceCode = ''
|
|
|
// 票 47:动效随图层一起消失(计划清空 + 引擎侧已在 clearAssociatedDevices 里停循环)。
|
|
// 票 47:动效随图层一起消失(计划清空 + 引擎侧已在 clearAssociatedDevices 里停循环)。
|
|
|
deviceEffectsPlan = null
|
|
deviceEffectsPlan = null
|
|
|
- paintDeviceEffects()
|
|
|
|
|
|
|
+ refreshCombinedEffectState()
|
|
|
paintDeviceReactions()
|
|
paintDeviceReactions()
|
|
|
paintDeviceState()
|
|
paintDeviceState()
|
|
|
}
|
|
}
|
|
@@ -4409,7 +4440,14 @@ function paintMarkerState() {
|
|
|
host.dataset.mapMarkersPlan = String(markerPlan.total)
|
|
host.dataset.mapMarkersPlan = String(markerPlan.total)
|
|
|
host.dataset.mapMarkersStatus = keys.map((key) => `${key}:${markerPlan.byStatus[key]}`).join(',')
|
|
host.dataset.mapMarkersStatus = keys.map((key) => `${key}:${markerPlan.byStatus[key]}`).join(',')
|
|
|
host.dataset.mapMarkerShapes = [...new Set(markerPlan.markers.map((item) => item.shape))].sort().join(',')
|
|
host.dataset.mapMarkerShapes = [...new Set(markerPlan.markers.map((item) => item.shape))].sort().join(',')
|
|
|
- // 票 45/85:摘要标记动效读数(与设备动效读数同构,且按**跨图层合计**状态写)。
|
|
|
|
|
|
|
+ paintMarkerEffects()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 合计动效变化就刷新,不必等点位实体重画。 */
|
|
|
|
|
+function paintMarkerEffects() {
|
|
|
|
|
+ if (!instance || !isDomHost(instance.host)) return
|
|
|
|
|
+ const host = instance.host
|
|
|
|
|
+ // 摘要、设备与设施使用同一份跨图层合计读数。
|
|
|
const state = combinedEffectState
|
|
const state = combinedEffectState
|
|
|
if (state.enabled !== true) host.dataset.mapMarkerEffects = 'off'
|
|
if (state.enabled !== true) host.dataset.mapMarkerEffects = 'off'
|
|
|
else if (state.degraded) host.dataset.mapMarkerEffects = 'degraded'
|
|
else if (state.degraded) host.dataset.mapMarkerEffects = 'degraded'
|