From 2563ad7be3a71c18cb424fdf0dd35c49fcae61f9 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Wed, 26 Aug 2026 14:48:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/suppliers/api/platformSuppliers.ts | 1 + src/modules/suppliers/pages/SupplierDetailView.vue | 4 ++-- src/modules/suppliers/pages/SupplierFormView.vue | 13 +++++++++---- .../pages/SupplierRouteReuse.behavior.test.ts | 2 +- src/modules/suppliers/pages/SuppliersView.test.ts | 10 ++++++++++ src/modules/suppliers/pages/SuppliersView.vue | 4 +++- src/modules/suppliers/types.ts | 8 ++++++++ 7 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/modules/suppliers/api/platformSuppliers.ts b/src/modules/suppliers/api/platformSuppliers.ts index 3661e8d9..ec361b31 100644 --- a/src/modules/suppliers/api/platformSuppliers.ts +++ b/src/modules/suppliers/api/platformSuppliers.ts @@ -9,6 +9,7 @@ function normalizeSupplier(raw: Supplier): Supplier { return { ...raw, id: String(raw.id), tenantId: String(raw.tenantId), + carrierCode: raw.carrierCode ?? null, licenseFileId: id(raw.licenseFileId), createdBy: id(raw.createdBy), updatedBy: id(raw.updatedBy), version: Number(raw.version), deleted: Boolean(raw.deleted), } diff --git a/src/modules/suppliers/pages/SupplierDetailView.vue b/src/modules/suppliers/pages/SupplierDetailView.vue index ef026031..f486e2d4 100644 --- a/src/modules/suppliers/pages/SupplierDetailView.vue +++ b/src/modules/suppliers/pages/SupplierDetailView.vue @@ -11,7 +11,7 @@ import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http' import { useAccessPreviewStore } from '@/core/access/accessPreview' import SupplierLicenseDialog from '@/modules/suppliers/components/SupplierLicenseDialog.vue' import { getSupplier } from '@/modules/suppliers/api/platformSuppliers' -import { categoryLabels, settlementLabels, statusLabels, type Supplier } from '@/modules/suppliers/types' +import { categoryLabels, formatCarrierCode, settlementLabels, statusLabels, type Supplier } from '@/modules/suppliers/types' const route = useRoute(); const router = useRouter(); const access = useAccessPreviewStore() const canView = computed(() => access.can('platform:supplier:list')) @@ -19,7 +19,7 @@ const supplierId = computed(() => typeof route.params.id === 'string' ? route.pa const supplier = ref(null); const loading = ref(false); const error = ref(null); const licenseOpen = ref(false) let loadSequence = 0 const items = computed(() => supplier.value ? [ - ['供应商名称', supplier.value.name], ['供应商类别', categoryLabels[supplier.value.category]], ['地区', supplier.value.region], + ['供应商名称', supplier.value.name], ['供应商类别', categoryLabels[supplier.value.category]], ['船司标准编码', formatCarrierCode(supplier.value.carrierCode)], ['地区', supplier.value.region], ['法人代表', supplier.value.legalRepresentative], ['联系人', supplier.value.contactName], ['联系电话', supplier.value.phone], ['电子邮箱', supplier.value.email || '—'], ['营业执照号', supplier.value.businessLicenseNo || '—'], ['结算周期', settlementLabels[supplier.value.settlementPeriod]], ['公司地址', supplier.value.address || '—'], ['备注', supplier.value.remark || '—'], ] : []) diff --git a/src/modules/suppliers/pages/SupplierFormView.vue b/src/modules/suppliers/pages/SupplierFormView.vue index 8a4e0c9f..55aab772 100644 --- a/src/modules/suppliers/pages/SupplierFormView.vue +++ b/src/modules/suppliers/pages/SupplierFormView.vue @@ -13,7 +13,7 @@ import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http' import { useAccessPreviewStore } from '@/core/access/accessPreview' import { useUnsavedWorkRegistration } from '@/core/unsaved-work/useUnsavedWorkRegistration' import { createSupplier, getSupplier, updateSupplier } from '@/modules/suppliers/api/platformSuppliers' -import { categoryLabels, settlementLabels, statusLabels, type SaveSupplierRequest } from '@/modules/suppliers/types' +import { carrierCodeOptions, categoryLabels, settlementLabels, statusLabels, type SaveSupplierRequest } from '@/modules/suppliers/types' const route = useRoute() const router = useRouter() @@ -26,10 +26,11 @@ const loading = ref(false) const saving = ref(false) const loadError = ref(null) const submitError = ref(null) -const initial = (): SaveSupplierRequest => ({ name: '', category: 'BOOKING', region: '', legalRepresentative: '', contactName: '', phone: '', email: null, address: null, businessLicenseNo: null, licenseFileId: null, status: 'ACTIVE', settlementPeriod: 'MONTHLY_30', remark: null }) +const initial = (): SaveSupplierRequest => ({ name: '', category: 'BOOKING', carrierCode: null, region: '', legalRepresentative: '', contactName: '', phone: '', email: null, address: null, businessLicenseNo: null, licenseFileId: null, status: 'ACTIVE', settlementPeriod: 'MONTHLY_30', remark: null }) const form = reactive(initial()) const rules: FormRules = { name: [{ required: true, message: '请输入供应商名称', trigger: 'blur' }], category: [{ required: true, message: '请选择供应商类别', trigger: 'change' }], + carrierCode: [{ validator: (_rule, value, callback) => form.category === 'BOOKING' && !value ? callback(new Error('请选择船司标准编码')) : callback(), trigger: 'change' }], region: [{ required: true, message: '请输入地区', trigger: 'blur' }], legalRepresentative: [{ required: true, message: '请输入法人代表', trigger: 'blur' }], contactName: [{ required: true, message: '请输入联系人', trigger: 'blur' }], phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }], email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }], status: [{ required: true, message: '请选择合作状态', trigger: 'change' }], @@ -39,7 +40,9 @@ const { captureBaseline } = useUnsavedWorkRegistration({ key: 'supplier-editor', function optional(value: string | null) { return value?.trim() || null } function payload(): SaveSupplierRequest { - return { ...form, name: form.name.trim(), region: form.region.trim(), legalRepresentative: form.legalRepresentative.trim(), contactName: form.contactName.trim(), phone: form.phone.trim(), email: optional(form.email), address: optional(form.address), businessLicenseNo: optional(form.businessLicenseNo), licenseFileId: form.licenseFileId, remark: optional(form.remark) } + const { carrierCode, ...fields } = form + const normalized = { ...fields, name: form.name.trim(), region: form.region.trim(), legalRepresentative: form.legalRepresentative.trim(), contactName: form.contactName.trim(), phone: form.phone.trim(), email: optional(form.email), address: optional(form.address), businessLicenseNo: optional(form.businessLicenseNo), licenseFileId: form.licenseFileId, remark: optional(form.remark) } + return form.category === 'BOOKING' ? { ...normalized, carrierCode } : normalized } let loadSequence = 0 function resetForm() { Object.assign(form, initial()) } @@ -55,7 +58,7 @@ async function load() { try { const data = await getSupplier(requestedId) if (sequence !== loadSequence || requestedId !== supplierId.value) return - Object.assign(form, { name: data.name, category: data.category, region: data.region, legalRepresentative: data.legalRepresentative, contactName: data.contactName, phone: data.phone, email: data.email, address: data.address, businessLicenseNo: data.businessLicenseNo, licenseFileId: data.licenseFileId, status: data.status, settlementPeriod: data.settlementPeriod, remark: data.remark }) + Object.assign(form, { name: data.name, category: data.category, carrierCode: data.category === 'BOOKING' ? data.carrierCode : null, region: data.region, legalRepresentative: data.legalRepresentative, contactName: data.contactName, phone: data.phone, email: data.email, address: data.address, businessLicenseNo: data.businessLicenseNo, licenseFileId: data.licenseFileId, status: data.status, settlementPeriod: data.settlementPeriod, remark: data.remark }) captureBaseline() } catch (error) { if (sequence === loadSequence && requestedId === supplierId.value) loadError.value = getApiErrorDetails(error, '供应商详情加载失败') @@ -74,6 +77,7 @@ async function save() { } watch(supplierId, () => { void load() }, { immediate: true }) +watch(() => form.category, (category) => { if (category !== 'BOOKING') form.carrierCode = null }) + diff --git a/src/modules/suppliers/types.ts b/src/modules/suppliers/types.ts index 807d4923..68198f16 100644 --- a/src/modules/suppliers/types.ts +++ b/src/modules/suppliers/types.ts @@ -1,12 +1,14 @@ export type SupplierCategory = 'BOOKING' | 'CUSTOMS' | 'TRUCKING' | 'CERTIFICATE' export type SupplierStatus = 'ACTIVE' | 'INACTIVE' export type SettlementPeriod = 'MONTHLY_30' | 'MONTHLY_45' | 'MONTHLY_60' | 'MONTHLY_90' | 'PER_TRANSACTION' | 'IMMEDIATE' +export type CarrierCode = 'MATSON' | 'SML' | 'ZIM' | 'COSCO' | 'EMC' | 'HEDE' | 'OTHER' export interface Supplier { id: string tenantId: string name: string category: SupplierCategory + carrierCode?: CarrierCode | null region: string legalRepresentative: string contactName: string @@ -48,6 +50,7 @@ export interface SupplierQuery { export interface SaveSupplierRequest { name: string category: SupplierCategory + carrierCode?: CarrierCode | null region: string legalRepresentative: string contactName: string @@ -62,6 +65,11 @@ export interface SaveSupplierRequest { } export const categoryLabels: Record = { BOOKING: '订舱', CUSTOMS: '报关', TRUCKING: '拖车', CERTIFICATE: '证书' } +export const carrierCodeLabels: Record = { + MATSON: '美森', SML: 'SML', ZIM: '以星', COSCO: '中远', EMC: '长荣', HEDE: '合德', OTHER: '其他', +} +export const carrierCodeOptions = (Object.entries(carrierCodeLabels) as [CarrierCode, string][]).map(([value, name]) => ({ value, label: `${name} (${value})` })) +export function formatCarrierCode(code: CarrierCode | null | undefined) { return code ? `${carrierCodeLabels[code]} (${code})` : '—' } export const statusLabels: Record = { ACTIVE: '合作中', INACTIVE: '停用' } export const settlementLabels: Record = { MONTHLY_30: '月结30天', MONTHLY_45: '月结45天', MONTHLY_60: '月结60天', MONTHLY_90: '月结90天', PER_TRANSACTION: '票结', IMMEDIATE: '现结',