This commit is contained in:
2026-08-22 12:24:15 +08:00
parent 76c71a3e5e
commit 866ea58cab
18 changed files with 59 additions and 32 deletions
@@ -32,6 +32,7 @@ export interface LastMileOrderSummaryDto {
customerId: string
orderNo: string
orderType?: string | null
orderTypeName?: string | null
inboundCode?: string | null
sourceOrderNo?: string | null
sourceInboundId?: string | null
@@ -64,13 +65,13 @@ export interface LastMileOrderSummaryDto {
privateRemark?: string | null
customerRemark?: string | null
warehouseRemark?: string | null
createdAt?: string | null
}
export interface LastMileOrderDto extends LastMileOrderSummaryDto {
customerId: string
sourceOrderNo?: string | null
subOrderStatus?: string | null
createdAt?: string | null
updatedAt?: string | null
}
@@ -32,10 +32,10 @@ const warehouseTab = ref<'ALL' | 'LAX' | 'NYC'>('ALL')
const orderTypeOptions = [
{ value: 'FIRST_LEG', label: '头程订单' },
{ value: 'RELABEL_APPLICATION', label: '换标订单' },
{ value: 'RETURN_RELABEL', label: '退换标单' },
{ value: 'RELABEL_APPLICATION', label: '换标下单' },
{ value: 'RETURN_RELABEL', label: '退货换标' },
{ value: 'LOCAL_LOOSEBOARD', label: '本土散板' },
{ value: 'WAREHOUSE_TRANSFER', label: '仓储转运单' },
{ value: 'WAREHOUSE_TRANSFER', label: '仓储转运' },
]
const planIds = computed(() => [...new Set(props.orders.map((item) => item.planId).filter(Boolean))])
@@ -66,7 +66,7 @@ function palletId(item: DispatchPalletCandidateDto) { return String(item.planPal
function text(value: unknown) { const normalized = String(value ?? '').trim(); return normalized || '—' }
function number(value: unknown, digits = 0) { const normalized = Number(value); return Number.isFinite(normalized) ? normalized.toFixed(digits) : '0' }
function dateTime(value: unknown) { const raw = String(value || '').trim(); return raw ? raw.replace('T', ' ').slice(0, 16) : '—' }
function orderType(value: unknown) { return ({ FIRST_LEG: '头程订单', RELABEL_APPLICATION: '换标订单', RETURN_RELABEL: '退换标单', LOCAL_LOOSEBOARD: '本土散板', WAREHOUSE_TRANSFER: '仓储转运单', ONE_CLICK_DROPSHIP: '一件代发', REJECTED: '拒收订单', EXPRESS: '快递订单' } as Record<string, string>)[String(value || '')] || text(value) }
function orderType(value: unknown) { return ({ FIRST_LEG: '头程订单', RELABEL_APPLICATION: '换标下单', RETURN_RELABEL: '退货换标', LOCAL_LOOSEBOARD: '本土散板', WAREHOUSE_TRANSFER: '仓储转运', ONE_CLICK_DROPSHIP: '一件代发', REJECTED: '拒收订单', EXPRESS: '快递订单' } as Record<string, string>)[String(value || '')] || text(value) }
function cartonMarks(item: DispatchPalletCandidateDto) { return String(item.cartonMarks || '').split(',').map((value) => value.trim()).filter(Boolean) }
function containerFor(id: string) { return containers.value.find((item) => item.palletIds.includes(id)) }
function palletSnapshot(id: string) { return palletSnapshots.value[id] }
@@ -13,4 +13,14 @@ describe('last-mile order presentation adapter', () => {
})
expect(row.rejectedAt).toBe('—')
})
it.each([
['RELABEL_APPLICATION', '换标下单'],
['WAREHOUSE_TRANSFER', '仓储转运'],
['RETURN_RELABEL', '退货换标'],
['LOCAL_LOOSEBOARD', '本土散板'],
])('maps %s to its Chinese display name', (orderType, expected) => {
const row = toLastMileOrderListItem({ id: '1', customerId: '100', orderNo: 'LL-1', orderType })
expect(row.orderType).toBe(expected)
})
})
@@ -3,7 +3,11 @@ import type { LastMileOrderListItem } from './types'
const orderTypeLabels: Record<string, string> = {
ONE_CLICK_DROPSHIP: '一件代发',
FIRST_LEG: '头程',
FIRST_LEG: '头程订单',
RELABEL_APPLICATION: '换标下单',
WAREHOUSE_TRANSFER: '仓储转运',
RETURN_RELABEL: '退货换标',
LOCAL_LOOSEBOARD: '本土散板',
REJECTED: '拒收订单',
EXPRESS: '快递订单',
}
@@ -54,7 +58,7 @@ export function toLastMileOrderListItem(dto: LastMileOrderSummaryDto): LastMileO
customerId: String(dto.customerId),
orderNo: text(dto.orderNo),
warning: dto.abnormal ? '异常' : '—',
orderType: lastMileOrderTypeLabel(dto.orderType),
orderType: text(dto.orderTypeName || lastMileOrderTypeLabel(dto.orderType)),
rejectedAt: '—',
inboundCode: text(dto.inboundCode),
owner: text(dto.customerName),
@@ -83,5 +87,6 @@ export function toLastMileOrderListItem(dto: LastMileOrderSummaryDto): LastMileO
internalRemark: text(dto.privateRemark),
customerRemark: text(dto.customerRemark),
warehouseRemark: text(dto.warehouseRemark),
createdAt: formatOverseasDateTime(dto.createdAt),
}
}
@@ -16,7 +16,7 @@ const access = useAccessPreviewStore()
const router = useRouter()
const rows = ref<CartonListItem[]>([])
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const filters = ref<QueryModel>({ cartonNo: '', fbaWarehouse: '', status: '' })
const fields: QueryField[] = [
{ key: 'cartonNo', type: 'input', label: '箱号', placeholder: '请输入箱号', width: 190 },
@@ -49,7 +49,7 @@ describe('DispatchesView', () => {
it('loads immediately and sends only supported page filters', async () => {
const wrapper = mount(DispatchesView, { global: { plugins: [ElementPlus] } })
await flushPromises()
expect(listDispatches).toHaveBeenCalledWith({ page: 1, size: 20, dispatchNo: undefined, vehiclePlate: undefined, status: undefined, fbaAppointmentNo: undefined })
expect(listDispatches).toHaveBeenCalledWith({ page: 1, size: 10, dispatchNo: undefined, vehiclePlate: undefined, status: undefined, fbaAppointmentNo: undefined })
const model: QueryModel = {
dispatchNo: 'PC-1', vehiclePlate: 'CA-100',
@@ -59,7 +59,7 @@ describe('DispatchesView', () => {
await flushPromises()
expect(listDispatches).toHaveBeenCalledWith({
page: 1, size: 20, dispatchNo: 'PC-1',
page: 1, size: 10, dispatchNo: 'PC-1',
vehiclePlate: 'CA-100', status: 'PENDING_DEPARTURE', fbaAppointmentNo: 'FBA-1',
})
expect(wrapper.text()).toContain('PC-1')
@@ -12,13 +12,14 @@ import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/compone
import StatusBadge from '@/shared/components/StatusBadge.vue'
import { listDispatches, type DispatchSummaryDto } from '../api/dispatches'
import type { DispatchListItem } from '../types'
import { formatOverseasDateTime } from '../lastMilePresentation'
const router = useRouter()
const rows = ref<DispatchListItem[]>([])
const loading = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const filters = ref<QueryModel>({ dispatchNo: '', vehiclePlate: '', status: '', fbaAppointmentNo: '' })
@@ -99,7 +100,7 @@ function toListItem(dto: DispatchSummaryDto): DispatchListItem {
status: statusLabel(dto.status),
palletCount: number(dto.palletCount),
packageCount: number(dto.packageCount),
createdAt: text(dto.createdAt),
createdAt: formatOverseasDateTime(dto.createdAt),
}
}
@@ -16,6 +16,7 @@ import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/compone
import SmartDispatchDialog from '../components/SmartDispatchDialog.vue'
import { createFbaAppointment, getFbaAppointment, listInboundOrders, updateFbaAppointment, type InboundOrderSummaryDto } from '../api/inboundOrders'
import { overseasWarehousePermissions as permission } from '../permissions'
import { formatOverseasDateTime, lastMileOrderTypeLabel } from '../lastMilePresentation'
import type { InboundOrderListItem } from '../types'
const access = useAccessPreviewStore()
@@ -27,7 +28,7 @@ const saving = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const mutationError = ref<ApiErrorDetails | null>(null)
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const filters = ref<QueryModel>({ orderNo: '', inboundCode: '', status: '', warehouse: '', fbaWarehouse: '', appointmentStatus: '', dispatchStatus: '', inboundDate: [] })
const fields = computed<QueryField[]>(() => [
@@ -74,11 +75,12 @@ const columns: DataTableColumn[] = [
{ key: 'status', prop: 'status', label: '状态', width: 100 },
{ key: 'appointmentStatus', prop: 'appointmentStatus', label: 'FBA预约', width: 110 },
{ key: 'dispatchStatus', prop: 'dispatchStatus', label: '排车状态', width: 110 },
{ key: 'createdAt', prop: 'createdAt', label: '创建时间', minWidth: 170 },
]
function text(value: unknown) { const normalized = String(value ?? '').trim(); return normalized || '—' }
function number(value: unknown) { const normalized = Number(value); return Number.isFinite(normalized) ? normalized : 0 }
function typeLabel(value: unknown) { return ({ ONE_CLICK_DROPSHIP: '一件代发', FIRST_LEG: '头程', REJECTED: '拒收订单', EXPRESS: '快递订单' } as Record<string, string>)[String(value || '')] || text(value) }
function typeLabel(value: unknown) { return lastMileOrderTypeLabel(value) }
function planStatusLabel(value: unknown) { return ({ PENDING_ASSIGNMENT: '待分配', IN_PROGRESS: '入库中', COMPLETED: '已完成' } as Record<string, string>)[String(value || '')] || text(value) }
function appointmentStatusLabel(value: unknown) { return !value ? '未预约' : ({ PENDING: '预约中', SUCCESS: '预约成功', FAILED: '预约失败', CANCELLED: '已取消' } as Record<string, string>)[String(value)] || text(value) }
@@ -90,6 +92,7 @@ function toListItem(dto: InboundOrderSummaryDto): InboundOrderListItem {
fbaWarehouse: text(dto.fbaWarehouseCode), owner: text(dto.customerName), cartons: number(dto.packageCount), volume: number(dto.volumeCbm), pallets: number(dto.palletCount),
status: planStatusLabel(dto.status), appointmentNo: text(dto.appointmentNo), appointmentStatus: appointmentStatusLabel(dto.appointmentStatus),
appointmentAt: text(dto.appointmentAt), expectedLoadingAt: text(dto.expectedLoadingAt), dispatchStatus: dto.dispatchStatus === 'SCHEDULED' ? '已排车' : '未排车',
createdAt: formatOverseasDateTime(dto.createdAt),
}
}
@@ -6,7 +6,7 @@ import { getApiErrorDetails, type ApiErrorDetails } from '@/shared/api/http'
import AdminPage from '@/shared/components/AdminPage.vue'; import ApiErrorMeta from '@/shared/components/ApiErrorMeta.vue'; import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'; import ListPageLayout from '@/shared/components/ListPageLayout.vue'; import LoadErrorState from '@/shared/components/LoadErrorState.vue'; import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
import { listInventoryLedger } from '../api/inventory'; import { formatOverseasDateTime } from '../lastMilePresentation'; import type { InventoryTransactionListItem } from '../types'
const route = useRoute(); const router = useRouter(); const rows = ref<InventoryTransactionListItem[]>([]); const page = ref(1); const pageSize = ref(20); const total = ref(0); const loading = ref(false); const loadError = ref<ApiErrorDetails | null>(null)
const route = useRoute(); const router = useRouter(); const rows = ref<InventoryTransactionListItem[]>([]); const page = ref(1); const pageSize = ref(10); const total = ref(0); const loading = ref(false); const loadError = ref<ApiErrorDetails | null>(null)
const filters = ref<QueryModel>({ occurredDate: [], warehouse: '', sku: '', businessType: '', businessOrderNo: '', inboundOrderNo: '', outboundOrderNo: '' })
const fields = computed<QueryField[]>(() => [
{ key: 'occurredDate', type: 'daterange', label: '发生日期', width: 260 },
@@ -25,7 +25,7 @@ const loading = ref(false)
const contextLoading = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const filters = ref<QueryModel>({ warehouseId: '', owner: '', sku: '', productName: '', batchNo: '', location: '', status: '' })
const fields = computed<QueryField[]>(() => [
@@ -28,7 +28,7 @@ const referenceValue = computed(() => text(detail.value?.order.orderNo || orderI
const orderFields = computed<DetailField[]>(() => {
const order = detail.value?.order
return [
{ label: '订单类型', value: lastMileOrderTypeLabel(order?.orderType) },
{ label: '订单类型', value: text(order?.orderTypeName || lastMileOrderTypeLabel(order?.orderType)) },
{ label: '拒收时间', value: '—' },
{ label: '实际入库时间', value: '—' },
{ label: '头程单号', value: text(order?.sourceOrderNo) },
@@ -47,7 +47,7 @@ const orderFields = computed<DetailField[]>(() => {
const detailFields = computed<DetailField[]>(() => {
const order = detail.value?.order
return [
{ label: '订单类型', value: lastMileOrderTypeLabel(order?.orderType) },
{ label: '订单类型', value: text(order?.orderTypeName || lastMileOrderTypeLabel(order?.orderType)) },
{ label: '入仓码', value: text(order?.inboundCode) },
{ label: '目的仓', value: text(order?.transferWarehouseName) },
{ label: '托数', value: Number(order?.palletCount || 0) },
@@ -24,7 +24,7 @@ const loading = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const router = useRouter()
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const selectedRows = ref<LastMileOrderListItem[]>([])
const actionLoading = ref(false)
@@ -37,8 +37,8 @@ const fields = computed<QueryField[]>(() => [
{ key: 'orderNo', type: 'input', label: '尾程单号', placeholder: '请输入尾程单号' },
{ key: 'inboundCode', type: 'input', label: '入仓码', placeholder: '请输入入仓码' },
{ key: 'orderType', type: 'select', label: '订单类型', placeholder: '全部类型', options: [
{ label: '头程', value: 'FIRST_LEG' }, { label: '换标申请', value: 'RELABEL_APPLICATION' },
{ label: '转仓', value: 'WAREHOUSE_TRANSFER' }, { label: '本地拆板', value: 'LOCAL_LOOSEBOARD' },
{ label: '头程订单', value: 'FIRST_LEG' }, { label: '换标下单', value: 'RELABEL_APPLICATION' },
{ label: '仓储转运', value: 'WAREHOUSE_TRANSFER' }, { label: '本土散板', value: 'LOCAL_LOOSEBOARD' },
{ label: '退货换标', value: 'RETURN_RELABEL' }, { label: '一件代发', value: 'ONE_CLICK_DROPSHIP' },
] },
{ key: 'warehouse', type: 'input', label: '海外仓', placeholder: '请输入仓库名称或编码' },
@@ -87,6 +87,7 @@ const columns: DataTableColumn[] = [
{ key: 'relabelStatus', prop: 'relabelStatus', label: '换标状态', width: 110 },
{ key: 'consolidated', prop: 'consolidated', label: '合托标记', width: 100 },
{ key: 'status', prop: 'status', label: '当前状态', width: 110 },
{ key: 'createdAt', prop: 'createdAt', label: '创建时间', minWidth: 170 },
{ key: 'internalRemark', prop: 'internalRemark', label: '备注(仅自己)', minWidth: 160 },
{ key: 'customerRemark', prop: 'customerRemark', label: '备注(客户)', minWidth: 160 },
{ key: 'warehouseRemark', prop: 'warehouseRemark', label: '备注(仓库)', minWidth: 160 },
@@ -31,7 +31,7 @@ const loadError = ref<ApiErrorDetails | null>(null)
const mutationError = ref<ApiErrorDetails | null>(null)
const loadErrorKind = ref<'context' | 'list'>('context')
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const filters = ref<QueryModel>({ warehouseId: '', code: '', type: '', status: '' })
const fields = computed<QueryField[]>(() => [
@@ -16,7 +16,7 @@ const access = useAccessPreviewStore()
const router = useRouter()
const rows = ref<ProductListItem[]>([])
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const filters = ref<QueryModel>({ sku: '', productName: '', category: '' })
const fields: QueryField[] = [
{ key: 'sku', type: 'input', label: '商品SKU', placeholder: '请输入商品SKU', width: 180 },
@@ -15,6 +15,7 @@ import AppDialog from '@/shared/components/AppDialog.vue'
import { changeRelabelOrderStatus, createRelabelOrder, listRelabelOrders } from '../api/relabelOrders'
import { listCustomerWarehouses, type CustomerWarehouseDto } from '../api/pallets'
import { overseasWarehousePermissions as permission } from '../permissions'
import { formatOverseasDateTime } from '../lastMilePresentation'
import type { RelabelOrderListItem } from '../types'
const access = useAccessPreviewStore()
@@ -24,7 +25,7 @@ const loading = ref(false)
const loadError = ref<ApiErrorDetails | null>(null)
const warehouses = ref<CustomerWarehouseDto[]>([])
const page = ref(1)
const pageSize = ref(20)
const pageSize = ref(10)
const total = ref(0)
const filters = ref<QueryModel>({ sku: '', status: '' })
const fields = computed<QueryField[]>(() => [
@@ -41,6 +42,7 @@ const columns: DataTableColumn[] = [
{ key: 'labelRequirement', label: '贴标要求', minWidth: 150 },
{ key: 'fileName', label: '上传文件', minWidth: 160 },
{ key: 'status', label: '状态', width: 110 },
{ key: 'createdAt', label: '创建时间', minWidth: 170 },
]
const dialogOpen = ref(false)
const dialogMode = ref<'create' | 'edit'>('create')
@@ -96,6 +98,7 @@ async function load(model: QueryModel = filters.value) {
rows.value = result.records.map((item) => ({
customerId: '', orderNo: String(item.relabelNo), relatedOrderNo: String(item.lastlegOrderNo || item.customerOrderNo || '—'), sku: String(item.skuCodes || '—'),
productName: '—', cartons: Number(item.totalPackageCount || 0), budgetTotal: null, labelRequirement: '—', fileName: '—', status: relabelStatus(item.status), remark: '',
createdAt: formatOverseasDateTime(item.createdAt),
}))
total.value = result.total
} catch (error) { rows.value = []; total.value = 0; loadError.value = getApiErrorDetails(error, '换标单加载失败,请重试') }
@@ -198,7 +198,7 @@ describe('overseas warehouse first-batch prototype contract', () => {
]) {
const value = source(fileName)
expect(value).toContain('const page = ref(1)')
expect(value).toContain('const pageSize = ref(20)')
expect(value).toContain('const pageSize = ref(10)')
expect(value).toContain('const total = ref(0)')
expect(value).toContain('page: page.value')
expect(value).toContain('size: pageSize.value')
@@ -234,10 +234,10 @@ describe('overseas warehouse first-batch prototype contract', () => {
expect(dialog).toContain('洛杉矶')
expect(dialog).toContain('纽约')
expect(dialog).toContain("value: 'ALL', label: '全部'")
expect(dialog).toContain('换标订单')
expect(dialog).toContain('退换标单')
expect(dialog).toContain('换标下单')
expect(dialog).toContain('退货换标')
expect(dialog).toContain('本土散板')
expect(dialog).toContain('仓储转运单')
expect(dialog).toContain('仓储转运')
expect(dialog).toContain('class="warehouse-tabs"')
expect(dialog).not.toContain('排车路线(选填)')
expect(dialog).not.toContain('v-model="route"')
@@ -322,18 +322,18 @@ describe('overseas warehouse first-batch prototype contract', () => {
'transferWarehouse', 'fbaWarehouse', 'containerNo', 'abnormal', 'held', 'pallets',
'cartons', 'volume', 'quantity', 'volumeWeight', 'portEta', 'portAta', 'warehouseEta', 'inboundOrderNo',
'outboundOrderNo', 'dispatchOrderNo', 'relabelOrderNo', 'relabelStatus', 'consolidated', 'status',
'internalRemark', 'customerRemark', 'warehouseRemark',
'createdAt', 'internalRemark', 'customerRemark', 'warehouseRemark',
])
expect(columnKeys('InboundOrdersView.vue')).toEqual([
'actions', 'selection', 'orderNo', 'inboundCode', 'type', 'warehouse', 'fbaWarehouse', 'owner', 'cartons', 'volume',
'pallets', 'status', 'appointmentStatus', 'dispatchStatus',
'pallets', 'status', 'appointmentStatus', 'dispatchStatus', 'createdAt',
])
expect(columnKeys('InventoryView.vue')).toEqual([
'actions', 'owner', 'warehouse', 'sku', 'productName', 'location', 'onHand', 'available', 'held', 'looseboard',
'inTransit', 'updatedAt',
])
expect(columnKeys('RelabelOrdersView.vue')).toEqual([
'actions', 'orderNo', 'sku', 'productName', 'cartons', 'budgetTotal', 'labelRequirement', 'fileName', 'status',
'actions', 'orderNo', 'sku', 'productName', 'cartons', 'budgetTotal', 'labelRequirement', 'fileName', 'status', 'createdAt',
])
expect(columnKeys('PalletsView.vue')).toEqual([
'actions', 'code', 'type', 'warehouse', 'volume', 'purchasePrice', 'fbaWarehouse', 'status', 'remark',
@@ -24,5 +24,5 @@ describe('overseas warehouse mounted real API pages', () => {
vi.mocked(listInventoryLedger).mockReset().mockResolvedValue({ records: [{ id: '9007199254740997', customerId: '10001', destinationWarehouseCode: 'LAX', inboundOrderNo: 'IP-1', businessType: 'STOCK_IN', beforePackages: 0, deltaPackages: 10, afterPackages: 10, occurredAt: '2026-08-20T10:00:00' }], page: 1, size: 20, total: 1, pages: 1 })
})
it('mounts inbound detail with a string-safe source order id', async () => { routing.route.params = { orderId: 'IP-1' }; routing.route.query = { customerId: '10001' }; const wrapper = mount(InboundOrderDetailView, { global: { plugins: [ElementPlus] } }); await flushPromises(); expect(getInboundPlan).toHaveBeenCalledWith('IP-1', '10001'); expect(wrapper.text()).toContain('9007199254740995'); expect(wrapper.text()).toContain('洛杉矶仓') })
it('mounts inventory ledger as read-only facts', async () => { const wrapper = mount(InventoryTransactionsView, { global: { plugins: [ElementPlus] } }); await flushPromises(); expect(listInventoryLedger).toHaveBeenCalledWith(expect.objectContaining({ page: 1, size: 20 })); expect(listInventoryLedger).not.toHaveBeenCalledWith(expect.objectContaining({ customerId: expect.anything() })); expect(wrapper.text()).toContain('IP-1'); expect(wrapper.text()).toContain('10'); expect(wrapper.text()).toContain('不提供出库单跳转') })
it('mounts inventory ledger as read-only facts', async () => { const wrapper = mount(InventoryTransactionsView, { global: { plugins: [ElementPlus] } }); await flushPromises(); expect(listInventoryLedger).toHaveBeenCalledWith(expect.objectContaining({ page: 1, size: 10 })); expect(listInventoryLedger).not.toHaveBeenCalledWith(expect.objectContaining({ customerId: expect.anything() })); expect(wrapper.text()).toContain('IP-1'); expect(wrapper.text()).toContain('10'); expect(wrapper.text()).toContain('不提供出库单跳转') })
})
+3
View File
@@ -39,6 +39,7 @@ export interface LastMileOrderListItem {
internalRemark: string
customerRemark: string
warehouseRemark: string
createdAt: string
}
export interface InboundOrderListItem {
@@ -63,6 +64,7 @@ export interface InboundOrderListItem {
appointmentAt: string
expectedLoadingAt: string
dispatchStatus: string
createdAt: string
}
export interface DispatchListItem {
@@ -119,6 +121,7 @@ export interface RelabelOrderListItem {
fileName: string
status: string
remark: string
createdAt: string
}
export interface PalletListItem {