feat(waybill): 优化打卡时间轴按打卡时间排序展示
- 新增 computed 属性 orderedWaybillPunchRecords,按打卡时间升序排序已打卡记录 - 未打卡记录保持后端返回的节点顺序,排在已打卡记录之后 - 引入方法 waybillPunchRecordTimestamp 解析打卡时间,支持多种日期格式 - 修正 el-timeline v-for 使用 orderedWaybillPunchRecords 避免 key 冲突 - 保持原有流程节点顺序不变,仅调整时间轴展示顺序
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user