feat(waybill): 优化打卡时间轴按打卡时间排序展示

- 新增 computed 属性 orderedWaybillPunchRecords,按打卡时间升序排序已打卡记录
- 未打卡记录保持后端返回的节点顺序,排在已打卡记录之后
- 引入方法 waybillPunchRecordTimestamp 解析打卡时间,支持多种日期格式
- 修正 el-timeline v-for 使用 orderedWaybillPunchRecords 避免 key 冲突
- 保持原有流程节点顺序不变,仅调整时间轴展示顺序
This commit is contained in:
2026-09-17 14:47:29 +08:00
parent 2684624979
commit 17c482e21a
2 changed files with 52 additions and 2 deletions
+12
View File
@@ -0,0 +1,12 @@
# 2026-09-17 工作日志
## 运单管理详情:打卡时间轴改为按打卡顺序展示
- 文件:`src/views/business/components/waybill-manage-page.vue`(详情页「执行详情 → 打卡详情」tab)
- 需求:时间轴不再固定按流程节点顺序(发货/在途/到货/卸货/签收/回单),改为按打卡时间先后展示。
- 实现(不改后端、不改原始数据):
1. 新增 computed `orderedWaybillPunchRecords`:映射出 `punchedAt`(毫秒时间戳)后排序 —— **已打卡记录按打卡时间升序排在前**,未打卡记录保持后端返回的节点顺序排在其后;时间相同用原索引稳定排序。
2. 新增 method `waybillPunchRecordTimestamp(record)``punched === false``statusName === '未打卡'` 直接返回 null(防止后端返回计划时间造成误序);优先 `this.$dayjs(text).valueOf()`,失败兜底 `new Date(text.replace(/-/g,'/'))`(兼容 Safari)。
3. 模板 `el-timeline``v-for` 改用 `orderedWaybillPunchRecords``key``record.nodeCode || record.id || index` 改为 `${nodeCode||id||'punch'}-${index}`,避免同节点多次打卡(在途)时 key 重复。
- 校验:项目根目录临时脚本 `_verify-sfc.mjs`@vue/compiler-sfc parse + compileScript + compileTemplate)通过,已删除脚本。
- 注意:`getPunchRecords``src/api/business/waybill-manage.js``/punch-records`)后端未提供节点排序字段,排序只能在前端做。
@@ -1923,6 +1923,12 @@
}}</strong }}</strong
> >
</div> </div>
<div
v-if="!waybillIsCarrier(detailRow)"
class="waybill-manage-page__waybill-detail-field"
>
<span>里程(km)</span><strong>{{ detailRow.mileage || '-' }}</strong>
</div>
</template> </template>
<template v-else-if="waybillIsNonRoadTransport(detailRow)"> <template v-else-if="waybillIsNonRoadTransport(detailRow)">
<div class="waybill-manage-page__waybill-detail-field"> <div class="waybill-manage-page__waybill-detail-field">
@@ -2029,8 +2035,8 @@
<div v-loading="waybillPunchRecordsLoading"> <div v-loading="waybillPunchRecordsLoading">
<el-timeline v-if="waybillPunchRecords.length"> <el-timeline v-if="waybillPunchRecords.length">
<el-timeline-item <el-timeline-item
v-for="(record, index) in waybillPunchRecords" v-for="(record, index) in orderedWaybillPunchRecords"
:key="record.nodeCode || record.id || index" :key="`${record.nodeCode || record.id || 'punch'}-${index}`"
:timestamp="record.punchTime || record.statusName || '未打卡'" :timestamp="record.punchTime || record.statusName || '未打卡'"
:type="record.punched ? 'primary' : 'info'" :type="record.punched ? 'primary' : 'info'"
:color="record.punched ? '#2b6ce8' : '#c0c4cc'" :color="record.punched ? '#2b6ce8' : '#c0c4cc'"
@@ -3545,6 +3551,25 @@ export default {
addBtn: this.canCreate, addBtn: this.canCreate,
}; };
}, },
//
//
orderedWaybillPunchRecords() {
const records = Array.isArray(this.waybillPunchRecords) ? this.waybillPunchRecords : [];
return records
.map((record, index) => ({
record,
index,
punchedAt: this.waybillPunchRecordTimestamp(record),
}))
.sort((a, b) => {
const aPunched = a.punchedAt !== null;
const bPunched = b.punchedAt !== null;
if (aPunched && bPunched) return a.punchedAt - b.punchedAt || a.index - b.index;
if (aPunched !== bPunched) return aPunched ? -1 : 1;
return a.index - b.index;
})
.map(item => item.record);
},
isStandaloneWaybillPage() { isStandaloneWaybillPage() {
return this.standaloneFormPage && standaloneWaybillFormPaths.includes(this.$route.path); return this.standaloneFormPage && standaloneWaybillFormPaths.includes(this.$route.path);
}, },
@@ -4492,6 +4517,19 @@ export default {
}) })
.catch(() => []); .catch(() => []);
}, },
// null
waybillPunchRecordTimestamp(record = {}) {
if (record.punched === false || record.statusName === '未打卡') return null;
const raw = record.punchTime || record.punchAt || record.punchDateTime || '';
const text = String(raw).trim();
if (!text) return null;
const parsed = this.$dayjs ? this.$dayjs(text) : null;
if (parsed && typeof parsed.isValid === 'function' && parsed.isValid()) {
return parsed.valueOf();
}
const fallback = new Date(text.replace(/-/g, '/')).getTime();
return Number.isNaN(fallback) ? null : fallback;
},
loadWaybillPunchRecords() { loadWaybillPunchRecords() {
const waybillId = this.detailRow?.id; const waybillId = this.detailRow?.id;
if (!waybillId || this.waybillPunchRecordsLoading) return; if (!waybillId || this.waybillPunchRecordsLoading) return;