# 巡检管理模块重构规格文档

## 1. 概述

### 1.1 背景
当前巡检管理模块存在以下问题需要重构：
1. 巡检点管理不够独立，缺少批量创建和二维码/NFC支持
2. 巡检计划缺少路径编排功能
3. 缺少执行人排班管理
4. 任务详情缺少路径比对和问题标记

### 1.2 目标
- 完善巡检点管理功能，支持批量创建、二维码生成、NFC写入
- 实现巡检计划路径编排，支持巡检点顺序和间隔时间设置
- 增加执行人排班管理，支持按周循环排班
- 完善任务详情，支持路径比对和问题标记
- 支持巡检计划复制功能

## 2. 功能需求

### 2.1 巡检点管理（独立Tab页）

#### 2.1.1 批量创建巡检点
**需求描述**：支持批量创建多个巡检点，采用混合模式。

**交互设计**：
- 提供表格形式的批量创建界面
- 支持手动输入每个巡检点名称
- 支持自动编号功能：输入前缀+起始编号，系统自动生成如"巡检点-001、巡检点-002..."
- 支持混合模式：空白行可自动填充编号

**数据结构**：
```typescript
interface BatchCreateInspectionPointRequest {
  points: Array<{
    name: string;           // 巡检点名称
    location?: string;      // 位置描述
    type: string;           // 巡检点类型
    spaceNodeId?: string;   // 关联空间节点
    longitude?: number;     // 经度
    latitude?: number;      // 纬度
  }>;
  autoNumbering?: {
    enabled: boolean;
    prefix: string;         // 名称前缀
    startNumber: number;    // 起始编号
    padding: number;        // 编号位数，如3表示001
  };
}
```

#### 2.1.2 二维码生成
**需求描述**：每个巡检点可生成唯一二维码，存储完整信息。

**二维码内容（JSON格式）**：
```json
{
  "type": "INSPECTION_POINT",
  "id": "uuid",
  "code": "PT202502200001",
  "name": "巡检点名称",
  "projectId": "project-uuid",
  "location": "位置描述",
  "createdAt": "2025-02-20T10:00:00Z",
  "signature": "数字签名（可选，用于防伪）"
}
```

**功能要求**：
- 支持单个巡检点二维码生成和下载
- 支持批量生成二维码（ZIP打包下载）
- 二维码格式：QR Code，尺寸可配置（默认200x200px）
- 支持打印模板：A4纸每页10个二维码

#### 2.1.3 NFC写入
**需求描述**：支持将巡检点信息写入NFC贴片。

**NFC数据格式**：
- 使用NDEF格式存储
- 存储与二维码相同的JSON数据
- 支持手机NFC功能写入（待定具体实现）

**功能要求**：
- 提供NFC写入界面（Web NFC API或移动端App）
- 支持批量写入模式
- 记录NFC标签ID用于验证

### 2.2 巡检计划路径编排

#### 2.2.1 路径编排功能
**需求描述**：将已录入的巡检点进行先后顺序编排，形成巡检路径。

**数据结构**：
```typescript
interface InspectionPathPoint {
  pointId: string;           // 巡检点ID
  pointName: string;         // 巡检点名称
  pointCode: string;         // 巡检点编码
  order: number;             // 顺序号
  minIntervalMinutes: number; // 与上一个巡检点的最小间隔时间（分钟）
  estimatedMinutes: number;  // 预计停留时间（分钟）
  location?: string;         // 位置描述
}

interface InspectionPath {
  id: string;
  planId: string;
  points: InspectionPathPoint[];
  totalEstimatedMinutes: number;  // 总预计时间
  createdAt: string;
  updatedAt: string;
}
```

**交互设计**：
- 提供拖拽排序界面
- 左侧显示可选巡检点列表
- 右侧显示已选巡检点路径
- 支持设置每个巡检点的最小间隔时间
- 实时显示总预计时间

