| | |
| | | |
| | | <div class="form-group"> |
| | | <label class="form-label">å··éï¼</label> |
| | | <el-select size="mini" clearable filterable v-model="selectedRoadwayNo" placeholder="è¯·éæ©å··é" class="full-width" |
| | | @change="handleRoadwayNoChange"> |
| | | <el-select size="mini" clearable filterable v-model="selectedRoadwayNo" placeholder="è¯·éæ©å··é" |
| | | class="full-width" @change="handleRoadwayNoChange"> |
| | | <el-option v-for="item in roadwayNoList" :key="item" :value="item" :label="'å··é ' + item"></el-option> |
| | | </el-select> |
| | | </div> |
| | |
| | | </div> |
| | | |
| | | <div class="layers-container"> |
| | | <!-- é忝ä¸å± --> |
| | | <div class="layer-row" v-for="layer in sortedLayerData" :key="layer.layer"> |
| | | <div class="layer-title-area"> |
| | | <h3 class="layer-title">å± {{ layer.layer }}</h3> |
| | |
| | | </div> |
| | | |
| | | <div class="layer-content-wrap"> |
| | | <div class="layer-content"> |
| | | <div class="location-column" v-for="column in sortedColumns(layer.columns)" :key="column.column"> |
| | | <div class="column-label">å {{ column.column }}</div> |
| | | <div class="locations-wrapper"> |
| | | <div class="location-item" v-for="depth in sortedDepthsByRow(column.depths)" :key="depth.depth" |
| | | :class="getLocationStatusClass(depth)" |
| | | @mouseenter="showTooltip(depth, column.column, layer.layer, $event)" @mouseleave="hideTooltip" |
| | | @click="handleLocationClick(depth)"> |
| | | <div class="location-code"> |
| | | {{ depth.row || '?' }}æ-{{ column.column }}å-{{ layer.layer }}å±-{{ depth.depth == 1 ? 'æµ
' : 'æ·±' }} |
| | | </div> |
| | | <div class="location-status" v-if="depth.enableStatus !== 0"> |
| | | ç¦ç¨ |
| | | <!-- æè¡åç»æ¾ç¤º --> |
| | | <div class="row-group" v-for="rowGroup in getRowGroups(layer)" :key="rowGroup.row"> |
| | | <div class="row-title"> |
| | | <span class="row-label">{{ rowGroup.row }}æ</span> |
| | | <span class="row-count">{{ rowGroup.locations.length }} 个货ä½</span> |
| | | </div> |
| | | |
| | | <div class="row-content"> |
| | | <!-- 卿¯æå
æ¾ç¤ºåï¼ä¸æ¾ç¤ºåæ ç¾ï¼ --> |
| | | <div class="location-column" v-for="column in sortedColumns(rowGroup.columns)" :key="column.column"> |
| | | <div class="locations-wrapper"> |
| | | <!-- æ¯åæ¾ç¤ºæ·±åº¦ï¼æµ
/æ·±ï¼ --> |
| | | <div class="location-item" v-for="depth in column.depths" :key="depth.depth" |
| | | :class="getLocationStatusClass(depth)" |
| | | @mouseenter="showTooltip(depth, column.column, layer.layer, $event)" |
| | | @mouseleave="hideTooltip" |
| | | @click="handleLocationClick(depth)"> |
| | | <div class="location-code"> |
| | | {{ getLocationPositionForDisplay(depth, column.column, layer.layer) }} |
| | | </div> |
| | | <div class="location-status" v-if="depth.enableStatus !== 0"> |
| | | ç¦ç¨ |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | <div class="tooltip-body"> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">ä½ç½®ï¼</span> |
| | | <span class="tooltip-value">{{ getLocationCode(currentLocation) }}</span> |
| | | <span class="tooltip-label">ä»åºï¼</span> |
| | | <span class="tooltip-value">{{ getWarehouseName(selectedWarehouse) }}</span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">å··éï¼</span> |
| | | <span class="tooltip-value">{{ selectedRoadwayNo }}</span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">深度ï¼</span> |
| | | <span class="tooltip-value">{{ currentLocation.depth === 1 ? 'æµ
' : 'æ·±' }}</span> |
| | | <span class="tooltip-label">è´§ä½ç¼å·ï¼</span> |
| | | <span class="tooltip-value">{{ currentLocation?.locationCode || '--' }}</span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">ä½ç½®ï¼</span> |
| | | <span class="tooltip-value">{{ getLocationPosition(currentLocation) }}</span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">ç±»åï¼</span> |
| | | <span class="tooltip-value">{{ getLocationTypeText(currentLocation.locationType) }}</span> |
| | | <span class="tooltip-value">{{ getLocationTypeText(currentLocation?.locationType) }}</span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">ç¶æï¼</span> |
| | | <span class="tooltip-value" :class="getStatusClass(currentLocation.locationStatus)"> |
| | | {{ getStatusText(currentLocation.locationStatus) }} |
| | | <span class="tooltip-value" :class="getStatusClass(currentLocation?.locationStatus)"> |
| | | {{ getStatusText(currentLocation?.locationStatus) }} |
| | | </span> |
| | | </div> |
| | | <div class="tooltip-row"> |
| | | <span class="tooltip-label">å¯ç¨ç¶æï¼</span> |
| | | <span class="tooltip-value" :class="{ 'status-disabled': currentLocation.enableStatus !== 0 }"> |
| | | {{ getEnableStatusText(currentLocation.enableStatus) }} |
| | | <span class="tooltip-value" :class="{ 'status-disabled': currentLocation?.enableStatus !== 0 }"> |
| | | {{ getEnableStatusText(currentLocation?.enableStatus) }} |
| | | </span> |
| | | </div> |
| | | </div> |
| | |
| | | roadwayNoList: [], |
| | | selectedWarehouse: null, |
| | | selectedRoadwayNo: null, |
| | | selectedLocationCode: null, |
| | | infoMsg: [ |
| | | { bgcolor: "lightgreen", msg: "空货ä½" }, |
| | | { bgcolor: "#2BB3D5", msg: "空货ä½" }, |
| | | { bgcolor: "orange", msg: "æè´§" }, |
| | | { bgcolor: "#2BB3D5", msg: "éå®" }, |
| | | { bgcolor: "#ccc", msg: "ç¦ç¨" }, |
| | | { bgcolor: "#b7ba6b", msg: "å
¶å®" }, |
| | | { bgcolor: "lightgreen", msg: "éå®" }, |
| | | { bgcolor: "#ccc", msg: "ç¦ç¨" } |
| | | ], |
| | | locationData: [], |
| | | showTooltipFlag: false, |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | sortedColumns(columns) { |
| | | // æåå·æåº |
| | | return columns?.sort((a, b) => a.column - b.column) || []; |
| | | // æè¡åç»æ°æ® |
| | | getRowGroups(layer) { |
| | | const rowMap = {}; |
| | | |
| | | // éåææååæ·±åº¦ï¼æè¡åç» |
| | | layer.columns?.forEach(column => { |
| | | column.depths?.forEach(depth => { |
| | | const row = depth.row || '?'; |
| | | |
| | | if (!rowMap[row]) { |
| | | rowMap[row] = { |
| | | row: row, |
| | | locations: [], |
| | | columns: {} |
| | | }; |
| | | } |
| | | |
| | | // æ·»å å°è¯¥è¡çä½ç½®å表 |
| | | rowMap[row].locations.push({ |
| | | ...depth, |
| | | column: column.column, |
| | | layer: layer.layer |
| | | }); |
| | | |
| | | // æåç»ç»æ°æ® |
| | | if (!rowMap[row].columns[column.column]) { |
| | | rowMap[row].columns[column.column] = { |
| | | column: column.column, |
| | | depths: [] |
| | | }; |
| | | } |
| | | |
| | | rowMap[row].columns[column.column].depths.push(depth); |
| | | }); |
| | | }); |
| | | |
| | | // 转æ¢ä¸ºæ°ç»å¹¶æè¡æåº |
| | | return Object.values(rowMap) |
| | | .sort((a, b) => this.compareRows(a.row, b.row)); |
| | | }, |
| | | |
| | | sortedDepthsByRow(depths) { |
| | | // é¦å
æè¡(row)æåºï¼ç¶åææ·±åº¦(depth)æåº |
| | | return depths?.sort((a, b) => { |
| | | // 妿è¡å·ç¸åï¼ææ·±åº¦æåº |
| | | if (a.row === b.row) { |
| | | return a.depth - b.depth; |
| | | } |
| | | // æè¡å·æåºï¼è¿éå设è¡å·æ¯æ°åæå¯æ¯è¾çåç¬¦ä¸²ï¼ |
| | | return this.compareRows(a.row, b.row); |
| | | }) || []; |
| | | sortedColumns(columnsObj) { |
| | | // å°å¯¹è±¡è½¬æ¢ä¸ºæ°ç»å¹¶æåå·æåº |
| | | const columns = Object.values(columnsObj || {}); |
| | | return columns.sort((a, b) => a.column - b.column); |
| | | }, |
| | | |
| | | // æ¯è¾è¡å·çè¾
婿¹æ³ |
| | |
| | | } |
| | | // å¦åæå符串æ¯è¾ |
| | | return String(rowA).localeCompare(String(rowB)); |
| | | }, |
| | | |
| | | // è·åä½ç½®ä¿¡æ¯ç¨äºæ¾ç¤º |
| | | getLocationPositionForDisplay(location, column, layer) { |
| | | if (!location) return ''; |
| | | const row = location.row || '?'; |
| | | const depthText = location.depth === 1 ? 'æµ
' : 'æ·±'; |
| | | return `${row}æ${column}å${layer}å±${depthText}`; |
| | | }, |
| | | |
| | | // è·åä½ç½®ä¿¡æ¯ï¼ç¨äºæ¬æµ®æç¤ºæ¡ï¼ |
| | | getLocationPosition(location) { |
| | | if (!location || !this.currentColumn || !this.currentLayer) return '--'; |
| | | const row = location.row || '?'; |
| | | const depthText = location.depth === 1 ? 'æµ
' : 'æ·±'; |
| | | return `${row}æ-${this.currentColumn}å-${this.currentLayer}å±-${depthText}`; |
| | | }, |
| | | |
| | | async fetchWarehouseData() { |
| | |
| | | |
| | | if (response.data && response.status) { |
| | | this.locationData = response.data || []; |
| | | |
| | | // éªè¯æ°æ®ä¸æ¯å¦ærowåæ®µ |
| | | console.log("è´§ä½æ°æ®ç¤ºä¾:", this.locationData[0]); |
| | | |
| | | // éªè¯æ°æ® |
| | | console.log("è´§ä½æ°æ®:", this.locationData); |
| | | if (this.locationData.length > 0 && this.locationData[0].columns) { |
| | | console.log("第ä¸ä¸ªè´§ä½çrowåæ®µ:", this.locationData[0].columns[0]?.depths?.[0]?.row); |
| | | console.log("示ä¾è´§ä½:", this.locationData[0].columns[0]?.depths?.[0]); |
| | | } |
| | | |
| | | |
| | | if (this.locationData.length === 0) { |
| | | ElMessage.info("è¯¥å··éæ²¡æè´§ä½æ°æ®"); |
| | | } |
| | |
| | | } |
| | | |
| | | switch (depth.locationStatus) { |
| | | case 0: return 'location-empty'; // ç©ºè´§ä½ |
| | | case 1: return 'location-locked'; // éå® |
| | | case 0: return 'location-empty'; // ç©ºè´§ä½ |
| | | case 1: return 'location-locked'; // éå® |
| | | case 100: return 'location-occupied'; // æè´§ |
| | | default: return 'location-other'; // å
¶ä»ç¶æ |
| | | default: return 'location-other'; |
| | | } |
| | | }, |
| | | |
| | |
| | | |
| | | handleLocationClick(depth) { |
| | | console.log('ç¹å»è´§ä½:', depth); |
| | | }, |
| | | |
| | | getLocationCode(location) { |
| | | if (!location) return ''; |
| | | return `${location.row || '?'}æ-${this.currentColumn}å-${this.currentLayer}å±-${location.depth === 1 ? 'æµ
' : 'æ·±'}`; |
| | | // è¿éå¯ä»¥æ·»å ç¹å»è´§ä½çå¤çé»è¾ |
| | | ElMessage.info(`éä¸è´§ä½: ${depth.locationCode || 'æªç¥è´§ä½'}`); |
| | | }, |
| | | |
| | | getStatusText(status) { |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | /* æ ·å¼é¨åä¿æä¸åï¼ä¸ä¹åç¸å */ |
| | | /* æ ·å¼é¨å */ |
| | | .container { |
| | | display: flex; |
| | | flex-direction: column; |
| | |
| | | padding: 16px; |
| | | box-sizing: border-box; |
| | | background-color: #f0f2f5; |
| | | } |
| | | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| | | padding-bottom: 16px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | .title { |
| | | font-size: 22px; |
| | | font-weight: 600; |
| | | margin: 0; |
| | | color: #1890ff; |
| | | } |
| | | |
| | | .content-wrapper { |
| | |
| | | border-radius: 4px; |
| | | border: 1px solid rgba(0, 0, 0, 0.1); |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .depth-shallow-legend { |
| | | background-color: rgba(255, 255, 255, 0.7); |
| | | border: 1px solid #2c3e50; |
| | | } |
| | | |
| | | .depth-deep-legend { |
| | | background-color: rgba(0, 0, 0, 0.7); |
| | | border: 1px solid #000; |
| | | } |
| | | |
| | | .legend-label { |
| | |
| | | width: 100%; |
| | | overflow: hidden; |
| | | flex: 1; |
| | | padding: 16px; |
| | | } |
| | | |
| | | .layer-content { |
| | | /* è¡ç»æ ·å¼ */ |
| | | .row-group { |
| | | margin-bottom: 10px; |
| | | padding: 12px; |
| | | background: white; |
| | | border-radius: 6px; |
| | | border: 1px solid #e8e8e8; |
| | | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .row-group:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .row-title { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | padding-bottom: 8px; |
| | | border-bottom: 1px dashed #e8e8e8; |
| | | } |
| | | |
| | | .row-label { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .row-count { |
| | | font-size: 12px; |
| | | color: #666; |
| | | background: #f0f0f0; |
| | | padding: 2px 8px; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .row-content { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | padding: 16px; |
| | | min-width: 0; |
| | | box-sizing: border-box; |
| | | gap: 8px; /* åå°é´è· */ |
| | | } |
| | | |
| | | /* 缩å°è´§ä½æ¡å°ºå¯¸ */ |
| | | .location-column { |
| | | flex: 0 0 auto; |
| | | width: 140px; |
| | | min-height: 120px; |
| | | width: 70px; /* åå°å®½åº¦ */ |
| | | min-height: 30px; /* åå°é«åº¦ */ |
| | | display: flex; |
| | | flex-direction: column; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .column-label { |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | color: #666; |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | padding-bottom: 4px; |
| | | border-bottom: 1px dashed #ddd; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .locations-wrapper { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 6px; |
| | | gap: 4px; /* åå°é´è· */ |
| | | flex: 1; |
| | | min-height: 0; |
| | | } |
| | | |
| | | /* 缩å°è´§ä½é¡¹ */ |
| | | .location-item { |
| | | min-height: 40px; |
| | | padding: 6px 4px; |
| | | min-height: 32px; /* åå°é«åº¦ */ |
| | | padding: 4px 2px; /* åå°å
è¾¹è· */ |
| | | border-radius: 4px; |
| | | text-align: center; |
| | | cursor: pointer; |
| | |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 2px; |
| | | gap: 1px; |
| | | flex: 1; |
| | | } |
| | | |
| | |
| | | z-index: 10; |
| | | } |
| | | |
| | | /* 缩å°è´§ä½ç¼å·åä½ */ |
| | | .location-code { |
| | | font-size: 11px; |
| | | font-size: 9px; /* åå°åä½ */ |
| | | font-weight: 500; |
| | | line-height: 1.2; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .depth-indicator { |
| | | font-size: 10px; |
| | | padding: 2px 4px; |
| | | border-radius: 3px; |
| | | margin-top: 2px; |
| | | font-weight: bold; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .depth-shallow { |
| | | background-color: rgba(255, 255, 255, 0.7); |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | .depth-deep { |
| | | background-color: rgba(0, 0, 0, 0.7); |
| | | color: white; |
| | | } |
| | | |
| | | .location-item:hover .depth-indicator { |
| | | transform: scale(1.1); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .location-status { |
| | | font-size: 10px; |
| | | padding: 1px 4px; |
| | | font-size: 8px; /* åå°åä½ */ |
| | | padding: 1px 3px; |
| | | border-radius: 2px; |
| | | background: rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | /* è´§ä½ç¶æé¢è² */ |
| | | .location-empty { |
| | | background-color: lightgreen; |
| | | color: #333; |
| | | background-color: #2BB3D5; |
| | | color: white; |
| | | } |
| | | |
| | | .location-occupied { |
| | |
| | | } |
| | | |
| | | .location-locked { |
| | | background-color: #2BB3D5; |
| | | color: white; |
| | | background-color: lightgreen; |
| | | color: #333; |
| | | } |
| | | |
| | | .location-disabled { |
| | |
| | | color: #f5222d; |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .location-column { |
| | | width: 130px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .content-wrapper { |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .control-panel { |
| | | width: 100%; |
| | | } |
| | | |
| | | .location-column { |
| | | width: 120px; |
| | | } |
| | | |
| | | .layer-content { |
| | | gap: 12px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 480px) { |
| | | .location-column { |
| | | width: 110px; |
| | | } |
| | | |
| | | .location-code { |
| | | font-size: 10px; |
| | | } |
| | | |
| | | .layer-content { |
| | | gap: 10px; |
| | | padding: 12px; |
| | | } |
| | | |
| | | @media (max-width: 380px) { |
| | | .location-column { |
| | | width: 100px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* æ»å¨æ¡æ ·å¼ */ |
| | | .layers-container::-webkit-scrollbar { |
| | | width: 8px; |
| | | } |
| | |
| | | .layers-container::-webkit-scrollbar-thumb:hover { |
| | | background: #a8a8a8; |
| | | } |
| | | |
| | | /* ååºå¼è®¾è®¡ */ |
| | | @media (max-width: 1200px) { |
| | | .location-column { |
| | | width: 95px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .content-wrapper { |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .control-panel { |
| | | width: 100%; |
| | | } |
| | | |
| | | .location-column { |
| | | width: 90px; |
| | | } |
| | | |
| | | .row-content { |
| | | gap: 6px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 480px) { |
| | | .location-column { |
| | | width: 80px; |
| | | } |
| | | |
| | | .location-code { |
| | | font-size: 8px; |
| | | } |
| | | |
| | | .row-content { |
| | | gap: 4px; |
| | | } |
| | | |
| | | .row-group { |
| | | padding: 8px; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 380px) { |
| | | .location-column { |
| | | width: 70px; |
| | | } |
| | | |
| | | .location-code { |
| | | font-size: 7px; |
| | | } |
| | | } |
| | | </style> |