feat(scan): 出库/借库扫码增加未扫清单弹窗
- 扫码进度条旁新增「未扫清单 (N)」按钮(有未扫满物料时显示) - 弹窗列出计划中未扫满的物料:名称/规格/计划数量/已扫数量/待扫数量 - 提供「去扫码」快捷跳转,方便补扫漏掉的物料 - 未扫满 = 计划数量 > 已扫数量(含完全未扫和扫了一部分的情况)
This commit is contained in:
@ -80,6 +80,13 @@
|
||||
<span>扫码进度</span>
|
||||
<el-tag type="success" size="small">{{ scanScannedTypes }}/{{ scanTotalTypes }} 种</el-tag>
|
||||
<el-tag type="primary" size="small">{{ scanScannedQty }}/{{ scanTotalQty }} 件</el-tag>
|
||||
<el-button
|
||||
v-if="unscannedCount > 0"
|
||||
type="warning" plain size="small" style="margin-left: auto;"
|
||||
@click="showUnscannedDialog = true"
|
||||
>
|
||||
未扫清单 ({{ unscannedCount }})
|
||||
</el-button>
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="scanTotalQty > 0 ? Math.min(100, Math.round(scanScannedQty / scanTotalQty * 100)) : 0"
|
||||
@ -255,6 +262,37 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ★ 未扫清单弹窗 -->
|
||||
<el-dialog v-model="showUnscannedDialog" title="未扫清单" width="600px" destroy-on-close>
|
||||
<el-alert
|
||||
v-if="unscannedList.length > 0"
|
||||
:title="`以下 ${unscannedList.length} 种物料还未扫满,请补扫:`"
|
||||
type="warning" :closable="false" show-icon style="margin-bottom: 12px;"
|
||||
/>
|
||||
<el-table :data="unscannedList" border size="small" max-height="400">
|
||||
<el-table-column type="index" label="#" width="40" align="center" />
|
||||
<el-table-column prop="name" label="物料名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格型号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="计划" width="70" align="center">
|
||||
<template #default="{ row }">{{ row.planQty }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已扫" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<span style="color: #67C23A;">{{ row.scannedQty }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待扫" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<span style="color: #F56C6C; font-weight: bold;">{{ row.remaining }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button @click="showUnscannedDialog = false">关闭</el-button>
|
||||
<el-button type="primary" @click="showUnscannedDialog = false; showCamera = true">去扫码</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="showSignatureDialog"
|
||||
fullscreen
|
||||
@ -375,6 +413,31 @@ const scanScannedQty = computed(() =>
|
||||
const scanScannedTypes = computed(() => cartItems.value.length)
|
||||
const scanTotalTypes = computed(() => plannedItems.value.length)
|
||||
|
||||
// ★ 未扫清单:计划中还没扫满的物料
|
||||
const unscannedList = computed(() => {
|
||||
return plannedItems.value.map(plan => {
|
||||
const planQty = Number(plan.quantity) || 0
|
||||
// 已扫数量(按名称+规格匹配)
|
||||
const scannedQty = cartItems.value
|
||||
.filter(ci => {
|
||||
const ciName = (ci.name || '').trim()
|
||||
const ciSpec = (ci.spec_model || ci.standard || '').trim()
|
||||
return ciName === (plan.name || '').trim() &&
|
||||
ciSpec === (plan.spec_model || '').trim()
|
||||
})
|
||||
.reduce((sum, ci) => sum + (Number(ci.out_quantity) || 0), 0)
|
||||
return {
|
||||
name: plan.name || '',
|
||||
spec: plan.spec_model || '',
|
||||
planQty,
|
||||
scannedQty,
|
||||
remaining: Math.max(0, planQty - scannedQty)
|
||||
}
|
||||
}).filter(item => item.remaining > 0) // 只保留未扫满的
|
||||
})
|
||||
const unscannedCount = computed(() => unscannedList.value.length)
|
||||
const showUnscannedDialog = ref(false)
|
||||
|
||||
// ★ 加载已审批通过的申请单
|
||||
const loadApprovalRequests = async () => {
|
||||
requestsLoading.value = true
|
||||
|
||||
@ -71,6 +71,13 @@
|
||||
<span>扫码进度</span>
|
||||
<el-tag type="success" size="small">{{ scanScannedTypes }}/{{ scanTotalTypes }} 种</el-tag>
|
||||
<el-tag type="primary" size="small">{{ scanScannedQty }}/{{ scanTotalQty }} 件</el-tag>
|
||||
<el-button
|
||||
v-if="unscannedCount > 0"
|
||||
type="warning" plain size="small" style="margin-left: auto;"
|
||||
@click="showUnscannedDialog = true"
|
||||
>
|
||||
未扫清单 ({{ unscannedCount }})
|
||||
</el-button>
|
||||
</div>
|
||||
<el-progress
|
||||
:percentage="scanTotalQty > 0 ? Math.min(100, Math.round(scanScannedQty / scanTotalQty * 100)) : 0"
|
||||
@ -239,6 +246,37 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ★ 未扫清单弹窗 -->
|
||||
<el-dialog v-model="showUnscannedDialog" title="未扫清单" width="600px" destroy-on-close>
|
||||
<el-alert
|
||||
v-if="unscannedList.length > 0"
|
||||
:title="`以下 ${unscannedList.length} 种物料还未扫满,请补扫:`"
|
||||
type="warning" :closable="false" show-icon style="margin-bottom: 12px;"
|
||||
/>
|
||||
<el-table :data="unscannedList" border size="small" max-height="400">
|
||||
<el-table-column type="index" label="#" width="40" align="center" />
|
||||
<el-table-column prop="name" label="物料名称" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="spec" label="规格型号" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="计划" width="70" align="center">
|
||||
<template #default="{ row }">{{ row.planQty }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="已扫" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<span style="color: #67C23A;">{{ row.scannedQty }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="待扫" width="70" align="center">
|
||||
<template #default="{ row }">
|
||||
<span style="color: #F56C6C; font-weight: bold;">{{ row.remaining }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<el-button @click="showUnscannedDialog = false">关闭</el-button>
|
||||
<el-button type="primary" @click="showUnscannedDialog = false; showCamera = true">去扫码</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-model="showSignatureDialog"
|
||||
fullscreen
|
||||
@ -340,6 +378,31 @@ const scanScannedQty = computed(() =>
|
||||
const scanScannedTypes = computed(() => cartItems.value.length)
|
||||
const scanTotalTypes = computed(() => plannedItems.value.length)
|
||||
|
||||
// ★ 未扫清单:计划中还没扫满的物料
|
||||
const unscannedList = computed(() => {
|
||||
return plannedItems.value.map(plan => {
|
||||
const planQty = Number(plan.quantity) || 0
|
||||
// 已扫数量(按名称+规格匹配)
|
||||
const scannedQty = cartItems.value
|
||||
.filter(ci => {
|
||||
const ciName = (ci.name || '').trim()
|
||||
const ciSpec = (ci.spec_model || ci.standard || '').trim()
|
||||
return ciName === (plan.name || '').trim() &&
|
||||
ciSpec === (plan.spec_model || '').trim()
|
||||
})
|
||||
.reduce((sum, ci) => sum + (Number(ci.out_quantity) || 0), 0)
|
||||
return {
|
||||
name: plan.name || '',
|
||||
spec: plan.spec_model || '',
|
||||
planQty,
|
||||
scannedQty,
|
||||
remaining: Math.max(0, planQty - scannedQty)
|
||||
}
|
||||
}).filter(item => item.remaining > 0) // 只保留未扫满的
|
||||
})
|
||||
const unscannedCount = computed(() => unscannedList.value.length)
|
||||
const showUnscannedDialog = ref(false)
|
||||
|
||||
// ★ 加载已通过审批的借库申请单列表
|
||||
const loadApprovalRequests = async () => {
|
||||
requestsLoading.value = true
|
||||
|
||||
Reference in New Issue
Block a user