fix: keep container fee entries visible

This commit is contained in:
2026-09-08 23:23:47 +08:00
parent 43604b951d
commit 5068c13c37
2 changed files with 22 additions and 9 deletions
@@ -58,13 +58,15 @@ describe('ContainerDetailView customs integration', () => {
it('separates domestic first-leg fees and connects the overseas fee lifecycle lazily', () => {
expect(source).toContain('label="头程计费" name="first-leg-fees"')
expect(source).toContain('label="尾程计费" name="last-leg-fees"')
expect(source).toContain('v-if="isDomestic && firstLegFeesOpened"')
expect(source).toContain('<el-tab-pane label="头程计费" name="first-leg-fees" />')
expect(source).toContain('<el-tab-pane label="尾程计费" name="last-leg-fees" />')
expect(source).toContain('v-if="firstLegFeesOpened"')
expect(source).toContain('v-show="activeTab === \'first-leg-fees\'"')
expect(source).toContain('title="头程计费" :plan-id="overview.loadingPlanId" :container-booking-id="detail.id"')
expect(source).toContain('v-if="isOverseas && lastLegFeesOpened"')
expect(source).toContain('v-if="lastLegFeesOpened"')
expect(source).toContain('<ContainerLastLegFeesPanel :container-booking-id="detail.id" :container-no="detail.containerNo" />')
expect(source).toContain("if (isDomestic.value && activeTab.value === 'loading-list') await loadLoadingDetail(resource, aggregate)")
expect(source).toContain("tabName === 'loading-list' || tabName === 'first-leg-fees'")
expect(source).toContain("const needsLoadingDetail = tabName === 'first-leg-fees' || (isDomestic.value && tabName === 'loading-list')")
expect(lastLegFeesSource.indexOf('label="操作"')).toBeLessThan(lastLegFeesSource.indexOf('label="客户"'))
expect(lastLegFeesSource).toContain('show-overflow-tooltip')
expect(lastLegFeesSource).toContain('尾程计费加载失败')
@@ -76,6 +78,9 @@ describe('ContainerDetailView customs integration', () => {
expect(lastLegFeesSource).toContain('uploadContainerFeePaymentVoucher(form.customerId, file.raw)')
expect(lastLegFeesSource).toContain("access.can('platform:finance:fee-source:edit')")
expect(lastLegFeesSource).toContain("access.can('platform:finance:fee-source:review')")
expect(source).toContain("if (!overview.value?.loadingPlanId) return '当前货柜尚未关联装柜计划,暂无头程计费归属。'")
expect(source).toContain(':description="firstLegFeesEmptyReason"')
expect(source).toContain("const needsLoadingDetail = tabName === 'first-leg-fees' || (isDomestic.value && tabName === 'loading-list')")
})
it('mounts the new container customs panel only after loading completes', () => {
@@ -56,10 +56,18 @@ const feeBusinessReferences = computed(() => (loadingDetail.value?.items || []).
accountId: item.accountId, customerName: item.customerName, orderId: item.orderId, orderNo: item.orderNo,
inboundId: item.inboundId, inboundCode: item.inboundCode,
})))
const firstLegFeesEmptyReason = computed(() => {
if (!overview.value?.loadingPlanId) return '当前货柜尚未关联装柜计划,暂无头程计费归属。'
if (!detail.value?.warehouseId) return '当前货柜尚未关联装柜仓库,无法加载头程计费归属。'
if (detail.value.planStatus === 'COMPLETED' && !canViewLoadingList.value) return '当前账号无权读取已确认装柜清单,无法查看头程计费。'
if (detail.value.planStatus !== 'COMPLETED' && !canViewPreload.value) return '当前账号无权读取预装计划,无法查看头程计费。'
return '当前柜次暂无可用费用归属明细。'
})
async function rememberWorkbenchTab(tabName: string | number) {
if (tabName === 'first-leg-fees') firstLegFeesOpened.value = true
if (tabName === 'last-leg-fees') lastLegFeesOpened.value = true
if (isDomestic.value && (tabName === 'loading-list' || tabName === 'first-leg-fees') && detail.value && overview.value) {
const needsLoadingDetail = tabName === 'first-leg-fees' || (isDomestic.value && tabName === 'loading-list')
if (needsLoadingDetail && detail.value && overview.value) {
await loadLoadingDetail(detail.value, overview.value)
}
}
@@ -210,7 +218,7 @@ async function loadOutboundDispatch() {
async function loadLoadingDetail(resource: ContainerBookingResource, aggregate: ContainerOverview) {
if (loadingDetail.value || loadingDetailLoading.value) return
loadingDetail.value = null; loadingDetailError.value = null
if (!isDomestic.value || !aggregate.loadingPlanId || !resource.warehouseId) return
if (!aggregate.loadingPlanId || !resource.warehouseId) return
loadingDetailLoading.value = true
try {
if (resource.planStatus === 'COMPLETED') {
@@ -407,7 +415,7 @@ onMounted(async () => { await load(); if (isOverseas.value && route.query.action
</section>
<LoadErrorState v-if="error" title="货柜详情加载失败" :message="error.message" :loading="loading" @retry="load"><template #details><ApiErrorMeta :details="error" /></template></LoadErrorState>
<template v-else-if="detail">
<el-tabs v-model="activeTab" class="workbench-tabs" @tab-change="rememberWorkbenchTab"><el-tab-pane :label="isDomestic ? '送柜报关' : '清关提柜'" name="overview" /><el-tab-pane v-if="isDomestic && detail.planStatus === 'COMPLETED' && canViewLoadingList" label="装柜清单" name="loading-list" /><el-tab-pane v-if="isDomestic && overview?.loadingPlanId" label="头程计费" name="first-leg-fees" /><el-tab-pane v-if="isOverseas" label="尾程计费" name="last-leg-fees" /></el-tabs>
<el-tabs v-model="activeTab" class="workbench-tabs" @tab-change="rememberWorkbenchTab"><el-tab-pane :label="isDomestic ? '送柜报关' : '清关提柜'" name="overview" /><el-tab-pane v-if="isDomestic && detail.planStatus === 'COMPLETED' && canViewLoadingList" label="装柜清单" name="loading-list" /><el-tab-pane label="头程计费" name="first-leg-fees" /><el-tab-pane label="尾程计费" name="last-leg-fees" /></el-tabs>
<LoadErrorState v-if="overviewError" compact title="履约摘要加载失败" :message="overviewError.message" :show-retry="false" />
<section v-show="activeTab === 'overview'" class="detail-section surface-panel" aria-labelledby="container-information-heading">
<h2 id="container-information-heading">货柜信息</h2>
@@ -461,13 +469,13 @@ onMounted(async () => { await load(); if (isOverseas.value && route.query.action
<LoadingListDetailDrawer mode="confirmed" :loading="loadingDetailLoading" :detail="loadingDetail" :error="loadingDetailError" :can-edit="false" @back="activeTab = 'overview'" @retry="overview && loadLoadingDetail(detail, overview)" />
</section>
<section v-if="isDomestic && firstLegFeesOpened" v-show="activeTab === 'first-leg-fees'" v-loading="loadingDetailLoading" class="detail-section surface-panel" aria-label="头程计费">
<section v-if="firstLegFeesOpened" v-show="activeTab === 'first-leg-fees'" v-loading="loadingDetailLoading" class="detail-section surface-panel" aria-label="头程计费">
<LoadErrorState v-if="loadingDetailError" compact title="头程计费归属明细加载失败" :message="loadingDetailError.message" :loading="loadingDetailLoading" @retry="overview && loadLoadingDetail(detail, overview)"><template #details><ApiErrorMeta :details="loadingDetailError" /></template></LoadErrorState>
<ContainerFeesPanel v-else-if="overview?.loadingPlanId && loadingDetail" title="头程计费" :plan-id="overview.loadingPlanId" :container-booking-id="detail.id" :customers="feeCustomers" :business-references="feeBusinessReferences" />
<el-empty v-else-if="!loadingDetailLoading" description="当前柜次暂无可用装柜计划或费用归属明细" :image-size="72" />
<el-empty v-else-if="!loadingDetailLoading" :description="firstLegFeesEmptyReason" :image-size="72" />
</section>
<section v-if="isOverseas && lastLegFeesOpened" v-show="activeTab === 'last-leg-fees'" class="detail-section surface-panel" aria-label="尾程计费">
<section v-if="lastLegFeesOpened" v-show="activeTab === 'last-leg-fees'" class="detail-section surface-panel" aria-label="尾程计费">
<ContainerLastLegFeesPanel :container-booking-id="detail.id" :container-no="detail.containerNo" />
</section>
</template>