fix(dispatch): submit and preserve independent loading groups
This commit is contained in:
@@ -10,7 +10,7 @@ import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||||
import AppDialog from '@/shared/components/AppDialog.vue'
|
||||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||||
import OperationErrorToast from '@/shared/components/OperationErrorToast.vue'
|
||||
import { createDispatchDraftContainer, deleteDispatchDraftContainer, listDispatchCandidates, listDispatchDrafts, lockDispatchDraftPallet, preArrangeDispatch, unlockDispatchDraftPallet, type DispatchPalletCandidateDto } from '../api/dispatches'
|
||||
import { createDispatchDraftContainer, deleteDispatchDraftContainer, listDispatchCandidates, listDispatchDrafts, lockDispatchDraftPallet, preArrangeDispatch, preArrangeDraftDispatch, unlockDispatchDraftPallet, type DispatchPalletCandidateDto } from '../api/dispatches'
|
||||
import { formatOverseasDateTime } from '../lastMilePresentation'
|
||||
import type { InboundOrderListItem } from '../types'
|
||||
import { dispatchVehicleSpecs } from '../dispatchVehicleSpecs'
|
||||
@@ -198,10 +198,12 @@ function reset() {
|
||||
}
|
||||
|
||||
function addContainer() {
|
||||
if (saving.value) return
|
||||
selectedVehicle.value = ''
|
||||
vehicleDialogOpen.value = true
|
||||
}
|
||||
async function confirmAddContainer() {
|
||||
if (saving.value) return
|
||||
const spec = selectedVehicleSpec.value
|
||||
if (!spec) {
|
||||
ElMessage.warning('请选择车型')
|
||||
@@ -224,6 +226,7 @@ async function confirmAddContainer() {
|
||||
|
||||
async function movePallet(item: DispatchPalletCandidateDto, containerId: string) {
|
||||
const id = palletId(item)
|
||||
if (saving.value || busyPalletIds.value.includes(id)) return
|
||||
const target = containers.value.find((container) => container.id === containerId)
|
||||
if (!target || target.palletIds.includes(id)) return
|
||||
if (!String(item.overseasWarehouseId || '').trim()) {
|
||||
@@ -267,6 +270,7 @@ async function movePallet(item: DispatchPalletCandidateDto, containerId: string)
|
||||
}
|
||||
|
||||
async function removePallet(id: string) {
|
||||
if (saving.value || busyPalletIds.value.includes(id)) return
|
||||
const owner = containerFor(id)
|
||||
if (!owner) return
|
||||
busyPalletIds.value.push(id)
|
||||
@@ -282,6 +286,7 @@ async function removePallet(id: string) {
|
||||
}
|
||||
|
||||
async function deleteContainer(container: LoadingContainer) {
|
||||
if (saving.value) return
|
||||
for (const id of [...container.palletIds]) {
|
||||
await removePallet(id)
|
||||
}
|
||||
@@ -300,10 +305,16 @@ function dropInto(event: DragEvent, containerId: string) {
|
||||
}
|
||||
|
||||
async function close(value = false) {
|
||||
if (saving.value) return
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (saving.value) return
|
||||
if (busyPalletIds.value.length) {
|
||||
ElMessage.warning('托盘来源正在锁定,请稍后再预排车')
|
||||
return
|
||||
}
|
||||
if (loading.value || unresolvedAssignedIds.value.length) {
|
||||
ElMessage.warning('草稿中部分已选来源尚未恢复,请重试加载后再预排;原选择已保留')
|
||||
return
|
||||
@@ -312,6 +323,18 @@ async function submit() {
|
||||
ElMessage.warning('请至少移入一个托盘')
|
||||
return
|
||||
}
|
||||
const selectedContainers = containers.value.filter(container => container.palletIds.length > 0)
|
||||
if (new Set(assignedIds.value).size !== assignedIds.value.length
|
||||
|| selectedContainers.some(container => !container.id.trim())
|
||||
|| new Set(selectedContainers.map(container => container.id)).size !== selectedContainers.length) {
|
||||
ElMessage.warning('草稿中存在重复托盘或无效装车容器,请核对分组;原草稿已保留')
|
||||
return
|
||||
}
|
||||
if (assigned.value.some(item => item.sourceType === 'RETURN_RECEIPT'
|
||||
? !String(item.returnReceiptId || '').trim() : !String(item.planPalletId || '').trim())) {
|
||||
ElMessage.warning('所选托盘来源标识缺失,请重新加载核对;原草稿已保留')
|
||||
return
|
||||
}
|
||||
if (assigned.value.some((item) => !String(item.overseasWarehouseId || '').trim())) {
|
||||
ElMessage.warning('所选托盘中存在尚未关联海外仓的托盘')
|
||||
return
|
||||
@@ -326,14 +349,39 @@ async function submit() {
|
||||
ElMessage.warning('一张换标单的托盘需要单独排车')
|
||||
return
|
||||
}
|
||||
if (relabelOrders.length && selectedContainers.length !== 1) {
|
||||
ElMessage.warning('一张换标单仅支持一组排车,请将全部托盘移入同一个装车容器')
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
mutationError.value = null
|
||||
try {
|
||||
await preArrangeDispatch({
|
||||
planPalletIds: assigned.value.filter(item => item.sourceType !== 'RETURN_RECEIPT').map(palletId),
|
||||
returnReceiptIds: assigned.value.filter(item => item.sourceType === 'RETURN_RECEIPT').map(item => String(item.returnReceiptId)),
|
||||
...(relabelOrders.length ? { relabelNo: relabelOrders[0] } : { draftToken: ensureDraftToken() }),
|
||||
})
|
||||
if (relabelOrders.length) {
|
||||
await preArrangeDispatch({
|
||||
planPalletIds: assigned.value.filter(item => item.sourceType !== 'RETURN_RECEIPT').map(palletId),
|
||||
returnReceiptIds: assigned.value.filter(item => item.sourceType === 'RETURN_RECEIPT').map(item => String(item.returnReceiptId)),
|
||||
relabelNo: relabelOrders[0],
|
||||
})
|
||||
} else {
|
||||
const groups = selectedContainers.map(container => {
|
||||
const sources = container.palletIds.map(id => palletSnapshot(id)!)
|
||||
return {
|
||||
draftContainerId: container.id,
|
||||
planPalletIds: sources.filter(item => item.sourceType !== 'RETURN_RECEIPT').map(item => String(item.planPalletId)),
|
||||
returnReceiptIds: sources.filter(item => item.sourceType === 'RETURN_RECEIPT').map(item => String(item.returnReceiptId)),
|
||||
}
|
||||
})
|
||||
const results = await preArrangeDraftDispatch({ draftToken: ensureDraftToken(), groups })
|
||||
const expectedIds = new Set(groups.map(group => group.draftContainerId))
|
||||
if (!Array.isArray(results) || results.length !== groups.length
|
||||
|| results.some(result => !result || typeof result.draftContainerId !== 'string'
|
||||
|| typeof result.dispatch?.dispatchNo !== 'string' || !result.dispatch.dispatchNo.trim())
|
||||
|| new Set(results.map(result => result.draftContainerId)).size !== groups.length
|
||||
|| results.some(result => !expectedIds.has(result.draftContainerId))
|
||||
|| new Set(results.map(result => result.dispatch.dispatchNo)).size !== groups.length) {
|
||||
throw new Error('预排车返回的分组结果与原草稿不一致,原草稿已保留,请核对保存结果')
|
||||
}
|
||||
}
|
||||
emit('update:modelValue', false)
|
||||
emit('created')
|
||||
ElMessage.success('排车明细已同步到预排列表')
|
||||
@@ -541,14 +589,14 @@ watch([warehouseTab, () => query.orderType], () => {
|
||||
><span
|
||||
>托数 <b>{{ container.palletIds.length }}</b
|
||||
>/{{ container.capacity }} · 重量 <b>{{ formatWeightLb(containerWeightLb(container)) }}</b>/{{ container.maxWeightLb }}LB <em v-if="containerOverweight(container)">超限10%</em></span
|
||||
><el-button class="density-action" data-tone="danger" :aria-label="`删除装车车型${index + 1}`" @click="deleteContainer(container)">删除</el-button>
|
||||
><el-button class="density-action" data-tone="danger" :disabled="saving" :aria-label="`删除装车车型${index + 1}`" @click="deleteContainer(container)">删除</el-button>
|
||||
</div>
|
||||
<div class="container-body">
|
||||
<div v-for="id in container.palletIds" :key="id" class="loaded-pallet">
|
||||
<span
|
||||
><strong>{{ text(palletSnapshot(id)?.palletNo || '托盘号待补充') }}</strong
|
||||
><OrderReferenceText :value="text(palletSnapshot(id)?.orderNo)" /></span
|
||||
><el-button class="density-action" data-tone="danger" :loading="busyPalletIds.includes(id)" @click="removePallet(id)">移除</el-button>
|
||||
><el-button class="density-action" data-tone="danger" :disabled="saving" :loading="busyPalletIds.includes(id)" @click="removePallet(id)">移除</el-button>
|
||||
</div>
|
||||
<span v-if="!container.palletIds.length" class="drop-hint">拖入托盘,移入后立即锁定</span>
|
||||
</div>
|
||||
@@ -560,7 +608,7 @@ watch([warehouseTab, () => query.orderType], () => {
|
||||
|
||||
<template #footer><footer class="dialog-footer">
|
||||
<span>托盘移入即锁定,重量按 1kg = 2.2046lb 换算。</span>
|
||||
<div><el-button :disabled="saving" @click="close(false)">取消</el-button><el-button type="primary" :loading="saving" :disabled="!assignedIds.length" @click="submit">预排车</el-button></div>
|
||||
<div><el-button :disabled="saving" @click="close(false)">取消</el-button><el-button type="primary" :loading="saving" :disabled="!assignedIds.length || busyPalletIds.length > 0" @click="submit">预排车</el-button></div>
|
||||
</footer></template>
|
||||
</AppDialog>
|
||||
<el-dialog class="admin-density-dialog" v-model="vehicleDialogOpen" title="选择车型" width="360px" append-to-body>
|
||||
|
||||
Reference in New Issue
Block a user