feat: span transport plan list by plan and delivery column props

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-10-06 09:32:01 +08:00
1 parent e241a17077
commit 47cd09d1e5
2 files changed
+155 -12

No files matched your search

@@ -2,8 +2,12 @@ import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import type { Plan, PlanStopProduct } from '@/api/pl'
import {
buildPlPlanListSpanMethod,
flattenPlanArchivePairRows,
matchLoadProduct
flattenPlanListRows,
matchLoadProduct,
PL_DELIVERY_SPAN_PROPS,
PL_PLAN_SPAN_PROPS
} from './pl-plan-list-display-rows'
function sp(partial: Partial<PlanStopProduct> & Pick<PlanStopProduct, 'productId'>): PlanStopProduct {
@@ -93,3 +97,95 @@ describe('flattenPlanArchivePairRows product rows', () => {
assert.equal(rows[0].deliveryRowSpan, 1)
})
})
describe('buildPlPlanListSpanMethod two-level', () => {
it('merges plan and delivery columns independently', () => {
const rows = flattenPlanArchivePairRows([samplePlan()])
const span = buildPlPlanListSpanMethod()
const planFirst = span({
row: rows[0],
column: { property: 'loadCustomer' },
rowIndex: 0,
columnIndex: 0
})
assert.deepEqual(planFirst, { rowspan: 3, colspan: 1 })
const planSecond = span({
row: rows[1],
column: { property: 'loadCustomer' },
rowIndex: 1,
columnIndex: 0
})
assert.deepEqual(planSecond, { rowspan: 0, colspan: 0 })
const delFirst = span({
row: rows[0],
column: { property: 'deliveryCustomer' },
rowIndex: 0,
columnIndex: 0
})
assert.deepEqual(delFirst, { rowspan: 2, colspan: 1 })
const delThird = span({
row: rows[2],
column: { property: 'deliveryCustomer' },
rowIndex: 2,
columnIndex: 0
})
assert.deepEqual(delThird, { rowspan: 1, colspan: 1 })
const leaf = span({
row: rows[0],
column: { property: 'productName' },
rowIndex: 0,
columnIndex: 0
})
assert.equal(leaf, undefined)
const sel = span({
row: rows[0],
column: { type: 'selection' },
rowIndex: 0,
columnIndex: 0
})
assert.deepEqual(sel, { rowspan: 3, colspan: 1 })
assert.equal(PL_PLAN_SPAN_PROPS.has('loadAddressTime'), true)
assert.equal(PL_DELIVERY_SPAN_PROPS.has('deliveryContract'), true)
})
it('non-pair rows merge only plan columns by planRowSpan', () => {
const rows = flattenPlanListRows([samplePlan()])
const span = buildPlPlanListSpanMethod([], 3)
assert.deepEqual(
span({
row: rows[0],
column: { property: 'planDate' },
rowIndex: 0,
columnIndex: 0
}),
{ rowspan: 3, colspan: 1 }
)
assert.deepEqual(
span({
row: rows[1],
column: { property: 'planDate' },
rowIndex: 1,
columnIndex: 0
}),
{ rowspan: 0, colspan: 0 }
)
assert.equal(
span({
row: rows[1],
column: { property: 'deliveryCustomer' },
rowIndex: 1,
columnIndex: 0
}),
undefined
)
assert.equal(
span({
row: rows[2],
column: { property: 'deliveryContract' },
rowIndex: 2,
columnIndex: 0
}),
undefined
)
})
})
@@ -18,7 +18,7 @@ export interface PlPlanListDisplayRow {
stop: PlanLoad | PlanDelivery
deliverySeq?: number
/**
* 归档配对行:一行 = 装货 × 一送货。
* 归档配对行:一行 = 送货段 × 一产品。
* 为 true 时 stop 为送货段,pairLoad 为装货段;kind 固定为 delivery。
*/
isPairRow?: boolean
@@ -177,7 +177,7 @@ const EMPTY_DELIVERY_STOP: PlanDelivery = {
}
/**
* 归档列表配对展平:一行 = 装货 × 一个送货。
* 归档列表配对展平:一行 = 送货段 × 一个产品(带配对装货产品)。
* 无送货段时仍输出一行(送货侧为空),避免有装无送时整单消失。
*/
export function flattenPlanArchivePairRows(
@@ -469,23 +469,70 @@ export function isPlPlanListPlanMergeColumn(
return planColIndex >= 0 && planColIndex < visiblePlanProps.length
}
export const PL_PLAN_SPAN_PROPS = new Set([
'planNo',
'followStatus',
'planDate',
'deliveryTimes',
'planType',
'licensePlate',
'personnelSummary',
'followUserName',
'arrangeCopy',
'archiveStatus',
'documentAttachments',
'erpEntered',
'planAttachments',
'carrierName',
'hazardCertReady',
'loadCustomer',
'loadAddressTime',
'loadContract',
'loadDibang',
'loadContractGap'
])
export const PL_DELIVERY_SPAN_PROPS = new Set([
'deliveryCustomer',
'deliveryAddressTime',
'deliveryContract',
'deliveryDibang',
'deliveryContractGap'
])
export function buildPlPlanListSpanMethod(
visiblePlanProps: string[],
fixedMergeColCount: number = PLAN_FIXED_MERGE_COL_COUNT
_visiblePlanProps?: string[],
_fixedMergeColCount?: number
): (args: {
row: PlPlanListDisplayRow
column: { type?: string; property?: string }
rowIndex: number
columnIndex: number
}) => { rowspan: number; colspan: number } | undefined {
const fixed = Math.max(0, fixedMergeColCount)
const planMergeCount = fixed + visiblePlanProps.length
return ({ row, columnIndex }) => {
if (columnIndex >= planMergeCount) return undefined
if (row.isPlanFirstRow) {
return { rowspan: row.planRowSpan, colspan: 1 }
return ({ row, column }) => {
const type = column?.type
const prop = column?.property || ''
const isPlanCol =
type === 'selection' || type === 'index' || PL_PLAN_SPAN_PROPS.has(prop)
const isDeliveryCol = PL_DELIVERY_SPAN_PROPS.has(prop)
if (!row.isPairRow) {
if (isPlanCol) {
if (row.isPlanFirstRow) return { rowspan: row.planRowSpan, colspan: 1 }
return { rowspan: 0, colspan: 0 }
}
return undefined
}
return { rowspan: 0, colspan: 0 }
if (isPlanCol) {
if (row.isPlanFirstRow) return { rowspan: row.planRowSpan, colspan: 1 }
return { rowspan: 0, colspan: 0 }
}
if (isDeliveryCol) {
if (row.isDeliveryFirstRow) return { rowspan: row.deliveryRowSpan || 1, colspan: 1 }
return { rowspan: 0, colspan: 0 }
}
return undefined
}
}