瀏覽代碼

变更 1 楼库位规则和可以右键过道生成库位 sql

handy 2 周之前
父節點
當前提交
5c6e973766
共有 4 個文件被更改,包括 650 次插入315 次删除
  1. 30 0
      src/App.vue
  2. 599 0
      src/components/CreateLocationSqlModal.vue
  3. 18 2
      src/components/WarehouseMap.vue
  4. 3 313
      src/components/warehouse-layout-enhancers.ts

+ 30 - 0
src/App.vue

@@ -315,6 +315,15 @@
       </div>
     </div>
 
+    <CreateLocationSqlModal
+      :visible="createLocationSqlModalVisible"
+      :floor="createLocationSqlPayload.floor"
+      :x="createLocationSqlPayload.x"
+      :y="createLocationSqlPayload.y"
+      :theme-mode="isLightTheme ? 'light' : 'dark'"
+      @close="closeCreateLocationSqlModal"
+    />
+
     <main
       v-if="!showLoginModal"
       class="main-content"
@@ -353,6 +362,7 @@
             @select-loc-group="handleSelectLocGroup"
             @select-location-id="handleSelectLocationId"
             @selection-complete="handleSelectionComplete"
+            @create-location-sql="openCreateLocationSqlModal"
           />
         </WorkingHighlight>
       </div>
@@ -376,6 +386,7 @@ import type { LocationAttributeCode, LocationResourceDataVO } from './types'
 import WarehouseMap from './components/WarehouseMap.vue'
 import LoginModal from './components/LoginModal.vue'
 import WorkingHighlight from './components/WorkingHighlight.vue'
+import CreateLocationSqlModal from './components/CreateLocationSqlModal.vue'
 import { config } from './config'
 import { AUTH_INVALID_EVENT, getApiEnvironment, isAuthenticated, removeToken } from './utils/auth'
 
@@ -448,6 +459,12 @@ const appliedLocationIdKeyword = ref('')
 const showGroupBorder = ref(false)
 const showTooltip = ref(true)
 const selectionMode = ref(false)
+const createLocationSqlModalVisible = ref(false)
+const createLocationSqlPayload = ref({
+  floor: 1,
+  x: 0,
+  y: 0
+})
 const refreshIntervalMs = ref(getInitialRefreshInterval())
 const showRefreshPopover = ref(false)
 const refreshIntervalInput = ref(String(Math.max(Math.floor(refreshIntervalMs.value / 1000), 1)))
@@ -731,6 +748,19 @@ const handleSelectionComplete = () => {
   selectionMode.value = false
 }
 
