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

货架-兼容行列较多的情况

zhaohuanhuan 3 недель назад
Родитель
Сommit
6687e9b45b
1 измененных файлов с 79 добавлено и 352 удалено
  1. 79 352
      src/views/haikang/putaway/components/Shelf.vue

+ 79 - 352
src/views/haikang/putaway/components/Shelf.vue

@@ -1,36 +1,20 @@
 <template>
-  <div class="shelf-container" :style="{ '--cols': cols, '--rows': rows }">
-
-    <!-- 当前显示的面 -->
-    <div class="shelf-rack">
-      <!-- 货架主体 -->
-      <div class="rack-body">
-
-        <!-- 货架支柱 -->
-        <div class="rack-pillars">
-          <div class="rack-main">
-            <!-- 货架层板 -->
-            <div class="rack-shelves">
-              <div
-                v-for="row in reversedRows"
-                :key="`shelf-${row}`"
-                class="rack-shelf"
-              >
-                <!-- 货架板 -->
-                <div class="shelf-board">
-                  <div
-                    v-for="col in cols"
-                    :key="`cell-${shelfName}-${currentFace}${row}${col}`"
-                    class="shelf-cell"
-                    :class="{ 'highlight': isHighlighted(`${shelfName}-${currentFace}${row}${col}`) }"
-                  >
-                    <!-- 完整编号显示 -->
-                    <div class="cell-number">
-                      {{ shelfName }}-{{ currentFace }}{{ row }}{{ col }}
-                    </div>
-                  </div>
-                </div>
-              </div>
+  <div class="shelf-container">
+    <div ref="shelfScrollRef" class="shelf-scroll">
+      <div class="shelf-grid">
+        <div
+          v-for="row in reversedRows"
+          :key="`shelf-${row}`"
+          class="shelf-row"
+        >
+          <div
+            v-for="col in cols"
+            :key="`cell-${shelfName}-${currentFace}${row}${col}`"
+            class="shelf-cell"
+            :class="{ highlight: isHighlighted(`${shelfName}-${currentFace}${row}${col}`) }"
+          >
+            <div class="cell-number">
+              {{ shelfName }}-{{ currentFace }}{{ row }}{{ col }}
             </div>
           </div>
         </div>
@@ -40,9 +24,8 @@
 </template>
 
 <script setup>
-import { computed } from 'vue';
+import { computed, nextTick, onMounted, ref, watch } from 'vue';
 
