@@ -6,7 +6,9 @@ import { MapPin, Plus, Send, Trash2 } from '@lucide/vue'
import { useAuthStore } from '@/modules/auth/store/auth'
import {
getMerchantInboundCodePolicy ,
getMerchantOrderAddresses ,
getMerchantPricingChannels ,
type CustomerOrderAddress ,
type InboundCodePolicy ,
type MerchantPricingChannel ,
} from '@/modules/first-leg/api/firstLeg'
@@ -32,6 +34,7 @@ interface QuickOrderRow {
destinationWarehouseName : string
destinationCountryCode : string
amazonWarehouseCode : string
privateDestinationAddressId : string
consigneeContactName : string
consigneePhone : string
consigneeCity : string
@@ -64,6 +67,8 @@ const inboundCodePolicy = ref<InboundCodePolicy | null>(null)
const channelOptions = ref < QuickChannelOption [ ] > ( [ ] )
const destinationDialogOpen = ref ( false )
const destinationLoading = ref ( false )
const privateAddresses = ref < CustomerOrderAddress [ ] > ( [ ] )
const privateAddressesError = ref ( '' )
const editingDestinationRow = ref < QuickOrderRow > ( )
const draftResults = reactive < QuickDraftResult [ ] > ( [ ] )
const resultDialogOpen = ref ( false )
@@ -71,13 +76,7 @@ const activeBatchKey = ref('')
const destinationForm = reactive ( {
type : 'FBA' as DestinationType ,
warehouseId : '' ,
privateName : '' ,
countryCode : 'US' ,
contactName : '' ,
phone : '' ,
city : '' ,
address : '' ,
postalCode : '' ,
privateAddressId : '' ,
} )
let rowSequence = 0
let productSequence = 0
@@ -101,6 +100,7 @@ function createRow(): QuickOrderRow {
destinationWarehouseName : '' ,
destinationCountryCode : '' ,
amazonWarehouseCode : '' ,
privateDestinationAddressId : '' ,
consigneeContactName : '' ,
consigneePhone : '' ,
consigneeCity : '' ,
@@ -149,6 +149,10 @@ function selectedChannel(row: QuickOrderRow) {
return channelOptions . value . find ( ( channel ) => channelKey ( channel . warehouseId , channel . channelCode ) === row . channelKey )
}
function addressLabel ( address : CustomerOrderAddress ) {
return ` ${ address . addressName } · ${ address . contactName } · ${ address . countryCode } ${ address . city } ${ address . addressLine } `
}
function createConsigneeSnapshot ( row : QuickOrderRow ) {
return {
id : '' ,
@@ -187,7 +191,7 @@ function buildOrderDraft(row: QuickOrderRow, channel: QuickChannelOption): First
shipperPartySnapshot : null ,
shipper : '' ,
consigneePartyId : '' ,
privateDestinationAddressId : '' ,
privateDestinationAddressId : row . destinationType === 'PRIVATE' ? row . privateDestinationAddressId : '' ,
consigneePartySnapshot : row . destinationType === 'PRIVATE' && hasCompletePrivateContact ( row )
? createConsigneeSnapshot ( row ) : null ,
consignee : row . destinationType === 'PRIVATE' && hasCompletePrivateContact ( row )
@@ -231,21 +235,24 @@ async function openDestinationDialog(row: QuickOrderRow, typeValue: string | num
Object . assign ( destinationForm , {
type ,
warehouseId : row . destinationType === type ? row . destinationWarehouseId : '' ,
privateName : row . destinationType === type ? row . destinationWarehouseName : '' ,
countryCode : row . destinationType === type ? row . destinationCountryCode || 'US' : 'US' ,
contactName : row . destinationType === type ? row . consigneeContactName : '' ,
phone : row . destinationType === type ? row . consigneePhone : '' ,
city : row . destinationType === type ? row . consigneeCity : '' ,
address : row . destinationType === type ? row . consigneeAddress : '' ,
postalCode : row . destinationType === type ? row . consigneePostalCode : '' ,
privateAddressId : row . destinationType === type ? row . privateDestinationAddressId : '' ,
} )
destinationDialogOpen . value = true
if ( type === 'PRIVATE' ) return
destinationLoading . value = true
try {
await store . loadWarehouseType ( type )
if ( type === 'PRIVATE' ) {
privateAddressesError . value = ''
privateAddresses . value = await getMerchantOrderAddresses ( 'PRIVATE_DESTINATION' )
} else {
await store . loadWarehouseType ( type )
}
} catch ( error ) {
ElMessage . error ( error instanceof Error ? error . message : '目的仓加载失败,请稍后重试' )
const message = error instanceof Error ? error . message : '目的仓加载失败,请稍后重试'
if ( type === 'PRIVATE' ) {
privateAddresses . value = [ ]
privateAddressesError . value = message
}
ElMessage . error ( message )
} finally {
destinationLoading . value = false
}
@@ -266,6 +273,7 @@ function bindDestination() {
destinationWarehouseName : warehouse . name ,
destinationCountryCode : warehouse . countryCode ,
amazonWarehouseCode : destinationForm . type === 'FBA' ? warehouse . code : '' ,
privateDestinationAddressId : '' ,
consigneeContactName : '' ,
consigneePhone : '' ,
consigneeCity : '' ,
@@ -273,26 +281,23 @@ function bindDestination() {
consigneePostalCode : '' ,
} )
} else {
const required = [ destinationForm . privateName , destinationForm . countryCode ]
if ( required . some ( ( value ) => ! value . trim ( ) ) ) {
ElMessage . warning ( '请填写私人仓名称和目的国家 ' )
return
}
if ( ! /^[A-Za-z]{2}$/ . test ( destinationForm . countryCode . trim ( ) ) ) {
ElMessage . warning ( '目的国家请输入两位英文代码,例如 US' )
const address = privateAddresses . value . find ( ( item ) => String ( item . id ) === destinationForm . privateAddressId )
if ( ! address ) {
ElMessage . warning ( '请选择企业已保存的私人仓地址 ' )
return
}
Object . assign ( row , {
destinationType : 'PRIVATE' ,
destinationWarehouseId : '' ,
destinationWarehouseName : destinationForm . privateName . trim ( ) ,
destinationCountryCode : destinationForm . countryCode . trim ( ) . toUpperCase ( ) ,
destinationWarehouseName : address . addressName ,
destinationCountryCode : address . countryCode ,
amazonWarehouseCode : '' ,
consigneeContactName : destinationForm . contactName . trim ( ) ,
consigneePhone : destinationForm . phone . trim ( ) ,
consigneeCity : destinationForm . city . trim ( ) ,
consigneeAddress : destinationForm . address . trim ( ) ,
consigneePostalCode : destinationForm . postalCode . trim ( ) ,
privateDestinationAddressId : String ( address . id ) ,
consigneeContactName : address . contactName ,
consigneePhone : address . phone ,
consigneeCity : address . city ,
consigneeAddress : address . addressLine ,
consigneePostalCode : address . postalCode ? ? '' ,
} )
}
destinationDialogOpen . value = false
@@ -347,6 +352,7 @@ async function submitQuickOrder() {
return
}
const incompleteIndex = rows . findIndex ( ( row ) => ! row . channelKey || ! row . destinationWarehouseName
|| ( row . destinationType === 'PRIVATE' && ! row . privateDestinationAddressId )
|| row . products . some ( ( product ) => ! product . sku . trim ( ) || product . packageCount < 1 ) )
if ( incompleteIndex >= 0 ) {
ElMessage . warning ( ` 请完善第 ${ incompleteIndex + 1 } 行的渠道、目的仓、产品 SKU 和箱数 ` )
@@ -513,15 +519,13 @@ onMounted(loadChannels)
< small v-if = "!destinationLoading && availableDestinationWarehouses.length === 0" > 平台暂未维护可用目的仓 , 请联系平台管理员 。 < / small >
< / el -form -item >
< template v-else >
< el -form -item label = "私人地址名称 " required > < el-input v-model = "destinationForm.privateName" maxlength="128" placeholder="例如:洛杉矶客户自有仓" / > < / el-form-item >
< div class = "destination- private-grid " >
< el-form-item label = "目的国家" required > < el-input v-model = "destinationForm.countryCode" maxlength="2 " p laceholder="US" / > < / el-form-item >
< el-form-item label = "联系人" required > < el-input v-model = "destinationForm.contactName" maxlength="64" / > < / el-form-item >
< el-form-item label = "联系电话" required > < el-input v-model = "destinationForm.phone" maxlength="32" / > < / el-form-item >
< el-form-item label = "城市" required > < el-input v-model = "destinationForm.city" maxlength="64" / > < / el-form-item >
< / div >
< el-form-item label = "详细地址" required > < el-input v-model = "destinationForm.address" maxlength="256" / > < / el-form-item >
< el-form-item label = "邮编" > < el-input v-model = "destinationForm.postalCode" maxlength="20" / > < / el-form-item >
< el -form -item label = "私人仓 地址" required >
< el-select v-model = "destinationForm. privateAddressId" filterable :loading="destinationLoading" placeholder="请选择企业已保存的私人仓地址 " >
< el -option v-for = "address in privateAddresses" :key="String(address.id) " : label="addressLabel(address)" :value="String(address.id)" / >
< / el-select >
< small v-if = "privateAddressesError" > 私人仓地址加载失败 , 请关闭后重试 。 < / small >
< small v-else-if = "!destinationLoading && privateAddresses.length === 0" > 暂无已保存的私人仓地址 , 请先在普通下单页面维护 。 < / small >
< / el -form -item >
< / template >
< / el-form >
< template # footer >