优化
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormItemRule, type FormRules, type UploadRequestOptions } from 'element-plus'
|
||||
import { AlertTriangle, Box, ChevronDown, ChevronUp, Download, FilePlus2, FileText, GripVertical, ImagePlus, MapPin, PackageCheck, Pencil, Plus, RotateCcw, Send, SlidersHorizontal, Trash2, Upload } from '@lucide/vue'
|
||||
import { AlertTriangle, ChevronDown, ChevronUp, Download, FilePlus2, FileText, GripVertical, ImagePlus, MapPin, PackageCheck, Pencil, Plus, RotateCcw, Send, SlidersHorizontal, Trash2, Upload } from '@lucide/vue'
|
||||
import { FIRST_LEG_ORDER_STATUSES, type FirstLegOrderStatus } from '@chongchong/shared'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/components/common/QueryToolbar.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
|
||||
@@ -66,9 +66,11 @@ const workspace = useWorkspaceTabsStore()
|
||||
const auth = useAuthStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const props = withDefaults(defineProps<{ createPage?: boolean }>(), { createPage: false })
|
||||
const props = withDefaults(defineProps<{ createPage?: boolean; detailPage?: boolean; showCreateAction?: boolean }>(), { createPage: false, detailPage: false, showCreateAction: true })
|
||||
const isCreatePage = computed(() => props.createPage)
|
||||
const isDetailPage = computed(() => props.detailPage)
|
||||
const routeDraftId = computed(() => typeof route.params.draftId === 'string' ? route.params.draftId : '')
|
||||
const routeDetailId = computed(() => typeof route.params.orderId === 'string' ? route.params.orderId : '')
|
||||
const canViewCompanyProfile = computed(() => auth.hasPermission('company:profile:view'))
|
||||
const companyAuditLoaded = ref(false)
|
||||
const companySubmissionBlocked = computed(() => companyAuditLoaded.value && tenantStore.company.auditStatus !== 'ACTIVE')
|
||||
@@ -78,13 +80,12 @@ const canSubmitOrder = computed(() => auth.hasPermission('order:first-leg:submit
|
||||
const canConfirmInboundFee = computed(() => auth.hasPermission('order:first-leg:edit'))
|
||||
const availableWarehouses = computed(() => store.warehouses.filter((warehouse) => warehouse.warehouseType === 'DOMESTIC'))
|
||||
const availableDestinationWarehouses = computed(() => store.warehouses.filter((warehouse) => warehouse.warehouseType === form.destinationType))
|
||||
const filters = ref<QueryModel>({ orderNo: '', receivingWarehouseId: '', channelName: '', cargoKeyword: '', createdRange: [], status: '', destinationType: '', trackingNumber: '' })
|
||||
const filters = ref<QueryModel>({ receivingWarehouseId: '', channelName: '', cargoKeyword: '', createdRange: [], status: '', destinationType: '', trackingNumber: '' })
|
||||
const appliedFilters = ref<QueryModel>({ ...filters.value })
|
||||
const queryFields = computed<QueryField[]>(() => [
|
||||
{ key: 'orderNo', label: '订单号', type: 'input', placeholder: '请输入订单号', props: { 'aria-label': '订单号' } },
|
||||
{ key: 'cargoKeyword', label: '入仓码 / SKU', type: 'input', placeholder: '请输入入仓码或 SKU', props: { 'aria-label': '入仓码或 SKU' } },
|
||||
{ key: 'receivingWarehouseId', label: '收货仓', type: 'select', placeholder: '全部', options: availableWarehouses.value.map((item) => ({ label: item.name, value: item.id })), props: { 'aria-label': '收货仓' } },
|
||||
{ key: 'channelName', label: '渠道名称', type: 'select', placeholder: '全部', options: [...new Set(store.orders.map((item) => item.channelName).filter(Boolean))].map((name) => ({ label: name, value: name })), props: { 'aria-label': '渠道名称' } },
|
||||
{ key: 'cargoKeyword', label: '入仓码 / SKU', type: 'input', placeholder: '请输入入仓码或 SKU', props: { 'aria-label': '入仓码或 SKU' } },
|
||||
{ key: 'createdRange', label: '创建时间', type: 'daterange', placeholder: '请选择创建时间', props: { 'aria-label': '创建时间' } },
|
||||
{ key: 'status', label: '当前状态', type: 'select', placeholder: '全部', options: FIRST_LEG_ORDER_STATUSES.map((item) => ({ label: item.label, value: item.code })), props: { 'aria-label': '当前状态' } },
|
||||
{ key: 'destinationType', label: '目的仓类型', type: 'select', placeholder: '全部', options: [{ label: 'FBA 仓', value: 'FBA' }, { label: '海外仓', value: 'OVERSEAS' }, { label: '私人地址', value: 'PRIVATE' }], props: { 'aria-label': '目的仓类型' } },
|
||||
@@ -112,10 +113,9 @@ const batchImportError = ref('')
|
||||
const fixedOrderColumns: DataTableColumn[] = [
|
||||
{ key: 'selection', type: 'selection', width: 48, fixed: 'left', reserveSelection: true },
|
||||
{ key: 'actions', label: '操作', width: 284, fixed: 'left', align: 'left', headerAlign: 'left', slotName: 'actions' },
|
||||
{ key: 'order', label: '订单号', width: 240, fixed: 'left', align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'order' },
|
||||
{ key: 'inboundCode', label: '入仓码', width: 230, fixed: 'left', align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'inboundCode' },
|
||||
]
|
||||
const selectableOrderColumns: DataTableColumn[] = [
|
||||
{ key: 'inboundCode', label: '入仓码', width: 230, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'inboundCode' },
|
||||
{ key: 'status', label: '当前订单状态', width: 126, align: 'center', headerAlign: 'center', slotName: 'status' },
|
||||
{ key: 'channel', label: '渠道', width: 150, align: 'left', headerAlign: 'left', showOverflowTooltip: true, slotName: 'channel' },
|
||||
{ key: 'transportMode', label: '运输方式', width: 104, align: 'center', headerAlign: 'center', slotName: 'transportMode' },
|
||||
@@ -147,7 +147,8 @@ const selectableOrderColumns: DataTableColumn[] = [
|
||||
{ key: 'updatedAt', label: '更新时间', width: 164, align: 'center', headerAlign: 'center', slotName: 'updatedAt' },
|
||||
]
|
||||
const allSelectableColumnKeys = selectableOrderColumns.map((column) => String(column.key))
|
||||
const visibleColumnKeys = ref<string[]>([...allSelectableColumnKeys])
|
||||
const defaultVisibleColumnKeys = ['status', 'channel', 'transportMode', 'pickupMethod', 'receivingWarehouse', 'createdAt']
|
||||
const visibleColumnKeys = ref<string[]>([...defaultVisibleColumnKeys])
|
||||
const orderedColumnKeys = ref<string[]>([...allSelectableColumnKeys])
|
||||
const draggedColumnKey = ref('')
|
||||
const orderedSelectableColumns = computed(() => orderedColumnKeys.value
|
||||
@@ -179,7 +180,7 @@ function dropOrderColumn(targetKey: string) {
|
||||
|
||||
function resetOrderColumns() {
|
||||
orderedColumnKeys.value = [...allSelectableColumnKeys]
|
||||
visibleColumnKeys.value = [...allSelectableColumnKeys]
|
||||
visibleColumnKeys.value = [...defaultVisibleColumnKeys]
|
||||
}
|
||||
const tablePage = ref(1)
|
||||
const tablePageSize = ref(10)
|
||||
@@ -190,9 +191,10 @@ const selectedOrders = ref<FirstLegOrder[]>([])
|
||||
const selectedOrderCount = computed(() => selectedOrders.value.length)
|
||||
const selectedDraftOrders = computed(() => selectedOrders.value.filter((order) => order.status === 'DRAFT'))
|
||||
const orderTableVersion = ref(0)
|
||||
type OrderQueue = 'all' | 'fee' | 'customs'
|
||||
const activeOrderQueue = ref<OrderQueue>('all')
|
||||
const editorOpen = ref(false)
|
||||
const orderFormRef = ref<FormInstance>()
|
||||
const detailOpen = ref(false)
|
||||
const editingId = ref<string>()
|
||||
const openingEditor = ref(false)
|
||||
const detailId = ref<string>()
|
||||
@@ -442,11 +444,10 @@ useUnsavedWorkRegistration({
|
||||
dirty: editorDirty,
|
||||
})
|
||||
|
||||
const filteredOrders = computed(() => store.orders.filter((order) => {
|
||||
function matchesAppliedFilters(order: FirstLegOrder) {
|
||||
const statusValue = appliedFilters.value.status
|
||||
const createdRangeValue = appliedFilters.value.createdRange
|
||||
const textValue = (key: string) => typeof appliedFilters.value[key] === 'string' ? String(appliedFilters.value[key]).trim().toLowerCase() : ''
|
||||
const orderNo = textValue('orderNo')
|
||||
const receivingWarehouseId = textValue('receivingWarehouseId')
|
||||
const channelName = textValue('channelName')
|
||||
const cargoKeyword = textValue('cargoKeyword')
|
||||
@@ -454,7 +455,6 @@ const filteredOrders = computed(() => store.orders.filter((order) => {
|
||||
const trackingNumber = textValue('trackingNumber')
|
||||
const status = typeof statusValue === 'string' ? statusValue as FirstLegOrderStatus | '' : ''
|
||||
const createdRange = Array.isArray(createdRangeValue) ? createdRangeValue.filter((value): value is string => typeof value === 'string') : []
|
||||
const matchesOrderNo = !orderNo || String(order.orderNo ?? '').toLowerCase().includes(orderNo)
|
||||
const matchesWarehouse = !receivingWarehouseId || order.receivingWarehouseId.toLowerCase() === receivingWarehouseId
|
||||
const matchesChannel = !channelName || order.channelName.toLowerCase() === channelName
|
||||
const matchesCargo = !cargoKeyword || [order.businessSummary.inboundCode, ...order.skuNos, ...order.items.map((item) => item.sku)]
|
||||
@@ -463,13 +463,32 @@ const filteredOrders = computed(() => store.orders.filter((order) => {
|
||||
const matchesTrackingNumber = !trackingNumber || order.trackingNumber.toLowerCase().includes(trackingNumber)
|
||||
const matchesStatus = !status || order.status === status
|
||||
const matchesDate = createdRange.length !== 2 || (order.createdAt.slice(0, 10) >= createdRange[0] && order.createdAt.slice(0, 10) <= createdRange[1])
|
||||
return matchesOrderNo && matchesWarehouse && matchesChannel && matchesCargo && matchesDestinationType && matchesTrackingNumber && matchesStatus && matchesDate
|
||||
return matchesWarehouse && matchesChannel && matchesCargo && matchesDestinationType && matchesTrackingNumber && matchesStatus && matchesDate
|
||||
}
|
||||
|
||||
const queryMatchedOrders = computed(() => store.orders.filter(matchesAppliedFilters))
|
||||
const orderQueueCounts = computed(() => ({
|
||||
all: queryMatchedOrders.value.length,
|
||||
fee: queryMatchedOrders.value.filter((order) => order.businessSummary.customerFeeConfirmationRequired).length,
|
||||
customs: queryMatchedOrders.value.filter((order) => Boolean(eligibleCustomsDetail(order))).length,
|
||||
}))
|
||||
const filteredOrders = computed(() => queryMatchedOrders.value.filter((order) => {
|
||||
if (activeOrderQueue.value === 'fee') return order.businessSummary.customerFeeConfirmationRequired
|
||||
if (activeOrderQueue.value === 'customs') return Boolean(eligibleCustomsDetail(order))
|
||||
return true
|
||||
}))
|
||||
const pagedOrders = computed(() => {
|
||||
const start = (tablePage.value - 1) * tablePageSize.value
|
||||
return filteredOrders.value.slice(start, start + tablePageSize.value)
|
||||
})
|
||||
|
||||
function selectOrderQueue(queue: OrderQueue) {
|
||||
activeOrderQueue.value = queue
|
||||
tablePage.value = 1
|
||||
selectedOrders.value = []
|
||||
orderTableVersion.value += 1
|
||||
}
|
||||
|
||||
function eligibleCustomsDetail(order: FirstLegOrder) {
|
||||
const value = customsByOrder[order.id]
|
||||
if (order.status !== 'LOADED' || !value?.merchantStatus) return null
|
||||
@@ -536,7 +555,7 @@ const progressSummaryItems = computed(() => {
|
||||
{ label: '实测体积', value: formatMetric(summary.actualVolumeCbm ?? inbound?.actualVolumeCbm, 'm³') },
|
||||
{ label: '预装清单', value: preloadStatus ? `${preloadStatus}${summary.preloadItemCount == null ? '' : ` · ${summary.preloadItemCount} 项`}` : '待更新' },
|
||||
{ label: '拣货进度', value: pickingProgress },
|
||||
{ label: '柜次进度', value: summary.cabinetNo || summary.containerNo || '—' },
|
||||
{ label: '关联柜次', value: summary.cabinetNo || summary.containerNo || '—' },
|
||||
{ label: '船期摘要', value: transportReference || '待更新' },
|
||||
{ label: '计费重量', value: formatMetric(summary.chargeableWeightKg, 'kg') },
|
||||
{ label: '后续履约', value: summary.deliveryTrackingNo || (summary.deliveryCompletedAt ? `海外回传于 ${formatDateTime(summary.deliveryCompletedAt)}` : '待海外同步') },
|
||||
@@ -567,7 +586,7 @@ async function loadPageData() {
|
||||
const destinationRequest = isCreatePage.value && form.destinationType !== 'PRIVATE'
|
||||
? loadDestinationWarehouses(form.destinationType)
|
||||
: Promise.resolve()
|
||||
const orderPageRequest = isCreatePage.value
|
||||
const orderPageRequest = isCreatePage.value || isDetailPage.value
|
||||
? store.loadWarehouseType('DOMESTIC', true)
|
||||
: store.load({ includeDrafts: true })
|
||||
const addressRequest = isCreatePage.value ? loadOrderAddresses() : Promise.resolve()
|
||||
@@ -595,6 +614,7 @@ async function loadPageData() {
|
||||
if (addressResult.status === 'rejected') supportingDataErrors.value.push(`企业地址簿加载失败:${errorMessage(addressResult.reason)}`)
|
||||
await autofillWarehouseSelections()
|
||||
if (isCreatePage.value && routeDraftId.value) await loadRouteDraft(routeDraftId.value)
|
||||
if (isDetailPage.value && routeDetailId.value) await loadDetailPage(routeDetailId.value)
|
||||
supportingDataLoading.value = false
|
||||
}
|
||||
|
||||
@@ -635,12 +655,6 @@ function batchImportErrorMessage(error: unknown) {
|
||||
].filter(Boolean).join(' · ')
|
||||
}
|
||||
|
||||
function getOrderCargoSummary(order: FirstLegOrder) {
|
||||
if (order.items.length) return `${order.items[0]?.cargoNameCn || '货物'}${order.items.length > 1 ? `等 ${order.items.length} 项` : ''}`
|
||||
if (order.businessSummary.totalPackageCount != null) return `${order.businessSummary.totalPackageCount} 箱`
|
||||
return '待更新'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void loadPageData()
|
||||
})
|
||||
@@ -659,15 +673,13 @@ watch(isCreatePage, (isCreate, wasCreate) => {
|
||||
if (wasCreate === false) void loadPageData()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(detailOpen, (open) => {
|
||||
if (!open && !feeConfirmationOpen.value) {
|
||||
resetInboundBillingState()
|
||||
if (detailOrder.value) releaseProductImagePreviews(detailOrder.value.items)
|
||||
}
|
||||
watch(routeDetailId, (orderId, previousOrderId) => {
|
||||
if (!isDetailPage.value || !orderId || orderId === previousOrderId) return
|
||||
void loadDetailPage(orderId)
|
||||
})
|
||||
|
||||
watch(feeConfirmationOpen, (open) => {
|
||||
if (!open && !detailOpen.value) resetInboundBillingState()
|
||||
if (!open && !isDetailPage.value) resetInboundBillingState()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -1266,7 +1278,6 @@ async function openEdit(order: FirstLegOrder) {
|
||||
replaceForm(draft)
|
||||
await Promise.all(form.items.map(ensureProductImagePreview))
|
||||
if (warehouseAvailable) void loadSelectedWarehouse(detailedOrder.receivingWarehouseId)
|
||||
detailOpen.value = false
|
||||
editorOpen.value = true
|
||||
resetEditorValidation()
|
||||
} catch (error) {
|
||||
@@ -1277,15 +1288,18 @@ async function openEdit(order: FirstLegOrder) {
|
||||
}
|
||||
|
||||
async function openDetail(order: FirstLegOrder) {
|
||||
await router.push({ name: 'first-leg-order-detail', params: { orderId: order.id } })
|
||||
}
|
||||
|
||||
async function loadDetailPage(orderId: string) {
|
||||
feeConfirmationOpen.value = false
|
||||
detailId.value = order.id
|
||||
detailId.value = orderId
|
||||
detailCargoPage.value = 1
|
||||
detailOpen.value = true
|
||||
detailLoading.value = true
|
||||
detailError.value = ''
|
||||
void loadInboundBilling(order)
|
||||
try {
|
||||
const detailedOrder = await store.loadDetail(order.id)
|
||||
const detailedOrder = await store.loadDetail(orderId)
|
||||
void loadInboundBilling(detailedOrder)
|
||||
// Load previews from the persisted file IDs after the store has replaced the detail row.
|
||||
await Promise.all((detailOrder.value?.items ?? detailedOrder.items).map(ensureProductImagePreview))
|
||||
} catch (error) {
|
||||
@@ -1297,7 +1311,6 @@ async function openDetail(order: FirstLegOrder) {
|
||||
}
|
||||
|
||||
function openFeeConfirmation(order: FirstLegOrder) {
|
||||
detailOpen.value = false
|
||||
resetInboundBillingState()
|
||||
inboundBillingUnavailableMessage.value = '未推送计费重'
|
||||
feeConfirmationOpen.value = true
|
||||
@@ -1305,8 +1318,7 @@ function openFeeConfirmation(order: FirstLegOrder) {
|
||||
}
|
||||
|
||||
async function retryDetail() {
|
||||
const order = detailId.value ? store.getById(detailId.value) : undefined
|
||||
if (order) await openDetail(order)
|
||||
if (detailId.value) await loadDetailPage(detailId.value)
|
||||
}
|
||||
|
||||
function resetInboundBillingState() {
|
||||
@@ -1322,7 +1334,7 @@ function resetInboundBillingState() {
|
||||
function isCurrentInboundBillingRequest(sequence: number, orderId: string) {
|
||||
return sequence === inboundBillingRequestSequence
|
||||
&& inboundBillingOrderId.value === orderId
|
||||
&& (detailOpen.value || feeConfirmationOpen.value)
|
||||
&& (isDetailPage.value || feeConfirmationOpen.value)
|
||||
}
|
||||
|
||||
async function loadInboundBilling(order: FirstLegOrder, unavailableMessage = '还未测量推送') {
|
||||
@@ -1624,7 +1636,6 @@ function exportOrderInformation() {
|
||||
exportingOrders.value = true
|
||||
try {
|
||||
const rows = selectedOrders.value.map((order) => [
|
||||
displayListValue(order.orderNo),
|
||||
displayListValue(order.businessSummary.inboundCode),
|
||||
displayListValue(order.channelName),
|
||||
order.transportMode ? getFirstLegTransportModeLabel(order.transportMode) : '-',
|
||||
@@ -1651,7 +1662,7 @@ function exportOrderInformation() {
|
||||
formatExportDateTime(order.createdAt),
|
||||
])
|
||||
downloadCsv('订单信息.csv', [[
|
||||
'订单号', '入仓码', '渠道', '运输方式', '交货方式', '预约提货时间', '目的仓', '目的仓类型', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS',
|
||||
'入仓码', '渠道', '运输方式', '交货方式', '预约提货时间', '目的仓', '目的仓类型', '当前订单状态', '箱数', '快递公司', '快递单号', 'SKUS',
|
||||
'总毛重', '总净重', '总体积', '总数量', '计费单价', '计费体积', '计费重量', '备注',
|
||||
'货件编号', '跟踪编号', '国内仓入库时间', '创建时间',
|
||||
], ...rows])
|
||||
@@ -1879,8 +1890,7 @@ async function submitOrder() {
|
||||
ElMessage.success('订单已提交,等待平台审核')
|
||||
return
|
||||
}
|
||||
detailId.value = order.id
|
||||
detailOpen.value = true
|
||||
await router.push({ name: 'first-leg-order-detail', params: { orderId: order.id } })
|
||||
ElMessage.success('订单已提交,等待平台审核')
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '订单提交失败')
|
||||
@@ -1898,13 +1908,11 @@ async function searchOrders(model: QueryModel) {
|
||||
tablePage.value = 1
|
||||
try {
|
||||
const statusValue = typeof model.status === 'string' ? model.status as FirstLegOrderStatus | '' : ''
|
||||
const orderNo = typeof model.orderNo === 'string' ? model.orderNo.trim() : ''
|
||||
const cargoKeyword = typeof model.cargoKeyword === 'string' ? model.cargoKeyword.trim() : ''
|
||||
const range = Array.isArray(createdRange) ? createdRange.filter((value): value is string => typeof value === 'string') : []
|
||||
const query = {
|
||||
keyword: undefined,
|
||||
inboundCode: cargoKeyword || undefined,
|
||||
orderNo: orderNo || undefined,
|
||||
receivingWarehouseId: typeof model.receivingWarehouseId === 'string' && model.receivingWarehouseId ? model.receivingWarehouseId : undefined,
|
||||
mainStatus: statusValue && statusValue !== 'DRAFT' ? statusValue : undefined,
|
||||
draftOnly: statusValue === 'DRAFT',
|
||||
@@ -1926,17 +1934,24 @@ async function searchOrders(model: QueryModel) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="first-leg-page" :class="{ 'is-create-route': isCreatePage, 'client-ui': !isCreatePage }">
|
||||
<template v-if="!isCreatePage">
|
||||
<section class="first-leg-page" :class="{ 'is-create-route': isCreatePage, 'is-detail-route': isDetailPage, 'client-ui': !isCreatePage }">
|
||||
<template v-if="!isCreatePage && !isDetailPage">
|
||||
<QueryToolbar v-model="filters" class="first-leg-query-toolbar" layout="grid" :fields="queryFields" ariaLabel="订单查询" @search="searchOrders" />
|
||||
|
||||
<div class="client-card order-table-card">
|
||||
<DataTable v-model:page="tablePage" v-model:page-size="tablePageSize" :data="pagedOrders" :columns="visibleOrderColumns" :key="orderTableVersion" :loading="store.loading" :total="filteredOrders.length" :page-sizes="[10, 20, 50]" row-key="id" empty-text="暂无订单" class="prototype-order-table" :row-actions="getOrderRowActions" @selection-change="handleOrderSelectionChange">
|
||||
<template #toolbar><strong>订单列表</strong><span>共 {{ filteredOrders.length }} 条</span><span v-if="selectedOrderCount">已选 {{ selectedOrderCount }} 条</span></template>
|
||||
<template #toolbar>
|
||||
<nav class="order-queue-tabs" aria-label="订单事项分类">
|
||||
<button type="button" :class="{ active: activeOrderQueue === 'all' }" @click="selectOrderQueue('all')">全部</button>
|
||||
<button type="button" :class="{ active: activeOrderQueue === 'fee' }" @click="selectOrderQueue('fee')">确认计费重<span v-if="orderQueueCounts.fee" class="queue-count">{{ orderQueueCounts.fee }}</span></button>
|
||||
<button type="button" :class="{ active: activeOrderQueue === 'customs' }" @click="selectOrderQueue('customs')">上传资料<span v-if="orderQueueCounts.customs" class="queue-count">{{ orderQueueCounts.customs }}</span></button>
|
||||
</nav>
|
||||
<span>共 {{ filteredOrders.length }} 条</span><span v-if="selectedOrderCount">已选 {{ selectedOrderCount }} 条</span>
|
||||
</template>
|
||||
<template #toolbar-actions>
|
||||
<el-popover placement="bottom-end" :width="320" trigger="click" popper-class="order-column-popper">
|
||||
<template #reference>
|
||||
<el-button class="column-settings-trigger" aria-label="设置订单列表显示列" title="设置显示列"><SlidersHorizontal :size="18" /></el-button>
|
||||
<el-button class="column-settings-trigger" aria-label="设置订单列表显示列" title="设置显示列"><SlidersHorizontal :size="18" />显示字段筛选</el-button>
|
||||
</template>
|
||||
<div class="column-settings-panel">
|
||||
<p>拖动调整顺序,也可使用上下移动按钮。</p>
|
||||
@@ -1964,7 +1979,7 @@ async function searchOrders(model: QueryModel) {
|
||||
<el-button :loading="exportingOrders" :disabled="selectedOrderCount === 0" @click="exportOrderInformation"><Download :size="16" />导出订单信息</el-button>
|
||||
<el-button v-if="canSubmitOrder" :loading="batchSubmitting" :disabled="selectedDraftOrders.length === 0 || companySubmissionBlocked" @click="submitSelectedDraftOrders"><Send :size="17" />批量提交草稿</el-button>
|
||||
<el-button v-if="auth.hasPermission('order:first-leg:create')" @click="openBatchImport"><Upload :size="17" />批量导入订单</el-button>
|
||||
<el-button v-if="auth.hasPermission('order:first-leg:create')" type="primary" :loading="pageDataLoading" :disabled="pageDataLoading || availableWarehouses.length === 0" @click="openCreate"><FilePlus2 :size="17" />创建订单</el-button>
|
||||
<el-button v-if="props.showCreateAction && auth.hasPermission('order:first-leg:create')" type="primary" :loading="pageDataLoading" :disabled="pageDataLoading || availableWarehouses.length === 0" @click="openCreate"><FilePlus2 :size="17" />创建订单</el-button>
|
||||
|
||||
</template>
|
||||
<template #before-table>
|
||||
@@ -1988,18 +2003,15 @@ async function searchOrders(model: QueryModel) {
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<template #order="{ row }">
|
||||
<button class="order-number-link table-code" type="button" :title="(row as FirstLegOrder).orderNo || '—'" @click="openDetail(row as FirstLegOrder)">{{ (row as FirstLegOrder).orderNo || '—' }}</button>
|
||||
</template>
|
||||
<template #inboundCode="{ row }">
|
||||
<button
|
||||
v-if="(row as FirstLegOrder).businessSummary.inboundCode"
|
||||
class="inbound-code-link table-ellipsis table-code"
|
||||
class="inbound-code-primary table-ellipsis table-code"
|
||||
type="button"
|
||||
:title="`查看入仓码 ${(row as FirstLegOrder).businessSummary.inboundCode} 的关联摘要`"
|
||||
@click="openInboundCodeAssociation((row as FirstLegOrder).businessSummary.inboundCode)"
|
||||
:title="`查看入仓码 ${(row as FirstLegOrder).businessSummary.inboundCode} 的订单详情`"
|
||||
@click="openDetail(row as FirstLegOrder)"
|
||||
>{{ (row as FirstLegOrder).businessSummary.inboundCode }}</button>
|
||||
<span v-else>—</span>
|
||||
<span v-else class="pending-inbound-code">{{ (row as FirstLegOrder).status === 'DRAFT' ? '提交后生成' : '待生成' }}</span>
|
||||
</template>
|
||||
<template #channel="{ row }"><span class="table-ellipsis" :title="displayListValue((row as FirstLegOrder).channelName)">{{ displayListValue((row as FirstLegOrder).channelName) }}</span></template>
|
||||
<template #transportMode="{ row }">{{ (row as FirstLegOrder).transportMode ? getFirstLegTransportModeLabel((row as FirstLegOrder).transportMode) : '-' }}</template>
|
||||
@@ -2032,33 +2044,10 @@ async function searchOrders(model: QueryModel) {
|
||||
<template #updatedAt="{ row }">{{ formatDateTime((row as FirstLegOrder).updatedAt) }}</template>
|
||||
<template #empty>
|
||||
<el-empty :description="emptyDescription">
|
||||
<el-button v-if="auth.hasPermission('order:first-leg:create')" type="primary" :loading="pageDataLoading" :disabled="pageDataLoading || availableWarehouses.length === 0" @click="openCreate"><Plus :size="16" />{{ pageDataLoading ? '加载收货仓中' : (availableWarehouses.length ? '创建第一笔订单' : '暂无可用收货仓') }}</el-button>
|
||||
<el-button v-if="props.showCreateAction && auth.hasPermission('order:first-leg:create')" type="primary" :loading="pageDataLoading" :disabled="pageDataLoading || availableWarehouses.length === 0" @click="openCreate"><Plus :size="16" />{{ pageDataLoading ? '加载收货仓中' : (availableWarehouses.length ? '创建第一笔订单' : '暂无可用收货仓') }}</el-button>
|
||||
</el-empty>
|
||||
</template>
|
||||
</DataTable>
|
||||
<div v-if="!store.loadError" v-loading="store.loading" class="mobile-order-surface">
|
||||
<div v-if="filteredOrders.length" class="mobile-order-list">
|
||||
<article v-for="order in filteredOrders" :key="order.id" class="mobile-order-card">
|
||||
<header><button type="button" @click="openDetail(order)">{{ order.orderNo || '—' }}</button><el-tag :type="getFirstLegStatusTone(order.status)" effect="light">{{ getFirstLegStatusLabel(order.status) }}</el-tag></header>
|
||||
<button v-if="order.businessSummary.inboundCode" class="order-reference inbound-code-link" type="button" @click="openInboundCodeAssociation(order.businessSummary.inboundCode)">入仓码 {{ order.businessSummary.inboundCode }}</button>
|
||||
<span v-else class="order-reference">入仓码 —</span>
|
||||
<span class="order-reference">{{ order.referenceNo || '跟踪编号 —' }}</span>
|
||||
<dl><div><dt>目的地</dt><dd>{{ order.destination || '待更新' }}</dd></div><div><dt>目的仓类型</dt><dd>{{ destinationTypeLabels[order.destinationType] }}</dd></div><div><dt>收货仓</dt><dd>{{ order.receivingWarehouseName || '—' }}</dd></div><div><dt>货物摘要</dt><dd>{{ getOrderCargoSummary(order) }}</dd></div><div><dt>运输方式</dt><dd>{{ order.transportMode ? getFirstLegTransportModeLabel(order.transportMode) : '待更新' }}</dd></div><div><dt>交货方式</dt><dd>{{ pickupMethodLabels[order.pickupMethod] }}</dd></div><div><dt>预约提货时间</dt><dd>{{ order.pickupMethod === 'PICKUP' && order.requestedPickupAt ? formatDateTime(order.requestedPickupAt) : '—' }}</dd></div><div><dt>柜号 / 柜次</dt><dd>{{ order.businessSummary.cabinetNo || order.businessSummary.containerNo || '—' }}</dd></div><div v-if="order.businessSummary.vesselName || order.businessSummary.voyageNo"><dt>船名 / 航次</dt><dd>{{ [order.businessSummary.vesselName, order.businessSummary.voyageNo].filter(Boolean).join(' · ') }}</dd></div><div v-if="order.businessSummary.sailingAt"><dt>预计船期</dt><dd>{{ formatDateTime(order.businessSummary.sailingAt) }}</dd></div></dl>
|
||||
<footer>
|
||||
<span>更新于 {{ formatDateTime(order.updatedAt) }}</span>
|
||||
<div>
|
||||
<el-button link type="primary" @click="openDetail(order)">详情</el-button>
|
||||
<el-button v-if="canConfirmInboundFee && order.businessSummary.customerFeeConfirmationRequired" link type="primary" @click="openFeeConfirmation(order)">确认计费重</el-button>
|
||||
<el-button v-if="canEditOrder && canClientEditFirstLegOrder(order.status)" link type="primary" :loading="openingEditor" @click="openEdit(order)">编辑</el-button>
|
||||
<el-button v-if="eligibleCustomsDetail(order)" link type="primary" @click="openCustomsDocuments(order)">报关资料</el-button>
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
</div>
|
||||
<el-empty v-else :description="emptyDescription">
|
||||
<el-button v-if="auth.hasPermission('order:first-leg:create')" type="primary" :loading="pageDataLoading" :disabled="pageDataLoading || availableWarehouses.length === 0" @click="openCreate"><Plus :size="16" />{{ pageDataLoading ? '加载收货仓中' : (availableWarehouses.length ? '创建第一笔订单' : '暂无可用收货仓') }}</el-button>
|
||||
</el-empty>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2241,7 +2230,7 @@ async function searchOrders(model: QueryModel) {
|
||||
<template #footer><div class="editor-actions"><el-button v-if="batchImportResult?.result.succeeded && auth.hasPermission('order:first-leg:list')" :disabled="batchImportSubmitting" @click="viewImportedDrafts">查看订单草稿</el-button><el-button :disabled="batchImportSubmitting" @click="batchImportOpen = false">关闭</el-button><el-button type="primary" :loading="batchImportSubmitting" :disabled="!batchImportFile" @click="submitBatchImport">开始导入并创建草稿</el-button></div></template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="detailOpen" class="first-leg-detail-dialog" title="订单详情" width="94vw" top="3vh" destroy-on-close append-to-body>
|
||||
<section v-if="isDetailPage" class="first-leg-detail-page" aria-label="订单详情">
|
||||
<div v-loading="detailLoading" class="order-detail-content">
|
||||
<div v-if="detailError" class="order-load-state is-compact" role="alert">
|
||||
<AlertTriangle :size="24" />
|
||||
@@ -2250,13 +2239,16 @@ async function searchOrders(model: QueryModel) {
|
||||
</div>
|
||||
<template v-else-if="detailOrder">
|
||||
<div class="order-detail-heading">
|
||||
<div><span>{{ getFirstLegTransportModeLabel(detailOrder.transportMode) }}</span><h2>{{ detailOrder.orderNo || '—' }}</h2><p>{{ detailOrder.origin || '起运地待更新' }} → {{ detailOrder.destination || '目的地待更新' }}</p></div>
|
||||
<el-tag :type="getFirstLegStatusTone(detailOrder.status)" effect="light">{{ getFirstLegStatusLabel(detailOrder.status) }}</el-tag>
|
||||
<div class="detail-heading-main">
|
||||
<el-button link type="primary" class="detail-back-action" @click="router.push({ name: 'first-leg-orders' })">← 返回列表</el-button>
|
||||
<div><h2>{{ detailOrder.businessSummary.inboundCode || (detailOrder.status === 'DRAFT' ? '入仓码提交后生成' : '入仓码待生成') }}</h2><p>{{ getFirstLegTransportModeLabel(detailOrder.transportMode) }} · {{ detailOrder.origin || '起运地待更新' }} → {{ detailOrder.destination || '目的地待更新' }}</p></div>
|
||||
</div>
|
||||
<div class="detail-heading-actions"><el-tag :type="getFirstLegStatusTone(detailOrder.status)" effect="light">{{ getFirstLegStatusLabel(detailOrder.status) }}</el-tag><el-button v-if="canEditOrder && canClientEditFirstLegOrder(detailOrder.status)" type="primary" plain :loading="openingEditor" @click="openEdit(detailOrder)"><Pencil :size="16" />编辑草稿</el-button></div>
|
||||
</div>
|
||||
<section class="detail-section">
|
||||
<h3>订单与运输</h3>
|
||||
<dl class="order-detail-grid">
|
||||
<div><dt>入仓码</dt><dd><button v-if="detailOrder.businessSummary.inboundCode" class="inbound-code-link table-code" type="button" @click="openInboundCodeAssociation(detailOrder.businessSummary.inboundCode)">{{ detailOrder.businessSummary.inboundCode }}</button><span v-else>—</span></dd></div>
|
||||
<div><dt>入仓码</dt><dd><button v-if="detailOrder.businessSummary.inboundCode" class="inbound-code-link table-code" type="button" @click="openInboundCodeAssociation(detailOrder.businessSummary.inboundCode)">{{ detailOrder.businessSummary.inboundCode }}</button><span v-else>{{ detailOrder.status === 'DRAFT' ? '提交后生成' : '待生成' }}</span></dd></div>
|
||||
<div><dt>创建时间</dt><dd>{{ formatDateTime(detailOrder.createdAt) }}</dd></div>
|
||||
<div><dt>运输方式</dt><dd>{{ getFirstLegTransportModeLabel(detailOrder.transportMode) }}</dd></div>
|
||||
<div><dt>贸易条款</dt><dd>{{ displayValue(detailOrder.tradeTerm) }}</dd></div>
|
||||
@@ -2277,10 +2269,10 @@ async function searchOrders(model: QueryModel) {
|
||||
</section>
|
||||
<section class="detail-section">
|
||||
<h3>收发货信息</h3>
|
||||
<div class="party-detail-grid">
|
||||
<article><span>发货方</span><strong>{{ detailOrder.shipperPartySnapshot?.name || detailOrder.shipper || '未提供' }}</strong><p v-if="detailOrder.shipperPartySnapshot">{{ detailOrder.shipperPartySnapshot.contactName || '未填写联系人' }} · {{ detailOrder.shipperPartySnapshot.phone || '未填写电话' }}<br />{{ detailOrder.shipperPartySnapshot.email || '' }}<br />{{ detailOrder.shipperPartySnapshot.countryRegion }} {{ detailOrder.shipperPartySnapshot.province }} {{ detailOrder.shipperPartySnapshot.city }} {{ detailOrder.shipperPartySnapshot.address }} {{ detailOrder.shipperPartySnapshot.postalCode }}</p></article>
|
||||
<article><span>收货方</span><strong>{{ detailOrder.consigneePartySnapshot?.name || detailOrder.consignee || detailOrder.destinationWarehouseName || '未提供' }}</strong><p v-if="detailOrder.consigneePartySnapshot">{{ detailOrder.consigneePartySnapshot.contactName || '未填写联系人' }} · {{ detailOrder.consigneePartySnapshot.phone || '未填写电话' }}<br />{{ detailOrder.consigneePartySnapshot.email || '' }}<br />{{ detailOrder.consigneePartySnapshot.countryRegion }} {{ detailOrder.consigneePartySnapshot.province }} {{ detailOrder.consigneePartySnapshot.city }} {{ detailOrder.consigneePartySnapshot.address }} {{ detailOrder.consigneePartySnapshot.postalCode }}</p><p v-else>平台目的仓地址以最终履约安排为准</p></article>
|
||||
</div>
|
||||
<dl class="party-detail-grid">
|
||||
<div><dt>发货方</dt><dd><strong>{{ detailOrder.shipperPartySnapshot?.name || detailOrder.shipper || '未提供' }}</strong><span v-if="detailOrder.shipperPartySnapshot">{{ detailOrder.shipperPartySnapshot.contactName || '未填写联系人' }} · {{ detailOrder.shipperPartySnapshot.phone || '未填写电话' }} · {{ detailOrder.shipperPartySnapshot.email || '未填写邮箱' }}<br />{{ detailOrder.shipperPartySnapshot.countryRegion }} {{ detailOrder.shipperPartySnapshot.province }} {{ detailOrder.shipperPartySnapshot.city }} {{ detailOrder.shipperPartySnapshot.address }} {{ detailOrder.shipperPartySnapshot.postalCode }}</span></dd></div>
|
||||
<div><dt>收货方</dt><dd><strong>{{ detailOrder.consigneePartySnapshot?.name || detailOrder.consignee || detailOrder.destinationWarehouseName || '未提供' }}</strong><span v-if="detailOrder.consigneePartySnapshot">{{ detailOrder.consigneePartySnapshot.contactName || '未填写联系人' }} · {{ detailOrder.consigneePartySnapshot.phone || '未填写电话' }} · {{ detailOrder.consigneePartySnapshot.email || '未填写邮箱' }}<br />{{ detailOrder.consigneePartySnapshot.countryRegion }} {{ detailOrder.consigneePartySnapshot.province }} {{ detailOrder.consigneePartySnapshot.city }} {{ detailOrder.consigneePartySnapshot.address }} {{ detailOrder.consigneePartySnapshot.postalCode }}</span><span v-else>平台目的仓地址以最终履约安排为准</span></dd></div>
|
||||
</dl>
|
||||
<div v-if="detailOrder.customerRemark" class="customer-remark"><strong>客户备注</strong><p>{{ detailOrder.customerRemark }}</p></div>
|
||||
</section>
|
||||
<section v-if="detailOrder.status !== 'DRAFT'" class="detail-section">
|
||||
@@ -2289,28 +2281,28 @@ async function searchOrders(model: QueryModel) {
|
||||
<div v-for="item in progressSummaryItems" :key="item.label"><dt>{{ item.label }}</dt><dd>{{ item.value }}</dd></div>
|
||||
</dl>
|
||||
</section>
|
||||
<section v-if="detailOrder.status !== 'DRAFT'" class="detail-section">
|
||||
<h3>柜次进度</h3>
|
||||
<div v-if="cabinetProgressItems.length" class="cabinet-progress-list">
|
||||
<article v-for="cabinet in cabinetProgressItems" :key="cabinet.cabinetId" class="cabinet-progress-card">
|
||||
<header><strong>{{ cabinet.cabinetNo || '—' }}</strong><el-tag size="small" effect="plain">{{ cabinet.status || '待更新' }}</el-tag></header>
|
||||
<dl>
|
||||
<div><dt>柜号</dt><dd>{{ cabinet.cabinetNo || '—' }}</dd></div>
|
||||
<div><dt>船名 / 航次</dt><dd>{{ [cabinet.vesselName, cabinet.voyageNo].filter(Boolean).join(' · ') || '待更新' }}</dd></div>
|
||||
<div><dt>预计船期</dt><dd>{{ cabinet.sailingAt ? formatDateTime(cabinet.sailingAt) : '待更新' }}</dd></div>
|
||||
</dl>
|
||||
</article>
|
||||
</div>
|
||||
<el-empty v-else description="暂无柜次分配信息" :image-size="50" />
|
||||
</section>
|
||||
<OrderProgressPanel :order="detailOrder">
|
||||
<template #cabinet>
|
||||
<div class="cabinet-progress-detail">
|
||||
<strong>柜次明细</strong>
|
||||
<el-table v-if="cabinetProgressItems.length" :data="cabinetProgressItems" border size="small" class="cabinet-progress-table" row-key="cabinetId">
|
||||
<el-table-column prop="cabinetNo" label="柜号 / 柜次" min-width="150"><template #default="{ row }"><span class="table-code">{{ row.cabinetNo || '—' }}</span></template></el-table-column>
|
||||
<el-table-column label="船名 / 航次" min-width="180"><template #default="{ row }">{{ [row.vesselName, row.voyageNo].filter(Boolean).join(' · ') || '待更新' }}</template></el-table-column>
|
||||
<el-table-column label="预计船期" width="170"><template #default="{ row }">{{ row.sailingAt ? formatDateTime(row.sailingAt) : '待更新' }}</template></el-table-column>
|
||||
<el-table-column prop="status" label="当前节点" width="120"><template #default="{ row }"><el-tag size="small" effect="plain">{{ row.status || '待更新' }}</el-tag></template></el-table-column>
|
||||
</el-table>
|
||||
<p v-else class="detail-inline-empty">尚未分配柜次,后续柜次节点将在这里同步。</p>
|
||||
</div>
|
||||
</template>
|
||||
</OrderProgressPanel>
|
||||
<section class="detail-section">
|
||||
<h3>履约快递信息</h3>
|
||||
<div v-if="detailOrder.expressCompanyName || detailOrder.trackingNumber" class="express-information"><PackageCheck :size="20" /><div><span>快递公司</span><strong>{{ detailOrder.expressCompanyName || '待平台补充' }}</strong></div><div><span>快递单号</span><strong>{{ detailOrder.trackingNumber || '待平台补充' }}</strong></div></div>
|
||||
<dl v-if="detailOrder.expressCompanyName || detailOrder.trackingNumber" class="express-information"><div><dt>快递公司</dt><dd>{{ detailOrder.expressCompanyName || '待平台补充' }}</dd></div><div><dt>快递单号</dt><dd class="table-code">{{ detailOrder.trackingNumber || '待平台补充' }}</dd></div></dl>
|
||||
<div v-else class="express-empty"><PackageCheck :size="20" /><div><strong>平台尚未维护快递信息</strong><span>快递公司和快递单号由平台后台维护,客户端仅只读展示。</span></div></div>
|
||||
</section>
|
||||
<section class="detail-section">
|
||||
<h3>货物明细</h3>
|
||||
<div v-if="detailSummary" class="cargo-summary"><div><Box :size="18" /><span>明细</span><strong>{{ detailOrder.items.length }} 项</strong></div><div><span>件数</span><strong>{{ detailSummary.pieces }}</strong></div><div><span>毛重</span><strong>{{ detailSummary.grossWeightKg.toLocaleString() }} kg</strong></div><div><span>体积</span><strong>{{ detailSummary.volumeCbm }} m³</strong></div></div>
|
||||
<dl v-if="detailSummary" class="cargo-summary"><div><dt>明细</dt><dd>{{ detailOrder.items.length }} 项</dd></div><div><dt>件数</dt><dd>{{ detailSummary.pieces }}</dd></div><div><dt>毛重</dt><dd>{{ detailSummary.grossWeightKg.toLocaleString() }} kg</dd></div><div><dt>体积</dt><dd>{{ detailSummary.volumeCbm }} m³</dd></div></dl>
|
||||
<div v-if="detailOrder.items.length" class="cargo-detail-table-wrap">
|
||||
<el-table :data="pagedDetailCargoItems" border stripe class="cargo-detail-table" row-key="id">
|
||||
<el-table-column type="index" label="#" width="54" align="center" :index="(index: number) => (detailCargoPage - 1) * detailCargoPageSize + index + 1" />
|
||||
@@ -2354,7 +2346,6 @@ async function searchOrders(model: QueryModel) {
|
||||
</div>
|
||||
<el-empty v-else description="暂无货物明细" :image-size="56" />
|
||||
</section>
|
||||
<OrderProgressPanel :order="detailOrder" />
|
||||
<InboundBillingPanel
|
||||
:data="inboundBilling"
|
||||
:loading="inboundBillingLoading"
|
||||
@@ -2367,8 +2358,7 @@ async function searchOrders(model: QueryModel) {
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<template #footer><div v-if="detailOrder" class="editor-actions"><el-button @click="detailOpen = false">关闭</el-button><el-button v-if="canEditOrder && canClientEditFirstLegOrder(detailOrder.status)" :loading="openingEditor" @click="openEdit(detailOrder)"><Pencil :size="16" />编辑草稿</el-button></div></template>
|
||||
</el-dialog>
|
||||
</section>
|
||||
<InboundBillingPanel
|
||||
v-if="feeConfirmationOpen"
|
||||
dialog-only
|
||||
@@ -2398,9 +2388,10 @@ async function searchOrders(model: QueryModel) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.first-leg-page { display: flex; flex-direction: column; gap: var(--client-section-gap); }
|
||||
.first-leg-page { display: flex; min-width: 0; flex-direction: column; gap: var(--client-section-gap); }
|
||||
:global(.client-main:has(> .first-leg-page:not(.is-create-route)) > .client-page-heading) { margin-bottom: 0; }
|
||||
:global(.client-main:has(> .first-leg-page:not(.is-create-route)) > .client-page-heading > div) { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; border: 0; clip: rect(0 0 0 0); white-space: nowrap; }
|
||||
:global(.client-main:has(> .first-leg-page.is-detail-route) > .client-page-heading) { display: none; }
|
||||
.order-eligibility { display: flex; align-items: flex-start; gap: 12px; padding: 14px 16px; border: 1px solid; }
|
||||
.order-eligibility svg { flex: 0 0 20px; margin-top: 1px; }
|
||||
.order-eligibility div { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 3px; }
|
||||
@@ -2413,6 +2404,12 @@ async function searchOrders(model: QueryModel) {
|
||||
.supporting-data-error span { overflow-wrap: anywhere; color: var(--muted); font-size: 11px; line-height: 1.55; }
|
||||
.order-row-actions, .editor-actions { display: flex; justify-content: flex-end; gap: 8px; }
|
||||
.order-table-card { padding: 0; overflow: hidden; border: 1px solid var(--client-border); border-radius: var(--client-radius); box-shadow: none; }
|
||||
.order-queue-tabs { display: flex; align-items: center; gap: 4px; }
|
||||
.order-queue-tabs button { position: relative; min-height: 34px; padding: 0 12px; border: 1px solid transparent; border-radius: 7px; background: transparent; color: #667085; cursor: pointer; font: inherit; font-weight: 600; }
|
||||
.order-queue-tabs button:hover { color: var(--client-action); }
|
||||
.order-queue-tabs button.active { border-color: #cfe0ff; background: #f3f7ff; color: var(--client-action); }
|
||||
.order-queue-tabs button:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
||||
.queue-count { position: absolute; display: grid; min-width: 18px; height: 18px; place-items: center; padding: 0 4px; border: 2px solid #fff; border-radius: 999px; background: #ef5350; color: #fff; font-size: 10px; line-height: 1; right: -4px; top: -8px; }
|
||||
.batch-import-dialog { display: flex; flex-direction: column; gap: 18px; }
|
||||
.batch-import-actions { display: flex; min-width: 0; align-items: center; flex-wrap: wrap; gap: 10px; }
|
||||
.batch-import-actions > span { min-width: 0; overflow: hidden; color: var(--muted); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
@@ -2421,7 +2418,7 @@ async function searchOrders(model: QueryModel) {
|
||||
.batch-import-result > span, .batch-import-result li { color: var(--muted); font-size: 12px; line-height: 1.55; }
|
||||
.batch-import-result-actions { display: flex; margin-top: 4px; }
|
||||
.batch-import-result ul { max-height: 180px; margin: 4px 0 0; padding-left: 20px; overflow-y: auto; }
|
||||
.column-settings-trigger { width: 40px; min-width: 40px; height: 36px; padding: 0; color: #53627b; }
|
||||
.column-settings-trigger { min-width: 116px; height: 36px; padding: 0 12px; color: #53627b; }
|
||||
:global(.order-column-popper.el-popover) { padding: 0; border-color: #e3e8f0; border-radius: 4px; box-shadow: 0 8px 24px rgba(29, 45, 74, .12); }
|
||||
:global(.order-column-popper .column-settings-panel) { padding: 14px 10px 10px; }
|
||||
:global(.order-column-popper .column-settings-panel > p) { margin: 0 8px 10px; color: #778398; font-size: 12px; line-height: 1.5; }
|
||||
@@ -2443,20 +2440,14 @@ async function searchOrders(model: QueryModel) {
|
||||
.order-load-state strong { color: var(--navy); font-size: 14px; }
|
||||
.order-load-state span { overflow-wrap: anywhere; color: var(--muted); font-size: 12px; line-height: 1.55; }
|
||||
.order-load-state.is-compact { min-height: 180px; }
|
||||
.order-detail-content { min-height: 180px; }
|
||||
:global(.first-leg-detail-dialog.el-dialog) { display: flex; max-width: 1500px; height: 94vh; margin-bottom: 0; flex-direction: column; overflow: hidden; border-radius: 6px; }
|
||||
:global(.first-leg-detail-dialog .el-dialog__header) { flex: 0 0 auto; margin-right: 0; padding: 17px 22px; border-bottom: 1px solid var(--border); }
|
||||
:global(.first-leg-detail-dialog .el-dialog__title) { color: var(--navy); font-size: 16px; font-weight: 700; }
|
||||
:global(.first-leg-detail-dialog .el-dialog__headerbtn) { top: 8px; right: 10px; width: 44px; height: 44px; }
|
||||
:global(.first-leg-detail-dialog .el-dialog__body) { min-height: 0; flex: 1 1 auto; overflow-y: auto; padding: 22px 24px 28px; overscroll-behavior: contain; }
|
||||
:global(.first-leg-detail-dialog .el-dialog__footer) { flex: 0 0 auto; padding: 12px 22px; border-top: 1px solid var(--border); background: #fff; }
|
||||
.mobile-order-surface { display: none; min-height: 220px; }
|
||||
.mobile-order-list { display: none; }
|
||||
.order-number-link { display: block; width: 100%; max-width: 100%; overflow: hidden; padding: 0; border: 0; background: none; color: var(--client-action); cursor: pointer; font-size: var(--client-font-size); font-weight: 700; line-height: 18px; text-align: left; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.first-leg-detail-page { min-width: 0; padding: 10px 14px 20px; overflow: hidden; border: 1px solid var(--client-border); border-radius: var(--client-radius); background: #fff; }
|
||||
.order-detail-content { min-height: 360px; }
|
||||
.inbound-code-primary { display: block; width: 100%; max-width: 100%; overflow: hidden; padding: 0; border: 0; background: none; color: var(--client-action); cursor: pointer; font-size: var(--client-font-size); font-weight: 700; line-height: 18px; text-align: left; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.pending-inbound-code { color: var(--muted); font-size: 12px; }
|
||||
.inbound-code-link { max-width: 100%; overflow: hidden; padding: 0; border: 0; background: transparent; color: var(--client-action); cursor: pointer; text-align: left; text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.inbound-code-link:hover, .inbound-code-link:focus-visible { text-decoration-color: currentColor; }
|
||||
.inbound-code-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
||||
.order-number-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
|
||||
.inbound-code-primary:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
|
||||
.order-reference { display: block; margin-top: 4px; color: var(--muted); font-size: 11px; font-weight: 400; }
|
||||
.order-row-actions { align-items: center; justify-content: center; gap: 6px; white-space: nowrap; }
|
||||
.order-row-actions :deep(.el-button) { margin-left: 0; padding: 3px 1px; font-size: 11px; }
|
||||
@@ -2619,51 +2610,49 @@ async function searchOrders(model: QueryModel) {
|
||||
.dimension-inputs > span { color: var(--muted); }
|
||||
.cargo-detail-image { display: flex; width: 112px; height: 112px; align-items: center; justify-content: center; margin-top: 12px; overflow: hidden; border: 1px solid var(--border); background: #fff; color: var(--muted); font-size: 10px; text-align: center; }
|
||||
.cargo-detail-image img { width: 100%; height: 100%; object-fit: contain; }
|
||||
.order-detail-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding-bottom: 20px; border-bottom: 1px solid var(--border); }
|
||||
.order-detail-heading span { color: var(--muted); font-size: 11px; }
|
||||
.order-detail-heading h2 { margin: 6px 0; font-size: 21px; }
|
||||
.order-detail-heading p { margin: 0; color: var(--muted); }
|
||||
.order-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; margin: 18px 0; border: 1px solid var(--border); }
|
||||
.order-detail-grid div { padding: 13px; border-bottom: 1px solid var(--border); }
|
||||
.order-detail-grid div:nth-child(odd) { border-right: 1px solid var(--border); }
|
||||
.order-detail-grid dt { color: var(--muted); font-size: 11px; }
|
||||
.order-detail-grid dd { margin: 5px 0 0; font-size: 13px; font-weight: 600; }
|
||||
.detail-subline { display: block; margin-top: 4px; color: var(--muted); font-size: 11px; font-weight: 400; line-height: 1.5; }
|
||||
.detail-section { margin-top: 22px; }
|
||||
.detail-section h3 { margin: 0 0 12px; font-size: 15px; }
|
||||
.party-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
||||
.party-detail-grid article { min-width: 0; padding: 15px; border: 1px solid var(--border); background: #fbfcfc; }
|
||||
.party-detail-grid span { display: block; color: var(--muted); font-size: 10px; }
|
||||
.party-detail-grid strong { display: block; margin-top: 5px; overflow-wrap: anywhere; color: var(--navy); font-size: 13px; }
|
||||
.party-detail-grid p, .customer-remark p { margin: 7px 0 0; overflow-wrap: anywhere; color: var(--muted); font-size: 11px; line-height: 1.65; }
|
||||
.customer-remark { margin-top: 10px; padding: 13px 15px; background: #f2f7f6; }
|
||||
.order-detail-heading { display: flex; min-height: 50px; align-items: center; justify-content: space-between; gap: 16px; padding: 5px 0; border-bottom: 1px solid var(--border); }
|
||||
.detail-heading-main, .detail-heading-actions { display: flex; min-width: 0; align-items: center; gap: 12px; }
|
||||
.detail-heading-main > div { min-width: 0; }
|
||||
.detail-back-action, .detail-heading-actions { flex: 0 0 auto; }
|
||||
.order-detail-heading h2 { margin: 0; overflow: hidden; color: var(--navy); font-size: 18px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.order-detail-heading p { margin: 3px 0 0; overflow: hidden; color: var(--muted); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.order-detail-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin: 0; border-top: 1px solid var(--border); border-left: 1px solid var(--border); }
|
||||
.order-detail-grid div { display: grid; min-width: 0; min-height: 34px; grid-template-columns: 78px minmax(0, 1fr); align-items: center; gap: 7px; padding: 3px 8px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.order-detail-grid dt { color: var(--muted); font-size: 10px; white-space: nowrap; }
|
||||
.order-detail-grid dd { min-width: 0; margin: 0; overflow-wrap: anywhere; font-size: 12px; font-weight: 600; }
|
||||
.detail-subline { display: block; margin-top: 2px; color: var(--muted); font-size: 9px; font-weight: 400; line-height: 1.35; }
|
||||
.detail-section { margin-top: 10px; }
|
||||
.detail-section h3 { margin: 0; padding: 0 0 5px; border-bottom: 1px solid #eaf0f7; color: var(--navy); font-size: 13px; }
|
||||
.party-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; border-left: 1px solid var(--border); }
|
||||
.party-detail-grid > div { display: grid; min-width: 0; grid-template-columns: 62px minmax(0, 1fr); gap: 7px; padding: 5px 8px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.party-detail-grid dt { color: var(--muted); font-size: 10px; }
|
||||
.party-detail-grid dd { min-width: 0; margin: 0; }
|
||||
.party-detail-grid strong { display: block; overflow-wrap: anywhere; color: var(--navy); font-size: 12px; }
|
||||
.party-detail-grid span { display: block; margin-top: 3px; overflow-wrap: anywhere; color: var(--muted); font-size: 10px; line-height: 1.5; }
|
||||
.customer-remark p { margin: 7px 0 0; overflow-wrap: anywhere; color: var(--muted); font-size: 11px; line-height: 1.65; }
|
||||
.customer-remark { margin-top: 7px; padding: 8px 10px; background: #f2f7f6; }
|
||||
.customer-remark strong { color: var(--navy); font-size: 11px; }
|
||||
.fulfillment-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 0; border: 1px solid var(--border); }
|
||||
.fulfillment-summary > div { min-width: 0; padding: 13px; border-bottom: 1px solid var(--border); }
|
||||
.fulfillment-summary > div:not(:nth-child(3n)) { border-right: 1px solid var(--border); }
|
||||
.fulfillment-summary > div:nth-last-child(-n + 3) { border-bottom: 0; }
|
||||
.fulfillment-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; border-left: 1px solid var(--border); }
|
||||
.fulfillment-summary > div { display: grid; min-width: 0; min-height: 34px; grid-template-columns: 70px minmax(0, 1fr); align-items: center; gap: 7px; padding: 3px 8px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.fulfillment-summary dt { color: var(--muted); font-size: 10px; }
|
||||
.fulfillment-summary dd { margin: 5px 0 0; overflow-wrap: anywhere; color: var(--navy); font-size: 12px; font-weight: 650; }
|
||||
.cabinet-progress-list { display: grid; gap: 10px; }
|
||||
.cabinet-progress-card { padding: 14px 15px; border: 1px solid var(--border); background: #fbfcfc; }
|
||||
.cabinet-progress-card header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
||||
.cabinet-progress-card header strong { color: var(--navy); font-size: 13px; }
|
||||
.cabinet-progress-card dl { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin: 13px 0 0; }
|
||||
.cabinet-progress-card dt { color: var(--muted); font-size: 10px; }
|
||||
.cabinet-progress-card dd { margin: 4px 0 0; overflow-wrap: anywhere; color: var(--navy); font-size: 11px; font-weight: 600; }
|
||||
.express-information { display: grid; grid-template-columns: auto repeat(2, minmax(0, 1fr)); align-items: center; gap: 16px; padding: 15px 16px; background: #f2f7f6; color: var(--primary); }
|
||||
.express-information > div { display: flex; min-width: 0; flex-direction: column; gap: 4px; }
|
||||
.express-information span { color: var(--muted); font-size: 11px; }
|
||||
.express-information strong { overflow-wrap: anywhere; color: var(--navy); font-size: 13px; }
|
||||
.express-empty { display: flex; align-items: flex-start; gap: 12px; padding: 15px 16px; border: 1px dashed #cbd5da; color: var(--muted); }
|
||||
.fulfillment-summary dd { min-width: 0; margin: 0; overflow-wrap: anywhere; color: var(--navy); font-size: 11px; font-weight: 650; }
|
||||
.cabinet-progress-detail { border-top: 1px solid var(--border); }
|
||||
.cabinet-progress-detail > strong { display: block; padding: 7px 0 5px; color: var(--navy); font-size: 11px; }
|
||||
.cabinet-progress-table { margin-top: 0; }
|
||||
.detail-inline-empty { margin: 0; padding: 7px 9px; background: #f7f9fb; color: var(--muted); font-size: 10px; }
|
||||
.express-information { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 0; border-left: 1px solid var(--border); }
|
||||
.express-information > div { display: grid; min-width: 0; min-height: 40px; grid-template-columns: 70px minmax(0, 1fr); align-items: center; gap: 8px; padding: 6px 10px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.express-information dt { color: var(--muted); font-size: 10px; }
|
||||
.express-information dd { min-width: 0; margin: 0; overflow-wrap: anywhere; color: var(--navy); font-size: 11px; font-weight: 650; }
|
||||
.express-empty { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border: 1px dashed #cbd5da; color: var(--muted); }
|
||||
.express-empty svg { flex: 0 0 20px; color: var(--primary); }
|
||||
.express-empty div { display: flex; min-width: 0; flex-direction: column; gap: 4px; }
|
||||
.express-empty strong { color: var(--navy); font-size: 13px; }
|
||||
.express-empty span { font-size: 11px; line-height: 1.5; }
|
||||
.cargo-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border: 1px solid var(--border); }
|
||||
.cargo-summary div { display: flex; min-height: 74px; align-items: center; justify-content: center; flex-direction: column; gap: 4px; border-right: 1px solid var(--border); }
|
||||
.cargo-summary div:last-child { border-right: 0; }
|
||||
.cargo-summary span { color: var(--muted); font-size: 11px; }
|
||||
.cargo-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; border-left: 1px solid var(--border); }
|
||||
.cargo-summary div { display: grid; min-width: 0; min-height: 34px; grid-template-columns: 54px minmax(0, 1fr); align-items: center; gap: 7px; padding: 3px 8px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.cargo-summary dt { color: var(--muted); font-size: 10px; }
|
||||
.cargo-summary dd { margin: 0; color: var(--navy); font-size: 11px; font-weight: 700; }
|
||||
.cargo-detail-table-wrap { overflow: hidden; margin-top: 10px; border: 1px solid var(--border); border-radius: 5px; background: #fff; }
|
||||
.cargo-detail-table { width: 100%; font-size: 11px; }
|
||||
.cargo-detail-table :deep(.el-table__header th.el-table__cell) { height: 42px; padding: 0; background: #f7f8fb; color: #657187; font-size: 11px; font-weight: 650; white-space: nowrap; }
|
||||
@@ -2677,20 +2666,7 @@ async function searchOrders(model: QueryModel) {
|
||||
:deep(.el-timeline-item__content > span) { font-size: 11px; }
|
||||
@media (max-width: 1280px) {
|
||||
.first-leg-query-toolbar :deep(.query-toolbar__filters) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.prototype-order-table :deep(> .el-table), .prototype-order-table :deep(> .data-table__pagination) { display: none; }
|
||||
.mobile-order-surface { display: block; }
|
||||
.mobile-order-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding: 10px; }
|
||||
.mobile-order-card { min-width: 0; padding: 14px; border: 1px solid var(--border); background: #fff; }
|
||||
.mobile-order-card header, .mobile-order-card footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
||||
.mobile-order-card header button { min-width: 0; overflow: hidden; padding: 0; border: 0; background: none; color: var(--primary); font-weight: 750; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.mobile-order-card header button:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
|
||||
.mobile-order-card dl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 14px 0; }
|
||||
.mobile-order-card dl div { min-width: 0; }
|
||||
.mobile-order-card dt, .mobile-order-card footer > span { color: var(--muted); font-size: 10px; }
|
||||
.mobile-order-card dd { overflow: hidden; margin: 4px 0 0; font-size: 12px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.mobile-order-card dd span { margin-left: 4px; color: var(--muted); font-weight: 400; }
|
||||
.mobile-order-card footer { align-items: flex-end; padding-top: 10px; border-top: 1px solid var(--border); }
|
||||
.mobile-order-card footer > div { display: flex; }
|
||||
.order-detail-grid, .fulfillment-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
@media (min-width: 721px) and (max-width: 1050px) {
|
||||
.cargo-form-grid, .cargo-form-grid--basic { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
@@ -2706,7 +2682,7 @@ async function searchOrders(model: QueryModel) {
|
||||
.product-image-field { grid-row: auto; }
|
||||
.product-dimensions-field, .cargo-remark-field { grid-column: auto; }
|
||||
.fulfillment-summary { grid-template-columns: 1fr; }
|
||||
.fulfillment-summary > div, .fulfillment-summary > div:not(:nth-child(3n)) { border-right: 0; border-bottom: 1px solid var(--border); }
|
||||
.fulfillment-summary > div { border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); }
|
||||
.fulfillment-summary > div:last-child { border-bottom: 0; }
|
||||
.prototype-form-row, .prototype-form-row--wide, .prototype-form-row--compact, .prototype-form-row--short, .prototype-form-row--tabs { display: block; margin-bottom: 18px; }
|
||||
.prototype-form-row :deep(.el-form-item__label) { min-height: auto; justify-content: flex-start; padding: 0 0 8px; line-height: 1.4; }
|
||||
@@ -2728,38 +2704,23 @@ async function searchOrders(model: QueryModel) {
|
||||
.price-estimate__state.is-error { align-items: flex-start; flex-direction: column; }
|
||||
.form-span-full { grid-column: auto; }
|
||||
.editor-actions :deep(.el-button) { min-height: 44px; }
|
||||
.prototype-order-table :deep(> .el-table), .prototype-order-table :deep(> .data-table__pagination) { display: none; }
|
||||
.order-load-state { min-height: 240px; grid-template-columns: 1fr; justify-items: start; }
|
||||
.supporting-data-error { grid-template-columns: auto minmax(0, 1fr); }
|
||||
.supporting-data-error .el-button { grid-column: 1 / -1; width: 100%; min-height: 44px; }
|
||||
.order-load-state .el-button { width: 100%; min-height: 44px; }
|
||||
.mobile-order-list { grid-template-columns: 1fr; }
|
||||
.mobile-order-card { padding: 14px; border: 1px solid var(--border); background: #fff; }
|
||||
.mobile-order-card header, .mobile-order-card footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
|
||||
.mobile-order-card header button { padding: 0; border: 0; background: none; color: var(--primary); font-weight: 750; }
|
||||
.mobile-order-card header button:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
|
||||
.mobile-order-card dl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 14px 0; }
|
||||
.mobile-order-card dl div { min-width: 0; }
|
||||
.mobile-order-card dt, .mobile-order-card footer > span { color: var(--muted); font-size: 10px; }
|
||||
.mobile-order-card dd { overflow: hidden; margin: 4px 0 0; font-size: 12px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.mobile-order-card dd span { margin-left: 4px; color: var(--muted); font-weight: 400; }
|
||||
.mobile-order-card footer { align-items: flex-end; padding-top: 10px; border-top: 1px solid var(--border); }
|
||||
.mobile-order-card footer > div { display: flex; }
|
||||
.order-detail-grid div:nth-child(odd) { border-right: 0; }
|
||||
.express-information { grid-template-columns: auto 1fr; }
|
||||
.express-information > div:last-child { grid-column: 2; }
|
||||
.express-information { grid-template-columns: 1fr; }
|
||||
.cargo-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.cargo-summary div:nth-child(2) { border-right: 0; }
|
||||
.cargo-summary div:nth-child(-n+2) { border-bottom: 1px solid var(--border); }
|
||||
.cabinet-progress-card dl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
:global(.first-leg-detail-dialog.el-dialog) { width: calc(100vw - 24px) !important; height: 96vh; margin-top: 2vh; }
|
||||
}
|
||||
@media (max-width: 360px) {
|
||||
.cargo-detail-pagination { justify-content: flex-start; overflow-x: auto; }
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
:global(.first-leg-detail-dialog.el-dialog) { width: 100vw !important; height: 100vh; margin: 0; border-radius: 0; }
|
||||
:global(.first-leg-detail-dialog .el-dialog__body) { padding: 16px 12px 22px; }
|
||||
.first-leg-detail-page { padding-bottom: 22px; }
|
||||
.order-detail-heading { align-items: flex-start; flex-direction: column; }
|
||||
.detail-heading-main { width: 100%; align-items: flex-start; }
|
||||
.detail-heading-actions { width: 100%; justify-content: flex-end; }
|
||||
.editor-actions { display: grid; width: 100%; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.editor-actions :deep(.el-button) { width: 100%; min-width: 0; margin-left: 0; }
|
||||
.editor-actions :deep(.el-button:nth-child(3)) { grid-column: 1 / -1; }
|
||||
|
||||
Reference in New Issue
Block a user