This commit is contained in:
zlwu committed 2026-09-03 13:50:25 +08:00
1 parent 67d37a1f0e
commit 54a1ba0c5c
21 files changed
+8646 -7577

No files matched your search

+3 -3
View File
@@ -286,9 +286,10 @@
"284": "Community 284",
"285": "Community 285",
"286": "Community 286",
"287": "index.vue",
"288": "index.vue",
"289": "handleEdit",
"290": "index.js",
"291": "form.vue",
"292": "Community 292",
"293": "index.vue",
"294": "menuFavorite.ts",
@@ -296,6 +297,7 @@
"296": "Community 296",
"298": "error-handle.ts",
"299": "zh_CN.js",
"300": "emit",
"301": "ProcessStatusTag.vue",
"302": "Community 302",
"303": "Community 303",
@@ -306,7 +308,6 @@
"308": "Community 308",
"309": "Community 309",
"310": "Community 310",
"312": "loadUserOptions",
"314": "assignmentMatchesFilter",
"315": "Community 315",
"316": "Community 316",
@@ -336,7 +337,6 @@
"340": "Community 340",
"341": "Community 341",
"342": "error-handle.ts",
"343": "v2.4.2.1 - 2025-06-16",
"344": "ArtException.vue",
"346": "Community 346",
"347": "Community 347",
+1 -1
View File
@@ -1 +1 @@
/Users/wuzilong/work/00code/shanxia2.0/web-admin
.
@@ -286,8 +286,8 @@
"284": "Community 284",
"285": "Community 285",
"286": "Community 286",
"287": "pl-batch-print.ts",
"288": "syncStatsColumnWidths",
"287": "index.vue",
"288": "index.vue",
"289": "handleEdit",
"290": "index.js",
"291": "form.vue",
@@ -296,10 +296,10 @@
"294": "menuFavorite.ts",
"295": "Community 295",
"296": "Community 296",
"297": "zh_CN.js",
"297": "pool.ts",
"298": "error-handle.ts",
"299": "zh_CN.js",
"300": "index.vue",
"300": "emit",
"301": "ProcessStatusTag.vue",
"302": "Community 302",
"303": "Community 303",
@@ -310,9 +310,8 @@
"308": "Community 308",
"309": "Community 309",
"310": "Community 310",
"311": "index.vue",
"311": "pad",
"312": "loadUserOptions",
"313": "formatKgToTon",
"314": "assignmentMatchesFilter",
"315": "Community 315",
"316": "Community 316",
@@ -342,12 +341,9 @@
"340": "Community 340",
"341": "Community 341",
"342": "error-handle.ts",
"343": "v2.4.2.1 - 2025-06-16",
"344": "ArtException.vue",
"345": "loadUserOptions",
"346": "Community 346",
"347": "Community 347",
"348": "pad",
"349": "Community 349",
"350": "Community 350",
"355": "Community 355",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -205,11 +205,25 @@
:bundle="vehicleBundle"
/>
<PlPlanFormDialog
v-model:visible="planEditFormVisible"
:plan-id="planId"
plan-edit-only
@success="handlePlanEditSuccess"
/>
<template #footer>
<div class="dialog-footer pl-arrange-footer">
<el-button @click="innerVisible = false">
<el-icon><Close /></el-icon>取消
</el-button>
<el-button
type="danger"
:disabled="loading || !planId || plan.followStatus === 'cancelled'"
@click="handleOpenPlanEdit"
>
<el-icon><Edit /></el-icon>编辑运输计划
</el-button>
<el-button
v-if="!isAdjustMode"
:loading="draftLoading"
@@ -226,7 +240,7 @@
</template>
<script setup lang="ts">
import { Check, Close, Document } from '@element-plus/icons-vue'
import { Check, Close, Document, Edit } from '@element-plus/icons-vue'
import { fetchProductDetail, type ProductDetail } from '@/api/crm/product'
import {
inboundOrderApi,
@@ -244,6 +258,7 @@
import PlPlanArchiveSegmentBlock, {
type ArchiveSegmentMeta
} from '@/components/business/pl-plan-archive-segment-block/index.vue'
import PlPlanFormDialog from '@/components/business/pl-plan-form-dialog/index.vue'
import PlPlanStopsSplitShell from '@/components/business/pl-plan-stops-split-shell/index.vue'
import PlPlanViewTabs from '@/components/business/pl-plan-view-tabs/index.vue'
import PlVehicleSummaryStrip from '@/components/business/pl-vehicle-summary-strip/index.vue'
@@ -292,6 +307,7 @@
const activeTab = ref<'archive' | 'overview'>('archive')
const tabsRef = ref<InstanceType<typeof PlPlanViewTabs> | null>(null)
const vehicleViewVisible = ref(false)
const planEditFormVisible = ref(false)
const plan = ref<Partial<Plan>>({})
const {
@@ -1193,7 +1209,7 @@
}
}
async function handleOpened() {
async function reloadArchiveContent() {
if (!props.planId) return
loading.value = true
resetState()
@@ -1239,14 +1255,44 @@
await applyFreightPrefill(data)
initFeedbackAttachmentEdits()
} catch (error) {
innerVisible.value = false
const message = error instanceof Error ? error.message : '加载运输计划失败'
ElMessage.error(message.includes('加载') ? message : `加载运输计划失败:${message}`)
throw error
} finally {
loading.value = false
}
}
function handleOpenPlanEdit() {
if (!props.planId || plan.value.followStatus === 'cancelled') return
ElMessage.info({
message: '修改计划信息后,归档填写区将自动刷新,请核对装卸货数量与品牌归档。',
duration: 4000
})
planEditFormVisible.value = true
}
async function handlePlanEditSuccess() {
planEditFormVisible.value = false
activeTab.value = 'archive'
try {
await reloadArchiveContent()
tabsRef.value?.reload()
emit('success')
} catch {
// reloadArchiveContent 已提示错误
}
}
async function handleOpened() {
if (!props.planId) return
try {
await reloadArchiveContent()
} catch {
innerVisible.value = false
}
}
function handleClose() {
// destroy-on-close 由 el-dialog 处理
}
@@ -1450,7 +1496,7 @@
.pl-archive-tabs {
:deep(> .el-tabs__header) {
margin-bottom: 16px;
margin-bottom: 0;
}
/* 仅用顶部导航,内容区由下方面板接管 */
@@ -1461,6 +1507,7 @@
.pl-archive-tab-panel {
min-height: 360px;
margin-top: 20px;
}
.pl-arrange-form-scroll {
@@ -160,13 +160,19 @@
<div class="pl-plan-dibang-row">
<el-checkbox
:model-value="delivery.generateDibang === 1"
disabled
:disabled="readonly || !canManualDibang(delivery.customerName)"
@update:model-value="(checked) => handleDibangToggle(index, checked)"
>
生成地磅单({{ directionLabel(delivery.dibangDirection) }})
</el-checkbox>
<span
v-if="isPlInternalCustomerName(delivery.customerName)"
v-if="canManualDibang(delivery.customerName)"
class="pl-plan-dibang-row__hint"
>
该车辆地磅单可选,请自行勾选
</span>
<span
v-else-if="isPlInternalCustomerName(delivery.customerName)"
class="pl-plan-dibang-row__hint"
>
本段客户为内部客户时默认勾选
@@ -232,6 +238,7 @@
import PlPlanStopProductTable from '@/components/business/pl-plan-stop-product-table/index.vue'
import { resolveAddressNotesFill } from '@/utils/pl-address-notes-fill'
import {
canManualToggleStopDibang,
createEmptyDeliveryForm,
resolveStopDibangDefaults,
sumStopProductsPlanQty,
@@ -254,6 +261,8 @@
excludePlanId?: string
/** 装货段产品,用于「送货产品不在装货列表」软提醒 */
loadProducts?: PlanStopProductFormRow[]
/** 当前计划车牌(主牌),用于地磅可选车例外 */
vehiclePlate?: string
}>(),
{
tabMode: true,
@@ -262,7 +271,8 @@
qtyUnitLabel: '',
showSplitHint: false,
excludePlanId: '',
loadProducts: () => []
loadProducts: () => [],
vehiclePlate: ''
}
)
@@ -535,7 +545,7 @@
(item) => String(item.id) === String(customerId)
)
const customerName = customer?.customerName || ''
const defaults = resolveStopDibangDefaults(customerName, 'delivery')
const defaults = resolveStopDibangDefaults(customerName, 'delivery', props.vehiclePlate)
patchDelivery(index, {
customerId: String(customerId),
customerName,
@@ -573,11 +583,16 @@
}
}
function canManualDibang(customerName?: string | null) {
return canManualToggleStopDibang(customerName, props.vehiclePlate)
}
function handleDibangToggle(index: number, checked: boolean) {
const delivery = props.modelValue[index]
// 仅山峡/云栋可生成地磅单,且由客户类型自动决定,不允许手动勾选
if (!isPlInternalCustomerName(delivery?.customerName)) {
patchDelivery(index, { generateDibang: 0, dibangDirection: 'none' })
if (!canManualDibang(delivery?.customerName)) {
if (!isPlInternalCustomerName(delivery?.customerName)) {
patchDelivery(index, { generateDibang: 0, dibangDirection: 'none' })
}
return
}
patchDelivery(index, {
@@ -192,6 +192,7 @@
v-model="loadForm"
compact-products
:exclude-plan-id="planId || ''"
:vehicle-plate="currentVehiclePlate"
@open-customer-picker="openCustomerSelector('load')"
@add-products="openProductSelector('load')"
/>
@@ -233,6 +234,7 @@
:show-split-hint="showDeliverySplitHint"
:exclude-plan-id="planId || ''"
:load-products="loadForm.products"
:vehicle-plate="currentVehiclePlate"
@active-index-change="deliveryActiveIndex = $event"
@open-customer-picker="openCustomerSelector('delivery', $event)"
@sync-products="syncDeliveryProductsFromLoadManual"
@@ -377,6 +379,7 @@
enrichStopProductsDisplayFromPlan,
mapLoadProductsToPlanFormRows,
mergePlanProductsFromLoadMirror,
resolveStopDibangDefaults,
sumStopProductsPlanQty,
syncDeliveriesProductsFromLoad,
type PlanDeliveryForm,
@@ -426,6 +429,8 @@
copyFromPlanId?: string
/** 从列表/详情「安排运输」「调整运输」进入时展开安排区块 */
openForArrange?: boolean
/** 归档等场景:仅保存计划,不展示暂存/安排运输(已安排计划也显示「保存」) */
planEditOnly?: boolean
}>()
const emit = defineEmits<{
@@ -497,14 +502,19 @@
const selectedDriverId = ref('')
/** 已安排:禁止仅「保存」,须走保存并安排/调整运输,避免计划与地磅等联动字段脱节 */
const showSaveButton = computed(() => loadedTransportStatus.value !== 'arranged')
const showSaveButton = computed(() => {
if (props.planEditOnly && isEdit.value) return true
return loadedTransportStatus.value !== 'arranged'
})
const showDraftButton = computed(() => {
if (props.planEditOnly) return false
if (!isEdit.value) return true
return (
loadedFollowStatus.value === 'drafting' || loadedFollowStatus.value === 'pending_arrange'
)
})
const showSaveAndArrangeButton = computed(() => {
if (props.planEditOnly) return false
if (!isEdit.value) return true
if (props.openForArrange && loadedTransportStatus.value === 'arranged') return false
return loadedTransportStatus.value === 'pending' || loadedTransportStatus.value === 'arranged'
@@ -512,7 +522,7 @@
const isRearrangeMode = computed(
() => loadedTransportStatus.value === 'arranged' && Boolean(props.openForArrange)
)
const showRearrangeButton = computed(() => isRearrangeMode.value)
const showRearrangeButton = computed(() => !props.planEditOnly && isRearrangeMode.value)
const saveButtonLabel = computed(() => (isEdit.value ? '保存' : '创建'))
const saveAndArrangeButtonLabel = computed(() => {
if (!isEdit.value) return '创建并安排运输'
@@ -766,6 +776,35 @@
vehicleList.value.find((item) => item.id === formData.vehicleId)
)
const currentVehiclePlate = computed(() => {
const fromList = (selectedVehicle.value?.licensePlate || '').trim()
if (fromList) return fromList
return (vehicleBundle.value?.detail?.licensePlate || '').trim()
})
/** 按当前车牌重算各段地磅默认勾选(换车时调用;编辑回填勿调用以免覆盖已存值) */
function reapplyStopDibangByVehiclePlate(plate?: string | null) {
const vehiclePlate = (plate ?? currentVehiclePlate.value) || ''
const loadDefaults = resolveStopDibangDefaults(
loadForm.value.customerName,
'load',
vehiclePlate
)
loadForm.value = {
...loadForm.value,
generateDibang: loadDefaults.generateDibang,
dibangDirection: loadDefaults.dibangDirection
}
deliveryForms.value = deliveryForms.value.map((row) => {
const defaults = resolveStopDibangDefaults(row.customerName, 'delivery', vehiclePlate)
return {
...row,
generateDibang: defaults.generateDibang,
dibangDirection: defaults.dibangDirection
}
})
}
const summaryCarrierName = computed(() => {
const carrier = carrierList.value.find((item) => item.id === formData.carrierId)
if (carrier?.carrierName) return carrier.carrierName
@@ -1050,9 +1089,10 @@
function applyStopsFromPlan(data: Plan) {
stopFormsReady.value = false
const plate = data.licensePlate || ''
if (data.load || data.deliveries?.length) {
loadForm.value = mapLoadFromApi(data.load)
deliveryForms.value = mapDeliveriesFromApi(data.deliveries)
loadForm.value = mapLoadFromApi(data.load, plate)
deliveryForms.value = mapDeliveriesFromApi(data.deliveries, plate)
} else {
const legacy = mapLegacyPlanToStops(data)
loadForm.value = legacy.load
@@ -1696,7 +1736,7 @@
if (data.vehicleId) {
await ensureSelectedVehicleOption(data.vehicleId)
await handleVehicleChange(data.vehicleId)
await handleVehicleChange(data.vehicleId, { syncStopDibang: false })
}
if (data.driverId) {
selectedDriverId.value = data.driverId
@@ -1762,6 +1802,7 @@
formData.carrierId = ''
selectedDriverId.value = ''
vehicleBundle.value = null
reapplyStopDibangByVehiclePlate('')
freightCalc.resetFreightCalc()
syncSelectedCustomerOptions()
} catch (e) {
@@ -1790,11 +1831,16 @@
selectedDriverId.value = defaultDriver?.personnelId || ''
}
async function handleVehicleChange(vehicleId: string) {
async function handleVehicleChange(
vehicleId: string,
opts?: { syncStopDibang?: boolean }
) {
const syncStopDibang = opts?.syncStopDibang !== false
vehicleBundle.value = null
selectedDriverId.value = ''
if (!vehicleId) {
formData.carrierId = ''
if (syncStopDibang) reapplyStopDibangByVehiclePlate('')
return
}
@@ -1818,6 +1864,12 @@
} finally {
vehicleLoading.value = false
}
if (syncStopDibang) {
const plate =
(vehicle?.licensePlate || '').trim() ||
(vehicleBundle.value?.detail?.licensePlate || '').trim()
reapplyStopDibangByVehiclePlate(plate)
}
}
async function handleVehicleLibrarySelect(vehicle: Vehicle) {
@@ -108,12 +108,15 @@
<div class="pl-plan-dibang-row">
<el-checkbox
:model-value="modelValue.generateDibang === 1"
disabled
:disabled="readonly || !canManualDibang"
@update:model-value="handleDibangToggle"
>
生成地磅单({{ dibangDirectionLabel }})
</el-checkbox>
<span v-if="isInternal" class="pl-plan-dibang-row__hint">本段客户为内部客户时默认勾选</span>
<span v-if="canManualDibang" class="pl-plan-dibang-row__hint">
该车辆地磅单可选,请自行勾选
</span>
<span v-else-if="isInternal" class="pl-plan-dibang-row__hint">本段客户为内部客户时默认勾选</span>
<span v-else-if="modelValue.customerId" class="pl-plan-dibang-row__hint">
仅安庆山峡/安徽云栋可生成地磅单
</span>
@@ -162,7 +165,11 @@
import PlPlanContractMultiSelect from '@/components/business/pl-plan-contract-multi-select/index.vue'
import PlPlanStopProductTable from '@/components/business/pl-plan-stop-product-table/index.vue'
import { resolveAddressNotesFill } from '@/utils/pl-address-notes-fill'
import { resolveStopDibangDefaults, type PlanLoadForm } from '@/utils/pl-plan-stop-form'
import {
canManualToggleStopDibang,
resolveStopDibangDefaults,
type PlanLoadForm
} from '@/utils/pl-plan-stop-form'
import { isPlInternalCustomerName } from '@/utils/pl-internal-customer'
import { pickBxData } from '@/utils/http/bx'
@@ -173,11 +180,14 @@
compactProducts?: boolean
/** 编辑计划时排除本计划占用 */
excludePlanId?: string
/** 当前计划车牌(主牌),用于地磅可选车例外 */
vehiclePlate?: string
}>(),
{
readonly: false,
compactProducts: true,
excludePlanId: ''
excludePlanId: '',
vehiclePlate: ''
}
)
@@ -198,6 +208,9 @@
const customerOptionsLoading = ref(false)
const isInternal = computed(() => isPlInternalCustomerName(props.modelValue.customerName))
const canManualDibang = computed(() =>
canManualToggleStopDibang(props.modelValue.customerName, props.vehiclePlate)
)
const stopContractId = computed(() => {
const id = String(props.modelValue.contracts?.[0]?.contractId || '').trim()
@@ -365,7 +378,7 @@
}
const customer = customerOptions.value.find((item) => String(item.id) === String(customerId))
const customerName = customer?.customerName || ''
const defaults = resolveStopDibangDefaults(customerName, 'load')
const defaults = resolveStopDibangDefaults(customerName, 'load', props.vehiclePlate)
patch({
customerId: String(customerId),
customerName,
@@ -403,9 +416,11 @@
}
function handleDibangToggle(checked: boolean) {
// 仅山峡/云栋可生成地磅单,且由客户类型自动决定,不允许手动勾选
if (!isInternal.value) {
patch({ generateDibang: 0, dibangDirection: 'none' })
// 非可手动场景:外部客户强制不勾;内部非可选车由默认值锁定,忽略手动切换
if (!canManualDibang.value) {
if (!isInternal.value) {
patch({ generateDibang: 0, dibangDirection: 'none' })
}
return
}
patch({
@@ -2,7 +2,7 @@
<el-dialog
v-model="innerVisible"
title="从地址库选择"
width="1200px"
width="1320px"
align-center
destroy-on-close
append-to-body
@@ -74,6 +74,12 @@
align="center"
header-align="center"
/>
<el-table-column
prop="notes"
label="注意事项"
min-width="160"
show-overflow-tooltip
/>
<el-table-column
label="操作"
min-width="160"
@@ -0,0 +1,59 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import {
canManualToggleStopDibang,
resolveStopDibangDefaults
} from './pl-plan-stop-form'
import { isPlDibangOptionalVehiclePlate } from './pl-internal-customer'
const INTERNAL = '安庆市山峡化工有限公司'
const YUNDONG = '安徽云栋化工有限公司'
const EXTERNAL = '某某贸易有限公司'
const OPTIONAL_PLATE = '皖H21522'
describe('isPlDibangOptionalVehiclePlate', () => {
it('matches exact main plate', () => {
assert.equal(isPlDibangOptionalVehiclePlate(OPTIONAL_PLATE), true)
assert.equal(isPlDibangOptionalVehiclePlate(` ${OPTIONAL_PLATE} `), true)
})
it('rejects other plates', () => {
assert.equal(isPlDibangOptionalVehiclePlate('皖A12345'), false)
assert.equal(isPlDibangOptionalVehiclePlate(''), false)
})
})
describe('resolveStopDibangDefaults + canManualToggleStopDibang', () => {
it('internal + normal vehicle: auto-check, not manual', () => {
assert.deepEqual(resolveStopDibangDefaults(INTERNAL, 'load', '皖A11111'), {
generateDibang: 1,
dibangDirection: 'outbound'
})
assert.deepEqual(resolveStopDibangDefaults(YUNDONG, 'delivery', '皖A11111'), {
generateDibang: 1,
dibangDirection: 'inbound'
})
assert.equal(canManualToggleStopDibang(INTERNAL, '皖A11111'), false)
})
it('internal + optional vehicle: unchecked, manual allowed', () => {
assert.deepEqual(resolveStopDibangDefaults(INTERNAL, 'load', OPTIONAL_PLATE), {
generateDibang: 0,
dibangDirection: 'none'
})
assert.deepEqual(resolveStopDibangDefaults(YUNDONG, 'delivery', OPTIONAL_PLATE), {
generateDibang: 0,
dibangDirection: 'none'
})
assert.equal(canManualToggleStopDibang(INTERNAL, OPTIONAL_PLATE), true)
assert.equal(canManualToggleStopDibang(YUNDONG, OPTIONAL_PLATE), true)
})
it('external + optional vehicle: still locked off', () => {
assert.deepEqual(resolveStopDibangDefaults(EXTERNAL, 'load', OPTIONAL_PLATE), {
generateDibang: 0,
dibangDirection: 'none'
})
assert.equal(canManualToggleStopDibang(EXTERNAL, OPTIONAL_PLATE), false)
})
})
@@ -4,11 +4,22 @@ export const PL_INTERNAL_CUSTOMER_NAMES = [
'安徽云栋化工有限公司'
] as const
/**
* 地磅单「可选」车辆主牌:内部客户时默认不勾且允许手动勾选。
* 匹配主牌精确值(不含挂车拼接)。
*/
export const PL_DIBANG_OPTIONAL_VEHICLE_PLATES = ['皖H21522'] as const
export function isPlInternalCustomerName(name?: string | null): boolean {
const n = (name || '').trim()
return (PL_INTERNAL_CUSTOMER_NAMES as readonly string[]).includes(n)
}
export function isPlDibangOptionalVehiclePlate(plate?: string | null): boolean {
const p = (plate || '').trim()
return (PL_DIBANG_OPTIONAL_VEHICLE_PLATES as readonly string[]).includes(p)
}
/** 装货或送货段任一段客户为山峡/云栋时,需要现场链接。 */
export function planRequiresSiteLink(
plan?: {
+43 -12
View File
@@ -2,7 +2,10 @@ import type { Plan, PlanContractLink, PlanDelivery, PlanLoad, PlanStopProduct }
import type { PlanFormProductRow } from '@/composables/usePlContractToPlan'
import type { BrandOption } from '@/utils/crm-product-brand'
import { formatBrandConstraintLabel } from '@/utils/crm-product-brand'
import { isPlInternalCustomerName } from '@/utils/pl-internal-customer'
import {
isPlDibangOptionalVehiclePlate,
isPlInternalCustomerName
} from '@/utils/pl-internal-customer'
export interface PlanStopProductFormRow {
id?: string
@@ -111,27 +114,45 @@ export interface PlanDeliveryForm {
products: PlanStopProductFormRow[]
}
/** 地磅勾选仅对内部客户(山峡/云栋)生效:默认勾选且不可改;其他客户默认不勾且不可勾。 */
/**
* 地磅勾选规则:
* - 内部客户(山峡/云栋):默认勾选且不可改
* - 地磅可选车(如皖H21522)+ 内部客户:默认不勾,可手动勾选
* - 其他客户:默认不勾且不可勾
*/
export function resolveStopDibangDefaults(
customerName?: string | null,
stopType: 'load' | 'delivery' = 'load'
stopType: 'load' | 'delivery' = 'load',
vehiclePlate?: string | null
): { generateDibang: number; dibangDirection: string } {
if (!isPlInternalCustomerName(customerName)) {
return { generateDibang: 0, dibangDirection: 'none' }
}
if (isPlDibangOptionalVehiclePlate(vehiclePlate)) {
return { generateDibang: 0, dibangDirection: 'none' }
}
if (stopType === 'load') {
return { generateDibang: 1, dibangDirection: 'outbound' }
}
return { generateDibang: 1, dibangDirection: 'inbound' }
}
/** 仅「内部客户 + 地磅可选车」允许用户手动勾选地磅单 */
export function canManualToggleStopDibang(
customerName?: string | null,
vehiclePlate?: string | null
): boolean {
return isPlInternalCustomerName(customerName) && isPlDibangOptionalVehiclePlate(vehiclePlate)
}
function normalizeStopDibangFieldsFromApi(
customerName: string | null | undefined,
stopType: 'load' | 'delivery',
generateDibang?: number | null,
dibangDirection?: string | null
dibangDirection?: string | null,
vehiclePlate?: string | null
): { generateDibang: number; dibangDirection: string } {
const defaults = resolveStopDibangDefaults(customerName, stopType)
const defaults = resolveStopDibangDefaults(customerName, stopType, vehiclePlate)
// 非山峡/云栋:禁止生成地磅单(编辑回填也强制清掉历史勾选)
if (!isPlInternalCustomerName(customerName)) {
return { generateDibang: 0, dibangDirection: 'none' }
@@ -140,7 +161,8 @@ function normalizeStopDibangFieldsFromApi(
let direction = (dibangDirection || '').trim()
if (gen) {
if (direction !== 'outbound' && direction !== 'inbound') {
direction = defaults.dibangDirection
// 可选车默认 direction 为 none,勾选回填时按段类型补方向
direction = stopType === 'load' ? 'outbound' : 'inbound'
}
} else {
direction = 'none'
@@ -409,13 +431,17 @@ export function resolveDeliveryViewAddress(
return ''
}
export function mapLoadFromApi(load?: PlanLoad | null): PlanLoadForm {
export function mapLoadFromApi(
load?: PlanLoad | null,
vehiclePlate?: string | null
): PlanLoadForm {
if (!load) return createEmptyLoadForm()
const dibang = normalizeStopDibangFieldsFromApi(
load.customerName,
'load',
load.generateDibang,
load.dibangDirection
load.dibangDirection,
vehiclePlate
)
return {
customerId: load.customerId || '',
@@ -436,14 +462,18 @@ export function mapLoadFromApi(load?: PlanLoad | null): PlanLoadForm {
}
}
export function mapDeliveriesFromApi(deliveries?: PlanDelivery[]): PlanDeliveryForm[] {
export function mapDeliveriesFromApi(
deliveries?: PlanDelivery[],
vehiclePlate?: string | null
): PlanDeliveryForm[] {
if (!deliveries?.length) return [createEmptyDeliveryForm(1)]
return deliveries.map((row, index) => {
const dibang = normalizeStopDibangFieldsFromApi(
row.customerName,
'delivery',
row.generateDibang,
row.dibangDirection
row.dibangDirection,
vehiclePlate
)
return {
seq: row.seq ?? index + 1,
@@ -471,8 +501,9 @@ export function mapLegacyPlanToStops(plan: Plan): {
load: PlanLoadForm
deliveries: PlanDeliveryForm[]
} {
const loadDefaults = resolveStopDibangDefaults(plan.supplierName, 'load')
const deliveryDefaults = resolveStopDibangDefaults(plan.customerName, 'delivery')
const plate = plan.licensePlate
const loadDefaults = resolveStopDibangDefaults(plan.supplierName, 'load', plate)
const deliveryDefaults = resolveStopDibangDefaults(plan.customerName, 'delivery', plate)
const stopProducts = createStopProductsFromPlanProducts(
(plan.products || []).map((item, index) => ({
id: item.id,