feat(outbound): 出库流程强化(缺料防漏 + 完全移除直接出库)
① BOM 清单 SKU 改为规格型号(getBomWithStock 返回 children 无 sku,只有 child_spec) ② 缺货清单自动写入出库申请备注(借鸡生蛋:历史欠料永久留存在申请单) ③ 打印单底部增加欠料待补签收区(补料人签字/日期) ④ 有缺料时阻断式二次确认,防手快漏看 ⑤ 完全移除直接出库模式,所有出库必须按单出库 - create.vue 删除 radio 切换、direct 相关逻辑 - 提交前强制校验已选择审批申请单
This commit is contained in:
@ -15,19 +15,14 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ★ 出库模式切换 -->
|
||||
<!-- ★ 出库模式:仅支持按单出库(已移除直接出库) -->
|
||||
<div class="mode-switch-bar">
|
||||
<el-radio-group v-model="outboundMode" size="default" @change="handleModeChange">
|
||||
<el-radio-button value="by-request">按单出库</el-radio-button>
|
||||
<el-radio-button value="direct">直接出库</el-radio-button>
|
||||
</el-radio-group>
|
||||
<span class="mode-hint">
|
||||
{{ outboundMode === 'by-request' ? '需先选择已审批通过的申请单' : '无需审批单,自由扫码出库' }}
|
||||
</span>
|
||||
<el-tag type="primary" size="large" style="font-size: 14px;">按单出库</el-tag>
|
||||
<span class="mode-hint">请先选择已审批通过的申请单,再扫码出库</span>
|
||||
</div>
|
||||
|
||||
<!-- ★ 按单出库:审批单选择 -->
|
||||
<div v-if="outboundMode === 'by-request'" class="approval-request-select">
|
||||
<div class="approval-request-select">
|
||||
<el-select
|
||||
v-model="selectedRequestId"
|
||||
placeholder="请选择已审批通过的出库申请单"
|
||||
@ -54,7 +49,7 @@
|
||||
</div>
|
||||
|
||||
<!-- ★ 按单出库:计划清单预览 -->
|
||||
<div v-if="outboundMode === 'by-request' && selectedRequest" class="planned-items-section">
|
||||
<div v-if="selectedRequest" class="planned-items-section">
|
||||
<div class="planned-header">
|
||||
<span class="planned-title">计划出库清单</span>
|
||||
<el-tag type="success" size="small">{{ selectedRequest.items?.length || 0 }} 种</el-tag>
|
||||
@ -79,7 +74,7 @@
|
||||
|
||||
<div class="scan-section">
|
||||
|
||||
<template v-if="outboundMode === 'by-request' && !selectedRequestId">
|
||||
<template v-if="!selectedRequestId">
|
||||
<div class="camera-placeholder" style="background-color: #f5f5f5; cursor: not-allowed;">
|
||||
<el-icon :size="40" color="#909399"><CameraFilled /></el-icon>
|
||||
<span class="text">请先选择审批单</span>
|
||||
@ -304,7 +299,7 @@ const barcodeRef = ref()
|
||||
const formRef = ref()
|
||||
|
||||
// ★ 双轨制模式
|
||||
const outboundMode = ref<'by-request' | 'direct'>('by-request') // 'by-request' | 'direct'
|
||||
// ★ 已移除直接出库模式,所有出库必须按单出库(通过 selectedRequest 校验)
|
||||
const approvalRequests = ref<any[]>([])
|
||||
const selectedRequest = ref<any>(null)
|
||||
const requestsLoading = ref(false)
|
||||
@ -355,18 +350,6 @@ const selectedRequestId = computed({
|
||||
|
||||
const plannedItems = computed(() => selectedRequest.value?.items ?? [])
|
||||
|
||||
// ★ 模式切换
|
||||
const handleModeChange = () => {
|
||||
selectedRequest.value = null
|
||||
selectedRequestId.value = null
|
||||
cartItems.value = []
|
||||
form.consumer_name = ''
|
||||
form.remark = ''
|
||||
signatureFile.value = null
|
||||
signaturePreviewUrl.value = ''
|
||||
barcodeInput.value = ''
|
||||
}
|
||||
|
||||
// ★ 加载已审批通过的申请单
|
||||
const loadApprovalRequests = async () => {
|
||||
requestsLoading.value = true
|
||||
@ -489,7 +472,7 @@ const handleManualInput = async () => {
|
||||
if (!code) return
|
||||
|
||||
// ★ 按单出库模式:必须先选择申请单
|
||||
if (outboundMode.value === 'by-request' && !selectedRequest.value) {
|
||||
if (!selectedRequest.value) {
|
||||
ElMessage.warning('请先选择要出库的审批申请单')
|
||||
return
|
||||
}
|
||||
@ -503,14 +486,12 @@ const handleManualInput = async () => {
|
||||
const item = cartItems.value[existIndex]
|
||||
|
||||
// ★ 按单模式:追加时仍需校验计划数量
|
||||
if (outboundMode.value === 'by-request') {
|
||||
const err = validateAgainstPlan(item.name, item.spec_model, 1)
|
||||
if (err) {
|
||||
ElMessage.error(err)
|
||||
if (navigator.vibrate) navigator.vibrate([200, 100, 200])
|
||||
barcodeInput.value = ''
|
||||
return
|
||||
}
|
||||
const err = validateAgainstPlan(item.name, item.spec_model, 1)
|
||||
if (err) {
|
||||
ElMessage.error(err)
|
||||
if (navigator.vibrate) navigator.vibrate([200, 100, 200])
|
||||
barcodeInput.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
const maxQty = parseFloat(item.available_quantity)
|
||||
@ -540,14 +521,12 @@ const handleManualInput = async () => {
|
||||
}
|
||||
|
||||
// ★ 按单模式:扫码加入前校验是否在计划清单内
|
||||
if (outboundMode.value === 'by-request') {
|
||||
const err = validateAgainstPlan(item.name, item.spec_model, 1)
|
||||
if (err) {
|
||||
ElMessage.error(err)
|
||||
if (navigator.vibrate) navigator.vibrate([200, 100, 200])
|
||||
barcodeInput.value = ''
|
||||
return
|
||||
}
|
||||
const err = validateAgainstPlan(item.name, item.spec_model, 1)
|
||||
if (err) {
|
||||
ElMessage.error(err)
|
||||
if (navigator.vibrate) navigator.vibrate([200, 100, 200])
|
||||
barcodeInput.value = ''
|
||||
return
|
||||
}
|
||||
|
||||
// 加入购物车
|
||||
@ -610,6 +589,11 @@ const submitForm = async () => {
|
||||
}
|
||||
if (!formRef.value) return
|
||||
if (cartItems.value.length === 0) return ElMessage.warning('请先添加商品')
|
||||
// ★ 按单出库:提交前必须已选择审批申请单
|
||||
if (!selectedRequest.value) {
|
||||
ElMessage.warning('请先选择要出库的审批申请单')
|
||||
return
|
||||
}
|
||||
|
||||
await formRef.value.validate(async (valid: boolean) => {
|
||||
if (!valid) return
|
||||
@ -653,7 +637,7 @@ const submitForm = async () => {
|
||||
// 3. 组装发给后端的包
|
||||
const submitPayload: any = {
|
||||
outbound_type: form.outbound_type,
|
||||
request_id: outboundMode.value === 'by-request' && selectedRequest.value ? selectedRequest.value.id : null,
|
||||
request_id: selectedRequest.value ? selectedRequest.value.id : null,
|
||||
consumer_name: form.consumer_name,
|
||||
operator_name: form.operator_name,
|
||||
remark: form.remark,
|
||||
|
||||
Reference in New Issue
Block a user