feat(scrap): 前端适配报废审批收口
配合后端把三条报废旁路收口到审批流。
【删除】api/scrap.ts 的 createScrap()
对应后端已删的 POST /api/v1/scrap。该函数此前已是死代码(全仓无调用方),
页面早已切换到申请-审批-按单执行流程。
【改造】不良品看板 views/stock/defective/index.vue
「报废销毁」→「申请报废」:弹窗新增「指定审批人」(必填,复用
getApproversList)。API 由 scrapDefective 改为 submitDefectiveScrapRequest。
★ 弹窗与成功提示都明确写出「在管数量不会立即扣减,待审批通过并执行后才
扣减」—— 申请不预占 remaining_qty,行数据看起来毫无变化,不说明会诱发
重复提交。
【改造】借还记录页 views/transaction/records.vue
「报废」→「申请报废」:弹窗新增「指定审批人」(必填)。原先内联的
request() 调用挪到 api/transaction.ts 成为 submitBorrowScrapRequest,
与全仓 API 分层一致。确认框文案改为「提交后进入审批流程」。
顺带清理 canScrap 里硬编码的 `username === 'IRIS'` 后门 —— 该账号在
sys_user 表中根本不存在,属死代码。
【改造】按单报废执行页 views/operation/scrap/create.vue
按 scrap_mode 把批准明细分流:
· scan 项(库存行 / 在管不良品)—— 走原有扫码购物车,逻辑不变
· auto 项(借出未还)—— 实物在借用人手上、无法扫码,放入**只读区块**
展示,不进购物车(购物车语义是「扫码证据」,混入会让扫码校验失效)
纯 auto 单隐藏整个扫码区并提示「本单无可扫码物料,将按批准数量直接执行」;
扫码进度只统计 scan 项(否则进度条永远满不了,会让操作员误以为没扫完);
提交守卫放宽为「购物车与 auto 项都为空才拦」;确认框追加
「另有 N 项将按批准数量自动执行」,避免操作员误以为只报废了扫到的那些。
matchKey 同步加入来源表(与后端 _match_key 保持逐字同口径),
sourceLabel 补两种新来源的中文名。
存量单据没有 scrap_mode 字段,前端回落为 scan,行为与改造前完全一致。
This commit is contained in:
@ -199,7 +199,7 @@
|
||||
v-if="row.status === 'borrowed' || row.status === 'partial_returned'"
|
||||
type="danger" link size="small"
|
||||
@click="openScrapDialog(row)"
|
||||
>报废</el-button>
|
||||
>申请报废</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -212,10 +212,10 @@
|
||||
style="margin-top:10px; text-align:right"
|
||||
/>
|
||||
|
||||
<!-- ★ 借库报废弹窗 -->
|
||||
<el-dialog v-model="scrapDialogVisible" title="借库报废(未归还)" width="650px" destroy-on-close>
|
||||
<!-- ★ 借库报废**申请**弹窗(需审批,不再直报) -->
|
||||
<el-dialog v-model="scrapDialogVisible" title="申请借库报废(未归还)" width="650px" destroy-on-close>
|
||||
<el-alert
|
||||
title="报废后该笔借出不再追讨归还,并从总库存中扣除。此操作不可恢复,请谨慎确认。"
|
||||
title="提交后进入审批流程:审批通过并执行后,该笔借出才不再追讨归还,并从总库存中扣除。"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
@ -245,10 +245,15 @@
|
||||
placeholder="请填写报废原因,如:物品丢失 / 损坏无法归还"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批人" required>
|
||||
<el-select v-model="scrapApproverId" placeholder="请选择审批人" style="width: 100%" filterable>
|
||||
<el-option v-for="u in approvers" :key="u.id" :label="u.username" :value="u.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="scrapDialogVisible = false">取消</el-button>
|
||||
<el-button type="danger" :loading="scrapSubmitting" @click="confirmScrap">确认报废</el-button>
|
||||
<el-button type="danger" :loading="scrapSubmitting" @click="confirmScrap">提交报废申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@ -262,6 +267,8 @@ import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/zh-cn'
|
||||
dayjs.locale('zh-cn')
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { getApproversList } from '@/api/auth'
|
||||
import { submitBorrowScrapRequest } from '@/api/transaction'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
@ -365,11 +372,10 @@ const resetAdvancedFilter = () => {
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// ★ 借库报废相关
|
||||
// ★ 借库报废**申请**相关(需审批,不再直报)
|
||||
const canScrap = computed(() =>
|
||||
userStore.role === 'SUPER_ADMIN' ||
|
||||
userStore.hasPermission('op_return:operation') ||
|
||||
userStore.username === 'IRIS'
|
||||
userStore.hasPermission('op_return:operation')
|
||||
)
|
||||
const scrapDialogVisible = ref(false)
|
||||
const scrapSubmitting = ref(false)
|
||||
@ -377,15 +383,28 @@ const scrapBorrowNo = ref('')
|
||||
const scrapCandidates = ref<any[]>([])
|
||||
const scrapSelected = ref<any[]>([])
|
||||
const scrapReason = ref('')
|
||||
const scrapApproverId = ref<number | null>(null)
|
||||
const approvers = ref<any[]>([])
|
||||
|
||||
// 打开报废弹窗:收集该单号下所有未归还明细
|
||||
const loadApprovers = async () => {
|
||||
try {
|
||||
const res = await getApproversList()
|
||||
approvers.value = res.data || []
|
||||
} catch (e) {
|
||||
console.error('[借库报废申请] 审批人列表加载失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开报废申请弹窗:收集该单号下所有未归还明细
|
||||
const openScrapDialog = (row: any) => {
|
||||
const unreturned = (row.children || []).filter((c: any) => (c.pending_quantity || 0) > 0)
|
||||
scrapBorrowNo.value = row.borrow_no
|
||||
scrapCandidates.value = unreturned
|
||||
scrapSelected.value = []
|
||||
scrapReason.value = ''
|
||||
scrapApproverId.value = null
|
||||
scrapDialogVisible.value = true
|
||||
loadApprovers()
|
||||
}
|
||||
|
||||
// 勾选变更
|
||||
@ -393,16 +412,18 @@ const handleScrapSelection = (rows: any[]) => {
|
||||
scrapSelected.value = rows
|
||||
}
|
||||
|
||||
// 确认报废
|
||||
// 提交报废申请
|
||||
const confirmScrap = async () => {
|
||||
if (scrapSelected.value.length === 0) return ElMessage.warning('请至少选择一条要报废的借出记录')
|
||||
if (scrapSelected.value.length === 0) return ElMessage.warning('请至少选择一条要申请报废的借出记录')
|
||||
if (!scrapReason.value.trim()) return ElMessage.warning('请填写报废原因')
|
||||
if (!scrapApproverId.value) return ElMessage.warning('请选择审批人')
|
||||
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定报废 ${scrapSelected.value.length} 条借出记录吗?\n\n报废后不再追讨归还,并从总库存中扣除。此操作不可恢复!`,
|
||||
'⚠️ 报废确认',
|
||||
{ confirmButtonText: '确认报废', cancelButtonText: '取消', type: 'warning' }
|
||||
`确定对 ${scrapSelected.value.length} 条借出记录提交报废申请吗?\n\n`
|
||||
+ '提交后进入审批流程,审批通过并执行后才会扣减总库存。',
|
||||
'报废申请确认',
|
||||
{ confirmButtonText: '提交申请', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch (e) {
|
||||
return // 用户取消
|
||||
@ -411,16 +432,19 @@ const confirmScrap = async () => {
|
||||
scrapSubmitting.value = true
|
||||
try {
|
||||
const recordIds = scrapSelected.value.map((c: any) => c.id)
|
||||
await request({
|
||||
url: '/v1/transactions/borrow/scrap',
|
||||
method: 'post',
|
||||
data: { record_ids: recordIds, reason: scrapReason.value }
|
||||
const res = await submitBorrowScrapRequest({
|
||||
record_ids: recordIds,
|
||||
reason: scrapReason.value,
|
||||
approver_id: scrapApproverId.value,
|
||||
})
|
||||
ElMessage.success(`已报废 ${recordIds.length} 条借出记录`)
|
||||
// ★ 提示里点明「尚未扣减」—— 申请不立即改状态,否则用户会以为没生效而重复提交
|
||||
ElMessage.success(
|
||||
`${res?.msg || '报废申请已提交'}:审批通过并执行后才会标记为已报废`,
|
||||
)
|
||||
scrapDialogVisible.value = false
|
||||
fetchData()
|
||||
} catch (err: any) {
|
||||
ElMessage.error(err?.msg || err?.message || '报废失败')
|
||||
ElMessage.error(err?.msg || err?.message || '提交报废申请失败')
|
||||
} finally {
|
||||
scrapSubmitting.value = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user