管理端开发日记③:异常列表、统计与筛选

正常订单沿着固定状态向前走,异常订单则会突然岔路。异常管理页的目标不是简单罗列报错,而是帮助客服判断优先级、找到关联订单,并把工单送入正确的处置流程。
1. 组件拆分
入口文件 src/views/manage/exception-ticket/index.vue 主要负责组合:
| 组件 | 职责 |
|---|---|
ExceptionListFilters | 关键词、类型、来源、状态和级别筛选 |
TicketStatistics | 待处理、处理中、今日关闭、紧急工单统计 |
ExceptionTicketTable | 工单展示与操作入口 |
| 详情/关闭弹窗 | 查看证据与填写处理结果 |
ExceptionProcessPage | 取消、重派、补发的专用处置页 |
页面自身只管理“当前显示列表还是处置流程”,数据逻辑放进 useExceptionTicketList.js。这种拆分比在一个 .vue 文件里同时维护表格、弹窗和十几个接口清晰得多。
2. 查询条件与业务关键词
const query = reactive({ pageNum: 1, pageSize: 16, keyword: '', exceptionType: '', exceptionSource: '', processStatus: '', severityLevel: '', orderByColumn: 'createTime', isAsc: 'desc'})关键词不仅匹配异常编号,还要考虑订单号、手机号和 MMSI。服务端未一次性返回全部关联字段时,页面先获取工单,再补全订单资料。
3. 为什么需要订单信息补全
异常表保存的是 orderId,但管理人员真正会搜索和核对的是订单号、船名、收货人和 MMSI。组合式函数通过订单详情接口补齐:
async function enrichOrderInfo(rows) { const results = await Promise.allSettled( rows.map(item => getDeliveryOrder(item.orderId)) )
return rows.map((item, index) => ({ ...item, orderInfo: results[index].status === 'fulfilled' ? results[index].value.data : null }))}使用 Promise.allSettled 可以让某一张历史订单读取失败时,其余工单继续显示。补全后,页面再执行本地关键词匹配:
const haystack = [ item.exceptionOrderNo, item.orderInfo?.orderNo, item.orderInfo?.receiverPhone, item.orderInfo?.mmsi].join(' ').toLowerCase()这也说明了为什么界面不能直接展示 orderId:它是关联键,不是业务人员交流时使用的编号。
4. 统计卡片与列表必须使用同一口径
顶部统计包括:
- 待处理:尚未进入处置流程;
- 处理中:已经登记处置但未完成;
- 今日关闭:当天完成闭环;
- 紧急工单:严重级别较高且尚未关闭。
统计可以由后端专用接口返回,也可以在当前数据集上计算,但必须明确口径。分页列表的 16 条数据不能直接被误当成全部工单,否则统计会随翻页变化。
const statistics = computed(() => ({ pending: allRows.value.filter(isPending).length, processing: allRows.value.filter(isProcessing).length, closedToday: allRows.value.filter(isClosedToday).length, urgent: allRows.value.filter(isUrgentAndOpen).length}))5. 路由参数驱动列表和处置页
异常页面支持通过 exceptionId 与 processType 打开处置流程。有效类型只有:
const validProcessTypes = ['CANCEL', 'REDISPATCH', 'RESHIPMENT']当路由参数合法时显示 ExceptionProcessPage,否则回到列表。这样列表和流程仍处在管理端布局下,也能通过刷新或复制链接恢复当前工单。
6. 枚举集中管理
异常类型、来源、处理状态、严重程度和处置方式都放在 options.js 中。每个枚举同时提供值、文本和颜色,筛选器与表格共用同一份配置。
export const severityOptions = [ { value: 'NORMAL', label: '普通', type: 'info' }, { value: 'URGENT', label: '紧急', type: 'danger' }]集中枚举能防止同一个状态在筛选器叫“待处理”,在表格又叫“未处理”。文字统一看似小事,却直接影响客服是否理解流程。
7. 本篇小结
前端补全与 N+1 查询的取舍
逐条读取订单详情能够快速完成联调,但当一页有 16 条工单时,最坏会多出 16 个请求。当前实现通过 ID 去重、并发请求和失败容错控制影响;更长期的方案是让异常列表接口直接联表返回 orderNo、船名和联系方式,或者提供批量订单摘要接口。
短期:异常 rows → 去重 orderId → 并发详情 → 前端合并长期:异常列表 DTO 直接携带 OrderSummary页面还需要在筛选条件变化时重置页码和已选行,关闭详情弹窗后根据是否发生写操作决定是否刷新列表。筛选项多并不意味着每次输入都立刻请求,关键词可以在回车或点击查询时提交,枚举变化再即时刷新,减少无意义的往返。
这些细节最终都服务于同一目标:工单数量很多时,用户依然能稳定地找到那一张真正需要先处理的异常。
异常列表的核心是把“技术关联”翻译成“业务可读信息”,再按优先级送入处置链路。页面最终像一个交通指挥台:红灯不能只亮着,还得告诉人哪条路堵了、该往哪里绕。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!





