#### 2.2.2 最小间隔时间
**需求描述**：设置相邻巡检点之间的最小到达时间间隔。

**业务规则**：
- 从上一个巡检点打卡到下一个巡检点打卡的最小时间差
- 如果实际间隔小于设置值，标记为"时间间隔不足"问题
- 可设置默认值（如5分钟），也可单独设置每个点

### 2.3 巡检计划周期设置

#### 2.3.1 多种周期类型
**需求描述**：支持多种巡检周期类型。

**周期类型**：
- 每日（DAILY）
- 每周（WEEKLY）- 可指定星期几
- 每两周（BIWEEKLY）
- 每月（MONTHLY）- 可指定日期
- 每季度（QUARTERLY）
- 每半年（SEMIANNUAL）
- 每年（YEARLY）

#### 2.3.2 周期内最少完成次数
**需求描述**：设置每个周期内需要完成的最少巡检次数。

**数据结构**：
```typescript
interface InspectionPlanCycle {
  cycle: string;              // 周期类型
  cycleDay?: number;          // 执行日期（如每月几号）
  cycleDays?: number[];       // 执行日期数组（如每周几）
  executeTime: string;        // 执行时间（HH:mm）
  minCompletionsPerCycle: number;  // 周期内最少完成次数
  endDate?: string;           // 计划结束日期
}
```

### 2.4 巡检计划负责人和执行人

#### 2.4.1 角色定义
**负责人**：
- 管理巡检计划
- 监督巡检任务完成情况
- 查看巡检报告和统计数据
- 调整计划和排班

**执行人**：
- 完成巡检任务
- 扫码打卡
- 上报巡检问题

#### 2.4.2 人员选择器
**需求描述**：选择负责人和执行人时，只能选择符合条件的人员。

**筛选条件**：
- 本部门及下级部门的人员
- 具备本项目执行巡检任务权限的人员

**数据结构**：
```typescript
interface InspectionPlanPersonnel {
  planId: string;
  managerId: string;          // 负责人ID
  managerName: string;        // 负责人姓名
  executorIds: string[];      // 执行人ID列表
  executorNames: string[];    // 执行人姓名列表
}
```

### 2.5 执行人排班管理

#### 2.5.1 按周循环排班
**需求描述**：为多个执行人设置按周循环的排班。

**数据结构**：
```typescript
interface InspectionSchedule {
  id: string;
  planId: string;
  weekSchedules: WeekSchedule[];
  createdAt: string;
  updatedAt: string;
}

interface WeekSchedule {
  dayOfWeek: number;          // 1-7 表示周一到周日
  executorId: string;         // 执行人ID
  executorName: string;       // 执行人姓名
  timeSlot?: string;          // 时间段（可选）
}
```

**业务规则**：
- 每天可指定一个执行人
- 未指定的日期默认由所有执行人轮流
- 只要求多人里有一人完成任务即可标记完成

#### 2.5.2 任务完成判定
**需求描述**：多执行人情况下，只要有一人完成即标记任务完成。

**判定逻辑**：
1. 根据排班表确定当天执行人
2. 当天执行人扫码打卡完成巡检
3. 系统自动标记任务为完成状态
4. 记录实际执行人信息

### 2.6 任务详情路径比对

#### 2.6.1 时间线对比展示
**需求描述**：在任务详情中展示计划路径与实际路径的对比。

