<template>
|
<div class="container">
|
<div class="content-wrapper">
|
<!-- 控制面板区域 -->
|
<!-- <div class="form-group">
|
<label>区域:</label>
|
<el-select
|
size="mini"
|
filterable
|
v-model="Area.shelf_code"
|
placeholder="请选择"
|
class="full-width"
|
>
|
<el-option
|
v-for="item in slectData"
|
:value="item.shelf_code"
|
:label="item.house_name"
|
:key="item.house_name"
|
></el-option>
|
</el-select>
|
</div> -->
|
|
<div class="form-group">
|
<div style="display:flex;flex-direction: column;">
|
<h4>仓库</h4>
|
<el-select size="mini" @change="onWarehouseChange" v-model="Area.warehouse" placeholder="请选择仓库"
|
class="full-width">
|
<el-option v-for="item in warehouseList" :value="item" :label="item" :key="item"></el-option>
|
</el-select>
|
<h4>货位排</h4>
|
<el-select size="mini" @change="SCChange" v-model="Area.row" placeholder="请选择排" class="full-width">
|
<el-option v-for="item in scList" :value="item" :label="'第' + item + '排'" :key="item"></el-option>
|
</el-select>
|
<el-button type="success" class="refresh-btn" @click="GetViewData">
|
刷新
|
</el-button>
|
</div>
|
|
<div class="legend-section" style="margin-left: 20px;">
|
<h4>说明</h4>
|
<div class="legend-grid">
|
<div class="legend-item" v-for="item in infoMsg" :key="item.bgcolor">
|
<span class="color-box" :style="{ 'background-color': item.bgcolor }"></span>
|
<span class="legend-label">{{ item.msg }}</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 货位展示区域 -->
|
<div v-if="loading" class="loading-container">
|
<el-icon class="is-loading">
|
<Loading />
|
</el-icon>
|
<span>加载中...</span>
|
</div>
|
|
<div v-else-if="locationData.length === 0" class="empty-container">
|
<el-empty description="暂无数据" />
|
</div>
|
|
<div v-else>
|
<div class="location-view">
|
<div class="layer-container" v-for="(item, index) in locationData" :key="index">
|
<h3 class="layer-title">第{{ item.layer }}层</h3>
|
<div class="row">
|
<div class="location-cell" :style="{ 'background-color': GetBgColor(column) }"
|
v-for="(column, index) in item.locationObj" :key="index" @mouseenter="showTooltip(column, $event)"
|
@mouseleave="hideTooltip">
|
{{ column.row }}-{{ column.column }}-{{ column.layer }}
|
</div>
|
</div>
|
</div>
|
</div>
|
<!-- 悬浮提示框 -->
|
<div v-if="showTooltipFlag" class="location-tooltip" :style="{
|
left: tooltipPosition.x + 'px',
|
top: tooltipPosition.y + 'px',
|
}">
|
<div v-if="currentLocation">
|
<p><strong>仓库:</strong>{{ Area.warehouse || "未选择" }}</p>
|
<p><strong>货位号:</strong>{{ currentLocation.locationCode }}</p>
|
<!-- <p><strong>料箱号:</strong>{{ currentLocation.barCode ? currentLocation.barCode : "无料箱" }}</p> -->
|
<!-- 根据仓库类型显示不同的标签和内容 -->
|
<p v-if="Area.warehouse === '原料库'">
|
<strong>RFID:</strong>{{ this.rfidData[currentLocation.locationCode] || "无" }}
|
</p>
|
<p v-else-if="Area.warehouse === '成品库'">
|
<strong>托盘号:</strong>{{ this.rfidData[currentLocation.locationCode] || "无" }}
|
</p>
|
<p v-else>
|
<strong>标识:</strong>{{ this.rfidData[currentLocation.locationCode] || "无" }}
|
</p>
|
<p>
|
<strong>排列层:</strong> {{ currentLocation.row }}排{{
|
currentLocation.column
|
}}列{{ currentLocation.layer }}层
|
</p>
|
<p><strong>状态:</strong> {{ getStatusText(currentLocation) }}</p>
|
<!-- <p>
|
<strong>禁用:</strong>
|
{{ currentLocation.location_lock == 3 ? "是" : "否" }}
|
</p> -->
|
<!-- <p v-if="currentLocation.location_state > 0">
|
<strong>物料编码:</strong>
|
{{ currentLocation.material_code || "无" }}
|
</p>
|
<p v-if="currentLocation.location_state > 0">
|
<strong>数量:</strong> {{ currentLocation.quantity || "无" }}
|
</p> -->
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { ElButton, Loading } from "element-plus";
|
|
export default {
|
data() {
|
return {
|
slectData: [],
|
scList: [],
|
warehouseList: ["原料库", "成品库"],
|
warehouseMap: {
|
"原料库": 1,
|
"成品库": 2
|
},
|
Area: {
|
warehouse: "原料库",
|
row: "",
|
shelf_code: ""
|
},
|
mian_height: "",
|
loading: false,
|
infoMsg: [
|
{ bgcolor: "lightgreen", msg: "空闲", state: 0 },
|
{ bgcolor: "orange", msg: "有货", state: 100 },
|
{ bgcolor: "#2BB3D5", msg: "锁定", state: 1 },
|
{ bgcolor: "yellow", msg: "空闲锁定", state: 20 },
|
{ bgcolor: "purple", msg: "有货锁定", state: 10 },
|
],
|
locationData: [],
|
showTooltipFlag: false,
|
currentLocation: null,
|
tooltipPosition: { x: 0, y: 0 },
|
rfidData: {}, // 存储货位编号与RFID的映射关系
|
};
|
},
|
computed: {
|
GetBgColor() {
|
return (col) => {
|
var bgColor = "";
|
//优先显示禁用状态
|
if (col.location_lock > 0) {
|
this.infoMsg.forEach((el) => {
|
if (el.state === col.location_lock) {
|
bgColor = el.bgcolor;
|
}
|
});
|
}
|
else {
|
return "lightgreen";
|
}
|
return bgColor;
|
};
|
},
|
},
|
methods: {
|
// 获取RFID信息
|
getRfidInfo(locationCodes, warehouseId) {
|
if (!locationCodes || locationCodes.length === 0) {
|
console.log("没有货位编号,跳过RFID查询");
|
return;
|
}
|
|
console.log("调用RFID查询API:", {
|
locationCodes: locationCodes,
|
warehouseId: warehouseId
|
});
|
|
this.http
|
.post(`/api/LocationInfo/GetRfid`, { locationCodes, warehouseId }, "查询RFID中")
|
.then((response) => {
|
console.log("RFID查询API返回结果:", response);
|
if (response.status && response.data) {
|
console.log(`成功获取${response.data.length}条RFID记录`);
|
// 更新rfidData映射
|
response.data.forEach((item, index) => {
|
try {
|
// 检查字段名,支持大小写两种格式
|
const locationCode = item.LocationCode || item.locationCode;
|
const rfidCode = item.RfidCode || item.rfidCode;
|
|
if (item && locationCode !== undefined) {
|
console.log(`更新RFID数据: ${locationCode} -> ${rfidCode}`);
|
this.rfidData[locationCode] = rfidCode;
|
} else {
|
console.warn(`跳过无效的RFID数据项(${index}):`, item);
|
}
|
} catch (error) {
|
console.error(`处理RFID数据项(${index})时出错:`, error, item);
|
}
|
});
|
console.log("更新后的rfidData:", this.rfidData);
|
} else {
|
console.log("RFID查询API返回状态失败或数据为空");
|
}
|
})
|
.catch((error) => {
|
console.error("获取RFID信息失败:", error);
|
});
|
},
|
|
GetViewData() {
|
var _this = this;
|
|
this.loading = true;
|
this.rfidData = {}; // 清空之前的RFID数据
|
|
let warehouseId = 0;
|
if (this.Area.warehouse) {
|
warehouseId = this.warehouseMap[this.Area.warehouse] || 1;
|
console.log(`当前选择的仓库: ${this.Area.warehouse}, 对应的warehouseId: ${warehouseId}`);
|
}
|
|
console.log(`调用GetLocationStatus API: row=${_this.Area.row}, warehouseId=${warehouseId}`);
|
|
this.http
|
.post(`/api/LocationInfo/GetLocationStatus?row=${_this.Area.row}&warehouseId=${warehouseId}`, {}, "查询中")
|
.then((x) => {
|
console.log("GetLocationStatus API返回结果:", x);
|
this.locationData = x.data || [];
|
|
// 提取所有货位编号
|
let locationCodes = [];
|
this.locationData.forEach(layer => {
|
layer.locationObj.forEach(location => {
|
locationCodes.push(location.locationCode);
|
});
|
});
|
|
console.log(`从货位数据中提取到${locationCodes.length}个货位编号`);
|
console.log("提取的货位编号:", locationCodes);
|
|
// 调用API获取RFID信息
|
this.getRfidInfo(locationCodes, warehouseId);
|
})
|
.catch((error) => {
|
this.$message.error("获取数据失败,请重试");
|
console.error("获取货位状态失败:", error);
|
})
|
.finally(() => {
|
this.loading = false;
|
});
|
},
|
|
// 切换排
|
SCChange() {
|
this.GetViewData();
|
},
|
// 切换仓库
|
onWarehouseChange() {
|
// 切换仓库时重置排选择
|
this.GetViewData();
|
},
|
showTooltip(location, event) {
|
this.currentLocation = location;
|
this.showTooltipFlag = true;
|
|
// 设置提示框位置,稍微偏移避免遮挡鼠标
|
this.tooltipPosition = {
|
x: event.clientX + 10,
|
y: event.clientY + 10,
|
};
|
},
|
|
hideTooltip() {
|
this.showTooltipFlag = false;
|
this.currentLocation = null;
|
},
|
|
getStatusText(location) {
|
// if (location.location_lock === 3) return "禁用";
|
if (location.location_lock === 0) return "空闲";
|
if (location.location_lock === 1) return "锁定";
|
if (location.location_lock === 100) return "有货";
|
if (location.location_lock === 20) return "空闲锁定";
|
if (location.location_lock === 10) return "有货锁定";
|
// if (location.location_state > 0 && location.location_state < 100)
|
// return "锁定";
|
return "其他";
|
},
|
getWarehouseName(location) {
|
if (location.warehouseId === 1) return "原料库";
|
if (location.warehouseId === 2) return "成品库";
|
return "未知仓库";
|
},
|
},
|
mounted() {
|
var mainHeight = document.getElementById("vol-main");
|
if (mainHeight) {
|
this.mian_height = mainHeight.offsetHeight - 40 + "px";
|
}
|
var _this = this;
|
//加载下拉选项
|
this.http.post("/api/LocationInfo/GetRow", {}, "查询中").then((x) => {
|
//加载第一个区域,第一排
|
// _this.Area.shelf_code = _this.slectData[0].shelf_code;
|
_this.scList = x.data;
|
if (_this.scList.length > 0) {
|
_this.Area.row = _this.scList[0];
|
}
|
_this.GetViewData();
|
});
|
},
|
components: { ElButton, Loading },
|
};
|
</script>
|
|
<style scoped>
|
.container {
|
display: flex;
|
flex-direction: column;
|
height: 100%;
|
width: 100%;
|
padding: 10px;
|
}
|
|
.header {
|
text-align: center;
|
margin-bottom: 20px;
|
}
|
|
.title {
|
font-size: 20px;
|
font-weight: bold;
|
margin: 0;
|
}
|
|
.content-wrapper {
|
display: flex;
|
flex: 1;
|
min-height: 0;
|
padding: 10px;
|
}
|
|
.full-width {
|
width: 100%;
|
}
|
|
.refresh-btn {
|
margin-top: 10px;
|
width: 35%;
|
}
|
|
.legend-section h4 {
|
margin-bottom: 10px;
|
}
|
|
.legend-grid {
|
display: flex;
|
flex-direction: column;
|
gap: 8px;
|
}
|
|
.legend-item {
|
display: flex;
|
align-items: center;
|
}
|
|
.color-box {
|
display: inline-block;
|
width: 20px;
|
height: 20px;
|
margin-right: 8px;
|
border-radius: 3px;
|
}
|
|
.legend-label {
|
font-size: 13px;
|
}
|
|
.location-view {
|
flex: 1;
|
width: 100%;
|
max-width: 100%;
|
overflow: auto;
|
padding: 10px;
|
background-color: white;
|
border-radius: 4px;
|
}
|
|
.layer-container {
|
margin-bottom: 25px;
|
}
|
|
.layer-title {
|
margin: 0 0 10px 0;
|
font-size: 16px;
|
color: #333;
|
}
|
|
.row {
|
display: flex;
|
flex-wrap: wrap;
|
margin-bottom: 8px;
|
cursor: pointer;
|
}
|
|
.location-cell {
|
width: 85px;
|
height: 38px;
|
margin: 3px;
|
text-align: center;
|
font-size: 14px;
|
border-radius: 3px;
|
line-height: 38px;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
}
|
|
.location-tooltip {
|
position: fixed;
|
z-index: 9999;
|
background-color: white;
|
border: 1px solid #ddd;
|
border-radius: 4px;
|
padding: 10px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
pointer-events: none;
|
max-width: 250px;
|
}
|
|
.location-tooltip p {
|
margin: 5px 0;
|
font-size: 13px;
|
line-height: 1.4;
|
}
|
|
.location-tooltip strong {
|
display: inline-block;
|
width: 70px;
|
color: #666;
|
}
|
|
.form-group {
|
display: flex;
|
}
|
|
.loading-container {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
height: 200px;
|
font-size: 16px;
|
}
|
|
.empty-container {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
height: 200px;
|
}
|
</style>
|