| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- diff --git a/src/modules/cockpit/components/MapInfoPanel.vue b/src/modules/cockpit/components/MapInfoPanel.vue
- index 8668e75..b91d3f1 100644
- --- a/src/modules/cockpit/components/MapInfoPanel.vue
- +++ b/src/modules/cockpit/components/MapInfoPanel.vue
- @@ -43,0 +44,9 @@
- + <p class="map-info__note" data-pipe-model-note>{{ PIPE_MODEL_NOTE }}</p>
- + <p v-if="pipeModelState" class="map-info__line" data-pipe-model-status role="status">
- + 管道模型 {{ pipeModelState.instances }} 实例 / {{ pipeModelState.batches }} 批 ·
- + 折线/符号 {{ pipeModelState.fallback }} 对象
- + <template v-if="pipeModelState.planning || pipeModelState.pending"> · 模型加载中(保留降级表达)</template>
- + <template v-if="pipeModelState.failed"> · {{ pipeModelState.failed }} 批素材失败,已降级</template>
- + <template v-if="pipeModelState.terrainFailed"> · 地表高程采样失败,已保留折线/符号,稍后刷新重试</template>
- + </p>
- +
- @@ -59,0 +69,5 @@ import MapCoordinateBlocked from './MapCoordinateBlocked.vue'
- +import { PIPE_MODEL_NOTE } from '../domain/pipeModels.js'
- +
- +const pipeModelState = ref(null)
- +let modelHost = null
- +const updatePipeModelState = (event) => { pipeModelState.value = event.detail }
- @@ -102,0 +117,2 @@ onMounted(() => {
- + modelHost = host
- + host.addEventListener('cockpit-pipe-model-state', updatePipeModelState)
- @@ -107,0 +124,2 @@ onBeforeUnmount(() => {
- + if (modelHost) modelHost.removeEventListener('cockpit-pipe-model-state', updatePipeModelState)
- + modelHost = null
- diff --git a/src/modules/cockpit/services/cesiumPipeLayer.js b/src/modules/cockpit/services/cesiumPipeLayer.js
- index ddb0620..6dcb74a 100644
- --- a/src/modules/cockpit/services/cesiumPipeLayer.js
- +++ b/src/modules/cockpit/services/cesiumPipeLayer.js
- @@ -12,5 +12,4 @@
- - * 渲染口径(与 `domain/pipeNetwork.js` 同源,引擎不再做第二次判定):
- - * · 管段:`clampToGround` 贴地折线,管径映射线宽,行业映射颜色;
- - * · 构件:阀门 / 角管道 / 支管管道各用**可辨识符号 + 中文标签**表达。
- - * glTF 预制构件实例化需要素材库,仓库内暂无管线素材,故先用符号表达并保留扩展位——
- - * **不拿临时符号冒充"已建成的管道模型"**。
- + * 渲染口径(与领域建模计划同源,引擎不再做第二次准入判定):
- + * · 已知管径/类型:独立 Cesium GPU 批次、地表采样减虚拟埋深 2m;
- + * · 模型未就绪、缺管径/类型/素材/高程:保留贴地折线或符号标签。
- + * glTF 在 readyEvent 后替代降级表达,示意外形与近似朝向不冒充真实安装信息。
- @@ -20,0 +20,5 @@ import { pipeWidth } from '../domain/pipeNetwork.js'
- +// Viewer-scoped batches; loaded lazily so symbol-only/headless paths do not load the model adapter.
- +const modelLayers = new WeakMap()
- +const layerVersions = new WeakMap()
- +let modelAdapterPromise = null
- +
- @@ -124,2 +152,4 @@ function componentEntity(code, component) {
- -export async function syncPipeLayer(viewer, network) {
- - if (!viewer || !viewer.dataSources) return { pipes: 0, components: 0, rendered: false }
- +export async function syncPipeLayer(viewer, network, { onModelChange = () => {} } = {}) {
- + if (!viewer || !viewer.dataSources) return { pipes: 0, components: 0, rendered: false, added: 0, updated: 0, removed: 0, unchanged: 0 }
- + const version = (layerVersions.get(viewer) || 0) + 1
- + layerVersions.set(viewer, version)
- @@ -128,0 +159 @@ export async function syncPipeLayer(viewer, network) {
- + if (layerVersions.get(viewer) !== version) return { pipes: 0, components: 0, rendered: false }
- @@ -170 +221,14 @@ export async function syncPipeLayer(viewer, network) {
- - return { pipes: pipes.length, components: components.length, rendered: true }
- + // Keep fallback entities until ALL model spans for that business object signal ready.
- + // The model adapter alone controls entity.show; unchanged geometries still stay untouched (ticket 33).
- + if (viewer.scene && viewer.scene.primitives && !viewer.isDestroyed()) {
- + modelAdapterPromise ||= import('./cesiumPipeModels.js')
- + const { createCesiumPipeModels } = await modelAdapterPromise
- + if (viewer.isDestroyed() || layerVersions.get(viewer) !== version) return { pipes: 0, components: 0, rendered: false }
- + let layer = modelLayers.get(viewer)
- + if (!layer) {
- + layer = createCesiumPipeModels(viewer, { source, onChange: onModelChange })
- + modelLayers.set(viewer, layer)
- + }
- + layer.sync({ pipes, components })
- + }
- + return { pipes: pipes.length, components: components.length, rendered: true, ...stats }
- @@ -174,0 +239,3 @@ export async function clearPipeLayer(viewer) {
- + if (viewer) layerVersions.set(viewer, (layerVersions.get(viewer) || 0) + 1)
- + const layer = viewer && modelLayers.get(viewer)
- + if (layer) { layer.destroy(); modelLayers.delete(viewer) }
- diff --git a/src/modules/cockpit/services/mapService.js b/src/modules/cockpit/services/mapService.js
- index 2eaa74c..065ceac 100644
- --- a/src/modules/cockpit/services/mapService.js
- +++ b/src/modules/cockpit/services/mapService.js
- @@ -1004,0 +1005 @@ export function unmountMap() {
- + if (record.pipeLayer) record.pipeLayer.clearPipeLayer(record.viewer)
- @@ -2383,2 +2385,18 @@ export async function syncPipeLayerForPlan(plan) {
- - await engine.syncPipeLayer(instance.viewer, layer)
- - const host = instance.host
- + if (instance !== record || !record.viewer) return false
- + record.pipeLayer = engine
- + await engine.syncPipeLayer(record.viewer, layer, { onModelChange: (state) => {
- + if (instance !== record || !record.host) return
- + const host = record.host
- + if (host.dataset) {
- + host.dataset.mapPipeModelBatches = String(state.batches)
- + host.dataset.mapPipeModelInstances = String(state.instances)
- + host.dataset.mapPipeModelFallback = String(state.fallback)
- + host.dataset.mapPipeModelPending = String(state.pending)
- + host.dataset.mapPipeModelFailed = String(state.failed)
- + host.dataset.mapPipeModelKinds = JSON.stringify(state.byKind)
- + host.dataset.mapPipeVirtualDepth = '2'
- + }
- + host.dispatchEvent(new CustomEvent('cockpit-pipe-model-state', { detail: state }))
- + } })
- + if (instance !== record) return false
- + const host = record.host
|