# 财务数据建模与图表构建 **本文引用的文件** - [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) ## 目录 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
金融模拟与数据转换"] --> B["render_props.json
数据契约"] B --> C["前端 Remotion 组件
CashFlowChart.tsx / LifePlanChart.tsx / DualChartView.tsx"] C --> D["Recharts 图表
动态可视化"] ``` **图示来源** - [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)