handlingWorkO.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <!--经办工单-->
  2. <template>
  3. <div class="min-h-screen bg-[#f0f2f6] p-5">
  4. <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)]">
  5. <div class="flex items-center gap-3">
  6. <el-icon><List /></el-icon>
  7. <span class="text-[20px] font-600 text-[#1f2d3d]">经办工单</span>
  8. <el-tag type="danger" effect="dark" v-if="pendingOrdersCount > 0">待处理 {{ pendingOrdersCount }}</el-tag>
  9. </div>
  10. <div class="flex flex-wrap items-center gap-3">
  11. <el-input
  12. v-model="searchKeyword"
  13. placeholder="搜索工单编号/案件编号"
  14. clearable
  15. :prefix-icon="Search"
  16. class="w-[260px]"
  17. @keyup.enter="loadOrders"
  18. />
  19. <el-select v-model="orderLevelFilter" placeholder="优先级" clearable class="w-[120px]">
  20. <el-option label="紧急" :value="1" />
  21. <el-option label="一般" :value="2" />
  22. <el-option label="低" :value="3" />
  23. </el-select>
  24. <el-button type="primary" :icon="Refresh" @click="loadOrders">刷新</el-button>
  25. </div>
  26. </div>
  27. <div class="mb-5 flex flex-wrap gap-4">
  28. <div
  29. 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)]"
  30. :class="statusFilter === '' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
  31. @click="setStatusFilter('')"
  32. >
  33. <div class="text-[28px] font-bold">{{ totalOrders }}</div>
  34. <div class="mt-1 text-[13px] text-[#606266]">全部工单</div>
  35. </div>
  36. <div
  37. 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)]"
  38. :class="statusFilter === 'pending' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
  39. @click="setStatusFilter('pending')"
  40. >
  41. <div class="text-[28px] font-bold text-[#f56c6c]">{{ pendingOrdersCount }}</div>
  42. <div class="mt-1 text-[13px] text-[#606266]">待处理</div>
  43. </div>
  44. <div
  45. 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)]"
  46. :class="statusFilter === 'processing' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
  47. @click="setStatusFilter('processing')"
  48. >
  49. <div class="text-[28px] font-bold text-[#e6a23c]">{{ processingOrdersCount }}</div>
  50. <div class="mt-1 text-[13px] text-[#606266]">处理中</div>
  51. </div>
  52. <div
  53. 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)]"
  54. :class="statusFilter === 'overdue' ? 'border-2 border-[#409eff] bg-[#ecf5ff]' : 'border-2 border-transparent'"
  55. @click="setStatusFilter('overdue')"
  56. >
  57. <div class="text-[28px] font-bold text-[#f56c6c]">{{ overdueCount }}</div>
  58. <div class="mt-1 text-[13px] text-[#606266]">已逾期</div>
  59. </div>
  60. </div>
  61. <div class="rounded-2xl bg-white p-4 shadow-[0_2px_8px_rgba(0,0,0,0.04)]">
  62. <el-table :data="paginatedOrders" stripe border class="w-full" row-class-name="cursor-pointer" v-loading="loading" @row-click="handleRowClick">
  63. <el-table-column type="index" label="序号" width="55" align="center" />
  64. <el-table-column prop="orderNo" label="工单编号" min-width="170" />
  65. <el-table-column prop="caseNo" label="关联案件编号" min-width="170" />
  66. <el-table-column prop="orderLevelText" label="优先级" width="100" align="center">
  67. <template #default="{ row }">
  68. <el-tag :type="row.orderLevelTag" size="small">{{ row.orderLevelText }}</el-tag>
  69. </template>
  70. </el-table-column>
  71. <el-table-column prop="orderTypeText" label="工单类型" width="110" />
  72. <el-table-column prop="orderDesc" label="问题描述" min-width="220" show-overflow-tooltip />
  73. <el-table-column prop="deviceCode" label="设备编号" width="150" />
  74. <el-table-column prop="orderStatusText" label="工单状态" width="110" align="center">
  75. <template #default="{ row }">
  76. <el-tag :type="row.orderStatusTag" size="small">{{ row.orderStatusText }}</el-tag>
  77. </template>
  78. </el-table-column>
  79. <el-table-column prop="createTimeText" label="创建时间" width="170" />
  80. <el-table-column prop="planFinishTimeText" label="计划完成时间" width="170" />
  81. <el-table-column label="操作" width="150" fixed="right" align="center">
  82. <template #default="{ row }">
  83. <el-button link type="primary" size="small" @click.stop="viewDetail(row)">查看详情</el-button>
  84. <el-button v-if="canAcceptOrder(row)" link type="warning" size="small" @click.stop="acceptOrder(row)">接单</el-button>
  85. <el-button v-else-if="canStartRepair(row)" link type="success" size="small" @click.stop="startRepair(row)">开始维修</el-button>
  86. <el-button v-else-if="canSubmitVerify(row)" link type="warning" size="small" @click.stop="submitVerify(row)">提交验收</el-button>
  87. </template>
  88. </el-table-column>
  89. </el-table>
  90. <div class="mt-4 flex justify-end border-t border-[#e9ecef] pt-3">
  91. <el-pagination
  92. background
  93. layout="total, sizes, prev, pager, next, jumper"
  94. :total="filteredOrders.length"
  95. v-model:current-page="currentPage"
  96. v-model:page-size="pageSize"
  97. :page-sizes="[10, 20, 50]"
  98. />
  99. </div>
  100. </div>
  101. <el-drawer v-model="detailDrawerVisible" :title="`工单详情 - ${currentOrder?.orderNo || ''}`" size="540px" direction="rtl">
  102. <div v-if="currentOrder" class="p-2" v-loading="detailLoading">
  103. <el-descriptions :column="1" border>
  104. <el-descriptions-item label="工单ID">{{ currentOrder.orderId || '—' }}</el-descriptions-item>
  105. <el-descriptions-item label="工单编号">{{ currentOrder.orderNo }}</el-descriptions-item>
  106. <el-descriptions-item label="报警ID">{{ currentOrder.alarmId || '—' }}</el-descriptions-item>
  107. <el-descriptions-item label="案件ID">{{ currentOrder.caseId || '—' }}</el-descriptions-item>
  108. <el-descriptions-item label="关联案件编号">{{ currentOrder.caseNo || '—' }}</el-descriptions-item>
  109. <el-descriptions-item label="设备ID">{{ currentOrder.deviceId || '—' }}</el-descriptions-item>
  110. <el-descriptions-item label="设备编号">{{ currentOrder.deviceCode || '—' }}</el-descriptions-item>
  111. <el-descriptions-item label="工单状态">
  112. <el-tag :type="currentOrder.orderStatusTag">{{ currentOrder.orderStatusText }}</el-tag>
  113. </el-descriptions-item>
  114. <el-descriptions-item label="优先级">
  115. <el-tag :type="currentOrder.orderLevelTag">{{ currentOrder.orderLevelText }}</el-tag>
  116. </el-descriptions-item>
  117. <el-descriptions-item label="工单类型">{{ currentOrder.orderTypeText }}</el-descriptions-item>
  118. <el-descriptions-item label="问题描述">{{ currentOrder.orderDesc || '—' }}</el-descriptions-item>
  119. <el-descriptions-item label="负责部门ID">{{ currentOrder.deptId || '—' }}</el-descriptions-item>
  120. <el-descriptions-item label="设备类别">{{ currentOrder.equipmentTypeName || '—' }}</el-descriptions-item>
  121. <el-descriptions-item label="接单人ID">{{ currentOrder.receiveUser || '—' }}</el-descriptions-item>
  122. <el-descriptions-item label="派单人ID">{{ currentOrder.dispatchUser || '—' }}</el-descriptions-item>
  123. <el-descriptions-item label="派单时间">{{ currentOrder.dispatchTimeText }}</el-descriptions-item>
  124. <el-descriptions-item label="创建时间">{{ currentOrder.createTimeText }}</el-descriptions-item>
  125. <el-descriptions-item label="计划完成时间">{{ currentOrder.planFinishTimeText }}</el-descriptions-item>
  126. <el-descriptions-item label="延期原因">{{ currentOrder.delayedReason || '—' }}</el-descriptions-item>
  127. <el-descriptions-item label="延期截止时间">{{ currentOrder.delayedDeadlineText }}</el-descriptions-item>
  128. <el-descriptions-item label="验收人ID">{{ currentOrder.verifyUser || '—' }}</el-descriptions-item>
  129. <el-descriptions-item label="验收时间">{{ currentOrder.verifyTimeText }}</el-descriptions-item>
  130. <el-descriptions-item label="实际完成时间">{{ currentOrder.realFinishTimeText }}</el-descriptions-item>
  131. <el-descriptions-item label="维修处置结果">{{ currentOrder.repairResult || '—' }}</el-descriptions-item>
  132. <el-descriptions-item label="设备运维状态">{{ currentOrder.currentStatusText }}</el-descriptions-item>
  133. <el-descriptions-item label="设备在线状态">{{ currentOrder.onlineStatusText }}</el-descriptions-item>
  134. <el-descriptions-item label="设备报警状态">{{ currentOrder.alarmStatusText }}</el-descriptions-item>
  135. <el-descriptions-item label="状态更新时间">{{ currentOrder.statusUpdateTimeText }}</el-descriptions-item>
  136. <el-descriptions-item label="更新时间">{{ currentOrder.updateTimeText }}</el-descriptions-item>
  137. </el-descriptions>
  138. <div class="mt-4">
  139. <div class="mb-3 mt-4 text-[14px] font-600 text-[#2c3e50]">处理记录</div>
  140. <el-timeline v-if="currentOrder.workOrderLogList?.length">
  141. <el-timeline-item
  142. v-for="log in currentOrder.workOrderLogList"
  143. :key="log.logId"
  144. :timestamp="formatDateTime(log.operTime)"
  145. :type="getLogType(log.operType)"
  146. >
  147. {{ log.operDesc }}
  148. <span v-if="log.operUserName" class="ml-3 text-[12px] text-[#909399]">操作人: {{ log.operUserName }}</span>
  149. </el-timeline-item>
  150. </el-timeline>
  151. <el-empty v-else description="暂无处理记录" :image-size="80" />
  152. </div>
  153. <div class="mt-6 flex justify-end gap-3">
  154. <el-button v-if="canAcceptOrder(currentOrder)" type="warning" @click="acceptOrder(currentOrder)">接单</el-button>
  155. <el-button v-if="canStartRepair(currentOrder)" type="primary" @click="startRepair(currentOrder)">开始维修</el-button>
  156. <el-button v-if="canSubmitVerify(currentOrder)" type="success" @click="submitVerify(currentOrder)">提交验收</el-button>
  157. <el-button
  158. v-if="canDelay(currentOrder)"
  159. type="warning"
  160. plain
  161. @click="openDelayDialog(currentOrder)"
  162. >
  163. 申请延期
  164. </el-button>
  165. </div>
  166. <el-alert
  167. v-if="!hasOperationButtons(currentOrder)"
  168. class="mt-4"
  169. title="当前状态暂无可操作项"
  170. type="info"
  171. :closable="false"
  172. show-icon
  173. />
  174. </div>
  175. </el-drawer>
  176. <el-dialog v-model="delayDialogVisible" title="申请延期" width="420px">
  177. <el-form label-width="88px">
  178. <el-form-item label="截止时间">
  179. <el-date-picker
  180. v-model="delayDeadline"
  181. type="datetime"
  182. value-format="YYYY-MM-DD HH:mm:ss"
  183. placeholder="请选择延期截止时间"
  184. class="w-full"
  185. />
  186. </el-form-item>
  187. <el-form-item label="延期原因">
  188. <el-input v-model="delayReason" type="textarea" rows="3" placeholder="请输入延期原因" />
  189. </el-form-item>
  190. </el-form>
  191. <template #footer>
  192. <el-button @click="delayDialogVisible = false">取消</el-button>
  193. <el-button type="primary" @click="submitDelay">提交</el-button>
  194. </template>
  195. </el-dialog>
  196. </div>
  197. </template>
  198. <script setup>
  199. import {computed, onMounted, ref} from 'vue'
  200. import {List, Refresh, Search} from '@element-plus/icons-vue'
  201. import {ElMessage} from 'element-plus'
  202. import {
  203. getManholeWorkOrderDetail,
  204. getManholeWorkOrderProcessingPage,
  205. operManholeWorkOrder
  206. } from '@/api/pipeNetwork/basic'
  207. const DEFAULT_OPER_USER_ID = 1
  208. const orders = ref([])
  209. const loading = ref(false)
  210. const detailLoading = ref(false)
  211. const detailDrawerVisible = ref(false)
  212. const delayDialogVisible = ref(false)
  213. const currentOrder = ref(null)
  214. const searchKeyword = ref('')
  215. const orderLevelFilter = ref('')
  216. const statusFilter = ref('')
  217. const currentPage = ref(1)
  218. const pageSize = ref(10)
  219. const delayDeadline = ref('')
  220. const delayReason = ref('')
  221. function formatDateTime(value) {
  222. if (!value) return '—'
  223. return String(value).replace('T', ' ')
  224. }
  225. function getOrderLevelMeta(level) {
  226. const map = {
  227. 1: { text: '紧急', tag: 'danger' },
  228. 2: { text: '一般', tag: 'warning' },
  229. 3: { text: '低', tag: 'info' }
  230. }
  231. return map[Number(level)] || { text: '—', tag: 'info' }
  232. }
  233. function getOrderTypeText(type) {
  234. const map = {
  235. 1: '故障维修',
  236. 2: '日常巡检',
  237. 3: '设备保养'
  238. }
  239. return map[Number(type)] || '—'
  240. }
  241. function getOrderStatusMeta(status) {
  242. const map = {
  243. 1: { key: 'pending', text: '待派单', tag: 'danger' },
  244. 2: { key: 'pending', text: '待接单', tag: 'danger' },
  245. 3: { key: 'processing', text: '已接单', tag: 'warning' },
  246. 4: { key: 'processing', text: '处理中', tag: 'warning' },
  247. 5: { key: 'verify', text: '待验收', tag: 'primary' },
  248. 6: { key: 'completed', text: '已结案', tag: 'success' },
  249. 7: { key: 'completed', text: '已驳回', tag: 'danger' },
  250. 8: { key: 'verify', text: '延期审核', tag: 'warning' },
  251. 9: { key: 'completed', text: '已延期', tag: 'danger' }
  252. }
  253. return map[Number(status)] || { key: '', text: '—', tag: 'info' }
  254. }
  255. function getOnlineStatusText(status) {
  256. const map = {
  257. 0: '离线',
  258. 1: '在线'
  259. }
  260. return map[Number(status)] || '—'
  261. }
  262. function getAlarmStatusText(status) {
  263. const map = {
  264. 0: '正常',
  265. 1: '报警'
  266. }
  267. return map[Number(status)] || '—'
  268. }
  269. function getCurrentStatusText(status) {
  270. const map = {
  271. 1: '在用',
  272. 2: '闲置',
  273. 3: '维修',
  274. 4: '报废',
  275. 5: '待入库'
  276. }
  277. return map[Number(status)] || '—'
  278. }
  279. function normalizeOrder(item) {
  280. const levelMeta = getOrderLevelMeta(item.orderLevel)
  281. const statusMeta = getOrderStatusMeta(item.orderStatus)
  282. return {
  283. ...item,
  284. orderLevelText: levelMeta.text,
  285. orderLevelTag: levelMeta.tag,
  286. orderTypeText: getOrderTypeText(item.orderType),
  287. orderStatusKey: statusMeta.key,
  288. orderStatusText: statusMeta.text,
  289. orderStatusTag: statusMeta.tag,
  290. createTimeText: formatDateTime(item.createTime),
  291. dispatchTimeText: formatDateTime(item.dispatchTime),
  292. planFinishTimeText: formatDateTime(item.planFinishTime),
  293. delayedDeadlineText: formatDateTime(item.delayedDeadline),
  294. realFinishTimeText: formatDateTime(item.realFinishTime),
  295. verifyTimeText: formatDateTime(item.verifyTime),
  296. updateTimeText: formatDateTime(item.updateTime),
  297. currentStatusText: getCurrentStatusText(item.equipmentStatus?.currentStatus),
  298. onlineStatusText: getOnlineStatusText(item.equipmentStatus?.onlineStatus),
  299. alarmStatusText: getAlarmStatusText(item.equipmentStatus?.alarmStatus),
  300. statusUpdateTimeText: formatDateTime(item.equipmentStatus?.statusUpdateTime)
  301. }
  302. }
  303. function isOverdue(item) {
  304. if (!item.planFinishTime) return false
  305. return new Date(item.planFinishTime).getTime() < Date.now() && ![6, 7].includes(Number(item.orderStatus))
  306. }
  307. const filteredOrders = computed(() => {
  308. let list = orders.value
  309. if (statusFilter.value === 'pending') {
  310. list = list.filter(item => item.orderStatusKey === 'pending')
  311. } else if (statusFilter.value === 'processing') {
  312. list = list.filter(item => item.orderStatusKey === 'processing' && !isOverdue(item))
  313. } else if (statusFilter.value === 'overdue') {
  314. list = list.filter(item => isOverdue(item))
  315. }
  316. return list
  317. })
  318. const paginatedOrders = computed(() => {
  319. const start = (currentPage.value - 1) * pageSize.value
  320. return filteredOrders.value.slice(start, start + pageSize.value)
  321. })
  322. const totalOrders = computed(() => orders.value.length)
  323. const pendingOrdersCount = computed(() => orders.value.filter(item => item.orderStatusKey === 'pending').length)
  324. const processingOrdersCount = computed(() => orders.value.filter(item => item.orderStatusKey === 'processing' && !isOverdue(item)).length)
  325. const overdueCount = computed(() => orders.value.filter(item => isOverdue(item)).length)
  326. async function loadOrders() {
  327. loading.value = true
  328. try {
  329. const keyword = searchKeyword.value.trim()
  330. const payload = {
  331. pageNum: 1,
  332. pageSize: 200,
  333. orderLevel: orderLevelFilter.value || undefined,
  334. orderNo: keyword || undefined,
  335. caseNo: keyword || undefined
  336. }
  337. const res = await getManholeWorkOrderProcessingPage(payload)
  338. const records = Array.isArray(res?.data?.records) ? res.data.records : []
  339. orders.value = records.map(normalizeOrder)
  340. currentPage.value = 1
  341. if (currentOrder.value) {
  342. const matched = orders.value.find(item => item.orderId === currentOrder.value.orderId)
  343. if (matched) {
  344. await viewDetail(matched)
  345. } else {
  346. currentOrder.value = null
  347. detailDrawerVisible.value = false
  348. }
  349. }
  350. } catch (error) {
  351. orders.value = []
  352. currentOrder.value = null
  353. ElMessage.error('经办工单加载失败')
  354. } finally {
  355. loading.value = false
  356. }
  357. }
  358. async function viewDetail(order) {
  359. detailLoading.value = true
  360. detailDrawerVisible.value = true
  361. try {
  362. const res = await getManholeWorkOrderDetail(order.orderId)
  363. currentOrder.value = normalizeOrder(res?.data || order)
  364. } catch (error) {
  365. currentOrder.value = order
  366. ElMessage.error('工单详情加载失败')
  367. } finally {
  368. detailLoading.value = false
  369. }
  370. }
  371. function handleRowClick(row) {
  372. viewDetail(row)
  373. }
  374. function setStatusFilter(status) {
  375. statusFilter.value = status
  376. currentPage.value = 1
  377. if (detailDrawerVisible.value && currentOrder.value) {
  378. const first = filteredOrders.value[0]
  379. if (first) {
  380. viewDetail(first)
  381. } else {
  382. currentOrder.value = null
  383. detailDrawerVisible.value = false
  384. }
  385. }
  386. }
  387. function canStartRepair(order) {
  388. return Number(order.orderStatus) === 3
  389. }
  390. function canAcceptOrder(order) {
  391. return Number(order.orderStatus) === 2
  392. }
  393. function canSubmitVerify(order) {
  394. return Number(order.orderStatus) === 4
  395. }
  396. function canDelay(order) {
  397. return [3, 4].includes(Number(order.orderStatus))
  398. }
  399. function hasOperationButtons(order) {
  400. if (!order) return false
  401. return canAcceptOrder(order) || canStartRepair(order) || canSubmitVerify(order) || canDelay(order)
  402. }
  403. async function operateOrder(orderId, operType, operDesc, extra = {}) {
  404. await operManholeWorkOrder({
  405. orderId,
  406. operType,
  407. operDesc,
  408. operUserId: DEFAULT_OPER_USER_ID,
  409. ...extra
  410. })
  411. await loadOrders()
  412. if (currentOrder.value?.orderId === orderId) {
  413. const matched = orders.value.find(item => item.orderId === orderId)
  414. if (matched) {
  415. await viewDetail(matched)
  416. }
  417. }
  418. }
  419. async function startRepair(order) {
  420. try {
  421. await operateOrder(order.orderId, 4, '开始维修')
  422. ElMessage.success('已开始维修')
  423. } catch (error) {
  424. ElMessage.error(error?.message || '开始维修失败')
  425. }
  426. }
  427. async function acceptOrder(order) {
  428. try {
  429. await operateOrder(order.orderId, 3, '接单')
  430. ElMessage.success('已接单')
  431. } catch (error) {
  432. ElMessage.error(error?.message || '接单失败')
  433. }
  434. }
  435. async function submitVerify(order) {
  436. try {
  437. await operateOrder(order.orderId, 5, '提交验收')
  438. ElMessage.success('已提交验收')
  439. } catch (error) {
  440. ElMessage.error(error?.message || '提交验收失败')
  441. }
  442. }
  443. function openDelayDialog(order) {
  444. currentOrder.value = order
  445. delayDeadline.value = ''
  446. delayReason.value = ''
  447. delayDialogVisible.value = true
  448. }
  449. async function submitDelay() {
  450. if (!currentOrder.value?.orderId) return
  451. if (!delayDeadline.value) {
  452. ElMessage.warning('请选择延期截止时间')
  453. return
  454. }
  455. if (!delayReason.value.trim()) {
  456. ElMessage.warning('请输入延期原因')
  457. return
  458. }
  459. try {
  460. await operateOrder(currentOrder.value.orderId, 8, '申请延期', {
  461. delayedReason: delayReason.value.trim(),
  462. delayedDeadline: delayDeadline.value
  463. })
  464. delayDialogVisible.value = false
  465. ElMessage.success('延期申请已提交')
  466. } catch (error) {
  467. ElMessage.error(error?.message || '延期申请失败')
  468. }
  469. }
  470. function getLogType(operType) {
  471. const map = {
  472. 2: 'primary',
  473. 3: 'warning',
  474. 4: 'primary',
  475. 5: 'warning',
  476. 6: 'success',
  477. 7: 'danger',
  478. 8: 'warning',
  479. 9: 'success'
  480. }
  481. return map[Number(operType)] || 'info'
  482. }
  483. onMounted(() => {
  484. loadOrders()
  485. })
  486. </script>