107 lines
6.0 KiB
TypeScript
107 lines
6.0 KiB
TypeScript
import type { FormRules } from 'element-plus'
|
|
|
|
export type TransportDemandKind = 'truck' | 'looseboard'
|
|
export interface TransportDemandForm {
|
|
vehicleType: '' | 'PALLET_15' | 'PALLET_30'
|
|
origin: string
|
|
destination: string
|
|
originAddress: string
|
|
destinationAddress: string
|
|
originContactName: string
|
|
originContactPhone: string
|
|
destinationContactName: string
|
|
destinationContactPhone: string
|
|
productName: string
|
|
estimatedPalletCount: number
|
|
packageCount: number
|
|
totalWeightKg: number
|
|
totalVolumeCbm: number
|
|
budgetAmount: number | undefined
|
|
currency: 'USD' | 'CNY'
|
|
pickupAt: string
|
|
deliveryAt: string
|
|
remark: string
|
|
}
|
|
|
|
export function createTransportDemandForm(): TransportDemandForm {
|
|
return {
|
|
vehicleType: '', origin: '', destination: '', originAddress: '', destinationAddress: '',
|
|
originContactName: '', originContactPhone: '', destinationContactName: '', destinationContactPhone: '',
|
|
productName: '', estimatedPalletCount: 0, packageCount: 0, totalWeightKg: 0, totalVolumeCbm: 0,
|
|
budgetAmount: undefined, currency: 'USD', pickupAt: '', deliveryAt: '', remark: '',
|
|
}
|
|
}
|
|
|
|
const requiredText = {
|
|
origin: '起运地', destination: '目的地', originContactName: '起运地联系人',
|
|
originContactPhone: '起运地联系电话', destinationContactName: '目的地联系人', destinationContactPhone: '目的地联系电话',
|
|
} as const
|
|
|
|
export function localMinuteInput(value: unknown) {
|
|
return typeof value === 'string' && value ? `${value.slice(0, 16)}:00` : ''
|
|
}
|
|
|
|
export function transportDemandRules(kind: TransportDemandKind, form: TransportDemandForm): FormRules<TransportDemandForm> {
|
|
const rules: FormRules<TransportDemandForm> = {}
|
|
for (const [field, label] of Object.entries(requiredText)) {
|
|
rules[field as keyof typeof requiredText] = [{ required: true, whitespace: true, message: `请输入${label}`, trigger: 'blur' }]
|
|
}
|
|
if (kind === 'truck') rules.vehicleType = [{ required: true, message: '请选择车辆类型', trigger: 'change' }]
|
|
for (const [field, label] of [['packageCount', '件数'], ['estimatedPalletCount', '预计托数'], ['totalWeightKg', '总重量'], ['totalVolumeCbm', '总体积']] as const) {
|
|
if (field === 'estimatedPalletCount' && kind !== 'looseboard') continue
|
|
rules[field] = [{ required: true, type: 'number', min: 0, message: `${label}须为不小于 0 的数字`, trigger: 'change' }]
|
|
}
|
|
rules.budgetAmount = [{ type: 'number', min: 0, message: '预算总价不能小于 0', trigger: 'change' }]
|
|
rules.pickupAt = [{ required: true, message: '请选择取货时间', trigger: 'change' }]
|
|
rules.deliveryAt = [{ required: true, message: '请选择送货时间', trigger: 'change' }, {
|
|
validator: (_rule, value, callback) => callback(value && form.pickupAt && localMinuteInput(value) < localMinuteInput(form.pickupAt) ? new Error('送货时间不能早于取货时间') : undefined), trigger: 'change',
|
|
}]
|
|
return rules
|
|
}
|
|
|
|
export function transportDemandError(kind: TransportDemandKind, form: TransportDemandForm): string | undefined {
|
|
if (kind === 'truck' && !['PALLET_15', 'PALLET_30'].includes(form.vehicleType)) return '请选择车辆类型'
|
|
for (const [field, label] of Object.entries(requiredText)) {
|
|
if (!String(form[field as keyof typeof requiredText] || '').trim()) return `请输入${label}`
|
|
}
|
|
for (const [field, label] of [['pickupAt', '取货时间'], ['deliveryAt', '送货时间']] as const) {
|
|
if (!form[field]) return `请选择${label}`
|
|
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?$/.test(form[field])) return `请选择有效的${label}`
|
|
}
|
|
if (localMinuteInput(form.deliveryAt) < localMinuteInput(form.pickupAt)) return '送货时间不能早于取货时间'
|
|
for (const [field, label] of [['packageCount', '件数'], ['totalWeightKg', '总重量'], ['totalVolumeCbm', '总体积'], ...(kind === 'looseboard' ? [['estimatedPalletCount', '预计托数'] as const] : [])] as const) {
|
|
if (!Number.isFinite(form[field]) || form[field] < 0) return `${label}须为不小于 0 的数字`
|
|
}
|
|
if (!Number.isInteger(form.packageCount) || kind === 'looseboard' && !Number.isInteger(form.estimatedPalletCount)) return '件数和预计托数须为整数'
|
|
if (form.budgetAmount != null && (!Number.isFinite(form.budgetAmount) || form.budgetAmount < 0)) return '预算总价不能小于 0'
|
|
if (!['USD', 'CNY'].includes(form.currency)) return '请选择预算币种'
|
|
return undefined
|
|
}
|
|
|
|
function commonPayload(form: TransportDemandForm) {
|
|
return {
|
|
origin: form.origin.trim(), destination: form.destination.trim(),
|
|
originAddress: form.originAddress.trim() || undefined, destinationAddress: form.destinationAddress.trim() || undefined,
|
|
originContactName: form.originContactName.trim(), originContactPhone: form.originContactPhone.trim(),
|
|
destinationContactName: form.destinationContactName.trim(), destinationContactPhone: form.destinationContactPhone.trim(),
|
|
packageCount: form.packageCount, totalWeightKg: form.totalWeightKg, totalVolumeCbm: form.totalVolumeCbm,
|
|
budgetAmount: form.budgetAmount ?? undefined, currency: form.currency,
|
|
pickupAt: localMinuteInput(form.pickupAt), deliveryAt: localMinuteInput(form.deliveryAt), remark: form.remark.trim() || undefined,
|
|
}
|
|
}
|
|
|
|
type CommonPayload = ReturnType<typeof commonPayload>
|
|
type TruckPayload = CommonPayload & { vehicleType: 'PALLET_15' | 'PALLET_30' }
|
|
type LooseboardPayload = CommonPayload & { productName: string | undefined; estimatedPalletCount: number }
|
|
|
|
export function buildTransportDemand(kind: 'truck', form: TransportDemandForm): TruckPayload
|
|
export function buildTransportDemand(kind: 'looseboard', form: TransportDemandForm): LooseboardPayload
|
|
export function buildTransportDemand(kind: TransportDemandKind, form: TransportDemandForm) {
|
|
const failure = transportDemandError(kind, form)
|
|
if (failure) throw new Error(failure)
|
|
const common = commonPayload(form)
|
|
return kind === 'truck'
|
|
? { ...common, vehicleType: form.vehicleType as 'PALLET_15' | 'PALLET_30' }
|
|
: { ...common, productName: form.productName.trim() || undefined, estimatedPalletCount: form.estimatedPalletCount }
|
|
}
|