design.md 5.7 KB

Design Document: Yearly Dashboard Summary

Overview

本设计文档描述在仪表盘中添加年度汇总功能的技术实现方案。该功能将展示与Excel年度报表相同格式的数据,包括每人按月的收入统计和年度合计。

Architecture

系统架构

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

响应格式:

{
  "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
}

错误响应:

{
  "error": "年份无效,必须在 1900 到 9999 之间"
}

Backend Service

WorkRecordService.get_yearly_summary(year)

def get_yearly_summary(year: int) -> dict:
    """
    获取年度汇总数据,格式与Excel导出一致。
    
    Args:
        year: 年份
        
    Returns:
        包含年度汇总数据的字典
    """

Frontend API

workRecordApi.getYearlySummary

getYearlySummary: (params) => api.get('/work-records/yearly-summary', { params })

Frontend Component

Dashboard.jsx 修改

在现有月度报告下方添加年度汇总区域:

// 新增状态
const [selectedYear, setSelectedYear] = useState(dayjs())
const [yearlySummary, setYearlySummary] = useState(null)
const [yearlyLoading, setYearlyLoading] = useState(false)

// 新增年度汇总表格
<Card title="年度汇总">
  <DatePicker.YearPicker value={selectedYear} onChange={handleYearChange} />
  <Table columns={yearlySummaryColumns} dataSource={yearlySummary?.persons} />
</Card>

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 次迭代
  • 每个测试标注对应的设计属性编号