EarlyWarningMapper.xml 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="com.zksy.base.warning.mapper.EarlyWarningMapper">
  4. <resultMap id="BaseResultMap" type="com.zksy.base.warning.domain.EarlyWarning">
  5. <id column="warning_id" property="warningId"/>
  6. <result column="warning_no" property="warningNo"/>
  7. <result column="warning_type" property="warningType"/>
  8. <result column="warning_level" property="warningLevel"/>
  9. <result column="warning_special" property="warningSpecial"/>
  10. <result column="disposal_deadline" property="disposalDeadline"/>
  11. <result column="stage_deadline" property="stageDeadline"/>
  12. <result column="item_id" property="itemId"/>
  13. <result column="item_snapshot" property="itemSnapshot"/>
  14. <result column="device_code" property="deviceCode"/>
  15. <result column="device_name" property="deviceName"/>
  16. <result column="location" property="location"/>
  17. <result column="ownership_unit" property="ownershipUnit"/>
  18. <result column="publisher" property="publisher"/>
  19. <result column="publish_time" property="publishTime"/>
  20. <result column="handler" property="handler"/>
  21. <result column="reviewer" property="reviewer"/>
  22. <result column="status" property="status"/>
  23. <result column="warning_content" property="warningContent"/>
  24. <result column="process_instance_id" property="processInstanceId"/>
  25. <result column="create_by" property="createBy"/>
  26. <result column="create_time" property="createTime"/>
  27. <result column="update_by" property="updateBy"/>
  28. <result column="update_time" property="updateTime"/>
  29. <result column="remark" property="remark"/>
  30. </resultMap>
  31. <sql id="Base_Column_List">
  32. warning_id, warning_no, warning_type, warning_level, warning_special,
  33. disposal_deadline, stage_deadline, item_id, item_snapshot, device_code, device_name,
  34. location, ownership_unit, publisher, publish_time, handler, reviewer,
  35. status, warning_content, process_instance_id, create_by, create_time, update_by,
  36. update_time, remark
  37. </sql>
  38. <!-- The city-life project only contains water supply, drainage, gas and manhole warnings. -->
  39. <sql id="SupportedDashboardWarningTypes">
  40. AND EXISTS (SELECT 1 FROM app_user.warning_type wt WHERE wt.warning_code = w.warning_type)
  41. </sql>
  42. <sql id="DashboardWarningTypeFilter">
  43. <if test="warningType != null and warningType != ''">AND w.warning_type = #{warningType}</if>
  44. </sql>
  45. <sql id="DashboardWarningLevelFilter">
  46. <if test="warningLevel != null and warningLevel != ''">AND w.warning_level = #{warningLevel}</if>
  47. </sql>
  48. <sql id="DashboardWarningColumns">
  49. w.warning_id,
  50. w.warning_no,
  51. w.warning_type,
  52. (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  53. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  54. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name,
  55. w.warning_level,
  56. w.warning_special,
  57. w.location,
  58. w.ownership_unit,
  59. w.publisher,
  60. w.publish_time,
  61. w.handler,
  62. w.status,
  63. w.warning_content,
  64. w.create_time,
  65. w.update_time,
  66. w.device_code,
  67. w.device_name
  68. </sql>
  69. <sql id="DashboardResolvedTimeJoin">
  70. LEFT JOIN (
  71. SELECT warning_id, MAX(create_time) AS resolved_time
  72. FROM app_user.warning_disposal
  73. WHERE disposal_type IN ('RESOLVE', 'CLOSE', 'CLEAR', 'AUTO_CLEAR')
  74. GROUP BY warning_id
  75. ) resolved_record ON resolved_record.warning_id = w.warning_id
  76. </sql>
  77. <!-- 统计今日预警核心指标 -->
  78. <select id="selectTodayWarningStats" resultType="java.util.Map">
  79. SELECT
  80. COUNT(CASE WHEN w.status != 'DRAFT' THEN 1 END) AS today_total,
  81. COUNT(CASE WHEN w.status = 'HANDLED' THEN 1 END) AS handled_today,
  82. COUNT(CASE WHEN w.status = 'CLOSED' THEN 1 END) AS closed_today
  83. FROM app_user.early_warning w
  84. WHERE w.publish_time &gt;= CURRENT_DATE
  85. AND w.publish_time &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  86. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  87. <include refid="SupportedDashboardWarningTypes"/>
  88. </select>
  89. <!-- 查询今日预警列表 -->
  90. <select id="selectTodayWarningList" resultMap="BaseResultMap">
  91. SELECT <include refid="Base_Column_List"/>
  92. FROM app_user.early_warning w
  93. WHERE w.publish_time &gt;= CURRENT_DATE
  94. AND w.publish_time &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  95. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  96. <include refid="SupportedDashboardWarningTypes"/>
  97. <choose>
  98. <when test="status != null and status != ''">
  99. AND w.status = #{status}
  100. </when>
  101. <otherwise>
  102. AND w.status != 'DRAFT'
  103. </otherwise>
  104. </choose>
  105. ORDER BY w.publish_time DESC
  106. </select>
  107. <!-- 按日统计预警发展趋势 -->
  108. <select id="selectWarningTrendByDay" resultType="java.util.Map">
  109. SELECT
  110. TO_CHAR(publish_time, 'YYYY-MM-DD') AS stat_date,
  111. COALESCE(NULLIF(warning_special, ''), '其他') AS warning_special,
  112. COUNT(*) AS warning_count
  113. FROM app_user.early_warning
  114. WHERE status != 'DRAFT'
  115. AND EXISTS (SELECT 1 FROM app_user.warning_type wt WHERE wt.warning_code = early_warning.warning_type)
  116. <if test="startTime != null">
  117. AND publish_time &gt;= #{startTime}
  118. </if>
  119. <if test="endTime != null">
  120. AND publish_time &lt; #{endTime}
  121. </if>
  122. <if test="warningSpecial != null and warningSpecial != ''">
  123. AND COALESCE(NULLIF(warning_special, ''), '其他') = #{warningSpecial}
  124. </if>
  125. GROUP BY TO_CHAR(publish_time, 'YYYY-MM-DD'), COALESCE(NULLIF(warning_special, ''), '其他')
  126. ORDER BY stat_date ASC, warning_special ASC
  127. </select>
  128. <!-- 按月统计预警发展趋势 -->
  129. <select id="selectWarningTrendByMonth" resultType="java.util.Map">
  130. SELECT
  131. TO_CHAR(publish_time, 'YYYY-MM') AS stat_month,
  132. COALESCE(NULLIF(warning_special, ''), '其他') AS warning_special,
  133. COUNT(*) AS warning_count
  134. FROM app_user.early_warning
  135. WHERE status != 'DRAFT'
  136. AND EXISTS (SELECT 1 FROM app_user.warning_type wt WHERE wt.warning_code = early_warning.warning_type)
  137. <if test="startTime != null">
  138. AND publish_time &gt;= #{startTime}
  139. </if>
  140. <if test="endTime != null">
  141. AND publish_time &lt; #{endTime}
  142. </if>
  143. <if test="warningSpecial != null and warningSpecial != ''">
  144. AND COALESCE(NULLIF(warning_special, ''), '其他') = #{warningSpecial}
  145. </if>
  146. GROUP BY TO_CHAR(publish_time, 'YYYY-MM'), COALESCE(NULLIF(warning_special, ''), '其他')
  147. ORDER BY stat_month ASC, warning_special ASC
  148. </select>
  149. <!-- 处置状态分析:按预警状态分组统计数量 -->
  150. <select id="selectWarningGroupByStatus" resultType="java.util.Map">
  151. SELECT
  152. status,
  153. COUNT(warning_id) AS status_count
  154. FROM app_user.early_warning
  155. WHERE status != 'DRAFT'
  156. AND EXISTS (SELECT 1 FROM app_user.warning_type wt WHERE wt.warning_code = early_warning.warning_type)
  157. <if test="startTime != null">
  158. AND publish_time &gt;= #{startTime}
  159. </if>
  160. <if test="endTime != null">
  161. AND publish_time &lt; #{endTime}
  162. </if>
  163. <if test="warningSpecial != null and warningSpecial != ''">
  164. AND warning_special = #{warningSpecial}
  165. </if>
  166. GROUP BY status
  167. ORDER BY status_count DESC
  168. </select>
  169. <select id="selectDisposalGroupByType" resultType="java.util.Map">
  170. SELECT d.disposal_type, COUNT(*) AS disposal_count
  171. FROM app_user.warning_disposal d
  172. INNER JOIN app_user.early_warning w ON w.warning_id = d.warning_id
  173. WHERE w.status != 'DRAFT'
  174. <include refid="SupportedDashboardWarningTypes"/>
  175. <if test="startTime != null">
  176. AND w.publish_time &gt;= #{startTime}
  177. </if>
  178. <if test="endTime != null">
  179. AND w.publish_time &lt; #{endTime}
  180. </if>
  181. <if test="warningSpecial != null and warningSpecial != ''">
  182. AND w.warning_special = #{warningSpecial}
  183. </if>
  184. GROUP BY d.disposal_type
  185. ORDER BY disposal_count DESC
  186. </select>
  187. <!-- 处置时效分析-概览指标统计 -->
  188. <select id="selectDisposeEfficiencyOverview" resultType="java.util.Map">
  189. SELECT
  190. ROUND(AVG(dispose_hours), 2) AS avg_hours,
  191. ROUND(MAX(dispose_hours), 2) AS max_hours,
  192. ROUND(MIN(dispose_hours), 2) AS min_hours,
  193. COUNT(*) AS total_count
  194. FROM (
  195. SELECT
  196. EXTRACT(EPOCH FROM (CAST(MAX(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS dispose_hours
  197. FROM app_user.early_warning w
  198. INNER JOIN app_user.warning_disposal d
  199. ON w.warning_id = d.warning_id
  200. AND d.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT', 'AUTO_CLEAR')
  201. WHERE w.status IN ('HANDLED', 'CLOSED')
  202. <include refid="SupportedDashboardWarningTypes"/>
  203. <if test="startTime != null">
  204. AND w.publish_time &gt;= #{startTime}
  205. </if>
  206. <if test="endTime != null">
  207. AND w.publish_time &lt; #{endTime}
  208. </if>
  209. <if test="warningSpecial != null and warningSpecial != ''">
  210. AND w.warning_special = #{warningSpecial}
  211. </if>
  212. GROUP BY w.warning_id, w.publish_time
  213. HAVING MAX(d.create_time) &gt;= w.publish_time
  214. ) AS temp
  215. </select>
  216. <!-- 处置时效分析-时效区间分布统计 -->
  217. <select id="selectDisposeEfficiencyRange" resultType="java.util.Map">
  218. SELECT
  219. CASE
  220. WHEN dispose_hours &lt;= 2 THEN '0-2小时'
  221. WHEN dispose_hours &lt;= 6 THEN '2-6小时'
  222. WHEN dispose_hours &lt;= 24 THEN '6-24小时'
  223. ELSE '24小时以上'
  224. END AS time_range,
  225. COUNT(*) AS warning_count
  226. FROM (
  227. SELECT
  228. EXTRACT(EPOCH FROM (CAST(MAX(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS dispose_hours
  229. FROM app_user.early_warning w
  230. INNER JOIN app_user.warning_disposal d
  231. ON w.warning_id = d.warning_id
  232. AND d.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT', 'AUTO_CLEAR')
  233. WHERE w.status IN ('HANDLED', 'CLOSED')
  234. <include refid="SupportedDashboardWarningTypes"/>
  235. <if test="startTime != null">
  236. AND w.publish_time &gt;= #{startTime}
  237. </if>
  238. <if test="endTime != null">
  239. AND w.publish_time &lt; #{endTime}
  240. </if>
  241. <if test="warningSpecial != null and warningSpecial != ''">
  242. AND w.warning_special = #{warningSpecial}
  243. </if>
  244. GROUP BY w.warning_id, w.publish_time
  245. HAVING MAX(d.create_time) &gt;= w.publish_time
  246. ) AS temp
  247. GROUP BY time_range
  248. ORDER BY
  249. CASE time_range
  250. WHEN '0-2小时' THEN 1
  251. WHEN '2-6小时' THEN 2
  252. WHEN '6-24小时' THEN 3
  253. ELSE 4
  254. END ASC
  255. </select>
  256. <!-- 处置时效分析-按预警专项统计平均时效 -->
  257. <select id="selectDisposeEfficiencyBySpecial" resultType="java.util.Map">
  258. SELECT
  259. COALESCE(NULLIF(warning_special, ''), '其他') AS warning_special,
  260. COUNT(*) AS warning_count,
  261. ROUND(AVG(dispose_hours), 2) AS avg_dispose_hours
  262. FROM (
  263. SELECT
  264. COALESCE(NULLIF(w.warning_special, ''), '其他') AS warning_special,
  265. EXTRACT(EPOCH FROM (CAST(MAX(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS dispose_hours
  266. FROM app_user.early_warning w
  267. INNER JOIN app_user.warning_disposal d
  268. ON w.warning_id = d.warning_id
  269. AND d.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT', 'AUTO_CLEAR')
  270. WHERE w.status IN ('HANDLED', 'CLOSED')
  271. <include refid="SupportedDashboardWarningTypes"/>
  272. <if test="startTime != null">
  273. AND w.publish_time &gt;= #{startTime}
  274. </if>
  275. <if test="endTime != null">
  276. AND w.publish_time &lt; #{endTime}
  277. </if>
  278. <if test="warningSpecial != null and warningSpecial != ''">
  279. AND COALESCE(NULLIF(w.warning_special, ''), '其他') = #{warningSpecial}
  280. </if>
  281. GROUP BY w.warning_id, COALESCE(NULLIF(w.warning_special, ''), '其他'), w.publish_time
  282. HAVING MAX(d.create_time) &gt;= w.publish_time
  283. ) AS temp
  284. GROUP BY warning_special
  285. ORDER BY avg_dispose_hours DESC
  286. </select>
  287. <!-- 处置时效分析-明细列表 -->
  288. <select id="selectDisposeEfficiencyList" resultType="java.util.Map">
  289. SELECT
  290. w.warning_id,
  291. w.warning_no,
  292. COALESCE(w.warning_special, '其他') AS warning_special,
  293. w.publish_time,
  294. MAX(d.create_time) AS dispose_time,
  295. ROUND(EXTRACT(EPOCH FROM (CAST(MAX(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600, 2) AS dispose_hours,
  296. w.status
  297. FROM app_user.early_warning w
  298. INNER JOIN app_user.warning_disposal d
  299. ON w.warning_id = d.warning_id
  300. AND d.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT', 'AUTO_CLEAR')
  301. WHERE w.status IN ('HANDLED', 'CLOSED')
  302. <include refid="SupportedDashboardWarningTypes"/>
  303. <if test="startTime != null">
  304. AND w.publish_time &gt;= #{startTime}
  305. </if>
  306. <if test="endTime != null">
  307. AND w.publish_time &lt; #{endTime}
  308. </if>
  309. <if test="warningSpecial != null and warningSpecial != ''">
  310. AND w.warning_special = #{warningSpecial}
  311. </if>
  312. GROUP BY w.warning_id, w.warning_no, w.warning_special, w.publish_time, w.status
  313. HAVING MAX(d.create_time) &gt;= w.publish_time
  314. ORDER BY dispose_hours
  315. <if test="sortType != null and sortType == 'desc'">
  316. DESC
  317. </if>
  318. <if test="sortType == null or sortType == 'asc'">
  319. ASC
  320. </if>
  321. </select>
  322. <!-- 接警效率分析-概览指标统计 -->
  323. <select id="selectReceiveEfficiencyOverview" resultType="java.util.Map">
  324. SELECT
  325. ROUND(AVG(receive_hours), 2) AS avg_hours,
  326. ROUND(MAX(receive_hours), 2) AS max_hours,
  327. ROUND(MIN(receive_hours), 2) AS min_hours,
  328. COUNT(*) AS total_count
  329. FROM (
  330. SELECT
  331. EXTRACT(EPOCH FROM (CAST(MIN(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS receive_hours
  332. FROM app_user.early_warning w
  333. INNER JOIN app_user.warning_disposal d ON w.warning_id = d.warning_id
  334. WHERE w.status != 'DRAFT'
  335. <include refid="SupportedDashboardWarningTypes"/>
  336. <if test="startTime != null">
  337. AND w.publish_time &gt;= #{startTime}
  338. </if>
  339. <if test="endTime != null">
  340. AND w.publish_time &lt; #{endTime}
  341. </if>
  342. <include refid="DashboardWarningTypeFilter"/>
  343. <if test="warningSpecial != null and warningSpecial != ''">
  344. AND w.warning_special = #{warningSpecial}
  345. </if>
  346. <if test="status != null and status != ''">
  347. AND w.status = #{status}
  348. </if>
  349. GROUP BY w.warning_id, w.publish_time
  350. HAVING MIN(d.create_time) &gt;= w.publish_time
  351. ) AS temp
  352. </select>
  353. <!-- 接警效率分析-时效区间分布统计 -->
  354. <select id="selectReceiveEfficiencyRange" resultType="java.util.Map">
  355. SELECT
  356. CASE
  357. WHEN receive_hours &lt;= 0.5 THEN '0-30分钟'
  358. WHEN receive_hours &lt;= 2 THEN '30分钟-2小时'
  359. WHEN receive_hours &lt;= 6 THEN '2-6小时'
  360. ELSE '6小时以上'
  361. END AS time_range,
  362. COUNT(*) AS warning_count
  363. FROM (
  364. SELECT
  365. EXTRACT(EPOCH FROM (CAST(MIN(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS receive_hours
  366. FROM app_user.early_warning w
  367. INNER JOIN app_user.warning_disposal d ON w.warning_id = d.warning_id
  368. WHERE w.status != 'DRAFT'
  369. <include refid="SupportedDashboardWarningTypes"/>
  370. <if test="startTime != null">
  371. AND w.publish_time &gt;= #{startTime}
  372. </if>
  373. <if test="endTime != null">
  374. AND w.publish_time &lt; #{endTime}
  375. </if>
  376. <include refid="DashboardWarningTypeFilter"/>
  377. <if test="warningSpecial != null and warningSpecial != ''">
  378. AND w.warning_special = #{warningSpecial}
  379. </if>
  380. <if test="status != null and status != ''">
  381. AND w.status = #{status}
  382. </if>
  383. GROUP BY w.warning_id, w.publish_time
  384. HAVING MIN(d.create_time) &gt;= w.publish_time
  385. ) AS temp
  386. GROUP BY time_range
  387. ORDER BY
  388. CASE time_range
  389. WHEN '0-30分钟' THEN 1
  390. WHEN '30分钟-2小时' THEN 2
  391. WHEN '2-6小时' THEN 3
  392. ELSE 4
  393. END ASC
  394. </select>
  395. <!-- 接警效率分析-按预警类型统计平均时效 -->
  396. <select id="selectReceiveEfficiencyByType" resultType="java.util.Map">
  397. SELECT
  398. COALESCE(warning_type, '其他') AS warning_type,
  399. COUNT(*) AS warning_count,
  400. ROUND(AVG(receive_hours), 2) AS avg_receive_hours
  401. FROM (
  402. SELECT
  403. w.warning_type,
  404. EXTRACT(EPOCH FROM (CAST(MIN(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600 AS receive_hours
  405. FROM app_user.early_warning w
  406. INNER JOIN app_user.warning_disposal d ON w.warning_id = d.warning_id
  407. WHERE w.status != 'DRAFT'
  408. <include refid="SupportedDashboardWarningTypes"/>
  409. <if test="startTime != null">
  410. AND w.publish_time &gt;= #{startTime}
  411. </if>
  412. <if test="endTime != null">
  413. AND w.publish_time &lt; #{endTime}
  414. </if>
  415. <include refid="DashboardWarningTypeFilter"/>
  416. <if test="warningSpecial != null and warningSpecial != ''">
  417. AND w.warning_special = #{warningSpecial}
  418. </if>
  419. <if test="status != null and status != ''">
  420. AND w.status = #{status}
  421. </if>
  422. GROUP BY w.warning_id, w.warning_type, w.publish_time
  423. HAVING MIN(d.create_time) &gt;= w.publish_time
  424. ) AS temp
  425. GROUP BY warning_type
  426. ORDER BY avg_receive_hours DESC
  427. </select>
  428. <!-- 接警效率分析-明细列表 -->
  429. <select id="selectReceiveEfficiencyList" resultType="java.util.Map">
  430. SELECT
  431. w.warning_id,
  432. w.warning_no,
  433. COALESCE(w.warning_type, '其他') AS warning_type,
  434. COALESCE(w.warning_special, '其他') AS warning_special,
  435. w.publish_time,
  436. MIN(d.create_time) AS receive_time,
  437. ROUND(EXTRACT(EPOCH FROM (CAST(MIN(d.create_time) AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ))) / 3600, 2) AS receive_hours,
  438. w.status
  439. FROM app_user.early_warning w
  440. INNER JOIN app_user.warning_disposal d ON w.warning_id = d.warning_id
  441. WHERE w.status != 'DRAFT'
  442. <include refid="SupportedDashboardWarningTypes"/>
  443. <if test="startTime != null">
  444. AND w.publish_time &gt;= #{startTime}
  445. </if>
  446. <if test="endTime != null">
  447. AND w.publish_time &lt; #{endTime}
  448. </if>
  449. <include refid="DashboardWarningTypeFilter"/>
  450. <if test="warningSpecial != null and warningSpecial != ''">
  451. AND w.warning_special = #{warningSpecial}
  452. </if>
  453. <if test="status != null and status != ''">
  454. AND w.status = #{status}
  455. </if>
  456. GROUP BY w.warning_id, w.warning_no, w.warning_type,
  457. w.warning_special, w.publish_time, w.status
  458. HAVING MIN(d.create_time) &gt;= w.publish_time
  459. ORDER BY receive_hours
  460. <if test="sortType != null and sortType == 'desc'">
  461. DESC
  462. </if>
  463. <if test="sortType == null or sortType == 'asc'">
  464. ASC
  465. </if>
  466. </select>
  467. <!-- ————————————————————————————————————————————————————————————— -->
  468. <!-- Warning overview: headline numbers for current active and resolved-today warnings. -->
  469. <select id="selectDashboardTodaySummary" resultType="java.util.Map">
  470. SELECT
  471. COUNT(CASE
  472. WHEN w.publish_time &gt;= CURRENT_DATE
  473. AND w.publish_time &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  474. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  475. AND w.status != 'DRAFT'
  476. THEN 1 END) AS today_total,
  477. COUNT(CASE
  478. WHEN w.publish_time &lt;= CURRENT_TIMESTAMP
  479. AND w.status NOT IN ('DRAFT', 'CLOSED')
  480. THEN 1 END) AS unresolved_count,
  481. COUNT(CASE
  482. WHEN w.status IN ('CLOSED')
  483. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &gt;= CURRENT_DATE
  484. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time)
  485. &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  486. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &lt;= CURRENT_TIMESTAMP
  487. THEN 1 END) AS resolved_count
  488. FROM app_user.early_warning w
  489. <include refid="DashboardResolvedTimeJoin"/>
  490. WHERE 1 = 1
  491. <include refid="SupportedDashboardWarningTypes"/>
  492. </select>
  493. <!-- Small detail lists returned with the today overview cards. -->
  494. <select id="selectDashboardTodayPreview" resultType="java.util.Map">
  495. SELECT
  496. <include refid="DashboardWarningColumns"/>,
  497. COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) AS resolved_time,
  498. ROUND(
  499. EXTRACT(EPOCH FROM (
  500. CAST(CURRENT_TIMESTAMP AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ)
  501. )) / 3600,
  502. 2
  503. ) AS waiting_hours
  504. FROM app_user.early_warning w
  505. <include refid="DashboardResolvedTimeJoin"/>
  506. WHERE 1 = 1
  507. <include refid="SupportedDashboardWarningTypes"/>
  508. <choose>
  509. <when test="category == 'resolved'">
  510. AND w.status IN ('CLOSED')
  511. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &gt;= CURRENT_DATE
  512. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time)
  513. &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  514. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &lt;= CURRENT_TIMESTAMP
  515. ORDER BY resolved_time DESC, w.warning_id DESC
  516. </when>
  517. <otherwise>
  518. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  519. AND w.status NOT IN ('DRAFT', 'CLOSED')
  520. ORDER BY
  521. CASE w.warning_level
  522. WHEN '4' THEN 1 WHEN 'RED' THEN 1
  523. WHEN '3' THEN 2 WHEN 'ORANGE' THEN 2
  524. WHEN '2' THEN 3 WHEN 'YELLOW' THEN 3
  525. WHEN '1' THEN 4 WHEN 'BLUE' THEN 4
  526. ELSE 5
  527. END,
  528. w.publish_time ASC,
  529. w.warning_id ASC
  530. </otherwise>
  531. </choose>
  532. LIMIT #{limit}
  533. </select>
  534. <!-- Paged detail list for the two today overview categories. -->
  535. <select id="selectDashboardTodayPage" resultType="java.util.Map">
  536. SELECT
  537. <include refid="DashboardWarningColumns"/>,
  538. COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) AS resolved_time,
  539. ROUND(
  540. EXTRACT(EPOCH FROM (
  541. CAST(CURRENT_TIMESTAMP AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ)
  542. )) / 3600,
  543. 2
  544. ) AS waiting_hours
  545. FROM app_user.early_warning w
  546. <include refid="DashboardResolvedTimeJoin"/>
  547. <where>
  548. <include refid="SupportedDashboardWarningTypes"/>
  549. <choose>
  550. <when test="category == 'resolved'">
  551. AND w.status IN ('CLOSED')
  552. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &gt;= CURRENT_DATE
  553. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time)
  554. &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  555. AND COALESCE(resolved_record.resolved_time, w.update_time, w.publish_time) &lt;= CURRENT_TIMESTAMP
  556. </when>
  557. <when test="category == 'all'">
  558. AND w.publish_time &gt;= CURRENT_DATE
  559. AND w.publish_time &lt; CAST(CURRENT_DATE AS TIMESTAMP) + CAST('1 day' AS INTERVAL)
  560. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  561. AND w.status != 'DRAFT'
  562. </when>
  563. <otherwise>
  564. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  565. AND w.status NOT IN ('DRAFT', 'CLOSED')
  566. </otherwise>
  567. </choose>
  568. <include refid="DashboardWarningTypeFilter"/>
  569. <include refid="DashboardWarningLevelFilter"/>
  570. <if test="keyword != null and keyword != ''">
  571. AND (
  572. w.warning_no LIKE CONCAT('%', #{keyword}, '%')
  573. OR w.warning_special LIKE CONCAT('%', #{keyword}, '%')
  574. OR w.ownership_unit LIKE CONCAT('%', #{keyword}, '%')
  575. )
  576. </if>
  577. </where>
  578. <choose>
  579. <when test="category == 'resolved'">
  580. ORDER BY resolved_time DESC, w.warning_id DESC
  581. </when>
  582. <when test="category == 'all'">
  583. ORDER BY w.publish_time DESC, w.warning_id DESC
  584. </when>
  585. <otherwise>
  586. ORDER BY
  587. CASE w.warning_level
  588. WHEN '4' THEN 1 WHEN 'RED' THEN 1
  589. WHEN '3' THEN 2 WHEN 'ORANGE' THEN 2
  590. WHEN '2' THEN 3 WHEN 'YELLOW' THEN 3
  591. WHEN '1' THEN 4 WHEN 'BLUE' THEN 4
  592. ELSE 5
  593. END,
  594. w.publish_time ASC,
  595. w.warning_id ASC
  596. </otherwise>
  597. </choose>
  598. </select>
  599. <!-- Historical warning summary. Drafts and unsupported facility types are excluded. -->
  600. <select id="selectDashboardHistorySummary" resultType="java.util.Map">
  601. SELECT
  602. COUNT(*) AS total_count,
  603. COUNT(CASE WHEN w.status IN ('CLOSED') THEN 1 END) AS resolved_count,
  604. COUNT(CASE WHEN w.status NOT IN ('CLOSED') THEN 1 END) AS active_count
  605. FROM app_user.early_warning w
  606. WHERE w.status != 'DRAFT'
  607. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  608. <include refid="SupportedDashboardWarningTypes"/>
  609. </select>
  610. <select id="selectDashboardHistorySpecialStats" resultType="java.util.Map">
  611. WITH special_stats AS (
  612. SELECT
  613. COALESCE(NULLIF(w.warning_special, ''), '未分类') AS special_name,
  614. COUNT(*) AS warning_count
  615. FROM app_user.early_warning w
  616. WHERE w.status != 'DRAFT'
  617. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  618. <include refid="SupportedDashboardWarningTypes"/>
  619. <include refid="DashboardWarningTypeFilter"/>
  620. GROUP BY COALESCE(NULLIF(w.warning_special, ''), '未分类')
  621. )
  622. SELECT
  623. special_name,
  624. warning_count,
  625. ROUND(warning_count * 100.0 / NULLIF(SUM(warning_count) OVER (), 0), 2) AS percentage
  626. FROM special_stats
  627. ORDER BY warning_count DESC, special_name ASC
  628. </select>
  629. <select id="selectDashboardHistoryPage" resultType="java.util.Map">
  630. SELECT <include refid="DashboardWarningColumns"/>
  631. FROM app_user.early_warning w
  632. <where>
  633. AND w.status != 'DRAFT'
  634. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  635. <include refid="SupportedDashboardWarningTypes"/>
  636. <include refid="DashboardWarningTypeFilter"/>
  637. <if test="warningSpecial != null and warningSpecial != ''">
  638. AND COALESCE(NULLIF(w.warning_special, ''), '未分类') = #{warningSpecial}
  639. </if>
  640. <if test="keyword != null and keyword != ''">
  641. AND (
  642. w.warning_no LIKE CONCAT('%', #{keyword}, '%')
  643. OR w.ownership_unit LIKE CONCAT('%', #{keyword}, '%')
  644. )
  645. </if>
  646. </where>
  647. ORDER BY w.publish_time DESC, w.warning_id DESC
  648. </select>
  649. <!-- Outstanding warning list. One most-recent open todo is attached per warning. -->
  650. <select id="selectDashboardUnprocessedPage" resultType="java.util.Map">
  651. SELECT
  652. <include refid="DashboardWarningColumns"/>,
  653. open_todo.todo_id,
  654. open_todo.user_id AS todo_user_id,
  655. open_todo.user_name AS todo_user_name,
  656. open_todo.todo_type,
  657. open_todo.read_status,
  658. open_todo.task_name,
  659. open_todo.create_time AS todo_create_time,
  660. ROUND(
  661. EXTRACT(EPOCH FROM (
  662. CAST(CURRENT_TIMESTAMP AS TIMESTAMPTZ) - CAST(w.publish_time AS TIMESTAMPTZ)
  663. )) / 3600,
  664. 2
  665. ) AS waiting_hours
  666. FROM app_user.early_warning w
  667. LEFT JOIN (
  668. SELECT todo_id, warning_id, user_id, user_name, todo_type, read_status, task_name, create_time
  669. FROM (
  670. SELECT
  671. t.*,
  672. ROW_NUMBER() OVER (
  673. PARTITION BY t.warning_id
  674. ORDER BY t.create_time DESC, t.todo_id DESC
  675. ) AS row_num
  676. FROM app_user.warning_todo t
  677. WHERE t.complete_time IS NULL
  678. AND (t.todo_type IS NULL OR t.todo_type != 'DONE')
  679. ) ranked_todo
  680. WHERE row_num = 1
  681. ) open_todo ON open_todo.warning_id = w.warning_id
  682. <where>
  683. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  684. AND w.status IN ('PENDING', 'RECEIVED', 'PROCESSING')
  685. <include refid="SupportedDashboardWarningTypes"/>
  686. <include refid="DashboardWarningTypeFilter"/>
  687. <include refid="DashboardWarningLevelFilter"/>
  688. <if test="keyword != null and keyword != ''">
  689. AND (
  690. w.warning_no LIKE CONCAT('%', #{keyword}, '%')
  691. OR w.warning_special LIKE CONCAT('%', #{keyword}, '%')
  692. OR w.ownership_unit LIKE CONCAT('%', #{keyword}, '%')
  693. )
  694. </if>
  695. </where>
  696. ORDER BY
  697. CASE w.warning_level
  698. WHEN '4' THEN 1 WHEN 'RED' THEN 1
  699. WHEN '3' THEN 2 WHEN 'ORANGE' THEN 2
  700. WHEN '2' THEN 3 WHEN 'YELLOW' THEN 3
  701. WHEN '1' THEN 4 WHEN 'BLUE' THEN 4
  702. ELSE 5
  703. END,
  704. w.publish_time ASC,
  705. w.warning_id ASC
  706. </select>
  707. <!-- Aggregate cards for the unprocessed list. The filters mirror the page
  708. query so counts remain correct when the user searches or narrows a
  709. warning type/level. -->
  710. <select id="selectDashboardUnprocessedSummary" resultType="java.util.Map">
  711. SELECT
  712. COUNT(*) AS total,
  713. COUNT(DISTINCT NULLIF(w.ownership_unit, '')) AS ownership_count,
  714. MIN(CASE WHEN w.warning_level IN ('1', '2', '3', '4') THEN CAST(w.warning_level AS integer) END) AS highest_level
  715. FROM app_user.early_warning w
  716. <where>
  717. AND w.publish_time &lt;= CURRENT_TIMESTAMP
  718. AND w.status IN ('PENDING', 'RECEIVED', 'PROCESSING')
  719. <include refid="SupportedDashboardWarningTypes"/>
  720. <include refid="DashboardWarningTypeFilter"/>
  721. <include refid="DashboardWarningLevelFilter"/>
  722. <if test="keyword != null and keyword != ''">
  723. AND (
  724. w.warning_no LIKE CONCAT('%', #{keyword}, '%')
  725. OR w.warning_special LIKE CONCAT('%', #{keyword}, '%')
  726. OR w.ownership_unit LIKE CONCAT('%', #{keyword}, '%')
  727. )
  728. </if>
  729. </where>
  730. </select>
  731. <select id="selectWarningList" resultType="java.util.Map">
  732. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  733. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  734. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name
  735. FROM early_warning w
  736. <where>
  737. <if test="warningNo != null and warningNo != ''">AND w.warning_no LIKE CONCAT('%',#{warningNo},'%')</if>
  738. <if test="warningType != null and warningType != ''">
  739. AND w.warning_type = #{warningType}
  740. </if>
  741. <if test="warningLevel != null and warningLevel != ''">
  742. AND w.warning_level = #{warningLevel}
  743. </if>
  744. <if test="status != null and status != ''">
  745. AND w.status = #{status}
  746. </if>
  747. </where>
  748. ORDER BY w.create_time DESC
  749. </select>
  750. <select id="searchWarnings" resultType="java.util.Map">
  751. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  752. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  753. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name
  754. FROM early_warning w
  755. <where>
  756. <if test="warningNo != null and warningNo != ''">
  757. AND w.warning_no LIKE CONCAT('%', #{warningNo}, '%')
  758. </if>
  759. <if test="warningType != null and warningType != ''">
  760. AND w.warning_type = #{warningType}
  761. </if>
  762. <if test="warningLevel != null and warningLevel != ''">
  763. AND w.warning_level = #{warningLevel}
  764. </if>
  765. <if test="status != null and status != ''">
  766. AND w.status = #{status}
  767. </if>
  768. <if test="publisher != null and publisher != ''">
  769. AND w.publisher LIKE CONCAT('%', #{publisher}, '%')
  770. </if>
  771. <if test="excludePublisher != null and excludePublisher != ''">
  772. AND (w.publisher IS NULL OR w.publisher NOT LIKE CONCAT('%', #{excludePublisher}, '%'))
  773. </if>
  774. <if test="ownershipUnit != null and ownershipUnit != ''">
  775. AND w.ownership_unit LIKE CONCAT('%', #{ownershipUnit}, '%')
  776. </if>
  777. <if test="deviceCode != null and deviceCode != ''">
  778. AND w.device_code LIKE CONCAT('%', #{deviceCode}, '%')
  779. </if>
  780. <if test="deviceName != null and deviceName != ''">
  781. AND w.device_name LIKE CONCAT('%', #{deviceName}, '%')
  782. </if>
  783. <if test="startTime != null">
  784. AND w.create_time >= #{startTime}
  785. </if>
  786. <if test="endTime != null">
  787. AND w.create_time &lt;= #{endTime}
  788. </if>
  789. </where>
  790. <choose>
  791. <when test="releaseOrder">
  792. ORDER BY CASE w.status
  793. WHEN 'DRAFT' THEN 0
  794. WHEN 'PENDING' THEN 1
  795. WHEN 'RECEIVED' THEN 2
  796. WHEN 'PROCESSING' THEN 3
  797. WHEN 'HANDLED' THEN 4
  798. WHEN 'CLOSED' THEN 5
  799. ELSE 6 END,
  800. COALESCE(w.update_time, w.create_time) DESC NULLS LAST,
  801. w.create_time DESC NULLS LAST, w.warning_id DESC
  802. </when>
  803. <otherwise>ORDER BY w.create_time DESC</otherwise>
  804. </choose>
  805. </select>
  806. <select id="selectTodoList" resultType="java.util.Map">
  807. SELECT
  808. t.*,
  809. w.warning_no,
  810. w.warning_type,
  811. w.warning_level,
  812. w.handler,
  813. w.publisher,
  814. w.location,
  815. w.ownership_unit,
  816. w.publish_time
  817. FROM warning_todo t
  818. LEFT JOIN early_warning w ON t.warning_id = w.warning_id
  819. <where>
  820. t.user_id = #{userId}
  821. <if test="warningNo != null and warningNo != ''">AND w.warning_no LIKE CONCAT('%',#{warningNo},'%')</if>
  822. <if test="todoType != null and todoType != ''">
  823. AND t.todo_type = #{todoType}
  824. </if>
  825. </where>
  826. ORDER BY t.create_time DESC
  827. </select>
  828. <!-- 身份由服务端登录上下文传入,禁止使用请求中的 userName。 -->
  829. <select id="selectMyTasks" resultType="java.util.Map">
  830. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  831. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  832. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name, t.todo_id, t.todo_type, t.action_type, t.task_name, t.read_status,
  833. t.create_time AS task_create_time, t.complete_time,
  834. (SELECT STRING_AGG(DISTINCT a.alarm_no, ',')
  835. FROM alarm_warning_rel rel JOIN alarm_data a ON a.id = rel.alarm_id
  836. WHERE rel.warning_id = w.warning_id) AS alarm_numbers
  837. FROM (
  838. SELECT task.*, ROW_NUMBER() OVER (
  839. PARTITION BY CASE WHEN task.todo_type = 'NOTICE' THEN task.todo_id ELSE task.warning_id END
  840. ORDER BY task.complete_time DESC NULLS LAST, task.create_time DESC, task.todo_id DESC
  841. ) AS task_rank
  842. FROM warning_todo task
  843. WHERE (task.user_name = #{username} OR task.user_id = #{userId}
  844. OR (task.user_name IS NULL AND task.user_id = #{username}))
  845. <if test="q.todoType != null and q.todoType != ''">AND task.todo_type = #{q.todoType}</if>
  846. <if test="q.todoType == null or q.todoType == ''">AND task.todo_type IN ('TODO', 'DONE')</if>
  847. ) t JOIN early_warning w ON w.warning_id = t.warning_id
  848. WHERE t.task_rank = 1
  849. <if test="q.warningNo != null and q.warningNo != ''">AND w.warning_no LIKE CONCAT('%',#{q.warningNo},'%')</if>
  850. <if test="q.warningSpecial != null and q.warningSpecial != ''">AND w.warning_special LIKE CONCAT('%',#{q.warningSpecial},'%')</if>
  851. <if test="q.warningType != null and q.warningType != ''">AND w.warning_type = #{q.warningType}</if>
  852. <if test="q.warningLevel != null and q.warningLevel != ''">AND w.warning_level = #{q.warningLevel}</if>
  853. <if test="q.status != null and q.status != ''">AND w.status = #{q.status}</if>
  854. <if test="q.handler != null and q.handler != ''">AND w.handler LIKE CONCAT('%',#{q.handler},'%')</if>
  855. <if test="q.publisher != null and q.publisher != ''">AND w.publisher LIKE CONCAT('%',#{q.publisher},'%')</if>
  856. <if test="q.ownershipUnit != null and q.ownershipUnit != ''">AND w.ownership_unit LIKE CONCAT('%',#{q.ownershipUnit},'%')</if>
  857. <if test="q.startTime != null and q.startTime != ''">AND w.publish_time &gt;= CAST(#{q.startTime} AS TIMESTAMP)</if>
  858. <if test="q.endTime != null and q.endTime != ''">AND w.publish_time &lt;= CAST(#{q.endTime} AS TIMESTAMP)</if>
  859. <if test="q.alarmCode != null and q.alarmCode != ''">
  860. AND EXISTS (SELECT 1 FROM alarm_warning_rel r JOIN alarm_data a ON a.id = r.alarm_id
  861. WHERE r.warning_id = w.warning_id AND a.alarm_no LIKE CONCAT('%',#{q.alarmCode},'%'))
  862. </if>
  863. ORDER BY t.create_time DESC, t.todo_id DESC
  864. </select>
  865. <select id="selectProcessingWarnings" resultType="java.util.Map">
  866. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  867. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  868. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name
  869. FROM early_warning w
  870. <where>
  871. AND w.status IN ('PENDING', 'RECEIVED', 'PROCESSING', 'HANDLED')
  872. <if test="warningType != null and warningType != ''">
  873. AND w.warning_type = #{warningType}
  874. </if>
  875. <if test="warningLevel != null and warningLevel != ''">
  876. AND w.warning_level = #{warningLevel}
  877. </if>
  878. </where>
  879. ORDER BY w.publish_time DESC
  880. </select>
  881. <select id="selectCompletedWarnings" resultType="java.util.Map">
  882. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  883. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  884. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name
  885. FROM early_warning w
  886. <where>
  887. AND w.status = 'CLOSED'
  888. <if test="warningType != null and warningType != ''">
  889. AND w.warning_type = #{warningType}
  890. </if>
  891. <if test="warningLevel != null and warningLevel != ''">
  892. AND w.warning_level = #{warningLevel}
  893. </if>
  894. <if test="startTime != null">
  895. AND w.update_time >= #{startTime}
  896. </if>
  897. <if test="endTime != null">
  898. AND w.update_time &lt;= #{endTime}
  899. </if>
  900. </where>
  901. ORDER BY w.update_time DESC
  902. </select>
  903. <select id="selectWarningDetail" resultType="java.util.Map">
  904. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  905. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  906. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name
  907. FROM early_warning w
  908. WHERE w.warning_id = #{warningId}
  909. </select>
  910. <select id="selectStatistics" resultType="java.util.Map">
  911. SELECT
  912. COUNT(*) AS total,
  913. SUM(CASE WHEN status = 'DRAFT' THEN 1 ELSE 0 END) AS draftCount,
  914. SUM(CASE WHEN status = 'PENDING' THEN 1 ELSE 0 END) AS pendingCount,
  915. SUM(CASE WHEN status = 'PROCESSING' THEN 1 ELSE 0 END) AS processingCount,
  916. SUM(CASE WHEN status = 'RECEIVED' THEN 1 ELSE 0 END) AS receivedCount,
  917. SUM(CASE WHEN status = 'HANDLED' THEN 1 ELSE 0 END) AS handledCount,
  918. SUM(CASE WHEN status = 'CLOSED' THEN 1 ELSE 0 END) AS closedCount,
  919. SUM(CASE WHEN warning_level = '1' THEN 1 ELSE 0 END) AS level1Count,
  920. SUM(CASE WHEN warning_level = '2' THEN 1 ELSE 0 END) AS level2Count,
  921. SUM(CASE WHEN warning_level = '3' THEN 1 ELSE 0 END) AS level3Count,
  922. SUM(CASE WHEN warning_level = '4' THEN 1 ELSE 0 END) AS level4Count
  923. FROM early_warning
  924. </select>
  925. <!-- 行业处置分析:兼容 device_code 存设备实例编码或设备类别主键两种历史格式。
  926. 设备类别主键改为整数后,业态由根节点 id 决定:1=供水 2=排水 3=燃气 4=窨井,
  927. 对外仍以 water_supply/drainage/gas/manhole 作为 industry_code,保持接口契约不变。 -->
  928. <sql id="IndustryWarningCte">
  929. WITH RECURSIVE type_tree AS (
  930. SELECT et.id AS leaf_id, et.id AS current_id,
  931. et.type_name AS current_name, et.parent_id, CAST(0 AS bigint) AS depth
  932. FROM app_user.equipment_type et
  933. UNION ALL
  934. SELECT tree.leaf_id, parent.id, parent.type_name,
  935. parent.parent_id, tree.depth + 1
  936. FROM type_tree tree
  937. INNER JOIN app_user.equipment_type parent ON parent.id = tree.parent_id
  938. ),
  939. root_ranked AS (
  940. SELECT leaf_id, current_id AS industry_id, current_name AS industry_name,
  941. ROW_NUMBER() OVER (PARTITION BY leaf_id ORDER BY depth DESC) AS row_num
  942. FROM type_tree
  943. ),
  944. type_roots AS (
  945. SELECT leaf_id,
  946. CASE industry_id
  947. WHEN 1 THEN 'water_supply'
  948. WHEN 2 THEN 'drainage'
  949. WHEN 3 THEN 'gas'
  950. WHEN 4 THEN 'manhole'
  951. END AS industry_code,
  952. industry_name
  953. FROM root_ranked
  954. WHERE row_num = 1
  955. AND industry_id IN (1, 2, 3, 4)
  956. ),
  957. equipment_map AS (
  958. SELECT equipment_code, MIN(equipment_type_id) AS equipment_type_id
  959. FROM app_user.equipment_base
  960. WHERE del_flag = '0'
  961. GROUP BY equipment_code
  962. ),
  963. warning_industry AS (
  964. SELECT w.*, (SELECT wt.warning_name FROM app_user.warning_type wt WHERE wt.warning_code=w.warning_type ORDER BY wt.id LIMIT 1) AS warning_type_name,
  965. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='alert_level' AND dict_value=w.warning_level AND status='0' ORDER BY dict_sort LIMIT 1) AS warning_level_name,
  966. (SELECT dict_label FROM app_user.sys_dict_data WHERE dict_type='pre_alarm_status' AND dict_value=w.status AND status='0' ORDER BY dict_sort LIMIT 1) AS status_name, roots.industry_code, roots.industry_name
  967. FROM app_user.early_warning w
  968. LEFT JOIN equipment_map equipment ON equipment.equipment_code = w.device_code
  969. LEFT JOIN app_user.equipment_type direct_type
  970. ON CAST(direct_type.id AS varchar) = w.device_code
  971. INNER JOIN type_roots roots
  972. ON CAST(roots.leaf_id AS varchar) =
  973. COALESCE(equipment.equipment_type_id, CAST(direct_type.id AS varchar))
  974. WHERE w.status != 'DRAFT'
  975. <if test="startTime != null">
  976. AND w.publish_time &gt;= #{startTime}
  977. </if>
  978. <if test="endTime != null">
  979. AND w.publish_time &lt; #{endTime}
  980. </if>
  981. <if test="industryCode != null and industryCode != ''">
  982. AND roots.industry_code = #{industryCode}
  983. </if>
  984. ),
  985. completed_actions AS (
  986. SELECT disposal.warning_id, MAX(disposal.create_time) AS dispose_time
  987. FROM app_user.warning_disposal disposal
  988. WHERE disposal.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT', 'AUTO_CLEAR')
  989. GROUP BY disposal.warning_id
  990. )
  991. </sql>
  992. <select id="selectIndustryAnalysisSummary" resultType="java.util.Map">
  993. <include refid="IndustryWarningCte"/>
  994. SELECT warning.industry_code,
  995. warning.industry_name,
  996. COUNT(*) AS total_count,
  997. SUM(CASE WHEN warning.status IN ('PENDING', 'RECEIVED') THEN 1 ELSE 0 END) AS pending_count,
  998. SUM(CASE WHEN warning.status = 'PROCESSING' THEN 1 ELSE 0 END) AS processing_count,
  999. SUM(CASE WHEN warning.status IN ('HANDLED', 'CLOSED') THEN 1 ELSE 0 END) AS completed_count,
  1000. ROUND(100.0 * SUM(CASE WHEN warning.status IN ('HANDLED', 'CLOSED') THEN 1 ELSE 0 END)
  1001. / NULLIF(COUNT(*), 0), 2) AS completion_rate,
  1002. ROUND(AVG(CASE
  1003. WHEN warning.status IN ('HANDLED', 'CLOSED')
  1004. AND action.dispose_time &gt;= warning.publish_time
  1005. THEN EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1006. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600
  1007. END), 2) AS avg_dispose_hours,
  1008. SUM(CASE
  1009. WHEN warning.status IN ('HANDLED', 'CLOSED')
  1010. AND action.dispose_time &gt;= warning.publish_time
  1011. AND EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1012. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600 &gt; 24
  1013. THEN 1 ELSE 0 END) AS over_24h_count
  1014. FROM warning_industry warning
  1015. LEFT JOIN completed_actions action ON action.warning_id = warning.warning_id
  1016. GROUP BY warning.industry_code, warning.industry_name
  1017. ORDER BY CASE warning.industry_code
  1018. WHEN 'gas' THEN 1 WHEN 'water_supply' THEN 2
  1019. WHEN 'drainage' THEN 3 WHEN 'manhole' THEN 4 ELSE 5 END
  1020. </select>
  1021. <select id="selectIndustryStatusDistribution" resultType="java.util.Map">
  1022. <include refid="IndustryWarningCte"/>
  1023. <!-- 处置统计只使用 pre_alarm_status 字典中的 CLOSED 终态。 -->
  1024. SELECT industry_code,
  1025. industry_name,
  1026. CASE WHEN status IN ('CLOSED') THEN 'CLOSED' ELSE status END AS status,
  1027. COUNT(*) AS warning_count
  1028. FROM warning_industry
  1029. GROUP BY industry_code,
  1030. industry_name,
  1031. CASE WHEN status IN ('CLOSED') THEN 'CLOSED' ELSE status END
  1032. ORDER BY industry_name,
  1033. CASE WHEN status IN ('CLOSED') THEN 'CLOSED' ELSE status END
  1034. </select>
  1035. <select id="selectIndustryEfficiencyComparison" resultType="java.util.Map">
  1036. <include refid="IndustryWarningCte"/>
  1037. SELECT warning.industry_code,
  1038. warning.industry_name,
  1039. COUNT(*) AS completed_count,
  1040. ROUND(AVG(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1041. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS avg_dispose_hours,
  1042. ROUND(MAX(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1043. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS max_dispose_hours,
  1044. ROUND(MIN(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1045. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS min_dispose_hours,
  1046. ROUND(100.0 * SUM(CASE WHEN EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1047. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600 &lt;= 24
  1048. THEN 1 ELSE 0 END) / NULLIF(COUNT(*), 0), 2) AS within_24h_rate
  1049. FROM warning_industry warning
  1050. INNER JOIN completed_actions action ON action.warning_id = warning.warning_id
  1051. WHERE warning.status IN ('HANDLED', 'CLOSED')
  1052. AND action.dispose_time &gt;= warning.publish_time
  1053. GROUP BY warning.industry_code, warning.industry_name
  1054. ORDER BY avg_dispose_hours DESC
  1055. </select>
  1056. <select id="selectIndustryAnalysisList" resultType="java.util.Map">
  1057. <include refid="IndustryWarningCte"/>
  1058. SELECT warning.warning_id,
  1059. warning.warning_no,
  1060. warning.device_code,
  1061. warning.device_name,
  1062. warning.industry_code,
  1063. warning.industry_name,
  1064. warning.warning_level,
  1065. warning.publish_time,
  1066. warning.status,
  1067. action.dispose_time,
  1068. CASE WHEN action.dispose_time &gt;= warning.publish_time
  1069. THEN ROUND(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
  1070. - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600, 2)
  1071. ELSE NULL END AS dispose_hours
  1072. FROM warning_industry warning
  1073. LEFT JOIN completed_actions action ON action.warning_id = warning.warning_id
  1074. <where>
  1075. <if test="status != null and status != ''">
  1076. <choose>
  1077. <!-- 页面只提供一个“已解除”筛选项,但兼容两种历史状态值。 -->
  1078. <when test="status == 'CLOSED'">
  1079. warning.status IN ('CLOSED')
  1080. </when>
  1081. <otherwise>
  1082. warning.status = #{status}
  1083. </otherwise>
  1084. </choose>
  1085. </if>
  1086. </where>
  1087. ORDER BY dispose_hours
  1088. <if test="sortType != null and sortType == 'desc'">DESC</if>
  1089. <if test="sortType == null or sortType == 'asc'">ASC</if>
  1090. NULLS LAST, warning.publish_time DESC
  1091. </select>
  1092. </mapper>