41-warning-settings-endpoint-rework.md 11 KB

41: 后端执行票 —— 预警设置端点改为预警自身生命周期统计

Type: task Status: resolved Label: ready-for-agent Blocked by: None Category: backend-execution Assignee: codex

来源

维护者 2026-10-13 反馈第 1 条,并明确裁定:预警不走工单流程,走自己单独的流程;/overview/warning-settings 需要针对这条信息修改,只展示预警自身生命周期的统计(Q1=A:让后端改这个端点)。

背景(实测)

  • 当前 /api/cockpit/v1/overview/warning-settings 返回的是工单口径字段:workOrderStates、handled、pending、cancelledCount、handlingEfficiency(处置率)等。
  • 该端点在本地联调环境实测 HTTP 200 + body code=500:字段 "dispatch_user" 不存在(WorkOrderMapper 仍映射 app_user.work_order 已不存在的列)——即该端点的工单依赖本身就是当前故障源。
  • 前端「总体概览 - 预警设置」面板因此显示「数据加载失败」(前端行为正确,如实反映后端故障)。

范围

  1. 端点语义改为预警自身生命周期:去掉工单口径字段(工单状态分布、处置率、已处理/待处理等),改为预警自身统计:
    • 预警总数;
    • 按预警自身状态分布;
    • 按等级分布;
    • 近 7 日趋势(保留既有 range 窗口契约);
    • 按行业 / 片区分布。
  2. 与报警族的关系:需明确该端点是否仍同时给预警与报警两族(现状是一次给两族、态势总览共用)。若不改这一结构,报警族也应改为报警自身生命周期口径,而非工单口径。
  3. 移除对工单表的依赖:本端点不得再依赖 work_order(既消除 dispatch_user 故障,也符合「预警不走工单」)。
  4. 契约测试:新字段形状、状态/等级分布计数自洽、趋势窗口跟随 range、空态。

非目标

  • 不修改工单自身逻辑(工单仍由外部业务系统与既有流程负责)。
  • 不改驾驶舱只读边界。

验收

  • 后端:编译 + 契约测试;本地联调环境复验该端点返回新契约且不再 500(登记到基线卡片)。
  • 前端消费侧改动(面板改为读新字段)在契约确定后另立前端票。

诊断(2026-10-14,本会话实测)

结论一:票面背景里的根因已经过期

票面写「实测 HTTP 200 + body code=500:字段 dispatch_user 不存在」。本会话复测,HTTP 200 + body code=500 仍然成立,但报错列已变成 dept_id:

### Error querying database. Cause: com.kingbase8.util.KSQLException:
ERROR: 字段 "dept_id" 不存在
### SQL: SELECT order_id,order_no,device_id,fault_time,order_level,order_desc,
       dept_id,receive_user,order_status,... FROM app_user.work_order

dispatch_user 在本地 HEAD(a96091ce)里已经不存在——上游 8fb5cb52(工单新增创建人)已把 dispatchUser/dispatchTime 从 WorkOrder 删除。票面记的是更早一次的故障形态。

结论二:真实根因是「运行构建落后于库结构」,不是本端点的设计缺陷

  • 本地 HEAD a96091ce 的 WorkOrder.java 与 WorkOrderMapper.xml 仍声明并选择 dept_id(13d5bd1e 引入)。
  • 上游 origin/master(5a821872)的 94bb7e4d「移动端-工单管理」 已删掉 dept_id:实体去字段,WorkOrderMapper.xml 的 Base_Column_List 与 resultMap 同步去掉。
  • 联调实例(PID 17972,2026-10-14 08:48:40 启动)实测该列不存在 → 库已不再有 dept_id,而实例加载的构建仍去 SELECT 它。

这与 票 19 形态完全一致:构建/部署基线错位,不是缺列。同一错列还打穿了 events/handling-efficiency 与 /work-orders/{code}/timeline(本会话实测两者同样 code=500 + dept_id),故障面比票面记的「单点」更大。

结论三:这决定了本票的实施基点

维护者本轮裁定(见下)要求报警族保留工单口径(报警靠工单闭环),而工单读取正是当前故障点,所以:

本票实施必须建立在已含 94bb7e4d 的基点上,否则报警族仍会 dept_id 500,验收项「不再 500」无法达成。

本地 HEAD=a96091ce 不含该提交(本地领先 merge-base 989a707e 1 个未推送提交=票 32 几何改动;origin/master=5a821872 领先本地 4 个提交)。合并 origin/master 与共享工作树里并行会话的未提交几何改动无文本冲突:上游 989a707e..origin/master 未触碰 cockpit/geometry 任何文件(git diff --name-only 核实)。

维护者裁定(本会话 grilling,2026-10-14)

  • Q1 契约形状:两族都留。预警族改为预警自身生命周期(预警不走工单);报警族保留工单口径——「报警的生命周期与工单关联性很强,报警需要通过工单去进行处理解决」,同时报警自身生命周期也要保留。
  • Q2 验证授权:全授权 —— Maven 编译 + Cockpit*Test + 重启实例做真实复验。

前端影响(另立票,本票不改)

现前端 toOverviewWarningSettings() 读 warning.workOrderStates / handled / pending / handlingEfficiency 等工单口径字段。预警族字段改造后这些字段回 null,前端 numberish(null) 会数成 0(不是 —)——「预警设置」面板的预警半边会显示全 0 而非新分布块,直到前端消费票落地;报警半边保持可用(旧字段保留)。

实施(2026-10-14)

