| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- /**
- * panelId → 视图计划构造函数的**唯一注册表**(票 18)。
- *
- * 为什么要有这一层:票 17 把「四块面板画法相同」兑现成了一个共享渲染层
- * (当时叫 `InfrastructurePanel.vue`,票 18 改名 `PanelBlocks.vue`),但它当时自己
- * 按 `panelId` 去问 `domain/infrastructurePanels.js` 要视图 —— 那个模块的名字与职责
- * 都只属于**基础设施模式**。票 18 接进运行监测模式时,若组件继续直接引用它,
- * 组件就从"通用块渲染"退化成"基础设施专属",票 19/20 接进来时还会再长出第三个入口。
- *
- * 所以分发收在**这一处**:每个模式各自拥有自己的 `domain/*Panels.js`(领域 + 视图计划),
- * 本文件只把它们注册到一起;组件吃**算好的 `view`**,不再认识任何模式。
- *
- * 与票 17 的分工一字不变(本票不发明新形状):
- * · 组件只按 `block.kind` 分派画法,不认识后端字段、不认识 panelId;
- * · 「哪个面板有哪些块」归各模式的 domain 模块(纯函数,可脱浏览器断言)。
- *
- * 本文件是纯函数层:不 import service、不碰 DOM。
- */
- import { withFilterCaliber } from './filterCaliber.js'
- import { INFRASTRUCTURE_PANEL_BUILDERS } from './infrastructurePanels.js'
- import { MONITORING_PANEL_BUILDERS } from './monitoringPanels.js'
- import { WARNING_RESPONSE_PANEL_BUILDERS } from './warningResponsePanels.js'
- import { OVERVIEW_PANEL_BUILDERS } from './overviewPanels.js'
- /**
- * 全部已实现面板的视图构造器。
- *
- * panelId 扁平且全局唯一(ADR 0003),所以合并不会撞键;万一将来撞了,
- * 应当是**立刻可见的错误**而不是静默覆盖 —— 下面 `assertRegistry()` 会在模块加载时拦住。
- */
- const BUILDERS = {
- ...OVERVIEW_PANEL_BUILDERS,
- ...INFRASTRUCTURE_PANEL_BUILDERS,
- ...MONITORING_PANEL_BUILDERS,
- ...WARNING_RESPONSE_PANEL_BUILDERS,
- }
- /** 合并前逐键检查:两个模式不得注册同一个 panelId(撞了说明目录或命名出错)。 */
- function assertRegistry() {
- const groups = [OVERVIEW_PANEL_BUILDERS, INFRASTRUCTURE_PANEL_BUILDERS, MONITORING_PANEL_BUILDERS, WARNING_RESPONSE_PANEL_BUILDERS]
- const seen = new Set()
- const duplicates = []
- for (const group of groups) {
- for (const panelId of Object.keys(group)) {
- if (seen.has(panelId)) duplicates.push(panelId)
- seen.add(panelId)
- }
- }
- if (duplicates.length) {
- throw new Error(`panelId 在模式注册表里重复:${duplicates.join(', ')}`)
- }
- }
- assertRegistry()
- /** 这个 panelId 有没有接真实视图(没有的仍是占位面板,占位文案是"哪几块还没接数据"的信号)。 */
- export function hasPanelView(panelId) {
- return Object.prototype.hasOwnProperty.call(BUILDERS, panelId)
- }
- /** 已实现的面板 id 清单(外壳据此决定走真面板还是占位)。 */
- export function implementedPanelIds() {
- return Object.keys(BUILDERS)
- }
- /**
- * 算一个面板的视图计划。
- *
- * `data` 为 null(失败/空/还没取数)时**仍然返回结构完整的视图**(块为空)——
- * 「失败」不该让整块面板消失,那会连面板标题都没了(票 17 的立场,本票沿用)。
- *
- * @param {string} panelId 目录键
- * @param {object|null} data 分区里的领域对象
- * @param {object} section 分区(`domain/sectionState.js` 的 `section()`)
- * @param {object} [extra] 额外渲染输入(票 18 的台账徽标走这里;别的面板不需要)
- * @returns {object|null} 视图计划;panelId 没接数据时回 null(调用方画占位)
- */
- export function panelView(panelId, data, section, extra) {
- const build = BUILDERS[panelId]
- if (!build) return null
- // 票 67:全局筛选(当前范围/行业)**生效到哪里、没生效到哪里**由 domain/filterCaliber.js
- // 一张表说了算,在这里统一并进视图的 `gap`(口径缺口)。放在注册表这一处而不是逐面板
- // 各写一句:面板新增/改名时不会漏,闸门也能按 `implementedPanelIds()` 做正向普查。
- return withFilterCaliber(build(data, section, extra), panelId)
- }
|