diff --git a/nginx/default.conf.template b/nginx/default.conf.template index afeac1aa..0cf33330 100644 --- a/nginx/default.conf.template +++ b/nginx/default.conf.template @@ -14,7 +14,7 @@ server { # 前端代码中的 API 前缀为 /api;保持原始路径转给 Gateway。 location /api/ { - client_max_body_size 6m; + client_max_body_size 12m; proxy_pass ${API_UPSTREAM}; proxy_http_version 1.1; proxy_set_header Host $host; diff --git a/src/deployment/nginxConfig.test.ts b/src/deployment/nginxConfig.test.ts index 0b70ba19..6a586a5f 100644 --- a/src/deployment/nginxConfig.test.ts +++ b/src/deployment/nginxConfig.test.ts @@ -6,7 +6,7 @@ const config = readFileSync(resolve(process.cwd(), 'nginx/default.conf.template' describe('admin nginx deployment config', () => { it('allows qualification uploads with multipart overhead through the API proxy', () => { - expect(config).toContain('client_max_body_size 6m;') + expect(config).toContain('client_max_body_size 12m;') }) it('prevents the application shell from retaining stale chunk references', () => { diff --git a/src/modules/customers/pages/CustomersView.test.ts b/src/modules/customers/pages/CustomersView.test.ts index db6013db..b5d89708 100644 --- a/src/modules/customers/pages/CustomersView.test.ts +++ b/src/modules/customers/pages/CustomersView.test.ts @@ -12,6 +12,7 @@ import { rejectEnterpriseReview, updatePlatformTenant, uploadPlatformTenantQualification, + uploadPlatformTenantRequiredQualificationPackage, type EnterpriseReview, type PlatformTenantResource, } from '@/modules/iam' @@ -45,6 +46,7 @@ vi.mock('@/modules/iam', () => ({ submitPlatformTenantReview: vi.fn(), updatePlatformTenant: vi.fn(), uploadPlatformTenantQualification: vi.fn(), + uploadPlatformTenantRequiredQualificationPackage: vi.fn(), })) vi.mock('@/modules/downloads', () => ({ createPlatformExportTask: vi.fn() })) @@ -107,6 +109,13 @@ describe('CustomersView', () => { vi.mocked(uploadPlatformTenantQualification).mockResolvedValue({ qualificationId: 'qualification-1', reviewId: null, tenantStatus: 'PROFILE_REQUIRED', documentUrl: '/files/license.png', }) + vi.mocked(uploadPlatformTenantRequiredQualificationPackage).mockResolvedValue({ + businessLicenseQualificationId: 'qualification-business', + legalPersonIdQualificationId: 'qualification-legal', + tenantStatus: 'PROFILE_REQUIRED', + businessLicenseDocumentUrl: '/files/license.png', + legalPersonIdDocumentUrl: '/files/legal-person-new.png', + }) vi.mocked(createPlatformExportTask).mockResolvedValue({ id: 'export-1', taskName: '客户列表', taskNo: 'EXP2084', status: 'PENDING', } as never) @@ -198,7 +207,7 @@ describe('CustomersView', () => { expect(getPlatformTenant).not.toHaveBeenCalled() }) - it('saves customer data and selected qualifications with one action', async () => { + it('saves both required files and the credit code through one package action', async () => { vi.mocked(listTenantQualifications).mockResolvedValue([{ id: 'qualification-legal', tenantId: fullTenant.id, qualificationType: 'LEGAL_PERSON_ID', certificateNo: null, documentUrl: '/files/legal-person.png', status: 'PENDING', reviewComment: null, validTo: null, @@ -209,9 +218,14 @@ describe('CustomersView', () => { await flushPromises() const licenseFile = new File(['license'], 'license.png', { type: 'image/png' }) - const licenseInput = document.querySelector('.qualification-file input[type="file"]') + const legalPersonFile = new File(['legal-person'], 'legal-person.png', { type: 'image/png' }) + const qualificationInputs = document.querySelectorAll('.qualification-file input[type="file"]') + const licenseInput = qualificationInputs[0] + const legalPersonInput = qualificationInputs[1] Object.defineProperty(licenseInput, 'files', { configurable: true, value: [licenseFile] }) licenseInput?.dispatchEvent(new Event('change', { bubbles: true })) + Object.defineProperty(legalPersonInput, 'files', { configurable: true, value: [legalPersonFile] }) + legalPersonInput?.dispatchEvent(new Event('change', { bubbles: true })) await flushPromises() const buttons = [...document.querySelectorAll('button')] @@ -220,14 +234,15 @@ describe('CustomersView', () => { await flushPromises() expect(updatePlatformTenant).toHaveBeenCalledWith(fullTenant.id, expect.objectContaining({ tenantName: fullTenant.tenantName })) - expect(uploadPlatformTenantQualification).toHaveBeenCalledWith( + expect(uploadPlatformTenantRequiredQualificationPackage).toHaveBeenCalledWith( fullTenant.id, - 'BUSINESS_LICENSE', licenseFile, - undefined, + legalPersonFile, fullTenant.unifiedSocialCreditCode, false, + true, ) + expect(uploadPlatformTenantQualification).not.toHaveBeenCalled() }) it('submits the current filters to the backend export service without loading every customer page', async () => { diff --git a/src/modules/customers/pages/CustomersView.vue b/src/modules/customers/pages/CustomersView.vue index 5d482180..2eca6ddb 100644 --- a/src/modules/customers/pages/CustomersView.vue +++ b/src/modules/customers/pages/CustomersView.vue @@ -20,6 +20,7 @@ import { submitPlatformTenantReview, updatePlatformTenant, uploadPlatformTenantQualification, + uploadPlatformTenantRequiredQualificationPackage, type CreatePlatformTenantRequest, type EnterpriseApprovalResponse, type EnterpriseReview, @@ -97,7 +98,8 @@ const queryFields: QueryField[] = [ ] }, ] -const emptyForm = (): CreatePlatformTenantRequest => ({ +type CustomerForm = CreatePlatformTenantRequest & { unifiedSocialCreditCode: string } +const emptyForm = (): CustomerForm => ({ tenantName: '', legalName: '', legalRepresentative: '', unifiedSocialCreditCode: '', contactName: '', contactPhone: '', contactEmail: '', contactWechat: '', servicePackage: '基础版', salesOwnerName: '', paymentTermDays: 30, enterpriseType: '', establishedDate: null, registeredCapital: 100000, registeredCapitalCurrency: 'CNY', @@ -174,17 +176,24 @@ const canSubmitReview = computed(() => Boolean(editingId.value) && ['PROFILE_REQ const uploadingQualifications = computed(() => qualifications.value.some((item) => item.uploading)) const hasSelectedQualifications = computed(() => qualifications.value.some((item) => item.file)) const selectedBusinessLicense = computed(() => qualifications.value.find((item) => item.type === 'BUSINESS_LICENSE')?.file) -const creditCodeReadyForSave = computed(() => creditCodeEstablished.value - || (Boolean(selectedBusinessLicense.value) && unifiedSocialCreditCodePattern.test(form.value.unifiedSocialCreditCode || ''))) +const selectedLegalPersonId = computed(() => qualifications.value.find((item) => item.type === 'LEGAL_PERSON_ID')?.file) +const requiredPackageChangeSelected = computed(() => Boolean(selectedBusinessLicense.value || selectedLegalPersonId.value)) +const requiredPackageFilesSelected = computed(() => Boolean(selectedBusinessLicense.value && selectedLegalPersonId.value)) +const creditCodeReadyForSave = computed(() => requiredPackageChangeSelected.value + ? requiredPackageFilesSelected.value && (creditCodeEstablished.value + || unifiedSocialCreditCodePattern.test(form.value.unifiedSocialCreditCode || '')) + : creditCodeEstablished.value) const requiredQualificationPackageComplete = computed(() => creditCodeReadyForSave.value - && qualifications.value.filter((item) => item.required).every((item) => item.uploaded || Boolean(item.file))) + && (requiredPackageChangeSelected.value + ? requiredPackageFilesSelected.value + : qualifications.value.filter((item) => item.required).every((item) => item.uploaded))) const missingQualificationPackageItems = computed(() => { const businessLicense = qualifications.value.find((item) => item.type === 'BUSINESS_LICENSE') const legalPersonId = qualifications.value.find((item) => item.type === 'LEGAL_PERSON_ID') const missing: string[] = [] - if (!businessLicense?.uploaded && !businessLicense?.file) missing.push('营业执照') - if (!creditCodeReadyForSave.value) missing.push('18位统一社会信用代码(需随营业执照保存)') - if (!legalPersonId?.uploaded && !legalPersonId?.file) missing.push('法人身份证') + if (requiredPackageChangeSelected.value ? !businessLicense?.file : !businessLicense?.uploaded) missing.push('营业执照') + if (!creditCodeReadyForSave.value) missing.push('18位统一社会信用代码(需随必填资质包保存)') + if (requiredPackageChangeSelected.value ? !legalPersonId?.file : !legalPersonId?.uploaded) missing.push('法人身份证') return missing }) const hasUnsavedChanges = computed(() => Boolean(editingId.value) && JSON.stringify(form.value) !== savedFormSnapshot.value) @@ -322,7 +331,7 @@ function openCreate() { editingId.value = null; editorStatus.value = null; resetEditor(); editorOpen.value = true nextTick(() => formRef.value?.clearValidate()) } -function mapTenantToForm(row: PlatformTenantResource): CreatePlatformTenantRequest { +function mapTenantToForm(row: PlatformTenantResource): CustomerForm { return { tenantName: row.tenantName, legalName: row.legalName || '', legalRepresentative: row.legalRepresentative || '', unifiedSocialCreditCode: row.unifiedSocialCreditCode || '', contactName: row.contactName || '', contactPhone: row.contactPhone || '', contactEmail: row.contactEmail || '', @@ -435,16 +444,40 @@ function handleQualificationPreviewError(draft: QualificationDraft) { async function uploadSelectedQualifications(tenantId: string) { const failures: string[] = [] - for (const draft of qualifications.value.filter((item) => item.file)) { + const businessLicense = qualifications.value.find((item) => item.type === 'BUSINESS_LICENSE') + const legalPersonId = qualifications.value.find((item) => item.type === 'LEGAL_PERSON_ID') + if (requiredPackageChangeSelected.value && businessLicense?.file && legalPersonId?.file) { + businessLicense.uploading = true; legalPersonId.uploading = true + businessLicense.error = ''; legalPersonId.error = '' + try { + const uploaded = await uploadPlatformTenantRequiredQualificationPackage( + tenantId, businessLicense.file, legalPersonId.file, form.value.unifiedSocialCreditCode, + businessLicense.uploaded, legalPersonId.uploaded, + ) + businessLicense.uploaded = true; legalPersonId.uploaded = true + creditCodeEstablished.value = true + businessLicense.uploadedName = businessLicense.file.name + legalPersonId.uploadedName = legalPersonId.file.name + businessLicense.documentUrl = uploaded.businessLicenseDocumentUrl + legalPersonId.documentUrl = uploaded.legalPersonIdDocumentUrl + businessLicense.file = null; legalPersonId.file = null + } catch (error) { + const message = getApiErrorMessage(error, '必填资质包上传失败,请重试') + businessLicense.error = message; legalPersonId.error = message + failures.push('必填资质包') + } finally { + businessLicense.uploading = false; legalPersonId.uploading = false + } + } + for (const draft of failures.length ? [] : qualifications.value.filter((item) => !item.required && item.file)) { draft.uploading = true; draft.error = '' try { const uploaded = await uploadPlatformTenantQualification( tenantId, draft.type, draft.file as File, draft.validTo || undefined, - draft.type === 'BUSINESS_LICENSE' ? form.value.unifiedSocialCreditCode : undefined, + undefined, draft.uploaded, ) draft.uploaded = true - if (draft.type === 'BUSINESS_LICENSE') creditCodeEstablished.value = true draft.uploadedName = draft.file?.name || '已登记文件' draft.documentUrl = uploaded.documentUrl draft.file = null @@ -470,7 +503,8 @@ async function saveCustomer() { const { unifiedSocialCreditCode: _immutable, ...payload } = form.value saved = await updatePlatformTenant(editingId.value, payload) } else { - saved = await createPlatformTenant({ ...form.value, unifiedSocialCreditCode: undefined }) + const { unifiedSocialCreditCode: _qualificationCreditCode, ...payload } = form.value + saved = await createPlatformTenant(payload) editingId.value = String(saved.id) } editorStatus.value = saved.status @@ -667,7 +701,7 @@ onMounted(async () => {

企业认证必填业务项

营业执照、18位统一社会信用代码、法人身份证需共同完整保存;货代资质证书和银行开户许可证选填。

{{ statusMeta(editorStatus).label }}
- {{ creditCodeEstablished ? '已登记的统一社会信用代码不可直接修改。' : '必须与营业执照一致,并随营业执照文件共同保存。' }} + {{ creditCodeEstablished ? '已登记的统一社会信用代码不可直接修改。' : '必须与营业执照一致,并随营业执照、法人身份证共同保存。' }}
文件类型上传文件有效期
diff --git a/src/modules/iam/api/platformIam.test.ts b/src/modules/iam/api/platformIam.test.ts index 5c99e269..923b780a 100644 --- a/src/modules/iam/api/platformIam.test.ts +++ b/src/modules/iam/api/platformIam.test.ts @@ -34,6 +34,7 @@ import { updatePlatformRole, updatePlatformTenant, uploadPlatformTenantQualification, + uploadPlatformTenantRequiredQualificationPackage, type PlatformPermissionResource, type PlatformInternalUser, type PlatformManagedUser, @@ -271,7 +272,7 @@ describe('platform IAM roles', () => { it('creates, updates, and changes customer status with the platform tenant contract', async () => { const tenant = { id: '8', tenantCode: 'TEN8', tenantName: '柏悦物流', status: 'ACTIVE' } const create = { - tenantName: '柏悦物流', legalName: '柏悦物流有限公司', legalRepresentative: '张三', unifiedSocialCreditCode: '91440300MA5ABCDE12', + tenantName: '柏悦物流', legalName: '柏悦物流有限公司', legalRepresentative: '张三', contactName: '张三', contactPhone: '13800138000', contactEmail: 'ops@example.com', servicePackage: '标准版', contactWechat: 'baiyue-ops', salesOwnerName: '李四', paymentTermDays: 30, enterpriseType: '有限责任公司', establishedDate: '2020-01-01', registeredCapital: 1000, registeredCapitalCurrency: 'CNY', @@ -281,12 +282,11 @@ describe('platform IAM roles', () => { vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: tenant }) await expect(createPlatformTenant(create)).resolves.toEqual(tenant) - const { unifiedSocialCreditCode: _creditCode, ...update } = create - await expect(updatePlatformTenant('8', update)).resolves.toEqual(tenant) + await expect(updatePlatformTenant('8', create)).resolves.toEqual(tenant) await expect(changePlatformTenantStatus('8', 'DISABLED')).resolves.toEqual(tenant) expect(http.post).toHaveBeenCalledWith('/platform/v1/iam/tenants', create) - expect(http.put).toHaveBeenNthCalledWith(1, '/platform/v1/iam/tenants/8', update) + expect(http.put).toHaveBeenNthCalledWith(1, '/platform/v1/iam/tenants/8', create) expect(http.put).toHaveBeenNthCalledWith(2, '/platform/v1/iam/tenants/8/status', { status: 'DISABLED' }) }) @@ -297,26 +297,49 @@ describe('platform IAM roles', () => { expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/first-leg/tenant-counts?tenantIds=8,9') }) - it('uploads qualification metadata before explicitly submitting the customer review', async () => { + it('uploads optional qualification metadata before explicitly submitting the customer review', async () => { const uploadResult = { qualificationId: '91', reviewId: null, tenantStatus: 'PROFILE_REQUIRED', documentUrl: '/file.pdf' } const tenant = { id: '8', tenantCode: 'TEN8', tenantName: '柏悦物流', status: 'PENDING' } vi.mocked(http.post).mockResolvedValueOnce({ code: '200', message: 'success', data: uploadResult }) .mockResolvedValueOnce({ code: '200', message: 'success', data: tenant }) - const file = new File(['%PDF-1.4'], '营业执照.pdf', { type: 'application/pdf' }) + const file = new File(['%PDF-1.4'], '开户许可证.pdf', { type: 'application/pdf' }) - await expect(uploadPlatformTenantQualification('8', 'BUSINESS_LICENSE', file, '2030-12-31', '91440300MA5ABCDE12', true)).resolves.toEqual(uploadResult) + await expect(uploadPlatformTenantQualification('8', 'BANK_ACCOUNT_LICENSE', file, '2030-12-31', undefined, true)).resolves.toEqual(uploadResult) await expect(submitPlatformTenantReview('8')).resolves.toEqual(tenant) const form = vi.mocked(http.post).mock.calls[0]?.[1] as FormData expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/files/qualifications/8', expect.any(FormData)) expect(form.get('file')).toBe(file) - expect(form.get('qualificationType')).toBe('BUSINESS_LICENSE') + expect(form.get('qualificationType')).toBe('BANK_ACCOUNT_LICENSE') expect(form.get('validTo')).toBe('2030-12-31') - expect(form.get('certificateNo')).toBe('91440300MA5ABCDE12') + expect(form.get('certificateNo')).toBeNull() expect(form.get('replace')).toBe('true') expect(http.post).toHaveBeenNthCalledWith(2, '/platform/v1/iam/tenants/8/submit-review', {}) }) + it('uploads both required files and the credit code in one package request', async () => { + const result = { + businessLicenseQualificationId: '91', legalPersonIdQualificationId: '92', + tenantStatus: 'PROFILE_REQUIRED', businessLicenseDocumentUrl: '/license.pdf', + legalPersonIdDocumentUrl: '/legal-person.png', + } + vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: result }) + const businessLicense = new File(['%PDF-1.4'], '营业执照.pdf', { type: 'application/pdf' }) + const legalPersonId = new File(['image'], '法人身份证.png', { type: 'image/png' }) + + await expect(uploadPlatformTenantRequiredQualificationPackage( + '8', businessLicense, legalPersonId, '91440300MA5ABCDE12', true, true, + )).resolves.toEqual(result) + + const form = vi.mocked(http.post).mock.calls[0]?.[1] as FormData + expect(http.post).toHaveBeenCalledWith('/platform/v1/files/qualifications/8/required-package', form) + expect(form.get('businessLicense')).toBe(businessLicense) + expect(form.get('legalPersonId')).toBe(legalPersonId) + expect(form.get('unifiedSocialCreditCode')).toBe('91440300MA5ABCDE12') + expect(form.get('replaceBusinessLicense')).toBe('true') + expect(form.get('replaceLegalPersonId')).toBe('true') + }) + it('preserves long review identifiers and returns one-time administrator credentials', async () => { const reviewId = '190000000000000001' const approval = { diff --git a/src/modules/iam/api/platformIam.ts b/src/modules/iam/api/platformIam.ts index d25ab046..1464289f 100644 --- a/src/modules/iam/api/platformIam.ts +++ b/src/modules/iam/api/platformIam.ts @@ -53,7 +53,6 @@ export interface CreatePlatformTenantRequest { tenantName: string legalName: string legalRepresentative: string - unifiedSocialCreditCode?: string contactName: string contactPhone: string contactEmail: string @@ -69,7 +68,7 @@ export interface CreatePlatformTenantRequest { internalRemark: string } -export type UpdatePlatformTenantRequest = Omit +export type UpdatePlatformTenantRequest = CreatePlatformTenantRequest export interface PlatformTenantOrderCount { tenantId: number | string @@ -112,6 +111,14 @@ export interface PlatformQualificationUploadResponse { replacedDocumentUrl?: string | null } +export interface PlatformRequiredQualificationPackageUploadResponse { + businessLicenseQualificationId: number | string + legalPersonIdQualificationId: number | string + tenantStatus: PlatformTenantStatus + businessLicenseDocumentUrl: string + legalPersonIdDocumentUrl: string +} + export interface EnterpriseApprovalResponse { tenantId: number | string administratorCreated: boolean @@ -341,6 +348,27 @@ export async function uploadPlatformTenantQualification( return unwrapApiResponse(response) } +export async function uploadPlatformTenantRequiredQualificationPackage( + tenantId: number | string, + businessLicense: File, + legalPersonId: File, + unifiedSocialCreditCode: string, + replaceBusinessLicense = false, + replaceLegalPersonId = false, +) { + const form = new FormData() + form.append('businessLicense', businessLicense) + form.append('legalPersonId', legalPersonId) + form.append('unifiedSocialCreditCode', unifiedSocialCreditCode) + if (replaceBusinessLicense) form.append('replaceBusinessLicense', 'true') + if (replaceLegalPersonId) form.append('replaceLegalPersonId', 'true') + const response = await http.post, ApiEnvelope>( + `/platform/v1/files/qualifications/${tenantId}/required-package`, + form, + ) + return unwrapApiResponse(response) +} + export function listPlatformTenantOrderCounts(tenantIds: Array) { const ids = tenantIds.map((id) => encodeURIComponent(String(id))).join(',') return getData(`/platform/v1/orders/first-leg/tenant-counts?tenantIds=${ids}`) diff --git a/src/modules/inbounds/core/api.test.ts b/src/modules/inbounds/core/api.test.ts index 5a4d4c9f..d6af6e6a 100644 --- a/src/modules/inbounds/core/api.test.ts +++ b/src/modules/inbounds/core/api.test.ts @@ -23,7 +23,7 @@ describe('platform inbound query API', () => { it('uses the implemented non-v1 list path and normalizes page values and IDs', async () => { vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { - records: [{ id: 19001, orderId: 18001, customerId: 10001, totalPackageCount: '6', holdFlag: 'false' }], + records: [{ id: 19001, tenantId: 10002, orderId: 18001, customerId: 10001, totalPackageCount: '6', holdFlag: 'false' }], page: '1', size: '20', total: '1', pages: '1', }, }) @@ -31,7 +31,7 @@ describe('platform inbound query API', () => { await expect(listPlatformInbounds('10001', { page: 1, size: 20, tab: 'WAIT_MEASURE', inboundCode: 'RK', holdFlag: false, })).resolves.toMatchObject({ - records: [{ id: '19001', orderId: '18001', customerId: '10001', totalPackageCount: 6, holdFlag: false }], + records: [{ id: '19001', tenantId: '10002', orderId: '18001', customerId: '10001', totalPackageCount: 6, holdFlag: false }], total: 1, pages: 1, }) expect(http.get).toHaveBeenCalledWith('/platform/inbounds', { @@ -42,14 +42,14 @@ describe('platform inbound query API', () => { it('loads a tenant-scoped aggregate detail and keeps nested IDs as strings', async () => { vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { - summary: { id: 19001, orderId: 18001 }, publicRemark: null, + summary: { id: 19001, tenantId: 10002, orderId: 18001 }, publicRemark: null, palletLocations: [{ palletId: 21001, locationId: 22001 }], files: [{ fileId: 23001, uploadedBy: 2 }], internalNotes: [{ id: 24001, createdBy: 2 }], statusHistory: [{ operatorId: 2 }], }, }) await expect(getPlatformInbound('10001', '19001')).resolves.toMatchObject({ - summary: { id: '19001', orderId: '18001' }, + summary: { id: '19001', tenantId: '10002', orderId: '18001' }, palletLocations: [{ palletId: '21001', locationId: '22001' }], files: [{ fileId: '23001', uploadedBy: '2' }], internalNotes: [{ id: '24001', createdBy: '2' }], diff --git a/src/modules/inbounds/core/api.ts b/src/modules/inbounds/core/api.ts index 31e4aa54..9ef76349 100644 --- a/src/modules/inbounds/core/api.ts +++ b/src/modules/inbounds/core/api.ts @@ -39,6 +39,7 @@ export function normalizeInboundSummary(raw: InboundOrderSummary): InboundOrderS return { ...raw, id: String(raw.id), + tenantId: String(raw.tenantId), orderId: id(raw.orderId), customerId: id(raw.customerId), companyId: id(raw.companyId), diff --git a/src/modules/inbounds/core/types.ts b/src/modules/inbounds/core/types.ts index ccb440ef..bd0b7aa8 100644 --- a/src/modules/inbounds/core/types.ts +++ b/src/modules/inbounds/core/types.ts @@ -15,6 +15,7 @@ export type InboundFeeStatus = 'UNPRICED' | 'CALCULATED' | 'CONFIRMED' | 'SENT' export interface InboundOrderSummary { id: string + tenantId: string orderId: string | null orderNo: string | null inboundCode: string | null diff --git a/src/modules/inbounds/pages/InboundOrdersView.test.ts b/src/modules/inbounds/pages/InboundOrdersView.test.ts index d7dd9bfe..cf5a18bd 100644 --- a/src/modules/inbounds/pages/InboundOrdersView.test.ts +++ b/src/modules/inbounds/pages/InboundOrdersView.test.ts @@ -31,7 +31,7 @@ const customers: PlatformTenantResource[] = [ ] const summary: InboundOrderSummary = { - id: '19001', orderId: '18001', orderNo: 'ORD-001', inboundCode: 'RK-001', processStatus: 'WAIT_MEASURE', + id: '19001', tenantId: '10002', orderId: '18001', orderNo: 'ORD-001', inboundCode: 'RK-001', processStatus: 'WAIT_MEASURE', orderStatusSnapshot: 'APPROVED', measureReviewStatus: 'PENDING', feeStatus: 'UNPRICED', feeReviewStatus: null, notificationStatus: null, version: 1, expectedArrivalAt: '2026-08-04T10:00:00', customerId: '10001', customerName: '示例客户', companyId: '10001', companyName: '示例企业', warehouseId: '20001', warehouseName: '义乌收货仓', deliveryWarehouseId: null, @@ -165,7 +165,7 @@ describe('InboundOrdersView', () => { expect(listPlatformInbounds).toHaveBeenLastCalledWith('10001', expect.objectContaining({ tab: 'WAIT_REVIEW', page: 1 })) ;[...document.querySelectorAll('button')].filter((button) => button.textContent?.trim() === '查看').at(-1)?.click() await flushPromises() - expect(getPlatformInbound).toHaveBeenCalledWith('10001', '19001') + expect(getPlatformInbound).toHaveBeenCalledWith('10002', '19001') expect(document.body.textContent).toContain('托盘与库位') expect(document.body.textContent).toContain('请优先安排测量') wrapper.unmount() diff --git a/src/modules/inbounds/pages/InboundOrdersView.vue b/src/modules/inbounds/pages/InboundOrdersView.vue index 851d8ceb..21d553e0 100644 --- a/src/modules/inbounds/pages/InboundOrdersView.vue +++ b/src/modules/inbounds/pages/InboundOrdersView.vue @@ -281,7 +281,7 @@ async function openDetail(row: InboundOrderSummary) { detailError.value = null detail.value = null try { - const response = await getPlatformInbound(recordCustomerId(row), row.id) + const response = await getPlatformInbound(row.tenantId, row.id) if (disposed || requestId !== detailRequestId) return detail.value = response } catch (error) { @@ -293,10 +293,8 @@ async function openDetail(row: InboundOrderSummary) { } function closeDetail() { resetDetail() } -function recordCustomerId(row: InboundOrderSummary) { return row.customerId || row.companyId || selectedCustomerId.value } function openWorkspace(row: InboundOrderSummary) { - const customerId = recordCustomerId(row) - void router.push({ name: 'inbound-order-detail', params: { inboundId: row.id }, query: customerId ? { tenantId: customerId } : undefined }) + void router.push({ name: 'inbound-order-detail', params: { inboundId: row.id }, query: { tenantId: row.tenantId } }) } function formatNumber(value: number | null, digits = 3) { return value === null ? '—' : value.toFixed(digits) } function formatDate(value: string | null) {