This commit is contained in:
2026-10-28 16:33:35 +08:00
parent 510db2bb8c
commit e5c4003e3d
9 changed files with 174 additions and 144 deletions
@@ -150,7 +150,7 @@ test('truck requires both contacts vehicle and minute times without inheriting l
truck.form.pickupAt = '2026-10-20T09:30:00'
let failure
truck.rules.value.deliveryAt[1].validator({}, '2026-10-20T09:29:00', error => { failure = error })
assert.equal(failure.message, 'C点送达时间不能早于B点取货时间')
assert.equal(failure.message, '送达时间不能早于取货时间')
})
test('truck retry submits the complete new contract with identical local times and idempotency key', async () => {
@@ -176,8 +176,8 @@ test('truck details render saved minute times and unknown pool demand without ti
current.detail.value = { summary: { vehicleType: null, pickupAt: '2026-10-20T09:30:00', deliveryAt: null }, originAddress: null, destinationAddress: null, remark: null }
const fields = new Map(current.detailFields.value)
assert.equal(fields.get('车辆类型'), '—')
assert.equal(fields.get('B点取货时间'), '2026-10-20 09:30')
assert.equal(fields.get('C点送达时间'), '—')
assert.equal(fields.get('取货时间'), '2026-10-20 09:30')
assert.equal(fields.get('送达时间'), '—')
assert.equal(fields.has('柜型'), false)
assert.equal(fields.has('托盘数'), false)
})
@@ -50,10 +50,10 @@ const configuration = computed(() => ({
})[props.kind])
function transportColumns(looseboard: boolean): ColumnDefinition[] {
const originLabel = looseboard ? '起运地' : 'B点取货地'
const destinationLabel = looseboard ? '目的地' : 'C点送达地'
const pickupLabel = looseboard ? '取货时间' : 'B点取货时间'
const deliveryLabel = looseboard ? '送货时间' : 'C点送达时间'
const originLabel = looseboard ? '起运地' : '取货地'
const destinationLabel = looseboard ? '目的地' : '送达地'
const pickupLabel = looseboard ? '取货时间' : '取货时间'
const deliveryLabel = looseboard ? '送货时间' : '送达时间'
return [
{ key: 'orderNo', label: '订单编号', width: 180 },
...(!looseboard ? [{ key: 'vehicleType', label: '车辆类型', width: 110 }] : []),
@@ -127,13 +127,13 @@ const detailFields = computed(() => {
...(props.kind === 'looseboard' ? [
['商品名称', summary.productName], ['预计托数', summary.estimatedPalletCount],
] : [['车辆类型', vehicleTypeLabel(summary.vehicleType)]]),
[props.kind === 'trucking' ? 'B点取货地' : '起运地', read(summary, 'origin')], [props.kind === 'trucking' ? 'B点取货地址' : '起运地址', current.originAddress],
[props.kind === 'trucking' ? 'C点送达地' : '目的地', read(summary, 'destination')], [props.kind === 'trucking' ? 'C点送达地址' : '目的地址', current.destinationAddress],
[props.kind === 'trucking' ? '取货地' : '起运地', read(summary, 'origin')], [props.kind === 'trucking' ? '取货地址' : '起运地址', current.originAddress],
[props.kind === 'trucking' ? '送达地' : '目的地', read(summary, 'destination')], [props.kind === 'trucking' ? '送达地址' : '目的地址', current.destinationAddress],
['件数', read(summary, 'packageCount')], ['总重量(kg)', read(summary, 'totalWeightKg')],
['总体积(m³)', read(summary, 'totalVolumeCbm')], ['预算总价', money(read(summary, 'budgetAmount'), read(summary, 'currency'))],
[props.kind === 'trucking' ? 'B点联系人' : '起运地联系人', summary.originContactName], [props.kind === 'trucking' ? 'B点联系电话' : '起运地联系电话', summary.originContactPhone],
[props.kind === 'trucking' ? 'C点联系人' : '目的地联系人', summary.destinationContactName], [props.kind === 'trucking' ? 'C点联系电话' : '目的地联系电话', summary.destinationContactPhone],
[props.kind === 'trucking' ? 'B点取货时间' : '取货时间', localMinute(summary.pickupAt)], [props.kind === 'trucking' ? 'C点送达时间' : '送货时间', localMinute(summary.deliveryAt)], ['备注', current.remark],
[props.kind === 'trucking' ? '取货联系人' : '起运地联系人', summary.originContactName], [props.kind === 'trucking' ? '取货联系电话' : '起运地联系电话', summary.originContactPhone],
[props.kind === 'trucking' ? '送达联系人' : '目的地联系人', summary.destinationContactName], [props.kind === 'trucking' ? '送达联系电话' : '目的地联系电话', summary.destinationContactPhone],
[props.kind === 'trucking' ? '取货时间' : '取货时间', localMinute(summary.pickupAt)], [props.kind === 'trucking' ? '送达时间' : '送货时间', localMinute(summary.deliveryAt)], ['备注', current.remark],
]
})
@@ -216,7 +216,7 @@ function getRowActions(candidate: object): TableAction[] {
}
function detailFieldClass(label: unknown) {
return ['备注', props.kind === 'trucking' ? 'B点取货地址' : '起运地址', props.kind === 'trucking' ? 'C点送达地址' : '目的地址'].includes(String(label)) ? 'is-wide' : ''
return ['备注', props.kind === 'trucking' ? '取货地址' : '起运地址', props.kind === 'trucking' ? '送达地址' : '目的地址'].includes(String(label)) ? 'is-wide' : ''
}
const listRouteName = computed(() => ({
@@ -29,14 +29,14 @@ defineExpose({
<el-form-item v-if="kind === 'truck'" class="transport-demand-wide" label="车辆类型" prop="vehicleType">
<el-select v-model="model.vehicleType" placeholder=""><el-option label="15拖" value="PALLET_15" /><el-option label="30拖" value="PALLET_30" /></el-select>
</el-form-item>
<el-form-item :label="kind === 'truck' ? 'B点取货地' : '起运地'" prop="origin"><el-input v-model.trim="model.origin" maxlength="255" placeholder="城市 / 港口 / 州" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'C点送达地' : '目的地'" prop="destination"><el-input v-model.trim="model.destination" maxlength="255" placeholder="城市 / 州" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'B点联系人' : '起运地联系人'" prop="originContactName"><el-input v-model.trim="model.originContactName" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'C点联系人' : '目的地联系人'" prop="destinationContactName"><el-input v-model.trim="model.destinationContactName" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'B点联系电话' : '起运地联系电话'" prop="originContactPhone"><el-input v-model.trim="model.originContactPhone" type="tel" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'C点联系电话' : '目的地联系电话'" prop="destinationContactPhone"><el-input v-model.trim="model.destinationContactPhone" type="tel" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'B点取货地址' : '起运详细地址'"><el-input v-model.trim="model.originAddress" maxlength="500" placeholder="街道 / 门牌等补充信息(选填)" /></el-form-item>
<el-form-item :label="kind === 'truck' ? 'C点送达地址' : '目的详细地址'"><el-input v-model.trim="model.destinationAddress" maxlength="500" placeholder="街道 / 门牌等补充信息(选填)" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '取货地' : '起运地'" prop="origin"><el-input v-model.trim="model.origin" maxlength="255" placeholder="城市 / 港口 / 州" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '送达地' : '目的地'" prop="destination"><el-input v-model.trim="model.destination" maxlength="255" placeholder="城市 / 州" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '取货联系人' : '起运地联系人'" prop="originContactName"><el-input v-model.trim="model.originContactName" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '送达联系人' : '目的地联系人'" prop="destinationContactName"><el-input v-model.trim="model.destinationContactName" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '取货联系电话' : '起运地联系电话'" prop="originContactPhone"><el-input v-model.trim="model.originContactPhone" type="tel" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '送达联系电话' : '目的地联系电话'" prop="destinationContactPhone"><el-input v-model.trim="model.destinationContactPhone" type="tel" maxlength="128" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '取货地址' : '起运详细地址'"><el-input v-model.trim="model.originAddress" maxlength="500" placeholder="街道 / 门牌等补充信息(选填)" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '送达地址' : '目的详细地址'"><el-input v-model.trim="model.destinationAddress" maxlength="500" placeholder="街道 / 门牌等补充信息(选填)" /></el-form-item>
</div>
</section>
<section class="transport-demand-section">
@@ -58,8 +58,8 @@ defineExpose({
<el-select v-model="model.currency" aria-label="预算币种" placeholder=""><el-option label="USD" value="USD" /><el-option label="CNY" value="CNY" /></el-select>
</div></el-form-item>
<div />
<el-form-item :label="kind === 'truck' ? 'B点取货时间' : '取货时间'" prop="pickupAt"><el-date-picker v-model="model.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="kind === 'truck' ? 'C点送达时间' : '送货时间'" prop="deliveryAt"><el-date-picker v-model="model.deliveryAt" type="datetime" format="YYYY-MM-DD HH:mm" time-format="HH:mm" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="" /></el-form-item>
<el-form-item :label="kind === 'truck' ? '取货时间' : '取货时间'" prop="pickupAt"><el-date-picker v-model="model.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="kind === 'truck' ? '送达时间' : '送货时间'" prop="deliveryAt"><el-date-picker v-model="model.deliveryAt" type="datetime" format="YYYY-MM-DD HH:mm" time-format="HH:mm" value-format="YYYY-MM-DDTHH:mm:ss" placeholder="" /></el-form-item>
<el-form-item class="transport-demand-wide" label="备注"><el-input v-model="model.remark" type="textarea" :rows="3" maxlength="1000" show-word-limit placeholder="" /></el-form-item>
</div>
</section>
@@ -33,12 +33,12 @@ export function createTransportDemandForm(): TransportDemandForm {
}
const requiredText = (kind: TransportDemandKind) => ({
origin: kind === 'truck' ? 'B点取货地' : '起运地',
destination: kind === 'truck' ? 'C点送达地' : '目的地',
originContactName: kind === 'truck' ? 'B点联系人' : '起运地联系人',
originContactPhone: kind === 'truck' ? 'B点联系电话' : '起运地联系电话',
destinationContactName: kind === 'truck' ? 'C点联系人' : '目的地联系人',
destinationContactPhone: kind === 'truck' ? 'C点联系电话' : '目的地联系电话',
origin: kind === 'truck' ? '取货地' : '起运地',
destination: kind === 'truck' ? '送达地' : '目的地',
originContactName: kind === 'truck' ? '取货联系人' : '起运地联系人',
originContactPhone: kind === 'truck' ? '取货联系电话' : '起运地联系电话',
destinationContactName: kind === 'truck' ? '送达联系人' : '目的地联系人',
destinationContactPhone: kind === 'truck' ? '送达联系电话' : '目的地联系电话',
} as const)
export function localMinuteInput(value: unknown) {
@@ -57,7 +57,7 @@ export function transportDemandRules(kind: TransportDemandKind, form: TransportD
rules[field] = [{ required: true, type: 'number', min: 0, message: `${label}须为不小于 0 的数字`, trigger: 'change' }]
}
rules.budgetAmount = [{ type: 'number', min: 0, message: '预算总价不能小于 0', trigger: 'change' }]
const pickupLabel = kind === 'truck' ? 'B点取货时间' : '取货时间', deliveryLabel = kind === 'truck' ? 'C点送达时间' : '送货时间'
const pickupLabel = kind === 'truck' ? '取货时间' : '取货时间', deliveryLabel = kind === 'truck' ? '送达时间' : '送货时间'
rules.pickupAt = [{ required: true, message: `请选择${pickupLabel}`, trigger: 'change' }]
rules.deliveryAt = [{ required: true, message: `请选择${deliveryLabel}`, trigger: 'change' }, {
validator: (_rule, value, callback) => callback(value && form.pickupAt && localMinuteInput(value) < localMinuteInput(form.pickupAt) ? new Error(`${deliveryLabel}不能早于${pickupLabel}`) : undefined), trigger: 'change',
@@ -71,7 +71,7 @@ export function transportDemandError(kind: TransportDemandKind, form: TransportD
for (const [field, label] of Object.entries(labels)) {
if (!String(form[field as keyof typeof labels] || '').trim()) return `请输入${label}`
}
const pickupLabel = kind === 'truck' ? 'B点取货时间' : '取货时间', deliveryLabel = kind === 'truck' ? 'C点送达时间' : '送货时间'
const pickupLabel = kind === 'truck' ? '取货时间' : '取货时间', deliveryLabel = kind === 'truck' ? '送达时间' : '送货时间'
for (const [field, label] of [['pickupAt', pickupLabel], ['deliveryAt', deliveryLabel]] 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}`