Просмотр исходного кода

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

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 3 недель назад
Родитель
Сommit
47cd09d1e5

+ 97 - 1
web-admin/src/utils/pl-plan-list-display-rows.test.ts

@@ -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
+    )
+  })
+})

+ 58 - 11
web-admin/src/utils/pl-plan-list-display-rows.ts

@@ -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
+    }
+
+    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 { rowspan: 0, colspan: 0 }
+    return undefined
   }
 }