优化
This commit is contained in:
@@ -7,7 +7,7 @@ export interface PageResult<T> { records: T[]; page: number; size: number; total
|
||||
export interface LastlegOrderSummary { id: string; orderNo: string; inboundCode: string; orderType: string; packageCount: number; overseasWarehouseId?: string }
|
||||
export interface HistoricalOrderSummary { id: string | null; orderNo: string; sourceOrderNo?: string; outboundOrderNo?: string; relabelOrderNo?: string; orderType?: string; status?: string; packageCount?: number }
|
||||
export interface TransferSummary { id: string; transferNo: string; inboundCode: string; lastlegOrderId: string; lastlegOrderNo: string; operatingWarehouseId: string; fbaWarehouseCode?: string; packageCount: number; deliveryMethod: string; needRelabel: boolean; relabelNo?: string; relabelStatus?: string; relabelFulfillmentStatus?: string; status: string; estimatedArrivalAt: string; estimatedShipAt?: string; actualShipAt?: string; reviewedAt?: string; measuredAt?: string; outboundAt?: string; relabelCompletedAt?: string; createdAt: string }
|
||||
export interface RelabelSummary { id: string; relabelNo: string; lastlegOrderId: string; lastlegOrderNo: string; customerOrderNo: string; overseasWarehouseId: string; status: string; itemCount: number; totalPackageCount: number; notifiedPackageCount: number; skuCodes: string; createdAt: string; reviewedAt?: string; relabelCompletedAt?: string; outboundAt?: string; totalFileId?: string; totalFileName?: string; totalFileUrl?: string; cartonTotalFileId?: string; cartonTotalFileName?: string; cartonTotalFileUrl?: string; skuTotalFileId?: string; skuTotalFileName?: string; skuTotalFileUrl?: string; deliveryMethod?: RelabelDeliveryMethod; printShippingLabel?: boolean; shippingLabelFileId?: string; shippingLabelFileName?: string; shippingLabelFileUrl?: string; fulfillmentStatus?: string; outboundOrderNo?: string; customerConfirmedAt?: string; reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER'; reviewRemark?: string }
|
||||
export interface RelabelSummary { operationTypes?: Array<'CARTON_LABEL' | 'SKU_LABEL' | 'CARTON_AND_SKU' | 'RETURN_BULK_SKU_LABEL'>; id: string; relabelNo: string; lastlegOrderId: string; lastlegOrderNo: string; customerOrderNo: string; overseasWarehouseId: string; status: string; itemCount: number; totalPackageCount: number; notifiedPackageCount: number; skuCodes: string; createdAt: string; reviewedAt?: string; relabelCompletedAt?: string; outboundAt?: string; totalFileId?: string; totalFileName?: string; totalFileUrl?: string; cartonTotalFileId?: string; cartonTotalFileName?: string; cartonTotalFileUrl?: string; skuTotalFileId?: string; skuTotalFileName?: string; skuTotalFileUrl?: string; deliveryMethod?: RelabelDeliveryMethod; printShippingLabel?: boolean; shippingLabelFileId?: string; shippingLabelFileName?: string; shippingLabelFileUrl?: string; fulfillmentStatus?: string; outboundOrderNo?: string; customerConfirmedAt?: string; reviewChannel?: 'TAIL_ORDER' | 'RELABEL_ORDER'; reviewRemark?: string }
|
||||
export interface RelabelItemDetail {
|
||||
id: string; skuCode?: string; productNameZh: string; totalPackageCount: number; notifiedPackageCount: number
|
||||
shipmentNo: string; trackingCode?: string; newSkuCode?: string; labelRequirement?: string; remark?: string
|
||||
|
||||
@@ -318,7 +318,7 @@ onBeforeUnmount(clearPhotoUrls)
|
||||
</template>
|
||||
|
||||
<template v-else-if="!props.detailPage">
|
||||
<QueryToolbar v-model="queryModel" layout="grid" ariaLabel="退货签收筛选" :fields="queryFields" @search="search" />
|
||||
<QueryToolbar v-model="queryModel" class="return-query" layout="grid" ariaLabel="退货签收筛选" :fields="queryFields" @search="search" />
|
||||
<div class="return-table-card">
|
||||
<DataTable v-model:page="query.page" v-model:page-size="query.size" :data="rows" :columns="tableColumns" :loading="loading" :total="total" :page-sizes="[15, 30, 50, 100]" :row-actions="rowActions" row-key="returnNo" empty-text="暂无退货预报">
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />新建退货预报</el-button></template>
|
||||
@@ -471,6 +471,12 @@ onBeforeUnmount(clearPhotoUrls)
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.return-query.query-toolbar--grid { display:grid; grid-template-columns:repeat(4,minmax(0,280px)) max-content; gap:14px 18px; align-items:end; }
|
||||
.return-query :deep(.query-toolbar__filters) { display:contents; }
|
||||
.return-query :deep(.query-toolbar__field) { display:flex; flex-direction:column; align-items:stretch; gap:6px; }
|
||||
.return-query :deep(.query-toolbar__label) { line-height:18px; }
|
||||
.return-query :deep(.query-toolbar__actions) { margin:0; padding:0; border:0; align-self:end; }
|
||||
@media(max-width:1200px) { .return-query.query-toolbar--grid { grid-template-columns:repeat(2,minmax(0,320px)); } }
|
||||
.relabel-suborder { display: flex; align-items: center; gap: 8px; min-height: 30px; white-space: nowrap; }
|
||||
.return-orders-page { display:grid; gap:12px; } .return-create-form { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); column-gap:20px; } .return-form-wide { grid-column:1 / -1; } .items-title { display:flex; justify-content:space-between; align-items:center; margin:16px 0 4px; font-weight:600; } .items-hint { margin-bottom:10px; color:var(--el-text-color-secondary); font-size:12px; } h3 { margin:24px 0 10px; font-size:16px; } h4 { margin:16px 0 8px; font-size:14px; } .remark { white-space:pre-wrap; } .warehouse-error, .duplicate-sku-error { margin-top:6px; color:var(--el-color-danger); font-size:12px; } :deep(.duplicate-sku-input .el-input__wrapper) { box-shadow:0 0 0 1px var(--el-color-danger) inset; } :deep(.el-dialog .el-select) { width:100%; }
|
||||
.return-create-surface { width:calc(100% - 24px); max-width:1120px; min-width:0; margin:0 0 0 24px; justify-self:start; box-sizing:border-box; overflow:hidden; border:1px solid var(--client-border); border-radius:var(--client-radius); background:#fff; }
|
||||
|
||||
@@ -55,7 +55,7 @@ const canConfirmRelabel = computed(() => auth.hasPermission('merchant:overseas-w
|
||||
const canConfirmTransfer = computed(() => auth.hasPermission('merchant:overseas-warehouse:transfer:confirm'))
|
||||
const canCancelDiscard = computed(() => auth.hasPermission('merchant:overseas-warehouse:discard:cancel'))
|
||||
const configs: Record<ServiceType, ServiceConfig> = {
|
||||
labeling: { title: '贴标申请', createTitle: '新增贴标申请', numberLabel: '贴标申请单号', emptyText: '暂无贴标申请', columns: ['操作', '贴标申请单号', '客户单号', '海外操作仓', '贴标要求', 'SKU 数(种)', '总箱数', '状态', '审核时间', '贴标完成时间', '贴标出库时间', '创建时间'] },
|
||||
labeling: { title: '贴标申请', createTitle: '新增贴标申请', numberLabel: '贴标申请单号', emptyText: '暂无贴标申请', columns: ['操作', '贴标申请单号', '关联业务单号', '海外操作仓', 'SKU 数(种)', '总箱数/包裹', '换标类型', '状态', '审核时间', '贴标完成时间', '贴标出库时间', '创建时间'] },
|
||||
transfer: { title: '仓储转运单', createTitle: '新增仓储转运单', numberLabel: '转运单号', emptyText: '暂无仓储转运订单', columns: ['操作', '转运单号', '箱数', '海外仓', 'FBA 目的仓', '入仓方式', '是否换标', '换标单号', '换标状态', '状态', '审核时间', '测量时间', '出库时间', '创建时间'] },
|
||||
disposal: { title: '货物废弃', createTitle: '新增货物废弃申请', numberLabel: '废弃申请单号', emptyText: '暂无货物废弃申请', columns: ['操作', '废弃申请单号', '废弃出库单号', '进仓编号', '操作仓', 'SKU 汇总', '废弃数量', '预估费用', '状态', '废弃完成时间', '创建时间'] },
|
||||
relabel: { title: '退货换标', createTitle: '新建退货换标单', numberLabel: '退货换标单号', emptyText: '暂无退货换标订单', columns: ['操作', '退货换标单号', '来源 FBA 仓', '目的 FBA 仓', 'SKU 汇总', '退件总数', '是否换标', '换标状态', '尾程状态', '审核时间', '测量时间', '出库时间', '创建时间'] },
|
||||
@@ -183,7 +183,7 @@ const listQueryFields = computed<QueryField[]>(() => {
|
||||
const listColumns = computed<DataTableColumn[]>(() => config.value.columns.map((label, index) => index === 0
|
||||
? { key: 'actions', label, slotName: 'actions', width: props.service === 'transfer' ? 210 : 160, fixed: 'left' }
|
||||
: { key: String(index - 1), prop: String(index - 1), label, minWidth: index === 1 || label === '换标单号' ? 190 : 130,
|
||||
slotName: props.service === 'transfer' && label === '换标状态' ? 'transferRelabelStatus' : props.service === 'transfer' && label === '状态' ? 'transferStatus' : undefined }))
|
||||
slotName: props.service === 'labeling' && label === '换标类型' ? 'labelingType' : props.service === 'labeling' && label === '状态' ? 'labelingStatus' : props.service === 'transfer' && label === '换标状态' ? 'transferRelabelStatus' : props.service === 'transfer' && label === '状态' ? 'transferStatus' : undefined }))
|
||||
const discardCandidates = ref<import('../api/warehouseServices').DiscardCandidate[]>([])
|
||||
const selectedDiscardOrderId = ref('')
|
||||
const discardCandidatesLoading = ref(false)
|
||||
@@ -898,6 +898,19 @@ function statusLabel(value: string) {
|
||||
return labels[value] || value || '—'
|
||||
}
|
||||
type StatusTagType = 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
||||
function labelingTypeLabels(value: unknown): string[] {
|
||||
return typeof value === 'string' && value !== '—' ? [...new Set(value.split('、'))] : []
|
||||
}
|
||||
function labelingTypeTagType(label: string): StatusTagType {
|
||||
if (label === '只换 SKU') return 'primary'
|
||||
if (label === '只换箱唛') return 'warning'
|
||||
return 'success'
|
||||
}
|
||||
function labelingStatusTagType(status: string): StatusTagType {
|
||||
if (status === 'CANCELLED') return 'info'
|
||||
if (!['READY_FOR_OUTBOUND', 'COMPLETED', 'REJECTED', 'WAIT_APPROVAL', 'PENDING_REVIEW', 'PENDING_PROCESSING', 'CUSTOMER_CONFIRM_PENDING', 'PROCESSING'].includes(status)) return 'info'
|
||||
return relabelStatusTagType(status)
|
||||
}
|
||||
function relabelStatusTagType(status: string): StatusTagType {
|
||||
if (['READY_FOR_OUTBOUND', 'COMPLETED'].includes(status)) return 'success'
|
||||
if (['REJECTED', 'CANCELLED'].includes(status)) return 'danger'
|
||||
@@ -971,7 +984,7 @@ async function load() {
|
||||
total.value = Number.isFinite(Number(result.total)) ? Number(result.total) : result.records.length
|
||||
submittedRows.value = result.records.map((item) => {
|
||||
const destinationWarehouses = warehouseDisplay(item.overseasWarehouseId)
|
||||
return { ...row([item.relabelNo, item.customerOrderNo, destinationWarehouses, '—', new Set(item.skuCodes.split(',').map(code => code.trim()).filter(Boolean)).size, item.totalPackageCount, statusLabel(item.status), formatDateTime(item.reviewedAt), formatDateTime(item.relabelCompletedAt), formatDateTime(item.outboundAt), formatDateTime(item.createdAt)]), __status: item.status, __confirmedAt: item.customerConfirmedAt || '' }
|
||||
return { ...row([item.relabelNo, item.customerOrderNo, destinationWarehouses, new Set(item.skuCodes.split(',').map(code => code.trim()).filter(Boolean)).size, item.totalPackageCount, (item.operationTypes || []).map(type => ({ CARTON_LABEL: '只换箱唛', SKU_LABEL: '只换 SKU', RETURN_BULK_SKU_LABEL: '只换 SKU', CARTON_AND_SKU: 'SKU 和箱唛都换' }[type] || type)).join('、') || '—', statusLabel(item.status), formatDateTime(item.reviewedAt), formatDateTime(item.relabelCompletedAt), formatDateTime(item.outboundAt), formatDateTime(item.createdAt)]), __status: item.status, __confirmedAt: item.customerConfirmedAt || '' }
|
||||
})
|
||||
} else if (props.service === 'disposal') {
|
||||
const result = await listDiscards({ page: page.value, size: pageSize.value, discardNo: filters.number || undefined, inboundCode: filters.inboundNo || undefined, overseasWarehouseId: filters.warehouse || undefined, status: filters.status || undefined, createdFrom: dateTime(filters.start), createdTo: dateTime(filters.end, true), completedFrom: dateTime(filters.completedStart), completedTo: dateTime(filters.completedEnd, true) })
|
||||
@@ -1474,12 +1487,14 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
|
||||
<template>
|
||||
<section class="warehouse-service-page" :class="{ 'warehouse-service-page--detail': mode === 'detail', 'warehouse-service-page--return-relabel': isReturnRelabelSource }">
|
||||
<template v-if="mode === 'list'">
|
||||
<QueryToolbar v-model="listQueryModel" layout="grid" :ariaLabel="`${config.title}筛选`" :fields="listQueryFields" :search-on-reset="false" @search="query" @reset="resetListQuery" />
|
||||
<QueryToolbar v-model="listQueryModel" :class="{ 'labeling-query': props.service === 'labeling', 'transfer-query': props.service === 'transfer' || props.service === 'disposal', 'disposal-query': props.service === 'disposal' }" layout="grid" :ariaLabel="`${config.title}筛选`" :fields="listQueryFields" :search-on-reset="false" @search="query" @reset="resetListQuery" />
|
||||
<div class="warehouse-card warehouse-table-card">
|
||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="submittedRows" :columns="listColumns" :loading="loading" :total="total" :page-sizes="[15, 30, 50, 100]" :row-actions="listRowActions" :empty-text="config.emptyText">
|
||||
<template #toolbar-actions><el-button v-if="canCreate" type="primary" @click="openCreate"><Plus :size="16" />{{ props.service === 'relabel' ? '新建退货换标单' : props.service === 'transfer' ? '新增订单' : `新增${config.title}` }}</el-button></template>
|
||||
<template v-if="props.service === 'transfer' && submittedRows.some((item) => item.__status === 'WAIT_CUSTOMER_CONFIRMATION')" #before-table><div class="warehouse-list-notice">部分入库完成订单已有 PDA 实测数据,请在对应行确认测量数据。</div></template>
|
||||
<template #transferRelabelStatus="{ row }"><el-tag :type="transferRelabelStatusTagType(row.__relabelStatus)" effect="light">{{ row.__relabelStatusLabel }}</el-tag></template>
|
||||
<template #labelingType="{ row }"><span v-if="row['5'] === '—'">—</span><span v-else class="labeling-type-tags"><el-tag v-for="label in labelingTypeLabels(row['5'])" :key="label" :type="labelingTypeTagType(label)" size="small" effect="light">{{ label }}</el-tag></span></template>
|
||||
<template #labelingStatus="{ row }"><el-tag :type="labelingStatusTagType(row.__status)" size="small" effect="light">{{ statusLabel(row.__status) }}</el-tag></template>
|
||||
<template #transferStatus="{ row }"><el-tag :type="transferStatusTagType(row.__status)" effect="light">{{ row.__statusLabel }}</el-tag></template>
|
||||
</DataTable>
|
||||
</div>
|
||||
@@ -1687,6 +1702,32 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.labeling-type-tags { display:inline-flex; flex-wrap:wrap; gap:4px; }
|
||||
.labeling-query.query-toolbar--grid { display:grid; grid-template-columns:repeat(4,minmax(0,320px)); gap:14px 18px; align-items:end; }
|
||||
.labeling-query :deep(.query-toolbar__filters) { display:contents; }
|
||||
.labeling-query :deep(.query-toolbar__field) { display:flex; flex-direction:column; align-items:stretch; gap:6px; }
|
||||
.labeling-query :deep(.query-toolbar__field:nth-child(-n+3)) { grid-row:1; }
|
||||
.labeling-query :deep(.query-toolbar__field:nth-child(n+4)) { grid-row:2; }
|
||||
.labeling-query :deep(.query-toolbar__label) { line-height:18px; }
|
||||
.labeling-query :deep(.query-toolbar__actions) { grid-column:4; grid-row:1; margin:0; padding:0; border:0; align-self:end; }
|
||||
.transfer-query.query-toolbar--grid { display:grid; grid-template-columns:repeat(5,minmax(0,280px)); gap:14px 18px; align-items:end; }
|
||||
.transfer-query :deep(.query-toolbar__filters) { display:contents; }
|
||||
.transfer-query :deep(.query-toolbar__field) { display:flex; flex-direction:column; align-items:stretch; gap:6px; }
|
||||
.transfer-query :deep(.query-toolbar__field:nth-child(-n+5)) { grid-row:1; }
|
||||
.transfer-query :deep(.query-toolbar__field:nth-child(n+6)) { grid-row:2; }
|
||||
.transfer-query :deep(.query-toolbar__label) { line-height:18px; }
|
||||
.transfer-query :deep(.query-toolbar__actions) { grid-column:5; grid-row:2; margin:0; padding:0; border:0; align-self:end; }
|
||||
.disposal-query :deep(.query-toolbar__field:nth-child(5)) { grid-column:1; grid-row:2; }
|
||||
.disposal-query :deep(.query-toolbar__actions) { grid-column:2; }
|
||||
@media(max-width:1200px) {
|
||||
.labeling-query.query-toolbar--grid { grid-template-columns:repeat(2,minmax(0,320px)); }
|
||||
.labeling-query :deep(.query-toolbar__field:nth-child(n)) { grid-row:auto; }
|
||||
.labeling-query :deep(.query-toolbar__actions) { grid-column:auto; grid-row:auto; }
|
||||
.transfer-query.query-toolbar--grid { grid-template-columns:repeat(2,minmax(0,320px)); }
|
||||
.transfer-query :deep(.query-toolbar__field:nth-child(n)) { grid-row:auto; }
|
||||
.disposal-query :deep(.query-toolbar__field:nth-child(5)) { grid-column:auto; }
|
||||
.transfer-query :deep(.query-toolbar__actions) { grid-column:auto; grid-row:auto; }
|
||||
}
|
||||
.warehouse-order-info-heading { display: flex; align-items: center; justify-content: space-between; max-width: 1296px; margin-bottom: 16px; border-bottom: 1px solid #edf0f4; padding-bottom: 10px; }
|
||||
.warehouse-form-section .warehouse-order-info-heading h3 { margin: 0; padding: 0; border: 0; }
|
||||
.warehouse-order-info-summary { display: flex; flex-wrap: wrap; gap: 10px 24px; color: #64748b; font-size: 12px; }
|
||||
|
||||
Reference in New Issue
Block a user