From 97796478b084c139c853d9211cd76267d52f6ac8 Mon Sep 17 00:00:00 2001 From: oliver Date: Fri, 18 Sep 2026 09:27:30 +0800 Subject: [PATCH] Show before/after values for all non-key compare result columns. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Key stays single-value; other fields always render a paired 前/后 cell so cutover diffs are readable at a glance. Co-authored-by: Cursor --- web/src/i18n/en.ts | 2 + web/src/i18n/zh.ts | 2 + web/src/index.css | 39 ++++++++ web/src/pages/network/BizComparePage.tsx | 109 ++++++++++++----------- 4 files changed, 102 insertions(+), 50 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 3bb12f3..2749f33 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -381,6 +381,8 @@ const en = { failFields: "Failed fields", failFieldsEmpty: "—", failWholeRow: "Whole row", + pairBefore: "Before", + pairAfter: "After", sheetAllPass: "All match", filterFailField: "Failed compare field", filterFailFieldAll: "Any failed field", diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 7e095d2..6f535c8 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -381,6 +381,8 @@ const zh = { failFields: "失败项", failFieldsEmpty: "—", failWholeRow: "整行", + pairBefore: "前", + pairAfter: "后", sheetAllPass: "全部一致", filterFailField: "失败比对项", filterFailFieldAll: "全部失败项", diff --git a/web/src/index.css b/web/src/index.css index 877a26e..d24de33 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -10735,8 +10735,47 @@ html.login-page--paused .login-page__flare { background: rgba(245, 158, 11, 0.08); } +.bs-cmp-pair { + display: flex; + flex-direction: column; + gap: 3px; + min-width: 4.5rem; +} + +.bs-cmp-pair__row { + display: grid; + grid-template-columns: 1.6em minmax(0, 1fr); + gap: 6px; + align-items: baseline; +} + +.bs-cmp-pair__tag { + flex: 0 0 auto; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.02em; + color: #64748b; + line-height: 1.3; +} + +.bs-cmp-val-cell--diff .bs-cmp-pair__row:first-child .bs-cmp-pair__tag { + color: #fca5a5; +} + +.bs-cmp-val-cell--diff .bs-cmp-pair__row:last-child .bs-cmp-pair__tag { + color: #86efac; +} + .bs-cmp-val { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; + color: #e2e8f0; + word-break: break-all; + line-height: 1.35; +} + +.bs-cmp-val.is-empty { + color: #64748b; + font-style: italic; } .bs-cmp-val--pre { diff --git a/web/src/pages/network/BizComparePage.tsx b/web/src/pages/network/BizComparePage.tsx index 2a945c1..22549da 100644 --- a/web/src/pages/network/BizComparePage.tsx +++ b/web/src/pages/network/BizComparePage.tsx @@ -138,6 +138,51 @@ function failFieldNames(d: DiffRow): string[] { return Object.keys(d.changes || {}); } +/** Non-key fields: always show before/after pair for cutover review. */ +function PairCell(props: { + beforeText: string; + afterText: string; + mismatch: boolean; + reason?: string; + beforeLabel: string; + afterLabel: string; +}) { + const { beforeText, afterText, mismatch, reason, beforeLabel, afterLabel } = props; + const pre = beforeText || "—"; + const post = afterText || "—"; + return ( + +
+
+ {beforeLabel} + + {pre} + +
+
+ {afterLabel} + + {post} + +
+
+ {reason ?
{reason}
: null} + + ); +} + function toggleInList(list: string[], name: string, on: boolean): string[] { if (on) return list.includes(name) ? list : [...list, name]; return list.filter((x) => x !== name); @@ -2263,58 +2308,22 @@ export function BizComparePage() { {resultColumns.extras.map((f) => { const pv = cellText(pre[f]); const av = cellText(post[f]); - const isCmp = resultColumns.compareSet.has(f); const ch = d.changes?.[f]; - if (!isCmp) { - const show = - d.kind === "removed" ? pv || "—" : av || pv || "—"; - return ( - - {show} - - ); - } - if (d.kind === "added") { - return ( - - - {av || "—"} - - - ); - } - if (d.kind === "removed") { - return ( - - - {pv || "—"} - - - ); - } - const mismatch = Boolean(ch); - if (!mismatch) { - return ( - - {pv || av || "—"} - - ); - } + const isCmp = resultColumns.compareSet.has(f); + // Compare fields: engine mismatch; display fields: value differ / side missing + const mismatch = isCmp + ? Boolean(ch) || d.kind === "added" || d.kind === "removed" + : pv !== av; return ( - - - {pv || "—"} - - - → - - - {av || "—"} - - {ch?.reason ? ( -
{ch.reason}
- ) : null} - + ); })}