**数据结构**：
```typescript
interface InspectionTaskPath {
  taskId: string;
  plannedPath: PlannedPathPoint[];
  actualPath: ActualPathPoint[];
  issues: PathIssue[];
  summary: TaskSummary;
}

interface PlannedPathPoint {
  order: number;
  pointId: string;
  pointName: string;
  minIntervalMinutes: number;
  estimatedMinutes: number;
}

interface ActualPathPoint {
  order: number;
  pointId: string;
  pointName: string;
  scannedAt: string;          // 扫码时间
  scannedBy: string;          // 扫码人
  scannedByName: string;
  intervalFromPrevious: number; // 与上一个点的实际间隔（分钟）
  issues?: string[];          // 问题列表
}

interface PathIssue {
  type: 'ORDER_ERROR' | 'TIME_INTERVAL_ERROR' | 'POINT_SKIPPED' | 'INSPECTION_ISSUE';
  severity: 'WARNING' | 'ERROR';
  pointId?: string;
  pointName?: string;
  description: string;
  details?: any;
}

interface TaskSummary {
  totalPoints: number;
  completedPoints: number;
  skippedPoints: number;
  orderErrors: number;
  timeIntervalErrors: number;
  inspectionIssues: number;
  startedAt: string;
  completedAt: string;
  totalDuration: number;      // 总耗时（分钟）
}
```

**交互设计**：
- 使用时间线组件展示
- 计划路径用虚线表示
- 实际路径用实线表示
- 问题点用红色标记
- 点击节点显示详细信息

#### 2.6.2 问题标记
**需求描述**：标记路径问题和巡检问题。

**问题类型**：
1. **路径问题**：
   - 顺序错误（ORDER_ERROR）：未按计划顺序巡检
   - 时间间隔不足（TIME_INTERVAL_ERROR）：两点之间时间过短
   - 巡检点跳过（POINT_SKIPPED）：未巡检计划中的点

2. **巡检问题**：
   - 设备故障
   - 环境异常
   - 安全隐患
   - 其他问题

**问题展示**：
- 在任务详情顶部显示问题简报
- 问题点用不同颜色标记
- 支持查看问题详情和照片

### 2.7 巡检计划复制

#### 2.7.1 复制功能
**需求描述**：支持复制巡检计划，创建新计划。

**复制内容**：
- 计划基本信息（名称需修改）
- 巡检点路径
- 执行人设置
- 排班配置

**不复制内容**：
- 计划ID
- 创建时间
- 已生成的任务

**API设计**：
```
POST /api/v1/ops/inspection/plans/{id}/copy
Request: {
  name: string;              // 新计划名称
  startDate?: string;        // 新计划开始日期
  endDate?: string;          // 新计划结束日期
}
Response: InspectionPlan
```

## 3. 数据库设计

### 3.1 新增表

#### 3.1.1 巡检路径表 (ops_inspection_path)
```sql
CREATE TABLE ops_inspection_path (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    project_id UUID NOT NULL,
    plan_id UUID NOT NULL,
    name VARCHAR(100),
    description VARCHAR(500),
    total_estimated_minutes INTEGER DEFAULT 0,
    enabled BOOLEAN NOT NULL DEFAULT true,
    version BIGINT DEFAULT 0,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by UUID,
    updated_by UUID,
    CONSTRAINT fk_path_plan FOREIGN KEY (plan_id) REFERENCES ops_inspection_plan(id) ON DELETE CASCADE
);

CREATE INDEX idx_path_project ON ops_inspection_path(project_id);
CREATE INDEX idx_path_plan ON ops_inspection_path(plan_id);
```

#### 3.1.2 巡检路径点表 (ops_inspection_path_point)
```sql
CREATE TABLE ops_inspection_path_point (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    path_id UUID NOT NULL,
    point_id UUID NOT NULL,
    point_order INTEGER NOT NULL,
    min_interval_minutes INTEGER DEFAULT 5,
    estimated_minutes INTEGER DEFAULT 5,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_point_path FOREIGN KEY (path_id) REFERENCES ops_inspection_path(id) ON DELETE CASCADE,
    CONSTRAINT fk_point_inspection FOREIGN KEY (point_id) REFERENCES ops_inspection_point(id)
);

CREATE INDEX idx_path_point_path ON ops_inspection_path_point(path_id);
CREATE INDEX idx_path_point_order ON ops_inspection_path_point(path_id, point_order);
```

