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