Release/test #10

Merged
admin merged 40 commits from release/test into main 2026-09-28 15:59:06 +08:00
2 changed files with 56 additions and 0 deletions
Showing only changes of commit 8c8fdbc2ab - Show all commits
+25
View File
@@ -58,6 +58,24 @@ export interface MerchantCustomsContainer {
completedAt?: string | null
}
export type MerchantClearanceResultType = 'INSPECTION' | 'SUPPLEMENT_REQUIRED' | 'RELEASED' | 'DETAINED' | 'OTHER'
export type MerchantClearanceResultStatus = 'OPEN' | 'RESOLVED' | 'CANCELLED'
export interface MerchantClearanceResult {
id: string
declarationBatchId: string
customsContainerId: string
resultType: MerchantClearanceResultType
resultStatus: MerchantClearanceResultStatus
customsEntryNo: string | null
occurredAt: string
resolution: string | null
evidenceFileId: string | null
recordedByName: string
recordedAt: string
previousResultId: string | null
}
export interface ApiErrorMeta {
code: string
requestId: string | null
@@ -105,6 +123,13 @@ export function getMerchantCustomsForOrder(orderId: string) {
})
}
export function getMerchantClearanceResults(orderId: string) {
return apiRequest<MerchantClearanceResult[]>({
method: 'GET',
url: `/merchant/v1/customs/orders/${encodedId(orderId)}/clearance-results`,
})
}
export function uploadMerchantCustomsDocument(planId: string, inboundIds: string[], file: File) {
validateMerchantCustomsFile(file)
return apiRequest<MerchantCustomsDocument>({
@@ -10,6 +10,7 @@ import {
downloadMerchantCustomsFinal,
downloadMerchantCustomsSource,
getMerchantCustomsForOrder,
getMerchantClearanceResults,
merchantCustomsErrorMessage,
replaceMerchantCustomsDocument,
rejectMerchantCustomsReceipt,
@@ -18,6 +19,7 @@ import {
validateMerchantCustomsFile,
type MerchantCustomsContainer,
type MerchantCustomsDocument,
type MerchantClearanceResult,
} from '@/modules/first-leg/api/customs'
const props = defineProps<{
@@ -43,6 +45,7 @@ const uploadInput = ref<HTMLInputElement>()
const replaceInput = ref<HTMLInputElement>()
const mutating = ref(false)
const downloadingKey = ref('')
const clearanceResults = ref<MerchantClearanceResult[]>([])
const taxRefundInbounds = computed(() => detail.value?.inbounds.filter((item) => item.taxMode === 'TAX_REFUND') ?? [])
const locked = computed(() => Boolean(detail.value?.startedAt) || detail.value?.status === 'DECLARING' || detail.value?.status === 'COMPLETED')
@@ -71,6 +74,7 @@ async function loadDetail() {
const result = await getMerchantCustomsForOrder(props.orderId)
detail.value = result
initializeSelection(result)
try { clearanceResults.value = await getMerchantClearanceResults(props.orderId) } catch { clearanceResults.value = [] }
emit('updated', result)
} catch (error) {
detail.value = null
@@ -247,6 +251,14 @@ function formatSize(bytes: number) {
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
return `${(bytes / 1024 / 1024).toFixed(1)} MB`
}
function clearanceResultLabel(value: MerchantClearanceResult) {
return ({ INSPECTION: '查验', SUPPLEMENT_REQUIRED: '补充资料', RELEASED: '放行', DETAINED: '扣留', OTHER: '其他' } as Record<string, string>)[value.resultType] || value.resultType
}
function clearanceResultStatusLabel(value: MerchantClearanceResult) {
return value.resultStatus === 'RESOLVED' ? '已处理' : value.resultStatus === 'CANCELLED' ? '已取消' : '待处理'
}
</script>
<template>
@@ -302,6 +314,20 @@ function formatSize(bytes: number) {
<input ref="replaceInput" class="customs-hidden-input" type="file" @change="handleReplacementFile">
</section>
<section class="customs-section clearance-results-section">
<div class="customs-section-title">
<div><h3>海关申报结果</h3><p>平台完成正式申报后,客户可查看与本订单相关的查验、补充资料和放行结果。</p></div>
</div>
<el-empty v-if="!clearanceResults.length" description="暂无海关结果" :image-size="48" />
<div v-else class="clearance-result-list">
<div v-for="item in clearanceResults" :key="item.id" class="clearance-result-row">
<div><strong>{{ clearanceResultLabel(item) }}</strong><span>{{ formatDateTime(item.occurredAt) }} · 报关单号 {{ item.customsEntryNo || '—' }}</span></div>
<el-tag size="small" :type="item.resultStatus === 'RESOLVED' ? 'success' : 'warning'">{{ clearanceResultStatusLabel(item) }}</el-tag>
<p v-if="item.resolution">{{ item.resolution }}</p>
</div>
</div>
</section>
<section class="customs-section">
<div class="customs-section-title">
<div><h3>资料版本历史</h3><p>每份当前资料展示服务端版本、关联票和上传时间;覆盖及删除操作由服务端保留不可变历史。</p></div>
@@ -358,6 +384,11 @@ function formatSize(bytes: number) {
.customs-locked strong { color: var(--navy); font-size: 12px; }
.customs-locked span { margin-top: 3px; font-size: 11px; }
.customs-section { margin-top: 18px; }
.clearance-result-list { display:grid; gap:10px; }
.clearance-result-row { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:6px 14px; padding:12px 14px; border:1px solid var(--border); background:#fbfcfe; }
.clearance-result-row strong,.clearance-result-row span { display:block; }
.clearance-result-row span { margin-top:4px; color:var(--muted); font-size:11px; }
.clearance-result-row p { grid-column:1 / -1; margin:0; color:var(--navy); font-size:12px; }
.customs-section-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 12px; }
.customs-section-title h3 { margin: 0; color: var(--navy); font-size: 14px; }
.customs-section-title p { margin: 5px 0 0; color: var(--muted); font-size: 11px; line-height: 1.55; }