51 lines
4.2 KiB
Vue
51 lines
4.2 KiB
Vue
<script setup lang="ts">
|
||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||
import { useAuthStore } from '@/core/auth/auth'
|
||
import { DispatchWorkflowDialog, DispatchInputError, getDispatch, useDispatchCommandRecovery, type DispatchDetail } from '@/modules/overseas-warehouse'
|
||
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(), auth = useAuthStore(), recovery = useDispatchCommandRecovery(() => auth.user?.id || '')
|
||
const detail = ref<DispatchDetail | null>(null), open = ref(false), loading = ref(false), error = ref<ApiErrorDetails | null>(null)
|
||
const rejectionError = ref<ApiErrorDetails | null>(null)
|
||
const readable = computed(() => access.can('platform:overseas-warehouse:dispatch:list'))
|
||
const allowed = computed(() => props.canWrite && readable.value && access.can('platform:overseas-warehouse:dispatch:edit') && detail.value?.status === 'ACTIVE' && detail.value.stage === 'BEFORE_LOADING' && detail.value.actions.ADD_CARGO?.allowed === true)
|
||
const busy = computed(() => loading.value || open.value || Boolean(recovery.pending.value))
|
||
watch(busy, value => emit('busy', value), { immediate: true })
|
||
useWorkDraft(computed(() => false), busy)
|
||
let generation = 0
|
||
async function load() {
|
||
const current = ++generation; detail.value = null; error.value = null
|
||
if (!readable.value) return
|
||
loading.value = true
|
||
try {
|
||
const value = await getDispatch(props.dispatchNo)
|
||
if (current !== generation) return
|
||
if (value.dispatchNo !== props.dispatchNo) throw new DispatchInputError('读取结果与原排车单不一致,请重新核对')
|
||
detail.value = value
|
||
} catch (cause) { if (current === generation) error.value = getApiErrorDetails(cause, cause instanceof DispatchInputError ? cause.message : '本车加货资格读取失败') }
|
||
finally { if (current === generation) loading.value = false }
|
||
}
|
||
function prepare() { if (allowed.value && !loading.value && !recovery.pending.value) { rejectionError.value = null; open.value = true } }
|
||
function saved() { open.value = false; rejectionError.value = null; emit('updated'); void load() }
|
||
function rejected(details: ApiErrorDetails) { rejectionError.value = details; emit('updated'); void load() }
|
||
watch(() => props.dispatchNo, load, { immediate: true })
|
||
onBeforeUnmount(() => { generation++; emit('busy', false) })
|
||
</script>
|
||
<template>
|
||
<section class="work-form" aria-label="为原排车添加同仓货物">
|
||
<h4>为原排车添加同仓货物</h4><p>本车 {{ dispatchNo }}。只选择尚未安排的真实货物加入本车,不合并另一张排车单或搬迁已扫码货物。</p>
|
||
<p>箱数无法对应完整实物时,先在原库存作业完成拆托;预约分批不代替实物拆托。</p>
|
||
<LoadErrorState v-if="error" title="本车加货资格读取失败" :message="error.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
|
||
<LoadErrorState v-if="rejectionError" title="本车加货未完成" :message="rejectionError.message" :show-retry="false"><template #details><ApiErrorMeta :details="rejectionError" /></template></LoadErrorState>
|
||
<p v-if="detail">{{ detail.vehicleInfo.vehicle?.plate || '车辆待维护' }} · {{ detail.counts.packageCount }} 箱</p>
|
||
<p v-if="detail && !allowed">{{ detail.actions.ADD_CARGO?.blockReason || '当前阶段或权限不允许加货,请从原排车单继续作业。' }}</p>
|
||
<el-button :disabled="!allowed || busy" :loading="loading" @click="prepare">选择同仓未安排货物</el-button><el-button v-if="readable" :disabled="busy" @click="emit('external', `/overseas-warehouse/dispatches/${encodeURIComponent(dispatchNo)}`)">查看原排车单</el-button>
|
||
<DispatchWorkflowDialog v-model="open" :dispatch-no="dispatchNo" action="ADD_CARGO" @saved="saved" @rejected="rejected" />
|
||
</section>
|
||
</template>
|