This commit is contained in:
2026-08-28 09:19:24 +08:00
parent 44d05e77cb
commit 4687f17d09
2 changed files with 81 additions and 5 deletions
@@ -47,6 +47,7 @@ const documentOpen = ref(false)
type UploadDocumentType = 'DELIVERY_ORDER' | 'PICKUP_ORDER' | 'CUSTOMS_DECLARATION'
const documentType = ref<UploadDocumentType>('DELIVERY_ORDER')
const documentFile = ref<File | null>(null)
const documentUploadKey = ref(0)
const documentSaving = ref(false)
const documentDownloading = ref(false)
const documentError = ref<ApiErrorDetails | null>(null)
@@ -194,7 +195,7 @@ function openDocument(type: string) {
if (!['DELIVERY_ORDER', 'PICKUP_ORDER', 'CUSTOMS_DECLARATION'].includes(type)) return
if (type === 'CUSTOMS_DECLARATION' ? !canManageCustoms.value : !canEdit.value) return
documentType.value = type as UploadDocumentType
documentFile.value = null; documentError.value = null; documentOpen.value = true
documentFile.value = null; documentError.value = null; documentRefreshWarning.value = null; documentUploadKey.value += 1; documentOpen.value = true
if (type === 'CUSTOMS_DECLARATION' && !overview.value?.loadingPlanId) {
documentError.value = { code: 'LOADING_PLAN_REQUIRED', message: '当前货柜没有装柜清单,无法上传国内出口报关附件' }
}
@@ -222,10 +223,26 @@ async function saveDocument() {
}
catch (cause) { documentRefreshWarning.value = getApiErrorDetails(cause, '附件已上传,但最新资料刷新失败;当前已保留本次上传结果') }
} else {
await uploadContainerDocument(containerId.value, documentType.value, documentFile.value, expectedVersion, `上传${documentTitle.value}`)
overview.value = await getContainerOverview(containerId.value)
const targetType = documentType.value
const targetTitle = documentTitle.value
const uploaded = await uploadContainerDocument(containerId.value, targetType, documentFile.value, expectedVersion, `上传${targetTitle}`)
if (!uploaded) throw new Error(`${targetTitle}上传成功但未返回附件信息`)
const optimistic = toOverviewDocument(uploaded, targetType, selectedDocument.value)
replaceOverviewDocument(optimistic)
documentOpen.value = false; documentFile.value = null; documentError.value = null; documentUploadKey.value += 1
ElMessage.success(`${targetTitle}已上传`)
try {
const refreshed = await getContainerOverview(containerId.value)
const current = refreshed.documents.find((item) => item.documentType === targetType)
if (current && (current.fileId === optimistic.fileId || current.version > optimistic.version)) overview.value = refreshed
else {
overview.value = { ...refreshed, documents: [...refreshed.documents.filter((item) => item.documentType !== targetType), optimistic] }
documentRefreshWarning.value = { code: 'DOCUMENT_OVERVIEW_STALE', message: `${targetTitle}已上传,但资料汇总尚未同步;当前已保留本次上传结果` }
}
} catch (cause) { documentRefreshWarning.value = getApiErrorDetails(cause, `${targetTitle}已上传,但最新资料刷新失败;当前已保留本次上传结果`) }
return
}
documentOpen.value = false; documentFile.value = null; ElMessage.success(`${documentTitle.value}已上传`)
documentOpen.value = false; documentFile.value = null; documentUploadKey.value += 1; ElMessage.success(`${documentTitle.value}已上传`)
} catch (cause) {
const details = getApiErrorDetails(cause, `${documentTitle.value}上传失败`)
if (details.code === 'A0409') {
@@ -388,7 +405,7 @@ onMounted(async () => { await load(); if (route.query.action === 'documents') op
<div class="surface-panel carrier-panel"><CarrierScheduleQueryPanel :key="carrierRefreshKey" :ocean-booking-id="detail.oceanBookingId" :container-booking-id="detail.id" :warehouse-timeline="overview?.timeline || []" /></div>
</template>
<AppDialog v-model="documentOpen" :title="documentTitle" width="min(520px, calc(100vw - 28px))" confirm-text="上传资料" :confirm-loading="documentSaving" :confirm-disabled="!documentFile" @confirm="saveDocument"><el-form label-position="top"><el-form-item :label="documentTitle"><el-upload :auto-upload="false" :limit="1" :on-change="selectDocumentFile" :on-remove="removeDocumentFile"><el-button><FileUp :size="16" />选择文件</el-button><template #tip><div class="el-upload__tip">{{ selectedDocument ? '上传新文件将替换当前资料并保留历史。' : `请选择需要提交的${documentTitle}。` }}</div></template></el-upload></el-form-item></el-form><LoadErrorState v-if="documentError" compact title="资料上传失败" :message="documentError.message" :show-retry="false"><template #details><ApiErrorMeta :details="documentError" /></template></LoadErrorState></AppDialog>
<AppDialog v-model="documentOpen" :title="documentTitle" width="min(520px, calc(100vw - 28px))" confirm-text="上传资料" :confirm-loading="documentSaving" :confirm-disabled="!documentFile" @confirm="saveDocument"><el-form label-position="top"><el-form-item :label="documentTitle"><el-upload :key="documentUploadKey" :auto-upload="false" :limit="1" :on-change="selectDocumentFile" :on-remove="removeDocumentFile"><el-button><FileUp :size="16" />选择文件</el-button><template #tip><div class="el-upload__tip">{{ selectedDocument ? '上传新文件将替换当前资料并保留历史。' : `请选择需要提交的${documentTitle}。` }}</div></template></el-upload></el-form-item></el-form><LoadErrorState v-if="documentError" compact title="资料上传失败" :message="documentError.message" :show-retry="false"><template #details><ApiErrorMeta :details="documentError" /></template></LoadErrorState></AppDialog>
<AppDialog v-model="exceptionOpen" :title="exceptionTitle" width="min(520px, calc(100vw - 28px))" :confirm-text="overview?.exception.active ? '确认取消' : '确认标记'" :confirm-loading="exceptionSaving" :confirm-disabled="!exceptionReason.trim()" @confirm="saveException"><el-alert :title="overview?.exception.active ? '取消备注为必填项,提交后将保留历史记录。' : '异常原因将同步记录在货柜详情和操作日志中。'" :type="overview?.exception.active ? 'warning' : 'error'" :closable="false" /><el-form label-position="top"><el-form-item :label="overview?.exception.active ? '取消备注' : '异常原因'" required><el-input v-model="exceptionReason" type="textarea" :rows="4" maxlength="500" show-word-limit /></el-form-item></el-form><LoadErrorState v-if="exceptionError" compact title="异常处理失败" :message="exceptionError.message" :show-retry="false" /></AppDialog>
<AppDialog v-model="clearanceOpen" title="目的港清关资料" width="min(520px, calc(100vw - 28px))" :loading="clearanceLoading" :show-confirm="!clearanceDocument?.completedAt" confirm-text="上传资料" :confirm-loading="clearanceSaving" :confirm-disabled="!clearanceFile" @confirm="uploadClearance"><el-alert v-if="clearanceDocument?.completedAt" type="success" :closable="false" :title="`目的港清关已完成:${clearanceDocument.fileName}`" /><template v-else><el-form label-position="top"><el-form-item label="目的港清关资料"><el-upload :auto-upload="false" :limit="1" :on-change="selectClearanceFile" :on-remove="removeClearanceFile"><el-button><FileUp :size="16" />选择文件</el-button></el-upload></el-form-item></el-form><el-button v-if="clearanceDocument" type="success" plain :loading="clearanceSaving" @click="completeClearance">确认目的港清关完成</el-button></template><LoadErrorState v-if="clearanceError" compact title="目的港清关资料操作失败" :message="clearanceError.message" :show-retry="false"><template #details><ApiErrorMeta :details="clearanceError" /></template></LoadErrorState></AppDialog>
</AdminPage>