Commit 06f00976 by 冀忠欣

修改天合堂设备实时看板页面

parent 1d22e10b
...@@ -31,10 +31,7 @@ ...@@ -31,10 +31,7 @@
</div> </div>
<div class="workshop-filter" style="text-align: center; margin: 10px 0"> <div class="workshop-filter" style="text-align: center; margin: 10px 0">
<el-radio-group <el-radio-group v-model="selectedWorkshop" @change="onWorkshopChange" size="medium">
v-model="selectedWorkshop"
@change="onWorkshopChange"
size="medium">
<el-radio label=""> <el-radio label="">
<span style="font-size: 18px;">全部<span></el-radio> <span style="font-size: 18px;">全部<span></el-radio>
<el-radio label="预料车间"> <el-radio label="预料车间">
...@@ -43,13 +40,14 @@ ...@@ -43,13 +40,14 @@
<el-radio label="蒸煮车间"> <el-radio label="蒸煮车间">
<span style="font-size: 18px">成型车间<span> <span style="font-size: 18px">成型车间<span>
</el-radio> </el-radio>
<el-radio label="包装车间" > <el-radio label="包装车间">
<span style="font-size: 18px">包装车间<span> <span style="font-size: 18px">包装车间<span>
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<!-- 设备状态卡片区域 - 新设计 --> <!-- 设备状态卡片区域 - 新设计 -->
<div class="scrollBoxClass">
<div class="device-cards-container"> <div class="device-cards-container">
<div v-for="(device, index) in deviceList" :key="index" class="device-card new-design" <div v-for="(device, index) in deviceList" :key="index" class="device-card new-design"
:class="getCardClass(device.status)"> :class="getCardClass(device.status)">
...@@ -122,6 +120,7 @@ ...@@ -122,6 +120,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- 底部状态图 --> <!-- 底部状态图 -->
<div class="status-chart glass-effect" v-if="false"> <div class="status-chart glass-effect" v-if="false">
...@@ -201,20 +200,20 @@ ...@@ -201,20 +200,20 @@
<script> <script>
// 发送消息给父页面(关闭odoo的菜单弹窗) // 发送消息给父页面(关闭odoo的菜单弹窗)
document.addEventListener("click", () => { document.addEventListener("click", function () {
window.parent.postMessage("hidePopover", "*"); window.parent.postMessage("hidePopover", "*");
}); });
let vue = new Vue({ let vue = new Vue({
el: "#app", el: "#app",
delimiters: ["[[", "]]"], // 替换原本vue的[[ key ]]取值方式(与odoo使用的jinja2冲突问题) delimiters: ["[[", "]]"], // 替换原本vue的[[ key ]]取值方式(与odoo使用的jinja2冲突问题)
data() { data: function () {
return { return {
isFullscreen: false, // 全屏状态 isFullscreen: false, // 全屏状态
currentTime: null, // 当前时间 currentTime: null, // 当前时间
timer: null, // 定时器 timer: null, // 定时器
windowHeight: window.innerHeight, // 窗口高度 windowHeight: window.innerHeight, // 窗口高度
// dwsURL: "https://workstation.rokeris.com", // 基地址 dwsURL: "https://tht.dws.rokecloud.com", // 基地址
dwsURL: "", // 基地址 // dwsURL: "", // 基地址
baseURL: "https://dws-platform.xbg.rokeris.com/dev-api", // 基地址 baseURL: "https://dws-platform.xbg.rokeris.com/dev-api", // 基地址
loading: false, // 全局加载效果 loading: false, // 全局加载效果
deviceList: [], // 设备列表 deviceList: [], // 设备列表
...@@ -230,7 +229,7 @@ ...@@ -230,7 +229,7 @@
selectedWorkshop: "", // 新增字段:当前选中的车间 selectedWorkshop: "", // 新增字段:当前选中的车间
}; };
}, },
created() { created: function () {
if (this.getUrlSearch("factory_code")) { if (this.getUrlSearch("factory_code")) {
this.factoryCode = this.getUrlSearch("factory_code"); //截取url后面的参数 this.factoryCode = this.getUrlSearch("factory_code"); //截取url后面的参数
} }
...@@ -238,13 +237,13 @@ ...@@ -238,13 +237,13 @@
}, },
computed: { computed: {
// 选中设备的信息 // 选中设备的信息
selDeviceInfo() { selDeviceInfo: function () {
return this.deviceList.find((item) => item.id == this.selectedDevice); return this.deviceList.find(function (item) { return item.id == this.selectedDevice; }.bind(this));
}, },
}, },
async mounted() { async mounted() {
window.addEventListener("resize", this.handleResize); window.addEventListener("resize", this.handleResize);
this.$nextTick(() => { this.$nextTick(function () {
document.getElementById("bodyId").style.display = "block"; document.getElementById("bodyId").style.display = "block";
}); });
...@@ -258,26 +257,26 @@ ...@@ -258,26 +257,26 @@
this.dateList = this.getLastAssignDays(); this.dateList = this.getLastAssignDays();
// 设置定时刷新(每分钟刷新一次,静默模式) // 设置定时刷新(每分钟刷新一次,静默模式)
this.refreshInterval = setInterval(() => { this.refreshInterval = setInterval(function () {
this.initData(true); // 传入true表示静默刷新,不显示加载提示 this.initData(true); // 传入true表示静默刷新,不显示加载提示
}, 60000); }.bind(this), 60000);
// 设置设备信息的title属性 // 设置设备信息的title属性
this.$nextTick(() => { this.$nextTick(function () {
document.querySelectorAll(".device-info").forEach((el) => { document.querySelectorAll(".device-info").forEach(function (el) {
el.title = el.dataset.fullTitle; el.title = el.dataset.fullTitle;
}); });
}); });
}, },
updated() { updated: function () {
// 在数据更新后也设置title属性 // 在数据更新后也设置title属性
this.$nextTick(() => { this.$nextTick(function () {
document.querySelectorAll(".device-info").forEach((el) => { document.querySelectorAll(".device-info").forEach(function (el) {
el.title = el.dataset.fullTitle; el.title = el.dataset.fullTitle;
}); });
}); });
}, },
beforeDestroy() { beforeDestroy: function () {
// 清除定时器 // 清除定时器
if (this.refreshInterval) { if (this.refreshInterval) {
clearInterval(this.refreshInterval); clearInterval(this.refreshInterval);
...@@ -290,7 +289,7 @@ ...@@ -290,7 +289,7 @@
}, },
methods: { methods: {
// 全屏icon点击事件 // 全屏icon点击事件
toggleFullscreen() { toggleFullscreen: function () {
if (!this.isFullscreen) { if (!this.isFullscreen) {
this.enterFullScreen() this.enterFullScreen()
} else { } else {
...@@ -298,7 +297,7 @@ ...@@ -298,7 +297,7 @@
} }
}, },
// 全屏方法 // 全屏方法
enterFullScreen() { enterFullScreen: function () {
// 获取需要全屏的元素 // 获取需要全屏的元素
const elem = this.$refs.fullScreenElement const elem = this.$refs.fullScreenElement
if (elem.requestFullscreen) { if (elem.requestFullscreen) {
...@@ -315,7 +314,7 @@ ...@@ -315,7 +314,7 @@
} }
this.isFullscreen = true this.isFullscreen = true
}, },
exitFullScreen() { exitFullScreen: function () {
if (document.exitFullscreen) { if (document.exitFullscreen) {
document.exitFullscreen() document.exitFullscreen()
} else if (document.mozCancelFullScreen) { } else if (document.mozCancelFullScreen) {
...@@ -330,12 +329,12 @@ ...@@ -330,12 +329,12 @@
} }
this.isFullscreen = false this.isFullscreen = false
}, },
onWorkshopChange() { onWorkshopChange: function () {
this.initData(); // 触发重新加载数据 this.initData(); // 触发重新加载数据
}, },
// 初始化当前时间 // 初始化当前时间
initCurrentTimeFn() { initCurrentTimeFn: function () {
this.timer = setInterval(() => { this.timer = setInterval(function () {
const now = new Date(); const now = new Date();
const year = now.getFullYear(); const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); const month = String(now.getMonth() + 1).padStart(2, '0');
...@@ -344,10 +343,10 @@ ...@@ -344,10 +343,10 @@
const minutes = String(now.getMinutes()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0');
this.currentTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` this.currentTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}, 1000) }.bind(this), 1000)
}, },
// 通过网址跳转过来的页面,截取后面的参数 // 通过网址跳转过来的页面,截取后面的参数
getUrlSearch(name) { getUrlSearch: function (name) {
// 未传参,返回空 // 未传参,返回空
if (!name) return ""; if (!name) return "";
// 查询参数:先通过search取值,如果取不到就通过hash来取 // 查询参数:先通过search取值,如果取不到就通过hash来取
...@@ -522,33 +521,33 @@ ...@@ -522,33 +521,33 @@
}, },
// 处理设备状态数据 // 处理设备状态数据
processDeviceStateData(deviceStateData) { processDeviceStateData: function (deviceStateData) {
if (!deviceStateData || !Array.isArray(deviceStateData)) { if (!deviceStateData || !Array.isArray(deviceStateData)) {
return; return;
} }
const codeToSeqMap = {}; var codeToSeqMap = {};
this.allEquipmentData.forEach(equip => { this.allEquipmentData.forEach(function (equip) {
codeToSeqMap[equip.code] = equip.sequence; codeToSeqMap[equip.code] = equip.sequence;
}); });
// 获取当前车间下的设备 code 列表 // 获取当前车间下的设备 code 列表
const validCodes = this.allEquipmentData var validCodes = this.allEquipmentData
.filter(e => !this.selectedWorkshop || e.plant_name === this.selectedWorkshop) .filter(function (e) { return !this.selectedWorkshop || e.plant_name === this.selectedWorkshop; }.bind(this))
.map(e => e.code); .map(function (e) { return e.code; });
// 过滤掉不属于当前车间的设备 // 过滤掉不属于当前车间的设备
const filteredDevices = deviceStateData.filter(d => var filteredDevices = deviceStateData.filter(function (d) {
!this.selectedWorkshop || validCodes.includes(d.code) return !this.selectedWorkshop || validCodes.includes(d.code);
).map(device => ({ }.bind(this)).map(function (device) {
...device, var newDevice = Object.assign({}, device);
seq: codeToSeqMap[device.code] || Number.MAX_SAFE_INTEGER // 如果找不到 seq,默认排最后 newDevice.seq = codeToSeqMap[device.code] || Number.MAX_SAFE_INTEGER; // 如果找不到 seq,默认排最后
})); return newDevice;
});
// 将API返回的数据转换为页面所需的格式 // 将API返回的数据转换为页面所需的格式
this.deviceList = filteredDevices.map((device) => { this.deviceList = filteredDevices.map(function (device) {
// 根据API返回的状态确定前端显示的状态 // 根据API返回的状态确定前端显示的状态
let status = "off"; var status = "off";
if (device.state === "green") { if (device.state === "green") {
status = "running"; status = "running";
} else if (device.state === "yellow") { } else if (device.state === "yellow") {
...@@ -559,33 +558,30 @@ ...@@ -559,33 +558,30 @@
status = "off"; status = "off";
} }
// 计算持续时间的显示格式 // 计算持续时间的显示格式
let durationText = "0" var durationText = "0"
if (device.duration_hours !== undefined) { if (device.duration_hours !== undefined) {
durationText = this.formatTime(Number(device.duration_hours * 3600)) durationText = this.formatTime(Number(device.duration_hours * 3600))
} }
let run_seconds = "0" var run_seconds = "0"
if (device.run_seconds !== undefined) run_seconds = this.formatTime(Number(device.run_seconds)) if (device.run_seconds !== undefined) run_seconds = this.formatTime(Number(device.run_seconds))
let green_seconds = "0" var green_seconds = "0"
if (device.green_seconds !== undefined) green_seconds = this.formatTime(Number(device.green_seconds)) if (device.green_seconds !== undefined) green_seconds = this.formatTime(Number(device.green_seconds))
let yellow_seconds = "0" var yellow_seconds = "0"
if (device.yellow_seconds !== undefined) yellow_seconds = this.formatTime(Number(device.yellow_seconds)) if (device.yellow_seconds !== undefined) yellow_seconds = this.formatTime(Number(device.yellow_seconds))
let red_seconds = "0" var red_seconds = "0"
if (device.red_seconds !== undefined) yellow_seconds = this.formatTime(Number(device.yellow_seconds)) if (device.red_seconds !== undefined) red_seconds = this.formatTime(Number(device.red_seconds))
// 计算利用率百分比,确保有效值 // 计算利用率百分比,确保有效值
const percentage = device.utilization_rate !== undefined ? Math.round(device var percentage = device.utilization_rate !== undefined ? Math.round(device.utilization_rate) : 0
.utilization_rate) : 0
// 从所有设备列表中获取准确的设备名称 // 从所有设备列表中获取准确的设备名称
let deviceName = device.name || device.code // 默认使用API返回的名称或编码 var deviceName = device.name || device.code // 默认使用API返回的名称或编码
// 在所有设备列表中查找匹配的设备 // 在所有设备列表中查找匹配的设备
if (this.allEquipmentData && this.allEquipmentData.length > 0) { if (this.allEquipmentData && this.allEquipmentData.length > 0) {
const matchedDevice = this.allEquipmentData.find( var matchedDevice = this.allEquipmentData.find(function (equip) { return equip.code === device.code; });
(equip) => equip.code === device.code
)
// 如果找到匹配的设备,使用其名称 // 如果找到匹配的设备,使用其名称
if (matchedDevice && matchedDevice.name) { if (matchedDevice && matchedDevice.name) {
deviceName = device.name ? matchedDevice.name : device.code deviceName = device.name ? matchedDevice.name : device.code
...@@ -605,27 +601,28 @@ ...@@ -605,27 +601,28 @@
yellow_seconds: yellow_seconds, yellow_seconds: yellow_seconds,
red_seconds: red_seconds red_seconds: red_seconds
} }
}).sort((a, b) => (codeToSeqMap[a.code] || Number.MAX_SAFE_INTEGER) }.bind(this)).sort(function (a, b) {
- (codeToSeqMap[b.code] || Number.MAX_SAFE_INTEGER)); return (codeToSeqMap[a.code] || Number.MAX_SAFE_INTEGER) - (codeToSeqMap[b.code] || Number.MAX_SAFE_INTEGER);
});
}, },
formatTime(seconds) { formatTime: function (seconds) {
if (seconds < 60) { if (seconds < 60) {
return `0min`; // 不足 1 分钟显示 0min return `0min`; // 不足 1 分钟显示 0min
} else if (seconds < 3600) { } else if (seconds < 3600) {
const minutes = Math.floor(seconds / 60); // 转换为分钟 var minutes = Math.floor(seconds / 60); // 转换为分钟
return `${minutes}min`; // 显示分钟 return `${minutes}min`; // 显示分钟
} else if (seconds < 86400) { // 小于 1 天 } else if (seconds < 86400) { // 小于 1 天
const hours = Math.floor(seconds / 3600); // 转换为小时 var hours = Math.floor(seconds / 3600); // 转换为小时
return `${hours}h`; // 只返回小时 return `${hours}h`; // 只返回小时
} else { } else {
const days = Math.floor(seconds / 86400); // 转换为天数 var days = Math.floor(seconds / 86400); // 转换为天数
return `${days}d`; // 只返回天 return `${days}d`; // 只返回天
} }
}, },
// 初始化模拟数据 (保留原有的模拟数据方法,作为备用) // 初始化模拟数据 (保留原有的模拟数据方法,作为备用)
initMockData() { initMockData: function () {
// 模拟设备数据 - 添加不同状态和明显不同百分比的测试数据 // 模拟设备数据 - 添加不同状态和明显不同百分比的测试数据
this.deviceList = [ this.deviceList = [
// { // {
...@@ -667,7 +664,7 @@ ...@@ -667,7 +664,7 @@
}, },
// 获取卡片的CSS类名 // 获取卡片的CSS类名
getCardClass(status) { getCardClass: function (status) {
switch (status) { switch (status) {
case "running": case "running":
return "card-running"; return "card-running";
...@@ -682,7 +679,7 @@ ...@@ -682,7 +679,7 @@
}, },
// 获取边框的CSS类名 // 获取边框的CSS类名
getBorderClass(status) { getBorderClass: function (status) {
switch (status) { switch (status) {
case "running": case "running":
return "border-running"; return "border-running";
...@@ -697,7 +694,7 @@ ...@@ -697,7 +694,7 @@
}, },
// 获取设备状态对应的CSS类名 // 获取设备状态对应的CSS类名
getStatusClass(status) { getStatusClass: function (status) {
switch (status) { switch (status) {
case "running": case "running":
return "status-running"; return "status-running";
...@@ -712,7 +709,7 @@ ...@@ -712,7 +709,7 @@
}, },
// 获取波浪效果的类名 // 获取波浪效果的类名
getWaveClass(status) { getWaveClass: function (status) {
switch (status) { switch (status) {
case "running": case "running":
return "wave-running"; return "wave-running";
...@@ -727,23 +724,16 @@ ...@@ -727,23 +724,16 @@
}, },
// 获取波浪高度 // 获取波浪高度
getWaveHeight(status, percentage) { getWaveHeight: function (status, percentage) {
// 将百分比限制在10%-100%之间,确保即使是低百分比也有一定的水位可见 // 将百分比限制在10%-100%之间,确保即使是低百分比也有一定的水位可见
let height = percentage; var height = percentage;
// 如果是故障或停机状态,固定显示50%
// if (status === "error" || status === "off") {
// height = 50;
// }
// 确保最小高度为10%,最大为100% // 确保最小高度为10%,最大为100%
height = Math.min(Math.max(height, 10), 100); height = Math.min(Math.max(height, 10), 100);
return height; return height;
}, },
// 获取设备状态对应的文本 // 获取设备状态对应的文本
getStatusText(status) { getStatusText: function (status) {
switch (status) { switch (status) {
case "running": case "running":
return "运行中"; return "运行中";
...@@ -758,10 +748,11 @@ ...@@ -758,10 +748,11 @@
}, },
// 处理小数位数方法 // 处理小数位数方法
toFixedHandle(value, num = 4) { toFixedHandle: function (value, num) {
if (num === undefined) num = 4;
if (value) { if (value) {
let strValue = String(value); var strValue = String(value);
if (strValue.split(".").length > 1 || strValue.split(".")[1]?.length > num) { if (strValue.split(".").length > 1 || (strValue.split(".")[1] && strValue.split(".")[1].length > num)) {
strValue = Number(strValue).toFixed(num); strValue = Number(strValue).toFixed(num);
} }
return Number(strValue); return Number(strValue);
...@@ -771,26 +762,26 @@ ...@@ -771,26 +762,26 @@
}, },
// 计算高度百分比 // 计算高度百分比
calculateHeight(hours) { calculateHeight: function (hours) {
// 24小时对应整个高度(100%) // 24小时对应整个高度(100%)
// 每4小时对应一个刻度区间,总共6个区间 // 每4小时对应一个刻度区间,总共6个区间
// 计算每小时占的百分比:100% / 24 ≈ 4.167% // 计算每小时占的百分比:100% / 24 ≈ 4.167%
const heightPerHour = 100 / 24; var heightPerHour = 100 / 24;
const percentage = hours * heightPerHour; var percentage = hours * heightPerHour;
// 确保高度在0-100%之间 // 确保高度在0-100%之间
return Math.min(Math.max(percentage, 0), 100); return Math.min(Math.max(percentage, 0), 100);
}, },
// 获取最后指定天数的日期 // 获取最后指定天数的日期
getLastAssignDays(num = 10) { getLastAssignDays: function (num) {
const dates = []; if (num === undefined) num = 10;
for (let i = num - 1; i >= 0; i--) { var dates = [];
const date = new Date(); for (var i = num - 1; i >= 0; i--) {
var date = new Date();
date.setDate(date.getDate() - i); date.setDate(date.getDate() - i);
const year = date.getFullYear(); var year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); var month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0"); var day = String(date.getDate()).padStart(2, "0");
dates.push(`${year}-${month}-${day}`); dates.push(`${year}-${month}-${day}`);
} }
this.start_time = dates[0]; // 第一天 this.start_time = dates[0]; // 第一天
...@@ -799,25 +790,25 @@ ...@@ -799,25 +790,25 @@
}, },
// 处理窗口大小变化 // 处理窗口大小变化
handleResize() { handleResize: function () {
// 窗口大小变化时的处理逻辑 // 窗口大小变化时的处理逻辑
}, },
// 文本截断方法 // 文本截断方法
truncateText(text, maxLength) { truncateText: function (text, maxLength) {
if (!text) return ""; if (!text) return "";
if (text.length <= maxLength) return text; if (text.length <= maxLength) return text;
return text.substring(0, maxLength) + "..."; return text.substring(0, maxLength) + "...";
}, },
// 显示完整标题 // 显示完整标题
showFullTitle(event, device) { showFullTitle: function (event, device) {
const fullTitle = device.name + " | " + device.code; var fullTitle = device.name + " | " + device.code;
event.target.setAttribute("title", fullTitle); event.target.setAttribute("title", fullTitle);
}, },
// 获取ERR文字的CSS类名 // 获取ERR文字的CSS类名
getErrClass(status) { getErrClass: function (status) {
if (status === "error") { if (status === "error") {
return "err-error"; return "err-error";
} }
...@@ -825,7 +816,7 @@ ...@@ -825,7 +816,7 @@
}, },
// 获取OFF文字的CSS类名 // 获取OFF文字的CSS类名
getOffClass(status) { getOffClass: function (status) {
if (status === "off") { if (status === "off") {
return "off-status"; return "off-status";
} }
...@@ -911,6 +902,12 @@ ...@@ -911,6 +902,12 @@
gap: 10px; gap: 10px;
} }
.scrollBoxClass {
height: 1px;
flex: auto;
overflow-y: auto;
}
/* 设备卡片容器 */ /* 设备卡片容器 */
.device-cards-container { .device-cards-container {
display: grid; display: grid;
...@@ -1299,6 +1296,7 @@ ...@@ -1299,6 +1296,7 @@
font-size: 10px; font-size: 10px;
color: #fff; color: #fff;
margin-top: 5px; margin-top: 5px;
}
.flxe_label_sty { .flxe_label_sty {
margin-right: 2px; margin-right: 2px;
...@@ -1313,7 +1311,6 @@ ...@@ -1313,7 +1311,6 @@
border-radius: 2px; border-radius: 2px;
margin-left: 10px; margin-left: 10px;
} }
}
</style> </style>
</html> </html>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment