|
@@ -993,4 +993,169 @@
|
|
|
FROM early_warning
|
|
FROM early_warning
|
|
|
</select>
|
|
</select>
|
|
|
|
|
|
|
|
|
|
+ <!-- 行业处置分析:兼容 device_code 存设备实例编码或设备类别业务编码两种历史格式。 -->
|
|
|
|
|
+ <sql id="IndustryWarningCte">
|
|
|
|
|
+ WITH RECURSIVE type_tree AS (
|
|
|
|
|
+ SELECT et.id AS leaf_id, et.id AS current_id, et.type_id AS current_type_id,
|
|
|
|
|
+ et.type_name AS current_name, et.parent_type_id, CAST(0 AS bigint) AS depth
|
|
|
|
|
+ FROM app_user.equipment_type et
|
|
|
|
|
+ UNION ALL
|
|
|
|
|
+ SELECT tree.leaf_id, parent.id, parent.type_id, parent.type_name,
|
|
|
|
|
+ parent.parent_type_id, tree.depth + 1
|
|
|
|
|
+ FROM type_tree tree
|
|
|
|
|
+ INNER JOIN app_user.equipment_type parent ON parent.id = tree.parent_type_id
|
|
|
|
|
+ ),
|
|
|
|
|
+ root_ranked AS (
|
|
|
|
|
+ SELECT leaf_id, current_type_id AS industry_code, current_name AS industry_name,
|
|
|
|
|
+ ROW_NUMBER() OVER (PARTITION BY leaf_id ORDER BY depth DESC) AS row_num
|
|
|
|
|
+ FROM type_tree
|
|
|
|
|
+ ),
|
|
|
|
|
+ type_roots AS (
|
|
|
|
|
+ SELECT leaf_id, industry_code, industry_name
|
|
|
|
|
+ FROM root_ranked
|
|
|
|
|
+ WHERE row_num = 1
|
|
|
|
|
+ AND industry_code IN ('water_supply', 'drainage', 'gas', 'manhole')
|
|
|
|
|
+ ),
|
|
|
|
|
+ equipment_map AS (
|
|
|
|
|
+ SELECT equipment_code, MIN(equipment_type_id) AS equipment_type_id
|
|
|
|
|
+ FROM app_user.equipment_base
|
|
|
|
|
+ WHERE del_flag = '0'
|
|
|
|
|
+ GROUP BY equipment_code
|
|
|
|
|
+ ),
|
|
|
|
|
+ type_code_map AS (
|
|
|
|
|
+ SELECT type_id, MIN(id) AS id
|
|
|
|
|
+ FROM app_user.equipment_type
|
|
|
|
|
+ GROUP BY type_id
|
|
|
|
|
+ ),
|
|
|
|
|
+ warning_industry AS (
|
|
|
|
|
+ SELECT w.*, roots.industry_code, roots.industry_name
|
|
|
|
|
+ FROM app_user.early_warning w
|
|
|
|
|
+ LEFT JOIN equipment_map equipment ON equipment.equipment_code = w.device_code
|
|
|
|
|
+ LEFT JOIN type_code_map direct_type ON direct_type.type_id = w.device_code
|
|
|
|
|
+ INNER JOIN type_roots roots
|
|
|
|
|
+ ON roots.leaf_id = COALESCE(equipment.equipment_type_id, direct_type.id)
|
|
|
|
|
+ WHERE w.status != 'DRAFT'
|
|
|
|
|
+ <if test="startTime != null">
|
|
|
|
|
+ AND w.publish_time >= #{startTime}
|
|
|
|
|
+ </if>
|
|
|
|
|
+ <if test="endTime != null">
|
|
|
|
|
+ AND w.publish_time < #{endTime}
|
|
|
|
|
+ </if>
|
|
|
|
|
+ <if test="industryCode != null and industryCode != ''">
|
|
|
|
|
+ AND roots.industry_code = #{industryCode}
|
|
|
|
|
+ </if>
|
|
|
|
|
+ ),
|
|
|
|
|
+ completed_actions AS (
|
|
|
|
|
+ SELECT disposal.warning_id, MAX(disposal.create_time) AS dispose_time
|
|
|
|
|
+ FROM app_user.warning_disposal disposal
|
|
|
|
|
+ WHERE disposal.disposal_type IN ('HANDLE', 'RESOLVE', 'CLEAR', 'CLOSE', 'MISREPORT')
|
|
|
|
|
+ GROUP BY disposal.warning_id
|
|
|
|
|
+ )
|
|
|
|
|
+ </sql>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="selectIndustryAnalysisSummary" resultType="java.util.Map">
|
|
|
|
|
+ <include refid="IndustryWarningCte"/>
|
|
|
|
|
+ SELECT warning.industry_code,
|
|
|
|
|
+ warning.industry_name,
|
|
|
|
|
+ COUNT(*) AS total_count,
|
|
|
|
|
+ SUM(CASE WHEN warning.status IN ('PENDING', 'RELEASED') THEN 1 ELSE 0 END) AS pending_count,
|
|
|
|
|
+ SUM(CASE WHEN warning.status = 'PROCESSING' THEN 1 ELSE 0 END) AS processing_count,
|
|
|
|
|
+ SUM(CASE WHEN warning.status IN ('HANDLED', 'CLOSED', 'RESOLVED') THEN 1 ELSE 0 END) AS completed_count,
|
|
|
|
|
+ ROUND(100.0 * SUM(CASE WHEN warning.status IN ('HANDLED', 'CLOSED', 'RESOLVED') THEN 1 ELSE 0 END)
|
|
|
|
|
+ / NULLIF(COUNT(*), 0), 2) AS completion_rate,
|
|
|
|
|
+ ROUND(AVG(CASE
|
|
|
|
|
+ WHEN warning.status IN ('HANDLED', 'CLOSED', 'RESOLVED')
|
|
|
|
|
+ AND action.dispose_time >= warning.publish_time
|
|
|
|
|
+ THEN EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600
|
|
|
|
|
+ END), 2) AS avg_dispose_hours,
|
|
|
|
|
+ SUM(CASE
|
|
|
|
|
+ WHEN warning.status IN ('HANDLED', 'CLOSED', 'RESOLVED')
|
|
|
|
|
+ AND action.dispose_time >= warning.publish_time
|
|
|
|
|
+ AND EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600 > 24
|
|
|
|
|
+ THEN 1 ELSE 0 END) AS over_24h_count
|
|
|
|
|
+ FROM warning_industry warning
|
|
|
|
|
+ LEFT JOIN completed_actions action ON action.warning_id = warning.warning_id
|
|
|
|
|
+ GROUP BY warning.industry_code, warning.industry_name
|
|
|
|
|
+ ORDER BY CASE warning.industry_code
|
|
|
|
|
+ WHEN 'gas' THEN 1 WHEN 'water_supply' THEN 2
|
|
|
|
|
+ WHEN 'drainage' THEN 3 WHEN 'manhole' THEN 4 ELSE 5 END
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="selectIndustryStatusDistribution" resultType="java.util.Map">
|
|
|
|
|
+ <include refid="IndustryWarningCte"/>
|
|
|
|
|
+ <!-- CLOSED 与 RESOLVED 是历史上并存的两个“已解除”编码,分析时统一为 CLOSED。 -->
|
|
|
|
|
+ SELECT industry_code,
|
|
|
|
|
+ industry_name,
|
|
|
|
|
+ CASE WHEN status IN ('CLOSED', 'RESOLVED') THEN 'CLOSED' ELSE status END AS status,
|
|
|
|
|
+ COUNT(*) AS warning_count
|
|
|
|
|
+ FROM warning_industry
|
|
|
|
|
+ GROUP BY industry_code,
|
|
|
|
|
+ industry_name,
|
|
|
|
|
+ CASE WHEN status IN ('CLOSED', 'RESOLVED') THEN 'CLOSED' ELSE status END
|
|
|
|
|
+ ORDER BY industry_name,
|
|
|
|
|
+ CASE WHEN status IN ('CLOSED', 'RESOLVED') THEN 'CLOSED' ELSE status END
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="selectIndustryEfficiencyComparison" resultType="java.util.Map">
|
|
|
|
|
+ <include refid="IndustryWarningCte"/>
|
|
|
|
|
+ SELECT warning.industry_code,
|
|
|
|
|
+ warning.industry_name,
|
|
|
|
|
+ COUNT(*) AS completed_count,
|
|
|
|
|
+ ROUND(AVG(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS avg_dispose_hours,
|
|
|
|
|
+ ROUND(MAX(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS max_dispose_hours,
|
|
|
|
|
+ ROUND(MIN(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600), 2) AS min_dispose_hours,
|
|
|
|
|
+ ROUND(100.0 * SUM(CASE WHEN EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600 <= 24
|
|
|
|
|
+ THEN 1 ELSE 0 END) / NULLIF(COUNT(*), 0), 2) AS within_24h_rate
|
|
|
|
|
+ FROM warning_industry warning
|
|
|
|
|
+ INNER JOIN completed_actions action ON action.warning_id = warning.warning_id
|
|
|
|
|
+ WHERE warning.status IN ('HANDLED', 'CLOSED', 'RESOLVED')
|
|
|
|
|
+ AND action.dispose_time >= warning.publish_time
|
|
|
|
|
+ GROUP BY warning.industry_code, warning.industry_name
|
|
|
|
|
+ ORDER BY avg_dispose_hours DESC
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
|
|
+ <select id="selectIndustryAnalysisList" resultType="java.util.Map">
|
|
|
|
|
+ <include refid="IndustryWarningCte"/>
|
|
|
|
|
+ SELECT warning.warning_id,
|
|
|
|
|
+ warning.warning_no,
|
|
|
|
|
+ warning.warning_name,
|
|
|
|
|
+ warning.device_code,
|
|
|
|
|
+ warning.device_name,
|
|
|
|
|
+ warning.industry_code,
|
|
|
|
|
+ warning.industry_name,
|
|
|
|
|
+ warning.warning_level,
|
|
|
|
|
+ warning.publish_time,
|
|
|
|
|
+ warning.status,
|
|
|
|
|
+ action.dispose_time,
|
|
|
|
|
+ CASE WHEN action.dispose_time >= warning.publish_time
|
|
|
|
|
+ THEN ROUND(EXTRACT(EPOCH FROM (CAST(action.dispose_time AS TIMESTAMPTZ)
|
|
|
|
|
+ - CAST(warning.publish_time AS TIMESTAMPTZ))) / 3600, 2)
|
|
|
|
|
+ ELSE NULL END AS dispose_hours
|
|
|
|
|
+ FROM warning_industry warning
|
|
|
|
|
+ LEFT JOIN completed_actions action ON action.warning_id = warning.warning_id
|
|
|
|
|
+ <where>
|
|
|
|
|
+ <if test="status != null and status != ''">
|
|
|
|
|
+ <choose>
|
|
|
|
|
+ <!-- 页面只提供一个“已解除”筛选项,但兼容两种历史状态值。 -->
|
|
|
|
|
+ <when test="status == 'CLOSED' or status == 'RESOLVED'">
|
|
|
|
|
+ warning.status IN ('CLOSED', 'RESOLVED')
|
|
|
|
|
+ </when>
|
|
|
|
|
+ <otherwise>
|
|
|
|
|
+ warning.status = #{status}
|
|
|
|
|
+ </otherwise>
|
|
|
|
|
+ </choose>
|
|
|
|
|
+ </if>
|
|
|
|
|
+ </where>
|
|
|
|
|
+ ORDER BY dispose_hours
|
|
|
|
|
+ <if test="sortType != null and sortType == 'desc'">DESC</if>
|
|
|
|
|
+ <if test="sortType == null or sortType == 'asc'">ASC</if>
|
|
|
|
|
+ NULLS LAST, warning.publish_time DESC
|
|
|
|
|
+ </select>
|
|
|
|
|
+
|
|
|
</mapper>
|
|
</mapper>
|