fix(after-sale): 前台售后不再展示「退款金额」字段

并非每次售后都真的退款——换货、补偿、仅作记录的情况都会把工单标成已完成,
此时退款金额要么是 0 要么没有实际意义,摆在前台只会让人误解钱已经退回去了。
两个前台入口都撤掉该字段:

- 售后详细弹窗:明细行只留「申请时间」,处理记录时间线不受影响
- 订单详情弹窗的售后记录卡片:撤掉退款金额后 meta 的 dl 会空壳,连同
  dl 一起移除;卡片仍保留状态徽章 + 申请时间 + 原因 + 「查看详细」

连带清理死代码:aftersaleAmountText / afterSaleAmount 两个格式化助手各自
只剩这一处调用,orders.css 里 5 条 .aksrt-order-detail__after-sale-meta
规则也随之无人引用。后台售后页与订单明细页的退款金额列不动——那边是运营
核对账目的口径,需要看到金额。

验证:tests/widget-system/ 462 项、tests/admin/ 76 项通过;抽取
buildDetailHtml 跑样例载荷,确认退款金额不再出现、申请时间 / 处理记录 /
再次申请售后按钮都还在。未做浏览器视觉验收。
This commit is contained in:
2026-10-10 13:04:37 +08:00
parent 1875470ac7
commit 16b57dcf1c
4 changed files with 10 additions and 20 deletions
-5
View File
@@ -211,10 +211,5 @@ html.dark .aksrt-orders-page__stat, html.dark .aksrt-orders-page__card { backgro
.aksrt-order-detail__after-sale-badge { padding: 3px 11px; border-radius: 999px; background: color-mix(in srgb, var(--as-accent) 12%, transparent); color: var(--as-accent); font-size: 12px; font-weight: 700; line-height: 1.5; } .aksrt-order-detail__after-sale-badge { padding: 3px 11px; border-radius: 999px; background: color-mix(in srgb, var(--as-accent) 12%, transparent); color: var(--as-accent); font-size: 12px; font-weight: 700; line-height: 1.5; }
.aksrt-order-detail__after-sale-head time { color: var(--detail-muted); font-size: 11.5px; font-variant-numeric: tabular-nums; } .aksrt-order-detail__after-sale-head time { color: var(--detail-muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.aksrt-order-detail__after-sale-reason { margin: 0; color: var(--detail-ink); font-size: 13px; line-height: 1.65; white-space: pre-wrap; word-break: break-word; } .aksrt-order-detail__after-sale-reason { margin: 0; color: var(--detail-ink); font-size: 13px; line-height: 1.65; white-space: pre-wrap; word-break: break-word; }
.aksrt-order-detail__after-sale-meta { display: grid; margin: 0; overflow: hidden; border: 1px solid var(--detail-line); border-radius: 10px; background: var(--detail-surface-3); }
.aksrt-order-detail__after-sale-meta > div { display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--detail-line); font-size: 12.5px; }
.aksrt-order-detail__after-sale-meta > div:last-child { border-bottom: 0; }
.aksrt-order-detail__after-sale-meta dt { color: var(--detail-muted); }
.aksrt-order-detail__after-sale-meta dd { margin: 0; color: var(--detail-ink); font-size: 12.5px; text-align: right; word-break: break-word; }
.aksrt-order-detail__after-sale-field { color: var(--detail-muted); } .aksrt-order-detail__after-sale-field { color: var(--detail-muted); }
.aksrt-order-detail__after-sale-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; } .aksrt-order-detail__after-sale-foot { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
-6
View File
@@ -91,11 +91,6 @@
return '¥' + raw; return '¥' + raw;
} }
function aftersaleAmountText(value, order) {
var amount = String(value == null ? '' : value);
return order && order.is_points ? amount + ' ' + String((order && order.currency_symbol) || '积分') : '¥' + amount;
}
function orderSummaryHtml(order) { function orderSummaryHtml(order) {
if (!order) return ''; if (!order) return '';
return '<div class="muted-box padding-10 mb20 em09 aksrt-after-sale-summary">' + return '<div class="muted-box padding-10 mb20 em09 aksrt-after-sale-summary">' +
@@ -231,7 +226,6 @@
html += '<div class="aksrt-after-sale-detail__rows">'; html += '<div class="aksrt-after-sale-detail__rows">';
html += detailRow('申请时间', String(latest.created_at || '')); html += detailRow('申请时间', String(latest.created_at || ''));
html += detailRow('退款金额', aftersaleAmountText(latest.refund_amount, order));
html += '</div>'; html += '</div>';
// 处理记录:每次后台提交一条,替代原先单行的「处理备注 / 完成时间」。 // 处理记录:每次后台提交一条,替代原先单行的「处理备注 / 完成时间」。
html += handlingLogHtml(latest.handling_log); html += handlingLogHtml(latest.handling_log);
-8
View File
@@ -106,11 +106,6 @@
return "<div><dt>" + escapeHtml(label) + "</dt><dd>" + cell + "</dd></div>"; return "<div><dt>" + escapeHtml(label) + "</dt><dd>" + cell + "</dd></div>";
} }
function afterSaleAmount(value, order) {
var amount = String(value == null ? "" : value);
return order && order.is_points ? amount + " " + String(order.currency_symbol || "积分") : "¥" + amount;
}
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>' +
@@ -190,9 +185,6 @@
} else if (item.reason) { } else if (item.reason) {
html += '<p class="aksrt-order-detail__after-sale-reason">' + escapeHtml(item.reason).replace(/\r\n|\r|\n/g, "<br>") + "</p>"; html += '<p class="aksrt-order-detail__after-sale-reason">' + escapeHtml(item.reason).replace(/\r\n|\r|\n/g, "<br>") + "</p>";
} }
html += '<dl class="aksrt-order-detail__after-sale-meta">';
html += "<div><dt>退款金额</dt><dd>" + escapeHtml(afterSaleAmount(item.refund_amount, order)) + "</dd></div>";
html += "</dl>";
// 查看详细:逐记录构造售后详细弹窗载荷(after_sale.latest 指向本条记录); // 查看详细:逐记录构造售后详细弹窗载荷(after_sale.latest 指向本条记录);
// 再次申请仅对最新一条且订单级可再申请时开放(after_sales 按 id 倒序,首条即最新)。 // 再次申请仅对最新一条且订单级可再申请时开放(after_sales 按 id 倒序,首条即最新)。
var recordPayload = escapeHtml(JSON.stringify({ var recordPayload = escapeHtml(JSON.stringify({
@@ -533,12 +533,19 @@ test('frontend renders the handling log as a rope-knot timeline', () => {
assert.match(js, /'<span class="aksrt-after-sale-timeline__knot"><\/span>'/) assert.match(js, /'<span class="aksrt-after-sale-timeline__knot"><\/span>'/)
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">';/)
// 退款金额不展示:并非每次售后都真的退款,工单被标完成也不代表把钱退回去了
assert.ok(!js.includes("detailRow('退款金额'"), 'after-sale detail modal must not show 退款金额')
assert.ok(!js.includes('aftersaleAmountText'), 'dead aftersaleAmountText must be removed')
assert.match(js, /detailRow\('申请时间', String\(latest\.created_at \|\| ''\)\)/)
// 订单详情弹窗:不再渲染售后状态节点进程,只保留状态徽章 + 原因 + 金额 + 「查看详细」; // 订单详情弹窗:不再渲染售后状态节点进程与退款金额,只保留状态徽章 + 原因 + 「查看详细」;
// 完整处理记录由点开的售后详细弹窗呈现,载荷仍带上 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.ok(!center.includes('<dt>退款金额</dt>'), 'order detail card must not show 退款金额')
assert.ok(!center.includes('afterSaleAmount'), 'dead afterSaleAmount must be removed')
assert.ok(!center.includes('aksrt-order-detail__after-sale-meta'), 'empty meta dl must be removed')
assert.ok(!center.includes('orderDetailHandlingLogHtml'), 'order detail modal must not render the timeline') assert.ok(!center.includes('orderDetailHandlingLogHtml'), 'order detail modal must not render the timeline')
assert.ok(!center.includes('AFTER_SALE_STATUS_LABELS'), 'order detail modal must not carry timeline labels') 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('handlingEntryTitle'), 'order detail modal must not carry the timeline title helper')
@@ -555,6 +562,8 @@ test('frontend renders the handling log as a rope-knot timeline', () => {
assert.match(css, /\.aksrt-after-sale-timeline__head \{ display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; \}/) assert.match(css, /\.aksrt-after-sale-timeline__head \{ display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; \}/)
assert.match(css, /\.aksrt-after-sale-timeline__knot/) assert.match(css, /\.aksrt-after-sale-timeline__knot/)
assert.match(css, /\.aksrt-after-sale-timeline__note/) assert.match(css, /\.aksrt-after-sale-timeline__note/)
const ordersCss = read('assets/css/routes/orders.css')
assert.ok(!ordersCss.includes('aksrt-order-detail__after-sale-meta'), 'dead after-sale-meta rules must be removed')
// 旧的两列结构(aside / main)已移除 // 旧的两列结构(aside / main)已移除
assert.ok(!css.includes('aksrt-after-sale-timeline__aside'), 'left-column aside must be removed') assert.ok(!css.includes('aksrt-after-sale-timeline__aside'), 'left-column aside must be removed')
assert.ok(!css.includes('aksrt-after-sale-timeline__main'), 'right-column main must be removed') assert.ok(!css.includes('aksrt-after-sale-timeline__main'), 'right-column main must be removed')