Explorar o código

fix(cockpit): 未处理积压按「当日状态」还原,不再用当前 alarm_status 回溯 (t97)

selectAlarmDailyCounts 的 unhandled_total 旧实现是
  COUNT(*) WHERE a2.alarm_status = 0 AND a2.create_time < 当日结束
即「按当前状态回溯历史」。维护者 2026-10-28 处置一条报警后七天从 1,2,2,2,2,2,2 整体塌成
1,1,1,1,1,1,1;而且历史值系统性偏低(10-22 真实积压 2:一条 10-16 创建的报警 10-23 才处置)。

改为按「首次被处置的时刻」判定:
  backlog(D) = create_time <= D 结束 且 ( 首次处置时刻为空 或 首次处置时刻 > D 结束 )
首次处置时刻 = MIN(alarm_log.oper_time) WHERE oper_type IN (1,3)。
实测 oper_type 语义(真库 alarm_log):0=报警产生(其 oper_time 恰等于 alarm_data.create_time,
绝不能当处置时刻)、1=人工确认/转工单、3=自动恢复「报警恢复,自动处理」。
不过滤 oper_type 会让 MIN(oper_time) 恒等于 create_time、整条积压线算成 0。

真库核验(192.168.110.30:54321/pipi_ner,只读,2026-10-28):
  旧表达式 10-22..10-28 = 1,1,1,1,1,1,2(今天多一条未处置新报警)
  新表达式            = 2,2,2,2,2,2,2(历史日固定,今天的处置只影响今天)
  184 条报警 / 92 条有日志;alarm_status 与 type1/3 日志零冲突,兜底分支当前不触发。

兜底:无 type1/3 日志的 HANDLED 报警退回 update_time(偏高,已在票 97 记录)。
lead hai 1 semana
pai
achega
674b7db5f7

+ 33 - 4
pipe-network-service/zksy-system/src/main/resources/mapper/cockpit/CockpitOverviewModulesMapper.xml

@@ -233,7 +233,15 @@
 
     <!-- 按日两个读数(维护者 2026-10-23):
            · daily_count     —— 当天新增(create_time 落在该日),走面板基础集合 audit_status = 1;
-           · unhandled_total —— 截至当天仍未处理的累计条数(alarm_status = 0,0 未处理 / 1 已处理)。
+           · unhandled_total —— **截至当天结束时仍未处置**的累计条数(按「首次被处置的时刻」判定)。
+
+             **口径修正(票 97,2026-10-28)**:旧实现用**当前** alarm_status = 0 过滤历史日,等于
+             「按今天的状态回溯过去」—— 今天处置一条,过去几天的值会一起变(维护者实测:处置后七天从
+             1,2,2,2,2,2,2 整体塌成 1,1,1,1,1,1,1),且历史值系统性偏低(10-22 那天真实积压 2:一条
+             10-16 创建的报警 10-23 才处置,旧实现对 10-22 只记 1)。现在改为:
+             backlog(D) = #{ create_time ≤ D 结束 且 ( 首次处置时刻为空 或 首次处置时刻 > D 结束 ) },
+             首次处置时刻取 MIN(alarm_log.oper_time) WHERE oper_type IN (1,3)(见下方 oper_type 语义);
+             没有 type 1/3 日志的 HANDLED 报警退回 update_time 兜底(略偏高,已记票 97)。
 
          **两条线口径不同,是刻意如此**:
          · 新增按面板基础集合(已核实报警),与上方「今日新增」等读数同口径;
@@ -242,6 +250,13 @@
            这条线会画成一条恒零的直线,"积压还在"的意思就丢了。
          累计必须从**入库最早一条**起算,不能只用窗口内数据 —— 否则窗口之前的积压会漏掉。
          票 81:片区/行业筛选对两条线**都**生效(同一个「范围内」定义),否则新增与积压会互相打架。 -->
+    <!-- 首次处置时刻(票 97,2026-10-28 在真实库上核验过 alarm_log.oper_type 语义):
+         0 = 报警产生(实测其 oper_time 与 alarm_data.create_time 完全相等,不能当处置时刻!);
+         1 = 人工确认/转工单;3 = 自动恢复("报警恢复,自动处理")。
+         所以处置时刻 = MIN(oper_time) WHERE oper_type IN (1, 3);对同一报警取**最早**一条
+         (取最后一条会把"处置后又更新"误当成处置时刻,积压会算得偏低)。
+         实测:184 条报警里 92 条有日志、其中大量是 type 0 的产生记录 —— 若不过滤 oper_type,
+         MIN(oper_time) 恒等于 create_time,整条积压线会被算成 0。 -->
     <select id="selectAlarmDailyCounts" resultType="java.util.LinkedHashMap">
         <include refid="typeTree"/>,
         days AS (
@@ -259,12 +274,26 @@
               AND a.create_time &gt;= #{startInclusive} AND a.create_time &lt; #{endExclusive}
         <include refid="alarmDeviceFilter"/>
             GROUP BY 1
+        ),
+        handled AS (
+            SELECT l.alarm_id AS alarm_id, MIN(l.oper_time) AS handled_at
+            FROM app_user.alarm_log l
+            WHERE l.oper_time IS NOT NULL
+              AND l.oper_type IN (1, 3)
+            GROUP BY l.alarm_id
         )
         SELECT d.day AS day,
                COALESCE(cr.c, 0) AS daily_count,
-               (SELECT COUNT(*) FROM app_user.alarm_data a2
-                 WHERE a2.alarm_status = 0
-                   AND a2.create_time &lt; (d.day_date + interval '1 day')
+               (SELECT COUNT(*)
+                  FROM app_user.alarm_data a2
+                  LEFT JOIN handled h2 ON h2.alarm_id = a2.id
+                 WHERE a2.create_time &lt; (d.day_date + interval '1 day')
+                   AND CASE
+                         WHEN h2.handled_at IS NOT NULL
+                             THEN h2.handled_at &gt;= (d.day_date + interval '1 day')
+                         WHEN a2.alarm_status = 0 THEN TRUE
+                         ELSE COALESCE(a2.update_time, a2.create_time) &gt;= (d.day_date + interval '1 day')
+                       END
                    <if test="district != null or unassigned">
                        AND <choose>
                            <when test="unassigned">