2026-05-22-storage-slot-occupancy-design.md 10 KB

库位占用记录功能设计文档

日期: 2026-05-22 状态: 已确认(§1.3 一对多关系已被废弃,见 2026-06-13-slot-one-item-design.md:一格任何物品只能一个) 范围: 前后端全做(含细胞产品对接)

1. 背景与需求

1.1 现状

库位管理模块由两张表组成:

  • biz_storage_facility:树形结构(液氮罐 → 层 → 盒,is_leaf=1 为叶子存储节点)
  • biz_storage_facility_slot:叶子节点下的储物格(如 A1-3),仅有 slot_code 和 slot_status("空"/"占用")

细胞产品表 biz_cell_product 通过 storage_slot_id FK 指向 slot,但 slot 本身不知道存了什么。

1.2 问题

  1. slot_status 只有"空/占用",不记录物品类型、编码、来源
  2. 多来源无法统一查询(想查"这格子里有什么"需逐表扫描)
  3. 一个格子可存放多个物品(一对多关系),当前设计无法支持
  4. 无出入库历史记录

1.3 需求确认

维度 决策
储物格与物品关系 一对多
物品类型 cell_product(细胞产品)+ other(其他,兜底)
入库触发 细胞产品自动同步 + 手动入库(其他物品)
出库触发 细胞产品状态变更自动出库 + 手动出库
历史记录 需要完整出入库历史
前端展示 点击储物格弹窗查看明细 + 手动出入库操作
实施范围 前后端全做

2. 方案选型

方案 描述 优点 缺点 结论
A(采用) 独立占用表 + Slot 缓存字段 统一查询入口、性能好、可扩展 双写需事务保证 ✅ 推荐
B 纯占用表,无缓存 单一数据源 列表页性能差 ❌
C 只加字段到 Slot 表 最简单 不支持一对多、无历史 ❌ 不满足需求

3. 数据模型

3.1 新增表 biz_storage_slot_occupancy