#### 3.1.3 执行人排班表 (ops_inspection_schedule)
```sql
CREATE TABLE ops_inspection_schedule (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    project_id UUID NOT NULL,
    plan_id UUID NOT NULL,
    executor_id UUID NOT NULL,
    executor_name VARCHAR(100),
    day_of_week INTEGER NOT NULL CHECK (day_of_week BETWEEN 1 AND 7),
    time_slot VARCHAR(50),
    enabled BOOLEAN NOT NULL DEFAULT true,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by UUID,
    updated_by UUID,
    CONSTRAINT fk_schedule_plan FOREIGN KEY (plan_id) REFERENCES ops_inspection_plan(id) ON DELETE CASCADE
);

CREATE INDEX idx_schedule_project ON ops_inspection_schedule(project_id);
CREATE INDEX idx_schedule_plan ON ops_inspection_schedule(plan_id);
CREATE INDEX idx_schedule_day ON ops_inspection_schedule(plan_id, day_of_week);
```

#### 3.1.4 任务打卡记录表 (ops_inspection_checkin)
```sql
CREATE TABLE ops_inspection_checkin (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    project_id UUID NOT NULL,
    task_id UUID NOT NULL,
    point_id UUID NOT NULL,
    point_order INTEGER,
    checkin_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    checkin_type VARCHAR(20) NOT NULL,  -- QR_CODE, NFC
    executor_id UUID NOT NULL,
    executor_name VARCHAR(100),
    longitude DECIMAL(10, 7),
    latitude DECIMAL(10, 7),
    location_verified BOOLEAN DEFAULT false,
    issues JSONB,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_checkin_task FOREIGN KEY (task_id) REFERENCES ops_inspection_task(id) ON DELETE CASCADE,
    CONSTRAINT fk_checkin_point FOREIGN KEY (point_id) REFERENCES ops_inspection_point(id)
);

CREATE INDEX idx_checkin_project ON ops_inspection_checkin(project_id);
CREATE INDEX idx_checkin_task ON ops_inspection_checkin(task_id);
CREATE INDEX idx_checkin_point ON ops_inspection_checkin(point_id);
CREATE INDEX idx_checkin_time ON ops_inspection_checkin(checkin_time);
```

### 3.2 修改表

#### 3.2.1 巡检计划表 (ops_inspection_plan)
```sql
ALTER TABLE ops_inspection_plan ADD COLUMN IF NOT EXISTS min_completions_per_cycle INTEGER DEFAULT 1;
ALTER TABLE ops_inspection_plan ADD COLUMN IF NOT EXISTS executor_ids JSONB;
ALTER TABLE ops_inspection_plan ADD COLUMN IF NOT EXISTS executor_names JSONB;
ALTER TABLE ops_inspection_plan ADD COLUMN IF NOT EXISTS path_id UUID;
```

#### 3.2.2 巡检点表 (ops_inspection_point)
```sql
ALTER TABLE ops_inspection_point ADD COLUMN IF NOT EXISTS qr_data JSONB;
ALTER TABLE ops_inspection_point ADD COLUMN IF NOT EXISTS nfc_data JSONB;
```

#### 3.2.3 巡检任务表 (ops_inspection_task)
```sql
ALTER TABLE ops_inspection_task ADD COLUMN IF NOT EXISTS path_id UUID;
ALTER TABLE ops_inspection_task ADD COLUMN IF NOT EXISTS planned_path JSONB;
ALTER TABLE ops_inspection_task ADD COLUMN IF NOT EXISTS actual_path JSONB;
ALTER TABLE ops_inspection_task ADD COLUMN IF NOT EXISTS path_issues JSONB;
ALTER TABLE ops_inspection_task ADD COLUMN IF NOT EXISTS task_summary JSONB;
```

## 4. API设计

### 4.1 巡检点管理API

#### 4.1.1 批量创建巡检点
```
POST /api/v1/ops/inspection/points/batch
Request: BatchCreateInspectionPointRequest
Response: InspectionPoint[]
```

