Kaynağa Gözat

应急与管理系统前端静态页面

LAPTOP-JI2IUVG1\26646 1 ay önce
ebeveyn
işleme
16222d87d3

+ 386 - 0
src/views/subSystem/dispatch/disOnDuty/cphs.vue

@@ -0,0 +1,386 @@
+<template>
+  <div class="app-container cphs-page">
+    <!-- 搜索区 -->
+    <div class="filter-panel">
+      <div class="filter-form">
+        <el-select v-model="filters.category" placeholder="事件类别" clearable style="width:160px">
+          <el-option label="管道泄漏" value="管道泄漏" />
+          <el-option label="塌陷" value="塌陷" />
+          <el-option label="积水" value="积水" />
+          <el-option label="设备故障" value="设备故障" />
+        </el-select>
+        <el-select v-model="filters.level" placeholder="事件等级" clearable style="width:140px">
+          <el-option label="一般" value="一般" />
+          <el-option label="较大" value="较大" />
+          <el-option label="重大" value="重大" />
+          <el-option label="特别重大" value="特别重大" />
+        </el-select>
+        <el-select v-model="filters.verifyStatus" placeholder="核实状态" clearable style="width:140px">
+          <el-option label="待核实" value="待核实" />
+          <el-option label="已核实" value="已核实" />
+          <el-option label="不实事件" value="不实事件" />
+        </el-select>
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </div>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-panel">
+      <el-table :data="pagedList" border stripe style="width:100%">
+        <el-table-column prop="eventNo" label="事件编号" width="140" />
+        <el-table-column prop="category" label="事件类别" width="110" />
+        <el-table-column prop="level" label="事件等级" width="100">
+          <template #default="{ row }">
+            <el-tag :type="levelTagType(row.level)" size="small">{{ row.level }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="location" label="发生地点" show-overflow-tooltip />
+        <el-table-column prop="judgeTime" label="初判时间" width="150" />
+        <el-table-column prop="verifier" label="核实人" width="100" />
+        <el-table-column prop="status" label="状态" width="100">
+          <template #default="{ row }">
+            <el-tag :type="statusTagType(row.status)" size="small">{{ row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="160" fixed="right">
+          <template #default="{ row }">
+            <el-button v-if="row.status === '待核实'" type="primary" link size="small" @click="handleVerify(row)">核实</el-button>
+            <el-button type="primary" link size="small" @click="handleDetail(row)">详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pagination.page"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+
+    <!-- GIS 占位区 -->
+    <div class="gis-panel">
+      <div class="gis-placeholder">事件坐标 GIS 展示区</div>
+    </div>
+
+    <!-- 核实弹窗 -->
+    <el-dialog v-model="verifyVisible" title="事件核实" width="600px" :close-on-click-modal="false">
+      <el-form :model="verifyForm" :rules="verifyRules" ref="verifyFormRef" label-width="100px">
+        <div class="section-title">事件基本信息</div>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="事件编号">{{ verifyForm.eventNo }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="发生地点">{{ verifyForm.location }}</el-form-item>
+          </el-col>
+        </el-row>
+        <el-form-item label="事件描述">
+          <div class="desc-text">{{ verifyForm.description }}</div>
+        </el-form-item>
+        <div class="section-title">核实信息</div>
+        <el-form-item label="事件类别" prop="category">
+          <el-select v-model="verifyForm.category" placeholder="请选择" style="width:100%">
+            <el-option label="管道泄漏" value="管道泄漏" />
+            <el-option label="塌陷" value="塌陷" />
+            <el-option label="积水" value="积水" />
+            <el-option label="设备故障" value="设备故障" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="事件等级" prop="level">
+          <el-select v-model="verifyForm.level" placeholder="请选择" style="width:100%">
+            <el-option label="一般" value="一般" />
+            <el-option label="较大" value="较大" />
+            <el-option label="重大" value="重大" />
+            <el-option label="特别重大" value="特别重大" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="核实意见" prop="opinion">
+          <el-input v-model="verifyForm.opinion" type="textarea" :rows="3" placeholder="请输入核实意见" />
+        </el-form-item>
+        <el-form-item label="是否真实" prop="isReal">
+          <el-radio-group v-model="verifyForm.isReal">
+            <el-radio label="真实">真实</el-radio>
+            <el-radio label="不实">不实</el-radio>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="verifyVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmVerify">确认核实</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 详情弹窗 -->
+    <el-dialog v-model="detailVisible" title="事件详情" width="600px" :close-on-click-modal="false">
+      <div v-if="currentRow" class="detail-content">
+        <el-form label-width="100px" size="default">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件编号">{{ currentRow.eventNo }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="事件标识">{{ currentRow.eventId || '未生成' }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件类别">{{ currentRow.category }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="事件等级">{{ currentRow.level }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="发生地点">{{ currentRow.location }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="初判时间">{{ currentRow.judgeTime }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item label="事件描述">
+            <div class="desc-text">{{ currentRow.description }}</div>
+          </el-form-item>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="核实人">{{ currentRow.verifier || '-' }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="核实时间">{{ currentRow.verifyTime || '-' }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item label="核实意见">
+            <div class="desc-text">{{ currentRow.opinion || '-' }}</div>
+          </el-form-item>
+          <el-form-item label="状态">
+            <el-tag :type="statusTagType(currentRow.status)" size="small">{{ currentRow.status }}</el-tag>
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="detailVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Cphs">
+import { ref, computed } from 'vue'
+
+// ==================== mock 数据 ====================
+const eventList = ref([
+  { eventNo: 'JB20250613001', category: '塌陷', level: '较大', location: '人民路与建设路交叉口', judgeTime: '2025-06-13 08:35:00', description: '路面出现明显塌陷,面积约2平方米', verifier: '', verifyTime: '', opinion: '', status: '待核实', eventId: '' },
+  { eventNo: 'JB20250613002', category: '设备故障', level: '一般', location: '幸福路123号门前', judgeTime: '2025-06-13 09:15:00', description: '市民反映排水井盖缺失,存在安全隐患', verifier: '', verifyTime: '', opinion: '', status: '待核实', eventId: '' },
+  { eventNo: 'JB20250613003', category: '积水', level: '一般', location: '科技大道中段', judgeTime: '2025-06-13 07:55:00', description: '视频监控发现路面积水严重,影响通行', verifier: '张三', verifyTime: '2025-06-13 08:10:00', opinion: '经核实,积水深度约10cm,因降雨导致', status: '已核实', eventId: 'EVT20250613003' },
+  { eventNo: 'JB20250613004', category: '管道泄漏', level: '重大', location: '和平路步行街', judgeTime: '2025-06-12 16:30:00', description: '市应急办转发:步行街燃气管道疑似泄漏', verifier: '李四', verifyTime: '2025-06-12 17:00:00', opinion: '已现场确认,燃气管道微泄漏,已采取临时措施', status: '已核实', eventId: 'EVT20250613004' },
+  { eventNo: 'JB20250613005', category: '管道泄漏', level: '一般', location: '长江路北侧辅道', judgeTime: '2025-06-13 10:05:00', description: '供水管道破裂,水涌至路面', verifier: '王五', verifyTime: '2025-06-13 10:30:00', opinion: '现场查看后未发现管道破裂,系消防栓放水', status: '不实事件', eventId: '' },
+  { eventNo: 'JB20250613006', category: '积水', level: '较大', location: '黄河路56号小区', judgeTime: '2025-06-13 11:25:00', description: '居民反映小区内污水外溢,气味刺鼻', verifier: '', verifyTime: '', opinion: '', status: '待核实', eventId: '' },
+  { eventNo: 'JB20250613007', category: '积水', level: '一般', location: '太湖路与松江路交叉口', judgeTime: '2025-06-13 06:45:00', description: '早高峰时段路口积水深度约15cm', verifier: '赵六', verifyTime: '2025-06-13 07:00:00', opinion: '积水属实,因排水口堵塞导致', status: '已核实', eventId: 'EVT20250613007' },
+  { eventNo: 'JB20250613008', category: '设备故障', level: '较大', location: '珠江路工业园A区', judgeTime: '2025-06-12 20:30:00', description: '省厅转发:园区内消防设施压力异常', verifier: '', verifyTime: '', opinion: '', status: '待核实', eventId: '' },
+  { eventNo: 'JB20250613009', category: '塌陷', level: '一般', location: '中山路与解放路交叉口', judgeTime: '2025-06-13 13:05:00', description: '路灯杆倾斜,存在倒塌风险', verifier: '', verifyTime: '', opinion: '', status: '待核实', eventId: '' },
+  { eventNo: 'JB20250613010', category: '设备故障', level: '一般', location: '新华路88号大厦', judgeTime: '2025-06-13 14:35:00', description: '大厦物业反映地下室排水泵故障', verifier: '孙七', verifyTime: '2025-06-13 15:00:00', opinion: '排水泵电机烧毁,需更换', status: '已核实', eventId: 'EVT20250613010' }
+])
+
+// ==================== 搜索筛选 ====================
+const filters = ref({ category: '', level: '', verifyStatus: '' })
+
+const filteredList = computed(() => {
+  let list = eventList.value
+  if (filters.value.category) {
+    list = list.filter(o => o.category === filters.value.category)
+  }
+  if (filters.value.level) {
+    list = list.filter(o => o.level === filters.value.level)
+  }
+  if (filters.value.verifyStatus) {
+    list = list.filter(o => o.status === filters.value.verifyStatus)
+  }
+  return list
+})
+
+function handleSearch() {
+  pagination.value.page = 1
+}
+
+function handleReset() {
+  filters.value = { category: '', level: '', verifyStatus: '' }
+  pagination.value.page = 1
+}
+
+// ==================== 分页 ====================
+const pagination = ref({ page: 1, pageSize: 10 })
+
+const pagedList = computed(() => {
+  const start = (pagination.value.page - 1) * pagination.value.pageSize
+  return filteredList.value.slice(start, start + pagination.value.pageSize)
+})
+
+function handleSizeChange(val) {
+  pagination.value.pageSize = val
+  pagination.value.page = 1
+}
+
+function handleCurrentChange(val) {
+  pagination.value.page = val
+}
+
+// ==================== 标签样式 ====================
+function statusTagType(status) {
+  if (status === '待核实') return 'warning'
+  if (status === '已核实') return 'success'
+  if (status === '不实事件') return 'info'
+  return 'info'
+}
+
+function levelTagType(level) {
+  if (level === '特别重大') return 'danger'
+  if (level === '重大') return 'danger'
+  if (level === '较大') return 'warning'
+  return 'info'
+}
+
+// ==================== 核实 ====================
+const verifyVisible = ref(false)
+const verifyFormRef = ref(null)
+const verifyForm = ref({ eventNo: '', location: '', description: '', category: '', level: '', opinion: '', isReal: '真实' })
+const verifyRules = {
+  category: [{ required: true, message: '请选择事件类别', trigger: 'change' }],
+  level: [{ required: true, message: '请选择事件等级', trigger: 'change' }],
+  opinion: [{ required: true, message: '请输入核实意见', trigger: 'blur' }],
+  isReal: [{ required: true, message: '请选择是否真实', trigger: 'change' }]
+}
+
+function handleVerify(row) {
+  verifyForm.value = { eventNo: row.eventNo, location: row.location, description: row.description, category: row.category, level: row.level, opinion: '', isReal: '真实' }
+  verifyVisible.value = true
+}
+
+function confirmVerify() {
+  verifyFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === verifyForm.value.eventNo)
+    if (idx > -1) {
+      eventList.value[idx].category = verifyForm.value.category
+      eventList.value[idx].level = verifyForm.value.level
+      eventList.value[idx].opinion = verifyForm.value.opinion
+      eventList.value[idx].verifier = '当前用户'
+      eventList.value[idx].verifyTime = new Date().toLocaleString()
+      if (verifyForm.value.isReal === '真实') {
+        eventList.value[idx].status = '已核实'
+        eventList.value[idx].eventId = 'EVT' + eventList.value[idx].eventNo.replace('JB', '')
+      } else {
+        eventList.value[idx].status = '不实事件'
+      }
+    }
+    verifyVisible.value = false
+  })
+}
+
+// ==================== 详情 ====================
+const detailVisible = ref(false)
+const currentRow = ref(null)
+
+function handleDetail(row) {
+  currentRow.value = row
+  detailVisible.value = true
+}
+</script>
+
+<style scoped>
+.cphs-page {
+  padding: 16px;
+  background: #f5f5f5;
+  min-height: calc(100vh - 84px);
+}
+
+.filter-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 12px 16px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 12px;
+}
+
+.filter-form {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.table-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+  margin-bottom: 12px;
+}
+
+.pagination-wrap {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.gis-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+}
+
+.gis-placeholder {
+  height: 240px;
+  background: #f5f7fa;
+  border: 1px dashed #c0c4cc;
+  border-radius: 4px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #909399;
+  font-size: 16px;
+}
+
+.detail-content {
+  padding: 0 8px;
+}
+
+.section-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-left: 8px;
+  border-left: 3px solid #409EFF;
+}
+
+.desc-text {
+  background: #f5f7fa;
+  border-radius: 4px;
+  padding: 10px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.6;
+  max-height: 120px;
+  overflow-y: auto;
+}
+
+:deep(.el-form-item__label) {
+  color: #909399;
+}
+
+:deep(.el-form-item__content) {
+  color: #303133;
+}
+</style>

+ 305 - 0
src/views/subSystem/dispatch/disOnDuty/gzcb.vue

@@ -0,0 +1,305 @@
+<template>
+  <div class="app-container gzcb-page">
+    <!-- 搜索区 -->
+    <div class="filter-panel">
+      <div class="filter-form">
+        <el-select v-model="filters.urgeStatus" placeholder="催办状态" clearable style="width:140px">
+          <el-option label="待催办" value="待催办" />
+          <el-option label="催办中" value="催办中" />
+          <el-option label="已完成" value="已完成" />
+        </el-select>
+        <el-input v-model="filters.receiver" placeholder="目标接收人" clearable style="width:140px" />
+        <el-input v-model="filters.eventNo" placeholder="事件编号" clearable style="width:160px" />
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </div>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-panel">
+      <el-table :data="pagedList" border stripe style="width:100%">
+        <el-table-column prop="eventNo" label="事件编号" width="140" />
+        <el-table-column prop="summary" label="事件摘要" show-overflow-tooltip />
+        <el-table-column prop="receiver" label="目标接收人" width="110" />
+        <el-table-column prop="receiverDept" label="接收部门" width="120" />
+        <el-table-column prop="urgeCount" label="催办次数" width="90" />
+        <el-table-column prop="lastUrgeTime" label="最近催办时间" width="150" />
+        <el-table-column prop="status" label="状态" width="100">
+          <template #default="{ row }">
+            <el-tag :type="statusTagType(row.status)" size="small">{{ row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="180" fixed="right">
+          <template #default="{ row }">
+            <el-button v-if="row.status !== '已完成'" type="primary" link size="small" @click="handleUrge(row)">催办</el-button>
+            <el-button type="primary" link size="small" @click="handleViewRecords(row)">查看记录</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pagination.page"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+
+    <!-- 催办弹窗 -->
+    <el-dialog v-model="urgeVisible" title="工作催办" width="600px" :close-on-click-modal="false">
+      <el-form :model="urgeForm" :rules="urgeRules" ref="urgeFormRef" label-width="100px">
+        <div class="section-title">事件信息</div>
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="事件编号">{{ urgeForm.eventNo }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="事件摘要">{{ urgeForm.summary }}</el-form-item>
+          </el-col>
+        </el-row>
+        <div class="section-title">接收人信息</div>
+        <el-row :gutter="20">
+          <el-col :span="8">
+            <el-form-item label="姓名">{{ urgeForm.receiver }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="部门">{{ urgeForm.receiverDept }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="电话">{{ urgeForm.receiverPhone }}</el-form-item>
+          </el-col>
+        </el-row>
+        <div class="section-title">催办内容</div>
+        <el-form-item label="催办方式" prop="methods">
+          <el-checkbox-group v-model="urgeForm.methods">
+            <el-checkbox label="电话" />
+            <el-checkbox label="短信" />
+            <el-checkbox label="系统消息" />
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="催办内容" prop="content">
+          <el-input v-model="urgeForm.content" type="textarea" :rows="4" placeholder="请输入催办内容" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="urgeVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmUrge">发送催办</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 查看记录弹窗 -->
+    <el-dialog v-model="recordsVisible" title="催办记录" width="700px" :close-on-click-modal="false">
+      <div v-if="currentRow">
+        <p style="margin-bottom:12px;font-weight:600">事件编号:{{ currentRow.eventNo }} | 事件摘要:{{ currentRow.summary }}</p>
+        <el-table :data="currentRow.records" border stripe style="width:100%">
+          <el-table-column prop="time" label="催办时间" width="160" />
+          <el-table-column prop="method" label="催办方式" width="120" />
+          <el-table-column prop="content" label="催办内容" show-overflow-tooltip />
+          <el-table-column prop="result" label="结果" width="100">
+            <template #default="{ row }">
+              <el-tag :type="row.result === '已反馈' ? 'success' : 'info'" size="small">{{ row.result }}</el-tag>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <template #footer>
+        <el-button @click="recordsVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Gzcb">
+import { ref, computed } from 'vue'
+
+// ==================== mock 数据 ====================
+const eventList = ref([
+  { eventNo: 'EVT20250613003', summary: '科技大道中段路面积水严重', receiver: '张三', receiverDept: '排水管理部', receiverPhone: '13800138001', urgeCount: 0, lastUrgeTime: '-', status: '待催办', records: [] },
+  { eventNo: 'EVT20250613004', summary: '和平路步行街燃气管道疑似泄漏', receiver: '李四', receiverDept: '市政部门', receiverPhone: '13900139002', urgeCount: 2, lastUrgeTime: '2025-06-13 09:00:00', status: '催办中', records: [
+    { time: '2025-06-12 18:00:00', method: '电话', content: '请尽快安排人员到现场处置燃气泄漏事件', result: '已反馈' },
+    { time: '2025-06-13 09:00:00', method: '系统消息', content: '燃气泄漏事件处置进度提醒', result: '未反馈' }
+  ] },
+  { eventNo: 'EVT20250613007', summary: '太湖路与松江路交叉口积水', receiver: '王五', receiverDept: '排水管理部', receiverPhone: '13700137003', urgeCount: 1, lastUrgeTime: '2025-06-13 08:30:00', status: '催办中', records: [
+    { time: '2025-06-13 08:30:00', method: '短信', content: '积水事件请尽快疏通排水口', result: '已反馈' }
+  ] },
+  { eventNo: 'EVT20250613010', summary: '新华路88号大厦地下室排水泵故障', receiver: '赵六', receiverDept: '设备运维部', receiverPhone: '13600136004', urgeCount: 0, lastUrgeTime: '-', status: '待催办', records: [] },
+  { eventNo: 'EVT20250613011', summary: '人民路与建设路交叉口路面塌陷', receiver: '孙七', receiverDept: '管网维护部', receiverPhone: '13500135005', urgeCount: 3, lastUrgeTime: '2025-06-13 14:00:00', status: '催办中', records: [
+    { time: '2025-06-13 10:00:00', method: '电话', content: '塌陷区域请尽快设置围挡', result: '已反馈' },
+    { time: '2025-06-13 12:00:00', method: '系统消息', content: '塌陷修复进度跟进', result: '未反馈' },
+    { time: '2025-06-13 14:00:00', method: '短信', content: '请反馈塌陷修复预计完成时间', result: '未反馈' }
+  ] },
+  { eventNo: 'EVT20250613012', summary: '珠江路工业园A区消防设施压力异常', receiver: '周八', receiverDept: '设备运维部', receiverPhone: '13400134006', urgeCount: 0, lastUrgeTime: '-', status: '待催办', records: [] },
+  { eventNo: 'EVT20250613013', summary: '黄河路56号小区污水外溢', receiver: '吴九', receiverDept: '排水管理部', receiverPhone: '13300133007', urgeCount: 1, lastUrgeTime: '2025-06-13 13:00:00', status: '催办中', records: [
+    { time: '2025-06-13 13:00:00', method: '电话', content: '污水外溢影响居民生活,请尽快处理', result: '已反馈' }
+  ] },
+  { eventNo: 'EVT20250613014', summary: '中山路与解放路交叉口路灯杆倾斜', receiver: '郑十', receiverDept: '管网维护部', receiverPhone: '13200132008', urgeCount: 0, lastUrgeTime: '-', status: '待催办', records: [] },
+  { eventNo: 'EVT20250613015', summary: '长江路北侧供水管道破裂', receiver: '刘一', receiverDept: '市政部门', receiverPhone: '13100131009', urgeCount: 2, lastUrgeTime: '2025-06-13 12:00:00', status: '已完成', records: [
+    { time: '2025-06-13 11:00:00', method: '系统消息', content: '供水管道破裂请尽快止水维修', result: '已反馈' },
+    { time: '2025-06-13 12:00:00', method: '电话', content: '维修进度确认', result: '已反馈' }
+  ] },
+  { eventNo: 'EVT20250613016', summary: '幸福路排水井盖缺失', receiver: '陈二', receiverDept: '排水管理部', receiverPhone: '13000130010', urgeCount: 0, lastUrgeTime: '-', status: '待催办', records: [] }
+])
+
+// ==================== 搜索筛选 ====================
+const filters = ref({ urgeStatus: '', receiver: '', eventNo: '' })
+
+const filteredList = computed(() => {
+  let list = eventList.value
+  if (filters.value.urgeStatus) {
+    list = list.filter(o => o.status === filters.value.urgeStatus)
+  }
+  if (filters.value.receiver) {
+    list = list.filter(o => o.receiver.includes(filters.value.receiver))
+  }
+  if (filters.value.eventNo) {
+    list = list.filter(o => o.eventNo.includes(filters.value.eventNo))
+  }
+  return list
+})
+
+function handleSearch() {
+  pagination.value.page = 1
+}
+
+function handleReset() {
+  filters.value = { urgeStatus: '', receiver: '', eventNo: '' }
+  pagination.value.page = 1
+}
+
+// ==================== 分页 ====================
+const pagination = ref({ page: 1, pageSize: 10 })
+
+const pagedList = computed(() => {
+  const start = (pagination.value.page - 1) * pagination.value.pageSize
+  return filteredList.value.slice(start, start + pagination.value.pageSize)
+})
+
+function handleSizeChange(val) {
+  pagination.value.pageSize = val
+  pagination.value.page = 1
+}
+
+function handleCurrentChange(val) {
+  pagination.value.page = val
+}
+
+// ==================== 标签样式 ====================
+function statusTagType(status) {
+  if (status === '待催办') return 'warning'
+  if (status === '催办中') return 'primary'
+  if (status === '已完成') return 'success'
+  return 'info'
+}
+
+// ==================== 催办 ====================
+const urgeVisible = ref(false)
+const urgeFormRef = ref(null)
+const urgeForm = ref({ eventNo: '', summary: '', receiver: '', receiverDept: '', receiverPhone: '', methods: [], content: '' })
+const urgeRules = {
+  methods: [{ required: true, message: '请选择催办方式', trigger: 'change', type: 'array' }],
+  content: [{ required: true, message: '请输入催办内容', trigger: 'blur' }]
+}
+
+function handleUrge(row) {
+  urgeForm.value = {
+    eventNo: row.eventNo,
+    summary: row.summary,
+    receiver: row.receiver,
+    receiverDept: row.receiverDept,
+    receiverPhone: row.receiverPhone,
+    methods: [],
+    content: '关于【' + row.summary + '】的处置进度,请尽快反馈处理情况。'
+  }
+  urgeVisible.value = true
+}
+
+function confirmUrge() {
+  urgeFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === urgeForm.value.eventNo)
+    if (idx > -1) {
+      eventList.value[idx].urgeCount += 1
+      eventList.value[idx].lastUrgeTime = new Date().toLocaleString()
+      eventList.value[idx].status = '催办中'
+      eventList.value[idx].records.push({
+        time: new Date().toLocaleString(),
+        method: urgeForm.value.methods.join('、'),
+        content: urgeForm.value.content,
+        result: '未反馈'
+      })
+    }
+    urgeVisible.value = false
+  })
+}
+
+// ==================== 查看记录 ====================
+const recordsVisible = ref(false)
+const currentRow = ref(null)
+
+function handleViewRecords(row) {
+  currentRow.value = row
+  recordsVisible.value = true
+}
+</script>
+
+<style scoped>
+.gzcb-page {
+  padding: 16px;
+  background: #f5f5f5;
+  min-height: calc(100vh - 84px);
+}
+
+.filter-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 12px 16px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 12px;
+}
+
+.filter-form {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.table-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+}
+
+.pagination-wrap {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.section-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-left: 8px;
+  border-left: 3px solid #409EFF;
+}
+
+:deep(.el-form-item__label) {
+  color: #909399;
+}
+
+:deep(.el-form-item__content) {
+  color: #303133;
+}
+</style>

+ 488 - 0
src/views/subSystem/dispatch/disOnDuty/gzjc.vue

@@ -0,0 +1,488 @@
+<template>
+  <div class="app-container gzjc-page">
+    <!-- 搜索区 -->
+    <div class="filter-panel">
+      <div class="filter-form">
+        <el-select v-model="filters.eventStatus" placeholder="事件状态" clearable style="width:140px">
+          <el-option label="处理中" value="处理中" />
+          <el-option label="已解除" value="已解除" />
+          <el-option label="已关闭" value="已关闭" />
+        </el-select>
+        <el-select v-model="filters.category" placeholder="事件类别" clearable style="width:140px">
+          <el-option label="管道泄漏" value="管道泄漏" />
+          <el-option label="塌陷" value="塌陷" />
+          <el-option label="积水" value="积水" />
+          <el-option label="设备故障" value="设备故障" />
+        </el-select>
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          style="width:260px"
+          value-format="YYYY-MM-DD"
+        />
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </div>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-panel">
+      <el-table :data="pagedList" border stripe style="width:100%">
+        <el-table-column prop="eventNo" label="事件编号" width="140" />
+        <el-table-column prop="category" label="事件类别" width="110" />
+        <el-table-column prop="level" label="事件等级" width="100">
+          <template #default="{ row }">
+            <el-tag :type="levelTagType(row.level)" size="small">{{ row.level }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="当前状态" width="100">
+          <template #default="{ row }">
+            <el-tag :type="statusTagType(row.status)" size="small">{{ row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="lastVisitTime" label="最近回访时间" width="150" />
+        <el-table-column prop="nextVisitTime" label="下次回访时间" width="150" />
+        <el-table-column prop="handler" label="负责人" width="100" />
+        <el-table-column label="操作" width="220" fixed="right">
+          <template #default="{ row }">
+            <el-button v-if="row.status === '处理中'" type="primary" link size="small" @click="handleTrack(row)">跟踪</el-button>
+            <el-button v-if="row.status === '处理中'" type="primary" link size="small" @click="handleClose(row)">解除</el-button>
+            <el-button v-if="row.status === '已解除'" type="primary" link size="small" @click="handleClose(row)">关闭</el-button>
+            <el-button type="primary" link size="small" @click="handleDetail(row)">详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pagination.page"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+
+    <!-- 跟踪弹窗 -->
+    <el-dialog v-model="trackVisible" title="事件跟踪" width="700px" :close-on-click-modal="false">
+      <div v-if="currentRow">
+        <div class="section-title">事件进展时间线</div>
+        <el-timeline>
+          <el-timeline-item
+            v-for="(item, index) in currentRow.timeline"
+            :key="index"
+            :type="item.type"
+            :timestamp="item.time"
+          >
+            <div style="font-weight:600">{{ item.title }}</div>
+            <div style="color:#606266;font-size:13px">{{ item.content }}</div>
+          </el-timeline-item>
+        </el-timeline>
+
+        <div class="section-title">新增跟踪记录</div>
+        <el-form :model="trackForm" :rules="trackRules" ref="trackFormRef" label-width="120px">
+          <el-form-item label="跟踪内容" prop="content">
+            <el-input v-model="trackForm.content" type="textarea" :rows="3" placeholder="请输入跟踪内容" />
+          </el-form-item>
+          <el-form-item label="当前态势评估" prop="assessment">
+            <el-radio-group v-model="trackForm.assessment">
+              <el-radio label="趋于平稳">趋于平稳</el-radio>
+              <el-radio label="仍在发展">仍在发展</el-radio>
+              <el-radio label="明显恶化">明显恶化</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="是否需要升级" prop="needUpgrade">
+            <el-radio-group v-model="trackForm.needUpgrade">
+              <el-radio label="否">否</el-radio>
+              <el-radio label="是">是</el-radio>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="下次回访时间" prop="nextVisitTime">
+            <el-date-picker v-model="trackForm.nextVisitTime" type="datetime" placeholder="选择日期时间" style="width:100%" value-format="YYYY-MM-DD HH:mm:ss" />
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="trackVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmTrack">保存跟踪记录</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 解除/关闭弹窗 -->
+    <el-dialog v-model="closeVisible" :title="closeTitle" width="500px" :close-on-click-modal="false">
+      <el-form :model="closeForm" :rules="closeRules" ref="closeFormRef" label-width="100px">
+        <el-form-item label="事件编号">{{ closeForm.eventNo }}</el-form-item>
+        <el-form-item label="事件摘要">{{ closeForm.summary }}</el-form-item>
+        <el-form-item label="解除原因" prop="reason">
+          <el-select v-model="closeForm.reason" placeholder="请选择" style="width:100%">
+            <el-option label="事件不存在" value="事件不存在" />
+            <el-option label="处置完成" value="处置完成" />
+            <el-option label="误报" value="误报" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="解除说明" prop="remark">
+          <el-input v-model="closeForm.remark" type="textarea" :rows="4" placeholder="请输入解除说明" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="closeVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmClose">确认</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 详情弹窗 -->
+    <el-dialog v-model="detailVisible" title="事件详情" width="600px" :close-on-click-modal="false">
+      <div v-if="currentRow" class="detail-content">
+        <el-form label-width="100px" size="default">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件编号">{{ currentRow.eventNo }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="事件类别">{{ currentRow.category }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件等级">{{ currentRow.level }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="当前状态">
+                <el-tag :type="statusTagType(currentRow.status)" size="small">{{ currentRow.status }}</el-tag>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="负责人">{{ currentRow.handler }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="发生地点">{{ currentRow.location }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item label="事件描述">
+            <div class="desc-text">{{ currentRow.description }}</div>
+          </el-form-item>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="最近回访">{{ currentRow.lastVisitTime || '-' }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="下次回访">{{ currentRow.nextVisitTime || '-' }}</el-form-item>
+            </el-col>
+          </el-row>
+          <div class="section-title">处置时间线</div>
+          <el-timeline>
+            <el-timeline-item
+              v-for="(item, index) in currentRow.timeline"
+              :key="index"
+              :type="item.type"
+              :timestamp="item.time"
+            >
+              <div style="font-weight:600">{{ item.title }}</div>
+              <div style="color:#606266;font-size:13px">{{ item.content }}</div>
+            </el-timeline-item>
+          </el-timeline>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="detailVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Gzjc">
+import { ref, computed } from 'vue'
+
+// ==================== mock 数据 ====================
+const eventList = ref([
+  { eventNo: 'EVT20250613003', category: '积水', level: '一般', status: '处理中', lastVisitTime: '2025-06-13 10:00:00', nextVisitTime: '2025-06-13 16:00:00', handler: '张三', location: '科技大道中段', description: '路面积水严重,影响通行', timeline: [
+    { time: '2025-06-13 07:55', title: '事件接报', content: '视频监控发现积水', type: 'primary' },
+    { time: '2025-06-13 08:10', title: '事件核实', content: '核实积水深度约10cm', type: 'success' },
+    { time: '2025-06-13 08:30', title: '事件转接', content: '转接至排水管理部', type: 'warning' },
+    { time: '2025-06-13 10:00', title: '跟踪记录', content: '已安排疏通车前往,预计2小时完成', type: 'primary' }
+  ] },
+  { eventNo: 'EVT20250613004', category: '管道泄漏', level: '重大', status: '处理中', lastVisitTime: '2025-06-13 08:00:00', nextVisitTime: '2025-06-13 12:00:00', handler: '李四', location: '和平路步行街', description: '燃气管道疑似泄漏', timeline: [
+    { time: '2025-06-12 16:30', title: '事件接报', content: '市应急办转发', type: 'primary' },
+    { time: '2025-06-12 17:00', title: '事件核实', content: '已现场确认微泄漏', type: 'success' },
+    { time: '2025-06-12 17:30', title: '事件转接', content: '转接至市政部门', type: 'warning' },
+    { time: '2025-06-13 08:00', title: '跟踪记录', content: '已关闭阀门,正在抢修', type: 'primary' }
+  ] },
+  { eventNo: 'EVT20250613007', category: '积水', level: '一般', status: '已解除', lastVisitTime: '2025-06-13 09:30:00', nextVisitTime: '-', handler: '王五', location: '太湖路与松江路交叉口', description: '路口积水深度约15cm', timeline: [
+    { time: '2025-06-13 06:45', title: '事件接报', content: '交警监控共享平台发现', type: 'primary' },
+    { time: '2025-06-13 07:00', title: '事件核实', content: '积水属实,排水口堵塞', type: 'success' },
+    { time: '2025-06-13 07:30', title: '事件转接', content: '转接至排水管理部', type: 'warning' },
+    { time: '2025-06-13 09:00', title: '跟踪记录', content: '排水口已疏通,积水消退', type: 'primary' },
+    { time: '2025-06-13 09:30', title: '事件解除', content: '解除原因:处置完成', type: 'success' }
+  ] },
+  { eventNo: 'EVT20250613010', category: '设备故障', level: '一般', status: '处理中', lastVisitTime: '2025-06-13 15:30:00', nextVisitTime: '2025-06-14 09:00:00', handler: '赵六', location: '新华路88号大厦', description: '地下室排水泵故障', timeline: [
+    { time: '2025-06-13 14:35', title: '事件接报', content: '物业反映排水泵故障', type: 'primary' },
+    { time: '2025-06-13 15:00', title: '事件核实', content: '排水泵电机烧毁', type: 'success' },
+    { time: '2025-06-13 15:30', title: '跟踪记录', content: '已联系供应商备货更换', type: 'primary' }
+  ] },
+  { eventNo: 'EVT20250613011', category: '塌陷', level: '较大', status: '处理中', lastVisitTime: '2025-06-13 11:00:00', nextVisitTime: '2025-06-13 17:00:00', handler: '孙七', location: '人民路与建设路交叉口', description: '路面塌陷面积约2平方米', timeline: [
+    { time: '2025-06-13 08:35', title: '事件接报', content: '巡查上报', type: 'primary' },
+    { time: '2025-06-13 08:50', title: '事件核实', content: '塌陷属实,已设围挡', type: 'success' },
+    { time: '2025-06-13 09:00', title: '事件转接', content: '转接至管网维护部', type: 'warning' },
+    { time: '2025-06-13 11:00', title: '跟踪记录', content: '已安排施工队,预计3天修复', type: 'primary' }
+  ] },
+  { eventNo: 'EVT20250613012', category: '设备故障', level: '较大', status: '处理中', lastVisitTime: '-', nextVisitTime: '2025-06-13 22:00:00', handler: '周八', location: '珠江路工业园A区', description: '消防设施压力异常', timeline: [
+    { time: '2025-06-12 20:30', title: '事件接报', content: '省厅转发', type: 'primary' },
+    { time: '2025-06-12 21:00', title: '事件核实', content: '压力传感器故障', type: 'success' }
+  ] },
+  { eventNo: 'EVT20250613013', category: '积水', level: '较大', status: '已关闭', lastVisitTime: '2025-06-13 14:00:00', nextVisitTime: '-', handler: '吴九', location: '黄河路56号小区', description: '小区内污水外溢', timeline: [
+    { time: '2025-06-13 11:25', title: '事件接报', content: '市民热线反映', type: 'primary' },
+    { time: '2025-06-13 11:45', title: '事件核实', content: '污水外溢属实', type: 'success' },
+    { time: '2025-06-13 12:00', title: '事件转接', content: '转接至排水管理部', type: 'warning' },
+    { time: '2025-06-13 14:00', title: '跟踪记录', content: '化粪池已清掏,外溢停止', type: 'primary' },
+    { time: '2025-06-13 14:30', title: '事件解除', content: '解除原因:处置完成', type: 'success' },
+    { time: '2025-06-13 15:00', title: '事件关闭', content: '事件已归档', type: 'info' }
+  ] },
+  { eventNo: 'EVT20250613014', category: '塌陷', level: '一般', status: '处理中', lastVisitTime: '-', nextVisitTime: '2025-06-13 18:00:00', handler: '郑十', location: '中山路与解放路交叉口', description: '路灯杆倾斜', timeline: [
+    { time: '2025-06-13 13:05', title: '事件接报', content: '巡查上报', type: 'primary' },
+    { time: '2025-06-13 13:20', title: '事件核实', content: '灯杆倾斜约15度', type: 'success' }
+  ] },
+  { eventNo: 'EVT20250613015', category: '管道泄漏', level: '较大', status: '已解除', lastVisitTime: '2025-06-13 13:00:00', nextVisitTime: '-', handler: '刘一', location: '长江路北侧辅道', description: '供水管道破裂', timeline: [
+    { time: '2025-06-13 10:05', title: '事件接报', content: '巡查上报', type: 'primary' },
+    { time: '2025-06-13 10:20', title: '事件核实', content: 'DN300管道破裂', type: 'success' },
+    { time: '2025-06-13 10:30', title: '事件转接', content: '转接至市政部门', type: 'warning' },
+    { time: '2025-06-13 12:00', title: '跟踪记录', content: '管道已修复,恢复供水', type: 'primary' },
+    { time: '2025-06-13 13:00', title: '事件解除', content: '解除原因:处置完成', type: 'success' }
+  ] },
+  { eventNo: 'EVT20250613016', category: '设备故障', level: '重大', status: '处理中', lastVisitTime: '2025-06-13 10:00:00', nextVisitTime: '2025-06-13 16:00:00', handler: '陈二', location: '幸福路123号门前', description: '排水井盖缺失', timeline: [
+    { time: '2025-06-13 09:15', title: '事件接报', content: '市民热线反映', type: 'primary' },
+    { time: '2025-06-13 09:30', title: '事件核实', content: '井盖缺失,已设警示', type: 'success' },
+    { time: '2025-06-13 10:00', title: '跟踪记录', content: '已联系仓库调配备用井盖', type: 'primary' }
+  ] }
+])
+
+// ==================== 搜索筛选 ====================
+const filters = ref({ eventStatus: '', category: '', dateRange: null })
+
+const filteredList = computed(() => {
+  let list = eventList.value
+  if (filters.value.eventStatus) {
+    list = list.filter(o => o.status === filters.value.eventStatus)
+  }
+  if (filters.value.category) {
+    list = list.filter(o => o.category === filters.value.category)
+  }
+  if (filters.value.dateRange && filters.value.dateRange.length === 2) {
+    const [start, end] = filters.value.dateRange
+    list = list.filter(o => {
+      const t = o.timeline[0] && o.timeline[0].time ? o.timeline[0].time : ''
+      return t >= start && t <= end + ' 23:59:59'
+    })
+  }
+  return list
+})
+
+function handleSearch() {
+  pagination.value.page = 1
+}
+
+function handleReset() {
+  filters.value = { eventStatus: '', category: '', dateRange: null }
+  pagination.value.page = 1
+}
+
+// ==================== 分页 ====================
+const pagination = ref({ page: 1, pageSize: 10 })
+
+const pagedList = computed(() => {
+  const start = (pagination.value.page - 1) * pagination.value.pageSize
+  return filteredList.value.slice(start, start + pagination.value.pageSize)
+})
+
+function handleSizeChange(val) {
+  pagination.value.pageSize = val
+  pagination.value.page = 1
+}
+
+function handleCurrentChange(val) {
+  pagination.value.page = val
+}
+
+// ==================== 标签样式 ====================
+function statusTagType(status) {
+  if (status === '处理中') return 'primary'
+  if (status === '已解除') return 'warning'
+  if (status === '已关闭') return 'success'
+  return 'info'
+}
+
+function levelTagType(level) {
+  if (level === '特别重大') return 'danger'
+  if (level === '重大') return 'danger'
+  if (level === '较大') return 'warning'
+  return 'info'
+}
+
+// ==================== 跟踪 ====================
+const trackVisible = ref(false)
+const trackFormRef = ref(null)
+const trackForm = ref({ eventNo: '', content: '', assessment: '趋于平稳', needUpgrade: '否', nextVisitTime: '' })
+const trackRules = {
+  content: [{ required: true, message: '请输入跟踪内容', trigger: 'blur' }],
+  assessment: [{ required: true, message: '请选择态势评估', trigger: 'change' }],
+  needUpgrade: [{ required: true, message: '请选择是否升级', trigger: 'change' }],
+  nextVisitTime: [{ required: true, message: '请选择下次回访时间', trigger: 'change' }]
+}
+
+function handleTrack(row) {
+  currentRow.value = row
+  trackForm.value = { eventNo: row.eventNo, content: '', assessment: '趋于平稳', needUpgrade: '否', nextVisitTime: '' }
+  trackVisible.value = true
+}
+
+function confirmTrack() {
+  trackFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === trackForm.value.eventNo)
+    if (idx > -1) {
+      eventList.value[idx].timeline.push({
+        time: new Date().toLocaleString(),
+        title: '跟踪记录',
+        content: trackForm.value.content + '(态势:' + trackForm.value.assessment + ',升级:' + trackForm.value.needUpgrade + ')',
+        type: 'primary'
+      })
+      eventList.value[idx].lastVisitTime = new Date().toLocaleString()
+      eventList.value[idx].nextVisitTime = trackForm.value.nextVisitTime
+    }
+    trackVisible.value = false
+  })
+}
+
+// ==================== 解除/关闭 ====================
+const closeVisible = ref(false)
+const closeFormRef = ref(null)
+const closeForm = ref({ eventNo: '', summary: '', reason: '', remark: '' })
+const closeRules = {
+  reason: [{ required: true, message: '请选择解除原因', trigger: 'change' }],
+  remark: [{ required: true, message: '请输入解除说明', trigger: 'blur' }]
+}
+const closeTitle = ref('事件解除')
+
+function handleClose(row) {
+  currentRow.value = row
+  closeTitle.value = row.status === '处理中' ? '事件解除' : '事件关闭'
+  closeForm.value = { eventNo: row.eventNo, summary: row.description, reason: '', remark: '' }
+  closeVisible.value = true
+}
+
+function confirmClose() {
+  closeFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === closeForm.value.eventNo)
+    if (idx > -1) {
+      if (eventList.value[idx].status === '处理中') {
+        eventList.value[idx].status = '已解除'
+        eventList.value[idx].timeline.push({
+          time: new Date().toLocaleString(),
+          title: '事件解除',
+          content: '解除原因:' + closeForm.value.reason + ';' + closeForm.value.remark,
+          type: 'success'
+        })
+        eventList.value[idx].nextVisitTime = '-'
+      } else if (eventList.value[idx].status === '已解除') {
+        eventList.value[idx].status = '已关闭'
+        eventList.value[idx].timeline.push({
+          time: new Date().toLocaleString(),
+          title: '事件关闭',
+          content: '事件已归档:' + closeForm.value.remark,
+          type: 'info'
+        })
+      }
+    }
+    closeVisible.value = false
+  })
+}
+
+// ==================== 详情 ====================
+const detailVisible = ref(false)
+const currentRow = ref(null)
+
+function handleDetail(row) {
+  currentRow.value = row
+  detailVisible.value = true
+}
+</script>
+
+<style scoped>
+.gzjc-page {
+  padding: 16px;
+  background: #f5f5f5;
+  min-height: calc(100vh - 84px);
+}
+
+.filter-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 12px 16px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 12px;
+}
+
+.filter-form {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.table-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+}
+
+.pagination-wrap {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.detail-content {
+  padding: 0 8px;
+}
+
+.section-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-left: 8px;
+  border-left: 3px solid #409EFF;
+}
+
+.desc-text {
+  background: #f5f7fa;
+  border-radius: 4px;
+  padding: 10px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.6;
+  max-height: 120px;
+  overflow-y: auto;
+}
+
+:deep(.el-form-item__label) {
+  color: #909399;
+}
+
+:deep(.el-form-item__content) {
+  color: #303133;
+}
+</style>

+ 350 - 0
src/views/subSystem/dispatch/disOnDuty/jbgl.vue

@@ -0,0 +1,350 @@
+<template>
+  <div class="app-container jbgl-page">
+    <!-- 搜索区 -->
+    <div class="filter-panel">
+      <div class="filter-form">
+        <el-select v-model="filters.source" placeholder="事件来源" clearable style="width:160px">
+          <el-option label="巡查上报" value="巡查上报" />
+          <el-option label="呼叫中心" value="呼叫中心" />
+          <el-option label="视频监控" value="视频监控" />
+          <el-option label="上级下达" value="上级下达" />
+        </el-select>
+        <el-date-picker
+          v-model="filters.dateRange"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          style="width:260px"
+          value-format="YYYY-MM-DD"
+        />
+        <el-select v-model="filters.status" placeholder="事件状态" clearable style="width:140px">
+          <el-option label="待受理" value="待受理" />
+          <el-option label="已受理" value="已受理" />
+          <el-option label="已驳回" value="已驳回" />
+        </el-select>
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </div>
+      <div class="filter-actions">
+        <el-button type="primary" @click="handleAdd">新增接报</el-button>
+      </div>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-panel">
+      <el-table :data="pagedList" border stripe style="width:100%">
+        <el-table-column prop="eventNo" label="事件编号" width="140" />
+        <el-table-column prop="source" label="事件来源" width="110" />
+        <el-table-column prop="location" label="发生地点" show-overflow-tooltip />
+        <el-table-column prop="happenTime" label="发生时间" width="150" />
+        <el-table-column prop="description" label="事件描述" show-overflow-tooltip />
+        <el-table-column prop="reporter" label="接报人" width="100" />
+        <el-table-column prop="status" label="状态" width="100">
+          <template #default="{ row }">
+            <el-tag :type="statusTagType(row.status)" size="small">{{ row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="160" fixed="right">
+          <template #default="{ row }">
+            <el-button v-if="row.status === '待受理'" type="primary" link size="small" @click="handleAccept(row)">受理</el-button>
+            <el-button type="primary" link size="small" @click="handleDetail(row)">详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pagination.page"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+
+    <!-- 受理确认弹窗 -->
+    <el-dialog v-model="acceptVisible" title="受理确认" width="400px" :close-on-click-modal="false">
+      <div v-if="currentRow">
+        <p>事件编号:{{ currentRow.eventNo }}</p>
+        <p>事件来源:{{ currentRow.source }}</p>
+        <p>发生地点:{{ currentRow.location }}</p>
+        <p>事件描述:{{ currentRow.description }}</p>
+      </div>
+      <template #footer>
+        <el-button @click="acceptVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmAccept">确认受理</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 详情弹窗 -->
+    <el-dialog v-model="detailVisible" title="事件详情" width="600px" :close-on-click-modal="false">
+      <div v-if="currentRow" class="detail-content">
+        <el-form label-width="100px" size="default">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件编号">{{ currentRow.eventNo }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="事件来源">{{ currentRow.source }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="发生地点">{{ currentRow.location }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="发生时间">{{ currentRow.happenTime }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item label="事件描述">
+            <div class="desc-text">{{ currentRow.description }}</div>
+          </el-form-item>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="接报人">{{ currentRow.reporter }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="接报时间">{{ currentRow.reportTime }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item label="来源渠道">{{ currentRow.channel }}</el-form-item>
+          <el-form-item label="状态">
+            <el-tag :type="statusTagType(currentRow.status)" size="small">{{ currentRow.status }}</el-tag>
+          </el-form-item>
+        </el-form>
+      </div>
+      <template #footer>
+        <el-button @click="detailVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 新增接报弹窗 -->
+    <el-dialog v-model="addVisible" title="新增接报" width="600px" :close-on-click-modal="false">
+      <el-form :model="addForm" :rules="addRules" ref="addFormRef" label-width="100px">
+        <el-form-item label="事件来源" prop="source">
+          <el-select v-model="addForm.source" placeholder="请选择" style="width:100%">
+            <el-option label="巡查上报" value="巡查上报" />
+            <el-option label="呼叫中心" value="呼叫中心" />
+            <el-option label="视频监控" value="视频监控" />
+            <el-option label="上级下达" value="上级下达" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="发生地点" prop="location">
+          <el-input v-model="addForm.location" placeholder="请输入发生地点" />
+        </el-form-item>
+        <el-form-item label="发生时间" prop="happenTime">
+          <el-date-picker v-model="addForm.happenTime" type="datetime" placeholder="选择日期时间" style="width:100%" value-format="YYYY-MM-DD HH:mm:ss" />
+        </el-form-item>
+        <el-form-item label="事件描述" prop="description">
+          <el-input v-model="addForm.description" type="textarea" :rows="3" placeholder="请输入事件描述" />
+        </el-form-item>
+        <el-form-item label="接报人" prop="reporter">
+          <el-input v-model="addForm.reporter" placeholder="请输入接报人" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="addVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmAdd">确认</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Jbgl">
+import { ref, computed } from 'vue'
+
+// ==================== mock 数据 ====================
+const eventList = ref([
+  { eventNo: 'JB20250613001', source: '巡查上报', location: '人民路与建设路交叉口', happenTime: '2025-06-13 08:30:00', description: '路面出现明显塌陷,面积约2平方米', reporter: '张三', reportTime: '2025-06-13 08:35:00', channel: '移动终端巡查系统', status: '待受理' },
+  { eventNo: 'JB20250613002', source: '呼叫中心', location: '幸福路123号门前', happenTime: '2025-06-13 09:10:00', description: '市民反映排水井盖缺失,存在安全隐患', reporter: '李四', reportTime: '2025-06-13 09:15:00', channel: '12345市民热线', status: '待受理' },
+  { eventNo: 'JB20250613003', source: '视频监控', location: '科技大道中段', happenTime: '2025-06-13 07:50:00', description: '视频监控发现路面积水严重,影响通行', reporter: '王五', reportTime: '2025-06-13 07:55:00', channel: '智慧城管视频监控平台', status: '已受理' },
+  { eventNo: 'JB20250613004', source: '上级下达', location: '和平路步行街', happenTime: '2025-06-12 16:00:00', description: '市应急办转发:步行街燃气管道疑似泄漏', reporter: '赵六', reportTime: '2025-06-12 16:30:00', channel: '市应急指挥平台', status: '已受理' },
+  { eventNo: 'JB20250613005', source: '巡查上报', location: '长江路北侧辅道', happenTime: '2025-06-13 10:00:00', description: '供水管道破裂,水涌至路面', reporter: '孙七', reportTime: '2025-06-13 10:05:00', channel: '移动终端巡查系统', status: '已驳回' },
+  { eventNo: 'JB20250613006', source: '呼叫中心', location: '黄河路56号小区', happenTime: '2025-06-13 11:20:00', description: '居民反映小区内污水外溢,气味刺鼻', reporter: '周八', reportTime: '2025-06-13 11:25:00', channel: '12345市民热线', status: '待受理' },
+  { eventNo: 'JB20250613007', source: '视频监控', location: '太湖路与松江路交叉口', happenTime: '2025-06-13 06:40:00', description: '早高峰时段路口积水深度约15cm', reporter: '吴九', reportTime: '2025-06-13 06:45:00', channel: '交警监控共享平台', status: '已受理' },
+  { eventNo: 'JB20250613008', source: '上级下达', location: '珠江路工业园A区', happenTime: '2025-06-12 20:00:00', description: '省厅转发:园区内消防设施压力异常', reporter: '郑十', reportTime: '2025-06-12 20:30:00', channel: '省应急管理厅平台', status: '待受理' },
+  { eventNo: 'JB20250613009', source: '巡查上报', location: '中山路与解放路交叉口', happenTime: '2025-06-13 13:00:00', description: '路灯杆倾斜,存在倒塌风险', reporter: '刘一', reportTime: '2025-06-13 13:05:00', channel: '移动终端巡查系统', status: '待受理' },
+  { eventNo: 'JB20250613010', source: '呼叫中心', location: '新华路88号大厦', happenTime: '2025-06-13 14:30:00', description: '大厦物业反映地下室排水泵故障', reporter: '陈二', reportTime: '2025-06-13 14:35:00', channel: '12345市民热线', status: '已受理' }
+])
+
+// ==================== 搜索筛选 ====================
+const filters = ref({ source: '', dateRange: null, status: '' })
+
+const filteredList = computed(() => {
+  let list = eventList.value
+  if (filters.value.source) {
+    list = list.filter(o => o.source === filters.value.source)
+  }
+  if (filters.value.status) {
+    list = list.filter(o => o.status === filters.value.status)
+  }
+  if (filters.value.dateRange && filters.value.dateRange.length === 2) {
+    const [start, end] = filters.value.dateRange
+    list = list.filter(o => o.happenTime >= start && o.happenTime <= end + ' 23:59:59')
+  }
+  return list
+})
+
+function handleSearch() {
+  pagination.value.page = 1
+}
+
+function handleReset() {
+  filters.value = { source: '', dateRange: null, status: '' }
+  pagination.value.page = 1
+}
+
+// ==================== 分页 ====================
+const pagination = ref({ page: 1, pageSize: 10 })
+
+const pagedList = computed(() => {
+  const start = (pagination.value.page - 1) * pagination.value.pageSize
+  return filteredList.value.slice(start, start + pagination.value.pageSize)
+})
+
+function handleSizeChange(val) {
+  pagination.value.pageSize = val
+  pagination.value.page = 1
+}
+
+function handleCurrentChange(val) {
+  pagination.value.page = val
+}
+
+// ==================== 状态标签样式 ====================
+function statusTagType(status) {
+  if (status === '待受理') return 'warning'
+  if (status === '已受理') return 'success'
+  if (status === '已驳回') return 'danger'
+  return 'info'
+}
+
+// ==================== 受理 ====================
+const acceptVisible = ref(false)
+const currentRow = ref(null)
+
+function handleAccept(row) {
+  currentRow.value = row
+  acceptVisible.value = true
+}
+
+function confirmAccept() {
+  if (currentRow.value) {
+    const idx = eventList.value.findIndex(o => o.eventNo === currentRow.value.eventNo)
+    if (idx > -1) eventList.value[idx].status = '已受理'
+  }
+  acceptVisible.value = false
+}
+
+// ==================== 详情 ====================
+const detailVisible = ref(false)
+
+function handleDetail(row) {
+  currentRow.value = row
+  detailVisible.value = true
+}
+
+// ==================== 新增接报 ====================
+const addVisible = ref(false)
+const addFormRef = ref(null)
+const addForm = ref({ source: '', location: '', happenTime: '', description: '', reporter: '' })
+const addRules = {
+  source: [{ required: true, message: '请选择事件来源', trigger: 'change' }],
+  location: [{ required: true, message: '请输入发生地点', trigger: 'blur' }],
+  happenTime: [{ required: true, message: '请选择发生时间', trigger: 'change' }],
+  description: [{ required: true, message: '请输入事件描述', trigger: 'blur' }],
+  reporter: [{ required: true, message: '请输入接报人', trigger: 'blur' }]
+}
+
+function handleAdd() {
+  addForm.value = { source: '', location: '', happenTime: '', description: '', reporter: '' }
+  addVisible.value = true
+}
+
+function confirmAdd() {
+  addFormRef.value.validate(valid => {
+    if (!valid) return
+    const now = new Date()
+    const no = 'JB' + now.getFullYear() + String(now.getMonth() + 1).padStart(2, '0') + String(now.getDate()).padStart(2, '0') + String(eventList.value.length + 1).padStart(3, '0')
+    eventList.value.unshift({
+      eventNo: no,
+      source: addForm.value.source,
+      location: addForm.value.location,
+      happenTime: addForm.value.happenTime,
+      description: addForm.value.description,
+      reporter: addForm.value.reporter,
+      reportTime: addForm.value.happenTime,
+      channel: '人工录入',
+      status: '待受理'
+    })
+    addVisible.value = false
+  })
+}
+</script>
+
+<style scoped>
+.jbgl-page {
+  padding: 16px;
+  background: #f5f5f5;
+  min-height: calc(100vh - 84px);
+}
+
+.filter-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 12px 16px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 12px;
+}
+
+.filter-form {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.table-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+}
+
+.pagination-wrap {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.detail-content {
+  padding: 0 8px;
+}
+
+.desc-text {
+  background: #f5f7fa;
+  border-radius: 4px;
+  padding: 10px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.6;
+  max-height: 120px;
+  overflow-y: auto;
+}
+
+:deep(.el-form-item__label) {
+  color: #909399;
+}
+
+:deep(.el-form-item__content) {
+  color: #303133;
+}
+</style>

+ 390 - 0
src/views/subSystem/dispatch/disOnDuty/zjbs.vue

@@ -0,0 +1,390 @@
+<template>
+  <div class="app-container zjbs-page">
+    <!-- 搜索区 -->
+    <div class="filter-panel">
+      <div class="filter-form">
+        <el-input v-model="filters.eventNo" placeholder="事件编号" clearable style="width:160px" />
+        <el-select v-model="filters.transferStatus" placeholder="转接状态" clearable style="width:140px">
+          <el-option label="待转接" value="待转接" />
+          <el-option label="已转接" value="已转接" />
+          <el-option label="已报送" value="已报送" />
+        </el-select>
+        <el-select v-model="filters.receiveDept" placeholder="接收部门" clearable style="width:160px">
+          <el-option label="市政部门" value="市政部门" />
+          <el-option label="消防部门" value="消防部门" />
+          <el-option label="排水管理部" value="排水管理部" />
+          <el-option label="管网维护部" value="管网维护部" />
+          <el-option label="设备运维部" value="设备运维部" />
+          <el-option label="安全管理部" value="安全管理部" />
+        </el-select>
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="handleReset">重置</el-button>
+      </div>
+    </div>
+
+    <!-- 数据表格 -->
+    <div class="table-panel">
+      <el-table :data="pagedList" border stripe style="width:100%">
+        <el-table-column prop="eventNo" label="事件编号" width="140" />
+        <el-table-column prop="category" label="事件类别" width="110" />
+        <el-table-column prop="level" label="事件等级" width="100">
+          <template #default="{ row }">
+            <el-tag :type="levelTagType(row.level)" size="small">{{ row.level }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="transferDept" label="转接部门" width="120" />
+        <el-table-column prop="reportLevel" label="报送层级" width="120" />
+        <el-table-column prop="transferTime" label="转接时间" width="150" />
+        <el-table-column prop="status" label="状态" width="100">
+          <template #default="{ row }">
+            <el-tag :type="statusTagType(row.status)" size="small">{{ row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200" fixed="right">
+          <template #default="{ row }">
+            <el-button v-if="row.status === '待转接'" type="primary" link size="small" @click="handleTransfer(row)">转接</el-button>
+            <el-button v-if="row.status === '待转接' || row.status === '已转接'" type="primary" link size="small" @click="handleReport(row)">报送</el-button>
+            <el-button type="primary" link size="small" @click="handleDetail(row)">详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="pagination-wrap">
+        <el-pagination
+          v-model:current-page="pagination.page"
+          v-model:page-size="pagination.pageSize"
+          :page-sizes="[10, 20, 50]"
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredList.length"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+
+    <!-- 转接弹窗 -->
+    <el-dialog v-model="transferVisible" title="事件转接" width="600px" :close-on-click-modal="false">
+      <el-form :model="transferForm" :rules="transferRules" ref="transferFormRef" label-width="120px">
+        <el-form-item label="事件摘要">
+          <div class="desc-text">{{ transferForm.summary }}</div>
+        </el-form-item>
+        <el-form-item label="推荐转接部门">
+          <el-tag type="success" size="small">{{ transferForm.recommendDept }}</el-tag>
+        </el-form-item>
+        <el-form-item label="选择转接部门" prop="depts">
+          <el-select v-model="transferForm.depts" multiple placeholder="请选择" style="width:100%">
+            <el-option label="市政部门" value="市政部门" />
+            <el-option label="消防部门" value="消防部门" />
+            <el-option label="排水管理部" value="排水管理部" />
+            <el-option label="管网维护部" value="管网维护部" />
+            <el-option label="设备运维部" value="设备运维部" />
+            <el-option label="安全管理部" value="安全管理部" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="transferForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="transferVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmTransfer">确认转接</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 报送弹窗 -->
+    <el-dialog v-model="reportVisible" title="事件报送" width="600px" :close-on-click-modal="false">
+      <el-form :model="reportForm" :rules="reportRules" ref="reportFormRef" label-width="120px">
+        <el-form-item label="报送层级" prop="reportTargets">
+          <el-checkbox-group v-model="reportForm.reportTargets">
+            <el-checkbox label="区级应急办" />
+            <el-checkbox label="市级应急办" />
+            <el-checkbox label="省级应急厅" />
+            <el-checkbox label="国务院应急管理部" />
+          </el-checkbox-group>
+        </el-form-item>
+        <el-form-item label="报送内容摘要">
+          <div class="desc-text">{{ reportForm.summary }}</div>
+        </el-form-item>
+        <el-form-item label="附件上传">
+          <el-upload action="#" :auto-upload="false" :file-list="reportForm.fileList">
+            <el-button type="primary">选择文件</el-button>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="reportVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmReport">确认报送</el-button>
+      </template>
+    </el-dialog>
+
+    <!-- 详情弹窗 -->
+    <el-dialog v-model="detailVisible" title="流转详情" width="700px" :close-on-click-modal="false">
+      <div v-if="currentRow" class="detail-content">
+        <el-form label-width="100px" size="default">
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件编号">{{ currentRow.eventNo }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="事件类别">{{ currentRow.category }}</el-form-item>
+            </el-col>
+          </el-row>
+          <el-row :gutter="20">
+            <el-col :span="12">
+              <el-form-item label="事件等级">{{ currentRow.level }}</el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="当前状态">{{ currentRow.status }}</el-form-item>
+            </el-col>
+          </el-row>
+        </el-form>
+        <div class="section-title">流转历史</div>
+        <el-timeline>
+          <el-timeline-item
+            v-for="(item, index) in currentRow.history"
+            :key="index"
+            :type="item.type"
+            :timestamp="item.time"
+          >
+            {{ item.content }}
+          </el-timeline-item>
+        </el-timeline>
+      </div>
+      <template #footer>
+        <el-button @click="detailVisible = false">关闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="Zjbs">
+import { ref, computed } from 'vue'
+
+// ==================== mock 数据 ====================
+const eventList = ref([
+  { eventNo: 'EVT20250613003', category: '积水', level: '一般', transferDept: '-', reportLevel: '-', transferTime: '-', status: '待转接', summary: '科技大道中段路面积水严重,影响通行', history: [{ time: '2025-06-13 07:55', content: '事件接报', type: 'primary' }, { time: '2025-06-13 08:10', content: '事件核实完成', type: 'success' }] },
+  { eventNo: 'EVT20250613004', category: '管道泄漏', level: '重大', transferDept: '市政部门', reportLevel: '-', transferTime: '2025-06-12 17:30:00', status: '已转接', summary: '和平路步行街燃气管道疑似泄漏', history: [{ time: '2025-06-12 16:30', content: '事件接报', type: 'primary' }, { time: '2025-06-12 17:00', content: '事件核实完成', type: 'success' }, { time: '2025-06-12 17:30', content: '转接至市政部门', type: 'warning' }] },
+  { eventNo: 'EVT20250613007', category: '积水', level: '一般', transferDept: '排水管理部', reportLevel: '区级应急办', transferTime: '2025-06-13 07:30:00', status: '已报送', summary: '太湖路与松江路交叉口积水', history: [{ time: '2025-06-13 06:45', content: '事件接报', type: 'primary' }, { time: '2025-06-13 07:00', content: '事件核实完成', type: 'success' }, { time: '2025-06-13 07:30', content: '转接至排水管理部', type: 'warning' }, { time: '2025-06-13 08:00', content: '报送至区级应急办', type: 'danger' }] },
+  { eventNo: 'EVT20250613010', category: '设备故障', level: '一般', transferDept: '-', reportLevel: '-', transferTime: '-', status: '待转接', summary: '新华路88号大厦地下室排水泵故障', history: [{ time: '2025-06-13 14:35', content: '事件接报', type: 'primary' }, { time: '2025-06-13 15:00', content: '事件核实完成', type: 'success' }] },
+  { eventNo: 'EVT20250613011', category: '塌陷', level: '较大', transferDept: '管网维护部', reportLevel: '-', transferTime: '2025-06-13 09:00:00', status: '已转接', summary: '人民路与建设路交叉口路面塌陷', history: [{ time: '2025-06-13 08:35', content: '事件接报', type: 'primary' }, { time: '2025-06-13 08:50', content: '事件核实完成', type: 'success' }, { time: '2025-06-13 09:00', content: '转接至管网维护部', type: 'warning' }] },
+  { eventNo: 'EVT20250613012', category: '设备故障', level: '较大', transferDept: '-', reportLevel: '-', transferTime: '-', status: '待转接', summary: '珠江路工业园A区消防设施压力异常', history: [{ time: '2025-06-12 20:30', content: '事件接报', type: 'primary' }, { time: '2025-06-12 21:00', content: '事件核实完成', type: 'success' }] },
+  { eventNo: 'EVT20250613013', category: '积水', level: '较大', transferDept: '排水管理部', reportLevel: '-', transferTime: '2025-06-13 12:00:00', status: '已转接', summary: '黄河路56号小区污水外溢', history: [{ time: '2025-06-13 11:25', content: '事件接报', type: 'primary' }, { time: '2025-06-13 11:45', content: '事件核实完成', type: 'success' }, { time: '2025-06-13 12:00', content: '转接至排水管理部', type: 'warning' }] },
+  { eventNo: 'EVT20250613014', category: '塌陷', level: '一般', transferDept: '-', reportLevel: '-', transferTime: '-', status: '待转接', summary: '中山路与解放路交叉口路灯杆倾斜', history: [{ time: '2025-06-13 13:05', content: '事件接报', type: 'primary' }, { time: '2025-06-13 13:20', content: '事件核实完成', type: 'success' }] },
+  { eventNo: 'EVT20250613015', category: '管道泄漏', level: '较大', transferDept: '市政部门', reportLevel: '市级应急办', transferTime: '2025-06-13 10:30:00', status: '已报送', summary: '长江路北侧供水管道破裂', history: [{ time: '2025-06-13 10:05', content: '事件接报', type: 'primary' }, { time: '2025-06-13 10:20', content: '事件核实完成', type: 'success' }, { time: '2025-06-13 10:30', content: '转接至市政部门', type: 'warning' }, { time: '2025-06-13 11:00', content: '报送至市级应急办', type: 'danger' }] },
+  { eventNo: 'EVT20250613016', category: '设备故障', level: '重大', transferDept: '-', reportLevel: '-', transferTime: '-', status: '待转接', summary: '幸福路排水井盖缺失', history: [{ time: '2025-06-13 09:15', content: '事件接报', type: 'primary' }, { time: '2025-06-13 09:30', content: '事件核实完成', type: 'success' }] }
+])
+
+// ==================== 推荐部门映射 ====================
+const recommendMap = {
+  '管道泄漏': '市政部门',
+  '塌陷': '管网维护部',
+  '积水': '排水管理部',
+  '设备故障': '设备运维部'
+}
+
+// ==================== 搜索筛选 ====================
+const filters = ref({ eventNo: '', transferStatus: '', receiveDept: '' })
+
+const filteredList = computed(() => {
+  let list = eventList.value
+  if (filters.value.eventNo) {
+    list = list.filter(o => o.eventNo.includes(filters.value.eventNo))
+  }
+  if (filters.value.transferStatus) {
+    list = list.filter(o => o.status === filters.value.transferStatus)
+  }
+  if (filters.value.receiveDept) {
+    list = list.filter(o => o.transferDept === filters.value.receiveDept || o.transferDept === '-')
+  }
+  return list
+})
+
+function handleSearch() {
+  pagination.value.page = 1
+}
+
+function handleReset() {
+  filters.value = { eventNo: '', transferStatus: '', receiveDept: '' }
+  pagination.value.page = 1
+}
+
+// ==================== 分页 ====================
+const pagination = ref({ page: 1, pageSize: 10 })
+
+const pagedList = computed(() => {
+  const start = (pagination.value.page - 1) * pagination.value.pageSize
+  return filteredList.value.slice(start, start + pagination.value.pageSize)
+})
+
+function handleSizeChange(val) {
+  pagination.value.pageSize = val
+  pagination.value.page = 1
+}
+
+function handleCurrentChange(val) {
+  pagination.value.page = val
+}
+
+// ==================== 标签样式 ====================
+function statusTagType(status) {
+  if (status === '待转接') return 'warning'
+  if (status === '已转接') return 'primary'
+  if (status === '已报送') return 'success'
+  return 'info'
+}
+
+function levelTagType(level) {
+  if (level === '特别重大') return 'danger'
+  if (level === '重大') return 'danger'
+  if (level === '较大') return 'warning'
+  return 'info'
+}
+
+// ==================== 转接 ====================
+const transferVisible = ref(false)
+const transferFormRef = ref(null)
+const transferForm = ref({ eventNo: '', summary: '', recommendDept: '', depts: [], remark: '' })
+const transferRules = {
+  depts: [{ required: true, message: '请选择转接部门', trigger: 'change', type: 'array' }]
+}
+
+function handleTransfer(row) {
+  transferForm.value = {
+    eventNo: row.eventNo,
+    summary: row.summary,
+    recommendDept: recommendMap[row.category] || '相关部门',
+    depts: [],
+    remark: ''
+  }
+  transferVisible.value = true
+}
+
+function confirmTransfer() {
+  transferFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === transferForm.value.eventNo)
+    if (idx > -1) {
+      eventList.value[idx].transferDept = transferForm.value.depts.join('、')
+      eventList.value[idx].transferTime = new Date().toLocaleString()
+      eventList.value[idx].status = '已转接'
+      eventList.value[idx].history.push({
+        time: new Date().toLocaleString(),
+        content: '转接至' + transferForm.value.depts.join('、'),
+        type: 'warning'
+      })
+    }
+    transferVisible.value = false
+  })
+}
+
+// ==================== 报送 ====================
+const reportVisible = ref(false)
+const reportFormRef = ref(null)
+const reportForm = ref({ eventNo: '', summary: '', reportTargets: [], fileList: [] })
+const reportRules = {
+  reportTargets: [{ required: true, message: '请选择报送层级', trigger: 'change', type: 'array' }]
+}
+
+function handleReport(row) {
+  reportForm.value = { eventNo: row.eventNo, summary: row.summary, reportTargets: [], fileList: [] }
+  reportVisible.value = true
+}
+
+function confirmReport() {
+  reportFormRef.value.validate(valid => {
+    if (!valid) return
+    const idx = eventList.value.findIndex(o => o.eventNo === reportForm.value.eventNo)
+    if (idx > -1) {
+      eventList.value[idx].reportLevel = reportForm.value.reportTargets.join('、')
+      eventList.value[idx].status = '已报送'
+      eventList.value[idx].history.push({
+        time: new Date().toLocaleString(),
+        content: '报送至' + reportForm.value.reportTargets.join('、'),
+        type: 'danger'
+      })
+    }
+    reportVisible.value = false
+  })
+}
+
+// ==================== 详情 ====================
+const detailVisible = ref(false)
+const currentRow = ref(null)
+
+function handleDetail(row) {
+  currentRow.value = row
+  detailVisible.value = true
+}
+</script>
+
+<style scoped>
+.zjbs-page {
+  padding: 16px;
+  background: #f5f5f5;
+  min-height: calc(100vh - 84px);
+}
+
+.filter-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 12px 16px;
+  margin-bottom: 12px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 12px;
+}
+
+.filter-form {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  flex-wrap: wrap;
+}
+
+.table-panel {
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  padding: 16px;
+}
+
+.pagination-wrap {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
+.detail-content {
+  padding: 0 8px;
+}
+
+.section-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #303133;
+  margin-bottom: 12px;
+  padding-left: 8px;
+  border-left: 3px solid #409EFF;
+}
+
+.desc-text {
+  background: #f5f7fa;
+  border-radius: 4px;
+  padding: 10px;
+  font-size: 13px;
+  color: #606266;
+  line-height: 1.6;
+  max-height: 120px;
+  overflow-y: auto;
+}
+
+:deep(.el-form-item__label) {
+  color: #909399;
+}
+
+:deep(.el-form-item__content) {
+  color: #303133;
+}
+</style>