本设计文档描述在仪表盘中添加年度汇总功能的技术实现方案。该功能将展示与Excel年度报表相同格式的数据,包括每人按月的收入统计和年度合计。
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
workRecordApi.getYearlySummary({ year })WorkRecordService.get_yearly_summary(year) 查询数据库请求参数:
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 之间"
}
def get_yearly_summary(year: int) -> dict:
"""
获取年度汇总数据,格式与Excel导出一致。
Args:
year: 年份
Returns:
包含年度汇总数据的字典
"""
getYearlySummary: (params) => api.get('/work-records/yearly-summary', { params })
在现有月度报告下方添加年度汇总区域:
// 新增状态
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>
| 字段 | 类型 | 描述 |
|---|---|---|
| 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 | 年度总计 |
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.
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
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
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
For any monetary value in the yearly summary response, the value SHALL be rounded to exactly 2 decimal places.
Validates: Requirements 4.2
For any yearly summary response with multiple persons, the persons array SHALL be sorted alphabetically by person_name.
Validates: Requirements 4.3
| 场景 | 处理方式 |
|---|---|
| 年份参数缺失 | 返回 400,错误信息:"缺少年份参数" |
| 年份格式无效 | 返回 400,错误信息:"年份无效,必须在 1900 到 9999 之间" |
| 无数据 | 返回空的 persons 数组,grand_total 为 0 |
| 数据库错误 | 返回 500,记录错误日志 |
API端点测试
Service层测试
使用 Hypothesis (Python) 进行属性测试:
Property 1: Grand Total Correctness
Property 3: Dashboard-Export Consistency
Property 5: Alphabetical Sorting