# Design Document: Work Records Backend Pagination ## Overview 本设计实现工作记录列表的后端分页功能,将当前的一次性加载全部数据改为按需加载当前页数据。主要修改涉及后端服务层、API路由层和前端组件。 ### 影响范围分析 经代码分析,`WorkRecordService.get_all()` 方法仅在 `/work-records` GET 端点中被调用。其他功能模块(导出、汇总统计等)使用独立的查询方法,不受影响: | 模块 | 方法 | 影响 | |------|------|------| | 工作记录列表 | `get_all()` | ✅ 需要修改 | | 每日汇总 | `get_daily_summary()` | ❌ 不受影响 | | 月度汇总 | `get_monthly_summary()` | ❌ 不受影响 | | 年度汇总 | `get_yearly_summary()` | ❌ 不受影响 | | 批量结算 | `batch_update_settlement()` | ❌ 不受影响 | | 导出功能 | `ExportService` | ❌ 不受影响(独立查询) | ### 向后兼容性 - 分页参数 `page` 和 `page_size` 均为可选参数,有默认值 - 不传分页参数时,行为与原来一致(返回第1页,默认20条) - API 响应结构新增 `pagination` 字段,原有 `data` 字段保持不变 ## Architecture ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Frontend │ │ Backend API │ │ Database │ │ WorkRecordList │────▶│ /work-records │────▶│ WorkRecord │ │ │ │ │ │ │ │ - page │ │ - get_all() │ │ - LIMIT │ │ - page_size │ │ - pagination │ │ - OFFSET │ │ - total │ │ - filters │ │ - COUNT │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 分页流程 1. 前端发送请求,携带 `page`、`page_size` 和筛选参数 2. 后端服务层构建查询,应用筛选条件 3. 执行 COUNT 查询获取总数 4. 执行分页查询(LIMIT/OFFSET)获取当前页数据 5. 返回数据和分页元数据 ## Components and Interfaces ### Backend Service Layer 修改 `WorkRecordService.get_all()` 方法: ```python @staticmethod def get_all(person_id=None, start_date=None, end_date=None, year=None, month=None, is_settled=None, page=1, page_size=20): """Get work records with pagination and filters. Args: person_id: Filter by person ID (optional) start_date: Filter by start date (optional) end_date: Filter by end date (optional) year: Filter by year (optional) month: Filter by month 1-12 (optional) is_settled: Filter by settlement status (optional) page: Page number, starting from 1 (default: 1) page_size: Number of records per page (default: 20, max: 100) Returns: Dictionary with: - data: List of work record dictionaries - total: Total number of matching records - page: Current page number - page_size: Records per page - total_pages: Total number of pages """ ``` ### Backend API Layer 修改 `/work-records` GET 端点: ```python @work_record_ns.param('page', '页码,从1开始', type=int, default=1) @work_record_ns.param('page_size', '每页数量,默认20,最大100', type=int, default=20) ``` ### API Response Format ```json { "success": true, "data": [...], "pagination": { "total": 150, "page": 1, "page_size": 20, "total_pages": 8 }, "message": "Work records retrieved successfully" } ``` ### Frontend API Service 修改 `workRecordApi.getAll()` 调用: ```javascript getAll: (params) => api.get('/work-records', { params: { ...params, page: params.page || 1, page_size: params.page_size || 20 } }) ``` ### Frontend Component 修改 `WorkRecordList` 组件: - 添加 `currentPage` 和 `pageSize` 状态 - 添加 `total` 状态存储后端返回的总数 - 修改 Table 的 `pagination` 配置使用后端返回的 `total` - 添加 `onChange` 处理器响应分页变化 ## Data Models ### Pagination Parameters | 参数 | 类型 | 默认值 | 范围 | 说明 | |------|------|--------|------|------| | page | int | 1 | >= 1 | 页码,小于1时使用1 | | page_size | int | 20 | 1-100 | 每页数量,超出范围使用20 | ### Pagination Response | 字段 | 类型 | 说明 | |------|------|------| | total | int | 匹配筛选条件的总记录数 | | page | int | 当前页码 | | page_size | int | 每页数量 | | total_pages | int | 总页数,计算公式: ceil(total / page_size) | ## 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: Pagination Data Count Correctness *For any* valid page and page_size parameters, the number of records returned should equal `min(page_size, total - (page - 1) * page_size)` when page is within valid range, or 0 when page exceeds total_pages. **Validates: Requirements 1.4, 4.3** ### Property 2: Pagination Metadata Consistency *For any* pagination request, the returned metadata should satisfy: - `total_pages == ceil(total / page_size)` - `page == requested_page` (after normalization) - `page_size == requested_page_size` (after normalization) - `len(data) <= page_size` **Validates: Requirements 1.5** ### Property 3: Filter and Pagination Composition *For any* combination of filter parameters and pagination parameters, the returned `total` should equal the count of all records matching the filter criteria, and the returned data should be a correct subset of filtered records for the requested page. **Validates: Requirements 2.1, 2.2** ### Property 4: Sort Order Preservation *For any* pagination request, the returned records should be sorted by `work_date` descending, then by `id` ascending. This order should be consistent across all pages. **Validates: Requirements 2.3** ### Property 5: Boundary Parameter Normalization *For any* page < 1, the service should return page 1 data. *For any* page_size < 1 or page_size > 100, the service should use page_size = 20. **Validates: Requirements 4.1, 4.2** ## Error Handling | 场景 | 处理方式 | |------|----------| | page < 1 | 使用 page = 1 | | page_size < 1 或 > 100 | 使用 page_size = 20 | | page > total_pages | 返回空数据列表,分页元数据正确 | | 无匹配数据 | 返回空列表,total = 0,total_pages = 0 | ## Testing Strategy ### Unit Tests - 测试默认分页参数(不传 page/page_size) - 测试边界值处理(page=0, page=-1, page_size=0, page_size=101) - 测试空结果集的分页元数据 ### Property-Based Tests 使用 `hypothesis` 库进行属性测试: - **Property 1**: 生成随机 page/page_size,验证返回数据量正确 - **Property 2**: 生成随机请求,验证分页元数据一致性 - **Property 3**: 生成随机筛选条件和分页参数,验证筛选与分页组合正确 - **Property 4**: 生成随机分页请求,验证排序顺序 - **Property 5**: 生成边界参数,验证参数规范化 每个属性测试运行至少 100 次迭代。