313 lines
10 KiB
Markdown
313 lines
10 KiB
Markdown
# 隐患验收页逻辑说明
|
||
|
||
> 对应文件:`pages/hiddendanger/acceptance.vue`
|
||
> 最后整理:2026-07-15
|
||
|
||
---
|
||
|
||
## 1. 页面职责
|
||
|
||
验收页用于对**已提交的整改记录**进行验收,主要能力:
|
||
|
||
1. 只读展示整改记录(方案、措施、人员、附件等)
|
||
2. 填写验收表单(结果、备注、验收附件、签名)
|
||
3. 根据验收选择**预览下一步流程**
|
||
4. 选择或通过只读展示**下一步处理人**
|
||
5. 提交到 `POST /frontend/hazard/verify`
|
||
|
||
---
|
||
|
||
## 2. 页面入参(URL Query)
|
||
|
||
从首页 / 巡检列表跳转,由 `utils/hazardNav.js` → `buildAcceptanceUrl` 构建:
|
||
|
||
| 参数 | 是否必需 | 说明 |
|
||
|------|----------|------|
|
||
| `rectifyId` | **推荐必带** | 整改记录 ID,有则只调整改详情接口 |
|
||
| `hazardId` | 列表通常会带 | 隐患 ID,无 `rectifyId` 时用于兜底拉取 |
|
||
| `assignId` | 可选 | 指派 ID,用于从隐患详情中定位正确 assign |
|
||
| `taskId` | **流程预览依赖** | 工作流任务 ID,用于「下一步流程」接口 |
|
||
|
||
示例:
|
||
|
||
```
|
||
/pages/hiddendanger/acceptance?hazardId=184&assignId=158&rectifyId=150&taskId=xxx
|
||
```
|
||
|
||
> **注意**:`rectify/detail` 响应里通常**没有** `taskId`,下一步流程主要依赖 URL 传入的 `taskId`。若列表未带且详情也解析不到,「下一步流程」会显示「暂无下一步流程」。
|
||
|
||
---
|
||
|
||
## 3. 页面加载流程
|
||
|
||
```
|
||
onLoad
|
||
├─ 解析 URL 参数(rectifyId / hazardId / assignId / taskId)
|
||
├─ loadPageData()
|
||
│ ├─ 有 rectifyId → fetchRectifyDetail() // 只调一次
|
||
│ ├─ 无 rectifyId、有 hazardId → fetchDetail()
|
||
│ └─ fetchNextStep()
|
||
└─ restoreDraft() // 恢复本地草稿(若有)
|
||
```
|
||
|
||
### 3.1 数据接口选择(重要)
|
||
|
||
**不要两个详情接口都调**,当前规则:
|
||
|
||
| 条件 | 调用接口 | 说明 |
|
||
|------|----------|------|
|
||
| 有 `rectifyId` | `GET /frontend/hazard/rectify/detail` | **唯一数据源** |
|
||
| 无 `rectifyId`、有 `hazardId` | `GET /frontend/hazard/detail` | 从 `assigns[].rectify` 取整改记录 |
|
||
|
||
### 3.2 两个详情接口的区别
|
||
|
||
| 对比项 | `rectify/detail` | `hazard/detail` 内嵌 `rectify` |
|
||
|--------|------------------|-------------------------------|
|
||
| 数据范围 | 单条整改记录 | 整条隐患 + 指派 + 整改 |
|
||
| 人员结构 | `members` / `managers` 对象数组 | `memberNames` / `managerNames` 字符串数组 |
|
||
| 整改人 | 有 `rectifierName` | 有 `rectifierName` |
|
||
| 状态字段 | `statusName` | `rectifyStatusName` |
|
||
| 适用场景 | 有 `rectifyId` 时优先 | 仅无 `rectifyId` 时兜底 |
|
||
|
||
---
|
||
|
||
## 4. 整改记录字段映射(`applyRectifyData`)
|
||
|
||
接口返回结构不统一,统一在 `applyRectifyData` 中做映射:
|
||
|
||
| 页面展示字段 | 映射规则 |
|
||
|--------------|----------|
|
||
| 整改方案/措施/管控/完成情况/费用 | 同名字段直取 |
|
||
| 安全管理人员 | 有 `managers[]` → 取 `nickName` 去重;否则用 `managerNames` |
|
||
| 整改责任人 | 有 `members[]` → 取 `nickName` 去重;否则用 `memberNames` |
|
||
| 完成情况 | `rectifyStatusName` 或 `statusName` |
|
||
| 整改附件 | `attachments` |
|
||
| 整改人(不通过时展示) | `rectifierName` |
|
||
|
||
### 人员名显示规则(易踩坑)
|
||
|
||
`rectify/detail` **同时可能返回**:
|
||
|
||
- `memberNames` / `managerNames`(身份名,如:阎勇、user1)
|
||
- `members` / `managers`(对象,含 `nickName`,如:xiaomi、duoduo)
|
||
|
||
**当前规则:有 `members` / `managers` 数组时,优先用其中的 `nickName`,不用 `memberNames`。**
|
||
|
||
---
|
||
|
||
## 5. 验收表单交互
|
||
|
||
### 5.1 验收结果 `formData.result`
|
||
|
||
| 值 | 含义 |
|
||
|----|------|
|
||
| `1` | 通过(默认) |
|
||
| `2` | 不通过 |
|
||
|
||
切换时触发 `onResultChange` → 重新请求下一步流程 `fetchNextStep()`。
|
||
|
||
- 切到「不通过」:清空已选下一步处理人
|
||
- 切到「通过」:若未选快速审批,默认 `quickApproveRadio = 'yes'`
|
||
|
||
### 5.2 是否快速审批 `formData.quickApproveRadio`
|
||
|
||
- **仅验收通过时显示**,必选
|
||
- `yes` = 快速审批;`no` = 不快速审批
|
||
- 切换时触发 `onQuickApproveChange` → `fetchNextStep()`
|
||
|
||
### 5.3 下一步流程(只读预览)
|
||
|
||
接口:`POST /flow/task/next-nodes`
|
||
|
||
**三种情况都必须传:**
|
||
|
||
```json
|
||
{
|
||
"taskId": "当前任务ID",
|
||
"includeSubProcess": true,
|
||
"previewVariables": { ... }
|
||
}
|
||
```
|
||
|
||
`previewVariables` 按验收选择变化:
|
||
|
||
| 场景 | previewVariables |
|
||
|------|------------------|
|
||
| 不通过 | `{ "pass": false }` |
|
||
| 通过 + 快速审批 | `{ "pass": true, "quickApprove": true }` |
|
||
| 通过 + 不快速审批 | `{ "pass": true, "quickApprove": false }` |
|
||
|
||
展示逻辑:取返回 `branches` 中 `matched === true` 的分支(没有则取第一个)的 `nextNode.taskName`。
|
||
|
||
### 5.4 下一步处理人
|
||
|
||
| 验收结果 | UI | 数据来源 |
|
||
|----------|-----|----------|
|
||
| 不通过 | 只读文本 | `rectify/detail` 的 **`rectifierName`**(整改人) |
|
||
| 通过 | 底部弹窗单选 | `GET /admin/user/dept/users/{deptId}` |
|
||
|
||
通过时选人说明:
|
||
|
||
- `deptId` 来自本地 `userInfo.userIdentity.deptId`(无则取 `userInfo.deptId`)
|
||
- 部门人员接口返回 `{ userId, nickName }`,可能没有 `identityId`
|
||
- 选人 ID 解析:`identityId` → `userIdentityId` → `userId`(兜底)
|
||
- 提交字段名是 `assigneeIdentityId`,无 `identityId` 时实际传的是 `userId`
|
||
|
||
### 5.5 电子签名
|
||
|
||
- 必填,提交前先上传云端得到 `signPath`
|
||
- 打开「选择下一步处理人」弹窗时,**卸载签名 Canvas**(`v-if="showCanvas && !showAssigneePopup"`),避免微信小程序原生 canvas 层级穿透盖住弹窗
|
||
|
||
### 5.6 验收图片/视频
|
||
|
||
- 使用 `up-upload` + 水印 canvas
|
||
- 提交时只取 `status === 'success'` 的文件,经 `buildAttachmentItem` 转成附件对象
|
||
|
||
---
|
||
|
||
## 6. 提交验收
|
||
|
||
接口:`POST /frontend/hazard/verify`(`acceptanceRectification`)
|
||
|
||
### 6.1 提交前校验
|
||
|
||
1. 必须有 `rectifyId`
|
||
2. 通过时:必须选「是否快速审批」
|
||
3. 通过 + 不快速审批:必须选下一步处理人
|
||
4. 必须有电子签名
|
||
|
||
### 6.2 请求体
|
||
|
||
**通用字段(通过/不通过都传):**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `rectifyId` | number | 整改记录 ID |
|
||
| `result` | number | `1` 通过 / `2` 不通过 |
|
||
| `verifyRemark` | string | 验收备注,可为空 |
|
||
| `attachments` | array | 验收附件 `[{ fileName, filePath, fileType, fileSize }]` |
|
||
| `signPath` | string | 电子签名服务器路径 |
|
||
|
||
**仅通过时额外传:**
|
||
|
||
| 字段 | 条件 | 说明 |
|
||
|------|------|------|
|
||
| `quickApprove` | `result === 1` | boolean |
|
||
| `assigneeIdentityId` | `quickApprove === false` | 下一步处理人 ID |
|
||
|
||
**不提交的内容:**
|
||
|
||
- 整改记录只读区所有字段
|
||
- 下一步流程名称(仅预览)
|
||
- 不通过时的 `rectifierName`(仅展示,后端按流程自行处理)
|
||
- 快速审批为「是」时的下一步处理人
|
||
|
||
### 6.3 提交示例
|
||
|
||
**不通过:**
|
||
```json
|
||
{
|
||
"rectifyId": 150,
|
||
"result": 2,
|
||
"verifyRemark": "整改不到位",
|
||
"attachments": [],
|
||
"signPath": "https://oss.../sign.png"
|
||
}
|
||
```
|
||
|
||
**通过 + 快速审批:**
|
||
```json
|
||
{
|
||
"rectifyId": 150,
|
||
"result": 1,
|
||
"verifyRemark": "",
|
||
"attachments": [],
|
||
"signPath": "https://oss.../sign.png",
|
||
"quickApprove": true
|
||
}
|
||
```
|
||
|
||
**通过 + 不快速审批:**
|
||
```json
|
||
{
|
||
"rectifyId": 150,
|
||
"result": 1,
|
||
"verifyRemark": "",
|
||
"attachments": [],
|
||
"signPath": "https://oss.../sign.png",
|
||
"quickApprove": false,
|
||
"assigneeIdentityId": "44"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 草稿缓存
|
||
|
||
使用 `useDraftCache`,命名空间 `DRAFT_NS.ACCEPT`,key 基于 `rectifyId`。
|
||
|
||
**会缓存:**
|
||
|
||
- 验收结果、备注、快速审批选择
|
||
- 下一步处理人选择
|
||
- 验收上传附件列表
|
||
- 签名相关状态
|
||
|
||
**不会缓存:**
|
||
|
||
- 整改记录只读区(每次进页重新拉接口)
|
||
|
||
恢复草稿后会再次调用 `fetchNextStep()`,保证下一步流程与当前验收选择一致。
|
||
|
||
---
|
||
|
||
## 8. 关键函数索引
|
||
|
||
| 函数 | 作用 |
|
||
|------|------|
|
||
| `loadPageData` | 页面数据加载入口 |
|
||
| `fetchRectifyDetail` | 调整改详情,有 `rectifyId` 时用 |
|
||
| `fetchDetail` | 调隐患详情,无 `rectifyId` 时兜底 |
|
||
| `applyRectifyData` | 统一映射整改记录到页面 |
|
||
| `resolveManagerNames` / `resolveMemberNames` | 人员名映射(优先 members/managers 的 nickName) |
|
||
| `buildPreviewVariables` | 构建下一步流程预览变量 |
|
||
| `fetchNextStep` | 请求下一步流程名称 |
|
||
| `onResultChange` / `onQuickApproveChange` | 切换验收选项后刷新流程预览 |
|
||
| `openAssigneePopup` / `fetchAssigneeList` | 通过时选择下一步处理人 |
|
||
| `validateFormBeforeSubmit` | 提交前表单校验 |
|
||
| `handleSubmit` / `executeSubmit` | 签名处理 + 提交验收 |
|
||
|
||
---
|
||
|
||
## 9. 关联文件
|
||
|
||
| 文件 | 关系 |
|
||
|------|------|
|
||
| `utils/hazardNav.js` | 构建跳转 URL(含 taskId) |
|
||
| `request/api.js` | 接口定义 |
|
||
| `utils/upload.js` | 附件上传与 `buildAttachmentItem` |
|
||
| `utils/draftCache.js` / `utils/useDraftCache.js` | 草稿 |
|
||
| `pages/hiddendanger/rectification.vue` | 签名 canvas 穿透弹窗的同类处理参考 |
|
||
|
||
---
|
||
|
||
## 10. 常见问题速查
|
||
|
||
| 现象 | 可能原因 |
|
||
|------|----------|
|
||
| 下一步流程显示「暂无」 | URL 未带 `taskId`,且详情接口也解析不到 |
|
||
| 人员显示身份名而非 nickName | `members` 数组为空,走了 `memberNames` 兜底 |
|
||
| 不通过时处理人不对 | 应检查 `rectify/detail` 的 `rectifierName` 是否有值 |
|
||
| 选人弹窗被白块挡住 | 签名 canvas 未在弹窗打开时卸载 |
|
||
| 选人列表为空 | `userInfo.userIdentity.deptId` 缺失,或部门无人员 |
|
||
| 提交了但后端报处理人错误 | `assigneeIdentityId` 传的是 `userId`,需确认后端是否接受 |
|
||
|
||
---
|
||
|
||
## 11. 维护建议
|
||
|
||
1. **有 `rectifyId` 就不要再调 `hazard/detail` 做展示**,避免重复请求和数据覆盖混乱。
|
||
2. 改人员展示逻辑时,优先看 `resolveManagerNames` / `resolveMemberNames`,不要直接改模板。
|
||
3. 改流程预览时,确认 `taskId`、`previewVariables`、`includeSubProcess: true` 三者始终齐全。
|
||
4. 新增提交字段时,同步更新本文档第 6 节。
|