# 前端执行票 —— 报警效率与预警分析支持近90天(复用 historyWindows 分窗取数 + 前端合并,撤下「最多支持31天」提示) ## Question 维护者 2026-10-21 反馈:报警效率与预警分析也应能取近 90 天数据,不应显示「最多支持31天」。 **实测取证(2026-10-21,`192.168.110.96:8301`)**: - 三个聚合端点(handling-efficiency / multidimensional-analysis / history-analysis)后端契约都是**单请求 ≤31 天**:显式给 90 天窗口 → `400 {"category":"INVALID_REQUEST","message":"efficiency window must not exceed 31 days"}`(analysis/history 同句式)。 - 但按 30 天切窗后逐窗请求全部 200:90 天 = 4 窗,实测第 3 窗 WARNING 13 条、ALARM 90 条,w1/w2/w4 为空。 - `history-analysis` 前端**已经**这么做了(票 61:`historyWindows()` 分窗 + 合并);`fetchHandlingEfficiency`/`fetchEventAnalysis` 遇 >31 天则直接返回 UNAVAILABLE(`unsupportedWindow()`),界面挂「当前接口最多支持31天统计」提示。 ## Acceptance - 报警效率与预警分析在 90 天下**出真实数据**:复用 `historyWindows` 分窗(≤30 天/窗)并行取数 + 合并,与票 61 同一先例。 - 合并口径逐字段如实:效率(durationTrend 按时序拼接去重、events 各窗首页拼接、summary 各计数求和、`handlingEfficiency` 用合并后 `stateCounts` 重算、`averageDuration` 按 `sampleCount` 加权、`workOrderStateCounts` 按码求和);分析(`totalCount` 求和、dimensions 按 `dimensionCode` 合并、buckets 按 `bucketCode` 求和并重算 `percentage`)。 - 单窗行为零变化(7/30 天仍走原路径,不因重构变味)。 - 任一窗失败 → 整分区 FAILED(不把 3/4 窗的数冒充 90 天);有窗 STALE → 整体 STALE。 - 删除「当前接口最多支持31天统计」提示(不再成立)。 - 闸门用 2026-10-21 实取的四窗载荷离线断言(`verify/artifacts/t75/`)+ 变异打红;按 AGENTS.md 跳过 build/dev/浏览器验证。 ## Context - 代码:`services/warningResponseApi.js`(`fetchHandlingEfficiency`/`fetchEventAnalysis`/`unsupportedWindow`)、`components/WarningResponsePane.vue`(31 天提示行)、`domain/eventRange.js`(`historyWindows`)。 - 先例:票 61 历史事件多窗合并(同一段 `historyWindows`)。 - 后端不改:31 天/请求是既有契约(报文里明说),分窗是前端消费侧职责。 ## Related spec 票 61(服务端分页批次三)的「多窗合并范围」三分类。 ## 进度 - 2026-10-21 **实施完成**:`fetchAggregated`(分窗 + 合并统一出口)替代 `unsupportedWindow` 拦截; `mergeEfficiencyPayloads` / `mergeAnalysisPayloads` 按 acceptance 逐字段实现并**从服务导出**(闸门直接消费, 不复刻第二份防漂移);7/30 天单窗路径零变化;「最多支持31天」提示撤除。 - 2026-10-21 **闸门 t75 18/18**(A 效率合并 / B 分析合并 / C 服务级分窗+失败语义 / D 提示撤除) + **变异 8/8**(含两处**等价变异教训**:`+=`→`||=` 对「前两窗为 0」的数据等价、"丢弃后窗空维度桶"不可观测, 改钉「末窗覆盖」才可观测——见 t75-mutations M2/M4 注释)。 - 2026-10-21 **回归全绿**:t13/t16/t19/t20/t39/t40/t42/t44(109+6/6)/t46/t56(9/9)/t61(39/39)/t64(17/17)/t65(51/51+27/27)。 Status: resolved Type: task Blocked by: Labels: wayfinder:task ## Comments ## Answer **结论:90 天支持已在前端实现(后端零改动)**。31 天/请求是后端既有契约(400 报文明说 `efficiency window must not exceed 31 days`),分窗是前端消费侧职责 —— 与票 61 历史事件多窗合并同一条先例。 **改动**(`services/warningResponseApi.js` + `components/WarningResponsePane.vue`): - `fetchAggregated(path, options, hooks)`:统一出口 —— `historyWindows` 切窗(≤30 天/窗,天然满足 31 天契约); 单窗走原 `fetchSection` 路径(7/30 天行为零变化);多窗并行取**原始载荷**(`toData` 恒等),合并后再过一次域转换 —— 单窗/多窗最后走同一段 `toHandlingEfficiency`/`toEventAnalysis`,不分叉出两套口径。 - `mergeEfficiencyPayloads`(导出):`durationTrend` 时序拼接去重、`events` 各窗首页拼接、summary 计数求和、 `handlingEfficiency` 用合并后 `stateCounts` **重算**(分子=已结案5,分母=可计入0–6,与后端 `stateCounts` 同一算法)、 `averageDuration` 按 `sampleCount` 加权(无样本如实 EMPTY)、`workOrderStateCounts` 按码求和。 - `mergeAnalysisPayloads`(导出):`totalCount` 求和、dimensions 按 `dimensionCode` 合并、buckets 按 `bucketCode` 求和 + `percentage` **重算**(50%+25%=75% 的老错误被闸门 B4 钉住)。 - 失败语义:任一窗失败 → 整分区 FAILED(不拿 3/4 窗冒充 90 天);有窗 STALE → 整体 STALE;全空窗 → EMPTY。 - 「当前接口最多支持31天统计」提示**撤除**(D1 断言)。 **判据**:[t75 闸门](../verify/t75-90d-multi-window.mjs) **18/18** —— 证据载荷是 2026-10-21 对 `192.168.110.96:8301` 按 30 天切窗**实取的 4 窗响应**(`artifacts/t75/`,WARNING/ALARM 效率各 4 窗 + 分析 4 窗; 实测 w3 窗 WARNING 13 条、ALARM 90 条,w1/w2/w4 为空 —— 90 天数据真实存在,只是原来被前端自己挡掉)。 [t75 变异](../verify/t75-mutations.mjs) **8/8**。 **变异的两条等价变异教训**(记入 t75-mutations M2/M4 注释): `totalEvents += x` 变 `||= x` 对「前两窗为 0」的数据是等价变异(结果不变,闸门不红);分析端 w1/w2 的 维度桶为空数组,「丢弃后窗同码桶」同样不可观测 —— 换成「末窗覆盖」形态才打得出红。 **回归**:t13/t16/t19/t20/t39/t40/t42/t44(109+6/6)/t46/t56(9/9)/t61(39/39)/t64(17/17)/t65(51/51+27/27) 全绿。 **未完成/如实记**: - 改动未提交(`services/warningResponseApi.js` 同时承载票 61 的既有未提交增量,与票 75 交叠在同一文件)。 - 真实浏览器走查按 AGENTS.md 未执行。