CREATE TABLE biz_storage_slot_occupancy (
    id               VARCHAR(64)  NOT NULL              COMMENT '主键ID',
    slot_id          VARCHAR(64)  NOT NULL              COMMENT '储物格ID (FK → biz_storage_facility_slot)',
    item_type        VARCHAR(32)  NOT NULL              COMMENT '物品类型: cell_product=细胞产品, other=其他',
    item_id          VARCHAR(64)  NOT NULL              COMMENT '物品ID (指向对应业务表主键)',
    item_code        VARCHAR(64)  NULL                  COMMENT '物品编码 (冗余展示)',
    item_name        VARCHAR(200) NULL                  COMMENT '物品名称 (冗余展示)',
    item_source      VARCHAR(32)  NULL                  COMMENT '来源: production=生产入库, manual=手动入库, transfer=转移',
    stored_at        DATETIME     NULL                  COMMENT '入库时间',
    removed_at       DATETIME     NULL                  COMMENT '出库时间 (NULL=当前在库)',
    occupancy_status VARCHAR(16)  NOT NULL DEFAULT 'stored' COMMENT 'stored=在库, removed=已出库',
    -- 标准公共字段
    tenant_no        VARCHAR(64)  NULL                  COMMENT '租户编号',
    order_num        INT          DEFAULT 0             COMMENT '排序',
    remark           VARCHAR(500) NULL                  COMMENT '备注',
    create_by        VARCHAR(64)  NULL                  COMMENT '创建者',
    create_dept_id   VARCHAR(64)  NULL                  COMMENT '创建部门',
    create_time      DATETIME     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    update_by        VARCHAR(64)  NULL                  COMMENT '更新者',
    update_time      DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
    del_flag         CHAR(1)      DEFAULT '0'           COMMENT '删除标志(0存在 1删除)',
    PRIMARY KEY (id),
    INDEX idx_sso_slot (slot_id, occupancy_status, del_flag),
    INDEX idx_sso_item (item_type, item_id, del_flag),
    INDEX idx_sso_tenant (tenant_no, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='库位占用记录表';

3.2 增强 biz_storage_facility_slot

ALTER TABLE biz_storage_facility_slot 
    ADD COLUMN occupied_count INT DEFAULT 0 COMMENT '当前占用数量',
    ADD COLUMN last_item_type VARCHAR(32) NULL COMMENT '最近存储物品类型',
    ADD COLUMN last_stored_at DATETIME NULL COMMENT '最近入库时间';

3.3 数据关系

biz_storage_facility (树: 液氮罐→层→盒)
  └── biz_storage_facility_slot (储物格, 新增: occupied_count, last_item_type, last_stored_at)
        ├── biz_storage_slot_occupancy (占用记录, 多态关联)
        │     ├── item_type='cell_product' → item_id 指向 biz_cell_product.id
        │     └── item_type='other'        → item_id 为手动录入的标识
        └── biz_cell_product.storage_slot_id (保留, 向后兼容)

3.4 一致性保证

  • 入库:同一事务内 → 写 occupancy 记录 + 更新 slot 缓存字段(occupied_count += 1)
  • 出库:同一事务内 → 更新 occupancy 状态 + 更新 slot 缓存字段(occupied_count -= 1)
  • occupied_count 降到 0 时,slot_status 改回"空"

4. 后端 API 与业务逻辑

4.1 新增/修改文件

文件 作用
backend/app/models/models.py 新增 BizStorageSlotOccupancy 模型
backend/app/schemas/storage_occupancy.py 新增,Pydantic schemas
backend/app/crud/storage_occupancy.py 新增,CRUD 层
backend/app/api/operations.py 在现有 router 下新增路由
backend/app/crud/cell_product.py 改造:入库/出库时同步写 occupancy
backend/app/models/__init__.py 新增导出

4.2 API 接口

所有接口挂载在 /api/web/admin/ 下:

方法 路径 用途
GET /storage-slot-occupancies 查询占用记录(按 slot_id / item_type / occupancy_status 筛选)
POST /storage-slot-occupancies 手动入库(item_type=other)
PUT /storage-slot-occupancies/{id}/remove 手动出库
GET /storage-slot-occupancies/history 出入库历史(支持时间范围、物品类型筛选)

GET /storage-slot-occupancies 查询参数:

  • slot_id(必传):储物格 ID
  • occupancy_status(可选,默认 stored):stored / removed
  • item_type(可选):cell_product / other
  • page / page_size:分页

GET /storage-slot-occupancies/history 查询参数:

  • slot_id(可选):储物格 ID
  • facility_node_id(可选):设施节点 ID(查该节点下所有格子的历史)
  • item_type(可选)
  • start_date / end_date(可选):时间范围
  • page / page_size:分页

4.3 CRUD 核心函数

函数 说明
list_occupancies(db, slot_id, status, item_type, page, page_size) 分页查询占用记录
list_occupancy_history(db, slot_id, facility_node_id, item_type, start_date, end_date, page, page_size) 出入库历史
create_occupancy(db, data, current_user) 创建入库记录 + 更新 slot 缓存(同一事务)。item_type=other 时 item_id 自动生成 UUID
remove_occupancy(db, occupancy_id, current_user) 出库 + 更新 slot 缓存(同一事务)
batch_create_occupancies(db, items, current_user) 批量入库(细胞产品批量创建时调用)
remove_by_item(db, item_type, item_id, current_user) 按物品出库(细胞产品状态变更时调用)
_refresh_slot_cache(db, slot_id) 内部函数:刷新 slot 的 occupied_count / last_item_type / last_stored_at / slot_status

4.4 细胞产品对接

触发点 改动
create_cell_product() 创建后同步调用 create_occupancy()
create_cell_products_batch() 批量创建后同步调用 batch_create_occupancies()
create_cell_products_by_quantity() 同上
update_cell_product() 状态变为 sold/used/voided 时调用 remove_by_item('cell_product', product_id)

5. 前端交互设计

5.1 库位管理页面改造

页面:web-admin/src/views/operations/storage-facility/index.vue

5.1.1 储物格弹窗(新增)

点击储物格 → 弹出占用明细弹窗,包含两个 Tab:

Tab 1:在库物品

列 说明
物品类型 Tag 标签:cell_product=细胞产品, other=其他
物品编码 item_code
物品名称 item_name
来源 production=生产入库, manual=手动入库, transfer=转移
入库时间 stored_at
操作 [出库] 按钮

Tab 2:出入库历史

列 说明
物品类型 同上
物品编码 item_code
物品名称 item_name
来源 item_source
入库时间 stored_at
出库时间 removed_at
状态 Tag:stored=在库, removed=已出库

5.1.2 手动入库对话框(新增)

弹窗底部「入库」按钮触发,表单字段:

字段 控件 必填
物品编码 el-input 是
物品名称 el-input 是
来源 el-select(manual/transfer) 是
备注 el-input textarea 否

提交后调用 POST /storage-slot-occupancies,刷新在库物品列表。

5.1.3 库位网格增强

现有网格每个格子显示 occupied_count 数字角标。占用格子背景色保持橙色,角标显示数量。

5.2 细胞产品页面

页面:web-admin/src/views/production/cell-product/index.vue

改动极小:

  • 入库/出库由后端事务自动完成,前端无需额外逻辑
  • 可选:储物格列增加 tooltip 显示占用数量

5.3 新增前端 API

文件:web-admin/src/api/admin.ts(追加)

函数 接口
fetchSlotOccupancies(params) GET /storage-slot-occupancies
fetchSlotOccupancyHistory(params) GET /storage-slot-occupancies/history
fetchCreateOccupancy(data) POST /storage-slot-occupancies
fetchRemoveOccupancy(id) PUT /storage-slot-occupancies/{id}/remove

5.4 SQL 迁移文件

文件:docs/sql/2026-05-22-storage-slot-occupancy.sql

包含:

  1. CREATE TABLE biz_storage_slot_occupancy
  2. ALTER TABLE biz_storage_facility_slot 增加缓存字段