51 lines
4.3 KiB
Vue
51 lines
4.3 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||
import { getDispatch, type DispatchSummaryDto } from '@/modules/overseas-warehouse'
|
||
import { TripPreparationDialog } from '@/modules/overseas-master-data'
|
||
import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
|
||
import LoadErrorState from '@/shared/components/LoadErrorState.vue'
|
||
import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'
|
||
import { useWorkDraft } from './useWorkDraft'
|
||
const props = defineProps<{ dispatchNo: string; canWrite: boolean }>()
|
||
const emit = defineEmits<{ updated: []; busy: [value: boolean]; external: [path: string] }>()
|
||
const access = useAccessPreviewStore(), otherNo = ref(''), rows = ref<DispatchSummaryDto[]>([])
|
||
const loading = ref(false), error = ref<ApiErrorDetails | null>(null), prepareOpen = ref(false)
|
||
const allowed = computed(() => props.canWrite && ['platform:overseas-warehouse:dispatch:list', 'platform:fleet:trip:list', 'platform:fleet:trip:edit'].every(permission => access.can(permission)))
|
||
watch(prepareOpen, value => emit('busy', value))
|
||
useWorkDraft(computed(() => false), prepareOpen)
|
||
let generation = 0
|
||
function changed() { ++generation; loading.value = false; rows.value = []; error.value = null }
|
||
async function prepare() {
|
||
if (!allowed.value || loading.value || prepareOpen.value) return
|
||
rows.value = []; error.value = null
|
||
const other = otherNo.value.trim()
|
||
if (!other || other === props.dispatchNo) { error.value = { message: '请填写另一张已备好的排车单业务号,不能重复选择本单。' }; return }
|
||
const current = ++generation; loading.value = true
|
||
try {
|
||
const numbers = [props.dispatchNo, other]
|
||
const details = await Promise.all(numbers.map(getDispatch))
|
||
if (current !== generation) return
|
||
if (details.some((row, index) => row.dispatchNo !== numbers[index])) throw new Error('返回的排车单与所选业务号不一致,请重新核对。')
|
||
if (details.some(row => row.status !== 'PENDING_DEPARTURE' || row.workflow)) throw new Error('请选择尚未关联车次的待发运排车单;已关联的货物请从原车次继续处理。')
|
||
if (!details[0]!.overseasWarehouseId || details.some(row => row.overseasWarehouseId !== details[0]!.overseasWarehouseId)) throw new Error('两张排车单必须有明确且相同的起运仓。')
|
||
rows.value = details; prepareOpen.value = true
|
||
} catch (cause) { if (current === generation) error.value = getApiErrorDetails(cause, '共车排车单核对失败') }
|
||
finally { if (current === generation) loading.value = false }
|
||
}
|
||
function saved(value: { trip: { tripNo: string } }) { prepareOpen.value = false; emit('updated'); emit('external', `/overseas-master-data/trips/${encodeURIComponent(value.trip.tripNo)}`) }
|
||
onBeforeUnmount(() => { ++generation; emit('busy', false) })
|
||
</script>
|
||
<template>
|
||
<section class="work-form" aria-label="与同仓其他排车单共车">
|
||
<h4>与同仓其他排车单共车</h4>
|
||
<p>本批排车单:{{ dispatchNo }}。请先按各客户实际托盘分别备好排车单,再核对同仓两单并安排同一车次。</p>
|
||
<p>所需箱数无法对应完整实物时,请先在原库存作业中完成拆托,再返回核对;分批计划不会代替实物拆托。</p>
|
||
<label>另一张排车单号<input v-model="otherNo" aria-label="共车排车单号" maxlength="64" :disabled="loading || prepareOpen || !allowed" @input="changed" @keydown.enter.prevent="prepare"></label>
|
||
<el-button :disabled="!allowed || prepareOpen" :loading="loading" @click="prepare">核对两单并安排共车</el-button>
|
||
<LoadErrorState v-if="error" title="共车排车单核对失败" :message="error.message" :show-retry="false"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||
<p v-for="row in rows" :key="row.dispatchNo">{{ row.dispatchNo }} · {{ row.overseasWarehouseName || '起运仓名称待核实' }} · {{ row.packageCount ?? '箱数待核实' }}<span v-if="row.packageCount != null"> 箱</span></p>
|
||
<TripPreparationDialog v-if="rows[0]?.overseasWarehouseId" v-model="prepareOpen" :warehouse-id="rows[0].overseasWarehouseId" :warehouse-name="rows[0].overseasWarehouseName || '起运仓名称待核实'" :dispatch-nos="rows.map(row => row.dispatchNo)" @saved="saved" />
|
||
</section>
|
||
</template>
|