# Design Document: Yearly Dashboard Summary ## Overview 本设计文档描述在仪表盘中添加年度汇总功能的技术实现方案。该功能将展示与Excel年度报表相同格式的数据,包括每人按月的收入统计和年度合计。 ## Architecture ### 系统架构 ```mermaid graph TB subgraph Frontend Dashboard[Dashboard.jsx] YearlySummary[YearlySummaryTable Component] API[api.js] end subgraph Backend Routes[work_record_routes.py] Service[work_record_service.py] DB[(Database)] end Dashboard --> YearlySummary Dashboard --> API API --> Routes Routes --> Service Service --> DB ``` ### 数据流 1. 用户在仪表盘选择年份 2. 前端调用 `workRecordApi.getYearlySummary({ year })` 3. 后端 `WorkRecordService.get_yearly_summary(year)` 查询数据库 4. 返回按人员分组的月度收入数据 5. 前端渲染年度汇总表格 ## Components and Interfaces ### Backend API #### 新增端点: GET /api/work-records/yearly-summary **请求参数:** ``` year: integer (required) - 年份,如 2024 ``` **响应格式:** ```json { "year": 2024, "persons": [ { "person_id": 1, "person_name": "张三", "monthly_earnings": [100.00, 200.00, 150.00, ...], // 12个月的收入 "yearly_total": 1500.00 } ], "monthly_totals": [500.00, 600.00, ...], // 每月所有人的合计 "grand_total": 6000.00 } ``` **错误响应:** ```json { "error": "年份无效,必须在 1900 到 9999 之间" } ``` ### Backend Service #### WorkRecordService.get_yearly_summary(year) ```python def get_yearly_summary(year: int) -> dict: """ 获取年度汇总数据,格式与Excel导出一致。 Args: year: 年份 Returns: 包含年度汇总数据的字典 """ ``` ### Frontend API #### workRecordApi.getYearlySummary ```javascript getYearlySummary: (params) => api.get('/work-records/yearly-summary', { params }) ``` ### Frontend Component #### Dashboard.jsx 修改 在现有月度报告下方添加年度汇总区域: ```jsx // 新增状态 const [selectedYear, setSelectedYear] = useState(dayjs()) const [yearlySummary, setYearlySummary] = useState(null) const [yearlyLoading, setYearlyLoading] = useState(false) // 新增年度汇总表格 ``` ## Data Models ### 年度汇总响应模型 | 字段 | 类型 | 描述 | |------|------|------| | year | integer | 年份 | | persons | array | 人员汇总列表 | | persons[].person_id | integer | 人员ID | | persons[].person_name | string | 人员姓名 | | persons[].monthly_earnings | array[12] | 12个月的收入数组 | | persons[].yearly_total | float | 年度总收入 | | monthly_totals | array[12] | 每月所有人的合计 | | grand_total | float | 年度总计 | ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: Grand Total Correctness *For any* yearly summary response, the grand_total SHALL equal the sum of all persons' yearly_total values, and each monthly_totals[i] SHALL equal the sum of all persons' monthly_earnings[i]. **Validates: Requirements 1.3, 3.3** ### Property 2: API Response Structure *For any* valid year parameter, the API response SHALL contain a persons array where each entry includes person_id (integer), person_name (string), monthly_earnings (array of 12 numbers), and yearly_total (number). **Validates: Requirements 3.1, 3.2** ### Property 3: Dashboard-Export Consistency *For any* year and set of work records, the yearly summary data returned by the API SHALL produce identical person totals and monthly breakdowns as the Excel export yearly summary for the same year. **Validates: Requirements 4.1** ### Property 4: Monetary Precision *For any* monetary value in the yearly summary response, the value SHALL be rounded to exactly 2 decimal places. **Validates: Requirements 4.2** ### Property 5: Alphabetical Sorting *For any* yearly summary response with multiple persons, the persons array SHALL be sorted alphabetically by person_name. **Validates: Requirements 4.3** ## Error Handling | 场景 | 处理方式 | |------|----------| | 年份参数缺失 | 返回 400,错误信息:"缺少年份参数" | | 年份格式无效 | 返回 400,错误信息:"年份无效,必须在 1900 到 9999 之间" | | 无数据 | 返回空的 persons 数组,grand_total 为 0 | | 数据库错误 | 返回 500,记录错误日志 | ## Testing Strategy ### 单元测试 1. **API端点测试** - 测试有效年份返回正确数据 - 测试无效年份返回400错误 - 测试空数据年份返回空结果 2. **Service层测试** - 测试数据聚合逻辑 - 测试边界条件(年初、年末) ### 属性测试 使用 Hypothesis (Python) 进行属性测试: 1. **Property 1: Grand Total Correctness** - 生成随机工作记录数据 - 验证 grand_total = sum(yearly_totals) - 验证 monthly_totals[i] = sum(monthly_earnings[i]) 2. **Property 3: Dashboard-Export Consistency** - 生成随机年份和工作记录 - 比较 API 返回数据与 ExportService 计算结果 3. **Property 5: Alphabetical Sorting** - 生成随机人员名称 - 验证返回结果按字母顺序排列 ### 测试配置 - 属性测试最少运行 100 次迭代 - 每个测试标注对应的设计属性编号