|
|
@@ -0,0 +1,152 @@
|
|
|
+export interface WarehouseLayoutParsedLocation {
|
|
|
+ floor: number
|
|
|
+ x: number
|
|
|
+ y: number
|
|
|
+ depth: number
|
|
|
+}
|
|
|
+
|
|
|
+export interface WarehouseLayoutPosition {
|
|
|
+ gridRow: number
|
|
|
+ gridCol: number
|
|
|
+}
|
|
|
+
|
|
|
+interface LocalColumnAisleRule {
|
|
|
+ afterColumn: number
|
|
|
+ gapCols: number
|
|
|
+ rows?: number[]
|
|
|
+ rowRange?: [number, number]
|
|
|
+}
|
|
|
+
|
|
|
+interface GlobalColumnAisleRule {
|
|
|
+ breakpoint: number
|
|
|
+ excludeRows?: number[]
|
|
|
+ excludeRowRange?: [number, number]
|
|
|
+}
|
|
|
+
|
|
|
+interface WarehouseLayoutEnhancer {
|
|
|
+ supports: (level: number) => boolean
|
|
|
+ apply: (
|
|
|
+ currentPosition: WarehouseLayoutPosition,
|
|
|
+ parsedLocation: WarehouseLayoutParsedLocation
|
|
|
+ ) => 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
|
|
|
+ }
|
|
|
+ ]
|
|
|
+
|
|
|
+ // 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 && parsedLocation.x >= 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) && parsedLocation.x > rule.afterColumn) {
|
|
|
+ nextPosition = {
|
|
|
+ ...nextPosition,
|
|
|
+ gridCol: nextPosition.gridCol + rule.gapCols
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ return nextPosition
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const LAYOUT_ENHANCERS: WarehouseLayoutEnhancer[] = [firstFloorEnhancer]
|
|
|
+
|
|
|
+export const applyWarehouseLayoutEnhancement = (
|
|
|
+ level: number,
|
|
|
+ parsedLocation: WarehouseLayoutParsedLocation,
|
|
|
+ basePosition: WarehouseLayoutPosition
|
|
|
+) => {
|
|
|
+ return LAYOUT_ENHANCERS
|
|
|
+ .filter((enhancer) => enhancer.supports(level))
|
|
|
+ .reduce(
|
|
|
+ (currentPosition, enhancer) => enhancer.apply(currentPosition, parsedLocation),
|
|
|
+ basePosition
|
|
|
+ )
|
|
|
+}
|