Files
threeonecheck_web/pages/hiddendanger/acceptance-逻辑说明.md
2026-07-27 09:27:22 +08:00

313 lines
10 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.

# 隐患验收页逻辑说明
> 对应文件:`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 节。