This commit is contained in:
2026-08-04 12:57:50 +08:00
parent 3dcc8b30db
commit 6354f5ca66
4 changed files with 139 additions and 38 deletions
@@ -24,18 +24,30 @@ describe('platform first-leg order API', () => {
vi.mocked(http.put).mockReset() vi.mocked(http.put).mockReset()
}) })
it('queries a tenant-scoped order page with server pagination and filters', async () => { it('queries the cross-tenant review queue with one server-paginated request', async () => {
const page = { records: [], page: 2, size: 20, total: 0, pages: 0 } const page = { records: [], page: 2, size: 20, total: 0, pages: 0 }
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: page }) vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: page })
await expect(listPlatformFirstLegOrders('10001', { await expect(listPlatformFirstLegOrders({
keyword: 'FL2026', status: 'SUBMITTED', createdFrom: '2026-07-01T00:00:00', createdTo: '2026-07-31T23:59:59', page: 2, size: 20, keyword: 'FL2026', status: 'SUBMITTED', createdFrom: '2026-07-01T00:00:00', createdTo: '2026-07-31T23:59:59', page: 2, size: 20,
})).resolves.toEqual(page) })).resolves.toEqual(page)
expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/first-leg', { expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/first-leg', {
params: { params: {
tenantId: '10001', keyword: 'FL2026', status: 'SUBMITTED', createdFrom: '2026-07-01T00:00:00', createdTo: '2026-07-31T23:59:59', page: 2, size: 20, keyword: 'FL2026', status: 'SUBMITTED', createdFrom: '2026-07-01T00:00:00', createdTo: '2026-07-31T23:59:59', page: 2, size: 20,
}, },
}) })
expect(http.get).toHaveBeenCalledTimes(1)
})
it('adds the optional enterprise filter without changing server pagination', async () => {
const page = { records: [], page: 1, size: 20, total: 0, pages: 0 }
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: page })
await listPlatformFirstLegOrders({ tenantId: '2084455952401629185', status: 'SUBMITTED', page: 1, size: 20 })
expect(http.get).toHaveBeenCalledWith('/platform/v1/orders/first-leg', {
params: { tenantId: '2084455952401629185', status: 'SUBMITTED', page: 1, size: 20 },
})
}) })
it('uses the platform lifecycle routes and target tenant query parameter', async () => { it('uses the platform lifecycle routes and target tenant query parameter', async () => {
@@ -106,6 +106,7 @@ export interface PlatformFirstLegOrderPageResource {
} }
export interface PlatformFirstLegOrderQuery { export interface PlatformFirstLegOrderQuery {
tenantId?: string
keyword?: string keyword?: string
status?: PlatformFirstLegOrderStatus status?: PlatformFirstLegOrderStatus
customerId?: string customerId?: string
@@ -126,8 +127,8 @@ async function postData<T>(path: string, body?: unknown, params?: Record<string,
return unwrapApiResponse(response) return unwrapApiResponse(response)
} }
export function listPlatformFirstLegOrders(tenantId: string, query: PlatformFirstLegOrderQuery) { export function listPlatformFirstLegOrders(query: PlatformFirstLegOrderQuery) {
return getData<PlatformFirstLegOrderPageResource>('/platform/v1/orders/first-leg', { tenantId, ...query }) return getData<PlatformFirstLegOrderPageResource>('/platform/v1/orders/first-leg', { ...query })
} }
export function getPlatformFirstLegOrder(tenantId: string, orderId: string) { export function getPlatformFirstLegOrder(tenantId: string, orderId: string) {
@@ -0,0 +1,34 @@
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
const source = readFileSync(resolve(process.cwd(), 'src/modules/first-leg-orders/components/PlatformFirstLegOrdersPanel.vue'), 'utf8')
describe('PlatformFirstLegOrdersPanel review queue', () => {
it('loads one cross-tenant page by default and keeps enterprise as an optional filter', () => {
expect(source).toContain("status: 'SUBMITTED'")
expect(source).toContain("tenantId: filters.value.tenantId || undefined")
expect(source).toContain('listPlatformTenants')
expect(source).toContain("key: 'tenantId'")
expect(source).toContain('tenantName((row as PlatformFirstLegOrderResource).tenantId)')
expect(source).toContain('result.pages')
})
it('does not retain the historical fixed tenant', () => {
expect(source).not.toContain('PlatformTenantSelector')
expect(source).not.toContain('selectedTenantId')
})
it('resets to the pending review queue instead of all statuses', () => {
expect(source).toContain(':search-on-reset="false"')
expect(source).toContain("filters.value = { ...filters.value, status: 'SUBMITTED' }")
expect(source).toContain('await nextTick()')
})
it('passes the order tenant through detail and lifecycle actions', () => {
expect(source).toContain('tenantId: String(order.tenantId)')
expect(source).toContain('getPlatformFirstLegOrder(tenantId, orderId)')
expect(source).toContain('approvePlatformFirstLegOrder(tenantId, String(order.id))')
expect(source).not.toContain('loadedTenantId.value')
})
})
@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, reactive, ref, watch } from 'vue' import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus'
import { ArrowLeft, Eye, FilePenLine, PackageCheck } from '@lucide/vue' import { ArrowLeft, Eye, FilePenLine, PackageCheck } from '@lucide/vue'
@@ -24,13 +24,14 @@ import StatusBadge from '@/shared/components/StatusBadge.vue'
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue' import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue' import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
import { useAccessPreviewStore } from '@/core/access/accessPreview' import { useAccessPreviewStore } from '@/core/access/accessPreview'
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
const PHASE_ONE_TENANT_ID = '10001'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const access = useAccessPreviewStore() const access = useAccessPreviewStore()
const loadedTenantId = ref(PHASE_ONE_TENANT_ID)
const orders = ref<PlatformFirstLegOrderResource[]>([]) const orders = ref<PlatformFirstLegOrderResource[]>([])
const tenants = ref<PlatformTenantResource[]>([])
const tenantLoadError = ref<ApiErrorDetails | null>(null)
const total = ref(0) const total = ref(0)
const page = ref(1) const page = ref(1)
const pageSize = ref(20) const pageSize = ref(20)
@@ -49,17 +50,26 @@ const expressFormRef = ref<FormInstance>()
const noteFormRef = ref<FormInstance>() const noteFormRef = ref<FormInstance>()
const expressForm = reactive({ expressCompany: '', expressTrackingNo: '' }) const expressForm = reactive({ expressCompany: '', expressTrackingNo: '' })
const filters = ref<QueryModel & { const filters = ref<QueryModel & {
tenantId: string
keyword: string keyword: string
status: PlatformFirstLegOrderStatus | '' status: PlatformFirstLegOrderStatus | ''
dateRange: string[] dateRange: string[]
}>({ }>({
tenantId: '',
keyword: '', keyword: '',
status: '', status: 'SUBMITTED',
dateRange: [], dateRange: [],
}) })
const queryFields: QueryField[] = [ const queryFields = computed<QueryField[]>(() => [
{ key: 'keyword', type: 'input', placeholder: '订单号或客户名称', props: { 'aria-label': '订单关键词' } }, {
key: 'tenantId',
type: 'select',
placeholder: tenantLoadError.value ? '企业列表加载失败' : '全部企业',
props: { 'aria-label': '企业客户', filterable: true, disabled: Boolean(tenantLoadError.value) },
options: tenants.value.map((tenant) => ({ value: String(tenant.id), label: `${tenant.tenantName}(${tenant.tenantCode || tenant.id})` })),
},
{ key: 'keyword', type: 'input', placeholder: '订单号或发货客户名称', props: { 'aria-label': '订单关键词' } },
{ {
key: 'status', key: 'status',
type: 'select', type: 'select',
@@ -77,7 +87,7 @@ const queryFields: QueryField[] = [
], ],
}, },
{ key: 'dateRange', type: 'daterange', props: { 'aria-label': '订单创建日期' } }, { key: 'dateRange', type: 'daterange', props: { 'aria-label': '订单创建日期' } },
] ])
const orderColumns: DataTableColumn[] = [ const orderColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', minWidth: 200, fixed: 'left', slotName: 'actions' }, { key: 'actions', label: '操作', minWidth: 200, fixed: 'left', slotName: 'actions' },
@@ -102,11 +112,14 @@ const noteRules: FormRules = {
content: [{ required: true, message: '请填写内部备注', trigger: 'blur' }], content: [{ required: true, message: '请填写内部备注', trigger: 'blur' }],
} }
const tenantReady = computed(() => loadedTenantId.value === PHASE_ONE_TENANT_ID)
const detailOrderId = computed(() => { const detailOrderId = computed(() => {
const orderId = route.query.orderId const orderId = route.query.orderId
return typeof orderId === 'string' && orderId ? orderId : '' return typeof orderId === 'string' && orderId ? orderId : ''
}) })
const detailTenantId = computed(() => {
const tenantId = route.query.tenantId
return typeof tenantId === 'string' && tenantId ? tenantId : ''
})
const isDetailPage = computed(() => Boolean(detailOrderId.value)) const isDetailPage = computed(() => Boolean(detailOrderId.value))
const statusOptions: Array<{ value: PlatformFirstLegOrderStatus; label: string }> = [ const statusOptions: Array<{ value: PlatformFirstLegOrderStatus; label: string }> = [
@@ -135,6 +148,29 @@ function formattedDate(value: string | null | undefined) {
return value ? value.replace('T', ' ') : '-' return value ? value.replace('T', ' ') : '-'
} }
function tenantName(tenantId: number | string) {
return tenants.value.find((tenant) => String(tenant.id) === String(tenantId))?.tenantName || `企业 ${tenantId}`
}
async function loadTenants() {
tenantLoadError.value = null
try {
const records: PlatformTenantResource[] = []
let currentPage = 1
let pages = 1
do {
const result = await listPlatformTenants({ page: currentPage, size: 200 })
records.push(...result.records)
pages = Math.max(1, result.pages)
currentPage += 1
} while (currentPage <= pages)
tenants.value = records
} catch (error) {
tenants.value = []
tenantLoadError.value = getApiErrorDetails(error, '企业列表加载失败,暂时无法按企业筛选;订单仍可正常审核')
}
}
function can(action: string) { function can(action: string) {
return access.can(action) return access.can(action)
} }
@@ -152,11 +188,11 @@ function actionLabel(order: PlatformFirstLegOrderResource) {
} }
async function loadOrders() { async function loadOrders() {
const targetTenantId = PHASE_ONE_TENANT_ID
loadError.value = null loadError.value = null
loading.value = true loading.value = true
try { try {
const result = await listPlatformFirstLegOrders(targetTenantId, { const result = await listPlatformFirstLegOrders({
tenantId: filters.value.tenantId || undefined,
keyword: filters.value.keyword.trim() || undefined, keyword: filters.value.keyword.trim() || undefined,
status: filters.value.status || undefined, status: filters.value.status || undefined,
createdFrom: filters.value.dateRange.length === 2 ? `${filters.value.dateRange[0]}T00:00:00` : undefined, createdFrom: filters.value.dateRange.length === 2 ? `${filters.value.dateRange[0]}T00:00:00` : undefined,
@@ -166,7 +202,6 @@ async function loadOrders() {
}) })
orders.value = result.records orders.value = result.records
total.value = result.total total.value = result.total
loadedTenantId.value = targetTenantId
} catch (error) { } catch (error) {
orders.value = [] orders.value = []
total.value = 0 total.value = 0
@@ -184,22 +219,34 @@ function searchOrders() {
void loadOrders() void loadOrders()
} }
async function resetOrders() {
filters.value = { ...filters.value, status: 'SUBMITTED' }
await nextTick()
searchOrders()
}
watch([page, pageSize], () => { watch([page, pageSize], () => {
void loadOrders() void loadOrders()
}) })
async function openDetail(order: PlatformFirstLegOrderResource) { async function openDetail(order: PlatformFirstLegOrderResource) {
if (!tenantReady.value) return
selectedOrder.value = order selectedOrder.value = order
await router.push({ path: route.path, query: { ...route.query, orderId: String(order.id) } }) await router.push({
path: route.path,
query: { ...route.query, orderId: String(order.id), tenantId: String(order.tenantId) },
})
} }
async function loadDetail(orderId: string) { async function loadDetail(orderId: string, tenantId = detailTenantId.value) {
if (!tenantReady.value) return if (!tenantId) {
detail.value = null
ElMessage.error('订单详情缺少企业租户标识,请从订单列表重新打开')
return
}
detail.value = null detail.value = null
detailLoading.value = true detailLoading.value = true
try { try {
detail.value = await getPlatformFirstLegOrder(loadedTenantId.value, orderId) detail.value = await getPlatformFirstLegOrder(tenantId, orderId)
selectedOrder.value = detail.value.order selectedOrder.value = detail.value.order
} catch (error) { } catch (error) {
const details = getApiErrorDetails(error, '订单详情加载失败') const details = getApiErrorDetails(error, '订单详情加载失败')
@@ -217,7 +264,7 @@ async function refreshAfterAction(orderId: string) {
} }
function closeDetailPage() { function closeDetailPage() {
const { orderId: _orderId, ...query } = route.query const { orderId: _orderId, tenantId: _tenantId, ...query } = route.query
void router.replace({ path: route.path, query }) void router.replace({ path: route.path, query })
} }
@@ -233,7 +280,6 @@ function getFieldValidationMessage(error: unknown, field: string, fallback: stri
} }
async function runLifecycleAction(order: PlatformFirstLegOrderResource) { async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
if (!tenantReady.value) return
const label = actionLabel(order) const label = actionLabel(order)
if (!label) return if (!label) return
try { try {
@@ -243,10 +289,11 @@ async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
type: 'warning', type: 'warning',
}) })
actionLoadingId.value = String(order.id) actionLoadingId.value = String(order.id)
if (order.status === 'SUBMITTED') await approvePlatformFirstLegOrder(loadedTenantId.value, String(order.id)) const tenantId = String(order.tenantId)
if (order.status === 'APPROVED') await acceptPlatformFirstLegOrder(loadedTenantId.value, String(order.id)) if (order.status === 'SUBMITTED') await approvePlatformFirstLegOrder(tenantId, String(order.id))
if (order.status === 'ACCEPTED') await startPlatformFirstLegOrder(loadedTenantId.value, String(order.id)) if (order.status === 'APPROVED') await acceptPlatformFirstLegOrder(tenantId, String(order.id))
if (order.status === 'PROCESSING') await completePlatformFirstLegOrder(loadedTenantId.value, String(order.id)) if (order.status === 'ACCEPTED') await startPlatformFirstLegOrder(tenantId, String(order.id))
if (order.status === 'PROCESSING') await completePlatformFirstLegOrder(tenantId, String(order.id))
await refreshAfterAction(String(order.id)) await refreshAfterAction(String(order.id))
ElMessage.success(`${label}已完成`) ElMessage.success(`${label}已完成`)
} catch (error) { } catch (error) {
@@ -258,7 +305,6 @@ async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
} }
async function cancelOrder(order: PlatformFirstLegOrderResource) { async function cancelOrder(order: PlatformFirstLegOrderResource) {
if (!tenantReady.value) return
try { try {
const result = await ElMessageBox.prompt('请填写取消原因。后端要求该字段必填,并将写入订单状态历史。', '取消订单', { const result = await ElMessageBox.prompt('请填写取消原因。后端要求该字段必填,并将写入订单状态历史。', '取消订单', {
confirmButtonText: '确认取消', confirmButtonText: '确认取消',
@@ -268,7 +314,7 @@ async function cancelOrder(order: PlatformFirstLegOrderResource) {
inputPlaceholder: '例如:客户取消本次运输安排', inputPlaceholder: '例如:客户取消本次运输安排',
}) })
actionLoadingId.value = String(order.id) actionLoadingId.value = String(order.id)
await cancelPlatformFirstLegOrder(loadedTenantId.value, String(order.id), result.value.trim()) await cancelPlatformFirstLegOrder(String(order.tenantId), String(order.id), result.value.trim())
await refreshAfterAction(String(order.id)) await refreshAfterAction(String(order.id))
ElMessage.success('订单已取消') ElMessage.success('订单已取消')
} catch (error) { } catch (error) {
@@ -288,12 +334,12 @@ function openExpress(order: PlatformFirstLegOrderResource) {
} }
async function saveExpress() { async function saveExpress() {
if (!selectedOrder.value || !tenantReady.value) return if (!selectedOrder.value) return
const valid = await expressFormRef.value?.validate().catch(() => false) const valid = await expressFormRef.value?.validate().catch(() => false)
if (!valid) return if (!valid) return
expressSaving.value = true expressSaving.value = true
try { try {
await updatePlatformFirstLegOrderExpress(loadedTenantId.value, String(selectedOrder.value.id), { await updatePlatformFirstLegOrderExpress(String(selectedOrder.value.tenantId), String(selectedOrder.value.id), {
expressCompany: expressForm.expressCompany.trim(), expressCompany: expressForm.expressCompany.trim(),
expressTrackingNo: expressForm.expressTrackingNo.trim(), expressTrackingNo: expressForm.expressTrackingNo.trim(),
}) })
@@ -315,12 +361,12 @@ function openNote(order: PlatformFirstLegOrderResource) {
} }
async function saveNote() { async function saveNote() {
if (!selectedOrder.value || !tenantReady.value) return if (!selectedOrder.value) return
const valid = await noteFormRef.value?.validate().catch(() => false) const valid = await noteFormRef.value?.validate().catch(() => false)
if (!valid) return if (!valid) return
noteSaving.value = true noteSaving.value = true
try { try {
await addPlatformFirstLegOrderNote(loadedTenantId.value, String(selectedOrder.value.id), noteForm.content.trim()) await addPlatformFirstLegOrderNote(String(selectedOrder.value.tenantId), String(selectedOrder.value.id), noteForm.content.trim())
noteDialogOpen.value = false noteDialogOpen.value = false
await refreshAfterAction(String(selectedOrder.value.id)) await refreshAfterAction(String(selectedOrder.value.id))
ElMessage.success('内部备注已保存') ElMessage.success('内部备注已保存')
@@ -331,15 +377,17 @@ async function saveNote() {
} }
} }
watch(detailOrderId, (orderId) => { watch([detailOrderId, detailTenantId], ([orderId, tenantId]) => {
if (orderId) { if (orderId) {
void loadDetail(orderId) void loadDetail(orderId, tenantId)
return return
} }
detail.value = null detail.value = null
selectedOrder.value = null selectedOrder.value = null
void loadOrders() void loadOrders()
}, { immediate: true }) }, { immediate: true })
onMounted(() => void loadTenants())
</script> </script>
<template> <template>
@@ -359,7 +407,7 @@ watch(detailOrderId, (orderId) => {
<div> <div>
<span>{{ transportLabel(detail.order) }}</span> <span>{{ transportLabel(detail.order) }}</span>
<h2>{{ detail.order.orderNo || detail.order.id }}</h2> <h2>{{ detail.order.orderNo || detail.order.id }}</h2>
<p>{{ detail.order.customerName }} · {{ detail.order.referenceId || '无客户参考号' }}</p> <p>{{ tenantName(detail.order.tenantId) }} · {{ detail.order.customerName }} · {{ detail.order.referenceId || '无客户参考号' }}</p>
</div> </div>
<StatusBadge :status="statusLabel(detail.order.status)" /> <StatusBadge :status="statusLabel(detail.order.status)" />
</div> </div>
@@ -430,10 +478,16 @@ watch(detailOrderId, (orderId) => {
ariaLabel="头程订单筛选" ariaLabel="头程订单筛选"
:fields="queryFields" :fields="queryFields"
search-text="查询" search-text="查询"
:search-on-reset="true" :search-on-reset="false"
@search="searchOrders" @search="searchOrders"
@reset="resetOrders"
/> />
<el-alert v-if="tenantLoadError" type="warning" :closable="false" show-icon role="alert">
<template #title><div class="api-error-alert-title"><span>{{ tenantLoadError.message }}</span><ApiErrorMeta :details="tenantLoadError" /></div></template>
<el-button link type="warning" @click="loadTenants">重新加载企业列表</el-button>
</el-alert>
<el-alert v-if="loadError" type="error" :closable="false" show-icon role="alert"> <el-alert v-if="loadError" type="error" :closable="false" show-icon role="alert">
<template #title><div class="api-error-alert-title"><span>{{ loadError.message }}</span><ApiErrorMeta :details="loadError" /></div></template> <template #title><div class="api-error-alert-title"><span>{{ loadError.message }}</span><ApiErrorMeta :details="loadError" /></div></template>
<el-button link type="danger" @click="loadOrders">重新加载</el-button> <el-button link type="danger" @click="loadOrders">重新加载</el-button>
@@ -453,7 +507,7 @@ watch(detailOrderId, (orderId) => {
> >
<template #actions="{ row }"><div class="table-actions"><el-button link type="primary" @click="openDetail(row as PlatformFirstLegOrderResource)"><Eye :size="15" />详情</el-button><el-button v-if="actionLabel(row as PlatformFirstLegOrderResource)" link type="success" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="runLifecycleAction(row as PlatformFirstLegOrderResource)">{{ actionLabel(row as PlatformFirstLegOrderResource) }}</el-button><el-button v-if="canCancel(row as PlatformFirstLegOrderResource)" link type="danger" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="cancelOrder(row as PlatformFirstLegOrderResource)">取消</el-button><el-button v-if="can('platform:order:fulfillment') && !['DRAFT', 'REJECTED', 'CANCELLED'].includes((row as PlatformFirstLegOrderResource).status)" link type="primary" @click="openExpress(row as PlatformFirstLegOrderResource)"><PackageCheck :size="15" />快递</el-button><el-button v-if="can('platform:order:note')" link type="primary" @click="openNote(row as PlatformFirstLegOrderResource)"><FilePenLine :size="15" />备注</el-button></div></template> <template #actions="{ row }"><div class="table-actions"><el-button link type="primary" @click="openDetail(row as PlatformFirstLegOrderResource)"><Eye :size="15" />详情</el-button><el-button v-if="actionLabel(row as PlatformFirstLegOrderResource)" link type="success" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="runLifecycleAction(row as PlatformFirstLegOrderResource)">{{ actionLabel(row as PlatformFirstLegOrderResource) }}</el-button><el-button v-if="canCancel(row as PlatformFirstLegOrderResource)" link type="danger" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="cancelOrder(row as PlatformFirstLegOrderResource)">取消</el-button><el-button v-if="can('platform:order:fulfillment') && !['DRAFT', 'REJECTED', 'CANCELLED'].includes((row as PlatformFirstLegOrderResource).status)" link type="primary" @click="openExpress(row as PlatformFirstLegOrderResource)"><PackageCheck :size="15" />快递</el-button><el-button v-if="can('platform:order:note')" link type="primary" @click="openNote(row as PlatformFirstLegOrderResource)"><FilePenLine :size="15" />备注</el-button></div></template>
<template #orderInfo="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).orderNo || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).referenceId || '无客户参考号' }} · {{ formattedDate((row as PlatformFirstLegOrderResource).createdAt) }}</span></div></template> <template #orderInfo="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).orderNo || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).referenceId || '无客户参考号' }} · {{ formattedDate((row as PlatformFirstLegOrderResource).createdAt) }}</span></div></template>
<template #customer="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).customerName }}</strong><span>租户 {{ (row as PlatformFirstLegOrderResource).tenantId }}</span></div></template> <template #customer="{ row }"><div class="primary-cell"><strong>{{ tenantName((row as PlatformFirstLegOrderResource).tenantId) }}</strong><span>{{ (row as PlatformFirstLegOrderResource).customerName }} · {{ (row as PlatformFirstLegOrderResource).tenantId }}</span></div></template>
<template #transport="{ row }"><div class="primary-cell"><strong>{{ transportLabel(row as PlatformFirstLegOrderResource) }}</strong><span>{{ (row as PlatformFirstLegOrderResource).channelName || '未填写渠道' }}</span></div></template> <template #transport="{ row }"><div class="primary-cell"><strong>{{ transportLabel(row as PlatformFirstLegOrderResource) }}</strong><span>{{ (row as PlatformFirstLegOrderResource).channelName || '未填写渠道' }}</span></div></template>
<template #destination="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).destinationWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).destinationCountryCode || '-' }}</span></div></template> <template #destination="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).destinationWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).destinationCountryCode || '-' }}</span></div></template>
<template #receivingWarehouse="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseAddress || '-' }}</span></div></template> <template #receivingWarehouse="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseAddress || '-' }}</span></div></template>