diff --git a/YLErpWeb/fe-tests/diag.test.js b/YLErpWeb/fe-tests/diag.test.js index b47c3ff2..7a8ba756 100644 --- a/YLErpWeb/fe-tests/diag.test.js +++ b/YLErpWeb/fe-tests/diag.test.js @@ -135,6 +135,18 @@ describe('diag: 源码守卫(防回归——不许再硬编码易过期版本 expect(src).toMatch(/otcDebug\.banner|window\.ylotc\.__diag/); }); + test('swapTradeEdit.js 三字段调试埋点必须 gated(otcDebug.log),不得裸 console.log 退回', () => { + // 防回归:历史多次"改了不生效"靠日志兜底,曾出现①把 console.log 直接删了(出问题时看不见) + // ②或解除了开关控制(生产噪音)。正确做法是 otcDebug.log(?otcdebug=1 才输出)。 + const src = fs.readFileSync(path.join(SCRIPTS, 'app/swaptrade/swapTradeEdit.js'), 'utf8'); + // 存在 gated 埋点 + expect(src).toMatch(/otcDebug\.log\(/); + // 关键路径不得出现裸 console.log 调试行 + expect(src).not.toMatch(/console\.log\('\[onBondPriceKeydown\]/); + expect(src).not.toMatch(/console\.log\('\[calcBondForItem\]/); + expect(src).not.toMatch(/console\.log\('\[onBondPriceEdit\]/); + }); + test('fastVue.base.js 顶部 banner 不再硬编码 v20260729a', () => { const src = fs.readFileSync(path.join(SCRIPTS, 'fast/fastVue.base.js'), 'utf8'); expect(src).not.toContain('v20260729a'); diff --git a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js index 22914749..52858f91 100644 --- a/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js +++ b/YLErpWeb/wwwroot/Scripts/app/swaptrade/swapTradeEdit.js @@ -352,6 +352,7 @@ const vue = new Vue({ if (!item.isBond) return; SwapCalc.applyBondManualEdit(item, type); this.syncBondFlags(item); + otcDebug.log('[onBondPriceEdit] type=' + type + ' after: driver=' + item.bondDriverType + ' rev=' + JSON.stringify(item.bondRev)); }, //交互约定3(按键实时触发):vue-number-input 的 input 事件只在失焦/回车时触发, // 按键输入过程中不触发,导致用户输入时 源/AUTO 标识不会消失。 @@ -360,13 +361,19 @@ const vue = new Vue({ // 修饰键(Shift/Ctrl/Alt/Tab/方向键/F键等)除外——这些不改变数值,不应清标识。 onBondPriceKeydown(item, type, event) { if (!item.isBond) return; + var kc = event.which || event.keyCode; // 仅"会改变数值"的按键才清 源/AUTO 标识并标本字段 REV; // 回车/修饰键/导航键/功能键/纯 Shift 不改标识(见 SwapCalc.isBondPriceValueKey)。 // 修复:此前守卫漏掉 ↑(38)/↓(40)/Insert(45)/PageUp(33)/PageDown(34)/F键/Shift(16), // 导致"鼠标放进去没改值、只按了方向键/功能键"也会误标 REV。 if (!SwapCalc.isBondPriceValueKey(event)) return; + // 调试埋点(otcDebug 仅在 ?otcdebug=1 / localStorage.otcdebug=1 时输出,平时零噪音): + // 抓"逐键前后 driver/rev 变化",用于定位 REV 标记异常。 + otcDebug.log('[onBondPriceKeydown] type=' + type + ' kc=' + kc + + ' before: driver=' + item.bondDriverType + ' rev=' + JSON.stringify(item.bondRev)); SwapCalc.applyBondManualEdit(item, type); this.syncBondFlags(item); + otcDebug.log('[onBondPriceKeydown] after: driver=' + item.bondDriverType + ' rev=' + JSON.stringify(item.bondRev)); }, //确保 bondDriverType/bondAuto/bondRev 的变更触发 Vue 响应式更新。 //swapCalc.js 的纯函数直接对 state 赋值,但这些属性不在后端数据中(非响应式), @@ -433,6 +440,9 @@ const vue = new Vue({ // 该字段在页面上本就是可选择的日期控件(vue-datepicker),用户可改;现已默认即有。 // 不再"悄悄回退到交易日(TradeDate)"——真的为空时直接报错提示,由用户填写/手动填三数(需求2)。 var targetDate = (this.trade && this.trade.StartDate) ? this.trade.StartDate : null; + // 调试埋点(otcDebug 仅在 ?otcdebug=1 时输出):抓"回车→调计算器→源/结果"全链路,定位三字段互算异常。 + otcDebug.log('[calcBondForItem] enter driver=' + driver + ' priceType=' + priceType + + ' price(sent)=' + SwapCalc.bondPriceToCalc(price) + ' targetDate=' + targetDate); var sdMsg = SwapCalc.getBondStartDateMissingMsg(targetDate); if (sdMsg) { // D3 同款去重:开始日缺失时用户在价格格逐键输入会连刷相同提示,故同一文案只弹一次 @@ -466,6 +476,7 @@ const vue = new Vue({ if (SwapCalc.shouldShowBondErr(item, err)) main.message(err); SwapCalc.applyBondCalcFailure(item, driver); // 交互约定2:失败→清另两字段+标识 self.syncBondFlags(item); + otcDebug.log('[calcBondForItem] calc-error driver=' + driver + ' msg=' + err); return; } item._lastBondErr = null; // 成功则清标记,便于下次真出不同错误时仍能提示 @@ -487,6 +498,7 @@ const vue = new Vue({ item.InitYtm = SwapCalc.bondCalcPriceToStorage(proxy.ytm); SwapCalc.applyBondCalcSuccess(item, driver); // 交互约定2:成功→标 源/AUTO self.syncBondFlags(item); + otcDebug.log('[calcBondForItem] success driver=' + driver + ' auto=' + JSON.stringify(item.bondAuto) + ' rev=' + JSON.stringify(item.bondRev)); // 名义本金依赖全价(PosiGrossPrice):以净价/收益率为源反算出的全价被回写后, // 直接赋值不会触发组件 input 事件,需在此显式重算,保持名义本金与全价一致。 if (self.calcNotional) self.calcNotional(); @@ -501,6 +513,7 @@ const vue = new Vue({ // (与 .done 内 !resp.obj 分支行为一致;左侧 .done 的 getBondCalcErrorMessage 分支为兼容冗余,主路径在此)。 SwapCalc.applyBondCalcFailure(item, driver); self.syncBondFlags(item); + otcDebug.log('[calcBondForItem] post-fail/reject driver=' + driver); }); }, //变更收费基本单位