Quellcode durchsuchen

refactor(manholeCover): 重构井盖工单处理页面

- 将页面标题从"待处理工单"改为"经办工单"
- 更新搜索功能,移除地址搜索,保留工单编号和案件编号搜索
- 替换报警级别筛选为优先级筛选,支持紧急、一般、低三个等级
- 优化统计卡片样式,增加悬停效果和边框高亮
- 重命名表格列字段,使用更准确的字段名如orderNo、caseNo等
- 实现完整的工单流程操作,包括接单、开始维修、提交验收
- 添加延期申请功能,支持工单延期操作
- 更新工单详情面板,展示更多设备和状态信息
- 集成API接口,替换模拟数据为真实数据获取
- 优化表格操作按钮逻辑,根据工单状态显示相应操作
- 添加处理记录时间线,显示工单操作历史
- 实现工单状态映射,统一状态显示格式
- 优化页面布局,使用Tailwind CSS类替代内联样式
nahida vor 1 Woche
Ursprung
Commit
8e73ee2487
1 geänderte Dateien mit 407 neuen und 386 gelöschten Zeilen
  1. 407 386
      src/views/subSystem/manholeCover/caseHandling/handlingWorkO.vue

+ 407 - 386
src/views/subSystem/manholeCover/caseHandling/handlingWorkO.vue

@@ -1,281 +1,338 @@
 <!--经办工单-->
 <template>
-  <div class="pending-orders">
-    <!-- 页面头部 -->
-    <div class="page-header">
-      <div class="header-left">
+  <div class="min-h-screen bg-[#f0f2f6] p-5">
+    <div class="mb-5 flex flex-wrap items-center justify-between gap-3 rounded-2xl bg-white px-6 py-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
+      <div class="flex items-center gap-3">
         <el-icon><List /></el-icon>
-        <span class="title">待处理工单</span>
+        <span class="text-[20px] font-600 text-[#1f2d3d]">经办工单</span>
         <el-tag type="danger" effect="dark" v-if="pendingOrdersCount > 0">待处理 {{ pendingOrdersCount }}</el-tag>
       </div>
-      <div class="header-right">
+      <div class="flex flex-wrap items-center gap-3">
         <el-input
-            v-model="searchKeyword"
-            placeholder="搜索工单编号/案件编号/地址"
-            clearable
-            :prefix-icon="Search"
-            style="width: 260px"
-            size="default"
+          v-model="searchKeyword"
+          placeholder="搜索工单编号/案件编号"
+          clearable
+          :prefix-icon="Search"
+          class="w-[260px]"
+          @keyup.enter="loadOrders"
         />
-        <el-select v-model="alertLevelFilter" placeholder="报警级别" clearable style="width: 120px" size="default">
-          <el-option label="严重" value="critical" />
-          <el-option label="一般" value="warning" />
+        <el-select v-model="orderLevelFilter" placeholder="优先级" clearable class="w-[120px]">
+          <el-option label="紧急" :value="1" />
+          <el-option label="一般" :value="2" />
+          <el-option label="低" :value="3" />
         </el-select>
-        <el-button type="primary" :icon="Refresh" @click="refreshList">刷新</el-button>
+        <el-button type="primary" :icon="Refresh" @click="loadOrders">刷新</el-button>
       </div>
     </div>
 
-    <!-- 统计卡片 -->
-    <div class="stats-cards">
-      <div class="stat-card" :class="{ active: statusFilter === '' }" @click="setStatusFilter('')">
-        <div class="stat-value">{{ totalOrders }}</div>
-        <div class="stat-label">全部工单</div>
+    <div class="mb-5 flex flex-wrap gap-4">
+      <div
+        class="min-w-[100px] cursor-pointer rounded-xl bg-white px-6 py-3 text-center shadow-[0_1px_4px_rgba(0,0,0,0.05)] transition-all duration-200 hover:-translate-y-[2px] hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)]"
+        :class="statusFilter === '' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
+        @click="setStatusFilter('')"
+      >
+        <div class="text-[28px] font-bold">{{ totalOrders }}</div>
+        <div class="mt-1 text-[13px] text-[#606266]">全部工单</div>
       </div>
-      <div class="stat-card pending" :class="{ active: statusFilter === 'pending' }" @click="setStatusFilter('pending')">
-        <div class="stat-value">{{ pendingOrdersCount }}</div>
-        <div class="stat-label">待处理</div>
+      <div
+        class="min-w-[100px] cursor-pointer rounded-xl bg-white px-6 py-3 text-center shadow-[0_1px_4px_rgba(0,0,0,0.05)] transition-all duration-200 hover:-translate-y-[2px] hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)]"
+        :class="statusFilter === 'pending' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
+        @click="setStatusFilter('pending')"
+      >
+        <div class="text-[28px] font-bold text-[#f56c6c]">{{ pendingOrdersCount }}</div>
+        <div class="mt-1 text-[13px] text-[#606266]">待处理</div>
       </div>
