docs(valuation): 新增估值模块前端改造说明文档
记录: - 改造范围、路径A决策依据、方案对比(否决otcdms-ui/free-jqGrid的理由) - 分组配置映射表(需求字段 ↔ colModel.name ↔ 后端字段) - 缺失字段清单(TODO,待后端确认):标的类型/期间付息分红/付息方式/合约估值两口径/保证金利息/期间分红/预付金系列/TRS估值 - 已知约束:冻结列冲突绕法、setcolumnChooser兼容、导出口径区分 - 测试要点、后续工作
This commit is contained in:
@@ -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 新增「预付金」「汇总」两个分组
|
||||
Reference in New Issue
Block a user