This commit is contained in:
2026-09-09 17:42:19 +08:00
parent a47a7e9767
commit 2fd9c5fcc7
8 changed files with 39 additions and 7 deletions
@@ -231,7 +231,7 @@ const queryFields = computed<QueryField[]>(() => [
{ key: 'sailingRange', type: 'daterange', label: '预计开船', width: 260, props: { 'aria-label': '预计开船日期范围' } },
])
const allColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 140, fixed: 'left', slotName: 'actions' },
{ key: 'actions', label: '操作', width: 240, fixed: 'left', slotName: 'actions' },
{ key: 'emptyReturnWarning', label: '报空预警', width: 120, slotName: 'emptyReturnWarning' },
{ key: 'containerNo', label: '集装箱号', minWidth: 150, slotName: 'containerNo' },
{ key: 'planNo', prop: 'planNo', label: '装柜清单号', minWidth: 165, formatter: (row: ContainerBookingResource) => row.planNo || '—' },
@@ -568,7 +568,9 @@ async function selectRowFleet(source: object, supplierIdValue: unknown) {
drayageSavingIds.value = [...drayageSavingIds.value, row.id]
try {
replaceDrayage(await selectTerminalDrayageFleet(row.id, { expectedVersion: current.version, fleetSupplierId: supplier.id, fleetSupplierName: supplier.name }))
ElMessage.success(current.fleetSupplierId && current.fleetSupplierId !== supplier.id ? '码头车队已更新,取消及提柜邮件已加入发送队列' : '码头车队已更新')
ElMessage.success(current.fleetSupplierId && current.fleetSupplierId !== supplier.id
? '码头车队已更新,新车队提柜邮件已入队;原车队已下发过邮件时同时加入取消邮件'
: '码头车队已更新')
await loadRows()
} catch (error) {
const details = getApiErrorDetails(error, '码头车队更新失败')
@@ -79,8 +79,8 @@ describe('InboundOrdersView', () => {
vi.mocked(listPlatformTenants).mockResolvedValue({ records: customers, page: 1, size: 200, total: 2, pages: 1 })
vi.mocked(listPlatformWarehouses).mockResolvedValue({
records: [
{ id: '20001', tenantId: '10001', warehouseCode: 'YIWU', warehouseName: '义乌收货仓', warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null, contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null },
{ id: 20002, tenantId: '10001', warehouseCode: 'B001', warehouseName: '交货仓 B001', warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null, contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null },
{ id: '20001', tenantId: '10001', warehouseCode: 'YIWU', internalCode: null, warehouseName: '义乌收货仓', warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null, contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null },
{ id: 20002, tenantId: '10001', warehouseCode: 'B001', internalCode: null, warehouseName: '交货仓 B001', warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null, contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null },
],
page: 1, size: 200, total: 2, pages: 1,
})
@@ -53,6 +53,7 @@ const warehouse: PlatformWarehouseResource = {
id: warehouseId,
tenantId,
warehouseCode: 'CN-YW-01',
internalCode: null,
warehouseName: '义乌收货仓',
warehouseType: 'DOMESTIC',
countryCode: 'CN',
@@ -68,6 +69,7 @@ const fbaWarehouse: PlatformWarehouseResource = {
...warehouse,
id: '9223372036854775802',
warehouseCode: 'FBA-ONT8',
internalCode: '154',
warehouseName: 'ONT8 FBA 仓',
warehouseType: 'FBA',
}
@@ -76,6 +78,7 @@ const overseasWarehouse: PlatformWarehouseResource = {
...warehouse,
id: '9223372036854775801',
warehouseCode: 'US-LAX-01',
internalCode: null,
warehouseName: '洛杉矶海外仓',
warehouseType: 'OVERSEAS',
}
@@ -49,7 +49,7 @@ function createMemoryStorage(): Storage {
}
const warehouse: PlatformWarehouseResource = {
id: '19001', tenantId: 0, warehouseCode: 'CN-YW-01', warehouseName: '义乌收货仓',
id: '19001', tenantId: 0, warehouseCode: 'CN-YW-01', internalCode: null, warehouseName: '义乌收货仓',
warehouseType: 'DOMESTIC', countryCode: 'CN', timezone: 'Asia/Shanghai', contactName: null,
contactPhone: null, contactEmail: null, status: 'ACTIVE', remark: null,
}
@@ -58,6 +58,7 @@ const fbaWarehouse: PlatformWarehouseResource = {
...warehouse,
id: '19002',
warehouseCode: 'FBA-ONT8',
internalCode: '154',
warehouseName: 'ONT8 FBA 仓',
warehouseType: 'FBA',
}
@@ -66,6 +67,7 @@ const overseasWarehouse: PlatformWarehouseResource = {
...warehouse,
id: '19003',
warehouseCode: 'US-LAX-01',
internalCode: null,
warehouseName: '洛杉矶海外仓',
warehouseType: 'OVERSEAS',
}
@@ -19,6 +19,7 @@ vi.mock('@/shared/api/http', () => ({
const payload: SavePlatformWarehouseRequest = {
warehouseCode: 'CN-YW-01',
internalCode: null,
warehouseName: '义乌收货仓',
warehouseType: 'DOMESTIC',
countryCode: 'CN',
@@ -63,6 +64,7 @@ describe('platform warehouse API', () => {
id: '1',
tenantId: 0,
warehouseCode: 'LAX9',
internalCode: '154',
warehouseName: 'LAX9',
warehouseType: 'FBA',
countryCode: 'US',
@@ -201,6 +203,7 @@ describe('platform warehouse API', () => {
await expect(createFbaWarehouse({
warehouseCode: 'LAX9',
internalCode: '154',
stateProvince: 'CA',
city: 'Long Beach',
postalCode: '90802',
@@ -221,6 +224,7 @@ describe('platform warehouse API', () => {
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/warehouse-admin', {
warehouseCode: 'LAX9',
internalCode: '154',
warehouseName: 'LAX9',
warehouseType: 'FBA',
countryCode: 'US',
@@ -8,6 +8,7 @@ export interface PlatformWarehouseResource {
id: number | string
tenantId: number | string
warehouseCode: string
internalCode: string | null
warehouseName: string
warehouseType: WarehouseType
countryCode: string
@@ -105,6 +106,7 @@ export interface PlatformWarehouseCapabilityRequest {
export interface SavePlatformWarehouseRequest {
warehouseCode: string
internalCode: string | null
warehouseName: string
warehouseType: WarehouseType
countryCode: string
@@ -120,6 +122,7 @@ export interface SavePlatformWarehouseRequest {
export interface CreateFbaWarehouseRequest {
warehouseCode: string
internalCode: string | null
stateProvince: string
city: string
postalCode: string
@@ -252,6 +255,7 @@ export async function createPlatformWarehouse(payload: SavePlatformWarehouseRequ
export async function createFbaWarehouse(payload: CreateFbaWarehouseRequest) {
return createPlatformWarehouse({
warehouseCode: payload.warehouseCode,
internalCode: payload.internalCode,
warehouseName: payload.warehouseCode,
warehouseType: 'FBA',
countryCode: 'US',
@@ -72,6 +72,7 @@ const domesticWarehouse: PlatformWarehouseSummaryResource = {
id: '19001',
tenantId: 0,
warehouseCode: 'CN-YW-01',
internalCode: null,
warehouseName: '义乌收货仓',
warehouseType: 'DOMESTIC',
countryCode: 'CN',
@@ -106,6 +107,7 @@ const fbaWarehouse: PlatformWarehouseSummaryResource = {
id: '19011',
tenantId: 0,
warehouseCode: 'AKR1',
internalCode: '154',
warehouseName: 'AKR1',
warehouseType: 'FBA',
countryCode: 'US',
@@ -130,6 +132,7 @@ const partnerWarehouse: PlatformWarehouseSummaryResource = {
...fbaWarehouse,
id: '19021',
warehouseCode: 'PARTNER-US-01',
internalCode: null,
warehouseName: '洛杉矶合作仓',
warehouseType: 'OVERSEAS_PARTNER',
}
@@ -196,7 +199,7 @@ describe('WarehousesView', () => {
expect(warehousesSource).toMatch(/size="small"\s+plain\s+:type=/)
expect(warehousesSource).toContain('<Pencil :size="15" />')
expect(warehousesSource).toContain('<Power :size="15" />')
for (const label of ['仓库名称', '仓库编码', '州/省', '城市', '邮编']) expect(warehousesSource).toContain(`label: '${label}'`)
for (const label of ['仓库名称', '仓库编码', '内部编号', '州/省', '城市', '邮编']) expect(warehousesSource).toContain(`label: '${label}'`)
expect(warehousesSource).toContain('@media (max-width: 720px)')
})
it('uses the prototype-sized centered warehouse editor with a fixed footer', () => {
@@ -333,6 +336,7 @@ describe('WarehousesView', () => {
expect(stateSelect).toBeDefined()
setField('input[placeholder="例如 LAX9"]', 'lax9')
setField('input[placeholder="例如 154 或 CADF"]', '154')
stateSelect!.vm.$emit('update:modelValue', 'CA')
stateSelect!.vm.$emit('change', 'CA')
await flushPromises()
@@ -347,6 +351,7 @@ describe('WarehousesView', () => {
expect(createFbaWarehouse).toHaveBeenCalledWith({
warehouseCode: 'LAX9',
internalCode: '154',
stateProvince: 'CA',
city: 'Long Beach',
postalCode: '90802',
@@ -515,6 +520,7 @@ describe('WarehousesView', () => {
expect(stateSelect?.props('modelValue')).toBe('OH')
expect(timezoneSelect?.props('modelValue')).toBe('UTC-5')
expect(countrySelect).toBeDefined()
expect((wrapper.find('input[placeholder="例如 154 或 CADF"]').element as HTMLInputElement).value).toBe('154')
const saveButton = [...document.querySelectorAll('button')].find((button) => button.textContent?.trim() === '保存修改')
expect(saveButton).toBeDefined()
@@ -525,6 +531,7 @@ describe('WarehousesView', () => {
const [, payload] = vi.mocked(updatePlatformWarehouse).mock.calls[0]
expect(payload).toMatchObject({
warehouseType: 'FBA',
internalCode: '154',
countryCode: 'US',
timezone: 'UTC-5',
address: expect.objectContaining({ stateProvince: 'OH' }),
@@ -160,6 +160,7 @@ let loadSequence = 0
interface WarehouseRow extends Warehouse {
warehouseType: WarehouseType
internalCode: string
countryCode: string
timezone: string
postalCode: string
@@ -171,6 +172,7 @@ const warehouseColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', width: 180, fixed: 'left', slotName: 'actions' },
{ key: 'warehouse', label: '仓库名称', minWidth: 190, slotName: 'warehouse' },
{ key: 'code', prop: 'code', label: '仓库编码', minWidth: 145 },
{ key: 'internalCode', prop: 'internalCode', label: '内部编号', minWidth: 120 },
{ key: 'warehouseType', label: '仓库类型', width: 120, slotName: 'warehouseType' },
{ key: 'countryCode', label: '国家/地区', width: 140, slotName: 'countryCode' },
{ key: 'timezone', prop: 'timezone', label: '时区', width: 110, defaultVisible: false },
@@ -184,6 +186,7 @@ const warehouseColumns: DataTableColumn[] = [
type WarehouseForm = Omit<Warehouse, 'updatedAt'> & {
warehouseType: WarehouseType
internalCode: string
countryCode: string
timezone: string
postalCode: string
@@ -198,6 +201,7 @@ function generatedCode(type: WarehouseType) {
const emptyForm = (type: WarehouseType = 'FBA'): WarehouseForm => ({
id: '',
code: type === 'FBA' ? '' : generatedCode(type),
internalCode: '',
name: '',
province: '',
city: '',
@@ -291,6 +295,7 @@ watch(activeWarehouseType, (type) => {
form.province = ''
form.timezone = ''
}
if (type !== 'FBA') form.internalCode = ''
clearFieldError('countryCode')
clearFieldError('timezone')
})
@@ -302,6 +307,7 @@ function toRow(warehouse: PlatformWarehouseSummaryResource): WarehouseRow {
return {
id: String(warehouse.id),
code: warehouse.warehouseCode,
internalCode: warehouse.internalCode || '',
name: warehouse.warehouseName,
warehouseType: warehouse.warehouseType,
countryCode: warehouse.countryCode,
@@ -457,6 +463,7 @@ async function openEdit(warehouse: WarehouseRow) {
Object.assign(form, {
id: String(detail.warehouse.id),
code: detail.warehouse.warehouseCode,
internalCode: detail.warehouse.internalCode || '',
name: detail.warehouse.warehouseName,
warehouseType: detail.warehouse.warehouseType,
countryCode: detail.warehouse.countryCode,
@@ -508,6 +515,7 @@ function buildSaveRequest(): SavePlatformWarehouseRequest {
}
return {
warehouseCode: form.code.trim().toUpperCase(),
internalCode: form.warehouseType === 'FBA' ? nullable(form.internalCode)?.toUpperCase() || null : null,
warehouseName: form.name.trim(),
warehouseType: form.warehouseType,
countryCode,
@@ -540,6 +548,7 @@ async function saveWarehouse() {
if (isFbaCreate.value) {
await createFbaWarehouse({
warehouseCode: form.code.trim().toUpperCase(),
internalCode: nullable(form.internalCode)?.toUpperCase() || null,
stateProvince: form.province.trim().toUpperCase(),
city: form.city.trim(),
postalCode: form.postalCode.trim(),
@@ -735,7 +744,7 @@ onMounted(() => void loadWarehouses())
</div>
<span v-else class="warehouse-subline">仅查看</span>
</template>
<template #warehouse="{ row }"><div class="warehouse-cell"><span><WarehouseIcon :size="18" /></span><div><strong>{{ (row as WarehouseRow).name }}</strong></div></div></template>
<template #warehouse="{ row }"><div class="warehouse-cell"><div><strong>{{ (row as WarehouseRow).name }}</strong></div></div></template>
<template #warehouseType="{ row }"><el-tag effect="plain">{{ warehouseTypeLabels[(row as WarehouseRow).warehouseType] }}</el-tag></template>
<template #countryCode="{ row }">{{ formatCountryDisplay((row as WarehouseRow).countryCode) }}</template>
<template #address="{ row }"><div class="warehouse-address"><MapPin :size="15" /><span>{{ (row as WarehouseRow).address || '-' }}</span></div></template>
@@ -770,6 +779,7 @@ onMounted(() => void loadWarehouses())
<p v-if="formErrors.timezone" class="field-error" role="alert">{{ formErrors.timezone }}</p>
</el-form-item>
</template>
<el-form-item v-if="activeWarehouseType === 'FBA'" label="内部编号"><el-input v-model="form.internalCode" maxlength="16" placeholder="例如 154 或 CADF" @input="form.internalCode = String($event ?? '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase().slice(0, 16)" /></el-form-item>
</div>
</FormSection>