This commit is contained in:
2026-11-04 10:39:15 +08:00
parent 01d0a81603
commit 84dd9dcbb4
9 changed files with 34 additions and 12 deletions
@@ -25,5 +25,5 @@ export interface FleetArrangement {
export const poolOrderStatusLabels: Record<string, string> = {
WAITING_INBOUND: '待入仓', RECEIVING: '收货中', WAITING_CONSOLIDATION: '待合托',
PENDING_DISPATCH: '待派车', IN_TRANSIT: '运输中', COMPLETED: '已完成', CANCELLED: '已取消',
PENDING_DISPATCH: '待派车', IN_TRANSIT: '派送中', COMPLETED: '已完成', CANCELLED: '已取消',
}
@@ -5,6 +5,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { useAuthStore } from '@/core/auth/auth'
import { useAccessPreviewStore } from '@/core/access/accessPreview'
import RowActions from '@/shared/components/RowActions.vue'
import QueryToolbar from '@/shared/components/QueryToolbar.vue'
import type { DataTableColumn } from '@/shared/components/DataTable.vue'
import { listLocalLooseboardOrders, listUsTruckOrders } from '../api/platformOverseasBusiness'
import { overseasBusinessPermissions as permissions } from '../permissions'
@@ -31,7 +32,7 @@ function mountList(domain: 'truck' | 'looseboard', edit = false) {
auth.permissions = [permissions.truckList, permissions.looseboardList, ...(edit ? [permissions.looseboardEdit] : [])]
useAccessPreviewStore().initializeAfterLogin()
return mount(TransportOrdersView, { props: { domain }, global: { plugins: [pinia, ElementPlus], stubs: {
DataTable: { name: 'DataTable', props: ['data', 'columns'], template: '<div><div v-for="row in data" :key="row.id"><span v-for="column in columns" :key="column.key" :data-column="column.key">{{ column.prop ? row[column.prop] : \'\' }}</span><slot name="actions" :row="row" /></div></div>' },
DataTable: { name: 'DataTable', props: ['data', 'columns'], template: '<div><slot name="filters" /><div v-for="row in data" :key="row.id"><span v-for="column in columns" :key="column.key" :data-column="column.key">{{ column.prop ? row[column.prop] : \'\' }}</span><slot name="actions" :row="row" /></div></div>' },
AppDialog: true,
} } })
}
@@ -44,6 +45,15 @@ beforeEach(() => {
})
describe('transport document entry', () => {
it.each(['truck', 'looseboard'] as const)('limits retired status filters only in truck mode (%s)', async domain => {
const wrapper = mountList(domain); await flushPromises()
const status = wrapper.findComponent(QueryToolbar).props('fields').find(field => field.key === 'status')!
const values = status.options!.map(option => option.value)
expect(values.includes('WAITING_CONSOLIDATION')).toBe(domain === 'looseboard')
if (domain === 'truck') for (const value of ['WAITING_INBOUND', 'RECEIVING', 'PALLET_OVERAGE_REVIEW', 'PARTIALLY_ALLOCATED', 'ALLOCATED', 'PENDING_DISPATCH']) expect(values).not.toContain(value)
else expect(values).toContain('WAITING_INBOUND')
expect(status.options!.find(option => option.value === 'IN_TRANSIT')?.label).toBe('派送中')
})
it('lets list-only users open looseboard details without edit permission', async () => {
const wrapper = mountList('looseboard'); await flushPromises()
const actions = wrapper.findComponent(RowActions)
@@ -42,7 +42,7 @@ const page = ref(1); const pageSize = ref(20); const total = ref(0)
const arrangementOpen = ref(false), arrangement = ref<FleetArrangement | null>(null)
function showArrangement(row: LocalTransportOrder | LocalLooseboardOrder) { arrangement.value = row.fleetArrangement; arrangementOpen.value = true }
const filters = ref<QueryModel>({ orderNo: String(route.query.orderNo || ''), status: '', routeKeyword: '' }); const applied = ref({ ...filters.value })
const looseboardStatusLabels: Record<LocalLooseboardStatus, string> = { PENDING_ACCEPTANCE: '待接单', WAITING_INBOUND: '待入仓', RECEIVING: '收货中', WAITING_CONSOLIDATION: '待合托', PENDING_DISPATCH: '待派车', DISPATCHED: '已派车', IN_TRANSIT: '运输中', COMPLETED: '已完成', CANCELLED: '已取消', ...poolOrderStatusLabels }
const looseboardStatusLabels: Record<LocalLooseboardStatus, string> = { PENDING_ACCEPTANCE: '待接单', WAITING_INBOUND: '待入仓', RECEIVING: '收货中', WAITING_CONSOLIDATION: '待合托', PENDING_DISPATCH: '待派车', DISPATCHED: '已派车', IN_TRANSIT: '派送中', COMPLETED: '已完成', CANCELLED: '已取消', ...poolOrderStatusLabels }
const transportTypeLabels: Record<LocalTransportType, string> = { PORT_PICKUP: '港口提柜', WAREHOUSE_TO_WAREHOUSE: '仓到仓', WAREHOUSE_TO_DOOR: '仓到门' }
const statusLabels = computed<Record<string, string>>(() => isLooseboard.value ? looseboardStatusLabels : truckStatusLabels)
const statusTones: Record<LocalTransportStatus | LocalLooseboardStatus, 'warning' | 'primary' | 'success' | 'danger' | 'info'> = {
@@ -53,7 +53,7 @@ const statusTones: Record<LocalTransportStatus | LocalLooseboardStatus, 'warning
}
const fields = computed<QueryField[]>(() => [
{ key: 'orderNo', type: 'input', label: '商业单号', placeholder: '请输入商业单号', width: 230 },
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 170, options: Object.entries(isLooseboard.value ? looseboardStatusLabels : truckStatusLabels).map(([value, label]) => ({ value, label })) },
{ key: 'status', type: 'select', label: '状态', placeholder: '全部状态', width: 170, options: Object.entries(isLooseboard.value ? looseboardStatusLabels : truckStatusLabels).filter(([value]) => isLooseboard.value || !['WAITING_INBOUND', 'RECEIVING', 'WAITING_CONSOLIDATION', 'PALLET_OVERAGE_REVIEW', 'PARTIALLY_ALLOCATED', 'ALLOCATED', 'PENDING_DISPATCH'].includes(value)).map(([value, label]) => ({ value, label })) },
{ key: 'routeKeyword', type: 'input', label: '运输路线', placeholder: '起运地/目的地', width: 240 },
])
const truckColumns: DataTableColumn[] = [
@@ -35,7 +35,7 @@ export const truckCommandHints: Record<TruckCommand, string> = {
'allocate-pallets': '选择本单已实收且未分配的托盘,可分批分配;全部已接收托盘分配完成后才能进入待派车。',
'prepare-dispatch': '确认全部已接收托盘已分配完成,将本单交由调度安排车辆。',
dispatch: '请在车辆安排已实际完成后确认,本单将进入已派车。',
'start-transit': '请在车辆已实际发运后确认,本单将进入运输中。',
'start-transit': '请在车辆已实际发运后确认,本单将进入派送中。',
complete: '请在运输及交付已实际完成后确认。确认完成后不能撤回。',
cancel: '取消后本单不能继续履约,请填写取消原因。',
}