feat(borrow): 前端转交/流转明细 UI 与借用人选人适配

转交 UI(借还记录页)
----
· 操作列新增【转交】,v-permission="'borrow_transfer'" + 按钮 loading 防抖
· 弹窗明示「仅支持整单全部转交」与「转交后须由接收人本人归还」,并在确认框
  复述接收人与转交数量
· 列表是 borrow_no 主子表结构,trans_borrow.id 在**明细行**上,而一张单的明细
  可各有不同持有人(转交是逐条明细进行的),故弹窗先让用户选定明细;单条明细
  时自动选中(实测 54/60 的单号只有 1 条,等于零额外点击)。
  该「单号按钮 → 弹窗选明细」范式沿用本页既有的「申请报废」。

流转明细时间线
----
· 操作列新增【流转记录】,无特殊权限要求(页面本身已由 op_records 把守)
· Drawer + el-timeline 倒序展示 借出 → 转交(可多次) → 归还 → 报废,
  每节点显示时间、动作、当事人(借用人 / 转出→接收 / 实际归还人)与经手库管,
  转交备注一并展示
· 主列表新增「当前持有人」列:转交后可能与「借用人」不是同一人;一张单的明细
  持有人可能不同,去重后逐个展示,已全部回库显示「已回库」

身份锚点适配
----
· 借出页:借用人由「自由输入姓名」改为「用户下拉」,提交 borrower_id
  (姓名无法唯一锚定一个人,重名即责任链断裂)
· 归还页:新增「实际归还人」下拉,默认取首件物品的当前持有人,提交 returner_id;
  主表新增「当前持有人」列提示库管该由谁来还
· 错误提示不再本地重复弹出 —— request 拦截器已按后端 msg 全局 toast,
  再弹一次会双份

验证:vite build 通过;接口契约经后端回归用例校验。
This commit is contained in:
yueli
2026-09-17 09:18:06 +08:00
parent f7c49f41a8
commit ece5dd8d72
4 changed files with 452 additions and 14 deletions

View File

@ -215,12 +215,18 @@ export function getBorrowStockList(params: { page?: number; pageSize?: number; k
/**
* 执行借库扣减(审批通过后调用)
* @param data approval_id + 扫码选中的物品 + 借用人信息 + 签名
*
* ★ borrower_id 为**必填**:借用人身份从「姓名」升级为「ID 锚点」后,
* 后端以 borrower_id 反查 sys_user 生成姓名快照;缺失会被直接拒绝。
* borrower_name 仅作兼容保留,后端不采信。
*
* @param data approval_id + 扫码选中的物品 + 借用人ID + 签名
*/
export function dispatchBorrow(data: {
approval_id: number
items: Array<any>
borrower_name: string
borrower_id: number
borrower_name?: string
signature_path: string
remark?: string
expected_return_time?: string | null
@ -232,6 +238,67 @@ export function dispatchBorrow(data: {
})
}
/**
* 借库责任链人员名单(借用人 / 转交接收人 / 实际归还人共用)
* @returns [{ id, name }]
*/
export function getBorrowUsers() {
return request({
url: '/v1/transactions/borrow/users',
method: 'get'
})
}
/**
* 借库转交(一期:仅支持整单全量转交)
*
* ★ transfer_qty 必须严格等于待还量,部分转交会被后端拒绝 ——
* 单行模型无法同时追踪两个持有人。
* ★ 转交是纯持有权变更,不触碰任何库存字段。
*
* @param borrowId trans_borrow.id
* @param data transfer_qty + to_user_id + remark
*/
export function transferBorrow(borrowId: number, data: {
transfer_qty: number
to_user_id: number
to_user_name?: string
remark?: string
}) {
return request({
url: `/v1/transactions/borrow/${borrowId}/transfer`,
method: 'post',
data
})
}
/**
* 借出单的流转历史(**单品**维度):转交链 + 逐次归还明细
* @returns { record, transfers[], returns[] }
*/
export function getBorrowHistory(borrowId: number) {
return request({
url: `/v1/transactions/borrow/${borrowId}/history`,
method: 'get'
})
}
/**
* 整单流转时间线(**borrow_no** 维度):借出 → 转交(可多次) → 归还 → 报废
*
* ★ 与 getBorrowHistory 的分工:列表页是 borrow_no 主子表结构(单张单最多
* 21 条明细),逐条明细调用单品接口会产生 21 个请求,且各条时间线无法全局
* 排序。本接口一次返回合并后的事件流,按时间**倒序**。
*
* @returns { borrow_no, events[], records[] }
*/
export function getBorrowSlipHistory(borrowNo: string) {
return request({
url: `/v1/transactions/borrow/slip/${encodeURIComponent(borrowNo)}/history`,
method: 'get'
})
}
/**
* 提交「借出未归还」的**报废申请**(需审批人审批,通过后由库管执行报废)。
*