优化
This commit is contained in:
@@ -4,12 +4,31 @@ import { useRouter } from 'vue-router'
|
||||
import { ArrowLeft } from '@lucide/vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { getDeliveryOrder, type DeliveryOrderDetail, type DeliveryOrderItem } from '../api/deliveryOrders'
|
||||
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
|
||||
|
||||
const props = defineProps<{ deliveryNo: string }>()
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const detail = ref<DeliveryOrderDetail | null>(null)
|
||||
const statusLabels: Record<string, string> = { PENDING: '待派送', IN_TRANSIT: '派送中', DELIVERED: '已送达', SIGNED: '已签收', CANCELLED: '已取消' }
|
||||
const deliveryMethodLabels: Record<string, string> = { FBA_PICKUP: 'FBA 自提', CUSTOMER_PICKUP: '客户自提', TRUCK_PALLET: '卡派打托', TRUCK_FLOOR: '卡派地板', EXPRESS: '快递', OUTSOURCED: '外配', DEDICATED_TRUCK: '专车直送', LTL: '零担派送' }
|
||||
const pickupMethodLabels: Record<string, string> = { ONE_PICKUP_ONE_DROP: '一提一卸', ONE_PICKUP_MULTI_DROP: '一提多卸', MULTI_PICKUP_ONE_DROP: '多提一卸', MULTI_PICKUP_MULTI_DROP: '多提多卸', WAREHOUSE_PICKUP: '仓库自提' }
|
||||
const loadingTypeLabels: Record<string, string> = { PALLET: '托盘', FLOOR: '地板', MIXED: '混装' }
|
||||
const vehicleTypeLabels: Record<string, string> = { TRUCK: '卡车', VAN: '厢式货车', BOX_TRUCK: '箱式货车', TRAILER: '拖挂车' }
|
||||
const appointmentAccountLabels: Record<string, string> = { SELF: '自有账号', PLATFORM: '平台账号', CARRIER: '承运商账号' }
|
||||
const tableValueFormatter = (_row: object, _column: unknown, value: string | number | null | undefined) => display(value)
|
||||
const itemColumns: DataTableColumn[] = [
|
||||
{ prop: 'palletNo', label: '托盘码', minWidth: 170, formatter: tableValueFormatter }, { prop: 'inboundCode', label: '入仓码', minWidth: 190, formatter: tableValueFormatter },
|
||||
{ prop: 'skuCode', label: 'SKU', minWidth: 160, formatter: tableValueFormatter }, { prop: 'productName', label: '品名', minWidth: 180, formatter: tableValueFormatter },
|
||||
{ prop: 'packageCount', label: '箱数', width: 90, align: 'right', headerAlign: 'right', formatter: tableValueFormatter },
|
||||
{ prop: 'weightKg', label: '重量(kg)', width: 120, align: 'right', headerAlign: 'right', formatter: tableValueFormatter },
|
||||
{ prop: 'volumeCbm', label: '体积(m³)', width: 120, align: 'right', headerAlign: 'right', formatter: tableValueFormatter },
|
||||
]
|
||||
const feeColumns: DataTableColumn[] = [
|
||||
{ prop: 'feeType', label: '费用类型', minWidth: 180, formatter: tableValueFormatter }, { prop: 'currency', label: '币种', width: 100, formatter: tableValueFormatter },
|
||||
{ prop: 'amount', label: '金额', width: 140, align: 'right', headerAlign: 'right', formatter: tableValueFormatter }, { prop: 'remark', label: '备注', minWidth: 240, formatter: tableValueFormatter },
|
||||
]
|
||||
|
||||
const items = computed<DeliveryOrderItem[]>(() => {
|
||||
const value = detail.value?.items
|
||||
@@ -29,6 +48,17 @@ function formatQuantity(value: number | null | undefined, unit: string) {
|
||||
return value === null || value === undefined ? '—' : `${value} ${unit}`
|
||||
}
|
||||
|
||||
function statusLabel(value: string) { return statusLabels[value] ?? display(value) }
|
||||
function statusTone(value: string) {
|
||||
if (value === 'DELIVERED' || value === 'SIGNED') return 'success'
|
||||
if (value === 'IN_TRANSIT') return 'primary'
|
||||
if (value === 'CANCELLED') return 'danger'
|
||||
return 'warning'
|
||||
}
|
||||
function mappedLabel(value: string | null | undefined, labels: Record<string, string>) {
|
||||
return value ? labels[value] ?? value : '—'
|
||||
}
|
||||
|
||||
async function loadDetail() {
|
||||
loading.value = true
|
||||
errorMessage.value = ''
|
||||
@@ -50,24 +80,28 @@ onMounted(loadDetail)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="delivery-page" aria-labelledby="delivery-detail-title">
|
||||
<button type="button" class="delivery-back" @click="backToList"><ArrowLeft :size="16" />返回派送单列表</button>
|
||||
<div class="delivery-heading"><div><h2 id="delivery-detail-title">派送单详情</h2><p>{{ display(detail?.deliveryNo || deliveryNo) }}</p></div></div>
|
||||
|
||||
<section class="delivery-page" aria-label="派送单详情">
|
||||
<div v-if="errorMessage" class="delivery-card delivery-state delivery-state--error" role="alert"><p>{{ errorMessage }}</p><el-button @click="loadDetail">重试</el-button></div>
|
||||
<div v-else v-loading="loading" class="delivery-detail-content">
|
||||
<template v-if="detail">
|
||||
<section class="delivery-card delivery-section">
|
||||
<h3>订单信息</h3>
|
||||
<article class="delivery-detail-surface">
|
||||
<header class="delivery-detail-header">
|
||||
<div class="delivery-detail-title">
|
||||
<el-button link type="primary" @click="backToList"><ArrowLeft :size="16" />返回列表</el-button>
|
||||
<div><h2>{{ display(detail.deliveryNo) }}</h2><p>{{ display(detail.overseasWarehouseName) }} · {{ mappedLabel(detail.deliveryMethod, deliveryMethodLabels) }}</p></div>
|
||||
</div>
|
||||
<span class="client-status" :data-tone="statusTone(detail.status)">{{ statusLabel(detail.status) }}</span>
|
||||
</header>
|
||||
|
||||
<section class="delivery-detail-section">
|
||||
<h3>订单概览</h3>
|
||||
<div class="delivery-detail-grid">
|
||||
<div><span>派送单号</span><strong>{{ display(detail.deliveryNo) }}</strong></div>
|
||||
<div><span>排车单号</span><strong>{{ display(detail.dispatchNo) }}</strong></div>
|
||||
<div><span>出库单号</span><strong>{{ display(detail.outboundNo) }}</strong></div>
|
||||
<div><span>状态</span><strong>{{ display(detail.status) }}</strong></div>
|
||||
<div><span>海外仓</span><strong>{{ display(detail.overseasWarehouseName) }}</strong></div>
|
||||
<div><span>派送方式</span><strong>{{ display(detail.deliveryMethod) }}</strong></div>
|
||||
<div><span>提货方式</span><strong>{{ display(detail.pickupMethod) }}</strong></div>
|
||||
<div><span>装载类型</span><strong>{{ display(detail.loadingType) }}</strong></div>
|
||||
<div><span>派送方式</span><strong>{{ mappedLabel(detail.deliveryMethod, deliveryMethodLabels) }}</strong></div>
|
||||
<div><span>提货方式</span><strong>{{ mappedLabel(detail.pickupMethod, pickupMethodLabels) }}</strong></div>
|
||||
<div><span>装载类型</span><strong>{{ mappedLabel(detail.loadingType, loadingTypeLabels) }}</strong></div>
|
||||
<div><span>托盘数</span><strong>{{ formatQuantity(detail.palletCount, '托') }}</strong></div>
|
||||
<div><span>箱数</span><strong>{{ formatQuantity(detail.packageCount, '箱') }}</strong></div>
|
||||
<div><span>总重量</span><strong>{{ formatQuantity(detail.totalWeightKg, 'kg') }}</strong></div>
|
||||
@@ -75,17 +109,17 @@ onMounted(loadDetail)
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="delivery-card delivery-section">
|
||||
<section class="delivery-detail-section">
|
||||
<h3>运输与预约</h3>
|
||||
<div class="delivery-detail-grid">
|
||||
<div><span>运单号</span><strong>{{ display(detail.waybillNo) }}</strong></div>
|
||||
<div><span>承运商</span><strong>{{ display(detail.carrierName) }}</strong></div>
|
||||
<div><span>车型</span><strong>{{ display(detail.vehicleType) }}</strong></div>
|
||||
<div><span>车型</span><strong>{{ mappedLabel(detail.vehicleType, vehicleTypeLabels) }}</strong></div>
|
||||
<div><span>车辆尺寸</span><strong>{{ display(detail.vehicleSize) }}</strong></div>
|
||||
<div><span>车牌号</span><strong>{{ display(detail.vehiclePlate) }}</strong></div>
|
||||
<div><span>司机姓名</span><strong>{{ display(detail.driverName) }}</strong></div>
|
||||
<div><span>司机电话</span><strong>{{ display(detail.driverPhone) }}</strong></div>
|
||||
<div><span>预约账号</span><strong>{{ display(detail.appointmentAccount) }}</strong></div>
|
||||
<div><span>预约账号</span><strong>{{ mappedLabel(detail.appointmentAccount, appointmentAccountLabels) }}</strong></div>
|
||||
<div><span>卖家名称</span><strong>{{ display(detail.sellerName) }}</strong></div>
|
||||
<div><span>计划派送</span><strong>{{ formatDateTime(detail.plannedDeliveryAt) }}</strong></div>
|
||||
<div><span>预计到达</span><strong>{{ formatDateTime(detail.expectedArrivalAt) }}</strong></div>
|
||||
@@ -96,28 +130,16 @@ onMounted(loadDetail)
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="delivery-card delivery-section">
|
||||
<h3>货物明细</h3>
|
||||
<el-table :data="items" empty-text="暂无货物明细">
|
||||
<el-table-column prop="palletNo" label="托盘码" min-width="150"><template #default="{ row }">{{ display(row.palletNo) }}</template></el-table-column>
|
||||
<el-table-column prop="inboundCode" label="入仓码" min-width="150"><template #default="{ row }">{{ display(row.inboundCode) }}</template></el-table-column>
|
||||
<el-table-column prop="skuCode" label="SKU" min-width="140"><template #default="{ row }">{{ display(row.skuCode) }}</template></el-table-column>
|
||||
<el-table-column prop="productName" label="品名" min-width="180"><template #default="{ row }">{{ display(row.productName) }}</template></el-table-column>
|
||||
<el-table-column prop="packageCount" label="箱数" width="100"><template #default="{ row }">{{ display(row.packageCount) }}</template></el-table-column>
|
||||
<el-table-column prop="weightKg" label="重量(kg)" width="120"><template #default="{ row }">{{ display(row.weightKg) }}</template></el-table-column>
|
||||
<el-table-column prop="volumeCbm" label="体积(m³)" width="120"><template #default="{ row }">{{ display(row.volumeCbm) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<section class="delivery-detail-section">
|
||||
<div class="delivery-detail-section-heading"><h3>货物明细</h3><span>共 {{ items.length }} 条</span></div>
|
||||
<DataTable :data="items" :columns="itemColumns" empty-text="暂无货物明细" />
|
||||
</section>
|
||||
|
||||
<section class="delivery-card delivery-section">
|
||||
<h3>费用明细</h3>
|
||||
<el-table :data="detail.fees || []" empty-text="暂无费用明细">
|
||||
<el-table-column prop="feeType" label="费用类型" min-width="180"><template #default="{ row }">{{ display(row.feeType) }}</template></el-table-column>
|
||||
<el-table-column prop="currency" label="币种" width="110"><template #default="{ row }">{{ display(row.currency) }}</template></el-table-column>
|
||||
<el-table-column prop="amount" label="金额" width="140"><template #default="{ row }">{{ display(row.amount) }}</template></el-table-column>
|
||||
<el-table-column prop="remark" label="备注" min-width="220"><template #default="{ row }">{{ display(row.remark) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<section class="delivery-detail-section">
|
||||
<div class="delivery-detail-section-heading"><h3>费用明细</h3><span>共 {{ detail.fees.length }} 条</span></div>
|
||||
<DataTable :data="detail.fees" :columns="feeColumns" empty-text="暂无费用明细" />
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { Plus, RefreshCw, Search } from '@lucide/vue'
|
||||
import { Plus } from '@lucide/vue'
|
||||
import dayjs from 'dayjs'
|
||||
import { useAuthStore } from '@/modules/auth/public'
|
||||
import { listDeliveryOrders, type DeliveryQuery, type DeliveryRow } from '../api/deliveryOrders'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/components/common/QueryToolbar.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
|
||||
import type { TableAction } from '@/components/common/tableActions'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
@@ -26,6 +29,23 @@ const statusOptions = [
|
||||
]
|
||||
|
||||
const statusLabels: Record<string, string> = Object.fromEntries(statusOptions.map((item) => [item.value, item.label]))
|
||||
const queryModel = computed<QueryModel>({ get: () => ({ ...filters }), set: (value) => Object.assign(filters, value) })
|
||||
const queryFields: QueryField[] = [
|
||||
{ key: 'documentNo', label: '派送单 / 出库单', type: 'input', placeholder: '请输入派送单号或出库单号' },
|
||||
{ key: 'dispatchNo', label: '排车单号', type: 'input', placeholder: '请输入排车单号' },
|
||||
{ key: 'waybillNo', label: '运单号', type: 'input', placeholder: '请输入运单号' },
|
||||
{ key: 'status', label: '派送状态', type: 'select', options: statusOptions },
|
||||
{ key: 'deliveryMethod', label: '派送方式', type: 'select', options: [{ label: '卡车派送', value: 'TRUCK' }, { label: '快递派送', value: 'COURIER' }, { label: '客户自提', value: 'SELF_PICKUP' }] },
|
||||
{ key: 'plannedRange', label: '计划时间', type: 'daterange' },
|
||||
]
|
||||
const tableColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', slotName: 'actions', width: 90, fixed: 'left' }, { prop: 'deliveryNo', label: '派送单号', minWidth: 180 },
|
||||
{ prop: 'dispatchNo', label: '排车单号', minWidth: 170 }, { prop: 'outboundNo', label: '出库单号', minWidth: 170 },
|
||||
{ key: 'status', label: '状态', slotName: 'status', width: 110 }, { prop: 'overseasWarehouseName', label: '海外仓', minWidth: 160 },
|
||||
{ prop: 'deliveryMethod', label: '派送方式', width: 120 }, { prop: 'waybillNo', label: '运单号', minWidth: 150 },
|
||||
{ prop: 'carrierName', label: '承运商', minWidth: 140 }, { key: 'planned', label: '计划派送', slotName: 'planned', width: 160 },
|
||||
{ key: 'arrival', label: '预计到达', slotName: 'arrival', width: 160 }, { key: 'createdAt', label: '创建时间', slotName: 'createdAt', width: 160 },
|
||||
]
|
||||
|
||||
function display(value: string | number | null | undefined) {
|
||||
return value === null || value === undefined || value === '' ? '—' : String(value)
|
||||
@@ -77,8 +97,8 @@ async function loadOrders() {
|
||||
}
|
||||
|
||||
function search() {
|
||||
page.value = 1
|
||||
void loadOrders()
|
||||
if (page.value === 1) void loadOrders()
|
||||
else page.value = 1
|
||||
}
|
||||
|
||||
function reset() {
|
||||
@@ -105,46 +125,32 @@ function openDetail(row: DeliveryRow) {
|
||||
function openCreate() {
|
||||
void router.push({ name: 'orders-delivery-create' })
|
||||
}
|
||||
function rowActions(candidate: object): TableAction[] {
|
||||
const row = candidate as DeliveryRow
|
||||
return [{ key: 'detail', label: '详情', disabled: !row.deliveryNo, run: () => openDetail(row) }]
|
||||
}
|
||||
|
||||
onMounted(loadOrders)
|
||||
watch([page, pageSize], ([nextPage, nextSize], [previousPage, previousSize]) => {
|
||||
if (nextSize !== previousSize && nextPage !== 1) { page.value = 1; return }
|
||||
void loadOrders()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="delivery-page" aria-labelledby="delivery-list-title">
|
||||
<div class="delivery-heading">
|
||||
<div><h2 id="delivery-list-title">派送订单</h2><p>查看本企业海外仓派送进度与签收结果。</p></div>
|
||||
<el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />创建派送单</el-button>
|
||||
</div>
|
||||
|
||||
<form class="delivery-card delivery-filter" @submit.prevent="search">
|
||||
<div class="delivery-filter-grid">
|
||||
<el-input v-model="filters.documentNo" clearable placeholder="派送单号 / 出库单号" aria-label="派送单号或出库单号" />
|
||||
<el-input v-model="filters.dispatchNo" clearable placeholder="排车单号" aria-label="排车单号" />
|
||||
<el-input v-model="filters.waybillNo" clearable placeholder="运单号" aria-label="运单号" />
|
||||
<el-select v-model="filters.status" clearable placeholder="全部状态" aria-label="派送状态"><el-option v-for="option in statusOptions" :key="option.value" :label="option.label" :value="option.value" /></el-select>
|
||||
<el-select v-model="filters.deliveryMethod" clearable placeholder="全部派送方式" aria-label="派送方式"><el-option label="卡车派送" value="TRUCK" /><el-option label="快递派送" value="COURIER" /><el-option label="客户自提" value="SELF_PICKUP" /></el-select>
|
||||
<el-date-picker v-model="filters.plannedRange" type="datetimerange" value-format="YYYY-MM-DDTHH:mm:ss" start-placeholder="计划开始时间" end-placeholder="计划结束时间" range-separator="至" aria-label="计划派送时间" />
|
||||
</div>
|
||||
<div class="delivery-filter-actions"><el-button type="primary" native-type="submit"><Search :size="16" />查询</el-button><el-button @click="reset"><RefreshCw :size="16" />重置</el-button></div>
|
||||
</form>
|
||||
<QueryToolbar v-model="queryModel" layout="grid" ariaLabel="派送订单筛选" :fields="queryFields" :search-on-reset="false" @search="search" @reset="reset" />
|
||||
|
||||
<div class="delivery-card delivery-table-card">
|
||||
<div v-if="errorMessage" class="delivery-state delivery-state--error" role="alert"><p>{{ errorMessage }}</p><el-button @click="loadOrders">重试</el-button></div>
|
||||
<el-table v-else v-loading="loading" :data="records" empty-text="暂无派送单" table-layout="fixed">
|
||||
<el-table-column label="操作" width="96" fixed="left"><template #default="{ row }"><el-button link type="primary" :disabled="!row.deliveryNo" @click="openDetail(row as DeliveryRow)">详情</el-button></template></el-table-column>
|
||||
<el-table-column prop="deliveryNo" label="派送单号" min-width="180"><template #default="{ row }">{{ display(row.deliveryNo) }}</template></el-table-column>
|
||||
<el-table-column prop="dispatchNo" label="排车单号" min-width="170"><template #default="{ row }">{{ display(row.dispatchNo) }}</template></el-table-column>
|
||||
<el-table-column prop="outboundNo" label="出库单号" min-width="170"><template #default="{ row }">{{ display(row.outboundNo) }}</template></el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="110"><template #default="{ row }"><el-tag :type="statusType(row.status)" effect="light">{{ statusLabel(row.status) }}</el-tag></template></el-table-column>
|
||||
<el-table-column prop="overseasWarehouseName" label="海外仓" min-width="150"><template #default="{ row }">{{ display(row.overseasWarehouseName) }}</template></el-table-column>
|
||||
<el-table-column prop="deliveryMethod" label="派送方式" width="120"><template #default="{ row }">{{ display(row.deliveryMethod) }}</template></el-table-column>
|
||||
<el-table-column prop="waybillNo" label="运单号" min-width="150"><template #default="{ row }">{{ display(row.waybillNo) }}</template></el-table-column>
|
||||
<el-table-column prop="carrierName" label="承运商" min-width="140"><template #default="{ row }">{{ display(row.carrierName) }}</template></el-table-column>
|
||||
<el-table-column prop="plannedDeliveryAt" label="计划派送" min-width="160"><template #default="{ row }">{{ formatDateTime(row.plannedDeliveryAt) }}</template></el-table-column>
|
||||
<el-table-column prop="expectedArrivalAt" label="预计到达" min-width="160"><template #default="{ row }">{{ formatDateTime(row.expectedArrivalAt) }}</template></el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" min-width="160"><template #default="{ row }">{{ formatDateTime(row.createdAt) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<div v-if="!errorMessage && (records.length > 0 || total > 0)" class="delivery-pagination"><span>共 {{ total }} 条</span><el-pagination v-model:current-page="page" v-model:page-size="pageSize" :page-sizes="[10, 20, 50, 100]" layout="sizes, prev, pager, next" :total="total" @current-change="changePage" @size-change="changePageSize" /></div>
|
||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="records" :columns="tableColumns" :loading="loading" :total="total" :page-sizes="[10, 20, 50, 100]" :row-actions="rowActions" row-key="deliveryNo" empty-text="暂无派送单">
|
||||
<template #toolbar><strong id="delivery-list-title">派送订单</strong><span>共 {{ total }} 条</span></template>
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />创建派送单</el-button></template>
|
||||
<template v-if="errorMessage" #error><div class="delivery-state delivery-state--error" role="alert"><p>{{ errorMessage }}</p><el-button @click="loadOrders">重试</el-button></div></template>
|
||||
<template #status="{ row }"><el-tag :type="statusType(row.status)" effect="light">{{ statusLabel(row.status) }}</el-tag></template>
|
||||
<template #planned="{ row }">{{ formatDateTime(row.plannedDeliveryAt) }}</template>
|
||||
<template #arrival="{ row }">{{ formatDateTime(row.expectedArrivalAt) }}</template>
|
||||
<template #createdAt="{ row }">{{ formatDateTime(row.createdAt) }}</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive, ref } from 'vue'
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { ArrowLeft } from '@lucide/vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { getInboundPlan, listInboundPlans, type InboundPlanDetail, type InboundPlanSummary } from '../api/inboundPlans'
|
||||
import { overseasWarehouseLabel } from '../inboundPlanDisplay'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/components/common/QueryToolbar.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
|
||||
import type { TableAction } from '@/components/common/tableActions'
|
||||
|
||||
const props = withDefaults(defineProps<{ detailPage?: boolean }>(), { detailPage: false })
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const detailPlanNo = computed(() => String(route.params.planNo || ''))
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
const detailError = ref('')
|
||||
const rows = ref<InboundPlanSummary[]>([])
|
||||
const detail = ref<InboundPlanDetail | null>(null)
|
||||
const total = ref(0)
|
||||
@@ -22,6 +32,37 @@ const query = reactive({
|
||||
page: 1, size: 20, planNo: '', inboundCode: '', destinationWarehouseCode: '', status: '',
|
||||
appointmentStatus: '', dispatchStatus: '', createdDates: [] as string[],
|
||||
})
|
||||
const queryModel = computed<QueryModel>({ get: () => ({ ...query }), set: (value) => Object.assign(query, value) })
|
||||
const queryFields: QueryField[] = [
|
||||
{ key: 'planNo', label: '计划号', type: 'input', placeholder: '请输入计划号' },
|
||||
{ key: 'inboundCode', label: '入仓码', type: 'input', placeholder: '请输入入仓码' },
|
||||
{ key: 'destinationWarehouseCode', label: '目的仓', type: 'input', placeholder: '请输入仓库代码' },
|
||||
{ key: 'status', label: '作业状态', type: 'select', options: inboundStatusOptions },
|
||||
{ key: 'appointmentStatus', label: '预约状态', type: 'select', options: [{ label: '未预约', value: 'UNAPPOINTED' }, { label: '待处理', value: 'PENDING' }, { label: '成功', value: 'SUCCESS' }, { label: '失败', value: 'FAILED' }, { label: '已取消', value: 'CANCELLED' }] },
|
||||
{ key: 'dispatchStatus', label: '排车状态', type: 'select', options: [{ label: '未排车', value: 'UNSCHEDULED' }, { label: '已排车', value: 'SCHEDULED' }] },
|
||||
{ key: 'createdDates', label: '创建时间', type: 'daterange' },
|
||||
]
|
||||
const tableColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', slotName: 'actions', width: 90, fixed: 'left' }, { prop: 'planNo', label: '计划号', minWidth: 190 },
|
||||
{ prop: 'inboundCode', label: '入仓码', minWidth: 180 }, { key: 'overseasWarehouse', label: '海外接柜仓', slotName: 'overseasWarehouse', minWidth: 210 },
|
||||
{ key: 'destination', label: '目的仓', slotName: 'destination', minWidth: 140 }, { prop: 'packageCount', label: '计划箱数', width: 100 },
|
||||
{ prop: 'pickedPackageCount', label: '已拣箱数', width: 100 }, { prop: 'palletCount', label: '托盘数', width: 90 },
|
||||
{ key: 'status', label: '状态', slotName: 'status', width: 120 }, { key: 'appointment', label: '预约状态', slotName: 'appointment', width: 110 },
|
||||
{ key: 'dispatch', label: '排车状态', slotName: 'dispatch', width: 110 }, { key: 'createdAt', label: '创建时间', slotName: 'createdAt', width: 180 },
|
||||
]
|
||||
const detailLineColumns: DataTableColumn[] = [
|
||||
{ prop: 'inboundCode', label: '入仓码', minWidth: 210 },
|
||||
{ key: 'destination', label: '目的仓', slotName: 'destination', minWidth: 240 },
|
||||
{ prop: 'requiredPackageCount', label: '计划箱数', width: 110, align: 'right', headerAlign: 'right' },
|
||||
{ prop: 'plannedPalletCount', label: '计划托数', width: 110, align: 'right', headerAlign: 'right' },
|
||||
{ prop: 'volumeCbm', label: '体积(m³)', width: 120, align: 'right', headerAlign: 'right' },
|
||||
]
|
||||
const detailPalletColumns: DataTableColumn[] = [
|
||||
{ prop: 'palletNo', label: '托盘码', minWidth: 210 },
|
||||
{ key: 'destination', label: '目的仓', slotName: 'destination', minWidth: 240 },
|
||||
{ prop: 'capacityCbm', label: '容量(m³)', width: 130, align: 'right', headerAlign: 'right' },
|
||||
{ prop: 'allocatedVolumeCbm', label: '已分配体积(m³)', width: 160, align: 'right', headerAlign: 'right' },
|
||||
]
|
||||
|
||||
function text(value: unknown) { return value === null || value === undefined || value === '' ? '—' : String(value) }
|
||||
function destinationWarehouseLabel(...values: unknown[]) {
|
||||
@@ -63,97 +104,116 @@ async function load() {
|
||||
|
||||
function resetQuery() {
|
||||
Object.assign(query, { page: 1, planNo: '', inboundCode: '', destinationWarehouseCode: '', status: '', appointmentStatus: '', dispatchStatus: '', createdDates: [] })
|
||||
void load()
|
||||
search()
|
||||
}
|
||||
function statusTone(value: unknown) {
|
||||
if (value === 'COMPLETED') return 'success'
|
||||
if (value === 'PARTIAL_INBOUND' || value === 'PICKING' || value === 'SIGNED') return 'primary'
|
||||
if (value === 'CANCELLED' || value === 'FAILED') return 'danger'
|
||||
return 'warning'
|
||||
}
|
||||
function search() { if (query.page === 1) void load(); else query.page = 1 }
|
||||
function rowActions(candidate: object): TableAction[] { return [{ key: 'detail', label: '详情', run: () => openDetail(candidate) }] }
|
||||
|
||||
async function openDetail(candidate: unknown) {
|
||||
function openDetail(candidate: unknown) {
|
||||
const row = candidate as InboundPlanSummary
|
||||
void router.push({ name: 'orders-inbound-detail', params: { planNo: row.planNo } })
|
||||
}
|
||||
async function loadDetail() {
|
||||
if (!detailPlanNo.value) return
|
||||
loading.value = true
|
||||
try { detail.value = await getInboundPlan(row.planNo) }
|
||||
catch (cause) { ElMessage.error(errorMessage(cause)) }
|
||||
detailError.value = ''
|
||||
try { detail.value = await getInboundPlan(detailPlanNo.value) }
|
||||
catch (cause) { detail.value = null; detailError.value = errorMessage(cause); ElMessage.error(detailError.value) }
|
||||
finally { loading.value = false }
|
||||
}
|
||||
function returnToList() { void router.push({ name: 'orders-inbound' }) }
|
||||
|
||||
onMounted(() => void load())
|
||||
onMounted(() => { if (props.detailPage) void loadDetail(); else void load() })
|
||||
watch(() => [query.page, query.size] as const, ([nextPage, nextSize], [previousPage, previousSize]) => {
|
||||
if (nextSize !== previousSize && nextPage !== 1) { query.page = 1; return }
|
||||
if (!props.detailPage) void load()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section v-loading="loading" class="inbound-orders" :aria-busy="loading">
|
||||
<header class="page-head">
|
||||
<div><h2>{{ detail ? '入库订单详情' : '入库订单列表' }}</h2><p>{{ detail ? `计划号:${detail.planNo}` : '查询当前企业在海外仓的入库计划与作业进度' }}</p></div>
|
||||
<el-button v-if="detail" @click="detail = null">返回列表</el-button>
|
||||
</header>
|
||||
|
||||
<template v-if="!detail">
|
||||
<template v-if="!props.detailPage">
|
||||
<el-alert v-if="error" :title="error" type="error" show-icon :closable="false"><template #default><el-button size="small" @click="load">重新加载</el-button></template></el-alert>
|
||||
<el-card shadow="never" class="filter-card">
|
||||
<el-form inline @submit.prevent="query.page = 1; load()">
|
||||
<el-form-item label="计划号"><el-input v-model.trim="query.planNo" clearable placeholder="请输入计划号" /></el-form-item>
|
||||
<el-form-item label="入仓码"><el-input v-model.trim="query.inboundCode" clearable placeholder="请输入入仓码" /></el-form-item>
|
||||
<el-form-item label="目的仓"><el-input v-model.trim="query.destinationWarehouseCode" clearable placeholder="请输入仓库代码" /></el-form-item>
|
||||
<el-form-item label="作业状态"><el-select v-model="query.status" clearable placeholder="全部"><el-option v-for="option in inboundStatusOptions" :key="option.value" :label="option.label" :value="option.value" /></el-select></el-form-item>
|
||||
<el-form-item label="预约状态"><el-select v-model="query.appointmentStatus" clearable placeholder="全部"><el-option label="未预约" value="UNAPPOINTED" /><el-option label="待处理" value="PENDING" /><el-option label="成功" value="SUCCESS" /><el-option label="失败" value="FAILED" /><el-option label="已取消" value="CANCELLED" /></el-select></el-form-item>
|
||||
<el-form-item label="排车状态"><el-select v-model="query.dispatchStatus" clearable placeholder="全部"><el-option label="未排车" value="UNSCHEDULED" /><el-option label="已排车" value="SCHEDULED" /></el-select></el-form-item>
|
||||
<el-form-item label="创建时间"><el-date-picker v-model="query.createdDates" type="daterange" value-format="YYYY-MM-DD" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" /></el-form-item>
|
||||
<el-form-item><el-button type="primary" native-type="submit">查询</el-button><el-button @click="resetQuery">重置</el-button></el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<el-card shadow="never">
|
||||
<el-table :data="rows" border empty-text="暂无入库订单">
|
||||
<el-table-column label="操作" width="90" fixed="left"><template #default="scope"><el-button link type="primary" @click="openDetail(scope.row)">查看</el-button></template></el-table-column>
|
||||
<el-table-column prop="planNo" label="计划号" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="inboundCode" label="入仓码" min-width="170" show-overflow-tooltip />
|
||||
<el-table-column label="海外接柜仓" min-width="220" show-overflow-tooltip><template #default="scope">{{ overseasWarehouseLabel(scope.row.overseasWarehouseCode, scope.row.overseasWarehouseName) }}</template></el-table-column>
|
||||
<el-table-column label="目的仓" min-width="150" show-overflow-tooltip><template #default="scope">{{ text(scope.row.fbaWarehouseCode) }}</template></el-table-column>
|
||||
<el-table-column prop="packageCount" label="计划箱数" width="100" />
|
||||
<el-table-column prop="pickedPackageCount" label="已拣箱数" width="100" />
|
||||
<el-table-column prop="palletCount" label="托盘数" width="90" />
|
||||
<el-table-column label="状态" width="120" show-overflow-tooltip><template #default="scope">{{ statusLabel(scope.row.status) }}</template></el-table-column>
|
||||
<el-table-column label="预约状态" width="120" show-overflow-tooltip><template #default="scope">{{ statusLabel(scope.row.appointmentStatus) }}</template></el-table-column>
|
||||
<el-table-column label="排车状态" width="110" show-overflow-tooltip><template #default="scope">{{ statusLabel(scope.row.dispatchStatus) }}</template></el-table-column>
|
||||
<el-table-column label="创建时间" width="180" show-overflow-tooltip><template #default="scope">{{ dateTime(scope.row.createdAt) }}</template></el-table-column>
|
||||
</el-table>
|
||||
<el-pagination v-model:current-page="query.page" v-model:page-size="query.size" class="pagination" :total="total" :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next" @change="load" />
|
||||
</el-card>
|
||||
<QueryToolbar v-model="queryModel" layout="grid" ariaLabel="入库订单筛选" :fields="queryFields" :search-on-reset="false" @search="search" @reset="resetQuery" />
|
||||
<div class="inbound-table-card">
|
||||
<DataTable v-model:page="query.page" v-model:page-size="query.size" :data="rows" :columns="tableColumns" :loading="loading" :total="total" :page-sizes="[10, 20, 50, 100]" :row-actions="rowActions" row-key="planNo" empty-text="暂无入库订单">
|
||||
<template #toolbar><strong>入库订单</strong><span>共 {{ total }} 条</span></template>
|
||||
<template #overseasWarehouse="{ row }">{{ overseasWarehouseLabel(row.overseasWarehouseCode, row.overseasWarehouseName) }}</template>
|
||||
<template #destination="{ row }">{{ text(row.fbaWarehouseCode) }}</template>
|
||||
<template #status="{ row }"><el-tag effect="light">{{ statusLabel(row.status) }}</el-tag></template>
|
||||
<template #appointment="{ row }">{{ statusLabel(row.appointmentStatus) }}</template>
|
||||
<template #dispatch="{ row }">{{ statusLabel(row.dispatchStatus) }}</template>
|
||||
<template #createdAt="{ row }">{{ dateTime(row.createdAt) }}</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<el-card shadow="never">
|
||||
<template v-else-if="detail">
|
||||
<article class="inbound-detail-surface">
|
||||
<header class="inbound-detail-header">
|
||||
<div class="inbound-detail-title">
|
||||
<el-button link type="primary" @click="returnToList"><ArrowLeft :size="16" />返回列表</el-button>
|
||||
<div><h2>{{ detail.planNo }}</h2><p>{{ text(detail.containerNo) }} · {{ overseasWarehouseLabel(detail.overseasWarehouseCode, detail.overseasWarehouseName) }}</p></div>
|
||||
</div>
|
||||
<span class="client-status" :data-tone="statusTone(detail.status)">{{ statusLabel(detail.status) }}</span>
|
||||
</header>
|
||||
<section class="inbound-detail-section" aria-labelledby="inbound-summary-title">
|
||||
<h3 id="inbound-summary-title">入库概览</h3>
|
||||
<dl class="detail-grid">
|
||||
<div><dt>计划号</dt><dd>{{ detail.planNo }}</dd></div><div><dt>集装箱号</dt><dd>{{ text(detail.containerNo) }}</dd></div>
|
||||
<div><dt>集装箱号</dt><dd>{{ text(detail.containerNo) }}</dd></div>
|
||||
<div><dt>海外接柜仓</dt><dd>{{ overseasWarehouseLabel(detail.overseasWarehouseCode, detail.overseasWarehouseName) }}</dd></div>
|
||||
<div><dt>状态</dt><dd>{{ statusLabel(detail.status) }}</dd></div><div><dt>入仓码数</dt><dd>{{ detail.lineCount }}</dd></div>
|
||||
<div><dt>托盘数</dt><dd>{{ detail.palletCount }}</dd></div><div><dt>总体积(m³)</dt><dd>{{ detail.totalVolumeCbm }}</dd></div>
|
||||
<div><dt>计划箱数</dt><dd>{{ detail.expectedPackageCount }}</dd></div><div><dt>已拣箱数</dt><dd>{{ detail.pickedPackageCount }}</dd></div>
|
||||
<div><dt>入仓码数</dt><dd>{{ detail.lineCount }}</dd></div>
|
||||
<div><dt>托盘数</dt><dd>{{ detail.palletCount }}</dd></div>
|
||||
<div><dt>计划箱数</dt><dd>{{ detail.expectedPackageCount }}</dd></div>
|
||||
<div><dt>已拣箱数</dt><dd>{{ detail.pickedPackageCount }}</dd></div>
|
||||
<div><dt>总体积</dt><dd>{{ detail.totalVolumeCbm }} m³</dd></div>
|
||||
</dl>
|
||||
</el-card>
|
||||
<el-card shadow="never" header="入仓明细">
|
||||
<el-table :data="detail.lines" border empty-text="暂无入仓明细">
|
||||
<el-table-column prop="inboundCode" label="入仓码" min-width="180" /><el-table-column label="目的仓" min-width="220" show-overflow-tooltip><template #default="scope">{{ destinationWarehouseLabel(scope.row.fbaWarehouseCode, scope.row.destinationWarehouseCode, scope.row.destinationWarehouseName) }}</template></el-table-column>
|
||||
<el-table-column prop="requiredPackageCount" label="计划箱数" width="100" />
|
||||
<el-table-column prop="plannedPalletCount" label="计划托数" width="100" /><el-table-column prop="volumeCbm" label="体积(m³)" width="110" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
<el-card shadow="never" header="托盘明细">
|
||||
<el-table :data="detail.pallets" border empty-text="暂无托盘">
|
||||
<el-table-column prop="palletNo" label="托盘码" min-width="180" /><el-table-column label="目的仓" min-width="220" show-overflow-tooltip><template #default="scope">{{ destinationWarehouseLabel(scope.row.destinationWarehouseCode, scope.row.destinationWarehouseName) }}</template></el-table-column>
|
||||
<el-table-column prop="capacityCbm" label="容量(m³)" width="120" /><el-table-column prop="allocatedVolumeCbm" label="已分配体积(m³)" width="140" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</section>
|
||||
<section class="inbound-detail-section" aria-labelledby="inbound-lines-title">
|
||||
<div class="inbound-detail-section-heading"><h3 id="inbound-lines-title">入仓明细</h3><span>共 {{ detail.lines.length }} 条</span></div>
|
||||
<DataTable :data="detail.lines" :columns="detailLineColumns" row-key="inboundCode" empty-text="暂无入仓明细">
|
||||
<template #destination="{ row }">{{ destinationWarehouseLabel(row.fbaWarehouseCode, row.destinationWarehouseCode, row.destinationWarehouseName) }}</template>
|
||||
</DataTable>
|
||||
</section>
|
||||
<section class="inbound-detail-section" aria-labelledby="inbound-pallets-title">
|
||||
<div class="inbound-detail-section-heading"><h3 id="inbound-pallets-title">托盘明细</h3><span>共 {{ detail.pallets.length }} 条</span></div>
|
||||
<DataTable :data="detail.pallets" :columns="detailPalletColumns" row-key="palletNo" empty-text="暂无托盘">
|
||||
<template #destination="{ row }">{{ destinationWarehouseLabel(row.destinationWarehouseCode, row.destinationWarehouseName) }}</template>
|
||||
</DataTable>
|
||||
</section>
|
||||
</article>
|
||||
</template>
|
||||
<div v-else class="inbound-detail-state" role="alert"><strong>{{ detailError || '入库订单详情加载失败' }}</strong><el-button @click="loadDetail">重新加载</el-button></div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.inbound-orders { display: grid; gap: 18px; }
|
||||
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
|
||||
.page-head h2 { margin: 0; color: #111827; font-size: 26px; }
|
||||
.page-head p { margin: 7px 0 0; color: #64748b; font-size: 14px; }
|
||||
.filter-card :deep(.el-form-item) { margin-bottom: 12px; }
|
||||
.filter-card :deep(.el-input), .filter-card :deep(.el-select) { width: 190px; }
|
||||
.pagination { justify-content: flex-end; margin-top: 18px; }
|
||||
.inbound-orders { display: grid; gap: 12px; }
|
||||
.inbound-table-card { overflow: hidden; border: 1px solid var(--client-border); border-radius: var(--client-radius); background: #fff; }
|
||||
.inbound-detail-surface { overflow: hidden; border: 1px solid var(--client-border); border-radius: var(--client-radius); background: #fff; }
|
||||
.inbound-detail-state { display:flex; min-height:220px; align-items:center; justify-content:center; gap:12px; border:1px solid var(--client-border); border-radius:var(--client-radius); background:#fff; color:#b42318; }
|
||||
.inbound-detail-header { display: flex; min-height: 64px; align-items: center; justify-content: space-between; gap: 16px; padding: 8px 16px; border-bottom: 1px solid var(--client-border); }
|
||||
.inbound-detail-title { display: flex; min-width: 0; align-items: center; gap: 12px; }
|
||||
.inbound-detail-title > div { min-width: 0; }
|
||||
.inbound-detail-title h2 { margin: 0; overflow: hidden; color: #17233a; font-size: 18px; line-height: 24px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.inbound-detail-title p { margin: 2px 0 0; overflow: hidden; color: var(--client-muted); font-size: 12px; line-height: 18px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.inbound-detail-section + .inbound-detail-section { border-top: 1px solid var(--client-border); }
|
||||
.inbound-detail-section > h3, .inbound-detail-section-heading { min-height: 40px; margin: 0; padding: 0 16px; border-bottom: 1px solid var(--client-border); background: var(--client-header-bg); }
|
||||
.inbound-detail-section > h3 { display: flex; align-items: center; color: var(--client-text); font-size: 14px; }
|
||||
.inbound-detail-section-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||
.inbound-detail-section-heading h3 { margin: 0; color: var(--client-text); font-size: 14px; }
|
||||
.inbound-detail-section-heading span { color: var(--client-muted); font-size: 12px; }
|
||||
.detail-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; }
|
||||
.detail-grid div { min-width: 0; padding: 18px 20px; border-right: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5; }
|
||||
.detail-grid dt { margin-bottom: 7px; color: #8492a6; font-size: 13px; }
|
||||
.detail-grid dd { margin: 0; overflow: hidden; color: #1f2937; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.detail-grid div { display: grid; min-width: 0; min-height: 42px; grid-template-columns: 88px minmax(0, 1fr); align-items: center; gap: 8px; padding: 5px 12px; border-right: 1px solid var(--client-border); border-bottom: 1px solid var(--client-border); }
|
||||
.detail-grid div:nth-child(4n) { border-right: 0; }
|
||||
.detail-grid dt { color: var(--client-muted); font-size: 12px; }
|
||||
.detail-grid dd { margin: 0; overflow: hidden; color: var(--client-text); font-size: 13px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
|
||||
@media (max-width: 1100px) { .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .detail-grid div:nth-child(4n) { border-right: 1px solid var(--client-border); } .detail-grid div:nth-child(2n) { border-right: 0; } }
|
||||
@media (max-width: 720px) { .inbound-detail-header, .inbound-detail-title { align-items: flex-start; } .inbound-detail-header { flex-direction: column; } .inbound-detail-title { width: 100%; flex-direction: column; gap: 4px; } .detail-grid { grid-template-columns: 1fr; } .detail-grid div { border-right: 0; } }
|
||||
</style>
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
.delivery-page{color:#25324a}.delivery-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:16px}.delivery-heading h2{margin:0;color:#17233a;font-size:22px}.delivery-heading p{margin:6px 0 0;color:#7a8596;font-size:13px}.delivery-card{margin-bottom:14px;border:1px solid #e5eaf1;border-radius:6px;background:#fff;box-shadow:0 1px 3px rgba(25,42,70,.04)}.delivery-filter{padding:18px 20px}.delivery-filter-grid{display:grid;grid-template-columns:repeat(3,minmax(210px,1fr));gap:14px}.delivery-filter-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.delivery-table-card{overflow:hidden}.delivery-pagination{display:flex;align-items:center;justify-content:flex-end;gap:16px;padding:14px 18px;color:#778398;font-size:12px}.delivery-state{display:flex;min-height:220px;align-items:center;justify-content:center;gap:12px;flex-direction:column;color:#7a8596}.delivery-state p{margin:0}.delivery-state--error{margin:20px;border:1px solid #f5c2bd;border-radius:6px;background:#fff8f7;color:#b42318}.delivery-section{padding:20px}.delivery-section h3{margin:0 0 18px;padding-bottom:12px;border-bottom:1px solid #edf0f4;color:#26364f;font-size:15px}.delivery-detail-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:20px 28px}.delivery-detail-grid div{display:flex;min-width:0;flex-direction:column;gap:7px}.delivery-detail-grid span{color:#8792a2;font-size:12px}.delivery-detail-grid strong{overflow-wrap:anywhere;color:#334157;font-size:13px;font-weight:550}.delivery-span-all{grid-column:1/-1}.delivery-back{display:inline-flex;align-items:center;gap:6px;margin-bottom:14px;padding:0;border:0;background:none;color:#2176d2;cursor:pointer}.delivery-form{padding:22px}.delivery-form-grid{display:grid;grid-template-columns:repeat(3,minmax(210px,1fr));gap:4px 24px}.delivery-form-grid .delivery-span-2{grid-column:span 2}.delivery-form-grid .delivery-span-3{grid-column:1/-1}.delivery-form-actions{display:flex;justify-content:center;gap:10px;padding-top:8px}.delivery-fee-heading{display:flex;align-items:center;justify-content:space-between;margin:10px 0 12px}.delivery-fee-heading h3{margin:0;font-size:15px}.delivery-fee-empty{padding:20px;color:#8792a2;text-align:center}:deep(.el-button span){display:inline-flex;align-items:center;gap:6px}:deep(.el-date-editor){width:100%}@media(max-width:1200px){.delivery-filter-grid,.delivery-form-grid{grid-template-columns:repeat(2,minmax(210px,1fr))}.delivery-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.delivery-form-grid .delivery-span-3{grid-column:1/-1}}
|
||||
.delivery-page{display:grid;gap:12px}.delivery-card{margin-bottom:0;border-color:var(--client-border);border-radius:var(--client-radius);box-shadow:none}
|
||||
.delivery-detail-content{min-height:160px}.delivery-detail-surface{overflow:hidden;border:1px solid var(--client-border);border-radius:var(--client-radius);background:#fff}.delivery-detail-header{display:flex;min-height:64px;align-items:center;justify-content:space-between;gap:16px;padding:8px 16px;border-bottom:1px solid var(--client-border)}.delivery-detail-title{display:flex;min-width:0;align-items:center;gap:12px}.delivery-detail-title>div{min-width:0}.delivery-detail-title h2{margin:0;overflow:hidden;color:#17233a;font-size:18px;line-height:24px;text-overflow:ellipsis;white-space:nowrap}.delivery-detail-title p{margin:2px 0 0;overflow:hidden;color:var(--client-muted);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.delivery-detail-section+.delivery-detail-section{border-top:1px solid var(--client-border)}.delivery-detail-section>h3,.delivery-detail-section-heading{min-height:40px;margin:0;padding:0 16px;border-bottom:1px solid var(--client-border);background:var(--client-header-bg)}.delivery-detail-section>h3{display:flex;align-items:center;color:var(--client-text);font-size:14px}.delivery-detail-section-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.delivery-detail-section-heading h3{margin:0;color:var(--client-text);font-size:14px}.delivery-detail-section-heading span{color:var(--client-muted);font-size:12px}.delivery-detail-surface .delivery-detail-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:0}.delivery-detail-surface .delivery-detail-grid div{display:grid;min-height:42px;grid-template-columns:88px minmax(0,1fr);align-items:center;gap:8px;padding:5px 12px;border-right:1px solid var(--client-border);border-bottom:1px solid var(--client-border)}.delivery-detail-surface .delivery-detail-grid div:nth-child(4n){border-right:0}.delivery-detail-surface .delivery-detail-grid span{color:var(--client-muted);font-size:12px}.delivery-detail-surface .delivery-detail-grid strong{overflow:hidden;color:var(--client-text);font-size:13px;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.delivery-detail-surface .delivery-detail-grid .delivery-span-all{grid-column:1/-1;border-right:0}.delivery-detail-surface .delivery-detail-grid .delivery-span-all strong{white-space:normal}
|
||||
@media(max-width:1200px){.delivery-detail-surface .delivery-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.delivery-detail-surface .delivery-detail-grid div:nth-child(4n){border-right:1px solid var(--client-border)}.delivery-detail-surface .delivery-detail-grid div:nth-child(2n){border-right:0}}
|
||||
@media(max-width:720px){.delivery-detail-header{align-items:flex-start;flex-direction:column}.delivery-detail-title{width:100%;align-items:flex-start;flex-direction:column;gap:4px}.delivery-detail-surface .delivery-detail-grid{grid-template-columns:1fr}.delivery-detail-surface .delivery-detail-grid div{border-right:0}}
|
||||
|
||||
Reference in New Issue
Block a user