fix(web): 扫码页与备选库位带单据ID,按有效可用量限流

配合后端预占回加:扫码/借库/审批页面调用 /outbound/scan 与 /outbound/alternatives
时带上本单 id 与 biz_type,拿到的 available_quantity 即为「实时可用量 + 本单
预占」,本单锁定的行不会再因实时可用量为 0 而被拦住或从列表消失。

后端已在响应边界完成归一化,故前端模板与校验逻辑(:max、库存列展示、超量
警告、草稿存取)一律不动,只多传参数 —— 避免把同一语义散落到多个读写点。

- api/outbound.ts:getStockByBarcode / getStockAlternatives 加 requestId 与
  bizType 参数,导出 ScanBizType,ScanResult 补 reserved_quantity 等字段
- api/transaction.ts:同名的历史副本同步签名(当前无调用方,加注释指向唯一来源)
- views/outbound/create.vue、views/transaction/borrow.vue:各 3 处调用点带上
  单据 id;refreshStockFromDraft 改为显式透传 id,不依赖 computed 已解析
- views/borrow/approval/index.vue:审批页也带上本单 id,否则待审批单
  (预占已生效)锁定的行会因实时可用量为 0 而从备选列表消失

借库侧 request_id 是 BorrowApproval.id,靠 biz_type='borrow' 与出库单区分 ——
两张表 ID 空间独立,不可省。
This commit is contained in:
yueli
2026-09-11 10:34:23 +08:00
parent a8a3c82331
commit b313fefdfa
5 changed files with 107 additions and 32 deletions

View File

@ -31,6 +31,9 @@ export interface OutboundSubmitData {
remark?: string
}
/** 单据类型:出库单与借库单是两张独立表、ID 空间独立,必须显式区分 */
export type ScanBizType = 'outbound' | 'borrow'
export interface ScanResult {
id: number
sku: string
@ -38,7 +41,14 @@ export interface ScanResult {
spec_model: string
source_table: string // 'stock_buy' | 'stock_product' ...
stock_quantity: number
/** ★ 有效可用量 = 实时可用量 + 本单在该行的预占量(本单可扫的上限) */
available_quantity: number
/** 实时可用量原值(不含本单预占),备查/展示用 */
raw_available_quantity?: number
/** 本单在该库存行上的预占量 */
reserved_quantity?: number
/** 预占是否已生效;false 表示后端降级为实时可用量 */
reservation_applied?: boolean
batch_number?: string
warehouse_location?: string
barcode?: string
@ -47,13 +57,24 @@ export interface ScanResult {
/**
* 根据条码获取库存物品详情
*
* ★ 传 requestId + bizType 后,返回的 available_quantity 会回加本单在该行的
* 预占量。出库选单提交申请时已扣减 available_quantity,若扫码时不回加,
* 被本单占满的行会显示 0,工人根本扫不进去。
*
* @param barcode 扫描到的条码
* @param requestId 本单 ID(出库审批单 / 借库审批单)
* @param bizType 单据类型,决定 requestId 查哪张表(默认 outbound)
*/
export function getStockByBarcode(barcode: string) {
export function getStockByBarcode(
barcode: string,
requestId?: number | null,
bizType: ScanBizType = 'outbound'
) {
return request<any, ScanResult>({
url: '/v1/outbound/scan',
method: 'get',
params: { barcode }
params: { barcode, request_id: requestId, biz_type: bizType }
})
}
@ -175,15 +196,22 @@ export function bomMatchStock(payload: BomRequirement[] | { requirements: BomReq
* 备选库位查询 —— 为「物理覆盖」提供可见性
*
* 申请单把货预占在某个库位后,工人现场可能进不去该库位,需要改扫同物料的
* 其它批次。本接口按 available_quantity > 0 返回**真正能拿**的库位,
* 其它批次。本接口返回**真正能拿**的库位(实时可用量 > 0,或本单已预占该行),
* 并标注哪一条是本单锁定的推荐行。
*
* ★ 传 requestId + bizType 后,available_quantity 会回加本单在该行的预占量;
* 否则被本单占满的行实时可用量为 0,会从列表里凭空消失。
*
* @param baseId 物料 ID(申请明细里的 base_id)
* @param locked 本单锁定的批次(用于标注「推荐」),可选
* @param requestId 本单 ID(出库审批单 / 借库审批单),可选
* @param bizType 单据类型,决定 requestId 查哪张表(默认 outbound)
*/
export function getStockAlternatives(
baseId: number,
locked?: { stock_id?: number; source_table?: string }
locked?: { stock_id?: number; source_table?: string },
requestId?: number | null,
bizType: ScanBizType = 'outbound'
) {
return request({
url: '/v1/outbound/alternatives',
@ -191,7 +219,9 @@ export function getStockAlternatives(
params: {
base_id: baseId,
stock_id: locked?.stock_id,
source_table: locked?.source_table
source_table: locked?.source_table,
request_id: requestId,
biz_type: bizType
}
})
}

View File

@ -47,13 +47,24 @@ export interface ScanResult {
/**
* 根据条码获取库存物品详情
*
* ⚠ 本文件是与 `@/api/outbound` 同名的**历史副本**(同 URL、同返回形状),
* 当前无任何调用方 —— 借库扫码页 `views/transaction/borrow.vue` 是从
* `@/api/outbound` 导入的。改动请落到那边,这里同步仅为避免下次改漏。
*
* @param barcode 扫描到的条码
* @param requestId 本单 ID(出库审批单 / 借库审批单)
* @param bizType 单据类型,决定 requestId 查哪张表(默认 outbound)
*/
export function getStockByBarcode(barcode: string) {
export function getStockByBarcode(
barcode: string,
requestId?: number | null,
bizType: 'outbound' | 'borrow' = 'outbound'
) {
return request<any, ScanResult>({
url: '/v1/outbound/scan',
method: 'get',
params: { barcode }
params: { barcode, request_id: requestId, biz_type: bizType }
})
}