sx_yjb_vue/src/views/gas_alarm/index.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>