梦花仓管小程序 · 进销存

打包负责人物资申领 · 前端对接

打包负责人线上提交物资申领,仓库管理员审核发放。新增 7 个接口,另有 3 处既有接口的行为变化必须跟进。

后端模块 xm-bulky-mall-gallery(与现有 /supplier/wms/inventory/* 同一服务)· 测试分支 test-gallery · 2026-08-25

01通用约定

跟现有 /supplier/wms/inventory/* 一模一样:base https://api.xunmengvip.cn/xm-bulky-mall-gallery,全部 POST + JSON body,鉴权、{ code, msg, data, success } 包装(success 是布尔,等价于 code === 0;失败时 HTTP 状态码仍是 200,别用状态码判断成败)、index/size 分页都照旧,直接复用现成封装。失败响应的 msg 是可以直接 toast 的中文,速查见 08 节。

⚠️ 唯一的入参怪癖

/apply/sku/stock/apply/detail/apply/cancel 三个接口复用了通用的 IdQo,入参字段名都叫 id。其中 /apply/sku/stockid 传的是 skuId,不是申领单 ID,另外两个才是申领单 ID。

02角色与状态机

后端从两处判定当前账号的身份,不需要前端传角色来鉴权:

角色判定依据能做什么
仓库管理员 账号命中配置的仓管角色 看全部申领单、同意、拒绝。不能提交申领(除非同时也是负责人)
打包负责人 xm_bulky_team.leader_id = 当前账号,且团队为启用状态 提交申领、撤销自己提交的单、只看自己带的大区的单
两者都不是 调任意申领接口都会收到 无物资申领权限

一个账号可以同时是仓管和负责人,这种情况下列表默认看全部;如果前端提供了「角色切换」,把当前视角作为 roleName 传给 /apply/page 即可(见 04 节)。

申领单状态

STATUS 10
待审核
负责人提交后的初始态。此时库存不动,不占用、不冻结
STATUS 20
已同意
仓管同意,库存此刻才从库房划到大区,issuedQuantity 有值
STATUS 30
已拒绝
仓管拒绝,rejectReason 可能为空字符串
STATUS 40
已撤销
申领人本人撤回,仅待审核态可撤

💡 待审核不占库存

提交时只校验一次「申领数量 ≤ 库房剩余可用」,之后不做任何预占。所以两张待审核的单可能都显示能发,实际审批时第二张会因为库存不够被拒。审批失败的 toast 要能正常展示,不要假设提交通过就一定能审批通过。

03新增接口 · 负责人侧

查询物资库房剩余可用库存 NEW

POST/supplier/wms/apply/sku/stock负责人 / 仓管

选好物资后调用,用于在申领数量输入框旁边展示「当前可申领上限」。

请求字段类型必填说明
idLong物资 SKU ID(不是申领单 ID),取自 /supplier/wms/inventory/sku/listskuId
// 响应 data
{
  "skuId": 1012,
  "skuName": "打包纸箱",
  "specification": "60×40×40",
  "unitName": "个",
  "availableStock": 320   // 库房剩余可用 = 全局实物 − 各大区已分配剩余
}

提交物资申领 NEW

POST/supplier/wms/apply/create仅负责人
请求字段类型必填说明
skuIdLong物资 SKU ID
teamIdInteger条件申领大区。负责人只带 1 个大区时可以不传;带多个大区必传,不传报「请选择申领大区」。传了非自己带的大区报「无权为该大区申领」
quantityInteger申领数量,1 ~ 10000,且不能超过 availableStock
voucherUrlsStringJSON 数组的字符串,不是数组对象。1 ~ 5 个元素,整串 ≤ 512 字符
remarkString备注,≤ 255 字符

🔴 voucherUrls 是字符串,不是数组

后端字段类型是 String,前端要自己 JSON.stringify 后再放进 body:

// ✅ 正确
{ "skuId": 1012, "quantity": 50, "voucherUrls": "[\"https://oss/a.jpg\",\"https://oss/b.jpg\"]" }

// ❌ 会报「凭证图片格式错误」
{ "skuId": 1012, "quantity": 50, "voucherUrls": ["https://oss/a.jpg"] }

512 字符是整串长度,包含引号和逗号。OSS 地址长的话 5 张可能放不下 —— 建议前端上传后存相对路径或短地址,并在提交前自己先量一次 voucherUrls.length,超了就地提示,别等后端报错。

响应 datanull,成功即可返回列表页刷新。接口不返回新建的申领单 ID,需要跳详情的话得先刷列表拿。

撤销物资申领 NEW

POST/supplier/wms/apply/cancel仅申领人本人

入参 { "id": 申领单ID },响应 datanull

只有申领人本人且单据处于待审核时才能撤销。不满足条件统一返回 申领单状态已变更,请刷新后重试(不区分「不是你的单」和「已经被审了」,避免泄露他人单据)。收到这个提示应当刷新列表。

04新增接口 · 列表与详情

申领列表 NEW

POST/supplier/wms/apply/page负责人 / 仓管
请求字段类型必填说明
indexInteger页码,默认 1
sizeInteger页大小,默认 10
statusInteger10/20/30/40,不传查全部。传其他值报「申领状态不合法」
roleNameString当前视角角色名。传 "打包负责人" 时强制只看自己带的大区

roleName 的作用范围

  • 非仓管账号:无论传不传 roleName,永远只能看到自己带的大区的单。
  • 仓管账号:默认看全部;只有当它同时也是负责人、且传了 roleName="打包负责人" 时,才收窄到自己带的大区。
  • 字符串必须精确等于 打包负责人,拼错就当没传。这和现有 /supplier/wms/inventory/team/listroleName 是同一套约定,小程序当前传的 "仓库管理员" 走的就是默认(不收窄)分支,角色切换器的取值直接复用即可。

响应 records 单项:

{
  "id": 88,
  "applyNo": "SL20260825001",     // SL + yyyyMMdd + 3位序列
  "teamName": "昆明一区",
  "skuName": "打包纸箱",           // 即「物资类别」
  "specification": "60×40×40",
  "unitName": "个",
  "applyQuantity": 50,
  "issuedQuantity": 45,          // 仅「已同意」有值,其余状态恒为 null
  "status": 20,
  "statusDesc": "已同意",          // 后端已给中文,直接展示
  "createTime": "2026-08-25 09:12:33",
  "auditTime":  "2026-08-25 10:04:51",
  "canCancel": false,            // 撤销按钮显隐
  "canAudit":  false             // 同意/拒绝按钮显隐
}

✅ 按钮显隐直接用 canCancel / canAudit

这两个布尔是后端按「状态 + 当前账号」算好的,不要在前端用 status===10 && applicantId===me 自己推,列表里也没返回 applicantId。同一条单据对不同人返回的值不同,这是预期的。

申领详情 NEW

POST/supplier/wms/apply/detail仓管 / 本大区负责人

入参 { "id": 申领单ID }。返回值是列表项的超集,在上面所有字段之外多出:

字段类型说明
remarkString申领备注,无备注时是空字符串
voucherInfoString[]这里是真数组,可直接喂给图片预览组件(提交时是字符串,返回时是数组,注意不对称)
applicantNameString申领人姓名快照
auditorNameString审核人姓名,未审核时是空字符串
rejectReasonString拒绝原因,未拒绝或仓管没填时是空字符串
cancelTimeDateTime撤销时间,未撤销时为 null

非仓管账号查非自己大区的单,返回 申领记录不存在(不是无权限),前端按「记录不存在」处理即可。

05新增接口 · 仓管审核

同意申领 NEW

POST/supplier/wms/apply/approve仅仓管
请求字段类型必填说明
idLong申领单 ID
issuedQuantityInteger实际出库数量,可以少发但不能多发:必须 ≥1、≤ applyQuantity、≤ 当前库房剩余可用

审批弹窗建议把 issuedQuantity 默认填成 applyQuantity,允许仓管改小。响应 datanull

拒绝申领 NEW

POST/supplier/wms/apply/reject仅仓管

入参 { "id": 申领单ID, "rejectReason": "库存留给昆明二区" }rejectReason 后端不强制(≤255 字符),如果产品要求必填请前端自己拦。响应 datanull

并发下的统一反馈

同意/拒绝/撤销都是 CAS 更新,只有单据仍是「待审核」才会成功。两个仓管同时点,后点的那个会拿到 申领单状态已变更,请刷新后重试收到这条文案时请自动刷新列表并关闭弹窗,否则用户会一直点一直报错。

06既有接口的行为变化 · 必须跟进

这三处不是新接口,是本次一并收口的老接口。前端不跟会出报错或数字对不上。

新增入库补上了仓管校验 CHANGED

POST/supplier/wms/inventory/inbound/create

该接口此前完全没有角色校验,任何登录账号都能调。现在非仓管调用会返回 非仓库管理员,无进销存操作权限

团队选择逻辑不变,仓管依旧可以选库房或任意大区入库。打包负责人此前若能进到这个页面,现在会被拦下,入口按角色隐藏即可。

新增出库按来源团队收敛权限 BREAKING

POST/supplier/wms/inventory/outbound/create
出库来源谁能操作不满足时的报错
teamId = 0(库房)仅仓库管理员非仓库管理员,无进销存操作权限
teamId > 0(大区)仓库管理员,或该大区的打包负责人无该大区出库权限

打包负责人登记本大区物资消耗的能力保留,但不能再从库房直接出货。出库页的团队选择器建议按角色渲染:仓管给全量,负责人只给 /supplier/wms/inventory/team/listroleName="打包负责人" 后返回的那几个大区。

库存页「库房」一行的口径变了 BREAKING

POST/supplier/wms/inventory/stock/page

teamId = 0 那一行的 teamStock,从「全局实物库存」改成了「库房剩余可用」:

库房剩余可用 = 全局实物库存 − Σ(各大区批次剩余)

大区行的 teamStock 语义不变(该大区剩余)。响应额外带一个 availableStock 字段,值同库房剩余可用,各行都有。

数字会变小,这是预期的

只要有物资发到过大区,库房那一行的数就会比改版前小。这正是需求要的「发放给大区的部分不再在库房重复展示」。文案上建议把库房行标成「库房剩余可用」,避免仓管以为库存丢了。

注意 physicalStock(全局实物)字段在手机端接口被 @JsonIgnore 掉了,响应里没有,前端拿不到也不需要拿。

07搭页面时会用到的既有接口

申领相关页面不需要新的下拉数据接口,直接复用现成的两个:

用途接口说明
选申领大区 /supplier/wms/inventory/team/list {"roleName":"打包负责人"} 拿到「库房 + 自己带的大区」。申领页要把 teamId=0 的库房项过滤掉,只留大区。返回只有 1 个大区时可以隐藏选择器、create 不传 teamId
选物资 /supplier/wms/inventory/sku/list {"skuName":"纸箱"}{"specification":"60"} 模糊搜。返回 skuId / skuName / specification / unitName「物资类别」对应 skuName,「物资规格」对应 specification

推荐的提交页交互顺序

  1. team/list(带 roleName)→ 过滤掉库房 → 大区下拉;只有一个就选中并隐藏
  2. sku/list → 物资类别 / 规格下拉,选中拿到 skuId
  3. apply/sku/stockid 传 skuId)→ 展示「库房剩余可用 N 个」,作为数量输入框的 max
  4. 上传凭证 → JSON.stringify(urls),本地先校验张数 ≤5、长度 ≤512
  5. apply/create → 成功后回列表页刷新

08报错文案速查

所有失败响应的 msg 都是可以直接 toast 的中文,无需前端翻译。下表用于确认交互分支:

msg出现在建议处理
无物资申领权限全部申领接口既不是仓管也不是负责人,隐藏整个申领入口
非仓库管理员,无进销存操作权限approve / reject / 库房出入库隐藏审核按钮
无该大区出库权限outbound/create出库页团队下拉按角色收窄
请选择申领大区create负责人带多个大区却没传 teamId,前端应设为必填
无权为该大区申领createteamId 不在自己带的大区里,一般是前端串了数据
物资不存在或已停用sku/stock、create刷新物资下拉
申领数量超过库房剩余可用库存create重新拉 sku/stock 刷新上限
申领数量不能大于10000create前端 max 设 10000
请至少上传1张凭证create凭证必填
凭证图片最多上传5张create上传组件限 5 张
凭证图片URL文本不能超过512个字符create见 03 节说明,提交前本地量长度
凭证图片格式错误create大概率是传了数组而不是字符串
申领状态不合法pagestatus 只能传 10/20/30/40
申领记录不存在detail越权查看或单据已删,回列表
申领单状态已变更,请刷新后重试cancel / approve / reject自动刷新列表并关弹窗
实际出库数量不能超过申领数量approve审批弹窗 max = applyQuantity
实际出库数量超过库房剩余可用库存approve刷新后重审

09联调注意