ether-docs/02-DESIGN/domains/inspection-redesign/spec.md

800 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 巡检管理模块重构规格文档
## 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. 充分测试边界情况