提醒组件从单向(待我接收)扩展为双向,一次轮询同时取回两类: ① 转交被拒绝 —— 我发起、对方拒收,物品责任仍在我手上 ② 待我接收 —— 别人转给我、等我确认 弹窗(沿用中央 Modal + 遮罩,不进则已、进则打断): 标题「转交被拒绝」,列出被拒物品(物料名 + 单号 + 接收人,超过 5 笔折叠计数), 按钮【去处理】(跳借还记录) /【知道了】。 ★ 优先级:拒绝提醒优先于待接收提醒,且**一次只弹一个弹窗**。 前者是「责任已回到你手上」的状态变更,后者是「等你确认」的待办; 本次弹了拒绝就直接 return,待接收那条留给下一轮(此时拒绝已 ack), 避免两个 Modal 叠加打扰。 ★ 两条退出路径都算「已知悉」并 ack —— 否则每次登录都会再弹同一条, 从提醒退化成骚扰。ack 失败不阻断,下一轮还会再提醒(宁可多提醒一次, 也不能漏)。 防叠加沿用上一轮的模块标志 + DOM 探测,标题白名单扩为两个。 顺带:流转明细时间线为转交节点补状态标签(已拒绝/待接收),被拒的转交 不再与成功的长得一模一样。 验证(node 复刻判定链) 既有拒绝、又有 2 件待接收 → 弹[转交被拒绝];确认后 ack; 下一轮 → 弹[待办通知] count=2;再轮询 → 不弹(未变)。 拒绝优先、不叠加、ack 后待接收提醒正常补上。
380 lines
11 KiB
TypeScript
380 lines
11 KiB
TypeScript
import request from '@/utils/request'
|
||
|
||
// 购物车商品项接口
|
||
export interface CartItem {
|
||
id: number
|
||
sku: string
|
||
name: string
|
||
spec_model: string
|
||
source_table: string
|
||
stock_quantity: number
|
||
available_quantity: number
|
||
barcode: string
|
||
price: number // 单价
|
||
out_quantity: number // 本次出库数量
|
||
}
|
||
|
||
// 提交出库单的数据结构
|
||
export interface OutboundSubmitData {
|
||
items: Array<{
|
||
sku: string
|
||
source_table: string
|
||
stock_id: number
|
||
barcode: string
|
||
quantity: number
|
||
price: number
|
||
}>
|
||
outbound_type: string
|
||
consumer_name: string
|
||
operator_name: string
|
||
signature_path: string // 上传后返回的图片路径
|
||
remark?: string
|
||
}
|
||
|
||
export interface ScanResult {
|
||
id: number
|
||
sku: string
|
||
name: string
|
||
spec_model: string
|
||
source_table: string // 'stock_buy' | 'stock_product' ...
|
||
stock_quantity: number
|
||
available_quantity: number
|
||
batch_number?: string
|
||
warehouse_location?: string
|
||
barcode?: string
|
||
price?: number // 扫描返回的价格
|
||
}
|
||
|
||
/**
|
||
* 根据条码获取库存物品详情
|
||
*
|
||
* ⚠ 本文件是与 `@/api/outbound` 同名的**历史副本**(同 URL、同返回形状),
|
||
* 当前无任何调用方 —— 借库扫码页 `views/transaction/borrow.vue` 是从
|
||
* `@/api/outbound` 导入的。改动请落到那边,这里同步仅为避免下次改漏。
|
||
*
|
||
* @param barcode 扫描到的条码
|
||
* @param requestId 本单 ID(出库审批单 / 借库审批单)
|
||
* @param bizType 单据类型,决定 requestId 查哪张表(默认 outbound)
|
||
*/
|
||
export function getStockByBarcode(
|
||
barcode: string,
|
||
requestId?: number | null,
|
||
bizType: 'outbound' | 'borrow' = 'outbound'
|
||
) {
|
||
return request<any, ScanResult>({
|
||
url: '/v1/outbound/scan',
|
||
method: 'get',
|
||
params: { barcode, request_id: requestId, biz_type: bizType }
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 提交出库单 (批量)
|
||
*/
|
||
export function submitOutbound(data: OutboundSubmitData) {
|
||
return request({
|
||
url: '/v1/outbound',
|
||
method: 'post',
|
||
data
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取出库记录列表
|
||
*/
|
||
export function getOutboundList(params: any) {
|
||
return request({
|
||
url: '/v1/outbound',
|
||
method: 'get',
|
||
params
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 提交出库申请单(申请人 → 审批流)
|
||
*/
|
||
export function submitOutboundRequest(data: {
|
||
items: Array<{
|
||
material_type?: string
|
||
name: string
|
||
spec_model: string
|
||
warehouse_location?: string
|
||
quantity: number
|
||
}>
|
||
remark: string
|
||
}) {
|
||
return request({
|
||
url: '/v1/outbound/request',
|
||
method: 'post',
|
||
data
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取出库审批申请单列表
|
||
* @param params 支持 status, page, limit
|
||
*/
|
||
export function getApprovalRequestList(params: { status?: number | ''; page?: number; limit?: number }) {
|
||
return request({
|
||
url: '/v1/outbound/request',
|
||
method: 'get',
|
||
params
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 审批(通过 / 驳回)出库申请单
|
||
* @param id 审批单ID
|
||
* @param data action: 'approve' | 'reject',reject 时需传 reject_reason
|
||
*/
|
||
export function approveRequest(id: number, data: { action: 'approve' | 'reject'; reject_reason?: string }) {
|
||
return request({
|
||
url: `/v1/outbound/request/${id}/approve`,
|
||
method: 'patch',
|
||
data
|
||
})
|
||
}
|
||
|
||
// ==============================================================================
|
||
// 借库审批流 API
|
||
// ==============================================================================
|
||
|
||
/**
|
||
* 提交借库申请单(申请人 → 审批流)
|
||
*/
|
||
export function submitBorrowRequest(data: {
|
||
items: Array<{
|
||
name: string
|
||
spec_model: string
|
||
warehouse_location?: string
|
||
quantity: number
|
||
}>
|
||
remark?: string
|
||
allowed_approvers?: Array<{ type: string; value: string }>
|
||
approver_id?: number
|
||
}) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/request',
|
||
method: 'post',
|
||
data
|
||
})
|
||
}
|
||
|
||
// 借库申请预检:判断所选物料是否需审批
|
||
export function checkBorrowApproval(data: { items: Array<{ name?: string; spec_model?: string }> }) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/request/check-approval',
|
||
method: 'post',
|
||
data
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取借库审批申请单列表
|
||
* @param params 支持 status, page, limit
|
||
*/
|
||
export function getBorrowApprovalList(params: { status?: number | ''; page?: number; limit?: number }) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/request',
|
||
method: 'get',
|
||
params
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 审批(通过 / 驳回)借库申请单
|
||
* @param id 审批单ID
|
||
* @param data action: 'approve' | 'reject',reject 时需传 reject_reason
|
||
*/
|
||
export function approveBorrowRequest(id: number, data: { action: 'approve' | 'reject'; reject_reason?: string }) {
|
||
return request({
|
||
url: `/v1/transactions/borrow/request/${id}/approve`,
|
||
method: 'patch',
|
||
data
|
||
})
|
||
}
|
||
|
||
// 手动完结已通过的借库审批单(status 1 → 3)
|
||
export function closeBorrowRequest(id: number) {
|
||
return request({
|
||
url: `/v1/transactions/borrow/request/${id}/close`,
|
||
method: 'post'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 借库选单专用库存列表(独立权限 op_borrow_apply)
|
||
*/
|
||
export function getBorrowStockList(params: { page?: number; pageSize?: number; keyword?: string }) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/stock-list',
|
||
method: 'get',
|
||
params
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 执行借库扣减(审批通过后调用)
|
||
*
|
||
* ★ 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_id: number
|
||
borrower_name?: string
|
||
signature_path: string
|
||
remark?: string
|
||
expected_return_time?: string | null
|
||
}) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/dispatch',
|
||
method: 'post',
|
||
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'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 确认接收转交(双向握手第二步)—— 责任正式转移到接收人名下。
|
||
*
|
||
* ★ 仅该转交的 to_user_id 本人可调用(后端强校验,非库管权限)。
|
||
* ★ 副作用:该单**全部未归还明细**的当前持有人一并变更。
|
||
*/
|
||
export function acceptBorrowTransfer(transferId: number) {
|
||
return request({
|
||
url: `/v1/transactions/borrow/transfer/${transferId}/accept`,
|
||
method: 'post'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 拒绝转交 —— 主表不动,责任仍在原持有人。权限同上。
|
||
* @param reason 可选拒绝原因,写入转交流水备注
|
||
*/
|
||
export function rejectBorrowTransfer(transferId: number, reason?: string) {
|
||
return request({
|
||
url: `/v1/transactions/borrow/transfer/${transferId}/reject`,
|
||
method: 'post',
|
||
data: { reason }
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 全局待办强提醒的轮询数据源(初始化 + 轮询)。
|
||
*
|
||
* ★ 一次请求返回两类信息,避免前端多打一个请求:
|
||
* count —— 待**我接收**的转交数量
|
||
* rejects —— **我发起、被对方拒绝、尚未告知我**的转交
|
||
* (被拒时物品责任仍在我手上,不告知就会误以为已交接出去)
|
||
*
|
||
* @returns { count, rejects: [{ id, borrow_no, sku, material_name, to_user_name, remark, ... }] }
|
||
*/
|
||
export function getPendingTransferCount() {
|
||
return request({
|
||
url: '/v1/transactions/borrow/transfer/pending-count',
|
||
method: 'get'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 确认已知悉「转交被拒绝」—— 写 reject_seen_at,之后不再提醒。
|
||
* @param ids 留空表示该用户全部待告知的拒绝
|
||
*/
|
||
export function ackTransferRejects(ids?: number[]) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/transfer/reject-ack',
|
||
method: 'post',
|
||
data: { ids }
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 整单流转时间线(**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'
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 提交「借出未归还」的**报废申请**(需审批人审批,通过后由库管执行报废)。
|
||
*
|
||
* ★ 已由「直接报废」改为「申请」:
|
||
* 原 POST /v1/transactions/borrow/scrap 直接写 trans_scrap 并扣总库存,
|
||
* 绕过审批、构成职责分离漏洞,已删除。现统一走 申请 → 审批 → 执行。
|
||
*
|
||
* ★ 副作用提醒:申请**不立即改变**借用记录状态,提交后该笔仍显示为未归还。
|
||
* 前端必须提示用户「待审批并执行后才会标记为已报废」。
|
||
*
|
||
* @param data record_ids: trans_borrow.id 列表(按整条待还量报废)
|
||
* reason?: 写入申请单备注
|
||
* approver_id: 必填,指定审批人
|
||
*/
|
||
export function submitBorrowScrapRequest(data: {
|
||
record_ids: number[]
|
||
reason?: string
|
||
approver_id: number
|
||
}) {
|
||
return request({
|
||
url: '/v1/transactions/borrow/scrap-request',
|
||
method: 'post',
|
||
data
|
||
})
|
||
} |