Procházet zdrojové kódy

fix:应急bug修改

null před 3 týdny
rodič
revize
4f0d04e854

+ 19 - 0
src/api/dispatch.js

@@ -276,3 +276,22 @@ export function updateEventInfo(data) {
 export function deleteEventInfo(id) {
   return request({ url: '/api/dispatch/event/deleteById', method: 'delete', params: { id } })
 }
+
+// ============ 应急事件事后评估(总结评估) ============
+// 事件(已解除/已关闭) -> 四维评分 -> 生成报告/录入案例库
+// 查询单事件评估(无则返回 null)
+export function getEventAssess(eventId) {
+  return request({ url: '/api/dispatch/assess/findByEventId', method: 'get', params: { eventId } })
+}
+// 批量查询评估(列表标记已评估/待评估)
+export function listEventAssess(eventIds) {
+  return request({ url: '/api/dispatch/assess/listByEventIds', method: 'get', params: { eventIds: eventIds.join(',') } })
+}
+// 保存/更新评估(自动计算综合分与等级;仅传 eventId+caseFlag 表示录入案例库)
+export function saveEventAssess(data) {
+  return request({ url: '/api/dispatch/assess/save', method: 'post', data })
+}
+// 删除评估(重新评估)
+export function deleteEventAssess(eventId) {
+  return request({ url: '/api/dispatch/assess/delete', method: 'delete', params: { eventId } })
+}

+ 118 - 88
src/views/subSystem/dispatch/disAssess/DisSummary.vue

@@ -8,7 +8,7 @@
           <template #header>
             <div class="panel-title">应急事件列表</div>
           </template>
-          <div class="event-list">
+          <div class="event-list" v-if="events.length">
             <div
               v-for="event in events"
               :key="event.id"
@@ -22,12 +22,13 @@
               </div>
               <div class="event-meta">{{ event.location }}</div>
               <div class="event-status">
-                <el-tag v-if="event.evaluated" type="success" size="small">已评估</el-tag>
+                <el-tag v-if="evaluatedIds.has(event.id)" type="success" size="small">已评估</el-tag>
                 <el-tag v-else type="info" size="small">待评估</el-tag>
               </div>
             </div>
           </div>
-          <el-button type="primary" plain style="width: 100%; margin-top: 12px" @click="handleRefresh">刷新事件列表</el-button>
+          <el-empty v-else description="暂无已解除/已关闭事件" :image-size="80" />
+          <el-button type="primary" plain :loading="loading" style="width: 100%; margin-top: 12px" @click="handleRefresh">刷新事件列表</el-button>
         </el-card>
 
         <el-card shadow="hover" class="event-detail-card" v-if="currentEvent">
@@ -59,11 +60,11 @@
 
       <!-- 右侧评估面板 -->
       <div class="right-panel">
-        <el-card shadow="hover">
+        <el-card shadow="hover" v-if="currentEvent">
           <template #header>
             <div class="panel-title-row">
               <span class="panel-title">应急事件事后评估</span>
-              <el-tag v-if="currentEvent?.evaluated" type="success" effect="dark" size="large">已评估</el-tag>
+              <el-tag v-if="evaluatedIds.has(currentEvent.id)" type="success" effect="dark" size="large">已评估</el-tag>
               <el-tag v-else type="warning" effect="dark" size="large">未评估</el-tag>
             </div>
           </template>
@@ -111,50 +112,25 @@
             <el-button @click="resetEvaluation">重新评估</el-button>
           </div>
         </el-card>
+        <el-empty v-else description="暂无已解除/已关闭事件,请先完成事件处置后进行评估" />
       </div>
     </div>
   </div>
 </template>
 
 <script setup>
-import { ref, reactive, computed, watch } from 'vue'
+import { ref, reactive, computed, watch, onMounted } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
-
-// Mock 事件数据
-const events = ref([
-  {
-    id: 1, name: '化工园区氯气泄漏事故', time: '2025-05-15 08:30', location: '华东化工园区',
-    level: '重大', type: '事故灾难', desc: '储罐区氯气阀门失效导致泄漏,影响周边2km范围,已启动二级应急响应。',
-    evaluated: false, caseAdded: false,
-    assessments: { org: { score: 0, comment: '' }, cap: { score: 0, comment: '' }, effect: { score: 0, comment: '' }, loss: { score: 0, comment: '' } }
-  },
-  {
-    id: 2, name: '特大暴雨洪涝灾害', time: '2025-07-20 14:00', location: '华南沿海城市',
-    level: '特别重大', type: '自然灾害', desc: '连续强降雨引发城市内涝,受灾人口超10万,多处基础设施受损。',
-    evaluated: false, caseAdded: false,
-    assessments: { org: { score: 0, comment: '' }, cap: { score: 0, comment: '' }, effect: { score: 0, comment: '' }, loss: { score: 0, comment: '' } }
-  },
-  {
-    id: 3, name: '地铁施工坍塌事故', time: '2025-03-10 10:15', location: '城西地铁5号线',
-    level: '较大', type: '事故灾难', desc: '隧道施工段发生坍塌,3人被困,已组织现场救援。',
-    evaluated: false, caseAdded: false,
-    assessments: { org: { score: 0, comment: '' }, cap: { score: 0, comment: '' }, effect: { score: 0, comment: '' }, loss: { score: 0, comment: '' } }
-  },
-  {
-    id: 4, name: '太常片区供水管道爆裂', time: '2025-01-25 06:45', location: '太常片区主干道',
-    level: '重大', type: '管网泄漏', desc: 'DN800供水主管爆裂,影响周边3万居民用水,已紧急调度供水车。',
-    evaluated: true, caseAdded: true,
-    assessments: { org: { score: 4, comment: '组织架构较为清晰,指挥层级明确' }, cap: { score: 3.5, comment: '响应速度较快,但资源调配稍显滞后' }, effect: { score: 4, comment: '现场处置得当,各部门协同配合良好' }, loss: { score: 3, comment: '经济损失较大,但人员伤亡控制较好' } }
-  },
-  {
-    id: 5, name: '城南片区排水管网堵塞', time: '2025-04-08 16:30', location: '城南片区低洼路段',
-    level: '一般', type: '管道堵塞', desc: '排水管网严重堵塞导致路面积水,影响交通通行。',
-    evaluated: false, caseAdded: false,
-    assessments: { org: { score: 0, comment: '' }, cap: { score: 0, comment: '' }, effect: { score: 0, comment: '' }, loss: { score: 0, comment: '' } }
-  }
-])
-
-const currentEventId = ref(1)
+import { getEventPage, getEventAssess, listEventAssess, saveEventAssess, deleteEventAssess } from '@/api/dispatch'
+
+// 已解除/已关闭事件列表(可评估)
+const events = ref([])
+const loading = ref(false)
+const currentEventId = ref(null)
+// 已评估事件 id 集合
+const evaluatedIds = ref(new Set())
+// 当前事件评估记录(含案例库标记)
+const currentAssess = ref(null)
 const assessments = reactive({
   org: { score: 0, comment: '' },
   cap: { score: 0, comment: '' },
@@ -164,26 +140,62 @@ const assessments = reactive({
 
 // 当前选中事件
 const currentEvent = computed(() => {
-  return events.value.find(e => e.id === currentEventId.value) || events.value[0]
+  return events.value.find(e => e.id === currentEventId.value) || null
 })
 
-// 加载评估数据到表单
-const loadAssessmentsToForm = () => {
+// 清空评估表单
+const resetAssessments = () => {
+  assessments.org.score = 0; assessments.org.comment = ''
+  assessments.cap.score = 0; assessments.cap.comment = ''
+  assessments.effect.score = 0; assessments.effect.comment = ''
+  assessments.loss.score = 0; assessments.loss.comment = ''
+}
+
+// 加载评估数据到表单(查询后端评估记录回显)
+const loadAssessmentsToForm = async () => {
+  resetAssessments()
   const event = currentEvent.value
-  if (event && event.evaluated && event.assessments) {
-    assessments.org.score = event.assessments.org.score
-    assessments.org.comment = event.assessments.org.comment
-    assessments.cap.score = event.assessments.cap.score
-    assessments.cap.comment = event.assessments.cap.comment
-    assessments.effect.score = event.assessments.effect.score
-    assessments.effect.comment = event.assessments.effect.comment
-    assessments.loss.score = event.assessments.loss.score
-    assessments.loss.comment = event.assessments.loss.comment
-  } else {
-    assessments.org.score = 0; assessments.org.comment = ''
-    assessments.cap.score = 0; assessments.cap.comment = ''
-    assessments.effect.score = 0; assessments.effect.comment = ''
-    assessments.loss.score = 0; assessments.loss.comment = ''
+  currentAssess.value = null
+  if (!event) return
+  try {
+    const res = await getEventAssess(event.id)
+    currentAssess.value = res.data || null
+    if (currentAssess.value) {
+      assessments.org.score = Number(currentAssess.value.orgScore) || 0
+      assessments.org.comment = currentAssess.value.orgComment || ''
+      assessments.cap.score = Number(currentAssess.value.capScore) || 0
+      assessments.cap.comment = currentAssess.value.capComment || ''
+      assessments.effect.score = Number(currentAssess.value.effectScore) || 0
+      assessments.effect.comment = currentAssess.value.effectComment || ''
+      assessments.loss.score = Number(currentAssess.value.lossScore) || 0
+      assessments.loss.comment = currentAssess.value.lossComment || ''
+    }
+  } catch (e) {
+    currentAssess.value = null
+  }
+}
+
+// 加载事件列表(已解除/已关闭)并批量标记已评估
+const loadEvents = async () => {
+  loading.value = true
+  try {
+    const res = await getEventPage(1, 200, { statusList: ['已解除', '已关闭'] })
+    const rows = res.data?.records || res.data?.rows || res.records || res.rows || []
+    events.value = (rows || []).map(e => ({
+      id: e.id, name: e.eventName, time: e.happenTime, location: e.location,
+      level: e.level, type: e.eventType, desc: e.description
+    }))
+    evaluatedIds.value = new Set()
+    if (events.value.length) {
+      const ass = await listEventAssess(events.value.map(e => e.id))
+      evaluatedIds.value = new Set((ass.data || []).map(a => a.relEventId))
+    }
+    if (!currentEventId.value || !events.value.some(e => e.id === currentEventId.value)) {
+      currentEventId.value = events.value.length ? events.value[0].id : null
+    }
+    await loadAssessmentsToForm()
+  } finally {
+    loading.value = false
   }
 }
 
@@ -199,9 +211,10 @@ const levelTagType = (level) => {
   return map[level] || 'info'
 }
 
-// 生成评估报告
-const generateReport = () => {
+// 生成评估报告(保存评估到后端 + 下载报告)
+const generateReport = async () => {
   const event = currentEvent.value
+  if (!event) return
   const scores = {
     org: assessments.org.score,
     cap: assessments.cap.score,
@@ -246,13 +259,21 @@ const generateReport = () => {
 报告生成时间: ${new Date().toLocaleString()}
   `.trim()
 
-  // 保存到事件对象
-  event.evaluated = true
-  event.assessments = {
-    org: { score: scores.org, comment: assessments.org.comment },
-    cap: { score: scores.cap, comment: assessments.cap.comment },
-    effect: { score: scores.effect, comment: assessments.effect.comment },
-    loss: { score: scores.loss, comment: assessments.loss.comment }
+  // 保存评估到后端(自动计算综合分与等级)
+  try {
+    await saveEventAssess({
+      eventId: event.id,
+      orgScore: scores.org, orgComment: assessments.org.comment,
+      capScore: scores.cap, capComment: assessments.cap.comment,
+      effectScore: scores.effect, effectComment: assessments.effect.comment,
+      lossScore: scores.loss, lossComment: assessments.loss.comment,
+      caseFlag: currentAssess.value?.caseFlag || '0'
+    })
+    evaluatedIds.value.add(event.id)
+    currentAssess.value = { ...(currentAssess.value || {}), caseFlag: currentAssess.value?.caseFlag || '0' }
+  } catch (e) {
+    ElMessage.error('评估保存失败,请重试')
+    return
   }
 
   // 生成下载
@@ -264,51 +285,60 @@ const generateReport = () => {
   link.click()
   URL.revokeObjectURL(url)
 
-  ElMessage.success('评估报告已生成并下载')
+  ElMessage.success('评估已保存,报告已生成并下载')
 }
 
 // 录入案例库
-const saveToCaseLibrary = () => {
+const saveToCaseLibrary = async () => {
   const event = currentEvent.value
-  if (!event.evaluated) {
+  if (!event) return
+  if (!evaluatedIds.value.has(event.id)) {
     ElMessage.warning('请先生成评估报告后再录入案例库')
     return
   }
-  if (event.caseAdded) {
+  if (currentAssess.value?.caseFlag === '1') {
     ElMessage.warning('该事件已录入案例库,不可重复录入')
     return
   }
-  event.caseAdded = true
-  ElMessage.success('已成功录入案例库')
+  try {
+    await saveEventAssess({ eventId: event.id, caseFlag: '1' })
+    if (currentAssess.value) currentAssess.value.caseFlag = '1'
+    ElMessage.success('已成功录入案例库')
+  } catch (e) {
+    ElMessage.error('录入失败,请重试')
+  }
 }
 
-// 重新评估
+// 重新评估(删除后端评估记录并清空表单)
 const resetEvaluation = () => {
-  ElMessageBox.confirm('确认重新评估?所有评分和评语将被清空。', '提示', {
+  const event = currentEvent.value
+  if (!event) return
+  ElMessageBox.confirm('确认重新评估?当前评估记录将被删除,所有评分和评语将被清空。', '提示', {
     confirmButtonText: '确定',
     cancelButtonText: '取消',
     type: 'warning'
-  }).then(() => {
-    assessments.org.score = 0; assessments.org.comment = ''
-    assessments.cap.score = 0; assessments.cap.comment = ''
-    assessments.effect.score = 0; assessments.effect.comment = ''
-    assessments.loss.score = 0; assessments.loss.comment = ''
-    const event = currentEvent.value
-    if (event.evaluated) {
-      event.evaluated = false
-      event.caseAdded = false
+  }).then(async () => {
+    try {
+      await deleteEventAssess(event.id)
+      evaluatedIds.value.delete(event.id)
+      currentAssess.value = null
+      resetAssessments()
+      ElMessage.info('评估已重置')
+    } catch (e) {
+      ElMessage.error('重置失败,请重试')
     }
-    ElMessage.info('评估已重置')
   }).catch(() => {})
 }
 
 // 刷新事件列表
 const handleRefresh = () => {
-  ElMessage.success('事件列表已刷新')
+  loadEvents()
 }
 
 // 初始化加载
-loadAssessmentsToForm()
+onMounted(() => {
+  loadEvents()
+})
 
 // 监听事件切换
 watch(currentEventId, () => {

+ 0 - 1
src/views/subSystem/dispatch/disExerciseMan/DisPracticalDrill.vue

@@ -5,7 +5,6 @@
     <div class="drill-top-bar">
       <div class="top-left">
         <h2 class="page-title"><el-icon><TrendCharts /></el-icon>实战演练管理</h2>
-        <el-tag type="warning" size="large">5.2.3.3.4 实战演练管理</el-tag>
       </div>
       <div class="top-right">
         <el-button type="primary" size="large" @click="handleCreatePlan">