优化
This commit is contained in:
@@ -26,16 +26,14 @@ import {
|
||||
} from '@/modules/first-leg/api/firstLeg'
|
||||
import { loadAllWarehouseRecords } from '@/modules/first-leg/utils/warehousePagination'
|
||||
import { createIdempotencyKey } from '@/utils/idempotencyKey'
|
||||
import { createReturnRelabel, uploadReturnRelabelFile } from '../api/returnOrders'
|
||||
|
||||
type ServiceType = 'labeling' | 'transfer' | 'disposal' | 'relabel'
|
||||
type PageMode = 'list' | 'create' | 'edit' | 'detail'
|
||||
type LabelingMode = 'carton' | 'sku' | 'carton_and_sku'
|
||||
type RelabelTemplateType = 'carton' | 'sku' | 'mixed'
|
||||
interface CargoRow { id: number; included?: boolean; sku: string; name: string; quantity: number; availableQuantity?: number; sourceOrderId?: string; sourceType?: 'DROPSHIP' | 'RETURN_CARTON'; sourceInventoryBalanceId?: string; sourceInventoryPositionId?: string; sourceInboundOrderId?: string; returnCartonId?: string; sourceInboundOrderNo?: string; sourceInboundCode?: string; sourceWarehouseName?: string; palletNo?: string; warehouseLocationCode?: string; fnsku: string; shipmentNo: string; newSkuCode: string; shippingMark: string; customerCartonMarks: string; cartonMark: string; fbaCartonMark: string; destinationWarehouseId: string; remark: string }
|
||||
interface CargoRow { id: number; included?: boolean; sku: string; name: string; quantity: number; availableQuantity?: number; sourceOrderId?: string; sourceType?: 'DROPSHIP' | 'RETURN_CARTON' | 'RETURN_PARCEL'; sourceInventoryBalanceId?: string; sourceInventoryPositionId?: string; sourceInboundOrderId?: string; returnCartonId?: string; sourceInboundOrderNo?: string; sourceInboundCode?: string; sourceWarehouseName?: string; palletNo?: string; warehouseLocationCode?: string; fnsku: string; shipmentNo: string; newSkuCode: string; shippingMark: string; customerCartonMarks: string; cartonMark: string; fbaCartonMark: string; destinationWarehouseId: string; remark: string }
|
||||
interface SkuRelabelRow { id: number; sourceRowId: number | null; cartonMark: string; originalSku: string; newSku: string; quantity: number; fbaCartonMark: string; destinationWarehouseId: string; remark: string }
|
||||
interface ImportedRelabelBinding extends SkuRelabelRow { templateType: RelabelTemplateType; selected: boolean; shipmentNo: string }
|
||||
interface ReturnRelabelSkuRow { skuCode: string; productNameZh: string; availableQuantity: number; selected: boolean; quantity: number }
|
||||
interface ServiceConfig { title: string; createTitle: string; numberLabel: string; emptyText: string; columns: string[] }
|
||||
interface TransferCarton { cartonMark: string; customerCartonMark?: string; cartonIndex: number; totalCartons: number; status: string }
|
||||
|
||||
@@ -189,16 +187,21 @@ const selectedDiscardOrderId = ref('')
|
||||
const discardCandidatesLoading = ref(false)
|
||||
const relabelCandidates = ref<RelabelInventoryCandidate[]>([])
|
||||
const selectedRelabelInboundOrderId = ref('')
|
||||
const orderInfoCollapsed = ref(false)
|
||||
const relabelCandidatesLoading = ref(false)
|
||||
const transferInventoryCandidates = ref<RelabelInventoryCandidate[]>([])
|
||||
const selectedTransferInventory = ref('')
|
||||
// Snowflake IDs exceed JavaScript's safe integer range. Keep them as strings
|
||||
// all the way to JSON so the backend receives the exact source order ID.
|
||||
const selectedTransferSourceOrderIds = ref<string[]>([])
|
||||
const returnRelabelSkuRows = ref<ReturnRelabelSkuRow[]>([])
|
||||
const isReturnRelabelSource = computed(() => props.service === 'labeling' && selectedRelabelInboundOrderId.value.startsWith('RETURN_ORDER:'))
|
||||
const selectedReturnOrderNo = computed(() => isReturnRelabelSource.value ? selectedRelabelInboundOrderId.value.slice('RETURN_ORDER:'.length) : '')
|
||||
const requiresBothTotalFiles = computed(() => (props.service === 'labeling' || (props.service === 'transfer' && form.relabel)) && !isReturnRelabelSource.value && labelingMode.value === 'carton_and_sku')
|
||||
const hideReturnSkuCartonMark = computed(() => isReturnRelabelSource.value && labelingMode.value === 'sku')
|
||||
const selectedReturnCandidates = computed(() => relabelCandidates.value.filter(item => Boolean(item.returnCartonId) && item.inboundOrderNo === selectedReturnOrderNo.value))
|
||||
const returnBoxCandidates = computed(() => selectedReturnCandidates.value.filter(item => item.sourceType === 'RETURN_CARTON'))
|
||||
const returnLooseCandidates = computed(() => selectedReturnCandidates.value.filter(item => item.sourceType === 'RETURN_PARCEL'))
|
||||
const returnSkuOnly = computed(() => isReturnRelabelSource.value && returnLooseCandidates.value.length > 0 && returnBoxCandidates.value.length === 0)
|
||||
const requiresBothTotalFiles = computed(() => (props.service === 'labeling' || (props.service === 'transfer' && form.relabel)) && labelingMode.value === 'carton_and_sku')
|
||||
function inventoryQuantity(value: number | string | null | undefined) {
|
||||
const quantity = Number(value)
|
||||
return Number.isFinite(quantity) && quantity > 0 ? quantity : 0
|
||||
@@ -207,7 +210,7 @@ const relabelInboundOptions = computed(() => {
|
||||
const grouped = new Map<string, { value: string; inboundOrderNo: string; inboundCode: string; availablePackages: number; relabelledPackages: number; quantityUnit: '箱' | '件' }>()
|
||||
for (const candidate of relabelCandidates.value) {
|
||||
const returnOrderNo = candidate.inboundOrderNo || String(candidate.returnCartonId || '')
|
||||
const value = candidate.sourceType === 'RETURN_CARTON' ? `RETURN_ORDER:${returnOrderNo}` : String(candidate.inboundOrderId)
|
||||
const value = candidate.returnCartonId ? `RETURN_ORDER:${returnOrderNo}` : String(candidate.inboundOrderId)
|
||||
const current = grouped.get(value)
|
||||
if (current) {
|
||||
current.availablePackages += inventoryQuantity(candidate.availablePackages)
|
||||
@@ -215,11 +218,11 @@ const relabelInboundOptions = computed(() => {
|
||||
}
|
||||
else grouped.set(value, {
|
||||
value,
|
||||
inboundOrderNo: candidate.sourceType === 'RETURN_CARTON' ? `退货单 ${candidate.inboundOrderNo || '—'}` : (candidate.inboundOrderNo || '—'),
|
||||
inboundCode: candidate.sourceType === 'RETURN_CARTON' ? '已签收退货库存' : (candidate.inboundCode || '—'),
|
||||
inboundOrderNo: candidate.returnCartonId ? `退货单 ${candidate.inboundOrderNo || '—'}` : (candidate.inboundOrderNo || '—'),
|
||||
inboundCode: candidate.returnCartonId ? '已签收退货库存' : (candidate.inboundCode || '—'),
|
||||
availablePackages: inventoryQuantity(candidate.availablePackages),
|
||||
relabelledPackages: inventoryQuantity(candidate.relabelledPackages),
|
||||
quantityUnit: candidate.sourceType === 'RETURN_CARTON' ? '件' : '箱',
|
||||
quantityUnit: candidate.returnCartonId ? '件' : '箱',
|
||||
})
|
||||
}
|
||||
return [...grouped.values()]
|
||||
@@ -263,7 +266,10 @@ watch(() => cargoRows.value.map((row) => row.sku), (skus) => {
|
||||
if (sourceSku) row.sku = sourceSku
|
||||
})
|
||||
})
|
||||
watch(labelingMode, (value) => { if (value !== 'carton' && !skuRelabelRows.value.length) addSkuRelabelRow() })
|
||||
watch([returnSkuOnly, labelingMode], ([skuOnly, value]) => {
|
||||
if (skuOnly && value !== 'sku') { labelingMode.value = 'sku'; return }
|
||||
if (value !== 'carton' && !skuRelabelRows.value.length) addSkuRelabelRow()
|
||||
})
|
||||
watch(() => form.destination, (value) => {
|
||||
if (props.service !== 'labeling') return
|
||||
for (const row of cargoRows.value) row.destinationWarehouseId = value
|
||||
@@ -293,6 +299,7 @@ onMounted(() => {
|
||||
onBeforeUnmount(() => { clearCompletionPhotos(); clearMeasurementPhotos() })
|
||||
function resetFilters() { Object.assign(filters, { number: '', inboundNo: '', warehouse: '', destination: '', status: '', start: '', end: '', reviewStart: '', reviewEnd: '', completedStart: '', completedEnd: '', measuredStart: '', measuredEnd: '', outboundStart: '', outboundEnd: '' }) }
|
||||
function resetForm() {
|
||||
orderInfoCollapsed.value = false
|
||||
Object.assign(form, { customerNo: '', inboundNo: '', sourceWarehouse: '', warehouse: '', destination: '', privateDestinationAddress: '', privateDestinationPostalCode: '', privateDestinationContact: '', privateDestinationPhone: '', address: '', contact: '', phone: '', pickupContact: '', pickupPhone: '', relabelContact: '', relabelPhone: '', deliveryMethod: '', relabelDeliveryMethod: '', trackingNo: '', reason: '', requirement: '', relabel: false, remark: '', labelDeadline: '', estimatedArrivalAt: '', estimatedShipAt: '', fbaShipmentNo: '', volumeCbm: 0.01 })
|
||||
cargoRows.value = []
|
||||
transferRelabelRows.value = []
|
||||
@@ -490,7 +497,7 @@ function clearTransferRelabelRows() {
|
||||
function addSkuRelabelRow() {
|
||||
const source = cargoRows.value[Math.min(skuRelabelRows.value.length, Math.max(0, cargoRows.value.length - 1))]
|
||||
skuRelabelRows.value.push({ id: ++skuRelabelSequence, sourceRowId: source?.id || null,
|
||||
cartonMark: '', originalSku: source?.sku || '', newSku: '', quantity: 1,
|
||||
cartonMark: hideReturnSkuCartonMark.value ? source?.cartonMark || '' : '', originalSku: source?.sku || '', newSku: '', quantity: 1,
|
||||
fbaCartonMark: '', destinationWarehouseId: form.destination, remark: '' })
|
||||
}
|
||||
function removeSkuRelabelRow(id: number) { skuRelabelRows.value = skuRelabelRows.value.filter((row) => row.id !== id) }
|
||||
@@ -532,6 +539,16 @@ function chooseCreateTotalFile(scope: 'CARTON_TOTAL' | 'SKU_TOTAL') {
|
||||
function buildSkuRelabelItems(): RelabelCreate['items'] {
|
||||
const groups = new Map<string, SkuRelabelRow[]>()
|
||||
for (const row of skuRelabelRows.value) {
|
||||
if (hideReturnSkuCartonMark.value) {
|
||||
const source = cargoRows.value.find(item => item.id === row.sourceRowId)
|
||||
const candidate = selectedReturnCandidates.value.find(item => String(item.returnCartonId) === source?.returnCartonId)
|
||||
if (candidate?.skuItems?.some(item => item.skuCode === row.originalSku.trim())) row.cartonMark = source?.cartonMark || ''
|
||||
else {
|
||||
const matches = selectedReturnCandidates.value.filter(item => item.skuItems?.some(sku => sku.skuCode === row.originalSku.trim()))
|
||||
if (matches.length !== 1) throw new Error(`请从上方库存明细选择 SKU ${row.originalSku} 的来源库存`)
|
||||
row.cartonMark = matches[0].cartonMark || ''
|
||||
}
|
||||
}
|
||||
const cartonMark = row.cartonMark.trim().toUpperCase()
|
||||
if (!cartonMark) throw new Error('请填写每个箱子的我方箱唛')
|
||||
const rows = groups.get(cartonMark) || []
|
||||
@@ -546,7 +563,20 @@ function buildSkuRelabelItems(): RelabelCreate['items'] {
|
||||
throw new Error('填写的箱唛数量超过当前入仓单可用库存箱数')
|
||||
}
|
||||
return [...groups.entries()].map(([_, rows], groupIndex) => {
|
||||
const source = cargoRows.value.find((item) => item.id === rows[0].sourceRowId) || anchors[groupIndex]
|
||||
const source = isReturnRelabelSource.value
|
||||
? cargoRows.value.find(item => item.cartonMark === rows[0].cartonMark.trim())
|
||||
: cargoRows.value.find((item) => item.id === rows[0].sourceRowId) || anchors[groupIndex]
|
||||
if (isReturnRelabelSource.value && !source) throw new Error('请选择该退货单实际可用的来源箱号')
|
||||
if (isReturnRelabelSource.value) {
|
||||
const candidate = selectedReturnCandidates.value.find(item => String(item.returnCartonId) === source?.returnCartonId)
|
||||
if (candidate?.sourceType === 'RETURN_PARCEL' && labelingMode.value !== 'sku') throw new Error('散件库存只能贴 SKU,请先合箱后申请箱唛或混贴')
|
||||
const requested = new Map<string, number>()
|
||||
for (const row of rows) {
|
||||
const quantity = (requested.get(row.originalSku) || 0) + row.quantity
|
||||
requested.set(row.originalSku, quantity)
|
||||
if (quantity > Number(candidate?.skuItems?.find(item => item.skuCode === row.originalSku)?.quantity || 0)) throw new Error(`SKU ${row.originalSku} 超过来源箱可用数量`)
|
||||
}
|
||||
}
|
||||
if (!source?.returnCartonId && (!source?.sourceInventoryBalanceId || !source.sourceInventoryPositionId || !source.sourceInboundOrderId)) {
|
||||
throw new Error('来源库存已变化,请重新选择有库存的历史入仓单')
|
||||
}
|
||||
@@ -949,48 +979,18 @@ function listRowActions(candidate: object): TableAction[] {
|
||||
if (canConfirmRelabel.value && props.service === 'labeling' && item.__status === 'CUSTOMER_CONFIRM_PENDING' && !item.__confirmedAt) actions.push({ key: 'confirm-relabel', label: '确认换标', run: () => confirmRelabelFromList(item['0']) })
|
||||
return actions
|
||||
}
|
||||
async function submitReturnRelabel() {
|
||||
const items = returnRelabelSkuRows.value.filter(item => item.selected)
|
||||
.map(item => ({ skuCode: item.skuCode, quantity: Number(item.quantity) }))
|
||||
if (!selectedReturnOrderNo.value || !items.length) { ElMessage.warning('请至少选择一个需要贴标的 SKU'); return }
|
||||
if (items.some(item => item.quantity < 1 || item.quantity > (returnRelabelSkuRows.value.find(row => row.skuCode === item.skuCode)?.availableQuantity || 0))) {
|
||||
ElMessage.warning('本次贴标数量必须大于 0,且不能超过该 SKU 的库存总数'); return
|
||||
}
|
||||
const destination = fbaWarehouses.value.find(warehouse => warehouse.warehouseCode === form.destination)
|
||||
if (!destination) { ElMessage.warning('请选择 FBA 目的仓'); return }
|
||||
const selectedFile = cartonTotalFile.value || skuTotalFile.value
|
||||
const fileScope = cartonTotalFile.value ? 'CARTON_TOTAL' as const : 'SKU_TOTAL' as const
|
||||
if (!selectedFile) { ElMessage.warning('请上传箱唛总文件或 SKU 总文件(二选一)'); return }
|
||||
try { await ElMessageBox.confirm(`确认提交退货单 ${selectedReturnOrderNo.value} 的贴标申请吗?`, '提交确认', { confirmButtonText: '提交', cancelButtonText: '取消' }) } catch { return }
|
||||
saving.value = true
|
||||
try {
|
||||
const created = await createReturnRelabel(selectedReturnOrderNo.value, {
|
||||
items,
|
||||
fileScope,
|
||||
destinationFbaWarehouseId: String(destination.id),
|
||||
destinationFbaWarehouseCode: destination.warehouseCode,
|
||||
cartonRemark: form.remark.trim() || undefined,
|
||||
idempotencyKey: createIdempotencyKey(),
|
||||
})
|
||||
await uploadReturnRelabelFile(created.relabelNo, fileScope, selectedFile)
|
||||
ElMessage.success(`贴标申请 ${created.relabelNo} 已提交,等待审核`)
|
||||
await router.push({ name: 'overseas-labeling' })
|
||||
} catch (error) { ElMessage.error(error instanceof Error ? error.message : '退货贴标申请提交失败,请重试') }
|
||||
finally { saving.value = false }
|
||||
}
|
||||
watch([page, pageSize], ([nextPage, nextSize], [previousPage, previousSize]) => {
|
||||
if (nextSize !== previousSize && nextPage !== 1) { page.value = 1; return }
|
||||
void load()
|
||||
})
|
||||
async function submit(action: 'draft' | 'submit' = 'submit') {
|
||||
if (isReturnRelabelSource.value) { await submitReturnRelabel(); return }
|
||||
const primaryWarehouse = props.service === 'relabel' ? form.sourceWarehouse : form.warehouse
|
||||
const relabelRows = labelingMode.value === 'carton' ? cartonDetailRows.value : skuRelabelRows.value
|
||||
const invalidCargo = props.service === 'disposal'
|
||||
? !selectedDiscardOrderId.value || cargoRows.value.every((item) => item.quantity < 1)
|
||||
|| cargoRows.value.some((item) => item.quantity < 0 || item.quantity > Number(item.availableQuantity || 0))
|
||||
: (props.service === 'labeling' || props.service === 'relabel') && (relabelRows.length === 0 || (props.service === 'labeling' && labelingMode.value !== 'carton'
|
||||
? skuRelabelRows.value.some((item) => !item.cartonMark || !item.originalSku || !item.newSku || item.quantity < 1
|
||||
? skuRelabelRows.value.some((item) => (!hideReturnSkuCartonMark.value && !item.cartonMark) || !item.originalSku || !item.newSku || item.quantity < 1
|
||||
|| (labelingMode.value === 'carton_and_sku' && !item.fbaCartonMark))
|
||||
: cargoRows.value.some((item) => (props.service !== 'labeling' && !item.sku) || !item.name
|
||||
|| (props.service !== 'labeling' && item.quantity < 1))))
|
||||
@@ -1019,7 +1019,7 @@ async function submit(action: 'draft' | 'submit' = 'submit') {
|
||||
if (props.service === 'labeling' && labelingMode.value === 'carton' && cartonDetailRows.value.some((item) => !item.shipmentNo || !item.cartonMark || !item.fbaCartonMark)) {
|
||||
ElMessage.warning('请上传关联面单,确保每箱的我方箱唛和 FBA 箱唛完整'); return
|
||||
}
|
||||
if (props.service === 'labeling' && labelingMode.value === 'carton' && cartonDetailRows.value.some((item) => !item.sourceInventoryPositionId)) {
|
||||
if (props.service === 'labeling' && labelingMode.value === 'carton' && cartonDetailRows.value.some((item) => !item.returnCartonId && !item.sourceInventoryPositionId)) {
|
||||
ElMessage.warning('请选择有库存的历史入仓单'); return
|
||||
}
|
||||
if (props.service === 'disposal' && !form.reason) {
|
||||
@@ -1399,34 +1399,17 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
const rows: CargoRow[] = []
|
||||
const selectedCandidates = relabelCandidates.value.filter((item) => {
|
||||
const returnOrderNo = item.inboundOrderNo || String(item.returnCartonId || '')
|
||||
return (item.sourceType === 'RETURN_CARTON' ? `RETURN_ORDER:${returnOrderNo}` : String(item.inboundOrderId)) === inboundOrderId
|
||||
return (item.returnCartonId ? `RETURN_ORDER:${returnOrderNo}` : String(item.inboundOrderId)) === inboundOrderId
|
||||
})
|
||||
returnRelabelSkuRows.value = []
|
||||
if (inboundOrderId.startsWith('RETURN_ORDER:')) {
|
||||
const grouped = new Map<string, ReturnRelabelSkuRow>()
|
||||
for (const candidate of selectedCandidates) {
|
||||
const skuItems = candidate.skuItems?.length
|
||||
? candidate.skuItems
|
||||
: candidate.skuCode ? [{ skuCode: candidate.skuCode, quantity: inventoryQuantity(candidate.availablePackages) }] : []
|
||||
for (const item of skuItems) {
|
||||
const skuCode = item.skuCode.trim()
|
||||
if (!skuCode) continue
|
||||
const key = skuCode.toUpperCase()
|
||||
const current = grouped.get(key)
|
||||
const quantity = inventoryQuantity(item.quantity)
|
||||
if (current) current.availableQuantity += quantity
|
||||
else grouped.set(key, {
|
||||
skuCode,
|
||||
productNameZh: candidate.skuCode?.trim().toUpperCase() === key ? (candidate.productNameZh || '') : '',
|
||||
availableQuantity: quantity,
|
||||
selected: false,
|
||||
// 可贴库存和本次申请数量是两个概念;重复换标时默认不应自动带入上次/首个箱子的数量。
|
||||
quantity: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
returnRelabelSkuRows.value = [...grouped.values()]
|
||||
labelingMode.value = 'sku'
|
||||
for (const candidate of selectedCandidates) rows.push({
|
||||
id: ++cargoSequence, sku: candidate.skuItems?.[0]?.skuCode || candidate.skuCode || '',
|
||||
name: candidate.productNameZh || '退货库存', included: false, quantity: 1, availableQuantity: 1,
|
||||
returnCartonId: String(candidate.returnCartonId), sourceInboundOrderNo: candidate.inboundOrderNo,
|
||||
fnsku: '', shipmentNo: candidate.inboundOrderNo || '', newSkuCode: '', shippingMark: '', customerCartonMarks: '',
|
||||
cartonMark: candidate.cartonMark || '', fbaCartonMark: '', destinationWarehouseId: '', remark: '',
|
||||
})
|
||||
} else for (const candidate of selectedCandidates) {
|
||||
for (const position of candidate.positions) rows.push(...Array.from({ length: Math.min(inventoryQuantity(position.availablePackages), 500) }, () => ({
|
||||
id: ++cargoSequence, sku: candidate.skuCode || '', name: candidate.productNameZh || '库存货物',
|
||||
@@ -1440,7 +1423,7 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
})))
|
||||
}
|
||||
cargoRows.value = rows.slice(0, 500)
|
||||
if (cargoRows.value.length) cargoRows.value[0].included = true
|
||||
if (cargoRows.value.length && !inboundOrderId.startsWith('RETURN_ORDER:')) cargoRows.value[0].included = true
|
||||
skuRelabelRows.value = []
|
||||
importedRelabelBindings.value = []
|
||||
shippingLabelFile.value = null
|
||||
@@ -1448,6 +1431,22 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
skuTotalFile.value = null
|
||||
if (!isReturnRelabelSource.value && labelingMode.value !== 'carton') addSkuRelabelRow()
|
||||
}
|
||||
function addReturnSkuBinding(source: RelabelInventoryCandidate, skuCode: string) {
|
||||
const sku = source.skuItems?.find(item => item.skuCode === skuCode)
|
||||
if (!sku) return
|
||||
const row = skuRelabelRows.value.find(item => item.cartonMark === source.cartonMark && item.originalSku === skuCode)
|
||||
if (row) return
|
||||
const sourceRow = cargoRows.value.find(item => item.returnCartonId === String(source.returnCartonId))
|
||||
skuRelabelRows.value.push({ id: ++skuRelabelSequence, sourceRowId: sourceRow?.id || null, cartonMark: source.cartonMark || '', originalSku: skuCode, newSku: '', quantity: Math.max(1, Number(sku.quantity)), fbaCartonMark: '', destinationWarehouseId: '', remark: '' })
|
||||
}
|
||||
function addReturnBoxBinding(source: RelabelInventoryCandidate) {
|
||||
if (labelingMode.value !== 'carton') {
|
||||
for (const sku of source.skuItems || []) addReturnSkuBinding(source, sku.skuCode)
|
||||
return
|
||||
}
|
||||
if (cartonDetailRows.value.some(item => item.cartonMark === source.cartonMark)) return
|
||||
cargoRows.value.push({ id: ++cargoSequence, included: true, sku: source.skuItems?.map(item => item.skuCode).join(',') || '', name: source.productNameZh || '退货箱', shipmentNo: selectedReturnOrderNo.value, cartonMark: source.cartonMark || '', fbaCartonMark: '', remark: '', sourceInventoryBalanceId: undefined, sourceInventoryPositionId: undefined, sourceInboundOrderId: undefined, returnCartonId: String(source.returnCartonId), quantity: 1, fnsku: '', newSkuCode: '', shippingMark: '', customerCartonMarks: '', destinationWarehouseId: '' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -1467,8 +1466,17 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
<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"><h3>{{ props.service === 'transfer' ? '转运信息' : props.service === 'relabel' ? '退货信息' : props.service === 'labeling' ? '订单信息' : '基础信息' }}</h3>
|
||||
<div class="warehouse-form-grid">
|
||||
<div 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>
|
||||
</div>
|
||||
<h3 v-else>{{ props.service === 'transfer' ? '转运信息' : props.service === 'relabel' ? '退货信息' : '基础信息' }}</h3>
|
||||
<div v-if="props.service === 'labeling' && orderInfoCollapsed" class="warehouse-order-info-summary">
|
||||
<span>{{ operationWarehouses.find(item => String(item.id) === form.warehouse)?.warehouseName || '未选择操作仓' }}</span>
|
||||
<span>{{ relabelInboundOptions.find(item => item.value === selectedRelabelInboundOrderId)?.inboundOrderNo || '未选择来源单据' }}</span>
|
||||
</div>
|
||||
<div v-show="props.service !== 'labeling' || !orderInfoCollapsed" class="warehouse-form-grid">
|
||||
<label v-if="props.service === 'disposal'" class="warehouse-disposal-field"><span><i>*</i>操作仓</span><el-select v-model="form.warehouse" filterable clearable :loading="fbaWarehousesLoading" :disabled="Boolean(operationWarehousesError)" placeholder="请选择海外仓" @change="selectDiscardWarehouse"><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><small v-else class="warehouse-hint">请先选择本次废弃货物所在的海外仓。</small></label>
|
||||
<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 discardCandidates" :key="candidate.orderId" :label="candidate.sourceType === 'RETURN_CARTON' ? `退货|${candidate.inboundOrderNo || '—'}|${candidate.cartonMark || '—'}|可用 ${candidate.availablePackages}` : `${candidate.inboundOrderNo || candidate.inboundCode || '—'}|${candidate.inboundCode || '—'}|可用 ${candidate.availablePackages} 箱`" :value="candidate.orderId" /></el-select><small class="warehouse-hint">显示当前操作仓内有可用数量的普通入库库存和退货库存。</small></label>
|
||||
<label v-if="props.service === 'relabel'"><span><i>*</i>进仓编号</span><el-input v-model="form.inboundNo" placeholder="请输入已有入仓编号" /></label>
|
||||
@@ -1520,7 +1528,7 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
<div class="warehouse-section-heading warehouse-labeling-heading">
|
||||
<div><h3>货物明细</h3></div>
|
||||
</div>
|
||||
<div class="warehouse-file-groups" :class="{ 'warehouse-file-groups--single': isReturnRelabelSource }">
|
||||
<div class="warehouse-file-groups warehouse-file-groups--compact">
|
||||
<section v-if="canManageRelabelFiles" class="warehouse-file-group warehouse-file-group--primary">
|
||||
<div class="warehouse-file-group__heading"><div><strong><span>1</span>贴标总文件</strong></div><em>{{ requiresBothTotalFiles ? '必传 · 两份文件' : '必传 · 二选一' }}</em></div>
|
||||
<div class="warehouse-file-options">
|
||||
@@ -1529,7 +1537,7 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
<div class="warehouse-file-option" :class="{ 'is-selected': Boolean(skuTotalFile) }"><div class="warehouse-file-option__name"><strong>SKU 总文件</strong></div><el-button native-type="button" :type="skuTotalFile ? 'primary' : 'default'" plain @click="chooseCreateTotalFile('SKU_TOTAL')"><Upload :size="15" />{{ skuTotalFile ? '重新上传' : '选择文件' }}</el-button><div class="warehouse-file-option__status" :class="{ 'is-empty': !skuTotalFile }"><span>{{ skuTotalFile?.name || '尚未选择文件' }}</span><button v-if="skuTotalFile" type="button" class="warehouse-file-clear" title="清除 SKU 总文件" aria-label="清除 SKU 总文件" :disabled="saving" @click="clearCreateTotalFile('SKU_TOTAL')"><X :size="14" /></button></div></div>
|
||||
</div>
|
||||
</section>
|
||||
<section v-if="!isReturnRelabelSource" class="warehouse-file-group">
|
||||
<section class="warehouse-file-group">
|
||||
<div class="warehouse-file-group__heading"><div><strong><span>2</span>明细关联模板</strong></div><em>按需使用</em></div>
|
||||
<div class="warehouse-template-list">
|
||||
<div><span><strong>SKU 关联</strong></span><el-button size="small" :disabled="!cargoRows.length" @click="downloadRelabelTemplate('sku')"><Download :size="15" />下载模板</el-button><el-button type="primary" plain size="small" :disabled="!cargoRows.length" @click="skuTemplateInput?.click()"><Upload :size="15" />上传文件</el-button></div>
|
||||
@@ -1540,30 +1548,34 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
</div>
|
||||
<input ref="skuTemplateInput" class="warehouse-hidden-input" type="file" accept=".csv,text/csv" @change="importRelabelTemplate($event, 'sku')"><input ref="cartonTemplateInput" class="warehouse-hidden-input" type="file" accept=".csv,text/csv" @change="importRelabelTemplate($event, 'carton')"><input ref="mixedTemplateInput" class="warehouse-hidden-input" type="file" accept=".csv,text/csv" @change="importRelabelTemplate($event, 'mixed')"><input ref="cartonTotalCreateInput" class="warehouse-hidden-input" type="file" accept="application/pdf,.pdf" @change="selectCartonTotalFile"><input ref="skuTotalCreateInput" class="warehouse-hidden-input" type="file" accept="application/pdf,.pdf" @change="selectSkuTotalFile">
|
||||
<div v-if="isReturnRelabelSource" class="warehouse-table-scroll">
|
||||
<table class="warehouse-edit-table warehouse-return-relabel-table">
|
||||
<thead><tr><th>选择</th><th>SKU</th><th>中文品名</th><th>库存总数</th><th>本次贴标数量</th></tr></thead>
|
||||
<tbody><tr v-for="row in returnRelabelSkuRows" :key="row.skuCode"><td><el-checkbox :model-value="row.selected" @change="row.selected = Boolean($event)" /></td><td><strong>{{ row.skuCode }}</strong></td><td>{{ row.productNameZh || '—' }}</td><td><strong>{{ row.availableQuantity }}</strong></td><td><el-input-number v-model="row.quantity" :disabled="!row.selected" :min="1" :max="row.availableQuantity" :precision="0" controls-position="right" placeholder="请输入贴标数量" /></td></tr><tr v-if="returnRelabelSkuRows.length === 0"><td colspan="5"><div class="warehouse-empty">该退货单暂无可申请贴标的 SKU 库存</div></td></tr></tbody>
|
||||
</table>
|
||||
<template v-if="returnLooseCandidates.length">
|
||||
<h3>可用散件 SKU</h3>
|
||||
<table class="warehouse-edit-table"><thead><tr><th>SKU</th><th>可用数量(件)</th><th>操作</th></tr></thead><tbody><template v-for="source in returnLooseCandidates" :key="source.returnCartonId"><tr v-for="sku in source.skuItems" :key="sku.skuCode"><td>{{ sku.skuCode }}</td><td>{{ sku.quantity }}</td><td><el-button size="small" :disabled="labelingMode !== 'sku'" @click="addReturnSkuBinding(source, sku.skuCode)">添加贴标</el-button></td></tr></template><tr v-if="!returnLooseCandidates.length"><td colspan="3">暂无可用散件库存</td></tr></tbody></table>
|
||||
</template>
|
||||
<template v-if="returnBoxCandidates.length">
|
||||
<h3>可用箱子</h3>
|
||||
<table class="warehouse-edit-table"><thead><tr><th>系统箱唛号</th><th>箱内 SKU</th><th>可用数量(件)</th><th>操作</th></tr></thead><tbody><tr v-for="source in returnBoxCandidates" :key="source.returnCartonId"><td><strong>{{ source.cartonMark }}</strong></td><td><div v-for="sku in source.skuItems" :key="sku.skuCode">{{ sku.skuCode }}</div></td><td><div v-for="sku in source.skuItems" :key="sku.skuCode">{{ sku.quantity }}</div></td><td><el-button size="small" @click="addReturnBoxBinding(source)">添加贴标</el-button></td></tr><tr v-if="!returnBoxCandidates.length"><td colspan="4">暂无可用箱子库存</td></tr></tbody></table>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="!isReturnRelabelSource" class="warehouse-labeling-mode">
|
||||
<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="carton" :disabled="returnSkuOnly">只换箱唛</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-button value="carton_and_sku" :disabled="returnSkuOnly">SKU 和箱唛都换</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div v-if="!isReturnRelabelSource && importedRelabelBindings.length" class="warehouse-import-preview">
|
||||
<div v-if="importedRelabelBindings.length" class="warehouse-import-preview">
|
||||
<div class="warehouse-section-heading"><div><strong>待导入绑定关系</strong><p>可只勾选本次需要换标的部分,也可以全选后一次导入。</p></div><div><el-checkbox :model-value="importedRelabelBindings.every((item) => item.selected)" @change="selectAllImportedBindings(Boolean($event))">全选</el-checkbox><el-button type="primary" size="small" @click="importSelectedBindingsToDetails">导入到明细</el-button></div></div>
|
||||
<div class="warehouse-table-scroll"><table class="warehouse-binding-preview-table"><thead><tr><th>选择</th><th>关系类型</th><th>仓库唛头</th><th>旧 SKU</th><th>新 SKU</th><th>数量</th><th>新 FBA 箱唛</th></tr></thead><tbody><tr v-for="item in importedRelabelBindings" :key="item.id"><td><el-checkbox v-model="item.selected" /></td><td>{{ item.templateType === 'mixed' ? 'SKU 混箱换标' : item.templateType === 'carton' ? '箱号关联' : 'SKU 关联' }}</td><td>{{ item.cartonMark }}</td><td>{{ item.originalSku || '—' }}</td><td>{{ item.newSku || '—' }}</td><td>{{ item.quantity }}</td><td>{{ item.fbaCartonMark || '—' }}</td></tr></tbody></table></div>
|
||||
</div>
|
||||
<div v-if="!isReturnRelabelSource" class="warehouse-section-heading warehouse-tab-actions">
|
||||
<div class="warehouse-section-heading warehouse-tab-actions">
|
||||
<div><strong>绑定明细</strong></div>
|
||||
<div v-if="labelingMode === 'carton'"><el-button type="primary" size="small" @click="addRelabelCargoRow"><Plus :size="15" />手动添加行</el-button><el-button size="small" @click="clearRelabelRows">清空</el-button></div>
|
||||
<div v-else><el-button type="primary" size="small" @click="addSkuRelabelRow"><Plus :size="15" />添加 SKU 明细</el-button><el-button size="small" @click="skuRelabelRows = []">清空</el-button></div>
|
||||
</div>
|
||||
<div v-if="!isReturnRelabelSource && labelingMode === 'carton'" class="warehouse-table-scroll"><table class="warehouse-edit-table warehouse-label-table"><thead><tr><th>商品 SKU</th><th>中文品名 *</th><th>FBA 货件编号 *</th><th>箱数</th><th>仓库唛头 *</th><th>新 FBA 箱唛 *</th><th>备注</th><th>操作</th></tr></thead><tbody><tr v-for="row in cartonDetailRows" :key="row.id"><td><el-input v-model="row.sku" placeholder="选填" /></td><td><el-input v-model="row.name" placeholder="请输入中文品名" /></td><td><el-input v-model="row.shipmentNo" placeholder="请输入FBA货件编号" /></td><td><strong>1 箱</strong></td><td><el-input v-model="row.cartonMark" placeholder="请输入仓库唛头" /></td><td><el-input v-model="row.fbaCartonMark" placeholder="请输入新的 FBA 箱唛" /></td><td><el-input v-model="row.remark" type="textarea" :rows="2" maxlength="1000" show-word-limit placeholder="请输入明细备注" /></td><td><button type="button" class="warehouse-delete" title="移出本次明细" @click="removeCargoRow(row.id)"><Trash2 :size="16" />移出</button></td></tr><tr v-if="cartonDetailRows.length === 0"><td colspan="8"><div class="warehouse-empty">暂无本次换标明细,请上传关系后导入或手动添加</div></td></tr></tbody></table></div>
|
||||
<div v-else class="warehouse-table-scroll"><table class="warehouse-edit-table warehouse-sku-label-table"><thead><tr><th>仓库唛头 *</th><th>旧 SKU *</th><th>新 SKU *</th><th>换标数量(件)*</th><th v-if="labelingMode === 'carton_and_sku'">新 FBA 箱唛 *</th><th>备注</th><th>操作</th></tr></thead><tbody><tr v-for="row in skuRelabelRows" :key="row.id"><td><el-input v-model="row.cartonMark" placeholder="请输入仓库唛头" @change="applyExistingCartonBinding(row)" /></td><td><el-input v-model="row.originalSku" placeholder="请输入旧 SKU" @change="applyExistingSkuBinding(row)" /></td><td><el-input v-model="row.newSku" placeholder="请输入新 SKU" /></td><td><el-input-number v-model="row.quantity" :min="1" :precision="0" controls-position="right" placeholder="请输入件数" /></td><td v-if="labelingMode === 'carton_and_sku'"><el-input v-model="row.fbaCartonMark" placeholder="请输入新的 FBA 箱唛" /></td><td><el-input v-model="row.remark" placeholder="请输入备注" /></td><td><button type="button" class="warehouse-delete" title="删除" @click="removeSkuRelabelRow(row.id)"><Trash2 :size="16" />删除</button></td></tr><tr v-if="skuRelabelRows.length === 0"><td :colspan="labelingMode === 'carton_and_sku' ? 7 : 6"><div class="warehouse-empty">暂无绑定明细,请点击“添加 SKU 明细”</div></td></tr></tbody></table></div>
|
||||
<div v-if="labelingMode === 'carton'" class="warehouse-table-scroll"><table class="warehouse-edit-table warehouse-label-table"><thead><tr><th>商品 SKU</th><th>中文品名 *</th><th>FBA 货件编号 *</th><th>箱数</th><th>仓库唛头 *</th><th>新 FBA 箱唛 *</th><th>备注</th><th>操作</th></tr></thead><tbody><tr v-for="row in cartonDetailRows" :key="row.id"><td><el-input v-model="row.sku" placeholder="选填" /></td><td><el-input v-model="row.name" placeholder="请输入中文品名" /></td><td><el-input v-model="row.shipmentNo" placeholder="请输入FBA货件编号" /></td><td><strong>1 箱</strong></td><td><el-input v-model="row.cartonMark" placeholder="请输入仓库唛头" /></td><td><el-input v-model="row.fbaCartonMark" placeholder="请输入新的 FBA 箱唛" /></td><td><el-input v-model="row.remark" type="textarea" :rows="2" maxlength="1000" show-word-limit placeholder="请输入明细备注" /></td><td><button type="button" class="warehouse-delete" title="移出本次明细" @click="removeCargoRow(row.id)"><Trash2 :size="16" />移出</button></td></tr><tr v-if="cartonDetailRows.length === 0"><td colspan="8"><div class="warehouse-empty">暂无本次换标明细,请上传关系后导入或手动添加</div></td></tr></tbody></table></div>
|
||||
<div v-else class="warehouse-table-scroll"><table class="warehouse-edit-table warehouse-sku-label-table"><thead><tr><th v-if="!hideReturnSkuCartonMark">仓库唛头 *</th><th>旧 SKU *</th><th>新 SKU *</th><th>换标数量(件)*</th><th v-if="labelingMode === 'carton_and_sku'">新 FBA 箱唛 *</th><th>备注</th><th>操作</th></tr></thead><tbody><tr v-for="row in skuRelabelRows" :key="row.id"><td v-if="!hideReturnSkuCartonMark"><el-input v-model="row.cartonMark" placeholder="请输入仓库唛头" @change="applyExistingCartonBinding(row)" /></td><td><el-input v-model="row.originalSku" placeholder="请输入旧 SKU" @change="applyExistingSkuBinding(row)" /></td><td><el-input v-model="row.newSku" placeholder="请输入新 SKU" /></td><td><el-input-number v-model="row.quantity" :min="1" :precision="0" controls-position="right" placeholder="请输入件数" /></td><td v-if="labelingMode === 'carton_and_sku'"><el-input v-model="row.fbaCartonMark" placeholder="请输入新的 FBA 箱唛" /></td><td><el-input v-model="row.remark" placeholder="请输入备注" /></td><td><button type="button" class="warehouse-delete" title="删除" @click="removeSkuRelabelRow(row.id)"><Trash2 :size="16" />删除</button></td></tr><tr v-if="skuRelabelRows.length === 0"><td :colspan="hideReturnSkuCartonMark ? 5 : labelingMode === 'carton_and_sku' ? 7 : 6"><div class="warehouse-empty">暂无绑定明细,请点击“添加 SKU 明细”</div></td></tr></tbody></table></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="warehouse-section-heading" :class="{ 'warehouse-step-heading': props.service === 'transfer' }"><div><h3><span v-if="props.service === 'transfer'" class="warehouse-step-number">1</span>货物明细</h3></div><div v-if="props.service !== 'disposal'" class="warehouse-heading-actions"><el-button v-if="props.service === 'transfer'" size="small" :disabled="!cargoRows.some((row) => row.sku.trim() && row.quantity > 0)" @click="printTransferDraftCartonMarks"><Printer :size="15" />打印唛头</el-button><el-button type="primary" size="small" @click="addCargoRow"><Plus :size="15" />添加行</el-button><el-button size="small" @click="cargoRows = []">清空</el-button></div></div>
|
||||
@@ -1574,7 +1586,7 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
<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="TRUCK_PICKUP" /><el-option label="快递自提" value="EXPRESS_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><small class="warehouse-hint">本票所有换标货物统一前往该目的仓,暂不支持一票多个目的仓。</small></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>
|
||||
<div class="warehouse-transfer-file-groups">
|
||||
<div class="warehouse-transfer-file-groups warehouse-file-groups--compact">
|
||||
<section v-if="canManageRelabelFiles" class="warehouse-file-group warehouse-transfer-total-files">
|
||||
<div class="warehouse-file-group__heading"><div><strong>贴标总文件</strong></div><em>{{ requiresBothTotalFiles ? '必传 · 两份文件' : '必传 · 二选一' }}</em></div>
|
||||
<div class="warehouse-file-options">
|
||||
@@ -1652,6 +1664,65 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.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; }
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-labeling-mode {
|
||||
width: fit-content;
|
||||
max-width: 1296px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #f8fafc;
|
||||
padding: 8px 12px;
|
||||
gap: 14px;
|
||||
margin: 20px 0 22px;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-labeling-mode > span {
|
||||
color: #475569;
|
||||
font-size: 12px;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-table-scroll th {
|
||||
background: #f0f5fc;
|
||||
color: #385579;
|
||||
border-bottom: 1px solid #dce6f2;
|
||||
height: 38px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-labeling-mode :deep(.el-radio-button) {
|
||||
--el-color-primary: #2563eb;
|
||||
--el-radio-button-checked-bg-color: #2563eb;
|
||||
--el-radio-button-checked-border-color: #2563eb;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-labeling-mode :deep(.el-radio-button:not(.is-disabled) .el-radio-button__inner) {
|
||||
border-color: #cbdaf0;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-labeling-mode :deep(.el-radio-group) { gap: 6px; }
|
||||
.warehouse-service-page--return-relabel .warehouse-labeling-mode :deep(.el-radio-button .el-radio-button__inner) {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #dce3ec;
|
||||
border-radius: 5px;
|
||||
box-shadow: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-labeling-mode :deep(.el-radio-button.is-disabled .el-radio-button__inner) {
|
||||
color: #a3adbb;
|
||||
background: #f1f4f8;
|
||||
border-color: #e5eaf0;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-table-scroll td { padding: 10px 12px; }
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-table-scroll h3 {
|
||||
font-size: 14px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-sku-label-table :deep(.el-input__wrapper) {
|
||||
min-height: 30px;
|
||||
box-shadow: 0 0 0 1px #dce3ec inset;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-sku-label-table :deep(.el-input-number) { width: 120px; }
|
||||
.warehouse-service-page--return-relabel .warehouse-transfer-cargo-card .warehouse-tab-actions { margin-bottom: 10px; }
|
||||
.warehouse-service-page{display:grid;gap:12px;color:#25324a}.warehouse-breadcrumb{display:flex;align-items:center;gap:9px;margin:0 0 14px;color:#9aa3b2;font-size:12px}.warehouse-breadcrumb b{font-weight:400}.warehouse-breadcrumb strong{color:#606b7c}.warehouse-breadcrumb button{padding:0;border:0;background:transparent;color:#4376b8;cursor:pointer}.warehouse-page-heading{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}.warehouse-page-heading h2{margin:0;color:#17233a;font-size:22px;letter-spacing:0}.warehouse-card{margin-bottom:0;border:1px solid var(--client-border);border-radius:var(--client-radius);background:#fff;box-shadow:none}.warehouse-filter-card{padding:20px 22px 16px}.warehouse-filter-grid{display:grid;grid-template-columns:repeat(4,minmax(180px,1fr));gap:16px 20px}.warehouse-filter-grid label,.warehouse-form-grid label{display:flex;min-width:0;flex-direction:column;gap:7px}.warehouse-filter-grid label>span,.warehouse-form-grid label>span{color:#596579;font-size:12px}.warehouse-filter-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:18px}.warehouse-table-card{overflow:hidden}.warehouse-list-notice{padding:8px 12px;border-bottom:1px solid var(--client-border);background:#fff8e8;color:#8a6116;font-size:12px}.warehouse-table-scroll{overflow-x:auto}table{width:100%;min-width:940px;border-collapse:collapse;font-size:12px}th{height:44px;padding:0 14px;border-bottom:1px solid #e8edf3;background:#f7f9fc;color:#4d5a6e;font-weight:650;text-align:left;white-space:nowrap}td{height:48px;padding:8px 14px;border-bottom:1px solid #eef1f5;color:#526176;white-space:nowrap}.warehouse-empty{display:grid;height:72px;color:#a0a9b7;place-items:center}.warehouse-link,.warehouse-delete{display:inline-flex;align-items:center;gap:5px;padding:4px;border:0;background:transparent;color:#2176d2;cursor:pointer}.warehouse-delete{color:#d64545}.warehouse-pagination{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:14px 18px;color:#778398;font-size:12px}.warehouse-pagination span{margin-right:8px}.warehouse-page-number{width:28px;height:28px;border:1px solid #2176d2;border-radius:3px;background:#2176d2;color:#fff}.warehouse-form-section{padding:22px}.warehouse-form-section h3{margin:0 0 18px;padding-bottom:12px;border-bottom:1px solid #edf0f4;color:#26364f;font-size:15px;letter-spacing:0}.warehouse-form-grid{display:grid;grid-template-columns:repeat(2,minmax(240px,1fr));gap:18px 28px}.warehouse-form-grid i{margin-right:3px;color:#e24b4b;font-style:normal}.warehouse-span-2{grid-column:1/-1}.warehouse-section-heading{display:flex;align-items:center;justify-content:space-between}.warehouse-section-heading h3{flex:1}.warehouse-edit-table td{padding:9px 10px}.warehouse-edit-table :deep(.el-input-number){width:130px}.warehouse-hint{margin:12px 0 0;color:#8792a2;font-size:12px}.warehouse-submit-bar{display:flex;justify-content:center;gap:10px;padding:12px 0 30px}.warehouse-detail-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}.warehouse-detail-grid div{display:flex;flex-direction:column;gap:7px}.warehouse-detail-grid span{color:#8a95a5;font-size:12px}.warehouse-detail-grid strong{color:#334157;font-size:13px}:deep(.el-button){border-radius:4px}:deep(.el-button span){display:inline-flex;align-items:center;gap:6px}:deep(.el-select),:deep(.el-date-editor.el-input){width:100%}@media(max-width:1100px){.warehouse-filter-grid{grid-template-columns:repeat(2,1fr)}.warehouse-detail-grid{grid-template-columns:repeat(2,1fr)}}
|
||||
.warehouse-service-page--detail{display:block;overflow:hidden;border:1px solid var(--client-border);border-radius:var(--client-radius);background:#fff}.warehouse-detail-header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:14px;min-height:64px;padding:10px 16px;border-bottom:1px solid var(--client-border)}.warehouse-detail-back{display:inline-flex;align-items:center;gap:5px;padding:5px 0;border:0;background:transparent;color:var(--el-color-primary);cursor:pointer}.warehouse-detail-title{display:flex;min-width:0;flex-direction:column;gap:3px}.warehouse-detail-title strong{overflow:hidden;color:#1f2d45;font-size:18px;text-overflow:ellipsis;white-space:nowrap}.warehouse-detail-title span{color:#7c899c;font-size:12px}.warehouse-detail-actions{display:flex;align-items:center;gap:8px}.warehouse-service-page--detail>.warehouse-card{border:0;border-top:1px solid var(--client-border);border-radius:0}.warehouse-service-page--detail>.warehouse-detail-header+.warehouse-card{border-top:0}.warehouse-service-page--detail>.warehouse-form-section{padding:0}.warehouse-service-page--detail .warehouse-form-section h3{min-height:40px;margin:0;padding:11px 16px 9px;border-bottom:1px solid #edf1f5;font-size:14px}.warehouse-service-page--detail .warehouse-detail-grid{grid-template-columns:repeat(4,minmax(0,1fr));gap:0;margin:0}.warehouse-service-page--detail .warehouse-detail-grid>div{min-height:48px;flex-direction:row;align-items:center;gap:10px;padding:8px 14px;border-right:1px solid #edf1f5;border-bottom:1px solid #edf1f5}.warehouse-service-page--detail .warehouse-detail-grid span{flex:0 0 90px}.warehouse-service-page--detail .warehouse-detail-grid strong{min-width:0;overflow-wrap:anywhere}.warehouse-service-page--detail .warehouse-fulfillment-grid{margin-bottom:0}.warehouse-service-page--detail .warehouse-evidence{margin:12px 14px}.warehouse-service-page--detail .warehouse-completion-remark,.warehouse-service-page--detail .warehouse-hint{margin:10px 14px}.warehouse-service-page--detail .warehouse-table-scroll table{margin:0}.warehouse-service-page--detail .warehouse-empty{height:64px}@media(max-width:1100px){.warehouse-service-page--detail .warehouse-detail-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(max-width:720px){.warehouse-detail-header{grid-template-columns:1fr auto}.warehouse-detail-back{grid-column:1/-1}.warehouse-detail-actions{justify-content:flex-end}}
|
||||
.warehouse-detail-error{display:flex;min-height:220px;align-items:center;justify-content:center;gap:12px;color:#b42318}
|
||||
@@ -1667,7 +1738,42 @@ function selectRelabelInventory(inboundOrderId: string) {
|
||||
.warehouse-unmaintained{margin-left:8px;color:#e6a23c;font-size:12px;font-style:normal}
|
||||
.warehouse-labeling-tabs{margin-top:-8px}.warehouse-labeling-heading{align-items:flex-start}.warehouse-labeling-heading h3{margin-bottom:16px}.warehouse-template-actions{display:flex;gap:8px;padding-bottom:12px}.warehouse-tab-actions{align-items:center;margin:2px 0 14px}.warehouse-tab-actions p{margin:0;color:#7d8797;font-size:12px}.warehouse-tab-actions>div{display:flex;gap:8px}.warehouse-sku-notice{margin:0 0 14px;padding:10px 12px;border:1px solid #f2d39b;border-radius:4px;background:#fff8e8;color:#8a6116;font-size:12px}.warehouse-sku-label-table{min-width:980px}.warehouse-sku-label-table :deep(.el-input-number){width:160px}:deep(.warehouse-labeling-tabs>.el-tabs__header){margin-bottom:18px}:deep(.warehouse-labeling-tabs .el-tabs__item){height:42px;padding:0 26px;font-weight:600}.warehouse-labeling-mode{display:flex;align-items:center;gap:14px;margin:0 0 16px;padding:14px 16px;border:1px solid #dce5f5;border-radius:5px;background:#f7f9ff}.warehouse-labeling-mode>span{color:#34445c;font-size:13px;font-weight:650;white-space:nowrap}.warehouse-labeling-mode p{margin:0;color:#71809a;font-size:12px}.warehouse-labeling-mode :deep(.el-radio-group){display:flex;flex-shrink:0}.warehouse-labeling-mode :deep(.el-radio-button__inner){padding:8px 14px}
|
||||
.warehouse-relabel-detail-table{min-width:1420px}.warehouse-relabel-detail-table td strong{color:#253f67}
|
||||
.warehouse-service-page--return-relabel .warehouse-table-scroll:has(> .warehouse-return-relabel-table)~.warehouse-table-scroll{display:none}
|
||||
.warehouse-file-groups--compact {
|
||||
width: 100%;
|
||||
max-width: 1296px;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: 16px;
|
||||
align-items: stretch;
|
||||
}
|
||||
.warehouse-file-groups--compact .warehouse-file-group__heading {
|
||||
padding: 10px 12px;
|
||||
align-items: center;
|
||||
}
|
||||
.warehouse-file-groups--compact .warehouse-file-options {
|
||||
padding: 10px;
|
||||
grid-template-columns: minmax(0, 1fr) 20px minmax(0, 1fr);
|
||||
}
|
||||
.warehouse-file-groups--compact .warehouse-file-option {
|
||||
padding: 8px;
|
||||
gap: 8px;
|
||||
}
|
||||
.warehouse-file-groups--compact .warehouse-file-option__name strong { font-size: 12px; }
|
||||
.warehouse-file-groups--compact .warehouse-file-option :deep(.el-button) {
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.warehouse-file-groups--compact .warehouse-template-list { padding: 4px 12px; }
|
||||
.warehouse-file-groups--compact .warehouse-template-list > div {
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
padding: 7px 0;
|
||||
}
|
||||
@media (max-width: 1180px) {
|
||||
.warehouse-file-groups--compact { grid-template-columns: minmax(0, 1fr); }
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.warehouse-file-groups--compact .warehouse-file-options { grid-template-columns: minmax(0, 1fr); }
|
||||
.warehouse-file-groups--compact .warehouse-template-list > div { grid-template-columns: minmax(0, 1fr) auto; }
|
||||
}
|
||||
.warehouse-native-file{min-height:32px;padding:5px 8px;border:1px solid #dcdfe6;border-radius:4px;background:#fff;color:#606266}.warehouse-fulfillment-grid{margin-bottom:18px}.warehouse-evidence{display:flex;align-items:flex-start;gap:16px;padding:14px;border:1px solid #e7ebf1;border-radius:4px;background:#f8fafc}.warehouse-evidence>span{padding-top:6px;color:#71809a;font-size:12px;white-space:nowrap}.warehouse-evidence>strong{padding-top:6px;color:#8a95a5;font-size:12px;font-weight:400}.warehouse-photo-grid{display:grid;grid-template-columns:repeat(4,140px);gap:12px}.warehouse-photo-item{width:140px;height:105px;overflow:hidden;border:1px solid #dce3ed;border-radius:5px;background:#fff}.warehouse-photo-item :deep(.el-image){display:block;width:100%;height:100%;cursor:zoom-in}.warehouse-photo-placeholder{display:flex;width:100%;height:100%;align-items:center;justify-content:center;padding:10px;border:0;background:#f4f7fb;color:#8792a2;font-size:12px;text-align:center}.warehouse-photo-retry{cursor:pointer}.warehouse-completion-remark{margin:10px 0 0;color:#596579;font-size:12px}
|
||||
.warehouse-measurement-evidence{margin-top:16px}
|
||||
.warehouse-measurement-photo-grid{flex:1;grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}
|
||||
|
||||
Reference in New Issue
Block a user