feat(scan): 出库/借库扫码进度显示 + 重复扫码确认
- 出库 create.vue + 借库 borrow.vue 均增加扫码进度条 显示: 已扫/总数 种 + 已扫/总数 件 + 进度百分比 - 重复扫码时不再直接 +1,改为弹窗确认「确认 +1 / 取消」 防止手滑重复扫或误操作 - 扫码进度条选中审批单后显示
This commit is contained in:
@ -80,6 +80,20 @@
|
||||
|
||||
<div class="scan-section">
|
||||
|
||||
<!-- ★ 扫码进度条 -->
|
||||
<div v-if="selectedRequest && scanTotalQty > 0" class="scan-progress">
|
||||
<div class="progress-info">
|
||||
<span>扫码进度</span>
|
||||
<el-tag type="success" size="small">{{ scanScannedTypes }}/{{ scanTotalTypes }} 种</el-tag>
|
||||
<el-tag type="primary" size="small">{{ scanScannedQty }}/{{ scanTotalQty }} 件</el-tag>
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="scanTotalQty > 0 ? Math.min(100, Math.round(scanScannedQty / scanTotalQty * 100)) : 0"
|
||||
:stroke-width="8"
|
||||
:color="scanScannedQty >= scanTotalQty ? '#67C23A' : '#409EFF'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-if="!selectedRequestId">
|
||||
<div class="camera-placeholder" style="background-color: #f5f5f5; cursor: not-allowed;">
|
||||
<el-icon :size="40" color="#909399"><CameraFilled /></el-icon>
|
||||
@ -357,6 +371,17 @@ const selectedRequestId = computed({
|
||||
|
||||
const plannedItems = computed(() => selectedRequest.value?.items ?? [])
|
||||
|
||||
// ★ 扫码进度:总需扫数(计划数量总和)/ 已扫数(购物车数量总和)
|
||||
const scanTotalQty = computed(() =>
|
||||
plannedItems.value.reduce((sum, it) => sum + (Number(it.quantity) || 0), 0)
|
||||
)
|
||||
const scanScannedQty = computed(() =>
|
||||
cartItems.value.reduce((sum, it) => sum + (Number(it.out_quantity) || 0), 0)
|
||||
)
|
||||
// 已扫物品种类数 / 计划物品种类数
|
||||
const scanScannedTypes = computed(() => cartItems.value.length)
|
||||
const scanTotalTypes = computed(() => plannedItems.value.length)
|
||||
|
||||
// ★ 加载已审批通过的申请单
|
||||
const loadApprovalRequests = async () => {
|
||||
requestsLoading.value = true
|
||||
@ -534,6 +559,17 @@ const handleManualInput = async () => {
|
||||
|
||||
const maxQty = parseFloat(item.available_quantity)
|
||||
if (item.out_quantity < maxQty) {
|
||||
// ★ 重复扫码:弹窗确认是否 +1,防止手滑重复扫
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`【${item.name} × ${item.spec_model}】已在清单中(当前已扫 ${item.out_quantity} 个)。\n\n确认再 +1 吗?`,
|
||||
'重复扫码确认',
|
||||
{ confirmButtonText: '确认 +1', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch (e) {
|
||||
barcodeInput.value = ''
|
||||
return // 用户取消,不加
|
||||
}
|
||||
item.out_quantity++
|
||||
ElMessage.success(`数量+1 (当前: ${item.out_quantity})`)
|
||||
if (navigator.vibrate) navigator.vibrate(50)
|
||||
@ -837,6 +873,21 @@ onUnmounted(() => {
|
||||
|
||||
/* 扫码区(卡片内触发器) */
|
||||
.scan-section { margin-bottom: 20px; }
|
||||
.scan-progress {
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.progress-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.camera-placeholder {
|
||||
height: 120px; background: #f5f7fa; border: 1px dashed #dcdfe6; border-radius: 8px;
|
||||
display: flex; flex-direction: column; justify-content: center; align-items: center;
|
||||
|
||||
@ -64,6 +64,21 @@
|
||||
</div>
|
||||
|
||||
<div class="scan-section">
|
||||
|
||||
<!-- ★ 扫码进度条 -->
|
||||
<div v-if="selectedApproval && scanTotalQty > 0" class="scan-progress">
|
||||
<div class="progress-info">
|
||||
<span>扫码进度</span>
|
||||
<el-tag type="success" size="small">{{ scanScannedTypes }}/{{ scanTotalTypes }} 种</el-tag>
|
||||
<el-tag type="primary" size="small">{{ scanScannedQty }}/{{ scanTotalQty }} 件</el-tag>
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="scanTotalQty > 0 ? Math.min(100, Math.round(scanScannedQty / scanTotalQty * 100)) : 0"
|
||||
:stroke-width="8"
|
||||
:color="scanScannedQty >= scanTotalQty ? '#67C23A' : '#409EFF'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-if="!selectedApprovalId">
|
||||
<div class="camera-placeholder" style="background-color: #f5f5f5; cursor: not-allowed;">
|
||||
<el-icon :size="40" color="#909399"><CameraFilled /></el-icon>
|
||||
@ -314,6 +329,17 @@ const selectedApproval = computed(() =>
|
||||
|
||||
const plannedItems = computed(() => selectedApproval.value?.items ?? [])
|
||||
|
||||
// ★ 扫码进度:总需扫数(计划数量总和)/ 已扫数(购物车数量总和)
|
||||
const scanTotalQty = computed(() =>
|
||||
plannedItems.value.reduce((sum, it) => sum + (Number(it.quantity) || 0), 0)
|
||||
)
|
||||
const scanScannedQty = computed(() =>
|
||||
cartItems.value.reduce((sum, it) => sum + (Number(it.out_quantity) || 0), 0)
|
||||
)
|
||||
// 已扫物品种类数 / 计划物品种类数
|
||||
const scanScannedTypes = computed(() => cartItems.value.length)
|
||||
const scanTotalTypes = computed(() => plannedItems.value.length)
|
||||
|
||||
// ★ 加载已通过审批的借库申请单列表
|
||||
const loadApprovalRequests = async () => {
|
||||
requestsLoading.value = true
|
||||
@ -456,6 +482,17 @@ const handleManualInput = async () => {
|
||||
|
||||
const maxQty = parseFloat(item.available_quantity)
|
||||
if (item.out_quantity < maxQty) {
|
||||
// ★ 重复扫码:弹窗确认是否 +1,防止手滑重复扫
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`【${item.name} × ${item.spec_model}】已在清单中(当前已扫 ${item.out_quantity} 个)。\n\n确认再 +1 吗?`,
|
||||
'重复扫码确认',
|
||||
{ confirmButtonText: '确认 +1', cancelButtonText: '取消', type: 'warning' }
|
||||
)
|
||||
} catch (e) {
|
||||
barcodeInput.value = ''
|
||||
return // 用户取消,不加
|
||||
}
|
||||
item.out_quantity++
|
||||
ElMessage.success(`数量+1 (当前: ${item.out_quantity})`)
|
||||
if (navigator.vibrate) navigator.vibrate(50)
|
||||
@ -721,6 +758,21 @@ onUnmounted(() => {
|
||||
|
||||
/* 扫码区 */
|
||||
.scan-section { margin-bottom: 20px; }
|
||||
.scan-progress {
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.progress-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.camera-placeholder {
|
||||
height: 120px; background: #f5f7fa; border: 1px dashed #dcdfe6; border-radius: 8px;
|
||||
display: flex; flex-direction: column; justify-content: center; align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user