handy преди 1 месец
родител
ревизия
ce2453de6f
променени са 1 файла, в които са добавени 184 реда и са изтрити 157 реда
  1. 184 157
      src/components/warehouse-layout-enhancers.ts

+ 184 - 157
src/components/warehouse-layout-enhancers.ts

@@ -10,24 +10,34 @@ export interface WarehouseLayoutPosition {
   gridCol: number
 }
 
-interface LocalColumnAisleRule {
+type RowRange = readonly [number, number]
+
+interface RowScopedRule {
+  rows?: readonly number[]
+  rowRange?: RowRange
+}
+
+interface LocalColumnAisleRule extends RowScopedRule {
   afterColumn: number
   gapCols: number
-  rows?: number[]
-  rowRange?: [number, number]
 }
 
-interface LocalColumnShiftRule {
+interface LocalColumnShiftRule extends RowScopedRule {
   startColumn: number
   shiftCols: number
-  rows?: number[]
-  rowRange?: [number, number]
 }
 
 interface GlobalColumnAisleRule {
   breakpoint: number
-  excludeRows?: number[]
-  excludeRowRange?: [number, number]
+  excludeRows?: readonly number[]
+  excludeRowRange?: RowRange
+}
+
+interface WarehouseLayoutRuleSet {
+  rowAisleBreakpoints: readonly number[]
+  globalColumnAisles: readonly GlobalColumnAisleRule[]
+  localColumnAisles: readonly LocalColumnAisleRule[]
+  localColumnShifts: readonly LocalColumnShiftRule[]
 }
 
 interface WarehouseLayoutEnhancer {
@@ -38,160 +48,177 @@ interface WarehouseLayoutEnhancer {
   ) => WarehouseLayoutPosition
 }
 
-const firstFloorEnhancer: WarehouseLayoutEnhancer = {
-  supports: (level) => level === 1,
-  apply: (currentPosition, parsedLocation) => {
-    let nextPosition = currentPosition
-    const firstFloorRowAisleBreakpoints = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
-    const firstFloorGlobalColumnAisles: GlobalColumnAisleRule[] = [
-      { breakpoint: 1 },
-      {
-        breakpoint: 19,
-        excludeRows: [8, 9, 10, 11]
-      },
-      { breakpoint: 26 }
-    ]
-    const firstFloorLocalColumnAisles: LocalColumnAisleRule[] = [
-      {
-        rowRange: [0, 8],
-        afterColumn: 7,
-        gapCols: 1
-      },
-      {
-        rowRange: [11, 22],
-        afterColumn: 7,
-        gapCols: 1
-      },
-      {
-        rows: [9, 10],
-        afterColumn: 6,
-        gapCols: 3
-      },
-      {
-        rows: [9, 10],
-        afterColumn: 10,
-        gapCols: 1
-      },
-      {
-        rows: [8, 11],
-        afterColumn: 12,
-        gapCols: 1
-      },
-      {
-        rows: [8, 11],
-        afterColumn: 17,
-        gapCols: 1
-      },
-      {
-        rows: [9, 10],
-        afterColumn: 20,
-        gapCols: 1
-      },
-      {
-        rows: [8, 11],
-        afterColumn: 24,
-        gapCols: 1
-      },
-      {
-        rows: [9, 10],
-        afterColumn: 14,
-        gapCols: 3
-      }
-    ]
-    const firstFloorLocalColumnShifts: LocalColumnShiftRule[] = [
-      {
-        rows: [6, 13],
-        startColumn: 0,
-        shiftCols: 1
-      },
-      {
-        rows: [6, 13],
-        startColumn: 5,
-        shiftCols: 1
-      },
-      {
-        rows: [6, 13],
-        startColumn: 11,
-        shiftCols: 1
-      },
-      {
-        rows: [6, 13],
-        startColumn: 17,
-        shiftCols: 1
-      },
-      {
-        rows: [7],
-        startColumn: 20,
-        shiftCols: 1
-      }
-    ]
-
-    const columnShiftCount = firstFloorLocalColumnShifts.reduce((total, rule) => {
-      const matchedRows = rule.rows?.includes(parsedLocation.y) ?? false
-      const matchedRange = rule.rowRange
-        ? parsedLocation.y >= rule.rowRange[0] && parsedLocation.y <= rule.rowRange[1]
-        : false
-
-      if ((matchedRows || matchedRange) && parsedLocation.x >= rule.startColumn) {
-        return total + rule.shiftCols
-      }
-
-      return total
-    }, 0)
-    const effectiveColumn = parsedLocation.x + columnShiftCount
+const FIRST_FLOOR_RULE_SET: WarehouseLayoutRuleSet = {
+  rowAisleBreakpoints: [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22],
+  globalColumnAisles: [
+    { breakpoint: 1 },
+    {
+      breakpoint: 19,
+      excludeRows: [8, 9, 10, 11]
+    },
+    { breakpoint: 26 }
+  ],
+  localColumnAisles: [
+    {
+      rowRange: [0, 8],
+      afterColumn: 7,
+      gapCols: 1
+    },
+    {
+      rowRange: [11, 22],
+      afterColumn: 7,
+      gapCols: 1
+    },
+    {
+      rows: [9, 10],
+      afterColumn: 6,
+      gapCols: 3
+    },
+    {
+      rows: [9, 10],
+      afterColumn: 10,
+      gapCols: 1
+    },
+    {
+      rows: [8, 11],
+      afterColumn: 12,
+      gapCols: 1
+    },
+    {
+      rows: [8, 11],
+      afterColumn: 17,
+      gapCols: 1
+    },
+    {
+      rows: [9, 10],
+      afterColumn: 20,
+      gapCols: 1
+    },
+    {
+      rows: [8, 11],
+      afterColumn: 24,
+      gapCols: 1
+    },
+    {
+      rows: [9, 10],
+      afterColumn: 14,
+      gapCols: 3
+    }
+  ],
+  localColumnShifts: [
+    {
+      rows: [6, 13],
+      startColumn: 0,
+      shiftCols: 1
+    },
+    {
+      rows: [6, 13],
+      startColumn: 5,
+      shiftCols: 1
+    },
+    {
+      rows: [6, 13],
+      startColumn: 11,
+      shiftCols: 1
+    },
+    {
+      rows: [6, 13],
+      startColumn: 17,
+      shiftCols: 1
+    },
+    {
+      rows: [7],
+      startColumn: 20,
+      shiftCols: 1
+    }
+  ]
+}
+
+const matchesRowScope = (row: number, rule: RowScopedRule) => {
+  const matchedRows = rule.rows?.includes(row) ?? false
+  const matchedRange = rule.rowRange ? row >= rule.rowRange[0] && row <= rule.rowRange[1] : false
+
+  return matchedRows || matchedRange
+}
+
+const isRowExcluded = (row: number, rule: GlobalColumnAisleRule) => {
+  const excludedByRows = rule.excludeRows?.includes(row) ?? false
+  const excludedByRange = rule.excludeRowRange
+    ? row >= rule.excludeRowRange[0] && row <= rule.excludeRowRange[1]
+    : false
 
-    if (columnShiftCount > 0) {
-      nextPosition = {
-        ...nextPosition,
-        gridCol: nextPosition.gridCol + columnShiftCount
-      }
+  return excludedByRows || excludedByRange
+}
+
+const sumRowAisleOffsets = (row: number, breakpoints: readonly number[]) =>
+  breakpoints.reduce((total, breakpoint) => (row >= breakpoint ? total + 1 : total), 0)
+
+const sumGlobalColumnAisleOffsets = (
+  row: number,
+  effectiveColumn: number,
+  rules: readonly GlobalColumnAisleRule[]
+) =>
+  rules.reduce((total, rule) => {
+    if (!isRowExcluded(row, rule) && effectiveColumn >= rule.breakpoint) {
+      return total + 1
+    }
+
+    return total
+  }, 0)
+
+const sumLocalColumnAisleOffsets = (
+  row: number,
+  effectiveColumn: number,
+  rules: readonly LocalColumnAisleRule[]
+) =>
+  rules.reduce((total, rule) => {
+    if (matchesRowScope(row, rule) && effectiveColumn > rule.afterColumn) {
+      return total + rule.gapCols
+    }
+
+    return total
+  }, 0)
+
+const sumLocalColumnShiftOffsets = (
+  parsedLocation: WarehouseLayoutParsedLocation,
+  rules: readonly LocalColumnShiftRule[]
+) =>
+  rules.reduce((total, rule) => {
+    if (matchesRowScope(parsedLocation.y, rule) && parsedLocation.x >= rule.startColumn) {
+      return total + rule.shiftCols
     }
 
-    // 1 层增强规则:在指定列断点之间插入整列过道。
-    firstFloorGlobalColumnAisles.forEach((rule) => {
-      const excludedByRows = rule.excludeRows?.includes(parsedLocation.y) ?? false
-      const excludedByRange = rule.excludeRowRange
-        ? parsedLocation.y >= rule.excludeRowRange[0] && parsedLocation.y <= rule.excludeRowRange[1]
-        : false
-
-      if (!excludedByRows && !excludedByRange && effectiveColumn >= rule.breakpoint) {
-        nextPosition = {
-          ...nextPosition,
-          gridCol: nextPosition.gridCol + 1
-        }
-      }
-    })
-
-    // 1 层增强规则:在指定行断点之间插入整行过道。
-    firstFloorRowAisleBreakpoints.forEach((breakpoint) => {
-      if (parsedLocation.y >= breakpoint) {
-        nextPosition = {
-          ...nextPosition,
-          gridRow: nextPosition.gridRow + 1
-        }
-      }
-    })
-
-    // 1 层增强规则:指定行内在某列右侧插入局部整列过道。
-    firstFloorLocalColumnAisles.forEach((rule) => {
-      const matchedRows = rule.rows?.includes(parsedLocation.y) ?? false
-      const matchedRange = rule.rowRange
-        ? parsedLocation.y >= rule.rowRange[0] && parsedLocation.y <= rule.rowRange[1]
-        : false
-
-      if ((matchedRows || matchedRange) && effectiveColumn > rule.afterColumn) {
-        nextPosition = {
-          ...nextPosition,
-          gridCol: nextPosition.gridCol + rule.gapCols
-        }
-      }
-    })
-
-    return nextPosition
+    return total
+  }, 0)
+
+const createConfiguredEnhancer = (
+  level: number,
+  ruleSet: WarehouseLayoutRuleSet
+): WarehouseLayoutEnhancer => ({
+  supports: (currentLevel) => currentLevel === level,
+  apply: (currentPosition, parsedLocation) => {
+    const columnShiftCount = sumLocalColumnShiftOffsets(parsedLocation, ruleSet.localColumnShifts)
+    const effectiveColumn = parsedLocation.x + columnShiftCount
+    const gridColOffset =
+      columnShiftCount +
+      sumGlobalColumnAisleOffsets(
+        parsedLocation.y,
+        effectiveColumn,
+        ruleSet.globalColumnAisles
+      ) +
+      sumLocalColumnAisleOffsets(parsedLocation.y, effectiveColumn, ruleSet.localColumnAisles)
+    const gridRowOffset = sumRowAisleOffsets(parsedLocation.y, ruleSet.rowAisleBreakpoints)
+
+    return {
+      gridRow: currentPosition.gridRow + gridRowOffset,
+      gridCol: currentPosition.gridCol + gridColOffset
+    }
   }
-}
+})
 
-const LAYOUT_ENHANCERS: WarehouseLayoutEnhancer[] = [firstFloorEnhancer]
+const LAYOUT_ENHANCERS: WarehouseLayoutEnhancer[] = [
+  createConfiguredEnhancer(1, FIRST_FLOOR_RULE_SET)
+]
 
 export const applyWarehouseLayoutEnhancement = (
   level: number,