Files
huachuang/docs/superpowers/specs/2026-08-17-sub-package-relation-batch-create-design.md

233 lines
9.9 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.

# 子卷包装关系批量新增设计
## 1. 背景与目标
子卷包装关系列表目前仅支持单条新增。新增“批量新增”功能,用户可在同一个弹窗中录入多条 `lms_sub_package_relation` 数据,并在卡片视图与表格视图之间自由切换。两种视图共享同一份数据,切换时不丢失输入。
实现以 `docs/prototype_design/design/2026-08-17-sub-package-relation-card-batch-design.html` 中的“自由切换批量新增”为交互参考,不追求额外视觉扩展,重点是稳定录入、分组校验、部分成功保存和逐行错误反馈。
## 2. 范围
### 2.1 本次包含
- 在子卷包装关系列表工具栏增加“批量新增”按钮。
-`src/views/lms/subpackagerelation/modules` 中封装独立批量新增弹窗组件。
- 支持卡片和表格两种批量录入视图,并可自由切换。
- 复用现有木箱类型选择弹窗选择木箱类型并回填尺寸。
- 复用字典管理中的 `sub_package_status` 状态字典,默认状态为 `0`
- 新增独立批量创建 API、请求 VO、响应 VO 和服务方法。
- 按“木箱码 + 木箱类型”分组校验 `lms_box_type.max_num`
- 合法分组保存;失败分组返回到前端逐行展示,不影响其他合法分组。
### 2.2 本次不包含
- 不修改现有单条新增、修改接口及其请求实体。
- 不调整列表查询、删除、导出功能。
- 不新增权限标识,批量新增沿用 `lms:sub-package-relation:create`
- 不修改数据库表结构。
- 不增加原型之外的批量导入、Excel 粘贴、拖拽排序等功能。
## 3. 前端设计
### 3.1 页面接入
在子卷包装关系列表页接入批量新增弹窗,并在工具栏增加“批量新增”按钮。按钮使用 `lms:sub-package-relation:create` 权限。
批量新增全部成功时关闭弹窗并刷新列表;部分成功时保持弹窗打开,同时刷新列表以显示已保存的数据。
### 3.2 组件职责
`apps/web-antdv-next/src/views/lms/subpackagerelation/modules` 下新增独立批量新增弹窗组件。该组件负责:
- 维护统一的批量记录数组 `rows`
- 渲染卡片视图或表格视图。
- 新增、复制、删除和清空记录。
- 打开木箱类型选择弹窗并回填当前行。
- 执行前端必填校验。
- 提交批量请求并将失败结果映射回具体记录。
每条前端记录包含稳定且不重复的 `clientKey`。切换视图、增删记录和提交失败后均保留该标识。后端原样返回失败记录的 `clientKey`,前端以此定位错误行,不使用可能变化的数组下标作为唯一标识。
### 3.3 录入字段
批量新增只录入以下字段:
| 字段 | 必填 | 交互 |
| --- | --- | --- |
| `packageBoxSn` | 是 | 输入木箱唯一码 |
| `boxType` | 是 | 点击只读输入区域,打开木箱类型选择弹窗 |
| `boxLength` | 否 | 选择木箱类型后自动回填,只读 |
| `boxWidth` | 否 | 选择木箱类型后自动回填,只读 |
| `boxHigh` | 否 | 选择木箱类型后自动回填,只读 |
| `qualityGuaranPeriod` | 是 | 输入保质期 |
| `dateOfFgInbound` | 是 | 选择入库日期 |
| `containerName` | 是 | 输入子卷号 |
| `status` | 是 | 使用 `sub_package_status` 字典,默认 `0` |
木箱类型选择复用:
`apps/web-antdv-next/src/views/lms/boxtype/components/BoxTypeSelectModal.vue`
组件记录当前正在选择木箱类型的 `clientKey`。选择完成后,将 `boxType``boxLength``boxWidth``boxHigh` 回填到该记录。
### 3.4 卡片与表格切换
- 弹窗初始存在一条空记录,默认显示表格视图。
- 卡片和表格只负责展示与编辑,数据源始终是同一个 `rows` 数组。
- 视图切换不创建数据副本,不触发提交,也不清理校验错误。
- 卡片视图按记录展示字段和错误信息。
- 表格视图按行展示字段,宽度不足时使用横向滚动。
### 3.5 行操作
- 新增:在末尾添加一条空记录,状态默认 `0`
- 复制:复制木箱类型、尺寸、保质期、入库日期和状态;清空木箱唯一码、子卷号,并生成新的 `clientKey`
- 删除:删除目标记录;组件至少保留一条空记录。
- 清空:清除全部输入和错误,并恢复为一条状态为 `0` 的空记录。
### 3.6 前端校验和结果处理
提交前检查所有必填字段。有缺失时不发送请求,在卡片或表格对应行显示错误。
后端响应后:
- 全部成功:关闭弹窗,提示成功,触发列表刷新。
- 部分成功:刷新列表;删除已保存记录,只保留失败记录;根据 `clientKey` 写入错误信息;弹窗保持打开。
- 全部失败:保留全部记录,根据 `clientKey` 展示错误信息。
## 4. 后端接口设计
### 4.1 接口
新增独立接口:
`POST /lms/sub-package-relation/batch-create`
权限:`lms:sub-package-relation:create`
现有 `POST /create``PUT /update` 不变。
### 4.2 请求实体
新增批量请求 VO 和批量行 VO避免复用现有包含大量必填校验的 `SubPackageRelationSaveReqVO`
批量请求包含非空记录列表;每条记录包含:
- `clientKey`
- `packageBoxSn`
- `boxType`
- `boxLength`
- `boxWidth`
- `boxHigh`
- `qualityGuaranPeriod`
- `dateOfFgInbound`
- `containerName`
- `status`
后端对 `clientKey` 和业务必填字段再次校验。批量行 VO 不包含 `id`,该接口只执行新增。
### 4.3 响应实体
响应包含:
- `successCount`:成功保存条数。
- `failureCount`:失败条数。
- `failures`:失败记录列表。
每条失败记录包含:
- `clientKey`:前端记录标识。
- `rowIndex`:请求中的一基行号,用于辅助展示和日志定位。
- `errorCode`:稳定的错误类型。
- `message`:面向用户的中文错误信息。
预期错误类型至少包括必填校验失败、木箱类型不存在、木箱容量超限和分组保存失败。
## 5. 业务校验与保存流程
### 5.1 分组规则
请求记录按 `packageBoxSn + boxType` 分组。每个分组是容量校验和保存事务的最小业务单元。
### 5.2 木箱类型校验
根据请求中去重后的 `boxType` 批量查询 `lms_box_type`。不存在的木箱类型对应分组全部失败,每条记录均返回错误。
后端容量判断使用数据库中 `lms_box_type``max_num`,不信任前端回填数据。请求携带的长、宽、高作为本次关系记录的保存值;木箱类型不存在时不保存。
### 5.3 容量校验
对每个“木箱码 + 木箱类型”分组,统计数据库中相同木箱码和木箱类型的现有有效关系数量,并计算:
`数据库已有数量 + 本次分组数量 <= lms_box_type.max_num`
满足条件时分组可保存;超过上限时整个分组失败,本次分组内一条都不保存。错误信息包含木箱码、类型、最大容量、已有数量和本次提交数量,例如:
`木箱 BX001类型 A最多容纳 3 个子卷,已有 2 个,本次提交 2 个`
逻辑删除数据不计入已有数量,沿用 MyBatis-Plus 的逻辑删除过滤规则。
### 5.4 分组隔离保存
通过独立事务执行器或等价的可生效事务边界逐组保存,禁止依赖同类方法自调用触发事务。
- 合法分组在独立事务中写入。
- 分组内任意一条写入失败,该组事务全部回滚。
- 一个分组失败不影响其他分组继续保存。
- 保存失败时,该组每条记录均返回同一分组写入错误。
接口本身正常返回结构化结果;仅在无法继续处理整个请求的系统级异常时返回通用接口错误。
### 5.5 并发边界
本次仅在服务层执行“查询已有数量后判断”的容量校验,不新增数据库锁、唯一约束或表结构。并发请求同时操作相同木箱码和类型时,仍可能产生竞态;该问题不在本次“不修改数据库结构、不过度设计”的实现范围内。
## 6. 错误展示
前端在记录级别保存后端错误:
- 卡片视图:显示在卡片头部或卡片内容上方。
- 表格视图:显示在对应行的错误区域,并保留该行所有输入。
- 顶部汇总提示成功条数和失败条数。
错误记录在用户修改对应行后可清除;再次提交时只提交弹窗中保留的失败记录。
## 7. 验证方案
### 7.1 后端测试
- 未超 `max_num` 时正常保存。
- 数据库已有数量加本次数量刚好等于 `max_num` 时正常保存。
- 超过 `max_num` 时该组全部失败。
- 多个分组中一组超限,其他组正常保存。
- 木箱类型不存在时该组失败。
- 某组写入异常时该组回滚,其他组不受影响。
- `clientKey`、一基行号、成功数和失败数返回正确。
### 7.2 前端验证
- 卡片和表格切换后输入、行标识和错误不丢失。
- 新增、复制、删除和清空行为正确。
- 木箱类型弹窗回填到当前记录,并带出长、宽、高。
- `sub_package_status` 字典加载正确,新增行默认状态为 `0`
- 前端必填校验能定位具体记录。
- 部分成功后只保留失败记录并展示原因。
### 7.3 完成前命令验证
- 运行 LMS 后端受影响模块的定向测试或编译。
- 运行前端目标应用的类型检查。
- 对新增和修改的前端文件执行可用的静态检查。
- 若项目工具链自身异常,保留失败输出并在交付说明中区分代码问题和环境问题。
## 8. 成功标准
- 用户可从列表页打开批量新增弹窗。
- 用户可在卡片和表格视图间自由切换,输入不丢失。
- 木箱类型通过现有选择弹窗选择,尺寸正确回填。
- 状态来自 `sub_package_status` 字典,默认值为 `0`
- 后端按“木箱码 + 木箱类型”结合数据库已有数量校验 `max_num`
- 超限分组全部失败,合法分组正常保存。
- 前端准确显示每条失败记录及错误原因,并允许修改后重试。
- 现有单条新增、修改及列表功能不受影响。