From 6551b703cba01e9732e8a603301c1df64e3a8a26 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Thu, 8 Oct 2026 14:11:54 +0800 Subject: [PATCH] fix(fleet): align capacity availability and dispatch review navigation --- .../capacityOfferTypes.ts | 2 +- .../CapacityOfferSettingsDialog.vue | 2 +- .../pages/CapacityOfferDetailView.vue | 8 +- .../pages/CapacityOffersBehavior.test.ts | 23 +++++- .../pages/CapacityOffersView.vue | 21 ++++-- .../pages/TripDetailView.vue | 3 +- .../pages/TripsBehavior.test.ts | 14 +++- .../overseas-warehouse/api/dispatches.ts | 5 ++ .../pages/DispatchesView.test.ts | 46 ++++++++++++ .../pages/DispatchesView.vue | 75 ++++++++++++++++++- src/modules/overseas-warehouse/types.ts | 1 + src/styles/adminDensity.test.ts | 3 +- 12 files changed, 184 insertions(+), 19 deletions(-) diff --git a/src/modules/overseas-master-data/capacityOfferTypes.ts b/src/modules/overseas-master-data/capacityOfferTypes.ts index 5ca8e1c2..055c599f 100644 --- a/src/modules/overseas-master-data/capacityOfferTypes.ts +++ b/src/modules/overseas-master-data/capacityOfferTypes.ts @@ -22,7 +22,7 @@ export interface CapacityInquiry { actions: { canEdit: boolean; canConfirm: boolean; canCancel: boolean; blockReason: string | null } } export interface CapacityOfferDetail { offer: CapacityOffer; inquiries: OfferPage } -export interface OfferQuery { page?: number; size?: number; keyword?: string; origin?: string; destination?: string; departureFrom?: string; departureTo?: string; status?: string; canConfirm?: boolean; tripNo?: string } +export interface OfferQuery { scope?: 'AVAILABLE' | 'ALL'; page?: number; size?: number; keyword?: string; origin?: string; destination?: string; departureFrom?: string; departureTo?: string; status?: string; canConfirm?: boolean; tripNo?: string } export interface InquiryQuery { page?: number; size?: number; keyword?: string; offerNo?: string; status?: string; scope?: 'MINE' | 'ALL' } export interface OfferWrite { tripNo: string; tripRecordVersion: number; offerRecordVersion: number | null; cutoffAt: string; contactName: string | null; contactPhone: string | null; remark: string | null; idempotencyKey: string } export interface OfferCommand { tripRecordVersion: number; offerRecordVersion: number; idempotencyKey: string; reason?: string } diff --git a/src/modules/overseas-master-data/components/CapacityOfferSettingsDialog.vue b/src/modules/overseas-master-data/components/CapacityOfferSettingsDialog.vue index 6147c9ab..7f748e32 100644 --- a/src/modules/overseas-master-data/components/CapacityOfferSettingsDialog.vue +++ b/src/modules/overseas-master-data/components/CapacityOfferSettingsDialog.vue @@ -23,7 +23,7 @@ const guard = useFleetDraftGuard('capacity-offer-settings', open, form, busy, co async function load() { if (!writable.value || !open.value || pending.value) return const current = ++generation; loading.value = true; error.value = null; loaded.value = false - try { const value = await listCapacityOffers({ tripNo: props.trip.tripNo, page: 1, size: 1 }); if (current !== generation) return; offer.value = value.records[0] || null; loaded.value = true; Object.assign(form, { cutoffAt: offer.value?.cutoffAt || '', contactName: offer.value?.contactName || '', contactPhone: offer.value?.contactPhone || '', remark: offer.value?.remark || '' }); await nextTick(); guard.capture() } + try { const value = await listCapacityOffers({ scope: 'ALL', tripNo: props.trip.tripNo, page: 1, size: 1 }); if (current !== generation) return; offer.value = value.records[0] || null; loaded.value = true; Object.assign(form, { cutoffAt: offer.value?.cutoffAt || '', contactName: offer.value?.contactName || '', contactPhone: offer.value?.contactPhone || '', remark: offer.value?.remark || '' }); await nextTick(); guard.capture() } catch (cause) { if (current === generation) error.value = getApiErrorDetails(cause, '发布设置读取失败') } finally { if (current === generation) loading.value = false } } diff --git a/src/modules/overseas-master-data/pages/CapacityOfferDetailView.vue b/src/modules/overseas-master-data/pages/CapacityOfferDetailView.vue index b4fdaf8a..db94278c 100644 --- a/src/modules/overseas-master-data/pages/CapacityOfferDetailView.vue +++ b/src/modules/overseas-master-data/pages/CapacityOfferDetailView.vue @@ -18,7 +18,8 @@ const route = useRoute(), router = useRouter(), access = useAccessPreviewStore() const detail = ref(null), loading = ref(false), error = ref(null), inquiryError = ref(null) const page = ref(1), size = ref(20), inquiryLoading = ref(false), editorOpen = ref(false), editing = ref(null), readonly = ref(false) let sequence = 0, inquirySequence = 0, resetting = false -const canCreate = computed(() => detail.value?.offer.canCreateInquiry && (access.can('platform:fleet:capacity-offer:manage') || access.can('platform:fleet:capacity-offer:list') && access.can('platform:fleet:capacity-offer:inquiry-create'))) +const hasCreatePermission = computed(() => (access.can('platform:fleet:capacity-offer:manage') || access.can('platform:fleet:capacity-offer:list') && access.can('platform:fleet:capacity-offer:inquiry-create'))) +const canCreate = computed(() => detail.value?.offer.canCreateInquiry && hasCreatePermission.value) const columns: DataTableColumn[] = [{ key: 'fromName', label: '起始站', minWidth: 150 }, { key: 'toName', label: '到达站', minWidth: 150 }, { key: 'planned', label: '已关联货物计划占用', minWidth: 260, slotName: 'planned' }, { key: 'reserved', label: '未关联外接预留', minWidth: 260, slotName: 'reserved' }, { key: 'remaining', label: '可接托位 / 重量 / 体积', minWidth: 270, slotName: 'remaining' }] async function load() { const current = ++sequence; inquirySequence++; loading.value = true; error.value = null @@ -58,11 +59,12 @@ watch([page, size], loadInquiries) onBeforeUnmount(() => { sequence++; inquirySequence++ })