优化
This commit is contained in:
@@ -2,12 +2,20 @@
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useAuthStore } from '@/modules/auth/public'
|
||||
import { confirmDiscardCompletion, confirmRelabelCompletion, downloadDiscardPhoto, downloadRelabelCompletionPhoto, getDiscard, getRelabel, type DiscardPhoto } from '../api/warehouseServices'
|
||||
import { confirmDiscardCompletion, confirmRelabelCompletion, confirmTransferMeasurement, downloadDiscardPhoto, downloadRelabelCompletionPhoto, downloadTransferMeasurementPhoto, getDiscard, getRelabel, getTransfer, type DiscardPhoto } from '../api/warehouseServices'
|
||||
|
||||
const props = defineProps<{ modelValue: boolean; kind: 'disposal' | 'labeling'; documentNo: string }>()
|
||||
const props = defineProps<{ modelValue: boolean; kind: 'disposal' | 'labeling' | 'transfer'; documentNo: string }>()
|
||||
const emit = defineEmits<{ 'update:modelValue': [value: boolean]; confirmed: [documentNo: string] }>()
|
||||
const auth = useAuthStore()
|
||||
const title = computed(() => props.kind === 'disposal' ? '废弃确认' : '贴标完成确认')
|
||||
const title = computed(() => props.kind === 'transfer' ? '确认测量数据' : props.kind === 'disposal' ? '废弃确认' : '贴标完成确认')
|
||||
interface MeasurementEvidence {
|
||||
status?: string
|
||||
customerConfirmedAt?: string
|
||||
cartons?: Array<{ cartonMark: string; status: string; length?: number; width?: number; height?: number; weight?: number }>
|
||||
pallets?: Array<{ palletNo?: string; sequenceNo?: number; cartonCount?: number; lengthCm?: number; widthCm?: number; heightCm?: number; grossWeightKg?: number; volumeCbm?: number }>
|
||||
measurementPhotos?: Array<{ fileId: string | number }>
|
||||
}
|
||||
const measurement = ref<MeasurementEvidence | null>(null)
|
||||
const loading = ref(false)
|
||||
const busy = ref(false)
|
||||
const error = ref('')
|
||||
@@ -21,18 +29,19 @@ let generation = 0
|
||||
const previewUrls = computed(() => fileIds.value.map(id => urls.value[id]).filter(Boolean))
|
||||
const canConfirm = computed(() => eligible.value && checked.value && !loading.value && !busy.value && !error.value
|
||||
&& fileIds.value.length > 0 && fileIds.value.every(id => Boolean(urls.value[id]))
|
||||
&& auth.hasPermission(`merchant:overseas-warehouse:${props.kind === 'disposal' ? 'discard' : 'relabel'}:confirm`))
|
||||
&& auth.hasPermission(`merchant:overseas-warehouse:${props.kind === 'transfer' ? 'transfer' : props.kind === 'disposal' ? 'discard' : 'relabel'}:confirm`))
|
||||
function clear() {
|
||||
generation++
|
||||
Object.values(urls.value).forEach(URL.revokeObjectURL)
|
||||
urls.value = {}; failed.value = {}; photoLoading.value = {}; fileIds.value = []; checked.value = false; eligible.value = false
|
||||
measurement.value = null
|
||||
}
|
||||
async function loadPhoto(fileId: string) {
|
||||
if (photoLoading.value[fileId]) return
|
||||
const currentGeneration = generation; const no = props.documentNo; const kind = props.kind
|
||||
photoLoading.value[fileId] = true; failed.value[fileId] = false
|
||||
try {
|
||||
const blob = kind === 'disposal' ? await downloadDiscardPhoto(no, fileId) : await downloadRelabelCompletionPhoto(no, fileId)
|
||||
const blob = kind === 'transfer' ? await downloadTransferMeasurementPhoto(no, fileId) : kind === 'disposal' ? await downloadDiscardPhoto(no, fileId) : await downloadRelabelCompletionPhoto(no, fileId)
|
||||
if (generation !== currentGeneration || !props.modelValue) return
|
||||
if (urls.value[fileId]) URL.revokeObjectURL(urls.value[fileId])
|
||||
urls.value[fileId] = URL.createObjectURL(blob)
|
||||
@@ -43,7 +52,13 @@ async function loadEvidence() {
|
||||
clear(); error.value = ''; loading.value = true
|
||||
const currentGeneration = generation
|
||||
try {
|
||||
if (props.kind === 'disposal') {
|
||||
if (props.kind === 'transfer') {
|
||||
const detail = await getTransfer(props.documentNo) as MeasurementEvidence
|
||||
if (generation !== currentGeneration) return
|
||||
measurement.value = detail
|
||||
eligible.value = detail.status === 'WAIT_CUSTOMER_CONFIRMATION' && !detail.customerConfirmedAt
|
||||
fileIds.value = (detail.measurementPhotos || []).map(photo => String(photo.fileId))
|
||||
} else if (props.kind === 'disposal') {
|
||||
const detail = await getDiscard(props.documentNo) as { summary?: { status?: string }; photos?: DiscardPhoto[] }
|
||||
if (generation !== currentGeneration) return
|
||||
eligible.value = detail.summary?.status === 'PDA_COMPLETED'
|
||||
@@ -56,7 +71,7 @@ async function loadEvidence() {
|
||||
}
|
||||
fileIds.value = [...new Set(fileIds.value)]
|
||||
if (!eligible.value) error.value = '当前单据已确认或尚未完成 PDA 作业,请刷新列表核对。'
|
||||
else if (!fileIds.value.length) error.value = '暂无 PDA 完工作业照片,暂不能确认。'
|
||||
else if (!fileIds.value.length) error.value = props.kind === 'transfer' ? '暂无 PDA 测量打托照片,暂不能确认。' : '暂无 PDA 完工作业照片,暂不能确认。'
|
||||
await Promise.all(fileIds.value.map(loadPhoto))
|
||||
} catch (e) { if (generation === currentGeneration) error.value = e instanceof Error ? e.message : '作业照片加载失败' }
|
||||
finally { if (generation === currentGeneration) loading.value = false }
|
||||
@@ -65,9 +80,10 @@ async function submit() {
|
||||
if (!canConfirm.value) return
|
||||
busy.value = true
|
||||
try {
|
||||
if (props.kind === 'disposal') await confirmDiscardCompletion(props.documentNo)
|
||||
if (props.kind === 'transfer') await confirmTransferMeasurement(props.documentNo)
|
||||
else if (props.kind === 'disposal') await confirmDiscardCompletion(props.documentNo)
|
||||
else await confirmRelabelCompletion(props.documentNo)
|
||||
ElMessage.success(props.kind === 'disposal' ? '废弃已确认,单据已完结' : '贴标已确认,订单进入后续出库流程')
|
||||
ElMessage.success(props.kind === 'transfer' ? '仓库实测数据已确认' : props.kind === 'disposal' ? '废弃已确认,单据已完结' : '贴标已确认,订单进入后续出库流程')
|
||||
emit('confirmed', props.documentNo)
|
||||
emit('update:modelValue', false)
|
||||
} catch (e) { ElMessage.error(e instanceof Error ? e.message : '确认失败,请重试') }
|
||||
@@ -80,7 +96,22 @@ onBeforeUnmount(clear)
|
||||
<template>
|
||||
<el-dialog :model-value="modelValue" :title="title" width="760px" :close-on-click-modal="false" :close-on-press-escape="!busy" :show-close="!busy" @update:model-value="!busy && emit('update:modelValue', $event)">
|
||||
<p>单号:{{ documentNo }}</p>
|
||||
<p>请核对以下 PDA 作业照片,确认作业结果无误后再提交。</p>
|
||||
<p>{{ kind === 'transfer' ? '请核对 PDA 回传的箱数、尺寸、重量、打托数据及现场照片,确认无误后再提交。' : '请核对以下 PDA 作业照片,确认作业结果无误后再提交。' }}</p>
|
||||
<template v-if="kind === 'transfer' && measurement">
|
||||
<p>实际签收箱数:{{ measurement.cartons?.filter(carton => carton.status === 'COUNTED').length ?? 0 }} 箱;托盘数:{{ measurement.pallets?.length ?? 0 }} 托</p>
|
||||
<el-table :data="measurement.pallets || []" max-height="220" size="small" border empty-text="暂无 PDA 打托测量数据">
|
||||
<el-table-column label="托盘号" min-width="180"><template #default="{ row }">{{ row.palletNo || `第${row.sequenceNo || '—'}托` }}</template></el-table-column>
|
||||
<el-table-column prop="cartonCount" label="箱数" width="65" />
|
||||
<el-table-column label="尺寸(cm)" min-width="130"><template #default="{ row }">{{ row.lengthCm ?? '—' }} × {{ row.widthCm ?? '—' }} × {{ row.heightCm ?? '—' }}</template></el-table-column>
|
||||
<el-table-column prop="grossWeightKg" label="毛重(kg)" width="95" />
|
||||
<el-table-column prop="volumeCbm" label="体积(m³)" width="95" />
|
||||
</el-table>
|
||||
<el-table :data="measurement.cartons?.filter(carton => carton.status === 'COUNTED') || []" max-height="220" size="small" border empty-text="暂无已签收箱子">
|
||||
<el-table-column prop="cartonMark" label="箱唛" min-width="200" />
|
||||
<el-table-column label="尺寸(cm)" min-width="180"><template #default="{ row }">{{ row.length ?? '—' }} × {{ row.width ?? '—' }} × {{ row.height ?? '—' }}</template></el-table-column>
|
||||
<el-table-column prop="weight" label="重量(kg)" width="110" />
|
||||
</el-table>
|
||||
</template>
|
||||
<p v-if="loading">正在读取作业照片…</p>
|
||||
<el-alert v-if="error" :title="error" type="error" :closable="false" />
|
||||
<el-button v-if="error" :disabled="loading || busy" @click="loadEvidence">重新读取</el-button>
|
||||
@@ -91,10 +122,10 @@ onBeforeUnmount(clear)
|
||||
<el-button v-else :disabled="busy" @click="loadPhoto(fileId)">{{ failed[fileId] ? '照片加载失败,点击重试' : '加载照片' }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-checkbox v-model="checked" :disabled="loading || busy || !!error || previewUrls.length !== fileIds.length">我已核对 PDA 作业照片,确认作业结果无误</el-checkbox>
|
||||
<el-checkbox v-model="checked" :disabled="loading || busy || !!error || previewUrls.length !== fileIds.length">{{ kind === 'transfer' ? '我已核对 PDA 实测数据及现场照片,确认无误' : '我已核对 PDA 作业照片,确认作业结果无误' }}</el-checkbox>
|
||||
<template #footer>
|
||||
<el-button :disabled="busy" @click="emit('update:modelValue', false)">取消</el-button>
|
||||
<el-button type="primary" :loading="busy" :disabled="!canConfirm" @click="submit">{{ kind === 'disposal' ? '确认废弃完结' : '确认贴标完成' }}</el-button>
|
||||
<el-button type="primary" :loading="busy" :disabled="!canConfirm" @click="submit">{{ kind === 'transfer' ? '确认数据' : kind === 'disposal' ? '确认废弃完结' : '确认贴标完成' }}</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user