@@ -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;
diff --git a/inventory-web/src/views/transaction/borrow.vue b/inventory-web/src/views/transaction/borrow.vue
index 2dc13b0..3b1e2ca 100644
--- a/inventory-web/src/views/transaction/borrow.vue
+++ b/inventory-web/src/views/transaction/borrow.vue
@@ -64,6 +64,21 @@
+
+
+
+
+ 扫码进度
+ {{ scanScannedTypes }}/{{ scanTotalTypes }} 种
+ {{ scanScannedQty }}/{{ scanTotalQty }} 件
+
+
+
+
@@ -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;