# Research: 面板字段与后端契约覆盖 **Ticket:** [24: 面板字段与后端契约覆盖调研](../issues/24-panel-field-coverage.md) **Date:** 2026-09-15 **Scope:** 决策事实。只读调研,未改动任何业务代码、后端代码或构建产物。 **Method:** 逐类阅读后端控制器(`com.zksy.web.controller.cockpit`)与响应/快照类(`com.zksy.cockpit.*`),不依赖 OpenAPI(Swagger 已注释)。演示页 `E:\pipe-ner-server\docs\cockpit\*.html` 仅作样例旁证。 --- ## Decision **16 个二级面板中,5 个字段完全覆盖,11 个存在缺口。** 关键纠偏:**本票与上游任务书列举的「现有契约」清单遗漏了 4 个面板级读模型端点**。后端已经为总体概览与基础档案提供了一整层聚合读模型(`/overview/infrastructure`、`/overview/monitoring`、`/overview/warning-settings`、`/infrastructure/base-archives`),还有一个 `GET /api/cockpit/v1/events/{eventSource}/{eventCode}/work-orders`。因此「总体概览三面板 + 基础档案 + 监测概览」实际上是**已有**的,不需要补契约。 真正的缺口集中在四类,都是「**跨设备 / 跨设施的读模型**」缺失,而不是单设备字段缺失: 1. 跨设备事件流(当前 + 历史 + 时间范围参数)— 后端事件读取一律以 `deviceCode` 为路径参数。 2. 监测点的行业/类型维度(`map-snapshot` 既无 `industry` 入参,点位摘要也无 `industry`/类型字段)— 卡住 CONTEXT.md 定义的全局「行业筛选」。 3. 应急保障域(危险源/防护目标/应急资源)在后端 cockpit 包内**完全不存在**。 4. 效率时长聚合(响应时长/关闭时长)与事件多维分布聚合。 --- ## 1. 后端契约基线(实测端点清单) `@GetMapping` 全量枚举结果(`com.zksy.web.controller.cockpit`,共 18 个 GET): | # | 端点 | 控制器 | 关键入参 | 响应类 | | --- | --- | --- | --- | --- | | 1 | `/api/cockpit/v1/foundation` | `CockpitFoundationController`(类级 `@RequestMapping("/api/cockpit/v1")`) | — | `CockpitFoundationResponse` | | 2 | `/api/cockpit/v1/map-snapshot` | `CockpitMapSnapshotController` | `page`,`pageSize`(默认500,上限1000),`snapshotAt` | `CockpitMapSnapshotResponse` | | 3 | `/api/cockpit/v1/monitoring-points/{monitoringPointCode}` | `CockpitMonitoringPointDetailController` | path | `CockpitMonitoringPointDetailResponse` | | 4 | `/api/cockpit/v1/device-boundary` | `CockpitDeviceBoundaryController` | — | `CockpitDeviceBoundaryResponse` | | 5 | `/api/cockpit/v1/overview/infrastructure` | `CockpitOverviewInfrastructureController` | — | `CockpitOverviewInfrastructureResponse` | | 6 | `/api/cockpit/v1/overview/monitoring` | `CockpitOverviewMonitoringController` | `industry` | `CockpitOverviewMonitoringResponse` | | 7 | `/api/cockpit/v1/overview/warning-settings` | `CockpitOverviewWarningSettingsController` | `mode`(WARNING\|ALARM) | `CockpitOverviewWarningSettingsResponse` | | 8 | `/api/cockpit/v1/infrastructure/base-archives` | `CockpitInfrastructureBaseArchivesController` | `industry`,`facilityType`,`ageBucket`,`region` | `CockpitInfrastructureBaseArchivesResponse` | | 9 | `/api/cockpit/v1/equipments/{deviceCode}/archive` | `CockpitEquipmentArchiveController` | path | `CockpitEquipmentArchiveResponse` | | 10 | `/api/cockpit/v1/equipments/{deviceCode}/detail-aggregate` | `CockpitEquipmentDetailAggregateController` | path | `CockpitEquipmentDetailAggregateResponse` | | 11 | `/api/cockpit/v1/equipments/{deviceCode}/metrics/current` | `CockpitTypeMetricsController` | path | `CockpitTypeMetricsResponse` | | 12 | `/api/cockpit/v1/equipments/{deviceCode}/metrics/history` | `CockpitTypeMetricsController` | `startTime`,`endTime`,`page`,`pageSize` | `CockpitTypeMetricsResponse` | | 13 | `/api/cockpit/v1/equipments/{deviceCode}/events/current` | `CockpitEventReadController` | path | `CockpitEventReadResponse` | | 14 | `/api/cockpit/v1/equipments/{deviceCode}/events/history` | `CockpitEventReadController` | `startTime`(必填),`endTime`(必填),`page`,`pageSize` | `CockpitEventReadResponse` | | 15 | `/api/cockpit/v1/equipments/{deviceCode}/work-orders` | `CockpitWorkOrderReadController` | path | `CockpitWorkOrderReadResponse` | | 16 | `/api/cockpit/v1/events/{eventSource}/{eventCode}/work-orders` | `CockpitWorkOrderReadController` | path | `CockpitWorkOrderReadResponse` | | 17 | `/api/cockpit/v1/work-orders/{workOrderCode}/timeline` | `CockpitWorkOrderReadController` | path | `CockpitWorkOrderTimelineResponse` | | 18 | `/api/cockpit/v1/equipments/{deviceCode}/freshness` | `CockpitFreshnessController` | `calibrationPeriodSeconds` | `CockpitFreshnessResponse` | 端点 1、5、6、7、8、16 **不在**本票与上游任务书给出的清单里。这是本调研对字段覆盖判定影响最大的一条事实。 响应统一包在 `AjaxResult` 里(`ResponseEntity`),业务负载在 `data` 下。 ### WebSocket `/ws/deviceStatus` `DeviceStatusWebSocketHandler`(`zksy-admin/.../web/websocket/`)消息类型:`authenticate`、`subscribe`、`unsubscribe`、`cockpitSubscribe`、`deviceStatus`、`workOrderReminder`、`ping`。 驾驶舱相关链路: - 订阅:`→ {"type":"cockpitSubscribe","scope":"all"}`;`← {"type":"cockpitSubscribed","scope":"all","serverUpdatedAt":"..."}` - 增量:`← {"type":"cockpitDeviceStatusDelta","deviceCode":"DEV001","device_code":"DEV001","data":{"status":"ALARM","statusTime":"...","serverUpdatedAt":"...","reason":"..."}}` **重要语义(`DeviceStatusWebSocketHandler` 第 341-357 行注释原文)**:「驾驶舱全量范围订阅;**REST 仍是初始快照,这里只接收后续状态增量**」。`cockpitSubscribed` 回帧**不含**任何初始设备状态数组。 **字段名不一致**:WS 线上帧的增量状态键是 `data.status`(`DeviceStatusRedisListener.cockpitDeltaMessage` 第 179 行),而后端 DTO `CockpitOverviewMonitoringDeviceStatusDelta` 的字段名是 `monitoringState`。前端映射时需按 WS 线上帧的 `status` 取值。 **增量不含**坐标、行业、设备类型——只能靠 `deviceCode` 回联 REST 快照。 --- ## 2. 判定口径 | 等级 | 含义 | | --- | --- | | **已有** | 现有端点响应中存在对应字段(可能需换一个端点取) | | **可推导** | 需组合/回联现有字段,或有 N+1 代价;不需后端改契约 | | **缺失** | 现有契约无论怎么组合都拿不到,需后端补契约 | 每条判定附后端类名。字段语义以 ADR 0003 的面板词典 + `CONTEXT.md` 术语为准,实现细节参考票 17-20 的验收项,未发明业务。 --- ## 3. 逐面板字段覆盖 ### 3.1 `overview` 模式 #### `situationSummary` 态势总览 — ⚠️ 1 处缺口 `CONTEXT.md` 定义:跨行业 KPI,展示设施底数、监测规模、在线率、当前预警/报警、处置率和近 7 日趋势。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 设施底数 | `CockpitOverviewInfrastructureResponse.Totals.facilityCount` | 已有 | | 监测规模(智能设备数) | `CockpitOverviewInfrastructureResponse.Totals.smartDeviceCount` | 已有 | | 监测点规模 | `CockpitOverviewMonitoringResponse.Counts.monitoringPointCount` | 已有 | | 在线率 | `CockpitOverviewMonitoringResponse.Counts.OnlineRate.{value,onlineCount,denominator,state,reason}` | 已有 | | 当前预警/报警数 | `CockpitOverviewWarningSettingsResponse.FamilyMetrics.{total,pending}`(`warning` / `alarm` 各一份) | 已有 | | 处置率 | `FamilyMetrics.handlingEfficiency.{numerator,denominator,value,state,reason}` | 已有(语义为「结案率」:分子=state 6,分母=全部事件,见 `CockpitOverviewWarningSettingsService` 第 32、133-146 行) | | 近 7 日趋势 | `FamilyMetrics.trend[]`(`TrendPoint.{bucket,total,handled,handlingEfficiency}`) | **缺失(窗口不可声明)** | | 可读的「无数据」态 | `FamilyMetrics.{state,stateReason}`、`Freshness.{status,reason}` | 已有 | **缺口证据**:`CockpitOverviewWarningSettingsService.load` 第 59 行硬编码 `new Range("CURRENT_BASELINE", null, null)`,且控制器只接受 `mode`(`CockpitOverviewWarningSettingsController` 第 35 行)。趋势桶完全由适配器快照决定,前端**无法声明「近 7 日」**。ADR 0003 明确要求「近 7 日趋势」。 #### `infrastructureSummary` 基础设施 — ✅ 全覆盖 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 设施底数 | `CockpitOverviewInfrastructureResponse.Totals.facilityCount` | 已有 | | 行业构成 | `CockpitOverviewInfrastructureResponse.Industry[]`(`code,key,label,facilityCount,smartDeviceCount`) | 已有 | | 行业下的类型构成 | `Industry.facilityTypes[] / deviceTypes[]` → `TypeSummary.{code,name,count,lengthKm,scale,range}` | 已有 | | 区域分布 | `CockpitInfrastructureBaseArchivesResponse.regionDistribution[].{code,count}` | 已有(经 #8 端点) | | 规模里程 | `CockpitInfrastructureBaseArchivesResponse.Totals.{lengthKm,scale}` | 已有 | | 剔除口径可解释性 | `CockpitOverviewInfrastructureResponse.Excluded.{unknownTypeCount,typeKindMismatchCount}` | 已有 | `CockpitOverviewInfrastructureResponse` 自身不含区域字段,但 #8 端点提供,故判「已有」。 #### `monitoringSummary` 运行监测 — ✅ 全覆盖 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 在线率 | `CockpitOverviewMonitoringResponse.Counts.OnlineRate` | 已有 | | 离线统计 | `Counts.Status.{online,offline,stale,unknownOrMissing,denominator}` | 已有 | | 故障统计 | 同上(无独立「故障」桶;只能映射到 `stale` / `unknownOrMissing`) | 已有(语义需确认,见 §5 待定项) | | 监测覆盖 | `Counts.{deviceCount,monitoringPointCount,monitoringFacilityCount,infrastructureFacilityCount}` + `FormalScope.{industries,keys}` | 已有 | | 最近采集时间 | `CockpitOverviewMonitoringResponse.MetricFreshness.{status,updatedAt,serverUpdatedAt}` | 已有 | | 数据新鲜度 | `CockpitOverviewMonitoringResponse.Freshness.{status,reason,...}` | 已有 | | 类型分布 | `CockpitOverviewMonitoringResponse.TypeDistribution[]`(`industry`,`deviceType{code,name}`,`deviceCount`) | 已有 | | 行业筛选回显 | `selectedIndustry{code,key,label}` | 已有 | #### `alertSettings` 预警设置 — ✅ 全覆盖 票 20 要求「保持合同名称,只读展示预警/报警统计」,与 `CockpitOverviewWarningSettingsResponse` 一一对应。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 预警/报警总览 | `FamilyMetrics.{total,handled,pending}` | 已有 | | 已取消 | `FamilyMetrics.cancelledCount` | 已有 | | 未关联工单 / 异常工单状态 | `FamilyMetrics.{unlinkedEventCount,invalidWorkOrderStateCount}` | 已有 | | 工单七态分布 | `FamilyMetrics.workOrderStates`(`Map`,键 1-7,字典见 `CockpitWorkOrderStateDictionary`) | 已有 | | 处置率 | `FamilyMetrics.handlingEfficiency` | 已有 | | 趋势 | `FamilyMetrics.trend[]` | 已有 | | 双模式选择与地图过滤语义 | `selectedMode`、`MapFilter.{eventFamily,label}` | 已有 | | 时间范围声明 | `Range` | **缺失**(`type="CURRENT_BASELINE"`,start/end 为 null) | ### 3.2 `infrastructure` 模式 #### `archive` 基础档案 — ✅ 全覆盖 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 设施规模 | `CockpitInfrastructureBaseArchivesResponse.Totals.{facilityCount,lengthKm,scale}` | 已有 | | 行业分类 | `industryDistribution[].{code,count}` | 已有 | | 设施类型分布 | `facilityTypeDistribution[]` → `TypeSummary` | 已有 | | 区域分布 | `regionDistribution[].{code,count}` | 已有 | | 档案摘要(年限) | `ageDistribution[].{code,count}` + `ageReference.{asOfDate,commissionedCount,builtCount,unknownCount}` | 已有 | | 筛选回显 | `selectedFilters` + `mapFilter` | 已有 | | 口径剔除 | `excluded.{unknownTypeCount,typeKindMismatchCount,smartDeviceCount,futureDateCount}` | 已有 | | 单设备档案明细 | `CockpitEquipmentArchive`(`deviceModel,deviceSpec,manufacturer,productionDate,deviceType,deviceTypeName,assetValue,expectedServiceYears,longitude,latitude,equipmentLocation,installTime,maintainer,maintainerPhone,ownershipUnit,remark,coordinateSystem,latestImage`) | 已有(#9 端点) | #### `operation` 运行信息 — ❌ 2 处缺口 票 17 要求「供应、输送、承载能力和指标占位」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 指标占位(当前值) | `CockpitMetric.{metricCode,metricName,value,unit,status,sampledAt,freshness}` | 已有(**设备级**,#11 端点) | | 指标历史序列 | `CockpitMetric.points[]` → `CockpitMetricPoint.{value,status,sampledAt,freshness}` | 已有(设备级,#12 端点) | | 指标可用性态 | `CockpitTypeMetricsResponse.{state,stateReason}` | 已有 | | 设施级「供应能力」 | 无任何设施属性契约(`CockpitFacilityBoundary` 只有 `facilityCode,facilityName,facilityType,objectKind,industry,formalScope`) | **缺失** | | 设施级「输送能力」 | 同上 | **缺失** | | 设施级「承载能力」 | 同上 | **缺失** | | 设施级指标聚合(一个设施下多设备的汇总) | #11/#12 只以 `deviceCode` 为路径参数;无 `facilityCode` 维度 | **缺失** | 注:若「供应/输送/承载能力」首期只是**指标占位**,则可先以设备级 `CockpitMetric` 占位满足;但设施级聚合仍缺失。 #### `management` 管理信息 — ❌ 3 处缺口 票 17 要求「管理单位、权属单位和责任区域」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 权属单位 | `CockpitEquipmentArchive.ownershipUnit` | 已有(**仅设备级**) | | 维护方与联系人 | `CockpitEquipmentArchive.{maintainer,maintainerPhone}` | 已有 | | 管理单位 | 无该字段;最接近的是 `maintainer`(维护单位),与「管理单位」是不同的业务概念 | **缺失** | | 责任区域(设施维度) | `CockpitInfrastructureBaseArchivesSnapshot.SourceFacility.region` 存在,但**未在响应里逐设施暴露**;响应只有聚合的 `regionDistribution` | **可推导(弱)** | | 责任区域(设备维度) | `CockpitEquipmentArchive.equipmentLocation`(自由文本) | 可推导 | | 按区域聚合的管理单位/权属单位 | 无任何按 `ownershipUnit` / `maintainer` 分组的契约 | **缺失** | #### `emergency` 应急保障 — ❌ 全域缺失 票 17 要求「危险源、防护目标和应急资源」。 对 `com.zksy.cockpit` 全包按 `危险源|防护目标|应急|权属|管理单位|责任` 检索:**除 `region` 外无任何命中**。危险源、防护目标、应急资源、应急预案、应急物资、应急队伍在后端 cockpit 契约中均不存在。 | 需要的字段 | 判定 | | --- | --- | | 危险源 | **缺失** | | 防护目标 | **缺失** | | 应急资源 | **缺失** | | 空间定位与可上图状态 | **缺失** | #### `monitoring` 模式 #### `monitoringOverview` 监测概览 — ✅ 全覆盖 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 监测点规模 | `CockpitOverviewMonitoringResponse.Counts.monitoringPointCount` | 已有 | | 设备规模 | `Counts.deviceCount` | 已有 | | 在线率 | `Counts.OnlineRate` | 已有 | | 类型分布 | `typeDistribution[]` | 已有 | | 最近采集时间 | `metricFreshness.updatedAt` | 已有 | | 行业筛选 | 端点 `industry` 入参 + `selectedIndustry` | 已有 | | 监测设施/基础设施口径 | `Counts.{monitoringFacilityCount,infrastructureFacilityCount}` | 已有 | #### `monitoringDistribution` 监测分布 — ❌ 2 处缺口 票 18 要求「覆盖情况、状态分布和地图筛选」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 覆盖情况 | `CockpitOverviewMonitoringResponse.FormalScope` + `Counts.{monitoringFacilityCount,infrastructureFacilityCount}` | 已有 | | 状态分布(点位状态) | `CockpitMonitoringPointSummary.pointStatus`(`CockpitMonitoringPointStatus` 6 值:ALARM/WARNING/WORK_ORDER/NORMAL/OFFLINE/EMPTY) | 已有(前端计数) | | 状态原因明细 | `CockpitMonitoringPointSummary.statusReasons[]` + `CockpitMonitoringPointStatusReason.{status,deviceCode,reason}` | 已有 | | 状态字典与优先级 | `CockpitMonitoringPointDetailResponse.statusDictionary[]` → `{status,label,priority}` | 已有 | | 无坐标点位分布 | `CockpitCoordinateValidationSummary` + 逐点 `CockpitCoordinateValidation.{state,reason,renderable,crs}` | 已有 | | 未关联设备 | `CockpitMapSnapshotResponse.unassociatedEquipment[]` | 已有 | | **地图按行业筛选** | `CockpitMapSnapshotController` 只接受 `page,pageSize,snapshotAt`(第 33-38 行);`CockpitMonitoringPointSummary` 无 `industry` 字段 | **缺失** | | **地图按点位类型筛选** | `CockpitMonitoringPointSummary` 无类型字段(内部 `CockpitMapSnapshot.SourceMonitoringPoint` 也无类型) | **缺失** | **影响面超出本面板**:CONTEXT.md 定义「行业筛选」是**作用于整个驾驶舱的全局范围条件**。`overview/monitoring` 与 `base-archives` 支持 `industry`,但一张图的 `map-snapshot` 不支持,且点位摘要无法回联行业(见 `monitoringPointLedger`),所以全局行业筛选目前**无法落到地图点位上**。 #### `operationOverview` 运行概况 — ❌ 1 处缺口 票 18 要求「事件趋势、离线设备和异常态势」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 事件趋势 | `CockpitOverviewWarningSettingsResponse.FamilyMetrics.trend[]` | 已有(窗口不可声明) | | 离线数量 | `CockpitOverviewMonitoringResponse.Counts.Status.offline` | 已有 | | 离线设备**清单** | 无跨设备设备状态列表;`map-snapshot` 只给点位状态,`CockpitOverviewMonitoringDeviceStatusDelta` 只是增量 | **缺失** | | 异常态势 | 设备级 `CockpitTypeMetricsResponse.{state,stateReason}`、`CockpitFreshnessResponse.freshness` | 已有(逐设备) | | 跨设备异常汇总 | 无 | **缺失** | #### `monitoringPointLedger` 监测点台账 — ❌ 4 处缺口 CONTEXT.md:以滚动卡片列出当前筛选范围内监测点;点击卡片进入两级详情。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 点位编码/名称 | `CockpitMonitoringPointSummary.{pointCode,pointName}` | 已有 | | 点位状态 + 原因 | `pointStatus`,`statusReasons[]` | 已有 | | 坐标与可上图状态 | `longitude`,`latitude`,`coordinateValidation` | 已有 | | 滚动分页 | `page`,`pageSize`,`total`,`complete`,`snapshotAt` | 已有 | | **所属行业**(筛选范围) | 点位摘要无 `industry`;`map-snapshot` 无 `industry` 入参 | **缺失** | | **点位类型** | 点位摘要无类型字段 | **缺失** | | **设备计数徽标**(总数/在线/报警/预警) | 需对每个点调 `monitoring-points/{code}` 取 `CockpitMonitoringPointDeviceStatistics.{totalDeviceCount,alarmDeviceCount,warningDeviceCount,workOrderDeviceCount,normalDeviceCount,offlineDeviceCount}` | **可推导(N+1)** | | **点位最近采集时间** | 需逐设备 `metrics/current` 或 `freshness` | **缺失(批量)** | | 关联设备编码 | `CockpitMapSnapshot.SourceMonitoringPoint.devices` 存在于**内部**快照,但 `CockpitMapSnapshotService.monitoringPoint()` 第 145-160 行**不写入响应** | **缺失** | 台账面板因此无法在单次 `map-snapshot` 分页内渲染卡片,必须退化为 N+1 调用。 ### 3.3 `warningResponse` 模式 #### `currentEvents` 当前预警 — ❌ 2 处缺口 票 19 要求「当前事件、工单状态和设备定位」。ADR 0003:当前事件列表默认 10-15 条。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 事件明细字段(预警) | `CockpitEventWarning.{warningNo,warningName,warningType,level,levelColor,status,eventTime,value,unit,deviceCode,deviceName,location}` | 已有(**设备级**) | | 事件明细字段(报警)+ 阈值 | `CockpitEventAlarm.{alarmId,warningCode,warningName,warningType,level,levelColor,status,eventTime,value,thresholdMinValue,thresholdMaxValue,unit,deviceCode,deviceName,location}` | 已有(设备级) | | 预警-报警关联 | `CockpitAlarmWarningRelation.{relationId,warningNo,alarmId,relatedAt}` | 已有 | | 等级配色 | `level` + `levelColor`(`CockpitEventLevelColor.resolve`:1→RED,2→YELLOW,3→BLUE,4→GREEN) | 已有 | | 工单状态(设备维度) | `CockpitWorkOrderReadResponse.workOrders[]` → `CockpitWorkOrderSummary.stateCode/stateName` + `stateDictionary` | 已有(#15) | | 工单状态(事件维度) | #16 `events/{eventSource}/{eventCode}/work-orders` | 已有 | | 动作轨迹 | `CockpitWorkOrderTimelineResponse.timelineEntries[]` → `CockpitWorkOrderTimelineEntry.{stateCode,stateName,operationName,operationDesc,operatorName,operatedAt}` | 已有(#17) | | **跨设备当前事件列表**(一次取 10-15 条) | 三个事件端点全部以 `deviceCode` 为路径参数;无跨设备事件读模型 | **缺失** | | **事件 → 地图坐标** | `CockpitEventWarning/Alarm` 只有 `location`(文本),无经纬度;`map-snapshot` 也不返回已关联设备的坐标 | **缺失** | | 事件排序/截断规则 | 无跨设备契约 | **缺失** | #### `historyAnalysis` 历史分析 — ❌ 2 处缺口 票 19 要求「历史事件趋势和时间范围筛选」。ADR 0003:历史列表提供 7/30/90 天和自定义时间范围。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 历史事件明细(单设备,带时间范围) | `equipments/{deviceCode}/events/history?startTime&endTime&page&pageSize` | 已有(**设备级**,`startTime`/`endTime` 必填) | | 历史分页 | `CockpitEventReadResponse.{page,pageSize,total,startTime,endTime,timezone}` | 已有 | | **跨设备历史事件列表** | 无 | **缺失** | | **趋势的时间范围参数(7/30/90/自定义)** | `overview/warning-settings` 只接受 `mode`;`Range("CURRENT_BASELINE",null,null)` 硬编码 | **缺失** | | 趋势桶序列 | `FamilyMetrics.trend[].bucket` | 已有(但窗口服务端固定) | #### `responseEfficiency` 预警效率 — ❌ 1 处缺口(含 2 个字段) 票 19 要求「处置率、响应时长、关闭时长和工单七态分布」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 处置率 | `FamilyMetrics.handlingEfficiency` | 已有 | | 工单七态分布 | `FamilyMetrics.workOrderStates` + `CockpitWorkOrderStateDictionary`(7 态) | 已有 | | 趋势效率 | `trend[].handlingEfficiency` | 已有 | | 单工单时长(可算) | `CockpitWorkOrderSummary.{createTime,updateTime,planFinishTime,realFinishTime}` | 可推导(**逐工单**) | | 接单时点(算响应时长所需) | `CockpitWorkOrderTimelineEntry` 中 `stateCode=3`(已接单)的 `operatedAt` | 可推导(**逐工单,需拉 timeline**) | | **响应时长聚合 KPI** | 无任何时长字段 | **缺失** | | **关闭时长聚合 KPI** | 无任何时长字段 | **缺失** | 对 `docs/cockpit/*.html` 按 `duration|响应时长|关闭时长|responseTime` 检索:**零命中**,旁证该维度确未实现。 #### `eventAnalysis` 预警分析 — ❌ 1 处缺口(多个维度) 票 19 要求「多维事件分布和重点识别」。 | 需要的字段 | 来源 | 判定 | | --- | --- | --- | | 按类型(单设备) | `CockpitEventWarning.warningType` / `CockpitEventAlarm.warningType` | 可推导(**仅逐设备事件**) | | 按等级(单设备) | `level` + `levelColor` | 可推导(逐设备) | | 按设备类型(单设备) | `CockpitEventReadResponse.{deviceType,deviceTypeName}` | 可推导(逐设备,响应级字段) | | **按类型聚合分布** | 无聚合契约 | **缺失** | | **按等级聚合分布** | 无聚合契约 | **缺失** | | **按行业分布** | 事件对象无 `industry` 字段 | **缺失** | | **按区域分布** | 事件对象无区域字段 | **缺失** | | **重点识别 / Top-N / 热点** | 无 | **缺失** | --- ## 4. 补契约清单(汇总所有「缺失」项) ### A. 跨设备事件读模型 —— 最高优先级 覆盖面板:`currentEvents`、`historyAnalysis`、`eventAnalysis`、`operationOverview`(异常态势)。 现有事件端点全部是 `equipments/{deviceCode}/...`,无法支撑「当前事件列表 10-15 条」这类跨设备视图。 **A1. 建议新端点** `GET /api/cockpit/v1/events/current` | 参数 | 语义 | | --- | --- | | `industry` | 行业筛选(对齐 CONTEXT.md 全局行业筛选) | | `family` | `WARNING` \| `ALARM` \| 空=两者 | | `page`,`pageSize` | 分页,默认 1 / 15 | | 建议字段 | 语义 | | --- | --- | | `eventFamily` | `WARNING` \| `ALARM` | | `eventCode` | 预警用 `warningNo`,报警用 `alarmId`,统一键 | | `eventName`,`eventType`,`level`,`levelColor`,`status`,`eventTime`,`value`,`unit` | 复用 `CockpitEventWarning`/`CockpitEventAlarm` 同名语义 | | `thresholdMinValue`,`thresholdMaxValue` | 仅报警;复用 `CockpitEventAlarm` | | `deviceCode`,`deviceName` | 复用 | | `monitoringPointCode`,`monitoringPointName` | 新增:事件归属监测点,供两张图/台账联动 | | `industry`,`drainageScope`,`objectKind` | 新增:行业归属,供全局行业筛选与事件分析 | | `longitude`,`latitude` | **新增**:事件定位(当前只有文本 `location`) | | `coordinateValidation` | 复用 `CockpitCoordinateValidation`(`state,reason,renderable,crs`) | | `workOrderCode`,`workOrderStateCode`,`workOrderStateName` | 新增:事件当前工单状态,省掉按事件二次请求 | | `page`,`pageSize`,`total`,`updatedAt`,`freshness` | 复用既有分页/新鲜度语义 | **A2. 建议新端点** `GET /api/cockpit/v1/events/history` 参数在 A1 基础上加 `startTime`、`endTime`(必填,支持 7/30/90 天与自定义)。响应体结构与 A1 一致,另加 `range{type,start,end}`。 ### B. 趋势时间范围可声明 覆盖面板:`situationSummary`(近 7 日趋势)、`historyAnalysis`、`alertSettings`、`operationOverview`。 **建议扩展** `GET /api/cockpit/v1/overview/warning-settings` 入参:`range` + `startTime` + `endTime`。 | 建议字段 | 语义 | | --- | --- | | `range.type` | `LAST_7_DAYS` \| `LAST_30_DAYS` \| `LAST_90_DAYS` \| `CUSTOM`(替换硬编码的 `CURRENT_BASELINE`) | | `range.start`,`range.end` | 实际生效区间;`CUSTOM` 时回显请求值 | | `trend[].bucket` | 保持 `yyyy-MM-dd`;窗口跟随 `range` | `CockpitOverviewWarningSettingsResponse.Range` 与 `TrendPoint` 结构已存在,属**加参数 + 填值**,不需新端点。 ### C. 效率时长聚合 覆盖面板:`responseEfficiency`。 **建议在 `CockpitOverviewWarningSettingsResponse.FamilyMetrics` 内新增**: | 建议字段 | 语义 | | --- | --- | | `averageResponseSeconds` | 平均响应时长 = avg(首次接单时间 − 事件发生时间);接单时间取工单 timeline 中 `stateCode=3` 的 `operatedAt` | | `averageCloseSeconds` | 平均关闭时长 = avg(结案时间 − 事件发生时间);结案时间取 `CockpitWorkOrderSummary.realFinishTime` | | `medianResponseSeconds`,`medianCloseSeconds` | 中位数,抗长尾(大屏指标更稳健) | | `durationSampleCount` | 参与计算的样本数,供口径透明 | | `durationState`,`durationReason` | 复用既有 `state`/`reason` 模式表达 `EMPTY`/`NO_SAMPLES` | 数据源已存在(`createTime`/`realFinishTime` + timeline `operatedAt`),缺的是聚合层。 ### D. 应急保障域 —— 需全新读模型 覆盖面板:`emergency`。后端 cockpit 包内该域**完全不存在**。 **建议新端点** `GET /api/cockpit/v1/infrastructure/emergency`,参数 `industry`、`facilityType`、`region`。 | 建议结构 | 字段 | | --- | --- | | `totals` | `hazardSourceCount`,`protectionTargetCount`,`emergencyResourceCount` | | `hazardSources[]` | `code`,`name`,`hazardType`,`hazardLevel`,`industry`,`region`,`relatedFacilityCode`,`longitude`,`latitude`,`coordinateValidation` | | `protectionTargets[]` | `code`,`name`,`targetType`,`targetLevel`,`industry`,`region`,`distanceToSourceMeters`,`longitude`,`latitude`,`coordinateValidation` | | `emergencyResources[]` | `code`,`name`,`resourceType`,`quantity`,`unit`,`ownershipUnit`,`contactName`,`contactPhone`,`region`,`longitude`,`latitude` | | 信封 | `freshness`,`selectedFilters`,`mapFilter`,`excluded`(对齐 `CockpitInfrastructureBaseArchivesResponse` 既有模式) | ### E. 管理信息读模型 覆盖面板:`management`。 **E1. 扩展** `CockpitEquipmentArchive` / `CockpitEquipmentArchiveSnapshot` 补 `managementUnit`、`managementUnitCode`(当前只有 `ownershipUnit` + `maintainer`,「管理单位」缺失)。 **E2. 建议新端点** `GET /api/cockpit/v1/infrastructure/management`,参数 `industry`、`region`: | 建议结构 | 字段 | | --- | --- | | `managementUnits[]` | `code`,`name`,`unitType`,`contactName`,`contactPhone`,`region`,`facilityCount` | | `ownershipUnits[]` | `code`,`name`,`unitType`,`region`,`facilityCount` | | `responsibilityZones[]` | `code`,`name`,`region`,`managementUnitCode`,`ownershipUnitCode`,`facilityCount` | **E3. 或最小改动**:在 `CockpitInfrastructureBaseArchivesResponse.facilityTypeDistribution` 之外逐设施暴露 `region` + `managementUnitCode`(`CockpitInfrastructureBaseArchivesSnapshot.SourceFacility.region` 已存在,只是未输出)。 ### F. 运行信息(设施级能力指标) 覆盖面板:`operation`。 **建议新端点** `GET /api/cockpit/v1/facilities/{facilityCode}/operation`: | 建议字段 | 语义 | | --- | --- | | `supplyCapacity` | `{metricCode,metricName,value,unit,status,sampledAt}` — 供应能力 | | `transmissionCapacity` | 同上 — 输送能力 | | `carryingCapacity` | 同上 — 承载能力 | | `metrics[]` | 复用 `CockpitMetric` 结构承载其余指标 | | `state`,`stateReason`,`freshness` | 复用既有可用性语义 | 备选:给 #11/#12 指标端点增加 `facilityCode` 维度以支持设施级汇总。 ### G. 监测点/地图的行业与类型维度 —— 全局行业筛选的前置条件 覆盖面板:`monitoringPointLedger`、`monitoringDistribution`,并影响 CONTEXT.md 的全局「行业筛选」。 **G1.** `GET /api/cockpit/v1/map-snapshot` 增加入参 `industry`。 **G2.** `CockpitMonitoringPointSummary` 增设: | 建议字段 | 语义 | | --- | --- | | `industry` | 行业归属(燃气/供水/排水…),供全局筛选与台账分组 | | `pointTypeCode`,`pointTypeName` | 点位类型 | | `deviceCount`,`onlineDeviceCount`,`alarmDeviceCount`,`warningDeviceCount` | 卡片徽标;可直接复用 `CockpitMonitoringPointDeviceStatistics` 结构 | | `latestSampledAt` | 最近采集时间,省掉逐点 `metrics/current` | **G3.** `CockpitUnassociatedEquipmentSummary` 同样增设 `industry`、`deviceTypeCode/Name`。 **G4.** 保留 `CockpitMapSnapshot.SourceMonitoringPoint.devices` 的设备编码到响应(当前在 `CockpitMapSnapshotService.monitoringPoint()` 被丢弃),供 WS `cockpitDeviceStatusDelta` 用 `deviceCode` 回联点位状态。 ### H. 跨设备设备状态清单 覆盖面板:`operationOverview`(离线设备清单)、`monitoringSummary`。 WS 已明确「REST 是初始快照,WS 只推增量」,但当前**没有**跨设备设备状态 REST 快照。 **建议新端点** `GET /api/cockpit/v1/equipments/status`,参数 `industry`、`monitoringState`(如 `OFFLINE`)、`page`、`pageSize`: | 建议字段 | 语义 | | --- | --- | | `devices[]` | `deviceCode`,`deviceName`,`deviceTypeCode`,`deviceTypeName`,`industry`,`monitoringState`,`statusTime`,`serverUpdatedAt`,`freshness`,`longitude`,`latitude`,`monitoringPointCode` | | `total`,`counts` | `counts` 复用 `CockpitOverviewMonitoringResponse.Counts.Status` 语义 | 备选:让 `cockpitSubscribe` 的 `cockpitSubscribed` 回帧携带初始全量状态数组(与 WS 处理器注释的现状相反,需后端确认)。 --- ## 5. 结论摘要 | 判定 | 面板数 | 面板 | | --- | --- | --- | | ✅ 完全覆盖 | **5** | `infrastructureSummary`、`monitoringSummary`、`alertSettings`、`archive`、`monitoringOverview` | | ⚠️ 存在缺口 | **11** | `situationSummary`、`operation`、`management`、`emergency`、`monitoringDistribution`、`operationOverview`、`monitoringPointLedger`、`currentEvents`、`historyAnalysis`、`responseEfficiency`、`eventAnalysis` | 按模式: | 模式 | 覆盖 | 缺口 | | --- | --- | --- | | `overview` | 3 / 4 | `situationSummary`(趋势窗口不可声明,弱缺口) | | `infrastructure` | 1 / 4 | `operation`、`management`、`emergency`(`emergency` 为全域缺失) | | `monitoring` | 1 / 4 | `monitoringDistribution`、`operationOverview`、`monitoringPointLedger` | | `warningResponse` | 0 / 4 | 四个面板全部有缺口,根因都是「跨设备事件读模型缺失」 | Top 5 缺失字段(按阻塞强度): 1. **跨设备当前事件流**(`eventCode` + 归属设备/监测点/行业 + 分页)— 完全阻塞 `currentEvents` 2. **跨设备带时间范围的历史事件流 + 趋势 range 参数**(7/30/90/自定义)— 阻塞 `historyAnalysis` 3. **应急保障域三件套**(`hazardSources` / `protectionTargets` / `emergencyResources`)— 阻塞 `emergency` 整版 4. **监测点 `industry` + 点位类型 + 设备计数徽标**(含 `map-snapshot` 的 `industry` 入参)— 阻塞 `monitoringPointLedger` / `monitoringDistribution` 与全局行业筛选 5. **事件经纬度**(`longitude`/`latitude` + `coordinateValidation`)与**响应/关闭时长聚合**(`averageResponseSeconds` / `averageCloseSeconds`)— 阻塞 `currentEvents` 上图与 `responseEfficiency` 补充观察: - 后端已存在一整层**面板级聚合读模型**(#5/#6/#7/#8),前端实现票 17-20 的 mock 首期可直接按这 4 个响应的形状建模,不必从单设备端点上拼装。 - 4 个面板级端点 + `AjaxResult` 信封 + `freshness`/`state`/`stateReason`/`excluded` 的**错误与空态模式是全后端统一的**,前端只需实现一套分区状态渲染(对应 `CockpitSectionState`:`SUCCESS`/`EMPTY`/`STALE`/`FAILED`)。 - 待业务确认(本调研不发明结论): 1. 「故障」是否等同 `stale`,还是需要独立桶。 2. 「处置率」当前定义是 `state==6` / 全部事件(含已取消),是否即业务所说的处置率。 3. 「管理单位」与 `maintainer`(维护单位)是否同一概念。 --- ## 6. 证据索引 ### 控制器(`E:\pipe-ner-server\pipe-network-service\zksy-admin\src\main\java\com\zksy\web\controller\cockpit\`) `CockpitFoundationController`、`CockpitMapSnapshotController`、`CockpitMonitoringPointDetailController`、`CockpitDeviceBoundaryController`、`CockpitOverviewInfrastructureController`、`CockpitOverviewMonitoringController`、`CockpitOverviewWarningSettingsController`、`CockpitInfrastructureBaseArchivesController`、`CockpitEquipmentArchiveController`、`CockpitEquipmentDetailAggregateController`、`CockpitTypeMetricsController`、`CockpitEventReadController`、`CockpitWorkOrderReadController`、`CockpitFreshnessController` ### 响应/快照类(`E:\pipe-ner-server\pipe-network-service\zksy-system\src\main\java\com\zksy\cockpit\`) `foundation/`(`CockpitFoundationResponse`、`CockpitMapFrame`、`CockpitFreshnessResponse`、`CockpitFreshnessSection`、`CockpitFreshnessSectionData`、`CockpitFreshnessStatus`、`CockpitCoordinateValidation`) `map/`(`CockpitMapSnapshotResponse`、`CockpitMapSnapshot`、`CockpitMapSnapshotService`、`CockpitMonitoringPointSummary`、`CockpitUnassociatedEquipmentSummary`、`CockpitCoordinateValidationSummary`) `point/`(`CockpitMonitoringPointDetailResponse`、`CockpitMonitoringPointStatus`、`CockpitMonitoringPointStatusEntry`、`CockpitMonitoringPointStatusReason`、`CockpitMonitoringPointDeviceCard`、`CockpitMonitoringPointDeviceStatistics`、`CockpitMonitoringPointStatusResolver`) `equipment/`(`CockpitEquipmentArchiveResponse`、`CockpitEquipmentArchive`、`CockpitEquipmentArchiveSnapshot`、`CockpitEquipmentImage`) `type/`(`CockpitTypeMetricsResponse`、`CockpitMetric`、`CockpitMetricPoint`) `event/`(`CockpitEventReadResponse`、`CockpitEventWarning`、`CockpitEventAlarm`、`CockpitAlarmWarningRelation`、`CockpitEventLevelColor`) `workorder/`(`CockpitWorkOrderReadResponse`、`CockpitWorkOrderSummary`、`CockpitWorkOrderTimelineResponse`、`CockpitWorkOrderTimelineEntry`、`CockpitWorkOrderState`、`CockpitWorkOrderStateDictionary`、`CockpitWorkOrderEventAssociation`) `detail/`(`CockpitEquipmentDetailAggregateResponse`、`CockpitSectionResult`、`CockpitSectionState`) `overview/`(`CockpitOverviewInfrastructureResponse`、`CockpitOverviewMonitoringResponse`、`CockpitOverviewWarningSettingsResponse`、`CockpitOverviewWarningSettingsService`、`CockpitOverviewMonitoringDeviceStatusDelta`) `infrastructure/`(`CockpitInfrastructureBaseArchivesResponse`、`CockpitInfrastructureBaseArchivesSnapshot`) `device/`(`CockpitDeviceBoundaryResponse`、`CockpitDeviceBoundary`、`CockpitFacilityBoundary`、`CockpitDeviceBoundaryStatistics`、`CockpitIndustryStatistics`、`CockpitTypeScope`、`CockpitDeviceType`) ### WebSocket `E:\pipe-ner-server\pipe-network-service\zksy-admin\src\main\java\com\zksy\web\websocket\DeviceStatusWebSocketHandler.java`(协议注释第 34-86 行;`cockpitSubscribe` 第 341-357 行) `...\web\websocket\DeviceStatusRedisListener.java`(`cockpitDeltaMessage` 第 171-185 行) `...\web\websocket\WebSocketConfig.java`(注册 `/ws/deviceStatus`) ### 本仓库 - `docs/adr/0003-web-page-information-architecture.md` — 模式→面板词典与列布局 - `CONTEXT.md` — 态势总览、监测点台账、点位状态、行业筛选、两级详情等术语 - `.scratch/cockpit-shell-panel-layout/issues/17|18|19|20-*.md` — 各模式面板验收项 - `.scratch/cockpit-shell-panel-layout/issues/24-panel-field-coverage.md` — 本票 ### 旁证(样例响应,非权威) `E:\pipe-ner-server\docs\cockpit\*.html`:`overview-infrastructure`、`overview-monitoring`、`overview-warning-settings`、`infrastructure-base-archives`、`map-snapshot`、`monitoring-point-detail`、`equipment-archive`、`type-metrics`、`event-read`、`work-order-seven-states`、`equipment-detail-aggregate`、`freshness-semantics`、`websocket-scope-delta`、`foundation`、`device-boundary` 注:`overview-warning-settings-demo.html` 的 `points:[{code,x,y}]` 事件点位数组**只存在于演示页**,真实 `CockpitOverviewWarningSettingsResponse` 无对应字段(只有 `mapFilter`),是本报告 A 项缺口的旁证。