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

@@ -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,