Files
zkxw/docs/superpowers/specs/2026-06-11-env-detect-design.md
T
2026-06-11 15:42:58 +08:00

272 lines
11 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.
# 环境检测模块 — 功能设计文档
> 日期:2026-06-11
> 状态:已实现(2026-06-11)
> 需求来源:质检部门新增环境检测登记能力
> 已确认:**方案 B — 扁平单表**(一次登记对应一个检测项目)
> 已确认:**检测人支持多选**,新增时默认选中当前登录用户
---
## 1. 背景与目标
### 1.1 业务背景
质检部门需对实验室/洁净区环境进行定期检测并留存记录,包括检测时间、检测人、检测项目、结果描述及检测附件。
### 1.2 目标
1. 在 **质检基础信息** 下新增菜单 **环境检测项维护**,管理可选检测项目(编码、名称、启用/停用)。
2. 在 **质检管理** 下新增菜单 **环境检测管理**,支持环境检测信息的登记、查询、编辑、查看与软删除。
3. 迁移 SQL 预置 6 项初始检测项目,租户可通过维护菜单增删改(停用后新登记不可选,历史记录保留快照)。
### 1.3 非目标(一期不做)
- 一次登记包含多个检测项目(头 + 明细行模式)
- 与洁净室主数据(`biz_clean_room`)关联
- 合格/不合格结论字段、审批流、到期提醒
- 与样本质检工单/任务联动
- 小程序端
---
## 2. 已确认方案
| 方案 | 说明 | 结论 |
|------|------|------|
| A. 主表 + 明细行 | 一次登记可含多项,每项独立描述与附件 | 未采用 |
| **B. 扁平单表** | **每条记录 = 一次检测 = 一个检测项目** | **采用** |
| C. 硬编码项目 | 不做维护菜单 | 未采用 |
**方案 B 含义**:用户登记「表面微生物检测」与「沉降菌检测」需分别创建两条记录;检测时间、检测人(可多人)、结果描述、附件均挂在单条记录上。
---
## 3. 菜单与路由
| 菜单 | 父级 | path | 组件 | menuCode |
|------|------|------|------|----------|
| 环境检测项维护 | 质检基础信息 `QCB…001` | `env-detect-item` | `views/quality-inspection/env-detect-item/index.vue` | `biz:envDetectItem:list` |
| 环境检测管理 | 质检管理 `QCM…001` | `env-detect-record` | `views/quality-inspection/env-detect-record/index.vue` | `biz:envDetectRecord:list` |
同步文件:
- `web-admin/src/router/modules/sqxp.ts`
- `backend/app/api/menu.py`
- `docs/sql/migrations/2026-06-11-env-detect.sql`
- `docs/sql/zkxw.sql`(全量基线,实现阶段更新)
---
## 4. 数据模型
命名空间:`biz_env_detect_*`。均含标准公共字段(`id` UUID、`tenant_no`、`order_num`、`remark`、`create_by`、`create_dept_id`、`create_time`、`update_by`、`update_time`、`del_flag`)。
### 4.1 `biz_env_detect_item` — 环境检测项(主数据)
| 字段 | 类型 | 说明 |
|------|------|------|
| item_code | VARCHAR(64) | 项目编码,租户内唯一(`del_flag=0`) |
| item_name | VARCHAR(200) | 项目名称 |
| status | CHAR(1) | `1` 启用 / `0` 停用 |
**索引**:`uk_env_item_tenant_code (tenant_no, item_code, del_flag)`
**初始种子数据**(迁移时按租户 `zkxw` 插入,其他租户可自行维护):
| item_code | item_name |
|-----------|-----------|
| BMWS | 表面微生物检测 |
| SYFS | 实验室风速检测 |
| ZWQD | 紫外灯强度检测 |
| CJJ | 沉降菌检测 |
| JJZY | 洁净区噪音检测 |
| XFZL | 洁净区悬浮粒子检测 |
### 4.2 `biz_env_detect_record` — 环境检测登记(业务记录)
| 字段 | 类型 | 说明 |
|------|------|------|
| record_no | VARCHAR(32) | 登记编号:`HJ` + yyyyMMdd + 4 位日序,租户内唯一 |
| detect_time | DATETIME | 检测时间(必填) |
| inspector_ids | VARCHAR(500) | 检测人用户 ID,逗号分隔,至少 1 人(必填) |
| inspector_names | VARCHAR(500) | 检测人姓名快照,逗号分隔,顺序与 `inspector_ids` 一致 |
| env_detect_item_id | VARCHAR(64) | 检测项目主数据 ID(必填) |
| item_code | VARCHAR(64) | 项目编码快照 |
| item_name | VARCHAR(200) | 项目名称快照 |
| result_desc | VARCHAR(2000) | 检测结果描述(必填) |
| attachment_urls | VARCHAR(2000) | 检测附件 URL,逗号分隔(MinIO,可选) |
**索引**:
- `uk_env_rec_tenant_no (tenant_no, record_no, del_flag)`
- `idx_env_rec_tenant_time (tenant_no, detect_time, del_flag)`
- `idx_env_rec_tenant_item (tenant_no, env_detect_item_id, del_flag)`
**快照规则**:
- 检测项目:创建/更新时从 `biz_env_detect_item` 写入 `item_code`、`item_name`。
- 检测人:创建/更新时根据 `inspector_ids` 批量查询 `sys_user`,按提交顺序写入 `inspector_names`(`nick_name` 优先,无则 `user_name`)。
- 主数据或用户改名后,历史记录仍展示保存时的快照。
**存储约定**:`inspector_ids` / `inspector_names` 与 `attachment_urls` 相同,采用逗号分隔字符串落库;API 层 `_row_to_dict` 解析为 `inspectorIds: string[]`、`inspectorNames: string[]`,并额外输出 `inspectorDisplay`(姓名以 ` / ` 拼接,供列表列展示)。
---
## 5. 后端 API
路由注册于 `app/api/env_detect.py`(或拆分为 `env_detect_item.py` + `env_detect_record.py`),在 `app/api/__init__.py` 与 `app/main.py` 注册。
前缀:`/web/admin/`。租户隔离 + 数据权限 + 软删除,列表默认 `create_time DESC`。
### 5.1 环境检测项
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/env-detect-items` | 分页列表(keyword、status) |
| GET | `/env-detect-items/active` | 启用项全量(登记下拉用,无分页) |
| GET | `/env-detect-items/{id}` | 详情 |
| POST | `/env-detect-items` | 新增 |
| PUT | `/env-detect-items/{id}` | 更新 |
| DELETE | `/env-detect-items/{id}` | 软删除 |
**校验**:`item_code`、`item_name` 必填;编码租户内唯一;已被登记引用的项允许停用,不允许物理删除(软删除前可选:若存在引用则提示或禁止删除,一期采用**允许软删除**但登记下拉仅取 `status=1` 且 `del_flag=0`)。
### 5.2 环境检测登记
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/env-detect-records` | 分页列表 |
| GET | `/env-detect-records/{id}` | 详情 |
| POST | `/env-detect-records` | 新增(服务端生成 `record_no`) |
| PUT | `/env-detect-records/{id}` | 更新 |
| DELETE | `/env-detect-records/{id}` | 软删除 |
**列表筛选参数**:`keyword`(编号/检测人姓名/结果描述模糊)、`envDetectItemId`、`inspectorId`(命中 `inspector_ids` 中任一 ID 即返回,MySQL `FIND_IN_SET`)、`detectTimeStart`、`detectTimeEnd`。
**创建/更新 Body**:
```json
{
"detectTime": "2026-06-11 14:30:00",
"inspectorIds": ["current-user-uuid", "other-user-uuid"],
"envDetectItemId": "item-uuid",
"resultDesc": "检测结果描述",
"attachmentUrls": "url1,url2",
"remark": ""
}
```
**检测人校验**:
- `inspectorIds` 必填,去重后至少 1 个有效用户 ID。
- 用户须属于当前租户且未删除;无效 ID 返回 400。
- 保存时按 `inspectorIds` 数组顺序生成快照,不依赖前端传入姓名。
**编号生成**:`HJ` + `yyyyMMdd` + 4 位序,逻辑对齐 `pilot_delivery._generate_delivery_no`。
---
## 6. 前端设计
### 6.1 界面模式
| 页面 | 模式 | 参考 |
|------|------|------|
| 环境检测项维护 | **P01** | `sample-reception-check-item/index.vue` |
| 环境检测管理 | **P01** + 附件卡片 | `sample-reception-check-item` + OpenSpec 附件上传卡片 |
### 6.2 环境检测项维护
- 筛选:关键词(编码/名称)、状态
- 列表列:序号、项目编码、项目名称、状态 Tag、备注、操作(查看/编辑/删除)
- 弹窗字段:项目编码、项目名称、状态、备注
- 筛选区提示:「停用后新登记不再展示,历史记录仍按快照展示。」
### 6.3 环境检测管理
**筛选**:检测时间范围、检测项目(下拉,启用项)、检测人(用户单选下拉,筛「包含该检测人」的记录)、关键词(编号/结果描述)
**列表列**:序号、登记编号、检测时间、检测人(`inspectorDisplay`,多人以 ` / ` 分隔)、检测项目、结果描述(tooltip 截断)、创建时间、操作
**新增/编辑弹窗**(`dialog-form-layout`,宽约 640px,`form-grid-2`):
| 字段 | 控件 | 必填 |
|------|------|------|
| 检测时间 | `el-date-picker` type=datetime | 是 |
| 检测人 | `el-select` **multiple** + `filterable`,数据源 `fetchUserOptions()` | 是(≥1 人) |
| 检测项目 | 下拉,数据源 `/env-detect-items/active` | 是 |
| 检测结果描述 | `el-input` textarea,`form-col-span-2` | 是 |
| 检测附件 | 附件卡片上传(`fetchUploadAttachment`),`form-col-span-2` | 否 |
| 备注 | `el-input` textarea,`form-col-span-2` | 否 |
**检测人默认与交互**(对齐 `sample-reception` 经手人逻辑,扩展为多选):
1. **新增**:打开弹窗时 `inspectorIds` 默认包含 **当前登录用户 ID**;若用户列表中尚无当前用户,先 `ensureCurrentUserInOptions()` 注入选项(参考 `sample-reception/index.vue` `getCurrentUserHandler`)。
2. **新增默认值**:检测时间默认当前时刻(可选,与样本接收一致)。
3. 用户可继续勾选其他检测人;可取消当前登录人,但提交前须至少保留 1 人(前后端双重校验)。
4. **编辑**:回显已保存的 `inspectorIds`;若历史检测人不在下拉列表中,合并进选项以保证展示。
**查看**:`SystemViewDialog` 展示 `inspectorDisplay`(或逐人换行);附件区支持预览/下载。
**状态 Tag**:本模块无业务状态字段;检测项维护页 `status` 走 `status-tag-registry`。
### 6.4 API 模块
- `web-admin/src/api/env-detect-item.ts`
- `web-admin/src/api/env-detect-record.ts`
类型字段与后端 `_row_to_dict` 保持一致(camelCase)。
---
## 7. 权限与菜单 SQL(草案)
```sql
-- 环境检测项维护(父:质检基础信息 QCB00000000000000000000000000001)
INSERT INTO sys_menu (...) VALUES (
'71000000000000000000000000000001', '环境检测项维护',
'QCB00000000000000000000000000001', 'C', 'env-detect-item',
'/quality-inspection/env-detect-item/index', 'biz:envDetectItem:list', ...
);
-- 环境检测管理(父:质检管理 QCM00000000000000000000000000001)
INSERT INTO sys_menu (...) VALUES (
'71000000000000000000000000000002', '环境检测管理',
'QCM00000000000000000000000000001', 'C', 'env-detect-record',
'/quality-inspection/env-detect-record/index', 'biz:envDetectRecord:list', ...
);
```
`order_num`:项维护置于「质检物料库」之前(建议 7);环境检测管理置于「质检工单」之后(建议 3)。
---
## 8. 实现检查清单
- [ ] `python scripts/check_field_consistency.py` 通过(CRUD ↔ Schema ↔ 前端 formData)
- [ ] `./scripts/update-graph.sh backend` 与 `frontend`(新增模块后)
- [ ] `App.vue` `panelTitleBarTextRules` 写入「环境检测项列表」「环境检测登记列表」
- [ ] 手工验证:新增项 → 登记选到 → 编辑快照不变 → 停用项不出现在下拉
---
## 9. 工作量估时
| 层 | 内容 | 估时 |
|----|------|------|
| DB | 2 表 + 菜单 + 种子 | 0.5d |
| Backend | 2 组 CRUD + 编号生成 | 1d |
| Frontend | 2 个 P01 页 + 附件上传 | 1d |
| 联调 | 字段一致性 + 手工测试 | 0.5d |
| **合计** | | **约 3 人天** |
---
## 10. 变更记录
| 日期 | 说明 |
|------|------|
| 2026-06-11 | 初稿;用户确认方案 B(扁平单表) |
| 2026-06-11 | 检测人改为多选;新增默认选中当前登录用户;库表 `inspector_ids` / `inspector_names` |