#### 4.1.2 生成二维码
```
POST /api/v1/ops/inspection/points/{id}/generate-qrcode
Response: { qrCode: string, qrData: string, qrImage: string }
```

#### 4.1.3 批量生成二维码
```
POST /api/v1/ops/inspection/points/batch-qrcode
Request: { pointIds: string[] }
Response: { downloadUrl: string }
```

#### 4.1.4 NFC写入准备
```
GET /api/v1/ops/inspection/points/{id}/nfc-data
Response: { nfcData: string, pointId: string, pointName: string }
```

### 4.2 巡检路径API

#### 4.2.1 创建巡检路径
```
POST /api/v1/ops/inspection/plans/{planId}/path
Request: {
  name: string;
  points: Array<{
    pointId: string;
    minIntervalMinutes: number;
    estimatedMinutes: number;
  }>;
}
Response: InspectionPath
```

#### 4.2.2 更新巡检路径
```
PUT /api/v1/ops/inspection/plans/{planId}/path
Request: {
  name: string;
  points: Array<{
    pointId: string;
    minIntervalMinutes: number;
    estimatedMinutes: number;
  }>;
}
Response: InspectionPath
```

#### 4.2.3 获取巡检路径
```
GET /api/v1/ops/inspection/plans/{planId}/path
Response: InspectionPath
```

### 4.3 排班管理API

#### 4.3.1 设置排班
```
POST /api/v1/ops/inspection/plans/{planId}/schedule
Request: {
  schedules: Array<{
    dayOfWeek: number;
    executorId: string;
    executorName: string;
    timeSlot?: string;
  }>;
}
Response: InspectionSchedule[]
```

#### 4.3.2 获取排班
```
GET /api/v1/ops/inspection/plans/{planId}/schedule
Response: InspectionSchedule[]
```

### 4.4 打卡API

#### 4.4.1 扫码打卡
```
POST /api/v1/ops/inspection/checkin
Request: {
  taskId: string;
  qrCode?: string;
  nfcTag?: string;
  longitude?: number;
  latitude?: number;
}
Response: InspectionCheckin
```

#### 4.4.2 获取打卡记录
```
GET /api/v1/ops/inspection/tasks/{taskId}/checkins
Response: InspectionCheckin[]
```

### 4.5 任务路径比对API

#### 4.5.1 获取任务路径比对
```
GET /api/v1/ops/inspection/tasks/{taskId}/path-comparison
Response: InspectionTaskPath
```

### 4.6 计划复制API

#### 4.6.1 复制计划
```
POST /api/v1/ops/inspection/plans/{id}/copy
Request: {
  name: string;
  startDate?: string;
  endDate?: string;
}
Response: InspectionPlan
```

## 5. 前端页面设计

### 5.1 巡检点管理页面

#### 5.1.1 页面结构
```
巡检点管理
├── 搜索栏
│   ├── 关键词搜索
│   ├── 类型筛选
│   └── 状态筛选
├── 操作栏
│   ├── 新增巡检点
│   ├── 批量创建
│   └── 批量生成二维码
├── 数据表格
│   ├── 巡检点编码
│   ├── 巡检点名称
│   ├── 类型
│   ├── 位置
│   ├── 二维码
│   ├── NFC状态
│   ├── 状态
│   └── 操作
└── 批量创建弹窗
    ├── 表格形式输入
    ├── 自动编号设置
    └── 导入功能
```

#### 5.1.2 二维码弹窗
```
二维码详情
├── 巡检点信息
├── 二维码图片
├── 下载按钮
└── 打印按钮
```

### 5.2 巡检计划页面

#### 5.2.1 页面结构
```
巡检计划
├── 搜索栏
├── 操作栏
│   ├── 新增计划
│   └── 生成任务
├── 数据表格
│   ├── 计划编码
│   ├── 计划名称
│   ├── 类型
│   ├── 周期
│   ├── 最少完成次数
│   ├── 负责人
│   ├── 执行人数
│   ├── 状态
│   └── 操作
└── 计划详情/编辑弹窗
    ├── 基本信息 Tab
    ├── 巡检路径 Tab
    ├── 执行人 Tab
    └── 排班管理 Tab
```

