AI-video-lifeplan-demo/.qoder/repowiki/zh/content/核心功能/财务数据建模与图表构建.md

323 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 财务数据建模与图表构建
<cite>
**本文引用的文件**
- [backend/data_builder.py](file://backend/data_builder.py)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts)
- [src/types.ts](file://src/types.ts)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx)
- [src/DualChartView.tsx](file://src/DualChartView.tsx)
- [src/mock-cashflow.json](file://src/mock-cashflow.json)
- [src/mock-data.json](file://src/mock-data.json)
- [PROJECT_README.md](file://PROJECT_README.md)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向开发者,系统性阐述财务数据建模与图表构建模块,重点解析后端 data_builder.py 如何将原始财务输入转化为可用于 Remotion 动画渲染的结构化时序数据;详解现金流模拟算法、资产耗尽预测模型与年度快照(YearlySnapshot)生成逻辑;说明 CashFlowDataSchema 与 YearlySnapshotSchema 的设计原则及与前端 Recharts 组件的映射关系;结合代码展示数据插值、单位转换与异常值处理的关键步骤;解释 render_props.json 中 charts 字段的构造流程,并提供自定义财务假设(通胀率、投资回报率、赤字利率)的配置方法;最后给出大数据量下的分段处理与性能优化建议。
## 项目结构
该模块位于 Python 后端与前端 Remotion 之间,通过 render_props.json 建立强类型契约,确保前后端数据一致。后端负责财务模拟与数据转换,前端负责动画渲染与交互。
```mermaid
graph TB
A["后端 data_builder.py<br/>金融模拟与数据转换"] --> B["render_props.json<br/>数据契约"]
B --> C["前端 Remotion 组件<br/>CashFlowChart.tsx / LifePlanChart.tsx / DualChartView.tsx"]
C --> D["Recharts 图表<br/>动态可视化"]
```
**图示来源**
- [backend/data_builder.py](file://backend/data_builder.py#L150-L200)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L135)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L1-L176)
**章节来源**
- [PROJECT_README.md](file://PROJECT_README.md#L132-L208)
## 核心组件
- FinancialSimulator:负责按年推进财务模拟,应用通胀、退休收入停止、事件成本、正负资产余额的不同收益/利息规则,生成 YearlySnapshot 列表。
- build_chart_data:从 PDF 提取参数,调用 FinancialSimulator,产出 assetDepletion 与 cashFlow 两套图表数据。
- YearlySnapshot 与 CashFlowData:前后端共同约定的数据结构,分别用于资产耗尽趋势与收支明细可视化。
- Recharts 组件:CashFlowChart 与 LifePlanChart 将上述数据结构映射到图表,支持动画与 HUD 信息同步。
**章节来源**
- [backend/data_builder.py](file://backend/data_builder.py#L15-L115)
- [backend/data_builder.py](file://backend/data_builder.py#L150-L200)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L68)
- [src/types.ts](file://src/types.ts#L1-L30)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
## 架构总览
后端 data_builder.py 以 FinancialSimulator 为核心,将 PDF 输入转换为两条时间线:
- 年度快照(YearlySnapshot):资产余额、收入/支出、事件标记、是否临界。
- 现金流明细(CashFlowData):按类别拆分的支出、净现金流、资产余额。
前端通过 render_props.json 接收两条时间线,CashFlowChart 与 LifePlanChart 分别消费这些数据,实现双视图联动与统一动画进度。
```mermaid
sequenceDiagram
participant PDF as "PDF 输入"
participant Builder as "data_builder.py"
participant Sim as "FinancialSimulator"
participant JSON as "render_props.json"
participant CF as "CashFlowChart"
participant LP as "LifePlanChart"
PDF->>Builder : 提取年龄/退休/寿命/资产/收入/支出/事件
Builder->>Sim : 传入财务参数与生命周期
Sim-->>Builder : 返回 YearlySnapshot 列表
Builder->>Builder : 构造 CashFlowData 列表
Builder->>JSON : 写入 charts.assetDepletion 与 charts.cashFlow
JSON->>CF : 传入 CashFlowData
JSON->>LP : 传入 YearlySnapshot
CF-->>CF : 动画与 HUD 更新
LP-->>LP : 动画与 HUD 更新
```
**图示来源**
- [backend/data_builder.py](file://backend/data_builder.py#L150-L200)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L135)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
## 详细组件分析
### 1) FinancialSimulator 与现金流模拟算法
- 财务参数默认值:通胀率、投资回报率、赤字利率,均可通过配置注入。
- 生命周期推进:从当前年龄到预期寿命,每年计算:
- 收入:退休前为年收入,退休后为 0。
- 通胀:支出按年通胀指数增长。
- 事件:匹配当年事件成本累加到支出。
- 净现金流:收入减去总支出。
- 资产更新:若资产余额非负,按投资回报率复利;否则按赤字利率复利(债务复合)。
- 输出:YearlySnapshot 列表,包含年份、年龄、收入/支出/资产余额、事件标签、是否临界。
```mermaid
flowchart TD
Start(["开始模拟"]) --> Init["初始化资产余额与年份"]
Init --> Loop{"年龄未达寿命?"}
Loop --> |是| YearCalc["计算当年收入/通胀支出/事件成本"]
YearCalc --> Net["计算净现金流"]
Net --> Balance{"资产余额>=0?"}
Balance --> |是| Invest["按投资回报率复利"]
Balance --> |否| Deficit["按赤字利率复利"]
Invest --> Snapshot["生成 YearlySnapshot"]
Deficit --> Snapshot
Snapshot --> Loop
Loop --> |否| End(["结束"])
```
**图示来源**
- [backend/data_builder.py](file://backend/data_builder.py#L24-L98)
**章节来源**
- [backend/data_builder.py](file://backend/data_builder.py#L15-L115)
### 2) YearlySnapshot 与 CashFlowData 的生成与映射
- YearlySnapshot:用于资产耗尽趋势图,包含年份、代表者与配偶年龄、收入/支出/资产余额、事件与临界标记。
- CashFlowData:用于收支明细图,包含年份、年龄、收入(合计)、各类支出(生活/住房/教育/税费/事件)、总支出、净现金流、资产余额。
- 数据映射:DualChartView 将 CashFlowData 转换为 YearlySnapshot 供 LifePlanChart 使用,保持统一动画进度与 HUD。
```mermaid
classDiagram
class YearlySnapshot {
+number year
+object ages
+object financials
+string[] events
+boolean isCritical
}
class CashFlowData {
+number year
+number age
+object income
+object expenses
+number totalExpense
+number netCashFlow
+number assetBalance
}
class FinancialSimulator {
+simulate_timeline(...)
+build_cashflow_data(timeline)
}
class DualChartView {
+convert CashFlowData -> YearlySnapshot
}
FinancialSimulator --> YearlySnapshot : "生成"
FinancialSimulator --> CashFlowData : "生成"
DualChartView --> YearlySnapshot : "转换"
```
**图示来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L68)
- [src/types.ts](file://src/types.ts#L1-L30)
- [backend/data_builder.py](file://backend/data_builder.py#L116-L148)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L48-L67)
**章节来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L18-L68)
- [src/types.ts](file://src/types.ts#L1-L30)
- [backend/data_builder.py](file://backend/data_builder.py#L116-L148)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L48-L67)
### 3) Recharts 组件与数据契约映射
- YearlySnapshotSchema:约束资产耗尽图的时间线结构,含货币单位与起始年份元数据。
- CashFlowDataSchema:约束收支明细图的时间线结构,含货币单位元数据。
- 组件职责:
- CashFlowChart:堆叠柱状图展示各类支出,折线展示收入,支持年进度插值与 HUD。
- LifePlanChart:面积图展示资产余额,支持年进度插值与渐变色(正负区间)。
- DualChartView:统一动画进度,将 CashFlowData 转 YearlySnapshot 供 LifePlanChart 使用。
```mermaid
sequenceDiagram
participant TS as "render-props-types.ts"
participant CF as "CashFlowChart"
participant LP as "LifePlanChart"
participant DCV as "DualChartView"
TS->>CF : YearlySnapshotSchema/CashFlowDataSchema
TS->>LP : YearlySnapshotSchema
DCV->>LP : 转换后的 YearlySnapshot[]
DCV->>CF : CashFlowData[]
CF-->>CF : 动画与 HUD
LP-->>LP : 动画与 HUD
```
**图示来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L140-L231)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L1-L176)
**章节来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L140-L231)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L1-L176)
### 4) 数据插值、单位转换与异常值处理
- 插值:
- LifePlanChart:在年与年之间进行线性插值,生成“当前年进度”的中间点,保证面积图平滑过渡。
- CashFlowChart:对当前年份内的支出条目按阶段顺序增长,同时生成一个“延伸点”以平滑收入线的视觉过渡。
- 单位转换:
- 元数据 currencyUnit 统一为“万円”,前端 Y 轴与 HUD 显示使用该单位。
- LifePlanChart 对大数值采用“亿”格式化显示。
- 异常值处理:
- 事件成本按年聚合,避免重复或遗漏。
- 资产余额为负时标记 isCritical,用于图表颜色与 HUD 提示。
- 当可视窗口小于固定长度时,填充空年份占位,避免坐标轴偏移。
**章节来源**
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L100-L141)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L320-L341)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L156-L210)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L211-L240)
- [backend/data_builder.py](file://backend/data_builder.py#L100-L115)
### 5) render_props.json 中 charts 字段的构造过程
- 构造函数 build_chart_data 读取 PDF 参数,调用 FinancialSimulator 生成两条时间线:
- assetDepletion:timeline 为 YearlySnapshot[],meta 包含 currencyUnit 与 startYear。
- cashFlow:timeline 为 CashFlowData[],meta 包含 currencyUnit。
- 前端通过 render-props-types.ts 的 Schema 校验,确保数据一致性。
**章节来源**
- [backend/data_builder.py](file://backend/data_builder.py#L150-L200)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L117-L135)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L202-L216)
### 6) 自定义财务假设配置方法
- 配置入口:FinancialSimulator 的构造函数接收 config 字典,支持以下键:
- inflation_rate:通胀率,默认 2%
- investment_return:投资回报率,默认 3%
- deficit_interest_rate:赤字利率(负资产时的复合成本),默认 15%
- 使用方式:在调用 build_chart_data 前,将上述键值放入 config 传入 FinancialSimulator。
**章节来源**
- [backend/data_builder.py](file://backend/data_builder.py#L18-L23)
- [backend/data_builder.py](file://backend/data_builder.py#L150-L200)
## 依赖关系分析
- 后端依赖:typing、math(用于幂运算与圆整)。
- 前端依赖:Remotion hooks(useCurrentFrame/useVideoConfig/interpolate)、Recharts(ComposedChart/AreaChart 等)、Zod(Schema 校验)。
- 类型契约:render-props-types.ts 定义 YearlySnapshotSchema 与 CashFlowDataSchema,确保前后端一致。
```mermaid
graph LR
DB["data_builder.py"] --> FS["FinancialSimulator"]
FS --> YS["YearlySnapshot"]
FS --> CFData["CashFlowData"]
RP["render-props-types.ts"] --> YSS["YearlySnapshotSchema"]
RP --> CFS["CashFlowDataSchema"]
CF["CashFlowChart.tsx"] --> YS
LP["LifePlanChart.tsx"] --> YS
DCV["DualChartView.tsx"] --> YS
```
**图示来源**
- [backend/data_builder.py](file://backend/data_builder.py#L15-L148)
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L140-L231)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L1-L176)
**章节来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L140-L231)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L1-L441)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L1-L349)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L1-L176)
## 性能考量
- 大数据量分段处理策略:
- 限制每帧可见数据长度:当可视窗口较短时,使用固定域与占位年份,避免 Recharts 重绘抖动。
- 使用 useMemo 缓存转换结果(如 DualChartView 将 CashFlowData 转 YearlySnapshot),减少组件重渲染。
- 动画插值仅在必要范围内计算,避免全量数据参与每帧运算。
- 数值稳定性:
- 对资产余额与支出进行圆整,减少浮点误差累积。
- Y 轴域基于完整时间线计算,避免动画过程中轴范围跳变。
- 渲染优化:
- 关闭内部动画(isAnimationActive=false),由外部帧进度驱动,降低 Recharts 内部开销。
- 使用稳定的配置对象(如 CHART_MARGIN)避免每次渲染创建新对象。
**章节来源**
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L166-L190)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L211-L240)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L48-L67)
## 故障排查指南
- 数据不一致:
- 检查 render-props-types.ts 的 YearlySnapshotSchema 与 CashFlowDataSchema 是否与后端输出一致。
- 使用 validateRenderProps 或 isRenderProps 进行运行时校验。
- 图表显示异常:
- 确认 meta.currencyUnit 与前端 Y 轴单位一致。
- 若出现坐标轴跳变,检查 Y 轴域计算逻辑(完整时间线 vs 可见数据)。
- 动画不同步:
- 确保 DualChartView 使用统一的外部索引与年进度参数传递给两个子图。
- 事件/临界状态错误:
- 检查事件成本聚合与 isCritical 标记逻辑,确保资产余额为负时正确标注。
**章节来源**
- [frontend/src/render-props-types.ts](file://frontend/src/render-props-types.ts#L237-L251)
- [src/DualChartView.tsx](file://src/DualChartView.tsx#L31-L76)
- [src/CashFlowChart.tsx](file://src/CashFlowChart.tsx#L358-L438)
- [src/LifePlanChart.tsx](file://src/LifePlanChart.tsx#L292-L343)
## 结论
本模块通过 FinancialSimulator 将 PDF 输入转化为两条高质量时序数据,借助 YearlySnapshot 与 CashFlowData 的清晰契约,实现了资产耗尽趋势与收支明细的双视图联动渲染。前后端通过 Zod Schema 严格约束数据结构,配合 Recharts 的插值与 HUD 机制,提供了流畅且可解释的财务可视化体验。通过合理的分段处理与缓存策略,可在大数据量场景下保持稳定性能。
## 附录
- 示例数据参考:
- [src/mock-cashflow.json](file://src/mock-cashflow.json#L1-L120)
- [src/mock-data.json](file://src/mock-data.json#L1-L61)