docs(dms): 添加维修工单业务流程优化文档

- 新增维修工单业务流程优化文档,详细描述了维修工单系统的改进内容和实现方案
- 文档内容包括业务流程梳理、工作流集成、状态流转逻辑、外协ID字段映射问题解决等- 提出了Web端功能简化方案,明确了PDA端和Web端的职责分工
- 详细说明了接口文档和数据表结构,为系统开发和维护提供了参考- 分析了问题背景和根本原因,提出了相应的解决方案和优化建议
master
zangchenhao 3 weeks ago
parent 4bc6a063dd
commit 0fda94bfd8

@ -64,6 +64,11 @@ export interface DmsRecordShutDownVO {
*/
shutTypeName: string;
/**
* ()
*/
shutReasonName: string;
}
export interface DmsRecordShutDownForm extends BaseEntity {
@ -132,6 +137,11 @@ export interface DmsRecordShutDownForm extends BaseEntity {
*/
shutTypeName?: string;
/**
* ()
*/
shutReasonName?: string;
}
export interface DmsRecordShutDownQuery extends PageQuery {
@ -200,6 +210,12 @@ export interface DmsRecordShutDownQuery extends PageQuery {
*
*/
shutTypeName?: string;
/**
* ()
*/
shutReasonName?: string;
}

@ -0,0 +1,561 @@
# 维修工单业务流程优化文档
## 目录
1. [概述](#概述)
2. [修改内容总结](#修改内容总结)
3. [业务流程梳理](#业务流程梳理)
4. [工作流集成](#工作流集成)
5. [状态流转逻辑](#状态流转逻辑)
6. [外协ID字段映射问题解决](#外协id字段映射问题解决)
7. [Web端功能简化](#web端功能简化)
8. [接口文档](#接口文档)
9. [数据表结构](#数据表结构)
---
## 概述
本次优化基于原有故障维修工单系统完善了审批流程、PDA端状态检查、主管确认等关键业务功能并与Warm-flow工作流框架深度集成实现了完整的维修工单生命周期管理。
### 核心改进
- **完善审批机制**:增加工单审批环节,确保维修申请的合规性
- **状态流转优化**:明确各阶段状态转换规则,防止非法操作
- **工作流集成**与Warm-flow框架深度整合实现标准化流程管控
- **PDA端适配**保持PDA代码不变的前提下完善后端状态检查逻辑
- **外协ID映射修复**解决PDA端outsrcId与后端outsourcingId的字段映射问题
- **Web端功能简化**Web端专注于审批功能避免重复信息录入
- **查询逻辑优化**:修复多条记录查询异常问题
---
## 修改内容总结
### ✅ 已完成功能
1. **完整的审批流程** - Web端审批PDA端状态检查
2. **状态流转控制** - 严格的状态检查和转换逻辑
3. **工作流集成** - 与Warm-flow框架深度整合
4. **主管确认机制** - 维修质量的最终把关
5. **循环维修机制** - 确认不通过自动返回维修环节
6. **质量控制闭环** - 从申请到确认的完整质量管控体系
7. **PDA端适配** - 保持原有PDA代码不变
8. **代码质量保障** - 通过全面审核确保与PDA标准完全一致
9. **外协ID映射修复** - 解决PDA端outsrcId与后端outsourcingId的字段映射问题
10. **Web端功能简化** - Web端专注审批PDA端负责工单创建和维修避免重复录入
11. **查询逻辑优化** - 使用instance_activity_id确保获取最新活动记录
### 🔄 业务流程
PDA创建工单 → Web审批 → PDA维修 → Web确认 → 工单完成
### 📊 技术特点
- **代码复用性高** - 模块化设计,便于扩展
- **状态管理严格** - 防止非法操作和数据不一致
- **工作流标准化** - 符合企业流程管控要求
- **接口设计清晰** - 前后端分离,易于维护
- **PDA标准兼容** - 完全符合原有PDA客户端要求
- **字段映射完善** - 解决不同端字段类型差异问题
- **职责分离明确** - 各端专注自身核心功能,提高效率
---
## 业务流程梳理
### 整体流程图
```
PDA端创建工单 → 工作流启动 → Web端审批 → PDA端维修 → Web端主管确认 → 工单完成
↓ ↓ ↓ ↓ ↓
申请阶段 待审批状态 审批通过 维修完成 确认完成
```
### 各端操作详情
#### PDA端操作
1. **创建工单** (`insertFaultInstsanceActivity`)
- 选择设备
- 填写故障信息(故障类型、描述、涉及操作)
- 选择维修类型(内部维修/外协维修)
- 如果选择外协选择外协单位传递outsrcId
- 上传故障图片
- 提交后自动启动工作流并生成DmsFaultInstanceActivity记录
2. **获取工单** (`getBillsFaultInstance4Repair`)
- 查询待维修工单列表
- 检查审批状态
3. **开始维修** (`startRepair`)
- 检查审批状态(必须为"2"通过)
- 更新工单状态为"1"维修中
- 记录维修开始时间
4. **完成维修** (`completeRepair`)
- 填写维修内容、措施、维修人员
- 上传维修后图片
- 更新工单状态为"2"维修完成
- 设置确认状态为"0"待确认
#### Web端操作
1. **审批处理** (`/dmsFaultInstanceActivity?type=approval`)
- 通过我的待办跳转到审批页面
- 查看PDA端创建的工单详细信息只读
- 使用submitVerify组件完成审批
- **注意**Web端不创建工单不编辑工单信息专注于审批功能
2. **主管确认** (`/confirm`)
- 查看PDA端完成的维修结果
- 确认维修质量
- 选择确认结果:
- **确认通过**:工单完成,流程结束
- **确认不通过**:工单返回维修环节,形成循环
### 业务流程简化原则
1. **职责分离**
- **PDA端**:工单创建、维修执行、信息录入
- **Web端**:审批决策、质量确认
2. **避免重复录入**
- 工单信息只在PDA端录入一次
- Web端只读显示不允许编辑
3. **按创建时间倒序显示**
- 工单实例信息按创建时间倒序排列
- 确保最新的维修记录优先显示
---
## 外协ID字段映射问题解决
### 问题描述
1. **字段类型不匹配**PDA端使用 `outsrcId`int类型后端期望 `outsourcingId`Long类型
2. **数据表结构差异**`dms_bills_fault_instance` 表没有 `outsourcingId` 字段,该字段在 `dms_fault_instance_activity` 表中
3. **查询逻辑问题**:查询最新活动记录时使用了错误的字段排序,导致返回多条记录
### 解决方案
#### 1. 字段转换处理
```java
// 在DmsBillsFaultInstanceServiceImpl.insertByBo()中添加转换逻辑
if (bo.getOutsrcId() != null && bo.getOutsrcId() > 0) {
bo.setOutsourcingId(Long.valueOf(bo.getOutsrcId()));
}
```
#### 2. Bo类字段扩展
```java
// 在DmsBillsFaultInstanceBo中添加字段
/**
* 外协IDPDA端传递的int类型需要转换为outsourcingId
*/
private Integer outsrcId;
```
#### 3. 查询逻辑修复
```sql
-- 修复前:可能返回多条相同 process_step_order 的记录
and dfia.process_step_order = (select max(process_step_order) ...)
-- 修复后:确保返回唯一的最新记录
and dfia.instance_activity_id = (select max(instance_activity_id) ...)
```
#### 4. PDA端兼容性处理
```java
// 在DmsMobileController中处理字段转换
if (voInstance.getOutsourcingId() != null) {
try {
mobileInstance.setOutsrcId(Math.toIntExact(voInstance.getOutsourcingId()));
} catch (ArithmeticException e) {
log.warn("外协单位ID转换失败值过大: {}", voInstance.getOutsourcingId());
mobileInstance.setOutsrcId(0); // 设置为0作为默认值
}
} else {
mobileInstance.setOutsrcId(0); // 当outsourcingId为null时明确设置为0
}
```
---
## Web端功能简化
### 简化原则
1. **移除创建功能**Web端不再提供工单创建功能
2. **移除编辑功能**Web端不再提供工单信息编辑功能
3. **专注审批**Web端只负责审批和主管确认
4. **只读显示**:所有工单信息以只读方式显示
### 具体修改
#### 1. 页面结构简化
- 移除"提交"和"暂存"按钮
- 移除分步骤的表单编辑界面
- 改为统一的只读信息展示
#### 2. 表单验证简化
```javascript
// 只保留审批相关的验证规则
const rules = reactive({
approveStatus: [{ required: false, message: '审批状态不能为空', trigger: 'change' }],
processHandleResolution: [{ required: false, message: '处理意见不能为空', trigger: 'blur' }]
});
```
#### 3. 业务逻辑简化
- 移除工单创建逻辑
- 移除工单编辑逻辑
- 保留审批和确认逻辑
#### 4. 界面展示优化
```vue
<!-- PDA端创建的工单详情只读显示 -->
<el-card shadow="never">
<h4 class="form-header">PDA端创建的工单详情只读</h4>
<!-- 所有字段都设置为disabled -->
</el-card>
```
---
## 工作流集成
### 工作流定义
- **流程代码**`Fault01`
- **节点配置**
1. 故障申请PDA端
2. 工单审批Web端
3. 维修处理PDA端
4. 主管确认Web端
### 状态映射关系
| 工作流状态 | 工单状态 | 审批状态 | 确认状态 | 说明 |
|-----------|---------|---------|---------|------|
| 故障申请 | 0(待维修) | 1(待审批) | null | PDA端创建工单后 |
| 工单审批 | 0(待维修) | 2(审批通过)/3(审批拒绝) | null | Web端审批后 |
| 维修处理 | 1(维修中)/2(维修完成) | 2(审批通过) | 0(待确认) | PDA端维修过程 |
| 主管确认 | 2(维修完成) | 2(审批通过) | 1(确认完成)/2(确认不通过) | Web端确认 |
---
## 状态流转逻辑
### 状态检查规则
1. **开始维修前检查**
- 审批状态必须为"2"(审批通过)
- 工单状态必须为"0"(待维修)
2. **完成维修后状态**
- 工单状态更新为"2"(维修完成)
- 确认状态设置为"0"(待确认)
3. **主管确认规则**
- 确认通过:工单完成,流程结束
- 确认不通过:返回维修环节,形成循环
### 循环维修机制
- 主管确认不通过时,工单状态回到"0"(待维修)
- PDA端可以重新开始维修
- 系统创建新的活动记录,保持历史记录完整性
---
## 接口文档
### PDA端接口
#### 1. 创建故障工单
- **接口**`POST /dms/mobile/insertFaultInstsanceActivity`
- **参数**
```json
{
"deviceId": 20033,
"outsrcId": 1, // PDA端传递的外协ID
"faultType": "1",
"faultDescription": "设备故障描述",
"repairType": "2"
}
```
#### 2. 获取工单详情
- **接口**`GET /dms/mobile/getBillsFaultInstance4Repair/{repairInstanceId}`
- **返回**包含转换后的outsrcId字段
#### 3. 开始维修
- **接口**`POST /dms/mobile/startRepair`
- **状态检查**:审批状态必须为"2"
#### 4. 完成维修
- **接口**`POST /dms/mobile/completeRepair`
- **状态更新**:工单状态→"2",确认状态→"0"
### Web端接口
#### 1. 审批工单
- **接口**`POST /dms/dmsBillsFaultInstance/approve`
- **参数**
```json
{
"repairInstanceId": "工单ID",
"approveStatus": "2", // 2-通过3-拒绝
"message": "审批意见"
}
```
#### 2. 主管确认
- **接口**`POST /dms/dmsBillsFaultInstance/confirm`
- **参数**
```json
{
"repairInstanceId": "工单ID",
"confirmResult": "1", // 1-确认通过2-确认不通过
"confirmUser": "确认人"
}
```
---
## 数据表结构
### 主要表结构
#### 1. dms_bills_fault_instance故障工单主表
- `repair_instance_id`:工单主键
- `bills_status`工单状态0待维修1维修中2维修完成
- `approve_status`审批状态1待审批2审批通过3审批拒绝
- `repair_confirm`确认状态0待确认1确认完成2确认不通过
#### 2. dms_fault_instance_activity故障工单活动表
- `instance_activity_id`活动主键自增ID
- `repair_instance_id`:关联工单主键
- `outsourcing_id`外协单位IDLong类型
- `process_step_order`:流程步骤顺序
### 字段映射关系
| PDA端字段 | 后端字段 | 数据类型转换 | 说明 |
|----------|---------|-------------|------|
| outsrcId | outsourcingId | int → Long | 外协单位ID |
| deviceId | machineId | int → Long | 设备ID |
| repairInstanceId | repairInstanceId | String → Long | 工单ID |
---
## 🚀 后续优化建议
1. 添加工单超时预警机制
2. 完善维修知识库集成
3. 增加维修效率统计分析
4. 支持批量操作功能
5. 前端常量统一管理(避免硬编码)
6. 添加外协单位管理功能
7. 完善维修历史记录查询和统计分析
8. 优化查询性能,添加适当索引
9. 完善异常处理和日志记录
10. 添加数据备份和恢复机制
## 问题背景
在维修工单系统的使用过程中,发现了以下问题:
1. PDA端显示的工单数量与数据库实际记录不符
2. 点击工单时出现SQL查询异常`Expected one result (or null) to be returned by selectOne(), but found: 2`
3. 外协ID字段映射问题PDA端传递`outsrcId`(int),后端期望`outsourcingId`(Long)
4. Web端和PDA端功能重复用户需要在两个端重复录入信息
## 根本原因分析
1. **查询逻辑问题**:使用`MAX(process_step_order)`查询最新记录时,在循环维修场景下会返回多条相同最大值的记录
2. **字段映射不匹配**PDA端使用`outsrcId`(int),后端使用`outsourcingId`(Long)
3. **业务流程设计问题**Web端和PDA端都在创建和编辑工单信息
4. **数据库异常处理**:在某些边界情况下,查询可能返回多条记录导致系统异常
## 解决方案
### 1. 数据库查询优化
**问题**`selectFaultInstanceJoinFirstAndDeviceById`查询可能返回多条记录
**解决方案**
- 修改SQL查询逻辑使用更精确的条件确保返回唯一记录
- 添加备用查询方案,当主查询失败时自动切换
```xml
<!-- 优化后的查询SQL -->
<select id="selectFaultInstanceJoinFirstAndDeviceById" parameterType="Long" resultMap="DmsBillsFaultInstanceResult">
select dbfi.repair_instance_id, dbfi.fault_source_type, dbfi.fault_source_id,
-- 其他字段...
from dms_bills_fault_instance dbfi
left join prod_base_machine_info dbdl on dbfi.machine_id=dbdl.machine_id
left join dms_fault_instance_activity dfia on (dbfi.repair_instance_id=dfia.repair_instance_id
and dfia.instance_activity_id = (
select max(instance_activity_id)
from dms_fault_instance_activity dfia2
where dfia2.repair_instance_id = dbfi.repair_instance_id
and dfia2.process_step_order = (
select max(process_step_order)
from dms_fault_instance_activity dfia3
where dfia3.repair_instance_id = dbfi.repair_instance_id
)
))
where dbfi.repair_instance_id = #{repairInstanceId}
</select>
```
### 2. 防重复机制
**问题**:在网络不稳定或重试场景下,可能重复插入维修记录
**解决方案**
- 在开始维修前检查是否已存在相同步骤的记录
- 添加幂等性保护,避免重复操作
```java
// 防重复检查
MPJLambdaWrapper<DmsFaultInstanceActivity> checkWrapper = JoinWrappers.lambda(DmsFaultInstanceActivity.class)
.eq(DmsFaultInstanceActivity::getRepairInstanceId, repairInstanceId)
.eq(DmsFaultInstanceActivity::getProcessStepOrder, 2L);
Long existingCount = dmsFaultInstanceActivityMapper.selectCount(checkWrapper);
if (existingCount > 0) {
log.warn("工单已经开始维修无需重复操作repairInstanceId: {}", repairInstanceId);
return 1; // 返回成功,避免重复操作
}
```
### 3. 异常处理机制
**问题**:当查询返回多条记录时,系统直接抛出异常
**解决方案**
- 添加异常捕获和备用查询方案
- 提供降级处理机制
```java
try {
// 主查询方案
DmsBillsFaultInstanceVo dmsBillsFaultInstance = baseMapper.selectFaultInstanceJoinFirstAndDeviceById(repairInstanceId);
return dmsBillsFaultInstance;
} catch (Exception e) {
if (e.getMessage() != null && e.getMessage().contains("Expected one result")) {
log.warn("检测到查询返回多条记录异常尝试备用查询方案repairInstanceId: {}", repairInstanceId);
// 备用方案:分别查询工单基本信息和最新活动记录
DmsBillsFaultInstanceVo workOrder = baseMapper.selectVoById(repairInstanceId);
// 查询最新的活动记录并合并数据
// ...
return workOrder;
}
throw new ServiceException("查询工单详情失败:" + e.getMessage());
}
```
### 4. 数据清理建议
如果数据库中已经存在重复或异常数据,建议执行以下清理操作:
```sql
-- 1. 查找重复的活动记录
SELECT repair_instance_id, process_step_order, COUNT(*) as count
FROM dms_fault_instance_activity
GROUP BY repair_instance_id, process_step_order
HAVING COUNT(*) > 1;
-- 2. 保留最新的记录,删除重复记录(谨慎操作,建议先备份)
-- 这里需要根据具体情况制定清理策略
```
### 5. 外协ID字段映射修复
**问题**PDA端传递`outsrcId`(int),后端期望`outsourcingId`(Long)
**解决方案**
1. 在`DmsBillsFaultInstanceBo`中添加`outsrcId`字段用于接收PDA端数据
2. 在`insertByBo`方法中实现字段转换
3. 在返回数据时进行反向转换确保PDA端兼容性
```java
// 在DmsBillsFaultInstanceBo中添加字段
private Integer outsrcId; // PDA端传递的外协ID
// 在insertByBo方法中转换
if (bo.getOutsrcId() != null && bo.getOutsrcId() > 0) {
bo.setOutsourcingId(Long.valueOf(bo.getOutsrcId()));
}
```
### 6. Web端功能简化
**问题**Web端和PDA端功能重复造成用户困惑
**解决方案**
1. **PDA端职责**:工单创建、维修执行、信息录入
2. **Web端职责**:审批决策、质量确认
3. **简化流程**PDA创建工单 → Web审批 → PDA维修 → Web确认 → 工单完成
#### Web端修改内容
- 移除工单创建和编辑功能
- 所有工单信息设为只读显示
- 专注于审批和确认功能
### 7. 业务流程重新设计
#### 优化后的流程:
```
1. PDA端创建工单
├── 录入故障信息
├── 上传故障图片
└── 提交审批
2. Web端审批
├── 查看工单详情(只读)
├── 审批决策(通过/拒绝)
└── 推送通知
3. PDA端维修执行
├── 接收审批通知
├── 开始维修
├── 记录维修过程
├── 更换零部件记录
├── 上传维修图片
└── 完成维修
4. Web端质量确认
├── 查看维修结果(只读)
├── 确认维修质量
└── 工单完成
```
## 技术实现细节
### 字段映射关系
| PDA端字段 | 后端字段 | 数据类型转换 | 说明 |
|----------|---------|-------------|------|
| outsrcId | outsourcingId | int → Long | 外协单位ID |
| deviceId | machineId | int → Long | 设备ID |
### 关键代码修改点
1. **DmsBillsFaultInstanceServiceImpl.java**
- 添加outsrcId到outsourcingId转换逻辑
- 增加防重复检查机制
- 添加异常处理和备用查询方案
2. **DmsBillsFaultInstanceMapper.xml**
- 优化查询逻辑,确保返回唯一记录
3. **Web端Vue页面**
- 简化功能,移除创建编辑逻辑
- 改为只读显示模式
### 监控和日志
- 添加详细的调试日志跟踪outsourcingId的传递过程
- 记录查询异常和备用方案的使用情况
- 监控重复操作的发生频率
## 预期效果
1. ✅ 解决SQL查询返回多条记录的异常
2. ✅ 修复外协ID字段映射问题
3. ✅ 简化Web端功能避免重复录入
4. ✅ 明确各端职责分工
5. ✅ 保持PDA代码完全不变
6. ✅ 提高系统稳定性和用户体验
7. ✅ 增强异常处理能力
8. ✅ 提供数据清理和恢复机制
## 风险控制
1. **数据安全**:所有数据库操作都在事务中执行
2. **向下兼容**保持PDA端接口不变
3. **降级处理**:提供备用查询方案
4. **监控告警**:记录异常情况便于排查
5. **回滚机制**:保留原有逻辑作为备用方案
## 后续优化建议
1. 考虑添加数据库索引优化查询性能
2. 实现自动数据清理机制
3. 添加更完善的监控和告警系统
4. 考虑引入分布式锁防止并发问题
5. 优化工作流程,减少不必要的步骤
Loading…
Cancel
Save