fix(after-sale): 订单详情弹窗不再渲染售后状态节点进程

订单详情弹窗的「售后记录」卡片把整条处理时间线铺在了卡片里,和点开
「查看详细」后的售后详细弹窗重复,卡片本身也被拉得很长。改为只保留状态
徽章 + 申请时间、原因/申请理由、退款金额与「查看详细」入口;完整处理记录
由售后详细弹窗独占呈现,信息不缺、入口也还在。

- 删掉卡片里的 orderDetailHandlingLogHtml(item.handling_log) 调用
- 连带删除随之无人调用的 orderDetailHandlingLogHtml / handlingEntryTitle /
  AFTER_SALE_STATUS_LABELS 三个助手
- recordPayload 仍带 handling_log,点开详情弹窗照旧能看到时间线
- modal-runtime.css 的时间线规则不动:售后详细弹窗还在用,无需重打包

验证:tests/widget-system/ 462 项、tests/admin/ 76 项通过;契约测试改为断言
订单详情弹窗不再出现 timeline 标记与三个助手,同时锁住「查看详细」载荷仍带
handling_log;node --check 通过。未做浏览器视觉验收。
This commit is contained in:
2026-10-09 18:12:48 +08:00
parent 039fa6d863
commit 36b3ba6f45
2 changed files with 8 additions and 38 deletions
-35
View File
@@ -111,39 +111,6 @@
return order && order.is_points ? amount + " " + String(order.currency_symbol || "积分") : "¥" + amount; return order && order.is_points ? amount + " " + String(order.currency_symbol || "积分") : "¥" + amount;
} }
// 处理记录时间线:与售后详细弹窗(order-after-sale.js)同款标记与样式,
// 由 modal-runtime.css 的 .aksrt-after-sale-timeline 规则统一呈现。
var AFTER_SALE_STATUS_LABELS = { pending: "待审核", processing: "处理中", rejected: "已拒绝", cancelled: "已取消", completed: "已完成" };
function handlingEntryTitle(entry) {
var status = String((entry && entry.status) || "");
if (String((entry && entry.source) || "") === "user") {
return status === "cancelled" ? "用户撤销售后" : "用户提交申请";
}
return AFTER_SALE_STATUS_LABELS[status] || status;
}
function orderDetailHandlingLogHtml(log) {
var entries = Array.isArray(log) ? log : [];
if (!entries.length) return "";
var html = '<div class="aksrt-after-sale-log"><ol class="aksrt-after-sale-timeline">';
entries.forEach(function (entry) {
var status = String((entry && entry.status) || "");
var note = String((entry && entry.note) || "");
html += '<li class="aksrt-after-sale-timeline__item is-' + escapeHtml(status) + '">';
html += '<span class="aksrt-after-sale-timeline__knot"></span>';
html += '<div class="aksrt-after-sale-timeline__body">';
// [节点][处理状态][时间] 同一行,处理备注另起一行
html += '<div class="aksrt-after-sale-timeline__head">' +
'<span class="aksrt-after-sale-timeline__status">' + escapeHtml(handlingEntryTitle(entry)) + '</span>' +
'<time class="aksrt-after-sale-timeline__time">' + escapeHtml(String((entry && entry.created_at) || "")) + '</time>' +
'</div>';
if (note !== "") {
html += '<p class="aksrt-after-sale-timeline__note">' + escapeHtml(note).replace(/\r\n|\r|\n/g, "<br>") + '</p>';
}
html += '</div></li>';
});
return html + '</ol></div>';
}
function colorfulHeader(title, icon) { function colorfulHeader(title, icon) {
return '<div class="modal-colorful-header colorful-bg jb-blue">' + return '<div class="modal-colorful-header colorful-bg jb-blue">' +
'<button type="button" class="close" data-aksrt-modal-close aria-label="关闭"><svg class="ic-close" aria-hidden="true"><use xlink:href="#icon-close"></use></svg></button>' + '<button type="button" class="close" data-aksrt-modal-close aria-label="关闭"><svg class="ic-close" aria-hidden="true"><use xlink:href="#icon-close"></use></svg></button>' +
@@ -226,8 +193,6 @@
html += '<dl class="aksrt-order-detail__after-sale-meta">'; html += '<dl class="aksrt-order-detail__after-sale-meta">';
html += "<div><dt>退款金额</dt><dd>" + escapeHtml(afterSaleAmount(item.refund_amount, order)) + "</dd></div>"; html += "<div><dt>退款金额</dt><dd>" + escapeHtml(afterSaleAmount(item.refund_amount, order)) + "</dd></div>";
html += "</dl>"; html += "</dl>";
// 处理记录时间线:左列绳结状态条与时间,右列处理备注;与售后详细弹窗同款结构。
html += orderDetailHandlingLogHtml(item.handling_log);
// 查看详细:逐记录构造售后详细弹窗载荷(after_sale.latest 指向本条记录); // 查看详细:逐记录构造售后详细弹窗载荷(after_sale.latest 指向本条记录);
// 再次申请仅对最新一条且订单级可再申请时开放(after_sales 按 id 倒序,首条即最新)。 // 再次申请仅对最新一条且订单级可再申请时开放(after_sales 按 id 倒序,首条即最新)。
var recordPayload = escapeHtml(JSON.stringify({ var recordPayload = escapeHtml(JSON.stringify({
@@ -529,13 +529,18 @@ test('frontend renders the handling log as a rope-knot timeline', () => {
assert.match(js, /'<div class="aksrt-after-sale-timeline__head">' \+/) assert.match(js, /'<div class="aksrt-after-sale-timeline__head">' \+/)
assert.match(js, /'<div class="aksrt-after-sale-timeline__body">';/) assert.match(js, /'<div class="aksrt-after-sale-timeline__body">';/)
// 订单详情弹窗:每条工单同样渲染时间线,载荷带上 handling_log // 订单详情弹窗:不再渲染售后状态节点进程,只保留状态徽章 + 原因 + 金额 + 「查看详细」;
// 完整处理记录由点开的售后详细弹窗呈现,载荷仍带上 handling_log
assert.ok(!center.includes('gatewayResultText'), 'dead gateway-result renderer must be removed') assert.ok(!center.includes('gatewayResultText'), 'dead gateway-result renderer must be removed')
assert.ok(!center.includes('<dt>渠道结果</dt>'), 'dead 渠道结果 row must be removed') assert.ok(!center.includes('<dt>渠道结果</dt>'), 'dead 渠道结果 row must be removed')
assert.ok(!center.includes('<dt>处理备注</dt>'), 'single 处理备注 row must be removed') assert.ok(!center.includes('<dt>处理备注</dt>'), 'single 处理备注 row must be removed')
assert.match(center, /function orderDetailHandlingLogHtml\(log\)/) assert.ok(!center.includes('orderDetailHandlingLogHtml'), 'order detail modal must not render the timeline')
assert.match(center, /orderDetailHandlingLogHtml\(item\.handling_log\)/) assert.ok(!center.includes('AFTER_SALE_STATUS_LABELS'), 'order detail modal must not carry timeline labels')
assert.ok(!center.includes('handlingEntryTitle'), 'order detail modal must not carry the timeline title helper')
assert.ok(!center.includes('aksrt-after-sale-timeline'), 'order detail modal must not emit timeline markup')
assert.match(center, /handling_log: Array\.isArray\(item\.handling_log\) \? item\.handling_log : \[\],/) assert.match(center, /handling_log: Array\.isArray\(item\.handling_log\) \? item\.handling_log : \[\],/)
// 「查看详细」入口保留:处理记录从这里点开
assert.match(center, /data-aksrt-after-sale-detail="' \+ recordPayload \+ '"/)
// 时间线样式:竖线穿节点、末项不收口,左列固定宽度、右列自适应 // 时间线样式:竖线穿节点、末项不收口,左列固定宽度、右列自适应
const css = read('assets/css/frontend/modal-runtime.css') const css = read('assets/css/frontend/modal-runtime.css')