From 0747deb909af969ea3dac2a9babd185359bb7a45 Mon Sep 17 00:00:00 2001 From: hjhan Date: Thu, 30 Jul 2026 09:55:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=AD=A5=E9=AA=A43-b=20=E5=A4=9A?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E8=BF=9E=E7=BB=AD=E6=89=8B=E5=8A=A8=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=BA=94=E7=B4=AF=E8=AE=A1REV(=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BB=85=E6=9C=80=E5=90=8E=E8=B5=A2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:applyBondManualEdit 每次调用先重置全部 bondRev 再只标当前字段, 导致连续手动编辑多字段(不回车)时只有最后编辑的字段留 REV, 中间手工编辑字段的 REV 被静默抹掉,UI 与步骤3-b需求不符。 修复:applyBondManualEdit 改为累计 REV(仅置当前字段、保留其它已手工编辑字段的 REV), driver/AUTO 仍清。单字段编辑(步骤2/3)行为不变,无回归。 配套: - 更新 a2d2bb31 中3个旧断言("仅最后留REV")为断言累加,避免测试守护错误行为 - 文档约定3 补充"连续编辑多字段时各手动字段累计REV" swapCalc.js 为独立 script(?v=JsVersion),部署 dotnet publish 即生效,无需重建 bundle。 测试:bondCalc 全套 72 例通过。 --- .../fe-tests/bondCalc.integration.test.js | 25 +++++++++---------- .../wwwroot/Scripts/app/swaptrade/swapCalc.js | 12 ++++++--- YLErpWeb/wwwroot/Scripts/base/ylotc.base.js | 4 --- .../互换债券三字段互算踩坑总结与测试指南.md | 2 +- 4 files changed, 22 insertions(+), 21 deletions(-) delete mode 100644 YLErpWeb/wwwroot/Scripts/base/ylotc.base.js diff --git a/YLErpWeb/fe-tests/bondCalc.integration.test.js b/YLErpWeb/fe-tests/bondCalc.integration.test.js index 10f70267..b1a88e9f 100644 --- a/YLErpWeb/fe-tests/bondCalc.integration.test.js +++ b/YLErpWeb/fe-tests/bondCalc.integration.test.js @@ -674,7 +674,7 @@ describe('约定1/2/3 状态机:端到端转换', () => { // ---- 以下为步骤3-b 及多字段组合场景(文档明确列出但此前缺失) ---- - test('Step3-b 回车CP→改DP→改YD(均不回车) → 仅最后字段(YD)留REV,前面REV被覆盖', () => { + test('Step3-b 回车CP→改DP→改YD(均不回车) → DP与YD均累计REV(修复后行为)', () => { const item = makeBondItem(); // 步骤1:回车净价(CP) SwapCalc.applyBondCalcSuccess(item, 'CP'); @@ -685,20 +685,19 @@ describe('约定1/2/3 状态机:端到端转换', () => { SwapCalc.applyBondManualEdit(item, 'DP'); expect(item.bondRev).toEqual({ CP: false, DP: true, YD: false }); - // ★ 步骤3-b:不回车,又改收益率(YD) → DP的REV被覆盖,仅YD留REV + // ★ 步骤3-b:不回车,又改收益率(YD) → DP的REV保留、YD也标REV(累计,不再被覆盖) SwapCalc.applyBondManualEdit(item, 'YD'); expect(item.bondDriverType).toBeNull(); // 源已被清 expect(item.bondAuto).toEqual({ CP: false, DP: false, YD: false }); // AUTO 已清 - // ⚠️ 核心断言:applyBondManualEdit 每次重置全部 REV 再只标当前字段 - // 故多字段连续编辑时"最后赢",中间字段的 REV 静默丢失 - expect(item.bondRev).toEqual({ CP: false, DP: false, YD: true }); + // 核心断言:applyBondManualEdit 改为累计 REV,多字段连续手动编辑时每个改过的字段都留 REV + expect(item.bondRev).toEqual({ CP: false, DP: true, YD: true }); // 数值保持不变(约定3:编辑不联动) expect(item.PosiNetNoFeePrice).toBe(0.995); // 净价保留 expect(item.PosiGrossPrice).toBe(1.0); // 全价保留 expect(item.InitYtm).toBe(0.026); // 收益率保留 }); - test('Step3-b 变体:回车CP后连续编辑三字段(CP→DP→YD) → 仅最后(YD)留REV', () => { + test('Step3-b 变体:回车CP后连续编辑三字段(CP→DP→YD) → 三个字段均累计REV', () => { const item = makeBondItem(); SwapCalc.applyBondCalcSuccess(item, 'CP'); @@ -706,14 +705,14 @@ describe('约定1/2/3 状态机:端到端转换', () => { SwapCalc.applyBondManualEdit(item, 'CP'); // 先改源字段本身 expect(item.bondRev).toEqual({ CP: true, DP: false, YD: false }); - SwapCalc.applyBondManualEdit(item, 'DP'); // 再改第二个 → CP的REV被覆盖 - expect(item.bondRev).toEqual({ CP: false, DP: true, YD: false }); + SwapCalc.applyBondManualEdit(item, 'DP'); // 再改第二个 → CP的REV保留、DP也标REV + expect(item.bondRev).toEqual({ CP: true, DP: true, YD: false }); - SwapCalc.applyBondManualEdit(item, 'YD'); // 最后改第三个 → DP的REV被覆盖 - expect(item.bondRev).toEqual({ CP: false, DP: false, YD: true }); // 仅最后赢 + SwapCalc.applyBondManualEdit(item, 'YD'); // 最后改第三个 → 三者均累计 + expect(item.bondRev).toEqual({ CP: true, DP: true, YD: true }); // 全部累计,不再"最后赢" }); - test('Step3-b 三字段轮换编辑(CP→DP→YD→CP) → 仅最终(CP)留REV', () => { + test('Step3-b 三字段轮换编辑(CP→DP→YD→CP) → 三个字段均累计REV', () => { const item = makeBondItem(); SwapCalc.applyBondCalcSuccess(item, 'CP'); @@ -723,8 +722,8 @@ describe('约定1/2/3 状态机:端到端转换', () => { SwapCalc.applyBondManualEdit(item, 'YD'); SwapCalc.applyBondManualEdit(item, 'CP'); // 回到第一个 - // 无论轮换多少次,只有最后一次 applyBondManualEdit 的字段留 REV - expect(item.bondRev).toEqual({ CP: true, DP: false, YD: false }); + // 无论轮换多少次,每次编辑的字段都累计REV(不再"只有最后一次留REV") + expect(item.bondRev).toEqual({ CP: true, DP: true, YD: true }); expect(item.bondDriverType).toBeNull(); expect(item.bondAuto).toEqual({ CP: false, DP: false, YD: false }); }); diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js index 509fa7e2..df90bb43 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapCalc.js @@ -287,13 +287,19 @@ /** * 交互约定3(纯函数,jest 可测):编辑某字段但未回车(失焦/输入)时的标识落地。 * - 清除 源 与 AUTO 标识(不再代表任何已算结果); - * - 仅本字段标 bondRev[type]=true("REV"=人工输入),不联动另外两字段。 + * - 本字段标 bondRev[type]=true("REV"=人工输入),不联动另外两字段; + * - ★ 累计 REV(不清空其它已手工编辑字段的 REV):连续手动编辑多字段(不回车)时, + * 每个被改过的字段都保留 REV,使 UI 正确显示"全部为人工输入",且不会被后续计算器覆盖 + * (见文档步骤3-b)。此前的实现每次重置全部 REV 再只标当前字段,导致"只有最后编辑的字段留 REV", + * 中间手工编辑的字段 REV 被静默抹掉(步骤3-b 不满足需求)。 */ function applyBondManualEdit(state, type) { state.bondDriverType = null; state.bondAuto = { CP: false, DP: false, YD: false }; - state.bondRev = { CP: false, DP: false, YD: false }; - if (type) state.bondRev[type] = true; + if (!state.bondRev || typeof state.bondRev !== 'object') { + state.bondRev = { CP: false, DP: false, YD: false }; + } + if (type) state.bondRev[type] = true; // 累加:仅置当前字段,保留其它已手工编辑字段的 REV return state; } diff --git a/YLErpWeb/wwwroot/Scripts/base/ylotc.base.js b/YLErpWeb/wwwroot/Scripts/base/ylotc.base.js deleted file mode 100644 index 623799fe..00000000 --- a/YLErpWeb/wwwroot/Scripts/base/ylotc.base.js +++ /dev/null @@ -1,4 +0,0 @@ -(function (global) { - - -}(window)); \ No newline at end of file diff --git a/项目文档/互换债券三字段互算踩坑总结与测试指南.md b/项目文档/互换债券三字段互算踩坑总结与测试指南.md index d6e8b2c9..16af9ffc 100644 --- a/项目文档/互换债券三字段互算踩坑总结与测试指南.md +++ b/项目文档/互换债券三字段互算踩坑总结与测试指南.md @@ -14,7 +14,7 @@ **交互约定**: - **约定1**:在任一字段**敲回车** → 以该字段为"源"调计算器,反算另两个并覆盖。 - **约定2**:计算器调用成功→源字段标"源"、另两个标"AUTO";失败→保留源字段值、另两个清空、三标识全清。 -- **约定3**:编辑某字段(失焦/按键输入)但**未回车** → 不联动另两字段,清掉源/AUTO标识,仅本字段标"REV"(人工输入)。 +- **约定3**:编辑某字段(失焦/按键输入)但**未回车** → 不联动另两字段,清掉源/AUTO标识,本字段标"REV"(人工输入)。**连续手动编辑多字段(均不回车)时各被改过的字段均累计REV**(不清空其它已手工编辑字段的REV),使 UI 正确显示"全部为人工输入"、且后续计算器回写时不会被误覆盖。 ---