design.md 8.2 KB

Design Document: Mobile Adaptation and Import Feature

Overview

本设计文档描述工作统计系统的手机适配和数据导入功能的技术实现方案。手机适配将通过CSS媒体查询和Ant Design的响应式组件实现;导入功能将在后端使用openpyxl解析XLSX文件,前端使用Ant Design的Upload组件。

Architecture

系统架构图

graph TB
    subgraph Frontend
        A[index.html] --> B[Viewport Meta]
        C[Layout.jsx] --> D[Responsive Sider]
        E[Components] --> F[Mobile CSS]
        G[Import.jsx] --> H[Upload Component]
    end
    
    subgraph Backend
        I[import_routes.py] --> J[ImportService]
        J --> K[Template Generator]
        J --> L[XLSX Parser]
        L --> M[Data Validator]
        M --> N[WorkRecord Creator]
    end
    
    H -->|POST /api/import/upload| I
    H -->|GET /api/import/template| I

技术栈

  • 前端: React + Ant Design (响应式组件)
  • 后端: Flask + openpyxl (XLSX处理)
  • 样式: CSS Media Queries + Ant Design Grid

Components and Interfaces

1. Viewport Configuration (index.html)

修改viewport meta标签以禁止用户缩放:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />

2. Responsive Layout Component (Layout.jsx)

增强现有Layout组件以支持移动端:

// 移动端检测
const [isMobile, setIsMobile] = useState(window.innerWidth < 768)

// 移动端使用Drawer替代Sider
{isMobile ? (
  <Drawer placement="left" onClose={toggleMenu} open={menuVisible}>
    <Menu items={menuItems} onClick={handleMenuClick} />
  </Drawer>
) : (
  <Sider collapsible collapsed={collapsed}>
    <Menu items={menuItems} onClick={handleMenuClick} />
  </Sider>
)}

3. Import Service (Backend)

新增 backend/app/services/import_service.py:

class ImportService:
    REQUIRED_COLUMNS = ['人员姓名', '物品名称', '工作日期', '数量']
    MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB
    
    @staticmethod
    def generate_template() -> BytesIO:
        """生成导入模板XLSX文件"""
        pass
    
    @staticmethod
    def parse_and_validate(file_content: bytes) -> Tuple[List[dict], List[str]]:
        """解析并验证XLSX文件内容
        Returns: (valid_records, errors)
        """
        pass
    
    @staticmethod
    def import_records(records: List[dict]) -> int:
        """批量创建工作记录
        Returns: 成功导入的记录数
        """
        pass

4. Import Routes (Backend)

新增 backend/app/routes/import_routes.py:

@import_bp.route('/template', methods=['GET'])
def download_template():
    """下载导入模板"""
    pass

@import_bp.route('/upload', methods=['POST'])
def upload_import():
    """上传并导入XLSX文件"""
    pass

5. Import Component (Frontend)

新增 frontend/src/components/Import.jsx:

function Import() {
  // 模板下载
  const handleDownloadTemplate = async () => { ... }
  
  // 文件上传
  const handleUpload = async (file) => { ... }
  
  return (
    <Card>
      <Button onClick={handleDownloadTemplate}>下载导入模板</Button>
      <Upload beforeUpload={handleUpload} accept=".xlsx">
        <Button>选择文件上传</Button>
      </Upload>
      {errors && <Alert type="error" message={errors} />}
      {success && <Alert type="success" message={success} />}
    </Card>
  )
}

6. API Extensions

扩展 frontend/src/services/api.js:

export const importApi = {
  downloadTemplate: () => axios.get('/api/import/template', { responseType: 'blob' }),
  upload: (file) => {
    const formData = new FormData()
    formData.append('file', file)
    return api.post('/api/import/upload', formData, {
      headers: { 'Content-Type': 'multipart/form-data' }
    })
  }
}

Data Models

Import Template Structure

列名 字段 类型 说明
人员姓名 person_name string 必须匹配系统中已存在的人员
物品名称 item_name string 必须匹配系统中已存在的物品
工作日期 work_date date 格式: YYYY-MM-DD
数量 quantity number 正整数

Import Response

// 成功响应
interface ImportSuccessResponse {
  success: true
  count: number  // 导入记录数
}

// 失败响应
interface ImportErrorResponse {
  success: false
  errors: string[]  // 错误信息列表
}

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: Template Column Completeness

For any generated import template, it SHALL contain all required columns (人员姓名, 物品名称, 工作日期, 数量) in the header row.

Validates: Requirements 3.2

Property 2: XLSX Format Validation

For any uploaded file that is not a valid XLSX format, the Import_Service SHALL reject it with a format error.

Validates: Requirements 4.2

Property 3: Required Column Validation

For any uploaded XLSX file missing one or more required columns, the Import_Service SHALL reject it with a column missing error.

Validates: Requirements 4.3

Property 4: Row Validation Error Format

For any row with invalid data (non-existent person, non-existent item, invalid date format, non-positive quantity, or empty required field), the Import_Service SHALL return an error message containing the row number and specific error reason.

Validates: Requirements 4.4, 4.5, 5.1, 5.2, 5.3, 5.4, 5.5

Property 5: Successful Import Record Count

For any valid import file with N rows of data, the Import_Service SHALL create exactly N work records and return count=N.

Validates: Requirements 4.6, 4.7

Property 6: Atomic Import Operation

For any import file containing at least one invalid row, the Import_Service SHALL NOT create any work records (all-or-nothing).

Validates: Requirements 4.8

Property 7: File Size Validation

For any uploaded file exceeding 5MB, the System SHALL reject the upload with a file size error.

Validates: Requirements 4.11

Error Handling

Backend Error Handling

错误类型 HTTP状态码 错误消息格式
文件格式错误 400 "文件格式错误,请上传XLSX文件"
文件过大 400 "文件大小超过限制(最大5MB)"
缺少必需列 400 "缺少必需列: xxx"
人员不存在 400 "第X行: 人员 'xxx' 不存在"
物品不存在 400 "第X行: 物品 'xxx' 不存在"
日期格式错误 400 "第X行: 日期格式错误,应为 YYYY-MM-DD"
数量无效 400 "第X行: 数量必须为正数"
字段为空 400 "第X行: 'xxx' 不能为空"

Frontend Error Display

  • 所有验证错误显示在可滚动列表中
  • 第一个错误高亮显示
  • 提供"重新上传"按钮

Testing Strategy

Unit Tests

  1. Template Generation Tests

    • 验证模板包含所有必需列
    • 验证模板包含示例数据
    • 验证日期格式正确
  2. Validation Tests

    • 测试各种无效输入的错误消息
    • 测试边界条件(空文件、单行、多行)
  3. Import Tests

    • 测试成功导入场景
    • 测试部分失败场景(原子性)

Property-Based Tests

使用 hypothesis 库进行属性测试:

  1. Property 1: 生成模板列完整性
  2. Property 4: 验证错误消息格式
  3. Property 5: 成功导入记录计数
  4. Property 6: 原子性操作验证

Test Configuration

  • Property tests: 最少100次迭代
  • 使用 pytest + hypothesis
  • 测试标签格式: **Feature: mobile-and-import, Property N: {property_text}**

Mobile Responsive Breakpoints

/* 移动端 */
@media (max-width: 767px) {
  /* 单列布局 */
  /* 抽屉式导航 */
  /* 卡片式表格 */
}

/* 平板 */
@media (min-width: 768px) and (max-width: 991px) {
  /* 两列布局 */
}

/* 桌面 */
@media (min-width: 992px) {
  /* 多列布局 */
}