日期: 2026-06-11
状态: 已确认(2026-06-11 补充)
父模块: 质量检测 → 质检物料库
supersede:docs/superpowers/specs/2026-05-20-qc-material-library-design.md中「不做批次管理」约束
质检物料库采用 物资维度 的简单库存模式:
biz_qc_material:一种物资一行,汇总 stock_qtybiz_qc_material_usage:变动流水,入库仅记录数量与时间materialId)| 问题 | 选项 | 含义 |
|---|---|---|
| 出库/扣减批次策略 | B | 每次手动选择扣哪一批(按入库编号) |
| 物料列表展示粒度 | A | 一行 = 一条入库批次(同一物资可出现多行) |
| 入库编号来源 | B | 用户手工录入,系统做租户内唯一性校验 |
| 入库批次字段必填 | 是 | 货号、批号、厂家、单价(元)、金额(元)均必填(前端 + 后端校验) |
| 零库存批次展示 | 不隐藏 | 批次列表默认展示全部批次(含 remaining_qty=0),便于查看历史出库后的批次行 |
biz_qc_material(物资目录)职责:物资主数据,不再在列表 Tab 直接展示(无批次时不出现在批次列表)。
| 字段 | 说明 |
|---|---|
| material_code / material_name / spec_model / unit | 不变 |
| stock_qty | 汇总库存 = Σ 下属批次 remaining_qty(写入时同步维护) |
| warning_qty / status | 不变,预警仍按物资汇总库存判断 |
biz_qc_material_stock_batch(入库批次 / 库存明细)每次入库产生一条批次记录,是库存扣减的 最小粒度。
CREATE TABLE `biz_qc_material_stock_batch` (
`id` varchar(64) NOT NULL COMMENT '主键ID',
`material_id` varchar(64) NOT NULL COMMENT '关联 biz_qc_material.id',
`material_code` varchar(64) DEFAULT NULL COMMENT '物料编码快照',
`material_name` varchar(200) DEFAULT NULL COMMENT '物料名称快照',
`spec_model` varchar(200) DEFAULT NULL COMMENT '规格型号快照',
`unit` varchar(32) DEFAULT NULL COMMENT '单位快照',
`stock_in_no` varchar(64) NOT NULL COMMENT '入库编号(用户录入,租户内唯一)',
`stock_in_date` date NOT NULL COMMENT '入库日期',
`catalog_no` varchar(128) NOT NULL COMMENT '货号',
`batch_no` varchar(128) NOT NULL COMMENT '批号',
`manufacturer` varchar(200) NOT NULL COMMENT '厂家',
`unit_price` decimal(18,2) NOT NULL COMMENT '单价(元)',
`amount` decimal(18,2) NOT NULL COMMENT '金额(元)',
`in_qty` decimal(18,4) NOT NULL COMMENT '入库数量',
`remaining_qty` decimal(18,4) NOT NULL COMMENT '剩余数量',
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
`order_num` int(11) DEFAULT NULL COMMENT '排序号',
`remark` varchar(512) DEFAULT NULL COMMENT '备注',
`create_by` varchar(64) DEFAULT NULL COMMENT '创建人id',
`create_dept_id` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) DEFAULT NULL COMMENT '更新人id',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记:0-正常 1-已删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_qc_batch_tenant_stock_in_no` (`tenant_no`, `stock_in_no`, `del_flag`),
KEY `idx_qc_batch_material` (`material_id`, `del_flag`),
KEY `idx_qc_batch_tenant_date` (`tenant_no`, `stock_in_date`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='质检物料入库批次';
字段规则:
stock_in_no:必填,trim 后租户内唯一(del_flag=0 维度)catalog_no / batch_no / manufacturer / unit_price / amount:全部必填;入库弹窗与批量入库每行均 requiredamount:打开弹窗时默认 unit_price × in_qty 自动计算;用户可手工改金额;改单价或数量时若用户未手工改过金额则重新计算remaining_qty:初始 = in_qty;出库/任务扣减时递减;撤销时回加;为 0 时批次行仍保留并在列表中展示biz_qc_material_usage(变动流水)新增批次关联与快照字段:
| 新增字段 | 说明 |
|---|---|
batch_id |
关联 biz_qc_material_stock_batch.id(入库/出库/任务扣减均有值) |
stock_in_no |
入库编号快照 |
catalog_no |
货号快照 |
batch_no |
批号快照 |
manufacturer |
厂家快照 |
unit_price |
单价快照 |
amount |
金额快照(入库写正数;出库不写或写按量折算,见 3.3) |
stock_before |
变动前库存(补齐,与耗材模块一致) |
stock_after 语义调整为 物资汇总库存(biz_qc_material.stock_qty),与现网一致;批次剩余量查批次表。
新增物资 → 填写编码/名称/规格/单位/预警量 → stock_qty=0,尚无批次行
编辑 / 停用 / 删除(仅 stock_qty=0 且无未删批次时可删)
入口(仅工具栏,行内无入库按钮): 物料列表 Tab 工具栏「入库」「批量入库」。
每条入库必填:
事务内:
stock_in_no 租户唯一biz_qc_material_stock_batch(remaining_qty = in_qty)biz_qc_material.stock_qty += in_qtybiz_qc_material_usage(change_type=in, source_type=manual_in, batch_id=…)批量入库:同一事务,任一行失败全部回滚。
入口(仅工具栏,行内无出库按钮): 物料列表 Tab 工具栏「批量出库」(单条出库 = 批量出库弹窗内只填一行)。
粒度: 按 入库批次 出库(Q1=B);明细行选择 batchId(入库编号),非物资维度。
remaining_qty >= 出库数量remaining_qtystock_qty出库单头(整单共用): 领用人(必填)、用途、备注、出库时间。
现状: QcWorkOrderTaskSubList.vue 按 materialId 选物料,禁止同一物料重复行。
改造后:
| 列 | 说明 |
|---|---|
| 入库编号 | 下拉选择 batchId,选项文案:{stockInNo} / {materialName} / 批号:{batchNo} / 剩:{remainingQty}{unit} |
| 物料名称 | 选中批次后自动带出(只读) |
| 规格型号 | 自动带出 |
| 批号 / 货号 / 厂家 | 自动带出(只读,便于核对) |
| 剩余数量 | 自动带出 |
| 用量 | 校验 0 < qty <= remainingQty |
| 备注 | 选填 |
重复规则: 同一 batchId 不可重复添加(原为同一 materialId 不可重复)。
提交 API materialUsages 结构:
{
"batchId": "uuid",
"qty": 1.5,
"remark": "可选"
}
后端 deduct_for_task:
revert_task_material_usages 按 batch_id 回加 remaining_qty 与 stock_qtySELECT batch FOR UPDATE,校验剩余量batch.remaining_qty 与 material.stock_qty查看态: 任务查看弹窗、工单任务子表展示「入库编号、物料名称、批号、用量、单位」。
QcMaterialUsageTab.vue)变动记录是 全量流水审计,与批次列表互补:批次列表看「每批还剩多少」,变动记录看「每次入/出库发生了什么」。
筛选区调整:
| 筛选项 | 说明 |
|---|---|
| 关键词 | 新增,placeholder「物料编码/名称/入库编号/批号/货号」;替代仅按物资下拉的单维筛选(保留「物料筛选」下拉可选) |
| 入库编号 | 新增独立输入框(可选,与关键词二选一或叠加,实现时 keyword 已覆盖即可) |
| 物料筛选 | 保留,按 material_id |
| 变动类型 | 保留:入库 / 出库 / 任务使用 |
| 时间范围 | 保留 |
列表列调整(在物料编码/名称之后、变动类型之前插入批次列):
| 列 | 说明 |
|---|---|
| 入库编号 | stockInNo;出库/任务类来自 usage 快照 |
| 入库日期 | 仅 change_type=in 时有值(stockInDate);出库/任务类显示「—」 |
| 货号 | catalogNo |
| 批号 | batchNo |
| 厂家 | manufacturer |
| 单价(元) | 入库行展示快照单价,formatMoneyDisplay |
| 金额(元) | 入库行展示快照金额;出库/任务类显示「—」或按业务不写 |
| 变动类型 | 不变 |
| 变动数量 / 变动前库存 / 变动后库存 | 不变;变动后库存仍为 物资汇总 stock_after |
| 关联任务号 / 来源类型 / 领用人 / 用途 / 领用时间 | 不变 |
| 备注 / 操作人 / 变动时间 / 操作 | 不变 |
查看弹窗(SystemViewDialog)调整:
在「变动信息」区块增加字段:入库编号、入库日期(入库类)、货号、批号、厂家、单价、金额(入库类);出库/任务类展示入库编号 + 批号 + 货号 + 厂家(来自快照,便于追溯扣的是哪一批)。
后端 list_usages / _row_to_dict:
返回新增字段:batchId、stockInNo、stockInDate(入库类从批次表 join 或快照)、catalogNo、batchNo、manufacturer、unitPrice、amount;stockBefore 优先读库字段,无则 stockAfter - changeQty 兼容旧数据。
API 筛选扩展:
GET /qc-material-usages?keyword=&materialId=&changeType=&startTime=&endTime=&stockInNo=
keyword 匹配 material_code / material_name / stock_in_no / batch_no / catalog_no。
remaining_qty 显示 0,仍可点「查看」追溯该批历史GET /api/admin/web/admin/qc-material-batches
Query: page, pageSize, keyword(编码/名称/入库编号/批号/货号), materialId, status(物资状态)
Response: 分页,**默认返回全部批次(含 remaining_qty=0)**;每行含物资字段 + 批次字段 + 汇总 stockQty + 库存预警状态
GET /api/admin/web/admin/qc-material-batches/options
Query: keyword, materialId(可选)
Filter: status=1 物资且 remaining_qty > 0
Response: [{ id, stockInNo, materialId, materialCode, materialName, specModel, unit, batchNo, catalogNo, manufacturer, remainingQty, label }]
保留 GET /qc-materials/options 供「新增入库时搜索物资」使用;扣减场景改用 batches/options。
POST /api/admin/web/admin/qc-materials/{materialId}/stock-in
Body: {
stockInNo, stockInDate, catalogNo, batchNo, manufacturer,
unitPrice, amount, qty, remark?, stockInTime? // stockInTime 仍映射 create_time,stockInDate 为业务日期
}
POST /api/admin/web/admin/qc-material-batches/batch-stock-in
Body: {
stockInTime?, remark?,
items: [{ materialId, stockInNo, stockInDate, catalogNo, batchNo, manufacturer, unitPrice, amount, qty, remark? }]
}
POST /api/admin/web/admin/qc-material-batches/{batchId}/stock-out
Body: { qty, receiver, purpose?, remark?, stockOutTime? }
批量出库 items 元素改为 { batchId, qty, remark? }。
POST /qc-tasks/{id}/complete-with-result
materialUsages: [{ batchId, qty, remark? }] // 替代 materialId
GET /qc-tasks/{id}/material-usages
返回含 batchId, stockInNo, batchNo, catalogNo, manufacturer, ...
GET/POST/PUT/DELETE /qc-materials 保留,供目录维护;列表 Tab 改调 batches 接口。
qc-material/index.vue工具栏(从左到右,「已选 N 项」在最前):
| 按钮 | 类型 | 说明 |
|---|---|---|
| 新增物料 | primary | 维护物资目录(编码/名称/规格等) |
| 入库 | ghost | 打开 单条入库 弹窗,填写一条完整入库信息 |
| 批量入库 | ghost | 打开 批量入库 弹窗,列表模式多行录入 |
| 批量出库 | ghost | 打开 批量出库 弹窗,列表模式选批次并填数量 |
移除行内「入库」「出库」按钮;操作列仅保留:查看、编辑(物资)、删除(物资),或收拢至「更多」下拉(与现网 dropdown 一致)。行内 不提供 入/出库入口。
列表列(批次明细): 见 §4.1;含入库编号、入库日期、货号、批号、厂家、单价、金额、入库数量、剩余数量等;零库存批次仍展示。
dialog-form-layoutmaterialId,选物资目录)stockInTime,映射 usage.create_time;默认可当前时间)el-table,「新增一行」 增加空行,每行 = 一条独立入库信息(不同入库编号/批号/厂家/单价/金额)| 列 | 说明 |
|---|---|
| 序号 | index |
| 物资 | 下拉/远程搜索选 materialId,带出编码/名称/规格/单位(只读列) |
| 入库编号 | 手工输入,行内唯一性提交时校验 |
| 入库日期 | date-picker |
| 货号 / 批号 / 厂家 | 输入 |
| 单价 / 金额 | AmountInput,行内联动 |
| 入库数量 | input-number |
| 备注 | 可选 |
| 操作 | 删除行 |
| 字段 | 必填 |
|---|---|
| 出库时间 | 是 |
| 领用人 | 是(远程搜索用户) |
| 用途 | 否 |
| 备注 | 否(整单默认;行备注优先) |
batchId,文案含入库编号/物料名/批号/剩余量);仅可选 remaining_qty > 0 的批次| 列 | 说明 |
|---|---|
| 序号 | index |
| 入库编号 | 选择批次后带出(或选择列即 batch) |
| 物料编码 / 名称 / 规格 / 单位 | 自动带出 |
| 批号 / 货号 / 厂家 | 自动带出(只读,便于核对) |
| 剩余数量 | 只读 |
| 出库数量 | input-number,max = 剩余数量 |
| 备注 | 可选 |
| 操作 | 删除行 |
batchId 不可重复添加两行stockOutVisible 行内触发)— 统一走批量出库弹窗handleStockIn(row) / handleStockOut(row) 及对应按钮stockInVisible 组件,仅由工具栏「入库」打开且 不预填 materialId(或支持预填,但不绑行操作)material-batch-stock-dialog、batch-stock-move-lines 等沿用 index.vue / production/consumable 批量入出库弹窗AmountInput + formatMoneyDisplayQcWorkOrderTaskSubList.vueMaterialUsageRow:batchId 替代 materialId 为主键字段fetchQcMaterialBatchOptionsmaterialUsages: { batchId, qty, remark? }[]index.vue / qc-task-view-dialog 同步展示入库编号QcMaterialUsageTab.vue(专项)对照 §3.5,本 Tab 与批次列表 同步改造,不可遗漏:
api/qc-material-usage.ts:QcMaterialUsage 类型扩展 batchId、stockInNo、stockInDate、catalogNo、batchNo、manufacturer、unitPrice、amount;列表请求增加 keyword / stockInNo 参数formatMoneyDisplayviewSections:补充上述批次字段materialId 外支持 stockInNo query 预填筛选| 文件 | 改动 |
|---|---|
qc-work-order/index.vue |
物料使用子表增加入库编号、批号列 |
OutboundQcViewDialog.vue |
同上 |
qc-task-view-dialog/index.vue |
同上 |
不在本次范围: OutboundReleaseMaterialDialog.vue(台账模式,仍选物资)。
决策(2026-06-11): 现有质检物料库数据 不做迁移,功能开发完成后由 DBA/实施人员在库中手动执行脚本。
| 脚本 | 路径(计划) | 用途 |
|---|---|---|
| 清除旧数据 | docs/sql/migrations/2026-06-11-qc-material-batch-clear-data.sql |
软删或物理清理 biz_qc_material / biz_qc_material_usage 旧行(及上线前若已存在的批次表数据) |
| 新测试数据 | docs/sql/migrations/2026-06-11-qc-material-batch-test-data.sql |
插入物资目录、多条入库批次、若干变动记录,覆盖单物资多批次、零库存批次、入出库流水等验收场景 |
清除脚本范围:
biz_qc_material_usage(变动记录)biz_qc_material_stock_batch(入库批次,新表)biz_qc_material(物资目录)默认采用 软删(del_flag=1)或 DELETE 全表(脚本内注释说明,按环境选择);不在应用代码中自动清库。
测试数据脚本内容(示意):
remaining_qty=0(已出清,用于验证列表仍展示 + 变动记录可查)biz_qc_material_usage 入库/出库/(可选)任务扣减样例行执行顺序: 先跑 DDL(2026-06-11-qc-material-batch.sql)→ 部署代码 → 清除旧数据 → 导入测试数据。
| 文件 | 改动 |
|---|---|
models/qc_material.py |
新增 BizQcMaterialStockBatch;扩展 BizQcMaterialUsage |
crud/qc_material_stock_batch.py |
新建:list/options/stock_in/stock_out |
crud/qc_material.py |
入库/出库委托批次层;汇总 stock_qty 同步 |
crud/qc_material_usage.py |
deduct/revert 按 batch_id;_row_to_dict 扩展 |
api/qc.py |
新路由 + 调整 complete-with-result Body |
docs/sql/migrations/2026-06-11-qc-material-batch.sql |
DDL + 迁移 |
| 文件 | 改动 |
|---|---|
api/qc-material.ts |
批次类型与 API |
api/qc-task-result.ts |
materialUsages 改 batchId |
qc-material/index.vue |
列表/入出库弹窗 |
QcMaterialUsageTab.vue |
筛选、列表列、查看弹窗、API 类型(见 §5.3) |
api/qc-material-usage.ts |
类型与列表参数扩展 |
QcWorkOrderTaskSubList.vue |
物料使用区核心改造 |
qc-work-order/index.vue 等 |
查看态列 |
实现后运行 python scripts/check_field_consistency.py 覆盖新 CRUD。
| 项 | 结论 |
|---|---|
| 货号 / 批号 / 厂家 / 单价 / 金额 | 全部必填(元字段用 AmountInput + formatMoneyDisplay) |
| 零库存批次 | 默认展示,不隐藏;出库仅在批量出库弹窗中选批次,仅展示 remaining_qty > 0 |
| 入出库入口 | 仅工具栏;列表行内无入库/出库按钮 |
| 批量入库/出库 | 列表模式 +「新增一行」;出库单头含领用人/用途/备注/出库时间 |
| 金额与单价联动 | 默认 单价 × 入库数量;用户手工改金额后不再自动覆盖 |
| 变动记录 Tab | 必须同步改造(§3.5、§5.3) |
| 旧数据 | 不迁移;交付清除脚本 + 测试数据脚本,由人工在库中执行 |
Spec 已按上述确认更新。若无其他修改,可进入 writing-plans 编写分 Task 实施计划。