#### 5.2.2 路径编排界面
```
路径编排
├── 左侧：可选巡检点列表
│   ├── 搜索
│   └── 巡检点列表（可拖拽）
├── 右侧：已选巡检点路径
│   ├── 路径列表（可拖拽排序）
│   ├── 每个点设置间隔时间
│   └── 总预计时间显示
└── 操作按钮
    ├── 保存
    └── 重置
```

#### 5.2.3 排班管理界面
```
排班管理
├── 周视图
│   ├── 周一至周日
│   └── 每天显示执行人
├── 执行人列表
│   └── 勾选参与排班的人员
└── 快速排班
    ├── 轮流排班
    └── 指定排班
```

### 5.3 任务详情页面

#### 5.3.1 页面结构
```
任务详情
├── 任务简报
│   ├── 任务状态
│   ├── 完成进度
│   └── 问题摘要
├── 路径比对
│   ├── 时间线视图
│   ├── 计划路径（虚线）
│   ├── 实际路径（实线）
│   └── 问题标记（红色）
├── 打卡记录列表
│   ├── 序号
│   ├── 巡检点
│   ├── 打卡时间
│   ├── 执行人
│   ├── 间隔时间
│   └── 状态
└── 问题详情
    ├── 问题描述
    ├── 问题照片
    └── 处理状态
```

## 6. 开发任务

### 6.1 后端开发任务

1. **数据库变更**
   - 创建新表
   - 修改现有表结构
   - 编写数据迁移脚本

2. **实体和Repository**
   - 创建InspectionPath实体
   - 创建InspectionPathPoint实体
   - 创建InspectionSchedule实体
   - 创建InspectionCheckin实体
   - 修改InspectionPlan实体
   - 修改InspectionPoint实体
   - 修改InspectionTask实体

3. **Service层**
   - 实现批量创建巡检点服务
   - 实现二维码生成服务
   - 实现NFC数据准备服务
   - 实现路径编排服务
   - 实现排班管理服务
   - 实现打卡服务
   - 实现路径比对服务
   - 实现计划复制服务

4. **Controller层**
   - 实现巡检点批量API
   - 实现二维码API
   - 实现NFC API
   - 实现路径API
   - 实现排班API
   - 实现打卡API
   - 实现路径比对API
   - 实现计划复制API

### 6.2 前端开发任务

1. **巡检点管理页面**
   - 实现批量创建组件
   - 实现二维码生成和显示
   - 实现NFC写入界面

2. **巡检计划页面**
   - 实现路径编排组件
   - 实现执行人选择器
   - 实现排班管理组件

3. **任务详情页面**
   - 实现时间线对比组件
   - 实现问题标记展示
   - 实现简报组件

4. **API集成**
   - 集成所有新增API

### 6.3 测试任务

1. **单元测试**
   - 后端Service层测试
   - 前端组件测试

2. **集成测试**
   - API集成测试
   - 业务流程测试

3. **E2E测试**
   - 巡检点批量创建流程
   - 路径编排流程
   - 排班管理流程
   - 打卡流程
   - 路径比对流程

## 7. 风险和注意事项

### 7.1 技术风险
1. **NFC写入**：Web NFC API支持有限，可能需要移动端App支持
2. **二维码批量生成**：大量二维码生成可能影响性能，需要异步处理
3. **路径比对算法**：需要考虑各种边界情况

### 7.2 业务风险
1. **排班冲突**：同一执行人可能被分配到多个计划
2. **路径变更**：计划执行中修改路径需要处理已生成任务
3. **数据迁移**：现有数据需要兼容新结构

### 7.3 注意事项
1. 保持向后兼容性
2. 做好数据备份
3. 分阶段上线
4. 充分测试边界情况
