@@ -1,5 +1,9 @@
< script setup lang = "ts" >
import RelabelQuantityPanel from '../components/RelabelQuantityPanel.vue'
import { getRelabelQuantities , type RelabelQuantity } from '../api/relabelQuantities'
import TransferPickupProgressPanel from '../components/TransferPickupProgressPanel.vue'
import DiscardStatistics from '../components/DiscardStatistics.vue'
import TransferPaneDivider from '../components/TransferPaneDivider.vue'
import { computed , nextTick , onActivated , onBeforeUnmount , onMounted , reactive , ref , watch } from 'vue'
import { useRoute , useRouter } from 'vue-router'
import { ElMessage , ElMessageBox } from 'element-plus'
@@ -49,6 +53,7 @@ const props = withDefaults(defineProps<{ service: ServiceType; createPage?: bool
const auth = useAuthStore ( )
const router = useRouter ( )
const route = useRoute ( )
const transferPaneShare = ref ( 43 )
// 缓存列表不订阅其他详情页的路由参数,避免离开时清空筛选并重复请求。
const detailNumber = computed ( ( ) => props . detailPage ? props . detailNo || String ( route . params . detailNo || '' ) : '' )
const canCreate = computed ( ( ) => auth . hasPermission ( ( {
@@ -74,9 +79,9 @@ async function refreshAfterCompletion(no: string) {
}
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 汇总' , '废弃数量 ' , '预估费用' , '状态' , '废弃完成时间' , '创建时间' ] } ,
disposal : { title : '货物废弃' , createTitle : '新增货物废弃申请' , numberLabel : '废弃申请单号' , emptyText : '暂无货物废弃申请' , columns : [ '操作' , '废弃申请单号' , '废弃出库单号' , '进仓编号' , '操作仓' , 'SKU 汇总' , '申请箱数 ' , '预估费用' , '状态' , '废弃完成时间' , '创建时间' ] } ,
relabel : { title : '退货换标' , createTitle : '新建退货换标单' , numberLabel : '退货换标单号' , emptyText : '暂无退货换标订单' , columns : [ '操作' , '退货换标单号' , '来源 FBA 仓' , '目的 FBA 仓' , 'SKU 汇总' , '退件总数' , '是否换标' , '换标状态' , '尾程状态' , '审核时间' , '测量时间' , '出库时间' , '创建时间' ] } ,
}
const config = computed ( ( ) => configs [ props . service ] )
@@ -131,9 +136,12 @@ const skuRelabelRows = ref<SkuRelabelRow[]>([])
const importedRelabelBindings = ref < ImportedRelabelBinding [ ] > ( [ ] )
const cartonDetailRows = computed ( ( ) => cargoRows . value . filter ( ( row ) => row . included ) )
const submittedRows = ref < Record < string , string > [ ] > ( [ ] )
const discardStatisticsQuery = ref < Record < string , unknown > > ( { page : 1 , size : 15 } )
const discardStatisticsRevision = ref ( 0 )
const page = ref ( 1 )
const pageSize = ref ( 15 )
const total = ref ( 0 )
const relabelQuantityQuery = ref < Record < string , unknown > > ( { page : 1 , size : 15 } )
const editingTransferNo = ref ( '' )
interface TransferPallet { id ? : string | number ; sequenceNo ? : number ; palletNo ? : string ; warehouseLocationCode ? : string ; cartonCount ? : number ; lengthCm ? : number ; widthCm ? : number ; heightCm ? : number ; grossWeightKg ? : number ; volumeCbm ? : number ; status ? : string ; completedAt ? : string }
interface TransferMeasurementPhoto { fileId : string | number ; fileName ? : string ; contentType ? : string ; sizeBytes ? : number ; uploadedAt ? : string }
@@ -150,7 +158,7 @@ interface ServiceDetail extends Record<string, unknown> {
relabelContactPhone ? : string ; relabelDeliveryMethod ? : string ; relabelNo ? : string
relabelStatus ? : string ; relabelFulfillmentStatus ? : string ; createdAt ? : string
inboundCode ? : string ; sourceOrders ? : Array < { lastlegOrderId ? : string | number } >
items ? : Array < { id ? : string | number ; cartonMarks ? : string [ ] ; inboundCode ? : string ; productName ? : string ; discardPackages ? : number ; skuCode ? : string ; productNameZh ? : string ; quantity ? : number | null ; packageCount ? : number ; shippingMark ? : string } >
items ? : Array < { id ? : string | number ; cartonMarks ? : string [ ] ; inboundCode ? : string ; productName ? : string ; discardPackages ? : number ; quantityUnit ? : string ; actualDiscardPackages ? : number | null ; skuCode ? : string ; productNameZh ? : string ; quantity ? : number | null ; packageCount ? : number ; shippingMark ? : string } >
relabelBindings ? : Array < { operationType ? : string ; customerCartonMark ? : string ; originalSku ? : string ; newSku ? : string ; quantity ? : number ; fbaCartonMark ? : string ; destinationWarehouseCode ? : string ; remark ? : string } >
cartons ? : TransferCarton [ ] ; pallets ? : TransferPallet [ ] ; measurementPhotos ? : TransferMeasurementPhoto [ ] ; customerConfirmedAt ? : string
}
@@ -198,7 +206,7 @@ function transferCartonLines(carton: TransferCarton) {
return [ { transferItemId : carton . transferItemId , skuCode : item ? . skuCode || '—' , productNameZh : item ? . productNameZh || '—' , quantity : Number ( carton . quantity || 0 ) } ]
}
function palletCartons ( pallet : TransferPallet ) {
return ( selectedDetail . value ? . cartons || [ ] ) . filter ( ( carton ) => carton . status === 'COUNTED' && pallet . id != null && carton . transferPalletId != null && String ( carton . transferPalletId ) === String ( pallet . id ) )
return countedTransferCartons ( ) . filter ( ( carton ) => pallet . id != null && carton . transferPalletId != null && String ( carton . transferPalletId ) === String ( pallet . id ) )
}
function palletSkuRows ( pallet : TransferPallet ) {
const summary = new Map < string , number > ( )
@@ -208,7 +216,8 @@ function palletSkuRows(pallet: TransferPallet) {
return [ ... summary . entries ( ) ] . map ( ( [ sku , quantity ] ) => ( { sku , quantity } ) )
}
function palletQuantity ( pallet : TransferPallet ) { return palletCartons ( pallet ) . reduce ( ( sum , carton ) => sum + Number ( carton . quantity || 0 ) , 0 ) }
function countedTransferCartons ( ) { return ( selectedDetail . value ? . cartons || [ ] ) . filter ( ( carton ) => carton . status === 'COUNTED' ) }
/** 保留历史实收,后续占用、废弃与出库不回退签收事实。 */
function countedTransferCartons ( ) { return ( selectedDetail . value ? . cartons || [ ] ) . filter ( ( carton ) => [ 'COUNTED' , 'DISCARD_PENDING' , 'DISCARDED' , 'SHIPPED' ] . includes ( carton . status ) ) }
function receivedItemCartons ( itemId : string | number | undefined ) {
return countedTransferCartons ( ) . filter ( carton => itemId != null && transferCartonLines ( carton ) . some ( line => String ( line . transferItemId ) === String ( itemId ) ) )
}
@@ -218,6 +227,7 @@ function receivedItemQuantity(itemId: string | number | undefined) {
const detailError = ref ( '' )
const selectedRelabelDetail = ref < RelabelDetail | null > ( null )
const selectedRelabelQuantity = ref < RelabelQuantity | null > ( null )
const completionPhotoUrls = reactive < Record < string , string > > ( { } )
const completionPhotoLoading = reactive < Record < string , boolean > > ( { } )
const completionPhotoErrors = reactive < Record < string , boolean > > ( { } )
@@ -490,7 +500,10 @@ onMounted(() => {
} )
let activatedOnce = false
onActivated ( ( ) => {
if ( activatedOnce && ! props . createPage && ! props . detailPage && mode . value === 'list' ) void loadPage ( )
if ( activatedOnce && ! props . createPage && ! props . detailPage ) {
mode . value = 'list'
void loadPage ( )
}
activatedOnce = true
} )
onBeforeUnmount ( ( ) => { clearCompletionPhotos ( ) ; clearMeasurementPhotos ( ) ; clearDiscardPhotos ( ) } )
@@ -523,8 +536,12 @@ function resetForm() {
editingTransferNo . value = ''
}
async function openCreate ( ) {
if ( ! props . createPage && props . service !== 'relabel' ) {
await router . push ( { name : ` ${ serviceListRouteName ( props . service ) } -create ` } )
return
}
resetForm ( ) ; mode . value = 'create'
if ( props . service === 'labeling' || props . service === 'relabel' || props . service === 'transfer' ) await loadWarehouses ( )
await loadWarehouses ( )
if ( props . service === 'labeling' ) {
const requestedReturnNo = String ( route . query . returnNo || '' ) . trim ( )
const requestedWarehouseId = String ( route . query . warehouseId || '' ) . trim ( )
@@ -1115,14 +1132,18 @@ async function load() {
loading . value = true
try {
if ( props . service === 'labeling' ) {
const result = await listRelabels ( { page : page . value , size : pageSize . value , relabelNo : filters . number || undefined , overseasWarehouseId : filters . warehouse || undefined , status : filters . status || undefined , createdFrom : dateTime ( filters . start ) , createdTo : dateTime ( filters . end , true ) , reviewedFrom : dateTime ( filters . reviewStart ) , reviewedTo : dateTime ( filters . reviewEnd , true ) , completedFrom : dateTime ( filters . completedStart ) , completedTo : dateTime ( filters . completedEnd , true ) , outboundFrom : dateTime ( filters . outboundStart ) , outboundTo : dateTime ( filters . outboundEnd , true ) } )
const query = { page : page . value , size : pageSize . value , relabelNo : filters . number || undefined , overseasWarehouseId : filters . warehouse || undefined , status : filters . status || undefined , createdFrom : dateTime ( filters . start ) , createdTo : dateTime ( filters . end , true ) , reviewedFrom : dateTime ( filters . reviewStart ) , reviewedTo : dateTime ( filters . reviewEnd , true ) , completedFrom : dateTime ( filters . completedStart ) , completedTo : dateTime ( filters . completedEnd , true ) , outboundFrom : dateTime ( filters . outboundStart ) , outboundTo : dateTime ( filters . outboundEnd , true ) }
relabelQuantityQuery . value = query
const [ result , dimensionResult ] = await Promise . all ( [ listRelabels ( query ) , getRelabelQuantities ( query ) . catch ( ( ) => null ) ] )
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 . relatedBusinessOrderNos || [ ] ) . join ( '、' ) || '—' , 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 . createdAt ) ] ) , _ _status : item . status , _ _confirmedAt : item . customerConfirmedAt || '' }
return { ... row ( [ item . relabelNo , ( item . relatedBusinessOrderNos || [ ] ) . join ( '、' ) || '—' , destinationWarehouses , dimensionResult ? . orders [ item . relabelNo ] ? . skuCount ? ? '未提供' , dimensionResult ? . orders [ item . relabelNo ] ? . cartonCount ? ? '未提供' , dimensionResult ? . orders [ item . relabelNo ] ? . labelPieceCount ? ? '未提供' , ( 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 . 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 ) } )
const discardQuery = { 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 ) }
const result = await listDiscards ( discardQuery )
discardStatisticsQuery . value = discardQuery ; discardStatisticsRevision . value ++
total . value = Number . isFinite ( Number ( result . total ) ) ? Number ( result . total ) : result . records . length
submittedRows . value = result . records . map ( ( item ) => ( { ... row ( [ item . discardNo , item . outboundNo || '—' , item . inboundCodes , item . overseasWarehouseName || warehouseDisplay ( item . overseasWarehouseId ) || '—' , '—' , item . totalPackages , ` ${ item . currency } ${ item . totalFee } ` , statusLabel ( item . status ) , formatDateTime ( item . customerConfirmedAt ) , formatDateTime ( item . createdAt ) ] ) , _ _status : item . status } ) )
} else {
@@ -1339,12 +1360,17 @@ async function openDetail(value: Record<string, string>) {
return
}
detailError . value = ''
if ( props . service === 'labeling' ) selectedRelabelQuantity . value = null
try {
const detail = props . service === 'labeling' ? await getRelabel ( value [ '0' ] ) : props . service === 'disposal' ? await getDiscard ( value [ '0' ] ) : await getTransfer ( value [ '0' ] )
const discardSummary = props . service === 'disposal' ? ( detail as { summary ? : ServiceDetail } ) . summary : undefined
showTransferCartons . value = false
selectedDetail . value = { ... value , ... ( detail as ServiceDetail ) , ... ( discardSummary || { } ) }
selectedRelabelDetail . value = props . service === 'labeling' ? detail as RelabelDetail : null
if ( props . service === 'labeling' ) {
const quantities = await getRelabelQuantities ( { relabelNo : value [ '0' ] } ) . catch ( ( ) => null )
if ( selectedRelabelDetail . value ? . application . relabelNo === value [ '0' ] ) selectedRelabelQuantity . value = quantities ? . orders [ value [ '0' ] ] || null
}
mode . value = 'detail'
if ( props . service === 'labeling' ) void loadCompletionPhotos ( )
if ( props . service === 'transfer' ) void loadMeasurementPhotos ( )
@@ -1675,14 +1701,16 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
< / script >
< template >
< section class = "warehouse-service-page" : class = "{ 'warehouse-service-page--detail': mode === 'detail', 'warehouse-service-page--transfer': props.service === 'transfer', 'warehouse-service-page--return-relabel': isReturnRelabelSource }" >
< section class = "warehouse-service-page" : class = "{ 'warehouse-service-page--detail': mode === 'detail', 'warehouse-service-page--transfer': props.service === 'transfer', 'warehouse-service-page--disposal-form': props.service === 'disposal' && (mode === 'create' || mode === 'edit'), 'warehouse-service-page-- return-relabel': isReturnRelabelSource }" >
< template v-if = "mode === 'list'" >
< RelabelQuantityPanel v-if = "props.service === 'labeling'" :query="relabelQuantityQuery" / >
< 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" / >
< DiscardStatistics v-if = "props.service === 'disposal'" :query="discardStatisticsQuery" :revision="discardStatisticsRevision" / >
< 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 # 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 # labelingType = "{ row }" > < span v-if = "row['6 '] === '—'">—</span><span v-else class="labeling-type-tags"><el-tag v-for="label in labelingTypeLabels(row['6 '])" :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 >
@@ -1691,8 +1719,8 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
< template v-else-if = "mode === 'create' || mode === 'edit'" >
< div class = "warehouse-page-heading" > < h2 > { { mode === 'edit' ? ` 编辑转运草稿 ${ editingTransferNo } ` : config . createTitle } } < / h2 > < el-button @click ="returnToList" > < ArrowLeft :size = "16" / > 返回列表 < / el-button > < / div >
< form : class = "{ 'warehouse-transfer-form': props.service === 'transfer', 'warehouse-transfer-form--relabel': props.service === 'transfer' && form.relabel }" @submit.prevent ="submit('submit')" >
< div class = "warehouse-card warehouse-form-section warehouse-transfer-main-card" >
< form : class = "{ 'warehouse-transfer-form': props.service === 'transfer', 'warehouse-transfer-form--relabel': props.service === 'transfer' && form.relabel }" : style = "props.service === 'transfer' ? { '--transfer-left': `${transferPaneShare}fr`, '--transfer-right': `${100 - transferPaneShare}fr` } : undefined" @submit.prevent ="submit('submit')" >
< div id = "transfer-main-pane" class = "warehouse-card warehouse-form-section warehouse-transfer-main-card" >
< div v-if = "props.service === 'labeling'" class="warehouse-order-info-heading" >
< h3 > 订单信息 < / h3 >
< el-button text type = "primary" native -type = " button " :aria-expanded = "!orderInfoCollapsed" @click ="orderInfoCollapsed = !orderInfoCollapsed" > {{ orderInfoCollapsed ? ' 展开信息 ' : ' 收起信息 ' }} < / el -button >
@@ -1707,7 +1735,7 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
< label v-if = "props.service === 'disposal'" class="warehouse-disposal-field"><span><i>*</i>选择入库单</span><el-select v-model="selectedDiscardOrderId" filterable clearable :loading="discardCandidatesLoading" :disabled="!form.warehouse" no-data-text="当前海外仓暂无可废弃库存" placeholder="" @change="selectDiscardInbound"><el-option v-for="candidate in discardDocuments" :key="candidate.orderId" :label="`${candidate.sourceType === 'RETURN_CARTON' ? '退货|' : ''}${candidate.inboundOrderNo || candidate.inboundCode || '—'}|可用 ${candidate.availablePackages} 箱`" :value="candidate.orderId" / > < / el-select > < / label >
< label v-if = "props.service === 'relabel'"><span><i>*</i>进仓编号</span><el-input v-model="form.inboundNo" placeholder="请输入已有入仓编号" / > < / label >
< label v-if = "props.service === 'relabel'"><span><i>*</i>来源 FBA 仓库</span><el-select v-model="form.sourceWarehouse" :loading="fbaWarehousesLoading" :disabled="Boolean(fbaWarehousesError)" placeholder="请选择平台维护的 FBA 仓"><el-option v-for="warehouse in fbaWarehouses" :key="warehouse.id" :label="warehouseLabel(warehouse)" :value="warehouse.warehouseCode" / > < / el-select > < / label >
< label v-else-if = "props.service === 'disposal'" class="warehouse-disposal-field"><span><i>*</i>废弃原因</span><el-select v-model="form.reason" placeholder=""><el-option label="客户退货 " value="客户退货 " /><el-option label="亚马逊移除 " value="亚马逊移除" /><el-option label="残损不可售" value="残损不可售 " / > < / el-select > < / label >
< label v-else-if = "props.service === 'disposal'" class="warehouse-disposal-field"><span><i>*</i>废弃原因</span><el-select v-model="form.reason" placeholder=""><el-option label="残损不可售 " value="残损不可售 " /><el-option label="其他 " value="其他 " / > < / el-select > < / label >
< label v-else > < span > < i > * < / i > { { props . service === 'labeling' ? '海外操作仓(中转仓)' : props . service === 'transfer' ? '入库海外仓' : '操作仓' } } < / span > < el-select v-model = "form.warehouse" :loading="fbaWarehousesLoading || operationWarehouseDetailLoading" :disabled="Boolean(operationWarehousesError)" clearable placeholder="" @change="props.service === 'labeling' ? selectOperationWarehouse() : props.service === 'transfer' && selectTransferWarehouse()"><el-option v-for="warehouse in operationWarehouses" :key="warehouse.id" :label="warehouseLabel(warehouse)" :value="String(warehouse.id)" /></el-select><small v-if="operationWarehousesError" class="warehouse-hint" > {{ operationWarehousesError }} < / small > < / label >
< label v-if = "props.service === 'labeling'"><span><i>*</i>选择入仓单或退货单</span><el-select v-model="selectedRelabelInboundOrderId" filterable clearable :filter-method="(value: string) => relabelInventorySearch = value" :loading="relabelCandidatesLoading" :disabled="!form.warehouse" no-data-text="暂无匹配的可选库存" placeholder="" @change="selectRelabelInventory"><el-option v-for="option in visibleRelabelInboundOptions.filter(item => !relabelInventorySearch.trim() || item.inboundOrderNo.toUpperCase().includes(relabelInventorySearch.trim().toUpperCase()) || item.inboundCode.toUpperCase().includes(relabelInventorySearch.trim().toUpperCase()))" :key="option.value" :label="relabelOptionLabel(option)" :value="option.value" :disabled="option.availablePackages <= 0" / > < / el-select > < / label >
< label v-if = "props.service === 'transfer'"><span>库存转运来源(可选)</span><el-select v-model="selectedTransferInventory" filterable clearable :loading="relabelCandidatesLoading" :disabled="!form.warehouse" no-data-text="当前海外仓暂无可用库存" placeholder="" @change="selectTransferInventory"><el-option v-for="option in transferInventoryOptions" :key="option.value" :label="`${option.label}|可用 ${option.packages} 箱`" :value="option.value" / > < / el-select > < / label >
@@ -1825,7 +1853,8 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
<div v-if=" ! inventoryTransfer && ( props . service !== 'disposal' || ! discardSelectedCandidate ? . cartonSelectionSupported ) " class=" warehouse - table - scroll "><table class=" warehouse - edit - table "><thead><tr><th>商品 SKU{{ props.service === 'transfer' ? '' : ' *' }}</th><th>中文品名{{ props.service === 'transfer' ? '' : ' *' }}</th><th v-if=" props . service === 'disposal' ">可用箱数</th><th v-if=" props . service === 'relabel' ">FNSKU / 箱唛</th><th v-if=" props . service === 'transfer' ">SKU 数量(件)*</th><th>{{ props.service === 'disposal' ? '本次废弃箱数' : '预计箱数' }} *</th><th v-if=" props . service !== 'disposal' ">操作</th></tr></thead><tbody><tr v-for=" row in cargoRows " :key=" row . id "><td><el-input v-model=" row . sku " :readonly=" props . service === 'disposal' " :placeholder=" props . service === 'relabel' ? '请输入商品 SKU' : '' " /></td><td><el-input v-model=" row . name " :readonly=" props . service === 'disposal' " :placeholder=" props . service === 'relabel' ? '请输入中文品名' : '' " /></td><td v-if=" props . service === 'disposal' "><strong>{{ row.availableQuantity }} 箱</strong></td><td v-if=" props . service === 'relabel' "><el-input v-model=" row . shippingMark " placeholder=" 请输入FNSKU或箱唛 " /></td><td v-if=" props . service === 'transfer' "><el-input-number v-model=" row . quantity " :min=" 1 " :precision=" 0 " controls-position=" right " placeholder=" " /></td><td v-if=" props . service === 'transfer' "><el-input-number v-model=" row . expectedPackageCount " :min=" 1 " :precision=" 0 " controls-position=" right " placeholder=" " /></td><td v-else><el-input-number v-model=" row . quantity " :disabled=" props . service === 'disposal' " :min=" props . service === 'disposal' ? 0 : 1 " :max=" row . availableQuantity " controls-position=" right " :placeholder=" props . service === 'relabel' ? '请输入箱数' : '' " /></td><td v-if=" props . service !== 'disposal' "><button type=" button " class=" warehouse - delete " title=" 删除 " @click=" removeCargoRow ( row . id ) "><Trash2 :size=" 16 " />删除</button></td></tr><tr v-if=" cargoRows . length === 0 "><td :colspan=" props . service === 'disposal' ? 4 : props . service === 'relabel' || props . service === 'transfer' ? 5 : 4 "><div class=" warehouse - empty ">暂无货物明细</div></td></tr></tbody></table></div>
</template>
</div>
<div v-if=" props . service === 'transfer' && form . relabel " class=" warehouse - card warehouse - form - section warehouse - transfer - relabel ">
<TransferPaneDivider v-if=" props . service === 'transfer' && form . relabel " v-model=" transferPaneShare " class="warehouse - transfer - divider " / >
<div id=" transfer - relabel - pane " v-if=" props . service === 'transfer' && form . relabel " class=" warehouse - card warehouse - form - section warehouse - transfer - relabel ">
<div class=" warehouse - section - heading warehouse - labeling - heading warehouse - step - heading "><div><h3><span class=" warehouse - step - number ">2</span>换标申请</h3></div></div>
<div class=" warehouse - form - grid warehouse - transfer - relabel - fields "><label><span><i>*</i>换标截止时间</span><el-date-picker v-model=" form . labelDeadline " type=" datetime " value-format=" YYYY - MM - DDTHH : mm : ss " placeholder=" " /></label><label><span><i>*</i>换标联系人</span><el-input v-model=" form . relabelContact " placeholder=" " maxlength=" 128 " /></label><label><span><i>*</i>换标联系人电话</span><el-input v-model=" form . relabelPhone " placeholder=" " maxlength=" 64 " /></label><label v-if=" labelingMode !== 'sku' "><span><i>*</i>换标后派送方式</span><el-select v-model=" form . relabelDeliveryMethod " placeholder=" "><el-option label=" 卡车派送 " value=" TRUCK " /><el-option label=" 快递派送 " value=" EXPRESS " /><el-option label=" 亚马逊自提 " value=" AMAZON _PICKUP " /><el-option label=" 客户自提 " value=" CUSTOMER _PICKUP " /></el-select></label><label class=" warehouse - span - 2 "><span><i>*</i>整票换标货物目的 FBA 仓</span><el-select v-model=" transferRelabelDefaultDestination " :loading=" fbaWarehousesLoading " :disabled=" Boolean ( fbaWarehousesError ) " filterable placeholder=" "><el-option v-for=" warehouse in fbaWarehouses " :key=" warehouse . id " :label=" warehouseLabel ( warehouse ) " :value=" warehouse . warehouseCode " /></el-select></label><label><span>FBA 货件编号</span><el-input v-model=" form . fbaShipmentNo " placeholder=" " /></label><label class=" warehouse - span - 2 "><span>贴标要求</span><el-input v-model=" form . requirement " type=" textarea " :rows=" 2 " maxlength=" 1000 " show-word-limit placeholder=" " /></label></div>
<div class=" warehouse - labeling - mode "><span>换标类型</span><el-radio-group v-model=" labelingMode " aria-label=" 换标类型 "><el-radio-button value=" carton ">只换箱唛</el-radio-button><el-radio-button value=" sku ">只换 SKU 标签</el-radio-button><el-radio-button value=" carton _and _sku ">SKU 和箱唛都换</el-radio-button></el-radio-group></div>
@@ -1862,10 +1891,10 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
</header>
<div v-if=" detailError " class=" warehouse - detail - error " role=" alert "><strong>{{ detailError }}</strong><el-button @click=" loadDetailPage ">重新加载</el-button></div>
<ReviewRejectionNotice v-if=" ! detailError " :status=" props . service === 'labeling' ? selectedRelabelDetail ? . application . status : selectedDetail ? . status " :reason=" props . service === 'labeling' ? selectedRelabelDetail ? . application . reviewRemark : selectedDetail ? . reviewRemark " />
<div v-if=" ! detailError " class=" warehouse - card warehouse - form - section "><h3>订单概览</h3><div v-if=" props . service === 'labeling' " class=" warehouse - detail - grid "><div><span>操作仓</span><strong>{{ warehouseDisplay(selectedRelabelDetail?.application.overseasWarehouseId) }}</strong></div><div><span>关联单号</span><strong>{{ selectedRelabelDetail?.application.customerOrderNo || '—' }}</strong></div><div><span>SKU 数(种)</span><strong>{{ selectedRelabelDetail ? relabelSkuCount(selectedRelabelDetail.items) : '—' }}</strong></div><div><span>总 箱数</span><strong>{{ selectedRelabelDetail?.application.totalPackage Count ?? '— ' }}</strong></div><div><span>贴标截止时间</span><strong>{{ formatDateTime(selectedRelabelDetail?.application.labelDeadline) }}</strong></div><div><span>仓库联系人</span><strong>{{ selectedRelabelDetail?.application.contactName || '—' }}</strong></div><div><span>联系电话</span><strong>{{ selectedRelabelDetail?.application.contactPhone || '—' }}</strong></div><div><span>创建时间</span><strong>{{ formatDateTime(selectedRelabelDetail?.application.createdAt) }}</strong></div></div><div v-else-if=" props . service === 'transfer' " class=" warehouse - detail - grid warehouse - transfer - overview - grid "><div><span>状态</span><el-tag :type=" transferStatusTagType ( selectedDetail ? . status || '' ) " effect=" light ">{{ statusLabel(selectedDetail?.status || '') }}</el-tag></div><div><span>目的去向</span><strong>{{ destinationTypeLabel(selectedDetail?.destinationType, selectedDetail?.fbaWarehouseCode) }}</strong></div><div v-if=" selectedDetail ? . destinationType !== 'PRIVATE' "><span>FBA 目的仓</span><strong>{{ selectedDetail?.destinationWarehouseName || warehouseDisplay(selectedDetail?.destinationWarehouseCode || selectedDetail?.fbaWarehouseCode) }}</strong></div><div v-if=" selectedDetail ? . destinationType !== 'PRIVATE' "><span>FBA 货件号</span><strong>{{ selectedDetail?.fbaShipmentNo || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' " class=" warehouse - overview - wide "><span>私人仓地址</span><strong>{{ selectedDetail?.privateDestinationAddress || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>邮编</span><strong>{{ selectedDetail?.privateDestinationPostalCode || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>私人仓联系人</span><strong>{{ selectedDetail?.privateDestinationContactName || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>联系电话</span><strong>{{ selectedDetail?.privateDestinationContactPhone || '—' }}</strong></div><div><span>海外仓</span><strong>{{ warehouseDisplay(selectedDetail?.operatingWarehouseId) }}</strong></div><div><span>预报 SKU 种数</span><strong>{{ new Set((selectedDetail?.items || []).map(item => item.skuCode).filter(Boolean)).size }}</strong></div><div><span>预报 SKU 总件数</span><strong>{{ transferForecastQuantity }}</strong></div><div><span>预计箱数</span><strong>{{ selectedDetail?.packageCount ?? '—' }}</strong></div><div><span>实际签收箱数</span><strong>{{ selectedDetail?.cartons?.filter((carton) => carton.status === 'COUNTED' ).length ?? '—' }}</strong></div><div><span>入仓方式</span><strong>{{ deliveryMethodLabel(selectedDetail?.deliveryMethod || '') }}</strong></div><div><span>期望发货时间</span><strong>{{ formatDateTime(selectedDetail?.estimatedShipAt) }}</strong></div><div><span>实际发货时间</span><strong>{{ formatDateTime(selectedDetail?.actualShipAt) }}</strong></div><div><span>是否换标</span><strong>{{ selectedDetail?.needRelabel ? '是' : '否' }}</strong></div><div><span>换标状态</span><el-tag :type=" transferRelabelStatusTagType ( transferRelabelStatus ( selectedDetail || { } ) . code ) " effect=" light ">{{ transferRelabelStatus(selectedDetail || {}).label }}</el-tag></div><div><span>换标单号</span><strong>{{ selectedDetail?.relabelNo || '—' }}</strong></div><div><span>创建时间</span><strong>{{ formatDateTime(selectedDetail?.createdAt) }}</strong></div></div><div v-else class=" warehouse - detail - grid "><div v-for=" ( column , index ) in config . columns . slice ( 1 ) " :key=" column "><span>{{ column }}</span><strong>{{ selectedDetail?.[String(index)] || '—' }}</strong></div></div></div>
<div v-if=" ! detailError " class=" warehouse - card warehouse - form - section "><h3>订单概览</h3><div v-if=" props . service === 'labeling' " class=" warehouse - detail - grid "><div><span>操作仓</span><strong>{{ warehouseDisplay(selectedRelabelDetail?.application.overseasWarehouseId) }}</strong></div><div><span>关联单号</span><strong>{{ selectedRelabelDetail?.application.customerOrderNo || '—' }}</strong></div><div><span>SKU 数(种)</span><strong>{{ selectedRelabelDetail ? relabelSkuCount(selectedRelabelDetail.items) : '—' }}</strong></div><div><span>箱数</span><strong>{{ selectedRelabelQuantity?.carton Count ?? '未提供 ' }}</strong></div><div><span>贴标截止时间</span><strong>{{ formatDateTime(selectedRelabelDetail?.application.labelDeadline) }}</strong></div><div><span>仓库联系人</span><strong>{{ selectedRelabelDetail?.application.contactName || '—' }}</strong></div><div><span>联系电话</span><strong>{{ selectedRelabelDetail?.application.contactPhone || '—' }}</strong></div><div><span>创建时间</span><strong>{{ formatDateTime(selectedRelabelDetail?.application.createdAt) }}</strong></div></div><div v-else-if=" props . service === 'transfer' " class=" warehouse - detail - grid warehouse - transfer - overview - grid "><div><span>状态</span><el-tag :type=" transferStatusTagType ( selectedDetail ? . status || '' ) " effect=" light ">{{ statusLabel(selectedDetail?.status || '') }}</el-tag></div><div><span>目的去向</span><strong>{{ destinationTypeLabel(selectedDetail?.destinationType, selectedDetail?.fbaWarehouseCode) }}</strong></div><div v-if=" selectedDetail ? . destinationType !== 'PRIVATE' "><span>FBA 目的仓</span><strong>{{ selectedDetail?.destinationWarehouseName || warehouseDisplay(selectedDetail?.destinationWarehouseCode || selectedDetail?.fbaWarehouseCode) }}</strong></div><div v-if=" selectedDetail ? . destinationType !== 'PRIVATE' "><span>FBA 货件号</span><strong>{{ selectedDetail?.fbaShipmentNo || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' " class=" warehouse - overview - wide "><span>私人仓地址</span><strong>{{ selectedDetail?.privateDestinationAddress || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>邮编</span><strong>{{ selectedDetail?.privateDestinationPostalCode || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>私人仓联系人</span><strong>{{ selectedDetail?.privateDestinationContactName || '—' }}</strong></div><div v-if=" selectedDetail ? . destinationType === 'PRIVATE' "><span>联系电话</span><strong>{{ selectedDetail?.privateDestinationContactPhone || '—' }}</strong></div><div><span>海外仓</span><strong>{{ warehouseDisplay(selectedDetail?.operatingWarehouseId) }}</strong></div><div><span>预报 SKU 种数</span><strong>{{ new Set((selectedDetail?.items || []).map(item => item.skuCode).filter(Boolean)).size }}</strong></div><div><span>预报 SKU 总件数</span><strong>{{ transferForecastQuantity }}</strong></div><div><span>预计箱数</span><strong>{{ selectedDetail?.packageCount ?? '—' }}</strong></div><div><span>实际签收箱数</span><strong>{{ countedTransferCartons( ).length ?? '—' }}</strong></div><div><span>入仓方式</span><strong>{{ deliveryMethodLabel(selectedDetail?.deliveryMethod || '') }}</strong></div><div><span>期望发货时间</span><strong>{{ formatDateTime(selectedDetail?.estimatedShipAt) }}</strong></div><div><span>实际发货时间</span><strong>{{ formatDateTime(selectedDetail?.actualShipAt) }}</strong></div><div><span>是否换标</span><strong>{{ selectedDetail?.needRelabel ? '是' : '否' }}</strong></div><div><span>换标状态</span><el-tag :type=" transferRelabelStatusTagType ( transferRelabelStatus ( selectedDetail || { } ) . code ) " effect=" light ">{{ transferRelabelStatus(selectedDetail || {}).label }}</el-tag></div><div><span>换标单号</span><strong>{{ selectedDetail?.relabelNo || '—' }}</strong></div><div><span>创建时间</span><strong>{{ formatDateTime(selectedDetail?.createdAt) }}</strong></div></div><div v-else class=" warehouse - detail - grid "><div v-for=" ( column , index ) in config . columns . slice ( 1 ) " :key=" column "><span>{{ column }}</span><strong>{{ selectedDetail?.[String(index)] || '—' }}</strong></div></div></div>
<TransferPickupProgressPanel v-if=" ! detailError && props . service === 'transfer' && selectedDetail ? . deliveryMethod === 'WAREHOUSE_PICKUP' " :transfer-no=" String ( selectedDetail . transferNo || '' ) " />
<div v-if=" props . service === 'disposal' " class=" warehouse - card warehouse - form - section ">
<h3>本次废弃箱子</h3><div class=" warehouse - table - scroll "><table class=" warehouse - edit - table "><thead><tr><th>入仓码</th><th>SKU</th><th>品名</th><th>申请数量</th><th>所选箱唛</th></tr></thead><tbody><tr v-for=" ( item , index ) in selectedDetail ? . items || [ ] " :key=" index "><td>{{ item.inboundCode || '—' }}</td><td>{{ item.skuCode || '—' }}</td><td>{{ item.productName || '—' }}</td><td>{{ item.discardPackages ?? '—' }}</td><td>{{ item.cartonMarks?.join('、') || '全部库存(历史记录无箱唛快照)' }}</td></tr></tbody></table></div>
<h3>本次废弃箱子</h3><div class=" warehouse - table - scroll "><table class=" warehouse - edit - table "><thead><tr><th>入仓码</th><th>SKU</th><th>品名</th><th>申请数量</th><th>所选箱唛</th></tr></thead><tbody><tr v-for=" ( item , index ) in selectedDetail ? . items || [ ] " :key=" index "><td>{{ item.inboundCode || '—' }}</td><td>{{ item.skuCode || '—' }}</td><td>{{ item.productName || '—' }}</td><td>{{ item.discardPackages ?? '—' }} {{ item.quantityUnit || '单位未记录' }}<br>实际:{{ item.actualDiscardPackages == null ? '未记录' : `${item.actualDiscardPackages} ${item.quantityUnit || '单位未记录'}` }}</td><td>{{ item.cartonMarks?.join('、') || '全部库存(历史记录无箱唛快照)' }}</td></tr></tbody></table></div>
<h3>废弃现场照片</h3><div v-if=" selectedDetail ? . photos ? . length " class=" warehouse - photo - grid "><div v-for=" photo in selectedDetail . photos " :key=" photo . fileId " class=" warehouse - photo - item "><el-image v-if=" discardPhotoUrls [ photo . fileId ] " :src=" discardPhotoUrls [ photo . fileId ] " :preview-src-list=" discardPhotoPreviewUrls " :initial-index=" discardPhotoPreviewUrls . indexOf ( discardPhotoUrls [ photo . fileId ] ) " fit=" cover " preview-teleported /><div v-else-if=" discardPhotoLoading [ photo . fileId ] " class=" warehouse - photo - placeholder ">照片加载中…</div><button v-else class=" warehouse - photo - placeholder warehouse - photo - retry " type=" button " @click=" loadDiscardPhoto ( photo . fileId ) ">{{ discardPhotoErrors[photo.fileId] ? '加载失败,点击重试' : '加载照片' }}</button><small>{{ formatDateTime(photo.submittedAt) }}</small></div></div><div v-else class=" warehouse - empty ">暂无已提交的废弃现场照片</div>
</div>
<div v-if=" props . service === 'transfer' && selectedDetail ? . status !== 'DRAFT' " class=" warehouse - card warehouse - form - section ">
@@ -1939,14 +1968,14 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
<div class=" warehouse - section - heading "><h3>贴标明细资料</h3><input ref=" relabelFileInput " class=" warehouse - hidden - input " type=" file " accept=" application / pdf , . pdf " @change=" uploadSelectedRelabelFile "></div>
<div class=" warehouse - hint ">需要补充或替换资料时,可在对应明细行上传 SKU 或箱唛文件。</div>
<div class=" warehouse - table - scroll "><table class=" warehouse - relabel - detail - table "><thead><tr><th>换标模式</th><th>仓库唛头</th><th>SKU</th><th>明细文件</th><th>操作</th></tr></thead><tbody>
<tr v-for=" item in selectedRelabelDetail ? . items || [ ] " :key=" item . id "><td>{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}</td><td>{{ item.cartonMark || '—' }}</td><td>{{ relabelSkuCodes(item).join('、') || '—' }}</td><td>{{ item.relabelFileName || '未上传' }}</td><td><el-button size=" small " @click=" chooseRelabelFile ( 'ITEM' , String ( item . id ) ) "><Upload :size=" 14 " />上传明细文件</el-button></td></tr>
<tr v-for=" item in selectedRelabelDetail ? . items || [ ] " :key=" item . id "><td>{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : ['SKU_LABEL', 'RETURN_BULK_SKU_LABEL'].includes( item.operationType || '') ? 'SKU 换标' : '箱唛换标' }}</td><td>{{ item.cartonMark || '—' }}</td><td>{{ relabelSkuCodes(item).join('、') || '—' }}</td><td>{{ item.relabelFileName || '未上传' }}</td><td><el-button size=" small " @click=" chooseRelabelFile ( 'ITEM' , String ( item . id ) ) "><Upload :size=" 14 " />上传明细文件</el-button></td></tr>
<tr v-if=" ! selectedRelabelDetail ? . items ? . length "><td colspan=" 5 "><div class=" warehouse - empty ">暂无贴标明细</div></td></tr>
</tbody></table></div>
</div>
<div v-if=" props . service === 'labeling' " class=" warehouse - card warehouse - form - section ">
<h3>换标任务明细</h3>
<div class=" warehouse - table - scroll "><table class=" warehouse - relabel - detail - table "><thead><tr><th>换标模式</th><th>我方箱唛</th><th>新 FBA 箱唛</th><th>FBA 目的仓</th><th>任务箱 数</th><th>商品 SKU</th><th>SKU 换标明细</th><th>FBA 货件编号</th><th>贴标要求</th><th>备注</th></tr></thead><tbody>
<tr v-for=" item in selectedRelabelDetail ? . items || [ ] " :key=" item . id "><td>{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : item.operationType === 'SKU_LABEL' ? 'SKU 换标' : '箱唛换标' }}</td><td><strong>{{ item.cartonMark || '—' }}</strong></td><td><strong>{{ item.fbaCartonMark || '—' }}</strong></td><td>{{ warehouseDisplay(item.destinationFbaWarehouseCode) }}</td><td>{{ item.totalPackageCount }} 箱 </td><td>{{ relabelSkuCodes(item).join('、') || '—' }}</td><td><template v-if=" item . skuItems ? . length "><div v-for=" skuItem in item . skuItems " :key=" ` ${ skuItem . skuCode } - ${ skuItem . newSkuCode } - ${ skuItem . quantity } ` ">{{ skuItem.skuCode }} → {{ skuItem.newSkuCode }} × {{ skuItem.quantity }} 件</div></template><span v-else>{{ item.newSkuCode || '—' }}</span></td><td>{{ item.shipmentNo || '—' }}</td><td>{{ item.labelRequirement || '—' }}</td><td>{{ item.remark || '—' }}</td></tr>
<h3>换标任务明细</h3><RelabelQuantityPanel :relabel-no=" detailNumber " />
<div class=" warehouse - table - scroll "><table class=" warehouse - relabel - detail - table "><thead><tr><th>换标模式</th><th>我方箱唛</th><th>新 FBA 箱唛</th><th>FBA 目的仓</th><th>任务数量/单位 </th><th>商品 SKU</th><th>SKU 换标明细</th><th>FBA 货件编号</th><th>贴标要求</th><th>备注</th></tr></thead><tbody>
<tr v-for=" item in selectedRelabelDetail ? . items || [ ] " :key=" item . id "><td>{{ item.operationType === 'CARTON_AND_SKU' ? '箱唛 + SKU 换标' : ['SKU_LABEL', 'RETURN_BULK_SKU_LABEL'].includes( item.operationType || '') ? 'SKU 换标' : '箱唛换标' }}</td><td><strong>{{ item.cartonMark || '—' }}</strong></td><td><strong>{{ item.fbaCartonMark || '—' }}</strong></td><td>{{ warehouseDisplay(item.destinationFbaWarehouseCode) }}</td><td>{{ item.totalPackageCount ?? '未提供' }} {{ String(item.operationType) === 'RETURN_BULK_SKU_LABEL' ? '件' : '箱任务' }}</td><td>{{ relabelSkuCodes(item).join('、') || '—' }}</td><td><template v-if=" item . skuItems ? . length "><div v-for=" skuItem in item . skuItems " :key=" ` ${ skuItem . skuCode } - ${ skuItem . newSkuCode } - ${ skuItem . quantity } ` ">{{ skuItem.skuCode }} → {{ skuItem.newSkuCode }} × {{ skuItem.quantity }} 件</div></template><span v-else>{{ item.newSkuCode || '—' }}</span></td><td>{{ item.shipmentNo || '—' }}</td><td>{{ item.labelRequirement || '—' }}</td><td>{{ item.remark || '—' }}</td></tr>
<tr v-if=" ! selectedRelabelDetail ? . items ? . length "><td colspan=" 10 "><div class=" warehouse - empty ">暂无换标任务明细</div></td></tr>
</tbody></table></div>
</div>
@@ -2099,9 +2128,9 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
. warehouse - measurement - photo - item { width : 100 % ; height : 120 px }
. warehouse - template - actions { flex - wrap : wrap ; justify - content : flex - end } . warehouse - import - preview { margin : 0 0 16 px ; padding : 14 px ; border : 1 px solid # cfe0f5 ; border - radius : 5 px ; background : # f8fbff } . warehouse - import - preview . warehouse - section - heading { margin - bottom : 10 px } . warehouse - import - preview . warehouse - section - heading > div { display : flex ; align - items : center ; gap : 10 px } . warehouse - import - preview p { margin : 0 ; color : # 7 d8797 ; font - size : 12 px } . warehouse - binding - preview - table { min - width : 980 px ; background : # fff }
. warehouse - transfer - relabel . warehouse - labeling - heading > div : first - child { min - width : 0 } . warehouse - transfer - relabel . warehouse - labeling - heading h3 { margin - bottom : 6 px } . warehouse - transfer - relabel . warehouse - labeling - heading p { margin : 0 0 16 px ; color : # 7 d8797 ; font - size : 12 px } . warehouse - transfer - relabel - fields { margin - bottom : 18 px } . warehouse - transfer - file - groups { display : grid ; grid - template - columns : minmax ( 0 , 1.15 fr ) minmax ( 360 px , .85 fr ) ; align - items : stretch ; gap : 14 px ; margin - bottom : 14 px } . warehouse - transfer - total - files , . warehouse - transfer - template - group { height : 100 % ; margin : 0 } . warehouse - transfer - mark - table { min - width : 1420 px } . warehouse - transfer - mark - table td { vertical - align : top } . warehouse - transfer - mark - table : deep ( . el - textarea ) { min - width : 220 px } . warehouse - transfer - mark - table : deep ( . el - input - number ) { width : 150 px } . warehouse - count - error { color : # d64545 }
. warehouse - transfer - form { display : grid ; grid - template - columns : minmax ( 0 , 1 fr ) ; gap : 12 px } . warehouse - transfer - form -- relabel { grid - template - columns : minmax ( 0 , 1 fr ) minmax ( 0 , 1.35 fr ) ; align - items : start } . warehouse - transfer - form -- relabel . warehouse - transfer - main - card { grid - column : 1 ; grid - row : 1 } . warehouse - transfer - form -- relabel . warehouse - transfer - cargo - card { grid - column : 1 ; grid - row : 2 } . warehouse - transfer - form -- relabel . warehouse - transfer - relabel { grid - column : 2 ; grid - row : 1 / span 2 ; margin - bottom : 0 } . warehouse - transfer - form -- relabel . warehouse - transfer - submit - bar { grid - column : 1 / - 1 } . warehouse - transfer - form : deep ( . el - input _ _wrapper ) , . warehouse - transfer - form : deep ( . el - textarea _ _inner ) , . warehouse - transfer - form : deep ( . el - select _ _wrapper ) , . warehouse - transfer - form : deep ( . el - date - editor . el - input _ _wrapper ) { min - height : 32 px } . warehouse - transfer - form . warehouse - form - section { padding : 16 px } . warehouse - transfer - form . warehouse - form - section h3 { margin - bottom : 12 px ; padding - bottom : 9 px ; font - size : 14 px } . warehouse - transfer - form . warehouse - form - grid { gap : 12 px 16 px } . warehouse - transfer - form . warehouse - choice - field { min - height : 34 px ; padding : 8 px 10 px ; grid - template - columns : 118 px minmax ( 0 , 1 fr ) ; gap : 10 px } . warehouse - transfer - form . warehouse - choice - field > span { font - size : 12 px } . warehouse - transfer - form . warehouse - receiving - card { gap : 12 px ; padding : 10 px 12 px } . warehouse - transfer - form . warehouse - section - heading { margin - bottom : 8 px } . warehouse - transfer - form . warehouse - edit - table { font - size : 11 px } . warehouse - transfer - form . warehouse - edit - table th { height : 36 px ; padding : 0 9 px } . warehouse - transfer - form . warehouse - edit - table td { height : 42 px ; padding : 6 px 7 px } . warehouse - transfer - form . warehouse - transfer - mark - table : deep ( . el - textarea ) { min - width : 150 px } . warehouse - transfer - form . warehouse - transfer - mark - table : deep ( . el - input - number ) { width : 112 px } . warehouse - transfer - form . warehouse - hint { margin - top : 5 px ; font - size : 11 px } . warehouse - transfer - form . warehouse - labeling - mode { gap : 9 px ; margin - bottom : 10 px ; padding : 9 px 10 px } . warehouse - transfer - form . warehouse - labeling - mode > span { font - size : 12 px } . warehouse - transfer - form . warehouse - labeling - mode : deep ( . el - radio - button _ _inner ) { padding : 6 px 9 px } . warehouse - transfer - form . warehouse - template - actions { display : flex ; flex - wrap : wrap ; justify - content : flex - end ; gap : 5 px ; padding - bottom : 8 px } . warehouse - transfer - form . warehouse - template - actions : deep ( . el - button ) { padding : 6 px 8 px ; font - size : 11 px } . warehouse - transfer - form . warehouse - submit - bar { padding : 4 px 0 18 px } . warehouse - transfer - form . warehouse - submit - bar : deep ( . el - button ) { min - height : 32 px ; padding : 7 px 14 px } . warehouse - transfer - form . warehouse - transfer - relabel { overflow : hidden } . warehouse - transfer - form . warehouse - transfer - relabel - fields { margin - bottom : 10 px } . warehouse - step - heading { align - items : flex - start } . warehouse - step - heading h3 { display : flex ; align - items : center ; gap : 9 px } . warehouse - step - number { display : inline - grid ; flex : 0 0 auto ; width : 24 px ; height : 24 px ; border - radius : 50 % ; background : # 3478 c8 ; color : # fff ; font - size : 12 px ; place - items : center } . warehouse - heading - actions { display : flex ; flex - wrap : wrap ; justify - content : flex - end ; gap : 8 px } . warehouse - transfer - template - group { margin : 0 0 14 px ; padding : 12 px 14 px ; border : 1 px solid # dde5f0 ; border - radius : 7 px ; background : # fbfcfe } . warehouse - binding - heading { margin - top : 14 px ; padding : 12 px 14 px ; border : 1 px solid # dde5f0 ; border - radius : 7 px ; background : # f8faff } . warehouse - binding - heading strong { display : flex ; align - items : center ; gap : 8 px ; color : # 34445 c ; font - size : 13 px }
. warehouse - transfer - form { display : grid ; grid - template - columns : minmax ( 0 , 1 fr ) ; gap : 12 px } . warehouse - transfer - form -- relabel { grid - template - columns : minmax ( 0 , var ( -- transfer - left , 43 fr ) ) 16 px minmax ( 0 , var ( -- transfer - right , 57 fr ) ) ; column - gap : 0 ; align - items : start } . warehouse - transfer - form -- relabel . warehouse - transfer - main - card { grid - column : 1 ; grid - row : 1 } . warehouse - transfer - form -- relabel . warehouse - transfer - cargo - card { grid - column : 1 ; grid - row : 2 } . warehouse - transfer - form -- relabel . warehouse - transfer - relabel { grid - column : 3 ; grid - row : 1 / span 2 ; margin - bottom : 0 } . warehouse - transfer - form -- relabel . warehouse - transfer - submit - bar { grid - column : 1 / - 1 } . warehouse - transfer - form : deep ( . el - input _ _wrapper ) , . warehouse - transfer - form : deep ( . el - textarea _ _inner ) , . warehouse - transfer - form : deep ( . el - select _ _wrapper ) , . warehouse - transfer - form : deep ( . el - date - editor . el - input _ _wrapper ) { min - height : 32 px } . warehouse - transfer - form . warehouse - form - section { padding : 16 px } . warehouse - transfer - form . warehouse - form - section h3 { margin - bottom : 12 px ; padding - bottom : 9 px ; font - size : 14 px } . warehouse - transfer - form . warehouse - form - grid { gap : 12 px 16 px } . warehouse - transfer - form . warehouse - choice - field { min - height : 34 px ; padding : 8 px 10 px ; grid - template - columns : 118 px minmax ( 0 , 1 fr ) ; gap : 10 px } . warehouse - transfer - form . warehouse - choice - field > span { font - size : 12 px } . warehouse - transfer - form . warehouse - receiving - card { gap : 12 px ; padding : 10 px 12 px } . warehouse - transfer - form . warehouse - section - heading { margin - bottom : 8 px } . warehouse - transfer - form . warehouse - edit - table { font - size : 11 px } . warehouse - transfer - form . warehouse - edit - table th { height : 36 px ; padding : 0 9 px } . warehouse - transfer - form . warehouse - edit - table td { height : 42 px ; padding : 6 px 7 px } . warehouse - transfer - form . warehouse - transfer - mark - table : deep ( . el - textarea ) { min - width : 150 px } . warehouse - transfer - form . warehouse - transfer - mark - table : deep ( . el - input - number ) { width : 112 px } . warehouse - transfer - form . warehouse - hint { margin - top : 5 px ; font - size : 11 px } . warehouse - transfer - form . warehouse - labeling - mode { gap : 9 px ; margin - bottom : 10 px ; padding : 9 px 10 px } . warehouse - transfer - form . warehouse - labeling - mode > span { font - size : 12 px } . warehouse - transfer - form . warehouse - labeling - mode : deep ( . el - radio - button _ _inner ) { padding : 6 px 9 px } . warehouse - transfer - form . warehouse - template - actions { display : flex ; flex - wrap : wrap ; justify - content : flex - end ; gap : 5 px ; padding - bottom : 8 px } . warehouse - transfer - form . warehouse - template - actions : deep ( . el - button ) { padding : 6 px 8 px ; font - size : 11 px } . warehouse - transfer - form . warehouse - submit - bar { padding : 4 px 0 18 px } . warehouse - transfer - form . warehouse - submit - bar : deep ( . el - button ) { min - height : 32 px ; padding : 7 px 14 px } . warehouse - transfer - form . warehouse - transfer - relabel { overflow : hidden } . warehouse - transfer - form . warehouse - transfer - relabel - fields { margin - bottom : 10 px } . warehouse - step - heading { align - items : flex - start } . warehouse - step - heading h3 { display : flex ; align - items : center ; gap : 9 px } . warehouse - step - number { display : inline - grid ; flex : 0 0 auto ; width : 24 px ; height : 24 px ; border - radius : 50 % ; background : # 3478 c8 ; color : # fff ; font - size : 12 px ; place - items : center } . warehouse - heading - actions { display : flex ; flex - wrap : wrap ; justify - content : flex - end ; gap : 8 px } . warehouse - transfer - template - group { margin : 0 0 14 px ; padding : 12 px 14 px ; border : 1 px solid # dde5f0 ; border - radius : 7 px ; background : # fbfcfe } . warehouse - binding - heading { margin - top : 14 px ; padding : 12 px 14 px ; border : 1 px solid # dde5f0 ; border - radius : 7 px ; background : # f8faff } . warehouse - binding - heading strong { display : flex ; align - items : center ; gap : 8 px ; color : # 34445 c ; font - size : 13 px }
. warehouse - transfer - form . warehouse - choice - field -- relabel { grid - template - columns : 150 px auto minmax ( 240 px , 1 fr ) } . warehouse - choice - field -- relabel : deep ( . el - radio - group ) { display : flex ; flex - wrap : nowrap } . warehouse - choice - field -- relabel > small { min - width : 0 ; margin : 0 ; line - height : 1.5 }
@ media ( max - width : 1250 px ) { . warehouse - transfer - form -- relabel { grid - template - columns : minmax ( 0 , 1 fr ) minmax ( 0 , 1 fr ) } . warehouse - transfer - form . warehouse - template - actions { justify - content : flex - start } . warehouse - transfer - form . warehouse - labeling - heading { align - items : flex - start ; flex - direction : column } }
@ media ( max - width : 1250 px ) { . warehouse - transfer - form . warehouse - template - actions { justify - content : flex - start } . warehouse - transfer - form . warehouse - labeling - heading { align - items : flex - start ; flex - direction : column } }
@ media ( max - width : 1180 px ) { . warehouse - transfer - file - groups { grid - template - columns : minmax ( 0 , 1 fr ) } }
. warehouse - transfer - form . pickup - address - field { grid - column : span 1 }
. warehouse - transfer - main - card . warehouse - form - grid { grid - template - columns : repeat ( 2 , minmax ( 280 px , 640 px ) ) } . warehouse - transfer - cargo - card . warehouse - section - heading , . warehouse - transfer - cargo - card . warehouse - table - scroll { width : 100 % ; max - width : 1296 px }
@@ -2119,6 +2148,11 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
. warehouse - page - size - select : deep ( . el - input _ _inner ) , . warehouse - page - size - select : deep ( . el - select _ _selected - item ) { color : # 526176 ! important ; opacity : 1 ! important ; - webkit - text - fill - color : # 526176 ; }
. warehouse - list - actions { display : flex ; align - items : center ; gap : 8 px ; white - space : nowrap ; }
. warehouse - disposal - field { max - width : 520 px ; }
. warehouse - service - page -- disposal - form . warehouse - form - grid { grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ; }
. warehouse - service - page -- disposal - form . warehouse - disposal - field ,
. warehouse - service - page -- disposal - form . warehouse - order - info - heading ,
. warehouse - service - page -- disposal - form . warehouse - section - heading ,
. warehouse - service - page -- disposal - form . warehouse - table - scroll { width : 100 % ; max - width : none ; }
@ media ( max - width : 720 px ) {
. warehouse - pagination : deep ( . el - pagination ) { width : 100 % ; justify - content : flex - end ; }
. warehouse - transfer - main - card . warehouse - form - grid { grid - template - columns : minmax ( 0 , 1 fr ) ; }
@@ -2126,6 +2160,13 @@ function addReturnBoxBinding(source: RelabelInventoryCandidate) {
. warehouse - transfer - form . warehouse - choice - field -- relabel { grid - template - columns : 1 fr ; align - items : start ; }
}
. warehouse - transfer - form . warehouse - form - grid { grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ; }
. warehouse - transfer - form . warehouse - form - section { min - width : 0 ; }
. warehouse - transfer - form . warehouse - section - heading ,
. warehouse - transfer - form . warehouse - table - scroll ,
. warehouse - transfer - form . warehouse - order - info - heading ,
. warehouse - transfer - form . warehouse - file - groups -- compact { width : 100 % ; max - width : none ; }
. warehouse - transfer - form -- relabel . warehouse - transfer - divider { grid - column : 2 ; grid - row : 1 / span 2 ; }
< / style >
< style scoped >