日期: 2026-06-17
状态: 已确认
范围: 后端 + web-admin + SQL 迁移
关联模块: 库位管理、细胞产品库、生产任务、出库放行
库位管理由两张表组成(见 docs/superpowers/specs/2026-05-22-storage-slot-occupancy-design.md):
biz_storage_facility:树形结构(液氮罐 → 层 → 盒),字段含 node_name、node_type、is_leaf,无编号字段biz_storage_facility_slot:叶子节点下的储物格,slot_code 仅存盒内坐标(如 1-3)业务展示时,储物格位置拼接为 名称路径 + 本地编码:
液氮罐A / 第1层 / 盒01 / 1-3
名称路径用 / 分隔(buildTreePathLabelFromFlat / _build_facility_path_label)。
- 连接1 → 层 2 → 盒 03 → 格 1-3 → 完整编号 1-2-03-1-3| 维度 | 决策 |
|---|---|
| 节点编号格式 | 单段,不含 -(字母或数字,如 1、03、A) |
| 格子本地编码 | 保持 行-列(如 1-3) |
| 完整编号生成 | 动态计算(节点存 node_code,格子存本地 slot_code) |
| 编号修改策略 | 允许修改;修改后 批量刷新关联快照 |
| 名称 vs 编号 | 分离:node_name 继续用于名称路径;node_code 用于编号路径 |
| 方案 | 描述 | 结论 |
|---|---|---|
| A(采用) | 节点新增 node_code;slot_code 存本地坐标;API 返回 fullSlotCode |
✅ 推荐 |
| B | slot_code 直接存完整编号 |
❌ 父级改编号需批量改格子;字段冗余 |
| C | 双字段 slot_code + full_slot_code 冗余存储 |
❌ 同步成本高 |
| 方案 | 描述 | 结论 |
|---|---|---|
| A | 允许改,快照不更新 | ❌ |
| B | 有子节点/格子后禁止改 | ❌ |
| C(采用) | 允许改,并批量更新关联快照 | ✅ |
biz_storage_facility 新增字段ALTER TABLE biz_storage_facility
ADD COLUMN node_code VARCHAR(32) NOT NULL DEFAULT '' COMMENT '节点编号(单段,不含连字符)'
AFTER node_name;
约束与校验(应用层 + 可选 DB):
| 规则 | 说明 |
|---|---|
| 格式 | /^[A-Za-z0-9]+$/,禁止 - |
| 兄弟唯一 | 同一 parent_id + tenant_no 下 node_code 不可重复 |
| 必填 | 新建节点必填;迁移后存量须补全 |
| 根节点 | 同样必须有 node_code |
索引建议:
CREATE INDEX idx_sf_parent_code ON biz_storage_facility (parent_id, tenant_no, node_code, del_flag);
biz_storage_facility_slot 不变slot_code 仍存盒内本地坐标({row}-{col})full_slot_code 列def build_node_code_path(node_id: str, facility_by_id: dict) -> str:
"""从根到当前节点的 node_code,用 '-' 连接。例:'1-2-03'"""
def build_full_slot_code(facility_node_id: str, slot_code: str, facility_by_id: dict) -> str:
"""例:build_node_code_path(...) + '-' + slot_code → '1-2-03-1-3'"""
facility_node_id:格子所属叶子节点 IDslot_code:本地 行-列slot_code 为空,仅返回节点路径编号(一般不应出现在叶子格子上)租户内完整编号唯一性: 由树结构 + 兄弟唯一 node_code + 叶子内 slot_code 唯一共同保证;叶子内 slot_code 在同一 facility_node_id 下应已有业务约束(批量生成不重复)。
完整编号示例:1-2-03-1-3(约 10 字符)。深层树或长编号预估 ≤ 64 字符,当前 slot_code VARCHAR(64) 足够存储本地坐标;fullSlotCode 仅 API 返回,不入库。
update_facility 当 node_code 发生变化时,在同一事务内执行级联刷新。
is_leaf=1)biz_storage_facility_slotfullSlotCode当前持久化 storage_slot_name 的表:
| 表 | 字段 | 刷新方式 |
|---|---|---|
biz_outbound_release_cell |
storage_slot_name |
按 cell_product_id → biz_cell_product.storage_slot_id 匹配受影响 slot,更新为新 fullSlotCode |
运行时计算、无 DB 快照的模块(改编号后自动生效,无需刷表):
biz_cell_product 列表/详情中的 storageSlotName(_enrich_product_dicts 动态拼接)storage-slot-options.ts)def cascade_refresh_slot_name_snapshots(db, *, changed_node_ids: list[str], tenant_no: str):
affected_slot_ids = collect_slot_ids_under_nodes(db, changed_node_ids, tenant_no)
if not affected_slot_ids:
return 0
facility_by_id = load_all_facilities_map(db, tenant_no)
slot_full_map = {
sid: build_full_slot_code(slot.facility_node_id, slot.slot_code, facility_by_id)
for sid, slot in load_slots_by_ids(db, affected_slot_ids)
}
# 刷新 outbound_release_cell 快照
updated = refresh_outbound_release_cell_slot_names(db, slot_full_map, tenant_no)
return updated
update_slot 当 slot_code 变化时,同样触发上述快照刷新(仅该 slot ID 范围)。
| 方法 | 路径 | 变更 |
|---|---|---|
| GET | /storage-facilities |
返回增加 nodeCode |
| POST | /storage-facilities |
请求体增加 nodeCode(必填) |
| PUT | /storage-facilities/{id} |
可改 nodeCode;变更时级联刷新快照 |
CreateBody / UpdateBody 新增:
node_code: str = Field(..., alias="nodeCode", min_length=1, max_length=32)
校验错误文案:
节点编号只能包含字母和数字,不能包含连字符同级节点编号已存在| 方法 | 路径 | 变更 |
|---|---|---|
| GET | /storage-facility-slots |
每条增加 fullSlotCode |
| POST | /storage-facility-slots |
响应含 fullSlotCode;slot_code 仍为本地坐标 |
| PUT | /storage-facility-slots/{id} |
同上;改 slot_code 时刷新快照 |
| POST | /storage-facility-slots/batch |
移除 codePrefix;本地编码 {row}-{col} |
_slot_to_dict 增加:
"fullSlotCode": build_full_slot_code(...)
_enrich_product_dicts 中 storageSlotName 由:
{node_name_path} / {slot_code}
改为:
{fullSlotCode}
可选:保留 storageSlotPath(名称路径)供 tooltip,非必须。
文件: web-admin/src/views/operations/storage-facility/index.vue
| 区域 | 变更 |
|---|---|
| 节点弹窗 | 新增「节点编号」表单项(必填);hint:单段字母/数字,不含 - |
| 左侧树 | 展示 [nodeCode] nodeName 或 nodeCode · nodeName |
| 格子卡片 | 主文案显示 fullSlotCode(替代当前列序号 cellIndex+1) |
| 批量生成 | 移除「编码前缀」;预览示例完整编号 |
| 格子编辑/占用弹窗 | 展示完整编号;本地坐标可编辑时仍编辑 slotCode(行-列) |
货架行分组: 继续使用本地 slotCode 调用 parseSlotCode,不要对 fullSlotCode 做行/列解析。
文件: web-admin/src/utils/storage-slot-options.ts
mapSlotsToSelectOptions:name 改为 fullSlotCodenodePath 作 title/tooltip以下页面无需改交互,随 API storageSlotName / 下拉 name 变更自动显示新格式:
cell-product/index.vue文件: docs/sql/migrations/2026-06-17-storage-facility-node-code.sql
-- 1. 加字段(允许 DEFAULT '' 过渡)
ALTER TABLE biz_storage_facility
ADD COLUMN node_code VARCHAR(32) NOT NULL DEFAULT '' COMMENT '节点编号(单段,不含连字符)'
AFTER node_name;
-- 2. 存量补编号(需按租户人工确认后执行,示例按 order_num)
-- UPDATE biz_storage_facility SET node_code = LPAD(CAST(order_num + 1 AS CHAR), 2, '0') WHERE node_code = '' AND del_flag = 0;
-- 3. 补编号完成后,业务侧应禁止 node_code 为空的新增/编辑
-- 4. 刷新 outbound_release_cell 快照(部署后由后端脚本或一次性 SQL 执行,依赖新编号已补全)
迁移注意:
slot_code 无需修改node_code 后,运行一次性脚本刷新 biz_outbound_release_cell.storage_slot_name| # | 场景 | 期望 |
|---|---|---|
| 1 | 新建节点缺 nodeCode |
400 |
| 2 | nodeCode 含 - |
400 |
| 3 | 同级重复 nodeCode |
400 |
| 4 | 批量生成 4×6 | fullSlotCode 为 {祖先}-{row}-{col} |
| 5 | 修改层编号 2→5 |
其下所有 slot 的 fullSlotCode 前缀变化 |
| 6 | 修改层编号后 | biz_outbound_release_cell.storage_slot_name 同步更新 |
| 7 | 修改格子 slot_code |
关联 outbound 快照更新 |
| 8 | 细胞产品列表 | storageSlotName 显示 fullSlotCode |
| 9 | 下拉选格 | 选项文案为 fullSlotCode |
/#/operations/storage-facility — 树、节点 CRUD、批量生成、格子展示storage_location 纯文本字段(不关联库位主数据)- 分隔(名称路径仍用 /)| 层级 | 文件 | 操作 |
|---|---|---|
| SQL | docs/sql/migrations/2026-06-17-storage-facility-node-code.sql |
新增 |
| Model | backend/app/models/models.py |
修改 |
| Service | backend/app/services/storage_facility_code.py(或 crud 内) |
新增 |
| CRUD | backend/app/crud/storage_facility.py |
修改 |
| CRUD | backend/app/crud/cell_product.py |
修改 _enrich 拼接 |
| CRUD | backend/app/crud/outbound_release_material.py |
可选:抽取共用刷新 |
| API | backend/app/api/operations.py |
修改 schema |
| 前端 | web-admin/src/views/operations/storage-facility/index.vue |
修改 |
| 前端 | web-admin/src/utils/storage-slot-options.ts |
修改 |
| 前端 | web-admin/src/api/admin.ts |
类型字段补充 |
评审确认项: 若本设计无异议,下一步编写实施计划(docs/superpowers/plans/2026-06-17-storage-facility-node-code.md)并开始开发。