<template>
|
<div>
|
<el-row style="padding-bottom: 5px;">
|
<template v-for="item in columnCount" :key="item">
|
<el-col :span="columnWidth">
|
<span class="image-text">{{ 91-item }}</span>
|
<img src="../../public/货架.jpeg" />
|
</el-col>
|
</template>
|
</el-row>
|
</div>
|
<div class="line-container">
|
<div class="line"></div>
|
<div :class="update()" :style="{ transform: `translateX(${calculateDotPosition()}px)` }"
|
ref="childDot" @click="mouseClick"></div>
|
</div>
|
<div>
|
<el-row style="padding-top: 5px;">
|
<template v-for="item in columnCount" :key="item">
|
<el-col :span="columnWidth">
|
<span class="image-text">{{ 91-item }}</span>
|
<img src="../../public/货架.jpeg" />
|
</el-col>
|
</template>
|
<div style="margin-top: 60px;"></div>
|
</el-row>
|
</div>
|
|
<el-dialog v-model="dialogVisible" :before-close="handleClose" width="520px" class="modern-dialog">
|
<div class="dialog-header">
|
<h3 class="dialog-title">堆垛机信息</h3>
|
</div>
|
<div class="dialog-content">
|
<div class="info-list">
|
<div class="info-item">
|
<span class="item-label">设备编号</span>
|
<span class="item-value">{{ yL_DB.R_PP_Status || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">设备状态</span>
|
<span :class="['item-value', statusClass]">{{ yL_DB.YL_Status || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">工作模式</span>
|
<span :class="['item-value', autoStatusClass]">{{ yL_DB.YL_AutoStatus || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">任务号</span>
|
<span class="item-value">{{ yL_DB.YL_TaskNum || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">作业状态</span>
|
<span class="item-value">{{ yL_DB.YL_WorkStatus || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">当前行列层</span>
|
<span class="item-value">{{ yL_DB.YL_Row + '-' + yL_DB.YL_Column + '-' + yL_DB.YL_Layer || '无' }}</span>
|
</div>
|
<div class="info-item">
|
<span class="item-label">报警信息</span>
|
<span class="item-value">{{ yL_DB.StackerAlarm || '无' }}</span>
|
</div>
|
</div>
|
</div>
|
</el-dialog>
|
</template>
|
|
<script>
|
import { id } from "element-plus/es/locale";
|
import JElDescription from "./JElDescription";
|
export default {
|
components: {
|
JElDescription
|
},
|
data() {
|
return {
|
YLDBMap: {
|
YL_Status: {
|
0: "不在线",
|
1: "在线",
|
2: "急停",
|
3: "未知",
|
},
|
YL_AutoStatus: {
|
1: "半自动",
|
2: "单步",
|
3: "自动",
|
4: "手动",
|
5: "脱机",
|
},
|
YL_WorkStatus: {
|
1: "待命",
|
2: "取货完成",
|
3: "取货中",
|
5: "放货中",
|
6: "任务执行错误",
|
7: "未知",
|
9: "任务完成",
|
},
|
},
|
x: 0, // 初始x值
|
dialogVisible: false,
|
timer1: null,
|
yL_DB: {
|
R_PP_Status: "",
|
YL_Status: "",
|
YL_AutoStatus: "",
|
YL_TaskNum: "",
|
YL_WorkStatus: "",
|
YL_WorkType: "",
|
YL_Row: "",
|
YL_Column: "",
|
YL_Layer: "",
|
StackerAlarm: "",
|
CurrentColumn: "1"
|
},
|
form: {
|
TaskType: "",
|
SourceAddress: "",
|
TargetAddress: "",
|
DeviceCode: "",
|
},
|
};
|
},
|
|
props: {
|
equipNo: {
|
type: String,
|
default: "0",
|
},
|
},
|
computed: {
|
dotPosition() {
|
return this.x;
|
},
|
// 列数:原料库90列
|
columnCount() {
|
return 90;
|
},
|
// 列宽:根据90列计算
|
columnWidth() {
|
return 24 / 90;
|
},
|
// 每列的实际宽度(像素)
|
pixelPerColumn() {
|
return 30;
|
},
|
// 仓库最大列数
|
maxColumn() {
|
return 90;
|
},
|
// 设备状态文字颜色
|
statusClass() {
|
const status = this.yL_DB.YL_Status;
|
if (status === '不在线') {
|
return 'status-red';
|
} else if (status === '在线') {
|
return 'status-green';
|
}
|
return '';
|
},
|
// 工作模式文字颜色
|
autoStatusClass() {
|
const status = this.yL_DB.YL_AutoStatus;
|
if (status === '自动' || status === '半自动') {
|
return 'status-green';
|
} else if (status === '手动') {
|
return 'status-blue';
|
} else if (status === '脱机') {
|
return 'status-red';
|
}
|
return '';
|
}
|
},
|
mounted() {
|
// 初始化时传递空对象,避免类型不匹配错误
|
this.moveDot({});
|
// 启动定时器,每秒更新一次数据
|
this.timer1 = setInterval(() => {
|
this.updateData();
|
}, 1000);
|
},
|
beforeUnmount() {
|
// 清除定时器
|
if (this.timer1) {
|
clearInterval(this.timer1);
|
this.timer1 = null;
|
}
|
},
|
watch: {
|
'$root.stackerData': {
|
handler() {
|
this.updateData();
|
},
|
deep: true
|
}
|
},
|
methods: {
|
updateData() {
|
const equipNoStr = String(this.equipNo);
|
if (this.$root.stackerData && this.$root.stackerData[equipNoStr]) {
|
const stackerData = this.$root.stackerData[equipNoStr];
|
this.moveDot(stackerData);
|
}
|
},
|
// 计算指示器位置
|
calculateDotPosition() {
|
// 未收到信息或CurrentColumn为0,指示器在外面
|
if (!this.yL_DB.CurrentColumn || this.yL_DB.CurrentColumn == "0") {
|
return -30; // 显示在货位区域左侧外面
|
}
|
|
// 计算指示器位置,确保与对应列对齐
|
const currentColumn = parseInt(this.yL_DB.CurrentColumn);
|
|
// 实际货位宽度(图片宽度)
|
const columnWidth = 30; // 货位图片宽度为30px
|
const dotWidth = 25; // 指示器宽度为25px
|
|
// 由于列号是从右到左递减显示的,需要计算实际索引
|
// 例如:第90列在最左边,第1列在最右边
|
// 模板中显示的列号是 91-item,所以第1个el-col显示90,第90个el-col显示1
|
// 当前列号为currentColumn,对应的索引为 maxColumn - currentColumn
|
const actualIndex = this.maxColumn - currentColumn;
|
|
// 计算位置:
|
// (实际索引 * 货位宽度) = 该列的起始位置
|
// + (货位宽度 / 2) = 该列的中心位置
|
// - (指示器宽度 / 2) = 将指示器中心与列中心对齐
|
const position = actualIndex * columnWidth + (columnWidth / 2) - (dotWidth / 2);
|
|
// 调试信息
|
console.log('当前列:', currentColumn, '实际索引:', actualIndex);
|
console.log('货位宽度:', columnWidth, '指示器宽度:', dotWidth);
|
console.log('计算位置:', position);
|
|
return position;
|
},
|
|
moveDot(x) {
|
// 映射工作模式
|
const autoStatusCode = x.YL_AutoStatus;
|
if (autoStatusCode !== undefined) {
|
this.yL_DB.YL_AutoStatus = this.YLDBMap.YL_AutoStatus[autoStatusCode] || autoStatusCode;
|
} else {
|
this.yL_DB.YL_AutoStatus = "无";
|
}
|
|
// 映射设备状态
|
const statusCode = parseInt(x.YL_Status);
|
if (!isNaN(statusCode)) {
|
this.yL_DB.YL_Status = this.YLDBMap.YL_Status[statusCode] || statusCode.toString();
|
} else {
|
this.yL_DB.YL_Status = "无";
|
}
|
|
// 映射工作状态
|
const workStatusCode = x.YL_WorkStatus;
|
if (workStatusCode !== undefined) {
|
this.yL_DB.YL_WorkStatus = this.YLDBMap.YL_WorkStatus[workStatusCode] || workStatusCode;
|
} else {
|
this.yL_DB.YL_WorkStatus = "无";
|
}
|
|
// 其他数据赋值
|
this.yL_DB.R_PP_Status = x.DeviceCode || "无";
|
this.yL_DB.YL_WorkType = x.YL_WorkType || "无";
|
this.yL_DB.YL_TaskNum = x.YL_TaskNum || "无";
|
|
// 处理行号
|
const rowValue = parseInt(x.YL_Row);
|
this.yL_DB.YL_Row = (!isNaN(rowValue) && rowValue > 0) ? rowValue.toString() : "0";
|
|
// 根据小货位号计算列号
|
// 直接使用原始小货位号
|
const smallColumn = parseInt(x.YL_Column);
|
let displayColumn;
|
if (!isNaN(smallColumn) && smallColumn > 0) {
|
// 直接使用小货位号,不进行转换
|
displayColumn = smallColumn;
|
} else {
|
// 没有收到信息,指示器在外面
|
displayColumn = 0;
|
}
|
|
// 处理列号
|
this.yL_DB.YL_Column = (!isNaN(smallColumn) && smallColumn > 0) ? smallColumn.toString() : "0";
|
|
// 处理层号
|
const layerValue = parseInt(x.YL_Layer);
|
this.yL_DB.YL_Layer = (!isNaN(layerValue) && layerValue > 0) ? layerValue.toString() : "0";
|
// 处理后端新参数,显示到报警信息中
|
this.yL_DB.StackerAlarm = x.StackerAlarm || "无";
|
this.yL_DB.CurrentColumn = displayColumn.toString();
|
|
this.form.DeviceCode = x.DeviceCode || "";
|
},
|
update() {
|
// 获取StackerAlarm的值,转换为字符串进行比较
|
const alarmValue = String(this.yL_DB.StackerAlarm).trim();
|
// 当StackerAlarm字段的值不为0或空时,就故障报警(显示红色)
|
if (alarmValue !== '' && alarmValue !== '0' && alarmValue !== '无') {
|
return 'dot-Fault ';
|
}
|
if (this.yL_DB.YL_Status == "在线" && (this.yL_DB.YL_AutoStatus == "自动" || this.yL_DB.YL_AutoStatus == "半自动")) {
|
return 'dot-Automatic ';
|
}
|
else if (this.yL_DB.YL_Status == "在线" && this.yL_DB.YL_AutoStatus == "手动") {
|
return 'dot-Running ';
|
} else {
|
return 'dot-Fault ';
|
}
|
},
|
status() {
|
const statusText = this.ConveyorLineInfo.YL_Status;
|
if (statusText === '手动') {
|
return 'custom-img-blue';
|
} else if (statusText === '自动') {
|
return 'custom-img-green';
|
} else if (statusText === '脱机') {
|
return 'custom-img-red';
|
} else {
|
return '';
|
}
|
},
|
mouseClick() {
|
this.fullscreenLoading = true;
|
this.dialogVisible = true;
|
this.fullscreenLoading = false;
|
},
|
// start() {
|
// this.fullscreenLoading = true;
|
// this.http.post("api/DeviceInfo/StackerHandTask", this.form)
|
// .then((x) => {
|
// if (!x.status) {
|
// this.$message.error(x.message);
|
// } else {
|
// this.$Message.success("堆垛机命令已下发");
|
// // $vue.success("成功.");
|
// this.show = false;
|
// $vue.refresh();
|
// }
|
// })
|
// .finally(() => {
|
// this.fullscreenLoading = false;
|
// });
|
// }, reset() {
|
// this.fullscreenLoading = true;
|
// this.http.post("api/DeviceInfo/StackerReset?DeviceCode=" + this.form.DeviceCode)
|
// .then((x) => {
|
// if (!x.status) {
|
// this.$message.error(x.message);
|
// } else {
|
// this.$Message.success("复位成功");
|
// // $vue.success("成功.");
|
// this.show = false;
|
// $vue.refresh();
|
// }
|
// })
|
// .finally(() => {
|
// this.fullscreenLoading = false;
|
// });
|
// },
|
|
// emergencyStop() {
|
// this.fullscreenLoading = true;
|
// this.http.post("api/DeviceInfo/StackerEmergencyStop?DeviceCode=" + this.form.DeviceCode)
|
// .then((x) => {
|
// if (!x.status) {
|
// this.$message.error(x.message);
|
// } else {
|
// this.$Message.success("急停已按下");
|
// // $vue.success("成功.");
|
// // this.show = false;
|
// // $vue.refresh();
|
// }
|
// })
|
// .finally(() => {
|
// this.fullscreenLoading = false;
|
// });
|
// },
|
// disconnected() {
|
// this.fullscreenLoading = true;
|
// this.http.post("api/DeviceInfo/StackerDisconnected?DeviceCode=" + this.form.DeviceCode)
|
// .then((x) => {
|
// if (!x.status) {
|
// this.$message.error(x.message);
|
// } else {
|
// this.$Message.success("中断堆垛机任务");
|
// }
|
// })
|
// .finally(() => {
|
// this.fullscreenLoading = false;
|
// });
|
// },
|
// StackerRecall() {
|
// this.fullscreenLoading = true;
|
// this.http.post("api/DeviceInfo/StackerRecall?DeviceCode=" + this.form.DeviceCode)
|
// .then((x) => {
|
// if (!x.status) {
|
// this.$message.error(x.message);
|
// } else {
|
// this.$Message.success("召回堆垛机");
|
// }
|
// })
|
// .finally(() => {
|
// this.fullscreenLoading = false;
|
// });
|
// }
|
},
|
};
|
</script>
|
|
<style scoped>
|
.line-container {
|
position: relative;
|
height: 25px;
|
background-color: #ecf5ff;
|
width: 2720px;
|
/* 90列 * 30px每列 */
|
}
|
|
.line {
|
position: absolute;
|
top: 0;
|
left: 0;
|
right: 0;
|
height: 0px;
|
background-color: #a0cfff;
|
}
|
|
.dot-Running {
|
position: absolute;
|
top: 0px;
|
width: 25px;
|
height: 25px;
|
border-radius: 50%;
|
background-color: #409eff;
|
transition: transform 0.3s ease;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
font-size: 9px;
|
font-weight: bold;
|
color: white;
|
}
|
|
.dot-Automatic {
|
position: absolute;
|
top: 0px;
|
width: 25px;
|
height: 25px;
|
border-radius: 50%;
|
background-color: #0df705;
|
transition: transform 0.3s ease;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
font-size: 9px;
|
font-weight: bold;
|
color: white;
|
}
|
|
.dot-Fault {
|
position: absolute;
|
top: 0px;
|
width: 25px;
|
height: 25px;
|
border-radius: 50%;
|
background-color: #f80410;
|
transition: transform 0.3s ease;
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
font-size: 9px;
|
font-weight: bold;
|
color: white;
|
}
|
|
img {
|
width: 30px;
|
height: 30px;
|
}
|
|
.image-text {
|
position: absolute;
|
top: 5px;
|
color: #000000;
|
font-size: 12px;
|
font-weight: bold;
|
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
margin-left: 5px;
|
}
|
|
.modern-dialog {
|
border-radius: 16px !important;
|
overflow: hidden;
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
}
|
|
.modern-dialog .el-dialog__header {
|
display: none;
|
}
|
|
.modern-dialog .el-dialog__body {
|
padding: 0;
|
margin: 0;
|
}
|
|
.dialog-header {
|
background: linear-gradient(135deg, #409eff 0%, #67c23a 100%);
|
padding: 20px 24px;
|
text-align: center;
|
}
|
|
.dialog-title {
|
color: #fff;
|
font-size: 18px;
|
font-weight: 600;
|
margin: 0;
|
letter-spacing: 2px;
|
}
|
|
.dialog-content {
|
padding: 28px;
|
background: #f8fafc;
|
display: flex;
|
justify-content: center;
|
}
|
|
.info-list {
|
width: 100%;
|
max-width: 420px;
|
display: flex;
|
flex-direction: column;
|
gap: 12px;
|
}
|
|
.info-item {
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
padding: 16px 20px;
|
background: #fff;
|
border-radius: 12px;
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
transition: all 0.3s ease;
|
}
|
|
.info-item:hover {
|
transform: translateX(4px);
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
}
|
|
.item-label {
|
font-size: 14px;
|
color: #6b7280;
|
font-weight: 500;
|
min-width: 80px;
|
text-align: left;
|
}
|
|
.item-value {
|
font-size: 15px;
|
color: #1f2937;
|
font-weight: 500;
|
text-align: right;
|
flex: 1;
|
margin-left: 20px;
|
word-break: break-all;
|
padding-left: 20px;
|
border-left: 1px solid #e5e7eb;
|
}
|
|
.status-blue {
|
color: #409eff !important;
|
font-weight: 600;
|
}
|
|
.status-green {
|
color: #67c23a !important;
|
font-weight: 600;
|
}
|
|
.status-red {
|
color: #f56c6c !important;
|
font-weight: 600;
|
}
|
</style>
|