+const openCreateLocationSqlModal = (payload: { floor: number; x: number; y: number }) => {
+  createLocationSqlPayload.value = {
+    floor: payload.floor,
+    x: payload.x,
+    y: payload.y
+  }
+  createLocationSqlModalVisible.value = true
+}
+
+const closeCreateLocationSqlModal = () => {
+  createLocationSqlModalVisible.value = false
+}
+
 const refreshCountdownText = computed(() => {
   const remainMs = Math.max(nextRefreshAt.value - now.value, 0)
   const totalSeconds = Math.floor(remainMs / 1000)

+ 599 - 0
src/components/CreateLocationSqlModal.vue

@@ -0,0 +1,599 @@
+<template>
+  <div
+    v-if="visible"
+    class="sql-modal-overlay"
+    @click.self="handleClose"
+  >
+    <div :class="['sql-modal', themeClass]">
+      <div class="sql-modal-header">
+        <h3>库位 SQL 生成</h3>
+        <button
+          class="sql-modal-close"
+          type="button"
+          @click="handleClose"
+        >
+          ×
+        </button>
+      </div>
+      <div class="sql-modal-body">
+        <div class="sql-form-grid sql-form-grid-auto">
+          <label class="sql-form-item">
+            <span>楼层</span>
+            <input
+              :value="form.floor"
+              class="sql-input"
+              type="text"
+              disabled
+            >
+          </label>
+          <label class="sql-form-item">
+            <span>X</span>
+            <input
+              :value="form.x"
+              class="sql-input"
+              type="text"
+              disabled
+            >
+          </label>
+          <label class="sql-form-item">
+            <span>Y</span>
+            <input
+              :value="form.y"
+              class="sql-input"
+              type="text"
+              disabled
+            >
+          </label>
+          <label class="sql-form-item sql-form-item-location-id">
+            <span>库位号</span>
+            <input
+              :value="generatedLocationId"
+              class="sql-input"
+              type="text"
+              disabled
+            >
+          </label>
+          <label class="sql-form-item">
+            <span>深位</span>
+            <input
+              :value="generatedDepth"
+              class="sql-input"
+              type="text"
+              disabled
+            >
+          </label>
+        </div>
+
+        <div class="sql-form-grid sql-form-grid-edit">
+          <label class="sql-form-item sql-form-item-category">
+            <span>热度</span>
+            <select
+              v-model="form.category"
+              class="sql-input sql-select"
+            >
+              <option value="A">A</option>
+              <option value="B">B</option>
+              <option value="C">C</option>
+            </select>
+          </label>
+          <label class="sql-form-item sql-form-item-group">
+            <span>库位组</span>
+            <input
+              v-model.trim="form.locGroup1"
+              class="sql-input"
+              type="text"
+            >
+          </label>
+          <label class="sql-form-item sql-form-item-wcs">
+            <span>WCS库位</span>
+            <input
+              v-model.trim="form.wcsLocationId"
+              class="sql-input"
+              required
+              type="text"
+              placeholder="请输入 wcs_location_id"
+            >
+          </label>
+          <div class="sql-form-item sql-form-item-copy">
+            <span class="sql-form-item-placeholder">操作</span>
+            <button
+              class="sql-copy-all-btn"
+              type="button"
+              :disabled="!canCopyAll"
+              @click="copyGeneratedSql(allGeneratedSql)"
+            >
+              {{ copyButtonText.all }}
+            </button>
+          </div>
+        </div>
+
+        <div class="sql-preview-block">
+          <pre class="sql-preview"><code>{{ baseLocationInsertSql }}</code></pre>
+        </div>
+
+        <div class="sql-preview-block">
+          <pre class="sql-preview"><code>{{ customLocationExtInsertSql }}</code></pre>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue'
+
+interface Props {
+  visible: boolean
+  floor: number
+  x: number
+  y: number
+  themeMode?: 'dark' | 'light'
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  themeMode: 'dark'
+})
+
+const emit = defineEmits<{
+  (event: 'close'): void
+}>()
+
+const CATEGORY_DEPTH_MAP: Record<'A' | 'B' | 'C', 1 | 2 | 3> = {
+  A: 1,
+  B: 2,
+  C: 3
+}
+
+const form = ref({
+  floor: props.floor,
+  x: props.x,
+  y: props.y,
+  category: 'A' as 'A' | 'B' | 'C',
+  locGroup1: `H${props.floor}-${props.x}-${props.y}`,
+  wcsLocationId: ''
+})
+const copyButtonText = ref({
+  base: '复制',
+  ext: '复制',
+  all: '复制全部'
+})
+let feedbackTimer: number | null = null
+
+const themeClass = computed(() => (props.themeMode === 'light' ? 'theme-light' : 'theme-dark'))
+
+watch(
+  () => [props.visible, props.floor, props.x, props.y] as const,
+  ([visible, floor, x, y]) => {
+    if (!visible) {
+      return
+    }
+
+    form.value = {
+      floor,
+      x,
+      y,
+      category: 'A',
+      locGroup1: `H${floor}-${x}-${y}`,
+      wcsLocationId: ''
+    }
+  },
+  {
+    immediate: true
+  }
+)
+
+const generatedDepth = computed(() => CATEGORY_DEPTH_MAP[form.value.category])
+
+const generatedLocationId = computed(() => {
+  const { floor, x, y } = form.value
+  return `H${floor}-${x}-${y}-${generatedDepth.value}`
+})
+
+const generatedPutawayLogicalSequence = computed(() => {
+  const { floor, x, y } = form.value
+  return `${floor}${String(x).padStart(2, '0')}${String(y).padStart(2, '0')}${generatedDepth.value}`
+})
+
+const generatedLocationRow = computed(() => form.value.y + 1)
+const generatedLocationColumn = computed(() => form.value.x + 1)
+
+const escapeSqlString = (value: string) => value.replaceAll("'", "''")
+const quoteSqlValue = (value: string) => `'${escapeSqlString(value)}'`
+
+const baseLocationInsertSql = computed(() => {
+  const { category, floor, locGroup1 } = form.value
+  return `INSERT INTO wms_ftest.bas_location (
+  organizationId, warehouseId, locationId, putawayLogicalSequence, pickLogicalSequence,
+  locationUsage, locationAttribute, locationCategory, locationHandling, environment, demand,
+  zoneGroup, validationCode, locGroup1, locGroup2, workingArea, aisleNo, cubicCapacity,
+  weightCapacity, csCount, eaCount, plCount, skuCount, length, width, height, xCoord, yCoord,
+  zCoord, locLevel, xDistance, yDistance, mix_Flag, mix_LotFlag, loseId_Flag, noteText, udf01,
+  udf02, udf03, udf04, udf05, currentVersion, oprSeqFlag, addWho, addTime, editWho, editTime,
+  terminalNo1, terminalNo2, round, usedTime, zoneId, locationRow, locationColumn, loseMuid_Flag,
+  udf06, zDistance, toleranceFlag, cycleGroup, lastCycleCount
+) VALUES (
+  'BS', 'WH01', ${quoteSqlValue(generatedLocationId.value)}, ${quoteSqlValue(generatedPutawayLogicalSequence.value)}, ${quoteSqlValue(generatedLocationId.value)},
+  'PC', 'OK', 'ASRS', 'OT', null, ${quoteSqlValue(category)},
+  'WH01-3', null, ${quoteSqlValue(locGroup1)}, null, null, null, null,
+  null, null, null, null, null, 1.20000000, 1.00000000, 1.60000000, null, null,
+  null, ${floor}, null, null, 'N', 'N', 'N', null, null,
+  null, null, null, null, 100, '2022', 'system', NOW(), 'system', NOW(),
+  null, null, null, null, 'WH01-3-3', ${generatedLocationRow.value}, ${generatedLocationColumn.value}, 'N',
+  null, null, 'Y', null, null
+);`
+})
+
+const customLocationExtInsertSql = computed(() => {
+  const { category, wcsLocationId } = form.value
+  return `INSERT INTO wms_ftest.custom_location_ext (
+  warehouse_id, location_id, occupancy_rate, priority, category, length, width, height,
+  last_move_sku, last_move_lot_num, last_move_time, create_time, creator_id, update_time,
+  updater_id, delete_time, last_move_qty, actual_area, settle_area, wcs_location_id
+) VALUES (
+  'WH01', ${quoteSqlValue(generatedLocationId.value)}, null, null, ${quoteSqlValue(category)}, 1.20, 1.00, 1.60,
+  null, null, null, NOW(), 0, NOW(), 0, null, null, 0.0000, 0.0000, ${quoteSqlValue(wcsLocationId)}
+);`
+})
+
+const allGeneratedSql = computed(
+  () => `${baseLocationInsertSql.value}\n\n${customLocationExtInsertSql.value}`
+)
+const canCopyAll = computed(() => form.value.wcsLocationId.trim().length > 0)
+
+const resetCopyFeedback = () => {
+  copyButtonText.value = {
+    base: '复制',
+    ext: '复制',
+    all: '复制全部'
+  }
+  if (feedbackTimer !== null) {
+    window.clearTimeout(feedbackTimer)
+    feedbackTimer = null
+  }
+}
+
+const copyText = async (text: string) => {
+  if (!text) {
+    return
+  }
+
+  try {
+    await navigator.clipboard.writeText(text)
+    return
+  } catch (error) {
+    console.warn('Clipboard API copy failed, fallback to execCommand.', error)
+  }
+
+  const textarea = document.createElement('textarea')
+  textarea.value = text
+  textarea.setAttribute('readonly', 'true')
+  textarea.style.position = 'fixed'
+  textarea.style.top = '-9999px'
+  document.body.appendChild(textarea)
+  textarea.select()
+  document.execCommand('copy')
+  document.body.removeChild(textarea)
+}
+
+const copyGeneratedSql = async (text: string) => {
+  if (!canCopyAll.value) {
+    return
+  }
+
+  let type: 'base' | 'ext' | 'all' = 'all'
+  if (text === baseLocationInsertSql.value) {
+    type = 'base'
+  } else if (text === customLocationExtInsertSql.value) {
+    type = 'ext'
+  }
+
+  await copyText(text)
+  resetCopyFeedback()
+  copyButtonText.value[type] = type === 'all' ? '复制成功' : '已复制'
+  feedbackTimer = window.setTimeout(() => {
+    resetCopyFeedback()
+  }, 1800)
+}
+
+const handleClose = () => {
+  resetCopyFeedback()
+  emit('close')
+}
+</script>
+
+<style scoped>
+.sql-modal-overlay {
+  position: fixed;
+  inset: 0;
+  z-index: 1200;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 24px;
+  background: rgba(0, 0, 0, 0.58);
+  backdrop-filter: blur(4px);
+}
+
+.sql-modal {
+  width: min(920px, 100%);
+  max-height: min(88vh, 920px);
+  display: flex;
+  flex-direction: column;
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.sql-modal.theme-dark {
+  --sql-bg: rgba(4, 4, 4, 0.98);
+  --sql-border: #1f1f1f;
+  --sql-text: #f2f2f2;
+  --sql-text-dim: #d8d8d8;
+  --sql-input-bg: rgba(255, 255, 255, 0.03);
+  --sql-input-border: #252525;
+  --sql-input-hover-bg: rgba(255, 255, 255, 0.05);
+  --sql-input-hover-border: #3a3a3a;
+  --sql-btn-bg: rgba(255, 255, 255, 0.03);
+  --sql-btn-border: #252525;
+  --sql-btn-text: #cfcfcf;
+  --sql-btn-hover-bg: rgba(255, 255, 255, 0.06);
+  --sql-btn-hover-border: #3a3a3a;
+  background: var(--sql-bg);
+  border: 1px solid var(--sql-border);
+  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.32);
+}
+
+.sql-modal.theme-light {
+  --sql-bg: #ffffff;
+  --sql-border: #d7dce3;
+  --sql-text: #1f1f1f;
+  --sql-text-dim: #3f3f3f;
+  --sql-input-bg: #ffffff;
+  --sql-input-border: #cfd6df;
+  --sql-input-hover-bg: #f7f9fb;
+  --sql-input-hover-border: #aeb7c2;
+  --sql-btn-bg: #ffffff;
+  --sql-btn-border: #cfd6df;
+  --sql-btn-text: #2a2f36;
+  --sql-btn-hover-bg: #f1f4f8;
+  --sql-btn-hover-border: #aeb7c2;
+  background: var(--sql-bg);
+  border: 1px solid var(--sql-border);
+  box-shadow: 0 12px 24px rgba(31, 35, 40, 0.12);
+}
+
+.sql-modal-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 14px 16px;
+  border-bottom: 1px solid var(--sql-border);
+}
+
+.sql-modal-header h3 {
+  margin: 0;
+  font-size: 15px;
+  color: var(--sql-text);
+}
+
+.sql-modal-close,
+.sql-copy-all-btn {
+  border: 1px solid var(--sql-btn-border);
+  background: var(--sql-btn-bg);
+  color: var(--sql-btn-text);
+  cursor: pointer;
+}
+
+.sql-modal-close {
+  width: 28px;
+  height: 28px;
+  border-radius: 6px;
+  font-size: 18px;
+  line-height: 1;
+}
+
+.sql-modal-close:hover,
+.sql-copy-all-btn:hover {
+  background: var(--sql-btn-hover-bg);
+  border-color: var(--sql-btn-hover-border);
+}
+
+.sql-modal-body {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  padding: 16px;
+  overflow: auto;
+}
+
+.sql-form-grid {
+  display: grid;
+  gap: 10px;
+  align-items: end;
+}
+
+.sql-form-grid-auto {
+  grid-template-columns:
+    fit-content(72px)
+    fit-content(72px)
+    fit-content(72px)
+    minmax(160px, 1fr)
+    fit-content(72px);
+}
+
+.sql-form-grid-edit {
+  grid-template-columns:
+    fit-content(84px)
+    minmax(128px, 168px)
+    minmax(160px, 1fr)
+    auto;
+}
+
+.sql-form-item {
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+  color: var(--sql-text-dim);
+  font-size: 12px;
+}
+
+.sql-form-item-location-id {
+  min-width: 0;
+}
+
+.sql-form-item-category {
+  min-width: 0;
+}
+
+.sql-form-item-group {
+  min-width: 0;
+}
+
+.sql-form-item-group .sql-input {
+  width: 100%;
+}
+
+.sql-form-item-wcs {
+  min-width: 0;
+}
+
+.sql-form-item-wcs .sql-input {
+  width: 100%;
+  min-width: 0;
+}
+
+.sql-form-item-copy {
+  justify-content: flex-end;
+  align-self: end;
+}
+
+.sql-form-item-placeholder {
+  visibility: hidden;
+  user-select: none;
+}
+
+.sql-input,
+.sql-select,
+.sql-preview {
+  width: 100%;
+  box-sizing: border-box;
+  border: 1px solid var(--sql-input-border);
+  background: var(--sql-input-bg);
+  color: var(--sql-text);
+}
+
+.sql-input,
+.sql-select {
+  padding: 8px 10px;
+  border-radius: 6px;
+  font-size: 12px;
+  outline: none;
+}
+
+.sql-input:focus,
+.sql-select:focus {
+  background: var(--sql-input-hover-bg);
+  border-color: var(--sql-input-hover-border);
+}
+
+.sql-copy-all-btn:disabled {
+  opacity: 0.48;
+  cursor: not-allowed;
+  background: var(--sql-btn-bg);
+  border-color: var(--sql-btn-border);
+}
+
+.sql-input:disabled {
+  background: color-mix(in srgb, var(--sql-input-bg) 70%, #808080 30%);
+  color: color-mix(in srgb, var(--sql-text) 72%, #808080 28%);
+  border-color: var(--sql-input-border);
+  cursor: not-allowed;
+  opacity: 1;
+}
+
+.sql-preview-block {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  gap: 6px;
+}
+
+.sql-copy-all-btn {
+  padding: 4px 8px;
+  border-radius: 6px;
+  font-size: 11px;
+}
+
+.sql-preview {
+  margin: 0;
+  padding: 10px 12px;
+  border-radius: 8px;
+  font-size: 12px;
+  line-height: 1.5;
+  white-space: pre-wrap;
+  word-break: break-word;
+  overflow-x: auto;
+  background: var(--sql-input-bg);
+  color: var(--sql-text);
+  border-color: var(--sql-input-border);
+  cursor: text;
+  user-select: text;
+}
+
+.sql-preview code {
+  font-family:
+    ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono',
+    'Courier New', monospace;
+}
+
+@media (max-width: 900px) {
+  .sql-form-grid-auto {
+    grid-template-columns: repeat(4, minmax(0, 1fr));
+  }
+
+  .sql-form-item-location-id {
+    grid-column: span 4;
+  }
+
+  .sql-form-grid-edit {
+    grid-template-columns: fit-content(84px) minmax(120px, 1fr) minmax(160px, 1fr) auto;
+  }
+
+  .sql-form-item-wcs {
+    grid-column: span 2;
+  }
+}
+
+@media (max-width: 640px) {
+  .sql-modal-overlay {
+    padding: 12px;
+  }
+
+  .sql-form-grid-auto,
+  .sql-form-grid-edit {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+
+  .sql-form-item-category,
+  .sql-form-item-group,
+  .sql-form-item-wcs,
+  .sql-form-item-copy {
+    width: auto;
+  }
+
+  .sql-form-item-category .sql-select,
+  .sql-form-item-group .sql-input,
+  .sql-form-item-wcs .sql-input {
+    width: 100%;
+  }
+
+  .sql-form-item-location-id,
+  .sql-form-item-wcs,
+  .sql-form-item-copy {
+    grid-column: span 2;
+  }
+
+  .sql-preview {
+    min-height: 0;
+  }
+}
+</style>

+ 18 - 2
src/components/WarehouseMap.vue

@@ -171,6 +171,7 @@ const emit = defineEmits<{
   (event: 'select-loc-group', locGroup1: string): void
   (event: 'select-location-id', locationId: string): void
   (event: 'selection-complete'): void
+  (event: 'create-location-sql', payload: { floor: number; x: number; y: number }): void
 }>()
 const mapWrapperRef = ref<HTMLElement | null>(null)
 const cellRefs = ref<Array<HTMLElement | null>>([])
@@ -513,6 +514,10 @@ const isLocationCell = (cell: MapCell): cell is GridCell => {
   return Boolean(cell && !('type' in cell))
 }
 
+const isAisleCell = (cell: MapCell): cell is AisleCell => {
+  return Boolean(cell && 'type' in cell && cell.type === 'aisle')
+}
+
 const workingHighlightState = inject<WorkingHighlightState | null>(WORKING_HIGHLIGHT_KEY, null)
 
 const getWorkingHighlightClass = (cell: GridCell) => {
@@ -790,8 +795,19 @@ const handleCellClick = (cell: MapCell) => {
 }
 
 const handleCellContextMenu = (cell: MapCell) => {
-  if (!isLocationCell(cell) || !isCellVisible(cell)) return
-  emit('select-location-id', cell.locationId)
+  if (isLocationCell(cell)) {
+    if (!isCellVisible(cell)) return
+    emit('select-location-id', cell.locationId)
+    return
+  }
+
+  if (isAisleCell(cell)) {
+    emit('create-location-sql', {
+      floor: props.currentLevel,
+      x: cell.gridCol,
+      y: cell.gridRow
+    })
+  }
 }
 
 const copyText = async (text: string) => {

+ 3 - 313
src/components/warehouse-layout-enhancers.ts

@@ -10,320 +10,10 @@ export interface WarehouseLayoutPosition {
   gridCol: number
 }
 
-type RowRange = readonly [number, number]
-
-interface RowScopedRule {
-  rows?: readonly number[]
-  rowRange?: RowRange
-}
-
-interface ColumnScopedRule {
-  startColumn: number
-  endColumn?: number
-}
-
-interface LocalColumnAisleRule extends RowScopedRule {
-  afterColumn: number
-  gapCols: number
-}
-
-interface LocalColumnShiftRule extends RowScopedRule, ColumnScopedRule {
-  shiftCols: number
-}
-
-interface ManualColumnOffsetRule extends RowScopedRule, ColumnScopedRule {
-  offsetCols: number
-}
-
-interface ColumnCompactionRule extends RowScopedRule {
-  startColumn: number
-}
-
-interface GlobalColumnAisleRule {
-  breakpoint: number
-  excludeRows?: readonly number[]
-  excludeRowRange?: RowRange
-}
-
-interface WarehouseLayoutRuleSet {
-  rowAisleBreakpoints: readonly number[]
-  globalColumnAisles: readonly GlobalColumnAisleRule[]
-  localColumnAisles: readonly LocalColumnAisleRule[]
-  localColumnShifts: readonly LocalColumnShiftRule[]
-  manualColumnOffsets: readonly ManualColumnOffsetRule[]
-  columnCompactions: readonly ColumnCompactionRule[]
-}
-
-const scopedRows = <T extends object>(
-  rows: readonly number[],
-  rule: T
-): T & Pick<RowScopedRule, 'rows'> => ({
-  ...rule,
-  rows
-})
-
-const scopedRowRange = <T extends object>(
-  start: number,
-  end: number,
-  rule: T
-): T & Pick<RowScopedRule, 'rowRange'> => ({
-  ...rule,
-  rowRange: [start, end]
-})
-
-const localColumnAisleRows = (rows: readonly number[], afterColumn: number, gapCols: number) =>
-  scopedRows(rows, {
-    afterColumn,
-    gapCols
-  })
-
-const localColumnAisleRange = (
-  startRow: number,
-  endRow: number,
-  afterColumn: number,
-  gapCols: number
-) =>
-  scopedRowRange(startRow, endRow, {
-    afterColumn,
-    gapCols
-  })
-
-const localColumnShiftRows = (
-  rows: readonly number[],
-  startColumn: number,
-  shiftCols: number,
-  endColumn?: number
-) =>
-  scopedRows(rows, {
-    startColumn,
-    endColumn,
-    shiftCols
-  })
-
-const manualColumnOffsetRows = (
-  rows: readonly number[],
-  startColumn: number,
-  offsetCols: number,
-  endColumn?: number
-) =>
-  scopedRows(rows, {
-    startColumn,
-    endColumn,
-    offsetCols
-  })
-
-const columnCompactionRows = (rows: readonly number[], startColumn: number) =>
-  scopedRows(rows, {
-    startColumn
-  })
-
-const globalColumnAisle = (
-  breakpoint: number,
-  options: Omit<GlobalColumnAisleRule, 'breakpoint'> = {}
-): GlobalColumnAisleRule => ({
-  breakpoint,
-  ...options
-})
-
-const FIRST_FLOOR_ROWS_6_AND_13 = [6, 13] as const
-const FIRST_FLOOR_ROWS_8_AND_11 = [8, 11] as const
-const FIRST_FLOOR_ROWS_9_AND_10 = [9, 10] as const
-const FIRST_FLOOR_ROWS_7 = [7] as const
-
-const FIRST_FLOOR_ROW_AISLE_BREAKPOINTS = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] as const
-
-const FIRST_FLOOR_GLOBAL_COLUMN_AISLES = [
-  globalColumnAisle(1),
-  globalColumnAisle(19, {
-    excludeRows: [8, 9, 10, 11]
-  }),
-  globalColumnAisle(26, {
-    excludeRows: [8, 11]
-  })
-] as const
-
-const FIRST_FLOOR_LOCAL_COLUMN_AISLES = [
-  localColumnAisleRange(0, 7, 7, 1),
-  localColumnAisleRange(12, 22, 7, 1),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 6, 3),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 10, 1),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_8_AND_11, 13, 1),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 20, 1),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_8_AND_11, 26, 1),
-  localColumnAisleRows(FIRST_FLOOR_ROWS_9_AND_10, 14, 3)
-] as const
-
-const FIRST_FLOOR_LOCAL_COLUMN_SHIFTS = [
-  localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 0, 1),
-  localColumnShiftRows(FIRST_FLOOR_ROWS_8_AND_11, 8, 1),
-  localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 5, 1),
-  localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 11, 1),
-  localColumnShiftRows(FIRST_FLOOR_ROWS_6_AND_13, 17, 1),
-  localColumnShiftRows(FIRST_FLOOR_ROWS_7, 20, 1)
-] as const
-
-const FIRST_FLOOR_MANUAL_COLUMN_OFFSETS = [
-  manualColumnOffsetRows(FIRST_FLOOR_ROWS_8_AND_11, 13, -1, 17),
-  manualColumnOffsetRows(FIRST_FLOOR_ROWS_8_AND_11, 18, -1, 18)
-] as const
-
-const FIRST_FLOOR_COLUMN_COMPACTIONS = [
-  columnCompactionRows(FIRST_FLOOR_ROWS_9_AND_10, 11)
-] as const
-
-const FIRST_FLOOR_RULE_SET: WarehouseLayoutRuleSet = {
-  rowAisleBreakpoints: FIRST_FLOOR_ROW_AISLE_BREAKPOINTS,
-  globalColumnAisles: FIRST_FLOOR_GLOBAL_COLUMN_AISLES,
-  localColumnAisles: FIRST_FLOOR_LOCAL_COLUMN_AISLES,
-  localColumnShifts: FIRST_FLOOR_LOCAL_COLUMN_SHIFTS,
-  manualColumnOffsets: FIRST_FLOOR_MANUAL_COLUMN_OFFSETS,
-  columnCompactions: FIRST_FLOOR_COLUMN_COMPACTIONS
-}
-
-const RULE_SETS_BY_LEVEL: Readonly<Record<number, WarehouseLayoutRuleSet>> = {
-  1: FIRST_FLOOR_RULE_SET
-}
-
-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
-
-  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[]
-) => sumColumnScopedRuleValues(parsedLocation, rules, (rule) => rule.shiftCols)
-
-const sumManualColumnOffsets = (
-  parsedLocation: WarehouseLayoutParsedLocation,
-  rules: readonly ManualColumnOffsetRule[]
-) => sumColumnScopedRuleValues(parsedLocation, rules, (rule) => rule.offsetCols)
-
-const matchesColumnScope = (column: number, rule: ColumnScopedRule) => {
-  return column >= rule.startColumn && (rule.endColumn === undefined || column <= rule.endColumn)
-}
-
-const sumColumnScopedRuleValues = <TRule extends RowScopedRule & ColumnScopedRule>(
-  parsedLocation: WarehouseLayoutParsedLocation,
-  rules: readonly TRule[],
-  getValue: (rule: TRule) => number
-) =>
-  rules.reduce((total, rule) => {
-    if (matchesRowScope(parsedLocation.y, rule) && matchesColumnScope(parsedLocation.x, rule)) {
-      return total + getValue(rule)
-    }
-
-    return total
-  }, 0)
-
-const getBaseGridColOffset = (
-  parsedLocation: WarehouseLayoutParsedLocation,
-  ruleSet: WarehouseLayoutRuleSet
-) => {
-  const columnShiftCount = sumLocalColumnShiftOffsets(parsedLocation, ruleSet.localColumnShifts)
-  const effectiveColumn = parsedLocation.x + columnShiftCount
-
-  return (
-    columnShiftCount +
-    sumGlobalColumnAisleOffsets(parsedLocation.y, effectiveColumn, ruleSet.globalColumnAisles) +
-    sumLocalColumnAisleOffsets(parsedLocation.y, effectiveColumn, ruleSet.localColumnAisles)
-  )
-}
-
-const sumColumnCompactionOffsets = (
-  parsedLocation: WarehouseLayoutParsedLocation,
-  ruleSet: WarehouseLayoutRuleSet
-) =>
-  ruleSet.columnCompactions.reduce((total, rule) => {
-    if (!matchesRowScope(parsedLocation.y, rule) || parsedLocation.x < rule.startColumn) {
-      return total
-    }
-
-    if (parsedLocation.x === rule.startColumn) {
-      return total - 1
-    }
-
-    const previousLocation: WarehouseLayoutParsedLocation = {
-      ...parsedLocation,
-      x: parsedLocation.x - 1
-    }
-    const previousGridCol = previousLocation.x + getBaseGridColOffset(previousLocation, ruleSet)
-    const currentGridCol = parsedLocation.x + getBaseGridColOffset(parsedLocation, ruleSet)
-
-    return total + (previousGridCol - currentGridCol)
-  }, 0)
-
-const applyRuleSet = (
-  currentPosition: WarehouseLayoutPosition,
-  parsedLocation: WarehouseLayoutParsedLocation,
-  ruleSet: WarehouseLayoutRuleSet
-) => {
-  // 保持现有语义顺序:先结构性位移与过道,再单点修正,最后做链式补位。
-  const gridColOffset =
-    getBaseGridColOffset(parsedLocation, ruleSet) +
-    sumManualColumnOffsets(parsedLocation, ruleSet.manualColumnOffsets) +
-    sumColumnCompactionOffsets(parsedLocation, ruleSet)
-  const gridRowOffset = sumRowAisleOffsets(parsedLocation.y, ruleSet.rowAisleBreakpoints)
-
-  return {
-    gridRow: currentPosition.gridRow + gridRowOffset,
-    gridCol: currentPosition.gridCol + gridColOffset
-  }
-}
-
-const getRuleSet = (level: number) => {
-  return RULE_SETS_BY_LEVEL[level]
-}
-
 export const applyWarehouseLayoutEnhancement = (
-  level: number,
-  parsedLocation: WarehouseLayoutParsedLocation,
+  _level: number,
+  _parsedLocation: WarehouseLayoutParsedLocation,
   basePosition: WarehouseLayoutPosition
 ) => {
-  const ruleSet = getRuleSet(level)
-  if (!ruleSet) {
-    return basePosition
-  }
-
-  return applyRuleSet(basePosition, parsedLocation, ruleSet)
+  return basePosition
 }