-// 接收父组件传递的数据
 const props = defineProps({
   shelfCode: {
     type: String,
@@ -62,63 +45,69 @@ const props = defineProps({
   }
 });
 
-// 计算属性:从大到小排列,让第一层在底部
 const reversedRows = computed(() => {
   return Array.from({ length: props.rows }, (_, i) => props.rows - i);
 });
 
-// 当前显示的面
 const currentFace = computed(() => {
-  // 优先根据货架编码判断显示的面
   if (props.shelfCode) {
     const match = props.shelfCode.match(/^([A-Z]+\d+)-([AB])$/);
     if (match) {
-      return match[2]; // 返回A或B
+      return match[2];
     }
   }
 
-  // 如果货架编码没有指定面,则根据highlightCells中的编号自动判断显示的面
   if (props.highlightCells && props.highlightCells.length > 0) {
-    // 检查是否有A面或B面的编号
     const hasAFace = props.highlightCells.some(cell => cell.includes('-A'));
     const hasBFace = props.highlightCells.some(cell => cell.includes('-B'));
 
-    // 如果同时有AB面,默认显示A面;如果只有一面,显示那一面
     if (hasAFace) return 'A';
     if (hasBFace) return 'B';
   }
-  return 'A'; // 默认显示A面
+  return 'A';
 });
 
-// 货架名称
 const shelfName = computed(() => {
-  // 从货架编码中提取货架名称,如 HJ001-A -> HJ001
   if (props.shelfCode) {
     const match = props.shelfCode.match(/^([A-Z]+\d+)-[AB]$/);
     if (match) {
       return match[1];
     }
   }
-  return 'HJ001'; // 默认值
+  return 'HJ001';
 });
 
-// 判断格口是否需要高亮
 const isHighlighted = (cellId) => {
   if (!cellId || !props.highlightCells || props.highlightCells.length === 0) return false;
-
   return props.highlightCells.includes(cellId);
 };
 
-// 暴露高亮方法
+const shelfScrollRef = ref(null);
+
+function scrollHighlightIntoView() {
+  const scrollEl = shelfScrollRef.value;
+  if (!scrollEl || !props.highlightCells?.length) return;
+  const highlighted = scrollEl.querySelector('.shelf-cell.highlight');
+  highlighted?.scrollIntoView({ block: 'center', behavior: 'smooth', inline: 'nearest' });
+}
+
+watch(
+  () => [props.highlightCells, props.shelfCode, props.rows, props.cols],
+  () => {
+    nextTick(scrollHighlightIntoView);
+  },
+  { deep: true }
+);
+
+onMounted(() => {
+  nextTick(scrollHighlightIntoView);
+});
+
 const highlightCell = (cellId) => {
-  // 注意:由于 props 是只读的,这里只是为了保持接口兼容性
-  // 实际的高亮控制应该通过父组件更新 highlightCells prop
   console.log('Highlight cell:', cellId);
 };
 
 const clearHighlight = () => {
-  // 注意:由于 props 是只读的,这里只是为了保持接口兼容性
-  // 实际的高亮控制应该通过父组件更新 highlightCells prop
   console.log('Clear highlight');
 };
 
@@ -126,336 +115,74 @@ defineExpose({ highlightCell, clearHighlight });
 </script>
 
 <style scoped>
+
 .shelf-container {
-  width: 75%;
-  margin: 0;
-  padding: 0;
-  background:
-    linear-gradient(135deg, rgba(248, 249, 250, 0.95) 0%, rgba(233, 236, 239, 0.95) 100%),
-    radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
-    radial-gradient(circle at 80% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 50%);
-  border-radius: 16px;
-  box-shadow:
-    0 8px 32px rgba(0, 0, 0, 0.12),
-    0 2px 8px rgba(0, 0, 0, 0.06),
-    inset 0 1px 0 rgba(255, 255, 255, 0.3),
-    inset 0 -1px 0 rgba(0, 0, 0, 0.05);
+  box-sizing: border-box;
+  width: 80%;
+  max-width: 100%;
+  margin: 0 auto;
+  border-radius: 10px;
+  border: 1px solid #e5e7eb;
+  background: #f3f4f6;
   overflow: hidden;
-  position: relative;
-  border: 1px solid rgba(255, 255, 255, 0.2);
-}
-
-.shelf-container::before {
-  content: '';
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  height: 2px;
-  background: linear-gradient(90deg,
-    transparent 0%,
-    rgba(255, 255, 255, 0.9) 20%,
-    rgba(255, 255, 255, 0.6) 50%,
-    rgba(255, 255, 255, 0.9) 80%,
-    transparent 100%);
-  border-radius: 16px 16px 0 0;
-}
-
-.shelf-container::after {
-  content: '';
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  right: 0;
-  height: 1px;
-  background: linear-gradient(90deg,
-    transparent 0%,
-    rgba(0, 0, 0, 0.1) 50%,
-    transparent 100%);
 }
 
-.shelf-rack {
-  background:
-    linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(249, 250, 251, 0.9) 100%),
-    radial-gradient(circle at 30% 40%, rgba(59, 130, 246, 0.05) 0%, transparent 40%),
-    radial-gradient(circle at 70% 60%, rgba(16, 185, 129, 0.05) 0%, transparent 40%);
-  overflow: hidden;
-  position: relative;
-  backdrop-filter: blur(12px) saturate(1.2);
-  border-radius: 14px;
+.shelf-scroll {
+  box-sizing: border-box;
+  height: 100px;
   margin: 2px;
+  padding: 2px;
+  border-radius: 8px;
+  background: #fff;
+  overflow-y: auto;
+  overflow-x: hidden;
+  -webkit-overflow-scrolling: touch;
 }
 
-.rack-title {
-  margin: 0;
-  font-size: 14px;
-  font-weight: 500;
-  letter-spacing: 0.5px;
-}
-
-.rack-footer {
-  background: #f5f5f5;
-  padding: 8px 15px;
-  text-align: center;
-  border-radius: 3px;
-}
-
-.rack-footer .rack-title {
-  margin: 0;
-  font-size: 18px;
-  font-weight: 600;
-  color: #409eff;
-  letter-spacing: 0.5px;
-}
-
-.rack-body {
-  position: relative;
-  display: block;
-  min-height: calc(28px * var(--rows) + 4px);
-}
-
-/* 货架支柱 */
-.rack-pillars {
-  display: flex;
-  align-items: stretch;
-  position: relative;
-}
-
-.rack-pillar {
-  width: 5px;
-  background:
-    linear-gradient(180deg,
-      #9ca3af 0%,
-      #6b7280 20%,
-      #4b5563 50%,
-      #374151 80%,
-      #1f2937 100%);
-  position: relative;
-  border-radius: 2.5px;
-  box-shadow:
-    0 3px 8px rgba(0, 0, 0, 0.2),
-    inset 0 1px 0 rgba(255, 255, 255, 0.15),
-    inset 0 -1px 0 rgba(0, 0, 0, 0.2),
-    inset 1px 0 0 rgba(255, 255, 255, 0.05);
-  border: 1px solid rgba(255, 255, 255, 0.1);
-}
-
-.left-pillar {
-  margin-right: 10px;
-  transform: skewY(-1deg);
-}
-
-.right-pillar {
-  margin-left: 10px;
-  transform: skewY(1deg);
-}
-
-.rack-main {
-  flex: 1;
-  position: relative;
-}
-
-/* 货架层板 */
-.rack-shelves {
-  flex: 1;
+.shelf-grid {
   display: flex;
   flex-direction: column;
-  gap: 0px;
-}
-
-.rack-shelf {
-  position: relative;
-  flex: 1;
 }
 
-.shelf-board {
-  background: #fafafa;
-  padding: 2px 1px;
-  margin: 0;
+.shelf-row {
   display: flex;
-  gap: 0px;
-  align-items: center;
-  position: relative;
+  flex: 0 0 auto;
+  min-height: 28px;
+  padding: 1px 0;
+  background: #fafafa;
 }
 
-/* 货架格子 */
 .shelf-cell {
-  flex: 1;
+  flex: 1 1 0;
+  min-width: 0;
+  min-height: 24px;
+  margin: 1px;
   display: flex;
-  flex-direction: column;
   align-items: center;
   justify-content: center;
-  background:
-    linear-gradient(135deg, rgba(255, 255, 255, 0.95) 0%, rgba(248, 249, 250, 0.95) 100%),
-    radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.8) 0%, transparent 50%),
-    radial-gradient(circle at 75% 75%, rgba(0, 0, 0, 0.02) 0%, transparent 50%);
-  border: 1px solid rgba(222, 226, 230, 0.8);
-  border-bottom: 2px solid rgba(226, 232, 240, 0.9);
-  border-radius: 6px;
-  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
-  position: relative;
-  min-width: 50px;
-  min-height: 24px;
-  margin: 0.5px;
-  box-shadow:
-    0 1px 3px rgba(0, 0, 0, 0.06),
-    inset 0 1px 0 rgba(255, 255, 255, 0.4),
-    inset 0 -1px 0 rgba(0, 0, 0, 0.05);
-  cursor: pointer;
-}
-
-.shelf-cell:hover {
-  transform: translateY(-0.5px) scale(1.01);
-  box-shadow:
-    0 3px 8px rgba(0, 0, 0, 0.1),
-    0 1px 3px rgba(0, 0, 0, 0.06),
-    inset 0 1px 0 rgba(255, 255, 255, 0.5),
-    inset 0 -1px 0 rgba(0, 0, 0, 0.03);
-  border-color: #a0aec0;
-  background:
-    linear-gradient(135deg, rgba(255, 255, 255, 0.98) 0%, rgba(241, 243, 244, 0.98) 100%),
-    radial-gradient(circle at 25% 25%, rgba(255, 255, 255, 0.9) 0%, transparent 50%),
-    radial-gradient(circle at 75% 75%, rgba(0, 0, 0, 0.01) 0%, transparent 50%);
+  border: 1px solid #e5e7eb;
+  border-radius: 4px;
+  background: #fff;
 }
 
-/* 单元格编号 */
 .cell-number {
-  font-size: 16px;
+  font-size: 11px;
   font-weight: 600;
-  color: #1a202c;
+  color: #111827;
   text-align: center;
-  line-height: 1;
-  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
-  letter-spacing: 0.01em;
-  text-shadow: 0 0.5px 1px rgba(0, 0, 0, 0.03);
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
+  line-height: 1.2;
+  padding: 1px 2px;
+  word-break: break-all;
 }
 
 .shelf-cell.highlight {
-  background:
-    linear-gradient(135deg, rgba(240, 253, 244, 0.95) 0%, rgba(220, 252, 231, 0.95) 100%),
-    radial-gradient(circle at 30% 30%, rgba(34, 197, 94, 0.1) 0%, transparent 60%),
-    radial-gradient(circle at 70% 70%, rgba(255, 255, 255, 0.3) 0%, transparent 60%);
+  background: #dcfce7;
   border-color: #22c55e;
-  border-width: 1.5px;
-  box-shadow:
-    0 4px 12px rgba(34, 197, 94, 0.25),
-    0 2px 6px rgba(34, 197, 94, 0.15),
-    0 0 0 1px rgba(34, 197, 94, 0.1),
-    inset 0 1px 0 rgba(255, 255, 255, 0.2);
-  transform: translateY(-0.5px) scale(1.02);
-  animation: highlight-glow 2s ease-in-out infinite alternate;
+  border-width: 2px;
 }
 
 .shelf-cell.highlight .cell-number {
   color: #166534;
-  font-weight: 800;
-  text-shadow:
-    0 1px 2px rgba(22, 101, 52, 0.2),
-    0 0 0 1px rgba(34, 197, 94, 0.1);
-  background: linear-gradient(135deg, #166534 0%, #15803d 100%);
-  -webkit-background-clip: text;
-  -webkit-text-fill-color: transparent;
-  background-clip: text;
-}
-
-@keyframes highlight-glow {
-  0% {
-    box-shadow:
-      0 4px 12px rgba(34, 197, 94, 0.25),
-      0 2px 6px rgba(34, 197, 94, 0.15),
-      0 0 0 1px rgba(34, 197, 94, 0.1),
-      inset 0 1px 0 rgba(255, 255, 255, 0.2);
-  }
-  100% {
-    box-shadow:
-      0 6px 16px rgba(34, 197, 94, 0.35),
-      0 3px 8px rgba(34, 197, 94, 0.2),
-      0 0 0 1px rgba(34, 197, 94, 0.15),
-      inset 0 1px 0 rgba(255, 255, 255, 0.3);
-  }
-}
-
-/* 响应式调整 */
-@media (max-width: 768px) {
-  .shelf-container {
-    width: 260px !important;
-    height: 100px !important;
-    padding: 0;
-    margin: 0 auto;
-    border-radius: 12px;
-    box-shadow:
-      0 6px 24px rgba(0, 0, 0, 0.15),
-      0 2px 8px rgba(0, 0, 0, 0.08),
-      inset 0 1px 0 rgba(255, 255, 255, 0.2),
-      inset 0 -1px 0 rgba(0, 0, 0, 0.03);
-    border: 1px solid rgba(255, 255, 255, 0.15);
-  }
-
-  .shelf-rack {
-    background:
-      linear-gradient(135deg, rgba(255, 255, 255, 0.9) 0%, rgba(249, 250, 251, 0.9) 100%),
-      radial-gradient(circle at 30% 40%, rgba(59, 130, 246, 0.03) 0%, transparent 40%),
-      radial-gradient(circle at 70% 60%, rgba(16, 185, 129, 0.03) 0%, transparent 40%);
-    backdrop-filter: blur(8px) saturate(1.1);
-    border-radius: 10px;
-    margin: 1px;
-  }
-
-  .rack-body {
-    min-height: calc(18px * var(--rows) + 4px);
-    height: calc(100% - 8px);
-  }
-
-  .rack-pillars {
-    position: relative;
-    margin-bottom: 3px;
-  }
-
-  .rack-pillar {
-    width: 3px;
-  }
-
-  .left-pillar {
-    margin-right: 3px;
-  }
-
-  .right-pillar {
-    margin-left: 3px;
-  }
-
-  .rack-shelves {
-    gap: 2px;
-  }
-
-  .shelf-board {
-    padding: 1px 0px;
-    gap: 1px;
-  }
-
-  .shelf-cell {
-    min-height: 16px;
-    min-width: 32px;
-    padding: 1px;
-    border-width: 1px;
-    margin: 0.5px;
-    border-radius: 3px;
-  }
-
-  .cell-number {
-    font-size: 11px;
-    font-weight: 600;
-  }
-
-  .shelf-cell:hover {
-    transform: none;
-  }
-
-  .shelf-cell.highlight {
-    border-color: #22c55e;
-    border-width: 1.5px;
-    box-shadow: 0 1px 4px rgba(34, 197, 94, 0.15), 0 0 0 1px rgba(34, 197, 94, 0.08);
-  }
+  font-weight: 700;
 }
 </style>