fix(admin): align supplier carrier master data
This commit is contained in:
@@ -21,6 +21,7 @@ const payload: SavePlatformPartnerRequest = {
|
||||
partnerName: '测试往来单位',
|
||||
partnerType: 'SHIPPER',
|
||||
types: ['SHIPPER'],
|
||||
carrierCode: null,
|
||||
contactName: '测试联系人',
|
||||
contactPhone: '13800000000',
|
||||
contactEmail: null,
|
||||
@@ -66,7 +67,7 @@ describe('platform partner API', () => {
|
||||
vi.mocked(http.get)
|
||||
.mockResolvedValueOnce({ code: '200', message: 'success', data: {
|
||||
id: '19001', tenantId: 0, dataScopeId: 0, partnerCode: 'CUS-001', partnerName: '测试单位',
|
||||
partnerType: 'CONSIGNEE', contactName: '张三', contactPhone: '13800000000', contactEmail: null,
|
||||
partnerType: 'CONSIGNEE', carrierCode: null, contactName: '张三', contactPhone: '13800000000', contactEmail: null,
|
||||
countryCode: 'CN', province: null, city: '深圳市', district: null, addressLine: '测试地址',
|
||||
postalCode: null, status: 'ACTIVE',
|
||||
} })
|
||||
|
||||
@@ -2,6 +2,7 @@ import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
|
||||
export type PlatformPartnerType = 'CARRIER' | 'SHIPPER' | 'CONSIGNEE'
|
||||
export type PlatformPartnerStatus = 'ACTIVE' | 'INACTIVE'
|
||||
export type PlatformPartnerCarrierCode = 'MATSON' | 'SML' | 'ZIM' | 'COSCO' | 'EMC' | 'HEDE' | 'OTHER'
|
||||
|
||||
export interface PlatformPartnerResource {
|
||||
id: number | string
|
||||
@@ -11,6 +12,7 @@ export interface PlatformPartnerResource {
|
||||
partnerName: string
|
||||
partnerType: PlatformPartnerType
|
||||
types: PlatformPartnerType[]
|
||||
carrierCode: PlatformPartnerCarrierCode | null
|
||||
contactName: string
|
||||
contactPhone: string
|
||||
contactEmail: string | null
|
||||
@@ -54,6 +56,7 @@ export interface SavePlatformPartnerRequest {
|
||||
partnerName: string
|
||||
partnerType: PlatformPartnerType
|
||||
types: PlatformPartnerType[]
|
||||
carrierCode: PlatformPartnerCarrierCode | null
|
||||
contactName: string
|
||||
contactPhone: string
|
||||
contactEmail: string | null
|
||||
@@ -89,6 +92,7 @@ function normalizePartner(resource: PlatformPartnerResource): PlatformPartnerRes
|
||||
...resource,
|
||||
dataScopeId: resource.dataScopeId ?? resource.tenantId,
|
||||
types: resource.types?.length ? resource.types : [resource.partnerType],
|
||||
carrierCode: resource.carrierCode ?? null,
|
||||
remark: resource.remark ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ const partner: PlatformPartnerResource = {
|
||||
partnerName: '深圳示例贸易有限公司',
|
||||
partnerType: 'SHIPPER',
|
||||
types: ['SHIPPER'],
|
||||
carrierCode: null,
|
||||
contactName: '张三',
|
||||
contactPhone: '13800138000',
|
||||
contactEmail: 'contact@example.com',
|
||||
@@ -159,6 +160,25 @@ describe('PartnersView real API integration', () => {
|
||||
expect(document.body.textContent).not.toContain('供应商')
|
||||
})
|
||||
|
||||
it('uses the fixed carrier-code selector when the unit is a shipping company', async () => {
|
||||
const wrapper = await mountView()
|
||||
await wrapper.findAll('button').find((button) => button.text().trim() === '新增往来单位')?.trigger('click')
|
||||
await flushPromises()
|
||||
const typeSelect = wrapper.findAllComponents({ name: 'ElSelect' }).find((select) => select.props('multiple'))
|
||||
typeSelect!.vm.$emit('update:modelValue', ['CARRIER'])
|
||||
await flushPromises()
|
||||
|
||||
expect(document.body.textContent).toContain('船司标准编码')
|
||||
const carrierValues = new Set(['MATSON', 'SML', 'ZIM', 'COSCO', 'EMC', 'HEDE', 'OTHER'])
|
||||
const carrierOptions = wrapper.findAllComponents({ name: 'ElOption' }).filter((option) => carrierValues.has(String(option.props('value'))))
|
||||
expect(carrierOptions.map((option) => option.props('value'))).toEqual(['MATSON', 'SML', 'ZIM', 'COSCO', 'EMC', 'HEDE', 'OTHER'])
|
||||
expect(carrierOptions.map((option) => option.props('label'))).toContain('美森 (MATSON)')
|
||||
expect(source).toContain('placeholder="请选择船司标准编码"')
|
||||
expect(source).toContain("MATSON: '美森'")
|
||||
expect(source).toContain("OTHER: '其他'")
|
||||
expect(source).toContain("carrierCode: types.includes('CARRIER') ? form.carrierCode : null")
|
||||
})
|
||||
|
||||
it('renders a padded detail layout without an empty data-scope cell', async () => {
|
||||
const wrapper = await mountView()
|
||||
const detailButton = wrapper.findAll('button').find((button) => button.text().trim() === '详情')
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
listPlatformPartners,
|
||||
updatePlatformPartner,
|
||||
type PlatformPartnerResource,
|
||||
type PlatformPartnerCarrierCode,
|
||||
type PlatformPartnerStatus,
|
||||
type PlatformPartnerType,
|
||||
type SavePlatformPartnerRequest,
|
||||
@@ -94,6 +95,7 @@ const emptyForm = (): PartnerForm => ({
|
||||
partnerName: '',
|
||||
partnerType: 'SHIPPER',
|
||||
types: ['SHIPPER'],
|
||||
carrierCode: null,
|
||||
contactName: '',
|
||||
contactPhone: '',
|
||||
contactEmail: null,
|
||||
@@ -121,6 +123,7 @@ const rules: FormRules<PartnerForm> = {
|
||||
partnerCode: [{ required: true, whitespace: true, message: '请输入往来单位编码', trigger: 'blur' }],
|
||||
partnerName: [{ required: true, whitespace: true, message: '请输入往来单位名称', trigger: 'blur' }],
|
||||
types: [{ required: true, type: 'array', min: 1, message: '请至少选择一个单位类型', trigger: 'change' }],
|
||||
carrierCode: [{ validator: (_rule, value, callback) => form.types.includes('CARRIER') && !value ? callback(new Error('请选择船司标准编码')) : callback(), trigger: 'change' }],
|
||||
contactName: [{ required: true, whitespace: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
contactPhone: [{ required: true, whitespace: true, message: '请输入联系电话', trigger: 'blur' }],
|
||||
contactEmail: [{ type: 'email', message: '请输入有效的邮箱地址', trigger: 'blur' }],
|
||||
@@ -139,6 +142,11 @@ const typeLabels: Record<PlatformPartnerType, string> = {
|
||||
CONSIGNEE: '收货单位',
|
||||
}
|
||||
const typeOptions = Object.entries(typeLabels).map(([value, label]) => ({ value: value as PlatformPartnerType, label }))
|
||||
const carrierCodeLabels: Record<PlatformPartnerCarrierCode, string> = {
|
||||
MATSON: '美森', SML: 'SML', ZIM: '以星', COSCO: '中远', EMC: '长荣', HEDE: '合德', OTHER: '其他',
|
||||
}
|
||||
const carrierCodeOptions = (Object.entries(carrierCodeLabels) as [PlatformPartnerCarrierCode, string][]).map(([value, label]) => ({ value, label: `${label} (${value})` }))
|
||||
function formatCarrierCode(value?: PlatformPartnerCarrierCode | null) { return value ? `${carrierCodeLabels[value]} (${value})` : '—' }
|
||||
function partnerTypeLabel(type: PlatformPartnerType) {
|
||||
return typeLabels[type]
|
||||
}
|
||||
@@ -225,6 +233,7 @@ function openEdit(row: PlatformPartnerResource) {
|
||||
partnerName: row.partnerName,
|
||||
partnerType: row.types[0],
|
||||
types: [...row.types],
|
||||
carrierCode: row.carrierCode,
|
||||
contactName: row.contactName,
|
||||
contactPhone: row.contactPhone,
|
||||
contactEmail: row.contactEmail,
|
||||
@@ -249,6 +258,7 @@ function savePayload(): SavePlatformPartnerRequest {
|
||||
partnerName: form.partnerName.trim(),
|
||||
partnerType: types[0],
|
||||
types,
|
||||
carrierCode: types.includes('CARRIER') ? form.carrierCode : null,
|
||||
contactName: form.contactName.trim(),
|
||||
contactPhone: form.contactPhone.trim(),
|
||||
contactEmail: nullable(form.contactEmail),
|
||||
@@ -342,6 +352,11 @@ function formatUpdatedAt(value?: string | null) {
|
||||
}
|
||||
|
||||
watch([page, pageSize], () => { void loadPartners() })
|
||||
watch(() => form.types.includes('CARRIER'), (carrier) => {
|
||||
if (carrier) return
|
||||
form.carrierCode = null
|
||||
formRef.value?.clearValidate('carrierCode')
|
||||
})
|
||||
watch(detailOpen, (open) => {
|
||||
if (open) return
|
||||
detailSequence += 1
|
||||
@@ -415,6 +430,7 @@ onMounted(() => {
|
||||
<el-form-item label="单位名称" prop="partnerName" required><el-input v-model="form.partnerName" placeholder="请输入工商登记或常用单位名称" maxlength="128" /></el-form-item>
|
||||
<el-form-item label="单位类型" prop="types" required><el-select v-model="form.types" multiple collapse-tags collapse-tags-tooltip placeholder="请选择一个或多个单位类型"><el-option v-for="option in typeOptions" :key="option.value" :label="option.label" :value="option.value" /></el-select></el-form-item>
|
||||
<el-form-item label="状态" prop="status" required><el-radio-group v-model="form.status"><el-radio-button value="ACTIVE">启用</el-radio-button><el-radio-button value="INACTIVE">停用</el-radio-button></el-radio-group></el-form-item>
|
||||
<el-form-item v-if="form.types.includes('CARRIER')" label="船司标准编码" prop="carrierCode" required><el-select v-model="form.carrierCode" placeholder="请选择船司标准编码" style="width:100%"><el-option v-for="option in carrierCodeOptions" :key="option.value" :label="option.label" :value="option.value" /></el-select></el-form-item>
|
||||
</div></FormSection>
|
||||
<FormSection title="联系信息"><div class="form-grid two-cols">
|
||||
<el-form-item label="联系人" prop="contactName" required><el-input v-model="form.contactName" placeholder="请输入主要联系人姓名" maxlength="64" /></el-form-item>
|
||||
@@ -446,6 +462,7 @@ onMounted(() => {
|
||||
<div><dt>单位名称</dt><dd>{{ detail.partnerName }}</dd></div>
|
||||
<div><dt>状态</dt><dd><el-tag :type="detail.status === 'ACTIVE' ? 'success' : 'info'">{{ detail.status === 'ACTIVE' ? '启用' : '停用' }}</el-tag></dd></div>
|
||||
<div><dt>单位类型</dt><dd class="partner-types"><el-tag v-for="type in detail.types" :key="type" effect="plain">{{ partnerTypeLabel(type) }}</el-tag></dd></div>
|
||||
<div v-if="detail.types.includes('CARRIER')"><dt>船司标准编码</dt><dd>{{ formatCarrierCode(detail.carrierCode) }}</dd></div>
|
||||
</dl></FormSection>
|
||||
<FormSection title="联系与地址"><dl class="detail-grid">
|
||||
<div><dt>联系人</dt><dd>{{ detail.contactName }}</dd></div><div><dt>联系电话</dt><dd>{{ detail.contactPhone }}</dd></div>
|
||||
|
||||
Reference in New Issue
Block a user