@@ -1,13 +1,12 @@
< script setup lang = "ts" >
< script setup lang = "ts" >
import { computed , onMounted , reactive , ref , watch } from 'vue'
import { computed , onMounted , reactive , ref , watch } from 'vue'
import { Package , Truck } from '@lucide/vue'
import { Package } from '@lucide/vue'
import { useRoute , useRouter } from 'vue-router'
import { useRoute , useRouter } from 'vue-router'
import { ElMessage , type FormInstance , type FormRules } from 'element-plus'
import { ElMessage , type FormInstance , type FormRules } from 'element-plus'
import DataTable , { type DataTableColumn } from '@/components/common/DataTable.vue'
import DataTable , { type DataTableColumn } from '@/components/common/DataTable.vue'
import QueryToolbar , { type QueryField , type QueryModel } from '@/components/common/QueryToolbar.vue'
import QueryToolbar , { type QueryField , type QueryModel } from '@/components/common/QueryToolbar.vue'
import type { TableAction } from '@/components/common/tableActions'
import type { TableAction } from '@/components/common/tableActions'
import { useAuthStore } from '@/modules/auth/public'
import { useAuthStore } from '@/modules/auth/public'
import { getMerchantWarehouses , type MerchantWarehouse } from '@/modules/first-leg/public'
import {
import {
createTransport ,
createTransport ,
getBusinessOrder ,
getBusinessOrder ,
@@ -16,7 +15,6 @@ import {
type TransportDetail ,
type TransportDetail ,
type TransportSummary ,
type TransportSummary ,
} from '../api/businessOrders'
} from '../api/businessOrders'
import { CONTAINER _SPECIFICATIONS , DEFAULT _CONTAINER _TYPE } from '../containerSpecifications'
import { poolOrderStatusLabels } from '../fleetArrangement'
import { poolOrderStatusLabels } from '../fleetArrangement'
const props = withDefaults ( defineProps < { kind : CrossBorderBusinessKind ; createPage ? : boolean ; detailPage ? : boolean } > ( ) , { createPage : false , detailPage : false } )
const props = withDefaults ( defineProps < { kind : CrossBorderBusinessKind ; createPage ? : boolean ; detailPage ? : boolean } > ( ) , { createPage : false , detailPage : false } )
@@ -36,14 +34,12 @@ type PageMode = 'list' | 'create' | 'detail'
interface ColumnDefinition { key : string ; label : string ; width ? : number }
interface ColumnDefinition { key : string ; label : string ; width ? : number }
interface BusinessForm {
interface BusinessForm {
transportMode : string
productName : string
palletRequired : string
estimatedPalletCount : number
transportType : string
origin : string
origin : string
originAddress : string
originAddress : string
destination : string
destination : string
destinationAddress : string
destinationAddress : string
containerType : string
packageCount : number
packageCount : number
totalWeightKg : number
totalWeightKg : number
totalVolumeCbm : number
totalVolumeCbm : number
@@ -56,13 +52,7 @@ interface BusinessForm {
destinationContactPhone : string
destinationContactPhone : string
pickupAt : string
pickupAt : string
deliveryAt : string
deliveryAt : string
contactName : string
contactInfo : string
requestedDate : string
remark : string
remark : string
cargoName : string
deliveryDate : string
palletCount : number
}
}
const configuration = computed ( ( ) => ( {
const configuration = computed ( ( ) => ( {
@@ -81,14 +71,13 @@ const configuration = computed(() => ({
function transportColumns ( looseboard : boolean ) : ColumnDefinition [ ] {
function transportColumns ( looseboard : boolean ) : ColumnDefinition [ ] {
return [
return [
{ key : 'orderNo' , label : '订单编号' , width : 180 } ,
{ key : 'orderNo' , label : '订单编号' , width : 180 } ,
... ( looseboard ? [ { key : 'transportMode' , label : '运输方式' , width : 120 } , { key : 'palletRequired ', label : '是否打盘 ' , width : 100 } ] : [ ] ) ,
... ( ! looseboard ? [ { key : 'vehicleType ' , label : '车辆类型 ' , width : 110 } ] : [ ] ) ,
... ( looseboard ? [ { key : 'transportType' , label : '运输类型' , width : 130 } ] : [ { key : 'vehicleType' , label : '车辆类型' , width : 110 } ] ) ,
{ key : 'origin' , label : '起运地' , width : 150 } ,
{ key : 'origin' , label : '起运地' , width : 150 } ,
{ key : 'destination' , label : '目的地' , width : 150 } ,
{ key : 'destination' , label : '目的地' , width : 150 } ,
... ( looseboard ? [ { key : 'containerType ' , label : '柜型 ' , width : 100 } ] : [ ] ) ,
... ( looseboard ? [ { key : 'productName' , label : '商品名称' , width : 150 } , { key : 'estimatedPalletCount ', label : '预计托数 ' , width : 100 } ] : [ ] ) ,
{ key : 'totalWeightKg' , label : '总重量(kg)' , width : 120 } ,
{ key : 'totalWeightKg' , label : '总重量(kg)' , width : 120 } ,
{ key : 'budgetAmount' , label : '预算总价' , width : 110 } ,
{ key : 'budgetAmount' , label : '预算总价' , width : 110 } ,
... ( looseboard ? [ { key : 'requestedDate' , label : '要求时间' , width : 120 } ] : [
... ( [
{ key : 'pickupAt' , label : '取货时间' , width : 165 } , { key : 'deliveryAt' , label : '送货时间' , width : 165 } ,
{ key : 'pickupAt' , label : '取货时间' , width : 165 } , { key : 'deliveryAt' , label : '送货时间' , width : 165 } ,
] ) ,
] ) ,
{ key : 'status' , label : '状态' , width : 130 } ,
{ key : 'status' , label : '状态' , width : 130 } ,
@@ -107,10 +96,6 @@ const fleetArrangement = computed(() => detail.value ? (detail.value as Transpor
const formRef = ref < FormInstance > ( )
const formRef = ref < FormInstance > ( )
const query = reactive ( { page : 1 , size : 20 , orderNo : '' , routeKeyword : '' , status : '' } )
const query = reactive ( { page : 1 , size : 20 , orderNo : '' , routeKeyword : '' , status : '' } )
const total = ref ( 0 )
const total = ref ( 0 )
const overseasWarehouses = ref < MerchantWarehouse [ ] > ( [ ] )
const overseasWarehousesLoading = ref ( false )
const overseasWarehousesError = ref ( '' )
const isSelfDelivery = computed ( ( ) => props . kind === 'looseboard' && form . transportMode === 'SHARED_TRUCK' )
const queryModel = computed < QueryModel > ( {
const queryModel = computed < QueryModel > ( {
get : ( ) => ( {
get : ( ) => ( {
@@ -151,22 +136,15 @@ const form = reactive<BusinessForm>(emptyForm())
const rules = computed < FormRules < BusinessForm > > ( ( ) => ( {
const rules = computed < FormRules < BusinessForm > > ( ( ) => ( {
origin : [ { required : true , message : '请输入起运地' , trigger : 'blur' } ] ,
origin : [ { required : true , message : '请输入起运地' , trigger : 'blur' } ] ,
destination : [ { required : true , message : '请输入目的地' , trigger : 'blur' } ] ,
destination : [ { required : true , message : '请输入目的地' , trigger : 'blur' } ] ,
... ( props . kind === 'trucking' ? {
... ( props . kind === 'trucking' ? { vehicleType : [ { required : true , message : '请选择车辆类型' , trigger : 'change' } ] } : { } ) ,
vehicleType : [ { required : true , message : '请选择车辆类型 ' , trigger : 'change ' } ] ,
originContactName : [ { required : true , message : '请输入起运地联系人 ' , trigger : 'blur ' } ] ,
originContactName : [ { required : true , message : '请输入起运地联系人 ' , trigger : 'blur' } ] ,
originContactPhone : [ { required : true , message : '请输入起运地联系电话 ' , trigger : 'blur' } ] ,
originContactPhone : [ { required : true , message : '请输入起运 地联系电话 ' , trigger : 'blur' } ] ,
destinationContactName : [ { required : true , message : '请输入目的 地联系人 ' , trigger : 'blur' } ] ,
destinationContactName : [ { required : true , message : '请输入目的地联系人 ' , trigger : 'blur' } ] ,
destinationContactPhone : [ { required : true , message : '请输入目的地联系电话 ' , trigger : 'blur' } ] ,
destinationContactPhone : [ { required : true , message : '请输入目的地联系电话 ' , trigger : 'blur ' } ] ,
pickupAt : [ { required : true , message : '请选择取货时间 ' , trigger : 'change ' } ] ,
pickupAt : [ { required : true , message : '请选择取 货时间' , trigger : 'change' } ] ,
deliveryAt : [ { required : true , message : '请选择送 货时间' , trigger : 'change' } , {
deliveryAt : [ { required : true , message : '请选择送货时间' , trigger : 'change' } , {
validator : ( _rule : unknown , value : string , callback : ( error ? : Error ) => void ) => callback ( value && form . pickupAt && value < form . pickupAt ? new Error ( '送货时间不能早于取货时间' ) : undefined ) , trigger : 'change' ,
validator : ( _rule : unknown , value : string , callback : ( error ? : Error ) => void ) => {
} ] ,
callback ( value && form . pickupAt && value < form . pickupAt ? new Error ( '送货时间不能早于取货时间' ) : undefined )
} , trigger : 'change' ,
} ] ,
} : {
contactName : [ { required : true , message : '请输入联系人' , trigger : 'blur' } ] ,
contactInfo : [ { required : true , message : '请输入联系电话或联系方式' , trigger : 'blur' } ] ,
} ) ,
} ) )
} ) )
const detailFields = computed ( ( ) => {
const detailFields = computed ( ( ) => {
@@ -175,21 +153,15 @@ const detailFields = computed(() => {
const current = detail . value as TransportDetail
const current = detail . value as TransportDetail
return [
return [
... ( props . kind === 'looseboard' ? [
... ( props . kind === 'looseboard' ? [
[ '运输方式 ' , transportModeLabel ( read ( summary , 'transportMode' ) ) ] , [ '是否打盘 ' , yesNo ( read ( summary , 'palletRequired' ) ) ] ,
[ '商品名称 ' , summary . productName ] , [ '预计托数 ' , summary . estimatedPalletCount ] ,
[ '运输类型' , transportTypeLabel ( read ( summary , 'transportType' ) ) ] ,
] : [ [ '车辆类型' , vehicleTypeLabel ( summary . vehicleType ) ] ] ) ,
] : [ [ '车辆类型' , vehicleTypeLabel ( summary . vehicleType ) ] ] ) ,
[ '起运地' , read ( summary , 'origin' ) ] , [ '起运地址' , current . originAddress ] ,
[ '起运地' , read ( summary , 'origin' ) ] , [ '起运地址' , current . originAddress ] ,
[ '目的地' , read ( summary , 'destination' ) ] , [ '目的地址' , current . destinationAddress ] ,
[ '目的地' , read ( summary , 'destination' ) ] , [ '目的地址' , current . destinationAddress ] ,
... ( props . kind === 'looseboard' ? [ [ '柜型' , read ( summary , 'containerType' ) ] ] : [ ] ) ,
[ '件数' , read ( summary , 'packageCount' ) ] , [ '总重量(kg)' , read ( summary , 'totalWeightKg' ) ] ,
[ '件数' , read ( summary , 'packageCount' ) ] , [ '总重量(kg)' , read ( summary , 'totalWeightKg' ) ] ,
[ '总体积(m³)' , read ( summary , 'totalVolumeCbm' ) ] , [ '预算总价' , money ( read ( summary , 'budgetAmount' ) , read ( summary , 'currency' ) ) ] ,
[ '总体积(m³)' , read ( summary , 'totalVolumeCbm' ) ] , [ '预算总价' , money ( read ( summary , 'budgetAmount' ) , read ( summary , 'currency' ) ) ] ,
... ( props . kind === 'looseboard' ? [
[ '起运地联系人' , summary . originContactName ] , [ '起运地联系电话' , summary . originContactPhone ] ,
[ '联系人' , summary . contactName ] , [ '联系方式 ' , summary . contactInfo ] , [ '要求时间' , summary . requestedDate ] ,
[ '目的地 联系人' , summary . destinationContactName ] , [ '目的地联系电话 ' , summary . destinationContactPhone ] ,
] : [
[ '取货时间' , localMinute ( summary . pickupAt ) ] , [ '送货时间' , localMinute ( summary . deliveryAt ) ] , [ '备注' , current . remark ] ,
[ '起运地联系人' , summary . originContactName ] , [ '起运地联系电话' , summary . originContactPhone ] ,
[ '目的地联系人' , summary . destinationContactName ] , [ '目的地联系电话' , summary . destinationContactPhone ] ,
[ '取货时间' , localMinute ( summary . pickupAt ) ] , [ '送货时间' , localMinute ( summary . deliveryAt ) ] ,
] ) , [ '备注' , current . remark ] ,
]
]
} )
} )
@@ -207,33 +179,14 @@ const detailStatus = computed(() => detail.value ? statusLabel(detail.value.summ
function emptyForm ( ) : BusinessForm {
function emptyForm ( ) : BusinessForm {
return {
return {
transportMode : 'SHARED_TRUCK ' , palletRequired : 'NO' , transportType : 'PORT_PICKUP' , origin : '' , originAddress : '' ,
productName : '' , estimatedPalletCount : 0 , origin : '' , originAddress : '' ,
destination : '' , destinationAddress : '' , containerType : DEFAULT _CONTAINER _TYPE , packageCount : 0 ,
destination : '' , destinationAddress : '' , packageCount : 0 ,
totalWeightKg : 0 , totalVolumeCbm : 0 , currency : 'USD' , contactName : '' , contactInfo : '' , requestedDate : '' ,
totalWeightKg : 0 , totalVolumeCbm : 0 , currency : 'USD' ,
remark : '' , cargoName : '' , deliveryDate : '' , palletCount : 0 , vehicleType : '' , originContactName : '' , originContactPhone : '' , destinationContactName : '' , destinationContactPhone : '' , pickupAt : '' , deliveryAt : '' ,
remark : '' , vehicleType : '' , originContactName : '' , originContactPhone : '' , destinationContactName : '' , destinationContactPhone : '' , pickupAt : '' , deliveryAt : '' ,
}
}
}
}
function resetForm ( ) { Object . assign ( form , emptyForm ( ) ) ; submitKey . value = '' ; formRef . value ? . clearValidate ( ) }
function resetForm ( ) { Object . assign ( form , emptyForm ( ) ) ; submitKey . value = '' ; formRef . value ? . clearValidate ( ) }
function warehouseLabel ( warehouse : MerchantWarehouse ) { return ` ${ warehouse . warehouseName } · ${ warehouse . warehouseCode } ` }
function selectOriginMode ( ) {
form . origin = ''
form . originAddress = ''
formRef . value ? . clearValidate ( 'origin' )
}
async function loadOverseasWarehouses ( ) {
if ( props . kind !== 'looseboard' ) return
overseasWarehousesLoading . value = true
overseasWarehousesError . value = ''
try {
const result = await getMerchantWarehouses ( { page : 1 , size : 200 , warehouseType : 'OVERSEAS' } )
overseasWarehouses . value = result . records . filter ( item => item . status === 'ACTIVE' && [ 'OVERSEAS' , 'OVERSEAS_PARTNER' ] . includes ( item . warehouseType ) && item . countryCode === 'US' )
if ( ! overseasWarehouses . value . length ) overseasWarehousesError . value = '暂无可用的海外仓'
} catch ( cause ) {
overseasWarehouses . value = [ ]
overseasWarehousesError . value = errorMessage ( cause )
} finally { overseasWarehousesLoading . value = false }
}
function read ( source : object , key : string ) { return Reflect . get ( source , key ) as unknown }
function read ( source : object , key : string ) { return Reflect . get ( source , key ) as unknown }
function text ( value : unknown ) { return value === null || value === undefined || value === '' ? '—' : String ( value ) }
function text ( value : unknown ) { return value === null || value === undefined || value === '' ? '—' : String ( value ) }
function money ( amount : unknown , currency : unknown ) { return amount === null || amount === undefined ? '—' : ` ${ text ( currency ) } ${ Number ( amount ) . toFixed ( 2 ) } ` }
function money ( amount : unknown , currency : unknown ) { return amount === null || amount === undefined ? '—' : ` ${ text ( currency ) } ${ Number ( amount ) . toFixed ( 2 ) } ` }
@@ -242,7 +195,6 @@ function yesNo(value: unknown) { return value === 'YES' ? '是' : value === 'NO'
function vehicleTypeLabel ( value : unknown ) { return ( { PALLET _15 : '15拖' , PALLET _30 : '30拖' } as Record < string , string > ) [ String ( value ) ] || text ( value ) }
function vehicleTypeLabel ( value : unknown ) { return ( { PALLET _15 : '15拖' , PALLET _30 : '30拖' } as Record < string , string > ) [ String ( value ) ] || text ( value ) }
function localMinute ( value : unknown ) { return value ? String ( value ) . replace ( 'T' , ' ' ) . slice ( 0 , 16 ) : '—' }
function localMinute ( value : unknown ) { return value ? String ( value ) . replace ( 'T' , ' ' ) . slice ( 0 , 16 ) : '—' }
function transportTypeLabel ( value : unknown ) { return ( { PORT _PICKUP : '港口提柜' , WAREHOUSE _TO _WAREHOUSE : '仓到仓' , WAREHOUSE _TO _DOOR : '仓到门' } as Record < string , string > ) [ String ( value ) ] || text ( value ) }
function transportTypeLabel ( value : unknown ) { return ( { PORT _PICKUP : '港口提柜' , WAREHOUSE _TO _WAREHOUSE : '仓到仓' , WAREHOUSE _TO _DOOR : '仓到门' } as Record < string , string > ) [ String ( value ) ] || text ( value ) }
function transportModeLabel ( value : unknown ) { return ( { SHARED _TRUCK : '拼车' , PRIORITY _CONSOLIDATION : '优先拼载' } as Record < string , string > ) [ String ( value ) ] || text ( value ) }
function statusLabel ( value : unknown ) {
function statusLabel ( value : unknown ) {
if ( poolOrderStatusLabels [ String ( value ) ] ) return poolOrderStatusLabels [ String ( value ) ]
if ( poolOrderStatusLabels [ String ( value ) ] ) return poolOrderStatusLabels [ String ( value ) ]
return ( { PENDING _REVIEW : '待审核' , APPROVED : '已通过' , REJECTED : '已拒绝' , PENDING _ACCEPTANCE : '待接单' , PROCESSING : '处理中' , IN _TRANSIT : '运输中' , COMPLETED : '已完成' , CANCELLED : '已取消' } as Record < string , string > ) [ String ( value ) ] || text ( value )
return ( { PENDING _REVIEW : '待审核' , APPROVED : '已通过' , REJECTED : '已拒绝' , PENDING _ACCEPTANCE : '待接单' , PROCESSING : '处理中' , IN _TRANSIT : '运输中' , COMPLETED : '已完成' , CANCELLED : '已取消' } as Record < string , string > ) [ String ( value ) ] || text ( value )
@@ -257,7 +209,6 @@ function displayCell(candidate: unknown, key: string) {
if ( key === 'vehicleType' ) return vehicleTypeLabel ( value )
if ( key === 'vehicleType' ) return vehicleTypeLabel ( value )
if ( key === 'pickupAt' || key === 'deliveryAt' ) return localMinute ( value )
if ( key === 'pickupAt' || key === 'deliveryAt' ) return localMinute ( value )
if ( key === 'transportType' ) return transportTypeLabel ( value )
if ( key === 'transportType' ) return transportTypeLabel ( value )
if ( key === 'transportMode' ) return transportModeLabel ( value )
if ( key === 'palletRequired' ) return yesNo ( value )
if ( key === 'palletRequired' ) return yesNo ( value )
if ( key === 'createdAt' ) return dateTime ( value )
if ( key === 'createdAt' ) return dateTime ( value )
if ( key === 'budgetAmount' ) return money ( value , read ( row , 'currency' ) )
if ( key === 'budgetAmount' ) return money ( value , read ( row , 'currency' ) )
@@ -336,6 +287,7 @@ async function loadDetail() {
}
}
async function submit ( ) {
async function submit ( ) {
if ( props . kind === 'looseboard' && form . pickupAt && form . deliveryAt && form . deliveryAt < form . pickupAt ) { ElMessage . error ( '送达时间不能早于取货时间' ) ; return }
if ( ! await formRef . value ? . validate ( ) . catch ( ( ) => false ) ) return
if ( ! await formRef . value ? . validate ( ) . catch ( ( ) => false ) ) return
submitting . value = true
submitting . value = true
const stableSubmitKey = submitKey . value || idempotencyKey ( )
const stableSubmitKey = submitKey . value || idempotencyKey ( )
@@ -347,7 +299,7 @@ async function submit() {
packageCount : form . packageCount ,
packageCount : form . packageCount ,
totalWeightKg : form . totalWeightKg , totalVolumeCbm : form . totalVolumeCbm ,
totalWeightKg : form . totalWeightKg , totalVolumeCbm : form . totalVolumeCbm ,
budgetAmount : form . budgetAmount , currency : form . currency || undefined ,
budgetAmount : form . budgetAmount , currency : form . currency || undefined ,
remark : props . kind === 'looseboard' ? [ form . cargoName , form . remark ] . filter ( Boolean ) . join ( ' · ' ) || undefined : form . remark || undefined ,
remark : form . remark || undefined ,
idempotencyKey : stableSubmitKey ,
idempotencyKey : stableSubmitKey ,
}
}
if ( props . kind === 'trucking' ) {
if ( props . kind === 'trucking' ) {
@@ -358,9 +310,10 @@ async function submit() {
pickupAt : form . pickupAt , deliveryAt : form . deliveryAt ,
pickupAt : form . pickupAt , deliveryAt : form . deliveryAt ,
} )
} )
} else {
} else {
await createTransport ( 'looseboard' , { ... base , transportMode : form . transportMode , palletRequired : form . palletRequired ,
await createTransport ( 'looseboard' , { ... base , productName : form . productName || undefined , estimatedPalletCount : form . estimatedPalletCount ,
transportType : form . transportType , containerType : form . containerType || undefined ,
originContactName : form . originContactName , originContactPhone : form . originContactPhone ,
contactName : form . contactName || undefined , contactInfo : form . contactInfo || undefined , requestedDate : form . requestedDate || undefined ,
destinationContactName : form . destinationContactName , destinationContactPhone : form . destinationContactPhone ,
pickupAt : form . pickupAt , deliveryAt : form . deliveryAt ,
} )
} )
}
}
ElMessage . success ( '订单提交成功' )
ElMessage . success ( '订单提交成功' )
@@ -372,7 +325,7 @@ async function submit() {
}
}
watch ( ( ) => [ query . page , query . size ] , ( ) => { if ( ! props . createPage && mode . value === 'list' ) void load ( ) } )
watch ( ( ) => [ query . page , query . size ] , ( ) => { if ( ! props . createPage && mode . value === 'list' ) void load ( ) } )
onMounted ( ( ) => { if ( props . detailPage ) void loadDetail ( ) ; else if ( ! props . createPage ) void load ( ) ; void loadOverseasWarehouses ( ) } )
onMounted ( ( ) => { if ( props . detailPage ) void loadDetail ( ) ; else if ( ! props . createPage ) void load ( ) } )
< / script >
< / script >
< template >
< template >
@@ -432,36 +385,32 @@ onMounted(() => { if (props.detailPage) void loadDetail(); else if (!props.creat
< el-card v-else-if = "kind === 'looseboard'" shadow="never" class="form-card looseboard-form-card" >
< el-card v-else-if = "kind === 'looseboard'" shadow="never" class="form-card looseboard-form-card" >
< el -form ref = "formRef" :model = "form" :rules = "rules" label -position = " top " >
< el -form ref = "formRef" :model = "form" :rules = "rules" label -position = " top " >
< div class = "form-section transport-section " >
< div class = "form-grid two-col lower-grid " >
< h3 > < span class = "section-icon" > < Truck :size = "14" / > < / span > 运输方式 < em > * < / em > < / h3 >
< el-form-item label = "起运地" prop = "origin" > < el-input v -model .trim = " form.origin " maxlength = "255" placeholder = "城市 / 港口 / 州" / > < / el-form-item >
< div class = "mode-buttons" > < el-radio-group v-model = "form.transportMode" @change="selectOriginMode"><el-radio-button value="SHARED_TRUCK"><Truck :size="14" /> 自送</el-radio-button><el-radio-button value="PRIORITY_CONSOLIDATION"><Package :size="14" / > 我司提货 < / el-radio-button > < / el-radio-group > < / div >
< / div >
< div class = "form-grid two-col" >
< el-form-item : label = "isSelfDelivery ? '入仓库' : '取货地'" prop = "origin" : rules = "[{ required: true, message: isSelfDelivery ? '请选择美国仓库' : '请输入取货地', trigger: isSelfDelivery ? 'change' : 'blur' }]" >
< template v-if = "isSelfDelivery" >
< el -select v-model = "form.origin" filterable clearable :loading="overseasWarehousesLoading" placeholder="请选择美国仓库" no-data-text="暂无可用的美国海外仓" >
< el -option v-for = "warehouse in overseasWarehouses" :key="warehouse.id" :label="warehouseLabel(warehouse)" :value="warehouseLabel(warehouse)" / >
< / el-select >
< div v-if = "overseasWarehousesError" role="alert" class="warehouse-load-error">{{ overseasWarehousesError }} <el-button link type="primary" @click="loadOverseasWarehouses" > 重新加载 < / el -button > < / div >
< / template >
< el-input v-else v -model .trim = " form.origin " maxlength = "255" placeholder = "城市 / 港口 / 州" / >
< / el-form-item >
< el-form-item label = "目的地" prop = "destination" > < el-input v -model .trim = " form.destination " maxlength = "255" placeholder = "城市 / 州" / > < / el-form-item >
< el-form-item label = "目的地" prop = "destination" > < el-input v -model .trim = " form.destination " maxlength = "255" placeholder = "城市 / 州" / > < / el-form-item >
< el-form-item label = "联系人" prop = "c ontactName" > < el-input v -model .trim = " form.contactName " maxlength = "128" placeholder = "联系人姓名 " / > < / el-form-item >
< el-form-item label = "起运地 联系人" prop = "originC ontactName" > < el-input v -model .trim = " form.originContactName " maxlength = "128" placeholder = "请输入起运地 联系人" / > < / el-form-item >
< el-form-item label = "联系方式 " prop = "c ontactInfo " > < el-input v -model .trim = " form.contactInfo " maxlength = "128" placeholder = "联系电话 " / > < / el-form-item >
< el-form-item label = "目的地联系人 " prop = "destinationC ontactName " > < el-input v -model .trim = " form.destinationContactName " maxlength = "128" placeholder = "请输入目的地联系人 " / > < / el-form-item >
< el-form-item label = "起运地联系电话" prop = "originContactPhone" > < el-input v -model .trim = " form.originContactPhone " type = "tel" maxlength = "128" placeholder = "请输入起运地联系电话" / > < / el-form-item >
< el-form-item label = "目的地联系电话" prop = "destinationContactPhone" > < el-input v -model .trim = " form.destinationContactPhone " type = "tel" maxlength = "128" placeholder = "请输入目的地联系电话" / > < / el-form-item >
< / div >
< / div >
< div class = "form-section cargo-section" > < h3 > < span class = "section-icon" > < Package :size = "14" / > < / span > 托载 < / h3 > < div class = "form-grid cargo-grid" >
< div class = "form-section cargo-section" > < h3 > < span class = "section-icon" > < Package :size = "14" / > < / span > 托载 < / h3 > < div class = "form-grid cargo-grid" >
< el-form-item label = "商品名称" > < el-input v -model .trim = " form.cargoName " placeholder = "请输入商品名称" / > < / el-form-item >
< el-form-item label = "商品名称" > < el-input v -model .trim = " form.productName " placeholder = "请输入商品名称" / > < / el-form-item >
< el-form-item label = "托数" > < el-input-number v-model = "form.p alletCount" :min="0" controls-position="right" / > < / el-form-item >
< el-form-item label = "预计 托数" > < el-input-number v-model = "form.estimatedP alletCount" :min="0" controls-position="right" placeholder="请输入预计托数" / > < / el-form-item >
< el-form-item label = "总重量 (kg)" > < el-input-number v-model = "form.totalWeightKg" :min="0" :precision="2" controls-position="right" / > < / el-form-item >
< el-form-item label = "总重量 (kg)" > < el-input-number v-model = "form.totalWeightKg" :min="0" :precision="2" controls-position="right" placeholder="请输入总重量" / > < / el-form-item >
< el-form-item label = "总体积 (m³)" > < el-input-number v-model = "form.totalVolumeCbm" :min="0" :precision="3" controls-position="right" / > < / el-form-item >
< el-form-item label = "总体积 (m³)" > < el-input-number v-model = "form.totalVolumeCbm" :min="0" :precision="3" controls-position="right" placeholder="请输入总体积" / > < / el-form-item >
< / div > < / div >
< / div > < / div >
< div class = "form-grid two-col lower-grid" >
< div class = "form-grid two-col lower-grid" >
< el-form-item label = "预算总价( $) " > < el-input-number v-model = "form.budgetAmount" :min="0" :precision="2" controls-position="right" placeholder="0.00" / > < / el-form-item >
< el-form-item label = "预算总价" > < el-input-number v-model = "form.budgetAmount" :min="0" :precision="2" controls-position="right" placeholder="0.00" / > < / el-form-item >
< div > < / div >
< el-form-item label = "预算币种" > < el-select v-model = "form.currency"><el-option label="USD" value="USD" /><el-option label="CNY" value="CNY" / > < / el-select > < / el-form-item >
< el-form-item label = "要求 取货时间" prop = "requestedDate " > < el-date-picker v-model = "form.requestedDate" type="date " value-format="YYYY-MM-DD" placeholder="年 / 月 / 日 " / > < / el-form-item >
< el-form-item label = "取货时间" prop = "pickupAt " > < el-date-picker v-model = "form.pickupAt" type="datetime" format="YYYY-MM-DD HH:mm" time-format="HH:mm " value-format="YYYY-MM-DDTHH:mm:ss " placeholder="请选择取货时间" @change="formRef?.validateField('deliveryAt').catch(() => undefined) " / > < / el-form-item >
< el-form-item label = "送货到达 时间" > < el-date-picker v-model = "form.deliveryDate " type="date" value-format="YYYY-MM-DD" placeholder="年 / 月 / 日 " / > < / el-form-item >
< el-form-item label = "送货时间" prop = "deliveryAt "> < el-date-picker v-model = "form.deliveryAt " type="datetime" format="YYYY-MM-DD HH:mm" time-format="HH:mm " value-format="YYYY-MM-DDTHH:mm:ss " placeholder="请选择送货时间 " / > < / el-form-item >
< / div >
< / div >
< el-collapse class = "looseboard-extra" > < el-collapse-item title = "补充信息(选填)" name = "extra" > < div class = "form-grid two-col" >
< el-form-item label = "件数" > < el-input-number v-model = "form.packageCount" :min="0" :precision="0" controls-position="right" placeholder="请输入件数" / > < / el-form-item >
< el-form-item label = "备注" > < el-input v-model = "form.remark" type="textarea" maxlength="1000" :rows="2" placeholder="请输入备注(选填)" / > < / el-form-item >
< el-form-item label = "起运地址补充" > < el-input v -model .trim = " form.originAddress " maxlength = "500" placeholder = "请输入详细起运地址(选填)" / > < / el-form-item >
< el-form-item label = "目的地址补充" > < el-input v -model .trim = " form.destinationAddress " maxlength = "500" placeholder = "请输入详细目的地址(选填)" / > < / el-form-item >
< / div > < / el-collapse-item > < / el-collapse >
< div class = "form-actions" > < el-button @click ="returnToList" > 取消 < / el -button > < el-button v-if = "canCreate" type="primary" :loading="submitting" @click="submit" > 提交订单 < / el -button > < / div >
< div class = "form-actions" > < el-button @click ="returnToList" > 取消 < / el -button > < el-button v-if = "canCreate" type="primary" :loading="submitting" @click="submit" > 提交订单 < / el -button > < / div >
< / el-form >
< / el-form >
< / el-card >
< / el-card >
@@ -551,6 +500,7 @@ onMounted(() => { if (props.detailPage) void loadDetail(); else if (!props.creat
. lower - grid { padding - top : 20 px ; }
. lower - grid { padding - top : 20 px ; }
. lower - grid : deep ( . el - date - editor ) { width : 100 % ; }
. lower - grid : deep ( . el - date - editor ) { width : 100 % ; }
. form - actions { display : flex ; justify - content : flex - end ; gap : 10 px ; margin - top : 5 px ; padding : 20 px 30 px 25 px ; border - top : 1 px solid # f0f2f5 ; }
. form - actions { display : flex ; justify - content : flex - end ; gap : 10 px ; margin - top : 5 px ; padding : 20 px 30 px 25 px ; border - top : 1 px solid # f0f2f5 ; }
. looseboard - extra { margin : 0 30 px ; }
. looseboard - form - card . form - actions { padding - right : max ( 30 px , calc ( 100 % - 1150 px ) ) ; }
. looseboard - form - card . form - actions { padding - right : max ( 30 px , calc ( 100 % - 1150 px ) ) ; }
. form - actions . el - button { min - width : 80 px ; height : 36 px ; border - radius : 7 px ; }
. form - actions . el - button { min - width : 80 px ; height : 36 px ; border - radius : 7 px ; }
. form - actions . el - button -- primary { background : linear - gradient ( 135 deg , # 6774 df , # 7553 aa ) ; border : 0 ; box - shadow : 0 5 px 12 px rgb ( 103 116 223 / 24 % ) ; }
. form - actions . el - button -- primary { background : linear - gradient ( 135 deg , # 6774 df , # 7553 aa ) ; border : 0 ; box - shadow : 0 5 px 12 px rgb ( 103 116 223 / 24 % ) ; }