# 质检指标层级维护 - 前端联调方案 > 变更模块:`yudao-module-mes`(质检指标主数据) > 变更目的:让「分组项 / 所属分组 / 公式 / 排序号」这四个层级字段可以在**质检指标页**维护, > 不再只能靠 SQL 造数据。 > 报告侧的取数逻辑**一行未改** —— 界面造出来的分组与 SQL 造出来的分组,在报告里完全同形。 ## 涉及页面 - 质检指标列表页(菜单:质量管理 → 质检指标) ## 业务流程与数据带入 1. 在质检指标页新建「分组项」→ 该指标成为**顶级指标**,`所属分组` 固定为顶级、`公式` 必填。 2. 新建「录入项」→ 在 `所属分组` 里选择第 1 步建的分组项 → 该指标成为这个分组的子项。 3. 检测方案 → 质检单 → 出报告:报告侧按 `parent_id` 把分组项与它的子项还原成两层表头, 组名纵向合并、公式进「检测要求」列。**这一步的展示效果与数据来自 SQL 时完全一致。** ## API | 方法 | 路径 | 说明 | |------|------|------| | GET | `/mes/qc/indicator/page` | 分页查询(权限 `mes:qc-indicator:query`) | | GET | `/mes/qc/indicator/group-list` | **新增**:分组项精简列表(权限 `mes:qc-indicator:query`) | | POST | `/mes/qc/indicator/create` | 新增(权限 `mes:qc-indicator:create`) | | PUT | `/mes/qc/indicator/update` | 修改(权限 `mes:qc-indicator:update`) | | DELETE | `/mes/qc/indicator/delete` | 删除(权限 `mes:qc-indicator:delete`) | | GET | `/mes/qc/indicator/export-excel` | 导出(权限 `mes:qc-indicator:export`) | 接口前缀为 `/admin-api`,与既有约定一致,下文路径均省略该前缀。 ### GET /mes/qc/indicator/group-list 专供「所属分组」下拉。**只返回分组项**(`item_type = 2`),不返回录入项。 无请求参数。响应为指标对象数组(字段同下方响应字段表,此处只保证 `id` / `name` 有值)。 ### 请求参数(create / update) `update` 与 `create` 共用同一个请求体。新增字段标 ★。 | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | id | Long | update 必填 | 编号 | | code | String | 是 | 检测项编码 | | name | String | 是 | 检测项名称 | | type | Integer | 是 | 检测项类型(字典 `mes_indicator_type`) | | tool | String | 否 | 检测工具 | | ★ itemType | Integer | 否 | 条目类型:`1`=录入项(默认),`2`=分组项 | | ★ parentId | Long | 否 | 父指标编号,`0` 或留空 = 顶级指标 | | ★ formulaText | String | 分组项必填 | 公式展示文本,报告里作为该分组的「检测要求」 | | ★ sortOrder | Integer | 否 | 同级排序号,留空则自动排到同级末尾 | | resultType | Integer | 录入项必填 | 结果值类型(字典 `mes_qc_result_type`)。**分组项不填** | | resultSpecification | String | 条件必填 | 结果值属性。`resultType` 为「文件」或「字典」时必填 | | remark | String | 否 | 备注 | > `resultType` 原先带 `@NotNull`,本轮**摘掉了**:分组项按现网口径就是 `NULL`(现网 3 个分组行 > 的 `result_type` 全为 NULL)。改为服务端按条目类型条件校验:**只有录入项必填**。 ### 响应字段新增(page / export-excel) | 字段 | 类型 | 说明 | |------|------|------| | itemType | Integer | 条目类型 | | parentId | Long | 父指标编号,`0` 表示顶级 | | parentName | String | **所属分组名称**,由后端回填;顶级指标为 `null` | | formulaText | String | 公式 | | sortOrder | Integer | 同级排序号 | `parentName` 由控制器回填,取值方式是:收集本页所有非 `0` 的 `parentId` → 一次性按 id 批量查指标 → 建 `id → name` 映射回填。因此**父指标即使不在当前页、甚至不在筛选结果内,名称也能正确解析**。 > **`/get`(详情)接口不回填 `parentName`**,与 `/page`、`/export-excel` 不一致。 > 编辑弹窗的数据来源是列表行(列表行已带 `parentName`),不受影响;若后续有页面直接调 `/get` 展示 > 所属分组,需要另行处理。 ### 响应示例 ```json { "code": 0, "data": { "list": [ { "id": 21, "code": "SEED-BT-WATER", "name": "水分", "type": 4, "itemType": 2, "parentId": 0, "parentName": null, "formulaText": "w = (m1 - m0) / m × 100%", "sortOrder": 30, "resultType": null, "resultSpecification": null }, { "id": 22, "code": "SEED-BT-WATER-M", "name": "试样质量 m", "type": 4, "itemType": 1, "parentId": 21, "parentName": "水分", "formulaText": null, "sortOrder": 1, "resultType": 1, "resultSpecification": null } ], "total": 34 } } ``` ## 字段展示规则 | 字段 | 展示位置 | 说明 | |------|----------|------| | 条目类型 | 列表列、新增/修改表单 | 列表用标签展示:`分组项` / `录入项` | | 所属分组 | 列表列、新增/修改表单 | 列表取 `parentName`,为 `null` 时显示 `-`(表示顶级指标) | | 公式 | 新增/修改表单 | **仅分组项可见,且必填** | | 排序号 | 新增/修改表单 | 数字输入,最小 `0`;留空由服务端补齐 | | 条目类型 | 搜索表单 | 下拉:录入项 / 分组项 | **「所属分组」不是树形展示**:分组项只能是顶级,所以候选项就是一层平铺的分组项列表 (外层套一个「顶级指标」根节点)。不提供多级树。 ## 业务规则说明 ### 层级规则(只允许两层) | 场景 | 规则 | |------|------| | 分组项 | 必须是**顶级指标**,`所属分组` 项在表单上**不出现**,落库固定 `parentId = 0` | | 录入项 | 可挂到任意分组项下,也可作为顶级指标(`所属分组` 留空) | | 为什么只有两层 | 规则本身推出:父必须是**分组项**,而分组项**只能顶级** ⇒ 第三层无法构造 | **「所属分组」在表单上的候选只有分组项**:新建录入项时不可能选到自己,也不可能选到另一个录入项。 ### 校验规则与提示文案 服务端按业务优先级**只返回第一处不满足的条件**,避免一次抛多条让用户抓不住重点。 | 错误码 | 触发条件 | 提示文案要点 | |--------|----------|--------------| | `1040601007` | 分组项却选了所属分组 | 含分组名 + 所选父指标名 + 改法(把条目类型改为录入项再选分组) | | `1040601006` | 父指标是自己 | 「父指标不能是自己」 | | `1040601004` | 父指标不存在(已被删除) | 含父指标编号 + 改法(重新选择或清空) | | `1040601005` | 父指标不是分组项 | 含父指标名 + 它当前的条目类型中文名 + 改法(改选分组项 / 先把它的条目类型改为分组项) | | `1040601009` | 录入项未填结果值类型 | 「录入项的结果值类型不能为空」 | | `1040601003` | 结果值类型为文件/字典但结果值属性为空 | 「结果值属性不能为空」 | | `1040601008` | **改挂到分组下**时,该指标下已有子项 | 含指标名 + 子项条数 + 「请先删除或移走这 N 个子项」 | | `1040601008` | **改为录入项**时,该指标下已有子项 | 同上错误码,文案改为「否则这些子项会失去所属分组」 | 后两条用同一个错误码、**文案各自贴合场景**:一个是「不能再挂到别的分组下」,一个是 「不能反过来变成子项」。 ### 落库时的自动处理 | 字段 | 处理 | |------|------| | `parentId` | 留空补 `0` | | `itemType` | 留空补 `1`(录入项) | | `resultType` / `resultSpecification` | **分组项强制清空**。录入项改分组项时,旧的结果值会被真正写回 `NULL` | | `sortOrder` | 留空自动排到同级末尾:顶级步长 `10`,子项步长 `1` | > 「改分组项后结果值被清空」依赖 DO 上的 `updateStrategy = ALWAYS`。MyBatis-Plus 默认的 > `NOT_NULL` 策略会把 `null` 字段从 UPDATE 语句里剔除,导致旧结果值残留 —— 这是本轮修掉的 > 一个真实写入缺陷,前端无需感知。 ### 删除 **删除分组项会级联删除它下面的所有子项。** | 操作 | 结果 | |------|------| | 删除分组项 | 它的全部子项一并删除 | | 删除录入项 | 只删它自己 | 报告侧对指标被删已有兜底:指标已被删除的明细行只计入 `missingIndicatorCount` 进 `warnings`, 不会导致出件失败。 ## 注意事项 - **「条目类型」不在导出 Excel 里**。`所属分组`、`公式`、`排序号` 三列已进 Excel, 条目类型没有对应列(可结合「所属分组」是否有值判断)。这是本轮明确接受的口径。 - **`单位` 字段不对前端暴露**,也不在新增/修改表单里。原因:该列在全部后端代码里没有任何读取方, 报告里的「单位」取自检验方案行的计量单位;放一个没人读的字段进表单只会误导录入人。 - **切换条目类型会清空录入项专属字段**:表单切到「分组项」时,所属分组会被重置为顶级、 结果值类型与结果值属性会被清空。这是必要的 —— 否则被隐藏的字段仍会随表单提交, 残留的 `parentId` 会被后端层级校验顶回来。 - **编辑分组项时,「所属分组」字段不可见、「公式」必填生效**。 - **`sortOrder` 允许重复**:服务端不校验同级排序号的唯一性,相同排序号的相对顺序不保证。 - **`group-list` 返回的是全部分组项**,不按任何维度过滤;如果分组项数量增长到很大, 需要考虑改造为分页或搜索式选择。