基点:从 origin/master(5a821872)拉独立 worktree E:\pipe-ner-server-t41(git worktree add --detach), 不动共享工作树(其上有并行会话的票 32 几何未提交改动)。选这个基点的原因见「诊断 结论三」: 本地 HEAD 仍声明 dept_id,而上游 94bb7e4d 已删除它;报警族按裁定保留工单口径, 必须建立在已删除该列的基点上,否则「不再 500」无法达成。

改动(7 文件,+935/−279):

文件 改动
CockpitOverviewWarningSettingsResponse FamilyMetrics 工单口径字段改包装类型(Integer/Map)以便显式 null;新增 Bucket 与四个分布字段
CockpitOverviewWarningSettingsSnapshot SourceEvent 增自身生命周期 status/level 与维度 districtCode/industryCode(旧构造器保留为委托重载)
CockpitOverviewWarningSettingsService 拆 warningFamily(纯自身生命周期,工单字段全 null)与 alarmFamily(保留工单口径 + 并存自身生命周期);新增状态/等级/行业/片区分布构造
BusinessCockpitOverviewWarningSettingsAdapter 预警不再桥接工单(warningBuckets 的 handled 改判自身 CLOSED);两族沿 equipment_base + equipment_type 树解析片区/行业带入快照
三个测试文件 契约测试重写为两族口径分离

口径落点:

  • 预警族:total、statusDistribution(WarningWorkflow 六态全铺)、levelDistribution(1–4 全铺)、 industryDistribution(四正式行业 + 未知)、districtDistribution(0/1/2 + 恒有未分区)、 handlingEfficiency=已解除÷总数、trend(按发布时间分桶,handled=该桶已解除)。 工单口径六字段一律 null。
  • 报警族:工单口径原样保留(含 workOrderStates 0–7、工单口径处置率、未回联/脏码/已取消分列), 并存 statusDistribution(alarm_status 0/1)、等级/行业/片区分布。
  • 分布取整个快照(不随 range 收缩)→ sum(分布桶) == total 恒成立;只有趋势桶跟随窗口。
  • 「未知」类(脏状态/脏等级/推不出行业)与「未分区」都显式入桶,故计数不静默丢。

验证:

  • 编译:mvn -o -pl pipe-network-service/zksy-admin -am compile → 通过。
  • 针对性契约测试:CockpitOverviewWarningSettings*Test + BusinessCockpitOverviewWarningSettings*Test → 24/24。
  • 全量:-Dtest=Cockpit*Test,BusinessCockpit*Test → 479/479,BUILD SUCCESS。
  • 提交:ae9c5731(独立 worktree,7 文件)。

真实复验(2026-10-14,验收达成)

方法:不动共享实例(PID 17972,其他会话在用),从本票 jar 在 8399 端口起一个第二实例 (t41 本地 profile + 关闭 nacos 远端配置导入与注册、推送任务 initial-delay 全推后), 连同一个联调库与 Redis。实测 GET /overview/warning-settings?mode=WARNING&range=LAST_7_DAYS:

  • HTTP 200 + code=200(验收项「不再 500」达成)。
  • 预警族新契约实测(真实库数据,全部自洽):
    • total=31;工单口径六字段全部 null(handled/pending/cancelledCount/unlinkedEventCount/invalidWorkOrderStateCount/workOrderStates)。
    • statusDistribution:DRAFT 2 + PENDING 4 + RECEIVED 0 + PROCESSING 4 + HANDLED 2 + CLOSED 19 = 31 ✓(和=总数)。
    • levelDistribution:13+5+1+12 = 31 ✓;industryDistribution:0+2+24+1+UNKNOWN 4 = 31 ✓; districtDistribution:城南 24 + 城北 1 + 太常 2 + 未分区 4 = 31 ✓。
    • handlingEfficiency = 19/31 = 0.6129(已解除÷总数,预警自身口径)。
    • trend 按 LAST_7_DAYS 裁桶(2026-10-09/10/14 三桶,窗外桶被裁掉)。
  • 报警族实测(工单口径保留 + 自身生命周期并存):
    • handled=64(alarm_status=1);workOrderStates 0–7 齐全;处置率 1/5 = 0.2000(工单口径);
    • statusDistribution:UNHANDLED 2 + HANDLED 64 = 66 ✓;等级/行业/片区分布和均=66 ✓。
  • 对照证据(同一时刻):共享实例 8301(彼时已被他人重启到上游 05c23774,dept_id 故障已随上游修复消失) 仍回旧契约(warning.handled=0、workOrderStates 在、无 statusDistribution、处置率 0.2000)—— 证明 8301 的新 200 来自上游修复而非本票改动;本票的新契约在 8399 实例实测生效。

推送:变基到 05c23774 后复跑全量 498/498(变基带来 19 个新测试),提交最终为 b047a60d, 已推 origin/master(05c23774..b047a60d),远端 master=b047a60d 与本地一致。 第二实例与临时 worktree E:\pipe-ner-server-t41 已停机并清理,共享工作树未触碰 (票 32 几何改动仍原样留在工作树)。

边界说明:实施期间上游基点从 5a821872 前移到 05c23774(并行会话推送的票 35 createdAt),已通过变基合入,无冲突。

前端后续(另立票,不阻塞本票)

预警族 handled/pending/cancelledCount/workOrderStates 等工单口径字段在真实环境回 null 后, 前端 toOverviewWarningSettings() 会把 null 数成 0、workOrderStates 空铺 —— 「预警设置」面板的预警半边会显示全 0 而非新分布块。前端消费票(改读 statusDistribution/levelDistribution/industryDistribution/districtDistribution 与新处置率语义) 需按票面验收第 2 条另立,与 mock 契约(contractMocks.js 的 overviewWarningSettingsPayload)同步改。

关联