-      <div class="stat-card processing" :class="{ active: statusFilter === 'processing' }" @click="setStatusFilter('processing')">
-        <div class="stat-value">{{ processingOrdersCount }}</div>
-        <div class="stat-label">处理中</div>
+      <div
+        class="min-w-[100px] cursor-pointer rounded-xl bg-white px-6 py-3 text-center shadow-[0_1px_4px_rgba(0,0,0,0.05)] transition-all duration-200 hover:-translate-y-[2px] hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)]"
+        :class="statusFilter === 'processing' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
+        @click="setStatusFilter('processing')"
+      >
+        <div class="text-[28px] font-bold text-[#e6a23c]">{{ processingOrdersCount }}</div>
+        <div class="mt-1 text-[13px] text-[#606266]">处理中</div>
       </div>
-      <div class="stat-card overdue" :class="{ active: statusFilter === 'overdue' }" @click="setStatusFilter('overdue')">
-        <div class="stat-value">{{ overdueCount }}</div>
-        <div class="stat-label">已逾期</div>
+      <div
+        class="min-w-[100px] cursor-pointer rounded-xl bg-white px-6 py-3 text-center shadow-[0_1px_4px_rgba(0,0,0,0.05)] transition-all duration-200 hover:-translate-y-[2px] hover:shadow-[0_4px_12px_rgba(0,0,0,0.1)]"
+        :class="statusFilter === 'overdue' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
+        @click="setStatusFilter('overdue')"
+      >
+        <div class="text-[28px] font-bold text-[#f56c6c]">{{ overdueCount }}</div>
+        <div class="mt-1 text-[13px] text-[#606266]">已逾期</div>
       </div>
     </div>
 
-    <!-- 工单列表 -->
-    <div class="order-table-container">
-      <el-table
-          :data="paginatedOrders"
-          stripe
-          border
-          style="width: 100%"
-          v-loading="loading"
-          @row-click="handleRowClick"
-      >
+    <div class="rounded-2xl bg-white p-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
+      <el-table :data="paginatedOrders" stripe border class="w-full" row-class-name="cursor-pointer" v-loading="loading" @row-click="handleRowClick">
         <el-table-column type="index" label="序号" width="55" align="center" />
-        <el-table-column prop="code" label="工单编号" width="160" sortable />
-        <el-table-column prop="caseCode" label="关联案件编号" width="160" />
-        <el-table-column prop="alertLevel" label="报警级别" width="100" align="center">
+        <el-table-column prop="orderNo" label="工单编号" min-width="170" />
+        <el-table-column prop="caseNo" label="关联案件编号" min-width="170" />
+        <el-table-column prop="orderLevelText" label="优先级" width="100" align="center">
           <template #default="{ row }">
