diff --git a/项目文档/估值模块重构-前端改造说明.md b/项目文档/估值模块重构-前端改造说明.md new file mode 100644 index 00000000..ab1f2205 --- /dev/null +++ b/项目文档/估值模块重构-前端改造说明.md @@ -0,0 +1,181 @@ +# 估值模块重构 - 前端改造说明 + +> 对应需求:《估值模块V1》(`估值模块V1.pdf`) +> 分支:`glms/feature/1.4.2` +> 改造时间:2026-07 + +## 一、改造范围与决策 + +### 背景 +需求要求重构两个页面的互换相关 Tab: +1. **日终持仓风险_互换** 的「框架合约」Tab —— 适配内部盯市场景 +2. **每日估值报告** 的「互换估值」Tab —— 适配对客发送场景 + +### 决策:路径 A(改现有 jqGrid 前端) +经对比分析(详见下方"方案对比"),选择**直接改现有 jqGrid 前端**,理由: +- 计算逻辑全在后端 `SwapEodPositionService.cs`,前端只做格式化展示 —— 改动可控 +- 数据接口零改动,新旧同源,便于对比验证 +- 不换库(不升级到 free-jqGrid),零全站回归风险 +- 工作量最小 + +### 方案对比(已否决) +| 方案 | 否决理由 | +|------|----------| +| otcdms-ui 新建 Vue 页面 | 需加 Java 中转层,工作量大;数据仍来自 C#,未实现解耦 | +| 升级 free-jqGrid | 原生支持折叠,但需回归全站 40+ 处 grouping,风险过大 | + +## 二、改造内容 + +### 提交 1:通用工具(`utils.js`) +新增两个通用函数,所有 jqGrid 页面可复用: +- `main.initCollapsibleGroupHeaders(jgrid, groupConfig)`:生成合并表头 + 点击折叠/展开 +- `main.refreshCollapsibleGroupHeaders(jgrid)`:列重排后重建分组边界 +- `main.exportVisibleColumnsToExcel(jgrid, fileName)`:零依赖导出可见列为 Excel + +### 提交 2:框架合约 Tab(`EodPositionRisks.js`) +- colModel 按需求 2.2 分组重排(组内列连续) +- 字段命名对齐(预付金→保证金、利率端→利息端) +- 接入可折叠分组表头(7 组) +- **缺失字段已标注 TODO**(见第四节) + +### 提交 3:框架合约 Tab 导出 +- 恢复导出按钮(原被注释) +- 接入 `exportVisibleColumnsToExcel`,与折叠状态联动 + +### 提交 4:互换估值 Tab(`TradeMarketReport_EodPosition.js`) +- 新增分组配置(4 组),现有列顺序天然满足连续性,无需重排 +- 接入可折叠分组表头,保留异常行标红逻辑 +- 新增簿记账户筛选(需求 3.1) +- 新增「导出互换估值」按钮,与现有 DownLoadReport 独立 + +## 三、分组配置映射表 + +### 模块一:框架合约 Tab(`eodSwapGroupConfig`) + +| 分组 | 需求字段 | colModel.name | 后端字段 | +|------|----------|---------------|----------| +| 基本信息 | 交易日 | `position.ValueDate` | `eod_swap.ValueDate` | +| | 簿记账户 | `AssetBookName` | 关联 asset_unit | +| | 交易对手方 | `ClientName` | 关联 client | +| | 互换交易编码 | `SwapTradeNo` | `eod_swap.SwapTradeNo` | +| | 产品类型 | `StructureType` | trade.StructureType | +| | 互换类型 | `SwapTradeTypeStr` | 枚举翻译 | +| 名义本金 | 合约名义本金 | `position.NotionalValue` | `eod_swap.NotionalValue` | +| | 合约多头名义本金 | `position.NotionalValueLong` | 同上 | +| | 合约空头名义本金 | `position.NotionalValueShort` | 同上 | +| 标的市值 | 合约多头标的市值 | `position.MarketValueLong` | 计算字段 | +| | 合约空头标的市值 | `position.MarketValueShort` | 计算字段 | +| 浮动端 | 合约浮动端待实现收益 | `position.FloatingPnL` | `eod_swap.FloatingPnL` | +| 利息端 | 合约利息端待实现收益 | `position.InterestPnL` | `eod_swap.InterestPnL` | +| 保证金 | 收取对手方初始保证金 | `position.InitMarginGain` | 计算字段 | +| | 收取对手方维持保证金 | `position.PostionMarginGain` | 计算字段 | +| | 支付初始保证金 | `position.InitMarginLoss` | 计算字段 | +| | 支付维持保证金 | `position.PostionMarginLoss` | 计算字段 | +| 估值与实现收益 | 合约持仓价值 | `position.PostionValue` | `eod_swap.PostionValue` | +| | 合约当日实现收益 | `position.TdRealizedPnL` | `eod_swap.TdRealizedPnL` | +| | 合约已实现收益 | `position.RealizedPnL` | `eod_swap.RealizedPnL` | +| | DV | `position.dv01` | `eod_swap.dv01` | + +### 模块二:互换估值 Tab(`eodSwapValuationGroupConfig`) + +| 分组 | 需求字段 | colModel.name | 后端字段 | +|------|----------|---------------|----------| +| 基本信息 | 交易编号 | `TradeNumber` | trade.TradeNumber | +| | 确认书编号 | `ConfrimNo` | trade.ConfrimNo | +| | 交易对手 | `ClientName` | 关联 client | +| | 起始日 | `position.PosiStartDate` | swap_position.PosiStartDate | +| | 估值日 | `position.ValueDate` | swap_position.ValueDate | +| | 参考标的 | `position.UnderlyingCode` | swap_position.UnderlyingCode | +| 利率与规模 | 利差 | `InterestRate` | 计算字段 | +| | 基准利率 | `position.FloatRateUnderlyingCode` | swap_position | +| | 当日适用基准利率 | `position.FloatRate` | 计算字段 | +| | 标的名义金额 | `position.PosiNotionalValue` | swap_position | +| | 标的数量 | `position.PosiQuantity` | swap_position | +| | 期间付息 | `PeriodAmount` | 查询时现算 | +| 价格 | 期初标的交割全价 | `position.PosiGrossPrice` | swap_position | +| | 期初标的成交收益率 | `InitYtm` | trade_swap | +| | 期末标的交割全价 | `position.UnderlyingPrice` | swap_position | +| | 实际期限 | `DayCount` | 查询时现算 | +| 收益 | 浮动利率(绝对) | `FloatRateAbs` | 查询时现算 | +| | 利率收益金额 | `InterestAmount` | 查询时现算 | +| | 开仓交易费用 | `position.PosiFeePending` | swap_position | +| | 浮动收益金额 | `position.PosiProfitSum` | swap_position | +| | 净额结算金额 | `NetSettmentAmount` | 查询时现算 | + +## 四、缺失字段清单(TODO,待后端确认) + +以下需求字段本轮**未实现**,需后端确认数据来源后单独提交补充。 + +### 模块一(框架合约 Tab) + +| 需求字段 | 需求分组 | 后端状态 | 待办 | +|----------|----------|----------|------| +| 标的类型 | 基本信息 | 待确认 | 加 colModel,值"现券/ETF/指数" | +| 名义本金(概念性) | 基本信息 | 待确认 | 可能与合约名义本金重复 | +| 期间付息/分红 | 浮动端 | 待确认 | `eod_swap` 是否有此字段 | +| 付息方式 | 估值与实现收益 | 待确认 | 到期轧差/派息日支付,来源 trade 要素 | +| 合约估值(到期轧差口径) | 估值与实现收益 | 待确认 | `FloatingPnL + InterestPnL + 期间付息` | +| 合约估值(期间支付派息口径) | 估值与实现收益 | 待确认 | `FloatingPnL + InterestPnL` | +| 保证金利息(收取/支付) | 保证金 | 待确认 | 现状 colModel 无此字段 | + +### 模块二(互换估值 Tab) + +| 需求字段 | 需求分组 | 后端状态 | 待办 | +|----------|----------|----------|------| +| 期间分红 | 利率与规模 | 待确认 | ETF 适用 | +| 预付金利率 | 预付金(新分组) | 待确认 | | +| 预付金利息 | 预付金 | 待确认 | | +| 期初预付金 | 预付金 | 待确认 | 我方收取为正,支付为负 | +| 追加预付金 | 预付金 | 待确认 | 我方收取为正,支付为负 | +| TRS估值 | 汇总(新分组) | 待确认 | `净额结算金额 + 期初预付金 + 追加预付金` | + +## 五、已知约束 + +### 1. 冻结列与 groupHeader 冲突 +jqGrid 4.5.4 的 `setFrozenColumns` 与 `setGroupHeaders` 合用有限制。 +参考 `clientRiskMonitor.js:284-285` 的绕法:先 `destroyFrozenColumns` 再 `setFrozenColumns`。 +本改造的目标页面未使用冻结列,暂无影响。 + +### 2. setcolumnChooser 兼容 +`main.setcolumnChooser` 会 `remapColumns` 重排列,且不重建 groupHeader。 +解决方案:在 `gridComplete` 中用 `$.when(defer).done(...)` 确保 `setcolumnChooser` 完成后再初始化分组表头。 +若用户自定义列顺序打散了分组,`buildGroupHeaders` 会按实际可见列动态计算最接近的分组边界。 + +### 3. 导出口径区分 +| 导出方式 | 触发 | 数据源 | 口径 | +|----------|------|--------|------| +| 前端可见列导出(新增) | 「导出」按钮 | jqGrid 当前页数据 | 与页面显示一致 | +| 后端模板导出(现有) | `DownLoadReport` | C# Service | 报告格式,口径不同 | + +两者独立,需在 UI 和文档上区分,避免用户混淆。 + +### 4. 导出格式 +当前前端导出为 `.xls`(HTML table + ms-excel MIME),非严格 `.xlsx`。 +若需严格 xlsx,后续可引入 SheetJS(项目已有 `Statics/libs/export/excellentexport.js`,但无实际使用范例)。 + +## 六、测试要点 + +### 框架合约 Tab +1. 打开「风险控制-日终持仓风险_互换-框架合约」 +2. 表头按 7 组分组合并显示 +3. 点击各分组表头能收起(▶)/展开(▼) +4. 展开后列对齐不错位 +5. footer 汇总行(DV)不受折叠影响 +6. 「列设置」(configure.png)功能正常 +7. 点击「导出」生成 Excel,列与页面可见列一致 + +### 互换估值 Tab +1. 打开「结算管理-每日估值报告-互换估值」 +2. 表头按 4 组分组合并显示 +3. 折叠交互正常 +4. 异常行标红(dataError)不受影响 +5. 簿记账户筛选生效(需后端支持 BookId 参数) +6. 「导出互换估值」按钮可用 +7. 现有「发送报告/下载报告」功能不受影响 + +## 七、后续工作 + +1. **缺失字段补齐**(见第四节 TODO)—— 需后端确认字段来源 +2. **命名对齐回归** —— 预付金→保证金 改动需确认不影响现有用户习惯 +3. **导出格式升级** —— 若需严格 xlsx,引入 SheetJS +4. **预付金/TRS估值 分组** —— 缺失字段补齐后,互换估值 Tab 新增「预付金」「汇总」两个分组