290 lines
7.8 KiB
Vue
290 lines
7.8 KiB
Vue
<template>
|
|
<div class="container">
|
|
<div style="width: 300px">
|
|
<el-input
|
|
v-model="searchTextWait"
|
|
class="mb-10"
|
|
placeholder="输入搜索内容"
|
|
>
|
|
<template #append>
|
|
<el-button :icon="Search" @click="fnSetSearch" />
|
|
</template>
|
|
</el-input>
|
|
<el-tree
|
|
ref="treeRef"
|
|
node-key="label"
|
|
accordion
|
|
:data="treeData"
|
|
:filter-node-method="fnFilterNode"
|
|
:default-expanded-keys="[treeData.length > 0 ? treeData[0].label : '']"
|
|
@node-click="fnNodeClick"
|
|
/>
|
|
</div>
|
|
<div style="flex: 1; display: flex; flex-wrap: wrap; gap: 20px">
|
|
<div
|
|
v-for="item in list"
|
|
:id="'_' + item.PLC_ID"
|
|
:key="item.PLC_ID"
|
|
style="width: calc(20% - 20px); height: 190px"
|
|
@click="fnViewInfo(item)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<view-info
|
|
v-for="item in dialog"
|
|
:key="item.PLC_ID"
|
|
v-model:visible="item.visible"
|
|
:item="item"
|
|
/>
|
|
</template>
|
|
|
|
<script setup>
|
|
import * as echarts from "echarts";
|
|
import { nextTick, onBeforeUnmount, onMounted, ref } from "vue";
|
|
import ViewInfo from "./components/view_info.vue";
|
|
import { getEquipmentInfo, getEquipmentTree } from "@/request/gas_alarm.js";
|
|
import { useUserStore } from "@/pinia/user.js";
|
|
import { useIntervalFn } from "@vueuse/core";
|
|
import { Search } from "@element-plus/icons-vue";
|
|
const { pause, resume } = useIntervalFn(
|
|
() => {
|
|
fnGetData();
|
|
},
|
|
5000,
|
|
{ immediate: false, immediateCallback: true }
|
|
);
|
|
const userStore = useUserStore();
|
|
const treeRef = ref(null);
|
|
const treeData = ref([]);
|
|
const searchText = ref("");
|
|
const searchTextWait = ref("");
|
|
const fnFilterNode = (value, data) => {
|
|
if (!value) return true;
|
|
return data.label.includes(value);
|
|
};
|
|
const fnNodeClick = (_data, { data, parent }) => {
|
|
searchTextWait.value = "";
|
|
searchText.value = "";
|
|
if (parent.parent) {
|
|
equipmentInfoParams = {
|
|
ORG: parent.data.label,
|
|
DEPARTMENT: data.label,
|
|
};
|
|
} else {
|
|
equipmentInfoParams = {
|
|
ORG: data.label,
|
|
DEPARTMENT: "",
|
|
};
|
|
}
|
|
fnDisposeEcharts();
|
|
pause();
|
|
resume();
|
|
};
|
|
|
|
const list = ref([]);
|
|
const dialog = ref([]);
|
|
let equipmentInfoParams = {};
|
|
onMounted(() => {
|
|
fnGetTreeData();
|
|
});
|
|
const fnConversionTree = (data) => {
|
|
return data.map((item) => {
|
|
const newNode = {
|
|
label: item.data.ORG || item.data.DEPARTMENT,
|
|
children: [],
|
|
};
|
|
if (item.children && item.children.length > 0) {
|
|
newNode.children = fnConversionTree(item.children);
|
|
}
|
|
return newNode;
|
|
});
|
|
};
|
|
const fnGetTreeData = async () => {
|
|
const { root } = await getEquipmentTree({
|
|
DEVICE_TYPE: "gdsyyhtbjq01",
|
|
CORPINFO_ID: userStore.getUserInfo.CORPINFO_ID,
|
|
});
|
|
treeData.value = fnConversionTree(root.children);
|
|
equipmentInfoParams = {
|
|
ORG: treeData.value[0].label,
|
|
DEPARTMENT: treeData.value[0].children[0].label,
|
|
};
|
|
resume();
|
|
};
|
|
let isPending = false;
|
|
const fnGetData = async () => {
|
|
if (isPending) return;
|
|
isPending = true;
|
|
const { varList } = await getEquipmentInfo({
|
|
ORG: equipmentInfoParams.ORG,
|
|
searchText: searchText.value,
|
|
DEPARTMENT: equipmentInfoParams.DEPARTMENT,
|
|
CORPINFO_ID: userStore.getUserInfo.CORPINFO_ID,
|
|
loading: false,
|
|
});
|
|
list.value = varList;
|
|
isPending = false;
|
|
await nextTick();
|
|
list.value.forEach(async (item) => {
|
|
await fnInitEcharts(item);
|
|
});
|
|
};
|
|
let myChartMap = {};
|
|
const fnInitEcharts = (data) => {
|
|
return new Promise((resolve) => {
|
|
// const normalColor = "rgb(255,255,255)";
|
|
// const alarmColor = "rgb(0,255,0)";
|
|
// const alarmColors = "rgb(0,0,255)";
|
|
// const normalColors = "rgb(255, 255, 0)";
|
|
// const assistantColors = "rgb(255,0,0)";
|
|
const assistantColor = "rgb(0,191,255)";
|
|
let myChart;
|
|
if (!myChartMap[`_${data.PLC_ID}`]) {
|
|
myChart = echarts.init(document.querySelector(`#_${data.PLC_ID}`));
|
|
} else {
|
|
myChart = myChartMap[`_${data.PLC_ID}`];
|
|
}
|
|
const option = {
|
|
title: {
|
|
text: data.TARGET_PLACE.replace(/(.{20})/g, "$1\n"),
|
|
textStyle: {
|
|
fontSize: 12,
|
|
fontWeight: 400,
|
|
color: assistantColor,
|
|
lineHeight: 16,
|
|
},
|
|
left: "center",
|
|
top: "0",
|
|
},
|
|
series: [
|
|
{
|
|
type: "gauge",
|
|
name: "外层辅助",
|
|
radius: "86%",
|
|
center: ["50%", "62%"],
|
|
startAngle: "225",
|
|
endAngle: "-45",
|
|
splitNumber: "120",
|
|
pointer: { show: false },
|
|
detail: { show: false },
|
|
data: [{ value: 1 }],
|
|
title: { show: false },
|
|
axisLine: {
|
|
show: true,
|
|
lineStyle: { color: [[1, assistantColor]], width: 3 },
|
|
},
|
|
axisTick: { show: false },
|
|
splitLine: { show: false },
|
|
axisLabel: { show: false },
|
|
},
|
|
{
|
|
name: "内层数据刻度",
|
|
type: "gauge",
|
|
radius: "75%",
|
|
center: ["50%", "62%"],
|
|
axisLine: {
|
|
lineStyle: {
|
|
width: 10,
|
|
color: [
|
|
[23/200, '#FFFFFF'],
|
|
[50/200, '#00FF00'],
|
|
[100/200, '#0000FF'],
|
|
[160/200, '#FFFF00'],
|
|
[1, '#FF0000']
|
|
// [23/200, normalColor],
|
|
// [0.50, alarmColor],
|
|
// [1.0, alarmColors],
|
|
// [1.60, normalColors],
|
|
// [2.00, assistantColors],
|
|
],
|
|
},
|
|
},
|
|
max: 200,
|
|
splitLine: { show: false },
|
|
axisTick: { show: false },
|
|
axisLabel: { show: false },
|
|
detail: {
|
|
show: true,
|
|
offsetCenter: ["0", "80%"],
|
|
fontSize: 20,
|
|
color: getColorByValue(data.CURRENT_VALUE)
|
|
// color: data.CURRENT_VALUE >= 24 ? alarmColor : normalColor,
|
|
},
|
|
itemStyle: {
|
|
// color: data.CURRENT_VALUE >= 24 ? alarmColor : normalColor,
|
|
color: getColorByValue(data.CURRENT_VALUE)
|
|
},
|
|
pointer: { width: 3, length: "95%" },
|
|
data: [{ value: data.CURRENT_VALUE }],
|
|
silent: false,
|
|
},
|
|
{
|
|
name: "最内层线",
|
|
type: "gauge",
|
|
radius: "50%",
|
|
center: ["50%", "62%"],
|
|
startAngle: 360,
|
|
endAngle: 0,
|
|
axisLine: { show: false, lineStyle: { opacity: 0 } },
|
|
splitLine: { show: false, lineStyle: { opacity: 0 } },
|
|
axisLabel: { show: false },
|
|
axisTick: {
|
|
length: 2,
|
|
splitNumber: 3,
|
|
lineStyle: { color: assistantColor, width: 2, type: "dashed" },
|
|
},
|
|
detail: { show: false },
|
|
pointer: { show: false },
|
|
},
|
|
],
|
|
};
|
|
myChart.setOption(option);
|
|
if (!myChartMap[`_${data.PLC_ID}`]) {
|
|
myChartMap[`_${data.PLC_ID}`] = myChart;
|
|
}
|
|
resolve();
|
|
});
|
|
};
|
|
const fnSetSearch = async () => {
|
|
searchText.value = searchTextWait.value;
|
|
await fnDisposeEcharts();
|
|
await fnGetData();
|
|
};
|
|
const fnViewInfo = (data) => {
|
|
if (
|
|
dialog.value.find(
|
|
(item) => data.PLC_ID === item.PLC_ID && item.visible === true
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
dialog.value.push({ ...data, visible: true });
|
|
};
|
|
const fnDisposeEcharts = () => {
|
|
for (const myChartListKey in myChartMap) {
|
|
myChartMap[myChartListKey].dispose();
|
|
}
|
|
myChartMap = {};
|
|
};
|
|
const getColorByValue = (value) => {
|
|
return value < 24 ? 'rgb(255, 255, 255)' : // 白色
|
|
value <= 50 ? 'rgb(0, 255, 0)' : // 绿色
|
|
value <= 100 ? 'rgb(0, 0, 255)' : // 蓝色
|
|
value <= 160 ? 'rgb(255, 255, 0)' : // 黄色
|
|
'rgb(255, 0, 0)'; // 红色
|
|
};
|
|
onBeforeUnmount(() => {
|
|
fnDisposeEcharts();
|
|
});
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.container {
|
|
background-color: #030f2f;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
padding: 30px;
|
|
gap: 20px;
|
|
}
|
|
</style>
|