-            <el-tag :type="row.alertLevel === 'critical' ? 'danger' : 'warning'" size="small">
-              {{ row.alertLevel === 'critical' ? '严重' : '一般' }}
-            </el-tag>
+            <el-tag :type="row.orderLevelTag" size="small">{{ row.orderLevelText }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="alertType" label="报警类型" width="120" />
-        <el-table-column prop="alertDesc" label="报警描述" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="ownerUnit" label="权属单位" width="140" />
-        <el-table-column prop="address" label="详细地址" min-width="180" show-overflow-tooltip />
-        <el-table-column prop="status" label="工单状态" width="100" align="center">
+        <el-table-column prop="orderTypeText" label="工单类型" width="110" />
+        <el-table-column prop="orderDesc" label="问题描述" min-width="220" show-overflow-tooltip />
+        <el-table-column prop="deviceCode" label="设备编号" width="150" />
+        <el-table-column prop="orderStatusText" label="工单状态" width="110" align="center">
           <template #default="{ row }">
-            <el-tag :type="getStatusType(row.status)" size="small">
-              {{ getStatusText(row.status) }}
-            </el-tag>
+            <el-tag :type="row.orderStatusTag" size="small">{{ row.orderStatusText }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="createTime" label="创建时间" width="160" sortable />
-        <el-table-column label="操作" width="120" fixed="right" align="center">
+        <el-table-column prop="createTimeText" label="创建时间" width="170" />
+        <el-table-column prop="planFinishTimeText" label="计划完成时间" width="170" />
+        <el-table-column label="操作" width="150" fixed="right" align="center">
           <template #default="{ row }">
             <el-button link type="primary" size="small" @click.stop="viewDetail(row)">查看详情</el-button>
-            <el-button
-                v-if="row.status === 'pending'"
-                link type="success"
-                size="small"
-                @click.stop="handleOrder(row)"
-            >处理</el-button>
+            <el-button v-if="canAcceptOrder(row)" link type="warning" size="small" @click.stop="acceptOrder(row)">接单</el-button>
+            <el-button v-else-if="canStartRepair(row)" link type="success" size="small" @click.stop="startRepair(row)">开始维修</el-button>
+            <el-button v-else-if="canSubmitVerify(row)" link type="warning" size="small" @click.stop="submitVerify(row)">提交验收</el-button>
           </template>
         </el-table-column>
       </el-table>
 
-      <!-- 分页 -->
-      <div class="pagination-wrapper">
+      <div class="mt-4 flex justify-end border-t border-[#e9ecef] pt-3">
         <el-pagination
-            background
-            layout="total, sizes, prev, pager, next, jumper"
-            :total="filteredOrders.length"
-            v-model:current-page="currentPage"
-            v-model:page-size="pageSize"
-            :page-sizes="[10, 20, 50, 100]"
+          background
+          layout="total, sizes, prev, pager, next, jumper"
+          :total="filteredOrders.length"
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50]"
         />
       </div>
     </div>
 
-    <!-- 工单详情抽屉 -->
-    <el-drawer v-model="detailDrawerVisible" :title="`工单详情 - ${currentOrder?.code}`" size="500px" direction="rtl">
-      <div v-if="currentOrder" class="order-detail">
+    <el-drawer v-model="detailDrawerVisible" :title="`工单详情 - ${currentOrder?.orderNo || ''}`" size="540px" direction="rtl">
+      <div v-if="currentOrder" class="p-2" v-loading="detailLoading">
         <el-descriptions :column="1" border>
-          <el-descriptions-item label="工单编号">{{ currentOrder.code }}</el-descriptions-item>
-          <el-descriptions-item label="关联案件">
-            <el-link type="primary" @click="viewCaseDetail">{{ currentOrder.caseCode }}</el-link>
-          </el-descriptions-item>
-          <el-descriptions-item label="报警级别">
-            <el-tag :type="currentOrder.alertLevel === 'critical' ? 'danger' : 'warning'">
-              {{ currentOrder.alertLevel === 'critical' ? '严重' : '一般' }}
-            </el-tag>
-          </el-descriptions-item>
-          <el-descriptions-item label="报警类型">{{ currentOrder.alertType }}</el-descriptions-item>
-          <el-descriptions-item label="报警描述">{{ currentOrder.alertDesc }}</el-descriptions-item>
-          <el-descriptions-item label="权属单位">{{ currentOrder.ownerUnit }}</el-descriptions-item>
-          <el-descriptions-item label="详细地址">{{ currentOrder.address }}</el-descriptions-item>
-          <el-descriptions-item label="用途">{{ currentOrder.purpose || '市政排水' }}</el-descriptions-item>
+          <el-descriptions-item label="工单ID">{{ currentOrder.orderId || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="工单编号">{{ currentOrder.orderNo }}</el-descriptions-item>
+          <el-descriptions-item label="报警ID">{{ currentOrder.alarmId || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="案件ID">{{ currentOrder.caseId || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="关联案件编号">{{ currentOrder.caseNo || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="设备ID">{{ currentOrder.deviceId || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="设备编号">{{ currentOrder.deviceCode || '—' }}</el-descriptions-item>
           <el-descriptions-item label="工单状态">
-            <el-tag :type="getStatusType(currentOrder.status)">{{ getStatusText(currentOrder.status) }}</el-tag>
+            <el-tag :type="currentOrder.orderStatusTag">{{ currentOrder.orderStatusText }}</el-tag>
+          </el-descriptions-item>
+          <el-descriptions-item label="优先级">
+            <el-tag :type="currentOrder.orderLevelTag">{{ currentOrder.orderLevelText }}</el-tag>
           </el-descriptions-item>
-          <el-descriptions-item label="创建时间">{{ currentOrder.createTime }}</el-descriptions-item>
-          <el-descriptions-item label="指派人">{{ currentOrder.assignee || '未指派' }}</el-descriptions-item>
-          <el-descriptions-item label="计划完成时间">{{ currentOrder.deadline || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="工单类型">{{ currentOrder.orderTypeText }}</el-descriptions-item>
+          <el-descriptions-item label="问题描述">{{ currentOrder.orderDesc || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="负责部门ID">{{ currentOrder.deptId || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="设备类别">{{ currentOrder.equipmentTypeName || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="接单人ID">{{ currentOrder.receiveUser || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="派单人ID">{{ currentOrder.dispatchUser || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="派单时间">{{ currentOrder.dispatchTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="创建时间">{{ currentOrder.createTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="计划完成时间">{{ currentOrder.planFinishTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="延期原因">{{ currentOrder.delayedReason || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="延期截止时间">{{ currentOrder.delayedDeadlineText }}</el-descriptions-item>
+          <el-descriptions-item label="验收人ID">{{ currentOrder.verifyUser || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="验收时间">{{ currentOrder.verifyTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="实际完成时间">{{ currentOrder.realFinishTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="维修处置结果">{{ currentOrder.repairResult || '—' }}</el-descriptions-item>
+          <el-descriptions-item label="设备运维状态">{{ currentOrder.currentStatusText }}</el-descriptions-item>
+          <el-descriptions-item label="设备在线状态">{{ currentOrder.onlineStatusText }}</el-descriptions-item>
+          <el-descriptions-item label="设备报警状态">{{ currentOrder.alarmStatusText }}</el-descriptions-item>
+          <el-descriptions-item label="状态更新时间">{{ currentOrder.statusUpdateTimeText }}</el-descriptions-item>
+          <el-descriptions-item label="更新时间">{{ currentOrder.updateTimeText }}</el-descriptions-item>
         </el-descriptions>
 
-        <!-- 处理记录 -->
-        <div class="process-logs" v-if="currentOrder.processLogs?.length">
-          <div class="sub-title">处理记录</div>
-          <el-timeline>
-            <el-timeline-item v-for="log in currentOrder.processLogs" :key="log.id" :timestamp="log.time" :type="log.type">
-              {{ log.content }}
+        <div class="mt-4">
+          <div class="mb-3 mt-4 text-[14px] font-600 text-[#2c3e50]">处理记录</div>
+          <el-timeline v-if="currentOrder.workOrderLogList?.length">
+            <el-timeline-item
+              v-for="log in currentOrder.workOrderLogList"
+              :key="log.logId"
+              :timestamp="formatDateTime(log.operTime)"
+              :type="getLogType(log.operType)"
+            >
+              {{ log.operDesc }}
+              <span v-if="log.operUserName" class="ml-3 text-[12px] text-[#909399]">操作人: {{ log.operUserName }}</span>
             </el-timeline-item>
           </el-timeline>
+          <el-empty v-else description="暂无处理记录" :image-size="80" />
         </div>
 
-        <!-- 操作按钮 -->
-        <div class="detail-actions" v-if="currentOrder.status === 'pending'">
-          <el-button type="primary" @click="handleOrder(currentOrder)">开始处理</el-button>
-          <el-button type="warning" @click="openAssignDialog">指派人员</el-button>
+        <div class="mt-6 flex justify-end gap-3">
+          <el-button v-if="canAcceptOrder(currentOrder)" type="warning" @click="acceptOrder(currentOrder)">接单</el-button>
+          <el-button v-if="canStartRepair(currentOrder)" type="primary" @click="startRepair(currentOrder)">开始维修</el-button>
+          <el-button v-if="canSubmitVerify(currentOrder)" type="success" @click="submitVerify(currentOrder)">提交验收</el-button>
+          <el-button
+            v-if="canDelay(currentOrder)"
+            type="warning"
+            plain
+            @click="openDelayDialog(currentOrder)"
+          >
+            申请延期
+          </el-button>
         </div>
+        <el-alert
+          v-if="!hasOperationButtons(currentOrder)"
+          class="mt-4"
+          title="当前状态暂无可操作项"
+          type="info"
+          :closable="false"
+          show-icon
+        />
       </div>
     </el-drawer>
 
-    <!-- 指派人员对话框 -->
-    <el-dialog v-model="assignDialogVisible" title="指派维护人员" width="400px">
-      <el-form>
-        <el-form-item label="选择维护人员">
-          <el-select v-model="selectedWorkerId" placeholder="请选择" style="width: 100%">
-            <el-option v-for="worker in workers" :key="worker.id" :label="worker.name" :value="worker.id" />
-          </el-select>
+    <el-dialog v-model="delayDialogVisible" title="申请延期" width="420px">
+      <el-form label-width="88px">
+        <el-form-item label="截止时间">
+          <el-date-picker
+            v-model="delayDeadline"
+            type="datetime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择延期截止时间"
+            class="w-full"
+          />
         </el-form-item>
-        <el-form-item label="备注">
-          <el-input type="textarea" v-model="assignRemark" placeholder="可选,填写派单说明" rows="2" />
+        <el-form-item label="延期原因">
+          <el-input v-model="delayReason" type="textarea" rows="3" placeholder="请输入延期原因" />
         </el-form-item>
       </el-form>
       <template #footer>
-        <el-button @click="assignDialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="confirmAssign">确认指派</el-button>
+        <el-button @click="delayDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitDelay">提交</el-button>
       </template>
     </el-dialog>
   </div>
 </template>
 
 <script setup>
-import { ref, computed } from 'vue'
-import { List, Search, Refresh } from '@element-plus/icons-vue'
-import { ElMessage } from 'element-plus'
-
-// 模拟工单数据
-const mockOrders = ref([
-  {
-    id: 1, code: 'WO-20250402-001', caseCode: 'CASE-20250402-001', alertLevel: 'critical',
-    alertType: '倾斜超标', alertDesc: '井盖倾斜角度14.2°,超过阈值8°,有跌落风险',
-    ownerUnit: '市政工程管理处', address: '人民路与解放路口东50m', purpose: '主干道排水',
-    status: 'pending', createTime: '2025-04-02 14:25:00', assignee: null, deadline: '2025-04-03 14:25:00',
-    processLogs: [{ id: 1, time: '2025-04-02 14:25:00', content: '工单自动创建', type: 'info' }]
-  },
-  {
-    id: 2, code: 'WO-20250402-002', caseCode: 'CASE-20250402-002', alertLevel: 'critical',
-    alertType: '水位超限', alertDesc: '井下水位62cm,超过阈值40cm,溢水风险',
-    ownerUnit: '水务集团', address: '滨江路化工园区南门', purpose: '化工区雨水排放',
-    status: 'processing', createTime: '2025-04-02 14:00:00', assignee: '张建国', deadline: '2025-04-03 10:00:00',
-    processLogs: [
-      { id: 1, time: '2025-04-02 14:00:00', content: '工单自动创建', type: 'info' },
-      { id: 2, time: '2025-04-02 14:30:00', content: '已指派张建国前往处置', type: 'primary' }
-    ]
-  },
-  {
-    id: 3, code: 'WO-20250402-003', caseCode: 'CASE-20250402-003', alertLevel: 'warning',
-    alertType: '异常震动', alertDesc: '异常震动112mg,超过阈值80mg,疑似外力冲击',
-    ownerUnit: '市政设施管理处', address: '古城街北段树下', purpose: '老城区排水',
-    status: 'pending', createTime: '2025-04-02 12:15:00', assignee: null, deadline: '2025-04-03 12:15:00',
-    processLogs: [{ id: 1, time: '2025-04-02 12:15:00', content: '工单自动创建', type: 'info' }]
-  },
-  {
-    id: 4, code: 'WO-20250402-004', caseCode: 'CASE-20250402-004', alertLevel: 'warning',
-    alertType: '井盖开启异常', alertDesc: '井盖非正常开启',
-    ownerUnit: '市政工程管理处', address: '南港路旧车站段', purpose: '市政井盖',
-    status: 'overdue', createTime: '2025-04-01 10:30:00', assignee: '王大明', deadline: '2025-04-02 10:30:00',
-    processLogs: [
-      { id: 1, time: '2025-04-01 10:30:00', content: '工单创建', type: 'info' },
-      { id: 2, time: '2025-04-01 11:00:00', content: '指派王大明处置', type: 'primary' },
-      { id: 3, time: '2025-04-02 10:30:00', content: '工单已逾期,待处理', type: 'danger' }
-    ]
-  },
-  {
-    id: 5, code: 'WO-20250402-005', caseCode: 'CASE-20250402-005', alertLevel: 'critical',
-    alertType: '气体超标', alertDesc: '井下H₂S浓度28ppm,超过阈值15ppm',
-    ownerUnit: '生态环境局', address: '石化大道南侧', purpose: '化工区排污',
-    status: 'pending', createTime: '2025-04-02 09:20:00', assignee: null, deadline: '2025-04-03 09:20:00',
-    processLogs: [{ id: 1, time: '2025-04-02 09:20:00', content: '工单自动创建', type: 'info' }]
-  },
-  {
-    id: 6, code: 'WO-20250402-006', caseCode: 'CASE-20250402-006', alertLevel: 'warning',
-    alertType: '电池低电量', alertDesc: '设备电池电量仅剩12%,需及时更换',
-    ownerUnit: '市政设施管理处', address: '中央公园北门', purpose: '公园排水',
-    status: 'processing', createTime: '2025-04-02 08:45:00', assignee: '陈辉', deadline: '2025-04-03 08:45:00',
-    processLogs: [
-      { id: 1, time: '2025-04-02 08:45:00', content: '工单创建', type: 'info' },
-      { id: 2, time: '2025-04-02 09:30:00', content: '指派陈辉前往更换电池', type: 'primary' }
-    ]
-  }
-])
-
-// 维护人员列表
-const workers = ref([
-  { id: 'w1', name: '张建国 - 维修一组' },
-  { id: 'w2', name: '李志强 - 维修二组' },
-  { id: 'w3', name: '王大明 - 应急抢修队' },
-  { id: 'w4', name: '陈辉 - 巡检专员' },
-  { id: 'w5', name: '赵志远 - 抢修班' }
-])
-
-// 筛选状态
+import {computed, onMounted, ref} from 'vue'
+import {List, Refresh, Search} from '@element-plus/icons-vue'
+import {ElMessage} from 'element-plus'
+import {
+  getManholeWorkOrderDetail,
+  getManholeWorkOrderProcessingPage,
+  operManholeWorkOrder
+} from '@/api/pipeNetwork/basic'
+
+const DEFAULT_OPER_USER_ID = 1
+
+const orders = ref([])
+const loading = ref(false)
+const detailLoading = ref(false)
+const detailDrawerVisible = ref(false)
+const delayDialogVisible = ref(false)
+const currentOrder = ref(null)
 const searchKeyword = ref('')
-const alertLevelFilter = ref('')
-const statusFilter = ref('pending')  // 默认显示待处理
+const orderLevelFilter = ref('')
+const statusFilter = ref('')
 const currentPage = ref(1)
 const pageSize = ref(10)
-const loading = ref(false)
+const delayDeadline = ref('')
+const delayReason = ref('')
 
-// 弹窗/抽屉状态
-const detailDrawerVisible = ref(false)
-const assignDialogVisible = ref(false)
-const currentOrder = ref(null)
-const selectedWorkerId = ref('')
-const assignRemark = ref('')
+function formatDateTime(value) {
+  if (!value) return '—'
+  return String(value).replace('T', ' ')
+}
 
-// 计算属性
-const filteredOrders = computed(() => {
-  let list = mockOrders.value
+function getOrderLevelMeta(level) {
+  const map = {
+    1: { text: '紧急', tag: 'danger' },
+    2: { text: '一般', tag: 'warning' },
+    3: { text: '低', tag: 'info' }
+  }
+  return map[Number(level)] || { text: '—', tag: 'info' }
+}
 
-  // 状态筛选
-  if (statusFilter.value) {
-    list = list.filter(o => o.status === statusFilter.value)
+function getOrderTypeText(type) {
+  const map = {
+    1: '故障维修',
+    2: '日常巡检',
+    3: '设备保养'
   }
+  return map[Number(type)] || '—'
+}
 
-  // 报警级别筛选
-  if (alertLevelFilter.value) {
-    list = list.filter(o => o.alertLevel === alertLevelFilter.value)
+function getOrderStatusMeta(status) {
+  const map = {
+    1: { key: 'pending', text: '待派单', tag: 'danger' },
+    2: { key: 'pending', text: '待接单', tag: 'danger' },
+    3: { key: 'processing', text: '已接单', tag: 'warning' },
+    4: { key: 'processing', text: '处理中', tag: 'warning' },
+    5: { key: 'verify', text: '待验收', tag: 'primary' },
+    6: { key: 'completed', text: '已结案', tag: 'success' },
+    7: { key: 'completed', text: '已驳回', tag: 'danger' },
+    8: { key: 'verify', text: '延期审核', tag: 'warning' },
+    9: { key: 'completed', text: '已延期', tag: 'danger' }
   }
+  return map[Number(status)] || { key: '', text: '—', tag: 'info' }
+}
 
-  // 关键词搜索
-  if (searchKeyword.value) {
-    const kw = searchKeyword.value.toLowerCase()
-    list = list.filter(o =>
-        o.code.toLowerCase().includes(kw) ||
-        o.caseCode.toLowerCase().includes(kw) ||
-        o.address.toLowerCase().includes(kw)
-    )
+function getOnlineStatusText(status) {
+  const map = {
+    0: '离线',
+    1: '在线'
   }
+  return map[Number(status)] || '—'
+}
 
+function getAlarmStatusText(status) {
+  const map = {
+    0: '正常',
+    1: '报警'
+  }
+  return map[Number(status)] || '—'
+}
+
+function getCurrentStatusText(status) {
+  const map = {
+    1: '在用',
+    2: '闲置',
+    3: '维修',
+    4: '报废',
+    5: '待入库'
+  }
+  return map[Number(status)] || '—'
+}
+
+function normalizeOrder(item) {
+  const levelMeta = getOrderLevelMeta(item.orderLevel)
+  const statusMeta = getOrderStatusMeta(item.orderStatus)
+  return {
+    ...item,
+    orderLevelText: levelMeta.text,
+    orderLevelTag: levelMeta.tag,
+    orderTypeText: getOrderTypeText(item.orderType),
+    orderStatusKey: statusMeta.key,
+    orderStatusText: statusMeta.text,
+    orderStatusTag: statusMeta.tag,
+    createTimeText: formatDateTime(item.createTime),
+    dispatchTimeText: formatDateTime(item.dispatchTime),
+    planFinishTimeText: formatDateTime(item.planFinishTime),
+    delayedDeadlineText: formatDateTime(item.delayedDeadline),
+    realFinishTimeText: formatDateTime(item.realFinishTime),
+    verifyTimeText: formatDateTime(item.verifyTime),
+    updateTimeText: formatDateTime(item.updateTime),
+    currentStatusText: getCurrentStatusText(item.equipmentStatus?.currentStatus),
+    onlineStatusText: getOnlineStatusText(item.equipmentStatus?.onlineStatus),
+    alarmStatusText: getAlarmStatusText(item.equipmentStatus?.alarmStatus),
+    statusUpdateTimeText: formatDateTime(item.equipmentStatus?.statusUpdateTime)
+  }
+}
+
+function isOverdue(item) {
+  if (!item.planFinishTime) return false
+  return new Date(item.planFinishTime).getTime() < Date.now() && ![6, 7].includes(Number(item.orderStatus))
+}
+
+const filteredOrders = computed(() => {
+  let list = orders.value
+  if (statusFilter.value === 'pending') {
+    list = list.filter(item => item.orderStatusKey === 'pending')
+  } else if (statusFilter.value === 'processing') {
+    list = list.filter(item => item.orderStatusKey === 'processing' && !isOverdue(item))
+  } else if (statusFilter.value === 'overdue') {
+    list = list.filter(item => isOverdue(item))
+  }
   return list
 })
 
@@ -284,221 +341,185 @@ const paginatedOrders = computed(() => {
   return filteredOrders.value.slice(start, start + pageSize.value)
 })
 
-const totalOrders = computed(() => mockOrders.value.length)
-const pendingOrdersCount = computed(() => mockOrders.value.filter(o => o.status === 'pending').length)
-const processingOrdersCount = computed(() => mockOrders.value.filter(o => o.status === 'processing').length)
-const overdueCount = computed(() => mockOrders.value.filter(o => o.status === 'overdue').length)
+const totalOrders = computed(() => orders.value.length)
+const pendingOrdersCount = computed(() => orders.value.filter(item => item.orderStatusKey === 'pending').length)
+const processingOrdersCount = computed(() => orders.value.filter(item => item.orderStatusKey === 'processing' && !isOverdue(item)).length)
+const overdueCount = computed(() => orders.value.filter(item => isOverdue(item)).length)
 
-// 方法
-const setStatusFilter = (status) => {
-  statusFilter.value = status
-  currentPage.value = 1
-}
-
-const getStatusType = (status) => {
-  const map = { pending: 'danger', processing: 'warning', overdue: 'danger', completed: 'success' }
-  return map[status] || 'info'
-}
-
-const getStatusText = (status) => {
-  const map = { pending: '待处理', processing: '处理中', overdue: '已逾期', completed: '已完成' }
-  return map[status] || status
-}
-
-const refreshList = () => {
+async function loadOrders() {
   loading.value = true
-  setTimeout(() => {
+  try {
+    const keyword = searchKeyword.value.trim()
+    const payload = {
+      pageNum: 1,
+      pageSize: 200,
+      orderLevel: orderLevelFilter.value || undefined,
+      orderNo: keyword || undefined,
+      caseNo: keyword || undefined
+    }
+    const res = await getManholeWorkOrderProcessingPage(payload)
+    const records = Array.isArray(res?.data?.records) ? res.data.records : []
+    orders.value = records.map(normalizeOrder)
+    currentPage.value = 1
+    if (currentOrder.value) {
+      const matched = orders.value.find(item => item.orderId === currentOrder.value.orderId)
+      if (matched) {
+        await viewDetail(matched)
+      } else {
+        currentOrder.value = null
+        detailDrawerVisible.value = false
+      }
+    }
+  } catch (error) {
+    orders.value = []
+    currentOrder.value = null
+    ElMessage.error('经办工单加载失败')
+  } finally {
     loading.value = false
-    ElMessage.success('列表已刷新')
-  }, 500)
-}
-
-const handleRowClick = (row) => {
-  viewDetail(row)
+  }
 }
 
-const viewDetail = (order) => {
-  currentOrder.value = order
+async function viewDetail(order) {
+  detailLoading.value = true
   detailDrawerVisible.value = true
+  try {
+    const res = await getManholeWorkOrderDetail(order.orderId)
+    currentOrder.value = normalizeOrder(res?.data || order)
+  } catch (error) {
+    currentOrder.value = order
+    ElMessage.error('工单详情加载失败')
+  } finally {
+    detailLoading.value = false
+  }
 }
 
-const viewCaseDetail = () => {
-  ElMessage.info(`查看案件 ${currentOrder.value?.caseCode} 详情(演示)`)
+function handleRowClick(row) {
+  viewDetail(row)
 }
 
-const handleOrder = (order) => {
-  if (order.status === 'pending') {
-    // 如果未指派人员,先弹出指派对话框
-    if (!order.assignee) {
-      currentOrder.value = order
-      assignDialogVisible.value = true
+function setStatusFilter(status) {
+  statusFilter.value = status
+  currentPage.value = 1
+  if (detailDrawerVisible.value && currentOrder.value) {
+    const first = filteredOrders.value[0]
+    if (first) {
+      viewDetail(first)
     } else {
-      // 已有指派人,直接更新状态
-      order.status = 'processing'
-      order.processLogs.push({
-        id: Date.now(),
-        time: new Date().toLocaleString(),
-        content: `开始处理工单,负责人:${order.assignee}`,
-        type: 'primary'
-      })
-      ElMessage.success(`工单 ${order.code} 已开始处理`)
+      currentOrder.value = null
       detailDrawerVisible.value = false
     }
   }
 }
 
-const openAssignDialog = () => {
-  assignDialogVisible.value = true
-}
-
-const confirmAssign = () => {
-  if (!selectedWorkerId.value) {
-    ElMessage.warning('请选择维护人员')
-    return
-  }
-  const worker = workers.value.find(w => w.id === selectedWorkerId.value)
-  if (currentOrder.value) {
-    currentOrder.value.assignee = worker.name
-    currentOrder.value.status = 'processing'
-    currentOrder.value.processLogs.push({
-      id: Date.now(),
-      time: new Date().toLocaleString(),
-      content: `已指派 ${worker.name} 处理工单,备注:${assignRemark.value || '无'}`,
-      type: 'primary'
-    })
-    ElMessage.success(`工单已指派给 ${worker.name}`)
-  }
-  assignDialogVisible.value = false
-  selectedWorkerId.value = ''
-  assignRemark.value = ''
-  detailDrawerVisible.value = false
-}
-</script>
-
-<style scoped>
-.pending-orders {
-  background: #f0f2f6;
-  min-height: 100vh;
-  padding: 20px;
-}
-
-.page-header {
-  background: white;
-  border-radius: 16px;
-  padding: 16px 24px;
-  margin-bottom: 20px;
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-  flex-wrap: wrap;
-  gap: 12px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
-}
-
-.header-left {
-  display: flex;
-  align-items: center;
-  gap: 12px;
-}
-
-.header-left .title {
-  font-size: 20px;
-  font-weight: 600;
-  color: #1f2d3d;
+function canStartRepair(order) {
+  return Number(order.orderStatus) === 3
 }
 
-.header-right {
-  display: flex;
-  gap: 12px;
-  align-items: center;
-  flex-wrap: wrap;
+function canAcceptOrder(order) {
+  return Number(order.orderStatus) === 2
 }
 
-.stats-cards {
-  display: flex;
-  gap: 16px;
-  margin-bottom: 20px;
-  flex-wrap: wrap;
+function canSubmitVerify(order) {
+  return Number(order.orderStatus) === 4
 }
 
-.stat-card {
-  background: white;
-  border-radius: 12px;
-  padding: 12px 24px;
-  text-align: center;
-  cursor: pointer;
-  transition: all 0.2s;
-  min-width: 100px;
-  box-shadow: 0 1px 4px rgba(0,0,0,0.05);
+function canDelay(order) {
+  return [3, 4].includes(Number(order.orderStatus))
 }
 
-.stat-card:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+function hasOperationButtons(order) {
+  if (!order) return false
+  return canAcceptOrder(order) || canStartRepair(order) || canSubmitVerify(order) || canDelay(order)
 }
 
-.stat-card.active {
-  border: 2px solid #409eff;
-  background: #ecf5ff;
-}
-
-.stat-card.pending .stat-value { color: #f56c6c; }
-.stat-card.processing .stat-value { color: #e6a23c; }
-.stat-card.overdue .stat-value { color: #f56c6c; }
-
-.stat-value {
-  font-size: 28px;
-  font-weight: bold;
-}
-
-.stat-label {
-  font-size: 13px;
-  color: #606266;
-  margin-top: 4px;
-}
-
-.order-table-container {
-  background: white;
-  border-radius: 16px;
-  padding: 16px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.04);
+async function operateOrder(orderId, operType, operDesc, extra = {}) {
+  await operManholeWorkOrder({
+    orderId,
+    operType,
+    operDesc,
+    operUserId: DEFAULT_OPER_USER_ID,
+    ...extra
+  })
+  await loadOrders()
+  if (currentOrder.value?.orderId === orderId) {
+    const matched = orders.value.find(item => item.orderId === orderId)
+    if (matched) {
+      await viewDetail(matched)
+    }
+  }
 }
 
-.pagination-wrapper {
-  display: flex;
-  justify-content: flex-end;
-  margin-top: 16px;
-  padding-top: 12px;
-  border-top: 1px solid #e9ecef;
+async function startRepair(order) {
+  try {
+    await operateOrder(order.orderId, 4, '开始维修')
+    ElMessage.success('已开始维修')
+  } catch (error) {
+    ElMessage.error(error?.message || '开始维修失败')
+  }
 }
 
-.order-detail {
-  padding: 8px;
+async function acceptOrder(order) {
+  try {
+    await operateOrder(order.orderId, 3, '接单')
+    ElMessage.success('已接单')
+  } catch (error) {
+    ElMessage.error(error?.message || '接单失败')
+  }
 }
 
-.sub-title {
-  font-weight: 600;
-  margin: 16px 0 12px 0;
-  font-size: 14px;
-  color: #2c3e50;
+async function submitVerify(order) {
+  try {
+    await operateOrder(order.orderId, 5, '提交验收')
+    ElMessage.success('已提交验收')
+  } catch (error) {
+    ElMessage.error(error?.message || '提交验收失败')
+  }
 }
 
-.process-logs {
-  margin-top: 16px;
+function openDelayDialog(order) {
+  currentOrder.value = order
+  delayDeadline.value = ''
+  delayReason.value = ''
+  delayDialogVisible.value = true
 }
 
-.detail-actions {
-  margin-top: 24px;
-  display: flex;
-  gap: 12px;
-  justify-content: flex-end;
+async function submitDelay() {
+  if (!currentOrder.value?.orderId) return
+  if (!delayDeadline.value) {
+    ElMessage.warning('请选择延期截止时间')
+    return
+  }
+  if (!delayReason.value.trim()) {
+    ElMessage.warning('请输入延期原因')
+    return
+  }
+  try {
+    await operateOrder(currentOrder.value.orderId, 8, '申请延期', {
+      delayedReason: delayReason.value.trim(),
+      delayedDeadline: delayDeadline.value
+    })
+    delayDialogVisible.value = false
+    ElMessage.success('延期申请已提交')
+  } catch (error) {
+    ElMessage.error(error?.message || '延期申请失败')
+  }
 }
 
-:deep(.el-table__row) {
-  cursor: pointer;
+function getLogType(operType) {
+  const map = {
+    2: 'primary',
+    3: 'warning',
+    4: 'primary',
+    5: 'warning',
+    6: 'success',
+    7: 'danger',
+    8: 'warning',
+    9: 'success'
+  }
+  return map[Number(operType)] || 'info'
 }
 
-:deep(.el-table__row:hover) {
-  background-color: #f5f7fa;
-}
-</style>
+onMounted(() => {
+  loadOrders()
+})
+</script>