Files
klp-oa/klp-ui/src/views/wms/warehouse/components/WarehouseGrid.vue
砂糖 dd5c86470c style(wms): 修改仓库视图中的禁用和占用状态背景色
将禁用状态和占用状态的背景色统一改为更醒目的黄色(#eeff6f),提高视觉辨识度
2025-12-06 10:24:07 +08:00

366 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<div style="display: flex; align-items: center;">
<el-divider content-position="left">{{ layer }}层库位</el-divider>
<el-button type="text" icon="el-icon-refresh-left" size="mini" @click="toggleTranspose">
{{ isTransposed ? '恢复行列' : '行列转置' }}
</el-button>
</div>
<div class="grid-wrapper">
<div class="grid-scroll-container" ref="scrollContainerRef">
<div class="scroll-content" ref="contentRef">
<!-- 列标尺顶部 -->
<div class="col-ruler" :style="{ '--cell-width': `${cellWidth}px` }">
<div class="ruler-empty"></div>
<div v-for="col in transposedLayerData.maxColumn" :key="`col-${layer}-${col}`" class="ruler-item">
{{ col }}
</div>
</div>
<!-- 行标尺 + 库位网格 -->
<div class="row-grid-wrapper">
<!-- 行标尺左侧 -->
<div class="row-ruler">
<div v-for="row in transposedLayerData.maxRow" :key="`row-${layer}-${row}`" class="ruler-item">
{{ row }}
</div>
</div>
<!-- 库位网格 - 修复伪元素遮挡问题 -->
<div class="grid-container"
:style="{
'--cell-width': `${cellWidth}px`,
'--column-count': transposedLayerData.maxColumn
}">
<!-- 库位格子 -->
<div v-for="warehouse in transposedLayerData.warehouses" :key="warehouse.actualWarehouseId"
class="warehouse-cell" :class="{ disabled: warehouse.isEnabled === 0 }"
@click="handleCellClick(warehouse)">
<div class="cell-name">{{ warehouse.actualWarehouseName || '-' }}</div>
</div>
<!-- 空库位占位 -->
<div class="warehouse-cell empty-cell" v-for="i in transposedLayerData.emptyCount"
:key="`empty-${layer}-${i}`">
<div class="cell-code">-</div>
</div>
</div>
</div>
</div>
</div>
<!-- 弹窗修复改回 .sync 绑定恢复 footer 插槽写法 -->
<el-dialog title="库位详情" :visible.sync="dialogVisible" width="600px" destroy-on-close append-to-body center>
<el-descriptions :column="2" border size="small" v-if="currentWarehouse">
<el-descriptions-item label="库位编码">{{ currentWarehouse.actualWarehouseCode }}</el-descriptions-item>
<el-descriptions-item label="库位名称">{{ currentWarehouse.actualWarehouseName || '无' }}</el-descriptions-item>
<el-descriptions-item label="所属层级">{{ currentWarehouse.parsedInfo.layer || '未知' }}</el-descriptions-item>
<el-descriptions-item label="行号">
{{ isTransposed ? currentWarehouse.parsedInfo.column : currentWarehouse.parsedInfo.row || '未知' }}
</el-descriptions-item>
<el-descriptions-item label="列号">
{{ isTransposed ? currentWarehouse.parsedInfo.row : currentWarehouse.parsedInfo.column || '未知' }}
</el-descriptions-item>
<el-descriptions-item label="一级编码">{{ currentWarehouse.parsedInfo.warehouseFirst || '未知' }}</el-descriptions-item>
<el-descriptions-item label="二级编码">{{ currentWarehouse.parsedInfo.warehouseSecond || '未知' }}</el-descriptions-item>
<el-descriptions-item label="启用状态">
<el-tag :type="currentWarehouse.isEnabled === 1 ? 'success' : 'danger'">
{{ currentWarehouse.isEnabled === 1 ? '启用' : '禁用' }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="库位码">
<QRCode :content="currentWarehouse.actualWarehouseId" size="60" />
</el-descriptions-item>
<el-descriptions-item label="创建时间" span="2">{{ currentWarehouse.createTime || '无' }}</el-descriptions-item>
<el-descriptions-item label="备注信息" span="2">{{ currentWarehouse.remark || '无' }}</el-descriptions-item>
</el-descriptions>
<template slot="footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</template>
</el-dialog>
</div>
</div>
</template>
<script>
import QRCode from '@/components/QRCode/index.vue';
export default {
name: "WarehouseGrid",
components: { QRCode },
props: {
layer: {
type: [String, Number],
required: true
},
layerData: {
type: Object,
required: true,
default: () => ({
maxRow: 0,
maxColumn: 0,
warehouses: [],
emptyCount: 0
})
}
},
data() {
return {
dialogVisible: false,
currentWarehouse: null,
isTransposed: false,
containerWidth: 0,
resizeTimer: null
};
},
computed: {
transposedLayerData() {
const { maxRow, maxColumn, warehouses } = this.layerData;
const transMaxRow = this.isTransposed ? maxColumn : maxRow;
const transMaxColumn = this.isTransposed ? maxRow : maxColumn;
// 深拷贝避免修改原数据
const transWarehouses = JSON.parse(JSON.stringify(warehouses)).map(item => {
if (this.isTransposed && item.parsedInfo) {
const { row, column } = item.parsedInfo;
item.parsedInfo.row = column;
item.parsedInfo.column = row;
}
return item;
});
// 排序保证网格展示顺序正确
transWarehouses.sort((a, b) => {
if (a.parsedInfo.row !== b.parsedInfo.row) {
return a.parsedInfo.row - b.parsedInfo.row;
}
return a.parsedInfo.column - b.parsedInfo.column;
});
const totalGrid = transMaxRow * transMaxColumn;
const emptyCount = Math.max(0, totalGrid - transWarehouses.length);
return {
maxRow: transMaxRow,
maxColumn: transMaxColumn,
warehouses: transWarehouses,
emptyCount
};
},
cellWidth() {
if (!this.containerWidth || this.transposedLayerData.maxColumn === 0) return 60;
// 容器可用宽度 = 滚动容器宽度 - 行标尺宽度(30px)
const availableWidth = Math.max(0, this.containerWidth - 30);
// 均分宽度最小60px
const averageWidth = availableWidth / this.transposedLayerData.maxColumn;
return Math.max(60, averageWidth);
}
},
watch: {
isTransposed() {
this.calcContainerWidth();
},
layerData: {
deep: true,
handler() {
this.calcContainerWidth();
}
}
},
mounted() {
this.calcContainerWidth();
window.addEventListener('resize', this.handleResize);
},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize);
clearTimeout(this.resizeTimer);
},
methods: {
calcContainerWidth() {
if (this.$refs.scrollContainerRef) {
this.containerWidth = this.$refs.scrollContainerRef.clientWidth;
}
},
handleResize() {
clearTimeout(this.resizeTimer);
this.resizeTimer = setTimeout(() => {
this.calcContainerWidth();
}, 100);
},
toggleTranspose() {
this.isTransposed = !this.isTransposed;
this.dialogVisible = false;
this.currentWarehouse = null;
},
// 修复点击事件:增加日志便于调试,确保赋值正确
handleCellClick(warehouse) {
console.log('点击库位:', warehouse); // 调试用
this.currentWarehouse = warehouse;
this.dialogVisible = true;
}
}
};
</script>
<style scoped lang="scss">
.grid-wrapper {
background: #fff;
border-radius: 8px;
overflow: hidden;
width: 100%;
position: relative;
min-height: 100px;
}
.grid-scroll-container {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
position: relative;
padding-bottom: 8px;
&::-webkit-scrollbar {
height: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
scrollbar-width: thin;
scrollbar-color: #c1c1c1 #f1f1f1;
}
.scroll-content {
display: inline-block;
background: #fff;
min-width: 100%;
}
.col-ruler {
display: flex;
height: 30px;
line-height: 30px;
background: #eef2f7;
border-bottom: 1px solid #dcdfe6;
.ruler-empty {
width: 30px;
text-align: center;
font-weight: 600;
color: #606266;
border-right: 1px solid #dcdfe6;
flex-shrink: 0;
}
.ruler-item {
width: var(--cell-width);
min-width: 60px;
text-align: center;
font-weight: 600;
color: #606266;
border-right: 1px solid #dcdfe6;
box-sizing: border-box;
flex-shrink: 0;
}
}
.row-grid-wrapper {
display: flex;
width: 100%;
}
.row-ruler {
width: 30px;
background: #eef2f7;
border-right: 1px solid #dcdfe6;
flex-shrink: 0;
.ruler-item {
height: 60px;
line-height: 60px;
text-align: center;
font-weight: 600;
color: #606266;
border-bottom: 1px solid #dcdfe6;
box-sizing: border-box;
}
}
.grid-container {
display: flex;
flex-wrap: wrap;
width: 100%;
box-sizing: border-box;
// 修复伪元素遮挡点击事件:添加 pointer-events: none
&::before {
content: '';
width: calc(var(--cell-width) * var(--column-count));
display: block;
height: 0;
visibility: hidden;
pointer-events: none; // 关键:让伪元素不拦截点击事件
}
.warehouse-cell {
width: var(--cell-width);
min-width: 60px;
height: 60px;
border: 1px solid #e6e6e6;
border-radius: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.2s;
box-sizing: border-box;
margin: 0;
flex-shrink: 0;
position: relative; // 确保层级正常
z-index: 1; // 高于伪元素
&:hover {
border-color: #409eff;
background: #e8f4ff;
z-index: 2;
}
&.disabled {
background: #eeff6f;
color: #909399;
cursor: not-allowed;
&:hover {
border-color: #e6e6e6;
background: #eeff6f;
}
}
.cell-name {
font-size: 12px;
color: #606266;
word-break: break-all;
text-align: center;
padding: 0 2px;
}
}
.empty-cell {
background: #fafafa;
border-style: solid;
border-color: #e6e6e6;
pointer-events: none; // 空格子不需要点击事件
.cell-code {
color: #c0c4cc;
}
}
}
</style>