design.md 7.4 KB

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 ❌ 不受影响(独立查询)

向后兼容性

  • 分页参数 pagepage_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. 前端发送请求,携带 pagepage_size 和筛选参数
  2. 后端服务层构建查询,应用筛选条件
  3. 执行 COUNT 查询获取总数
  4. 执行分页查询(LIMIT/OFFSET)获取当前页数据
  5. 返回数据和分页元数据

Components and Interfaces

Backend Service Layer

修改 WorkRecordService.get_all() 方法:

@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 端点:

@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

{
  "success": true,
  "data": [...],
  "pagination": {
    "total": 150,
    "page": 1,
    "page_size": 20,
    "total_pages": 8
  },
  "message": "Work records retrieved successfully"
}

Frontend API Service

修改 workRecordApi.getAll() 调用:

getAll: (params) => api.get('/work-records', { 
  params: {
    ...params,
    page: params.page || 1,
    page_size: params.page_size || 20
  }
})

Frontend Component

修改 WorkRecordList 组件:

  • 添加 currentPagepageSize 状态
  • 添加 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 次迭代。