|
@@ -29,22 +29,16 @@
|
|
|
</div>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
- <!-- <VueUiXy :dataset="dataset" :config="config" /> -->
|
|
|
- <el-row :gutter="15" class="home-card-two mb15">
|
|
|
- <el-col :xs="24" :sm="14" :md="14" :lg="16" :xl="16">
|
|
|
- <div class="home-card-item chart">
|
|
|
- <!-- <div class="home-card-item-title">
|
|
|
- <span>设备消息</span>
|
|
|
- </div> -->
|
|
|
- <div style="height: 100%" ref="homeLineRef"></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="8" class="home-media">
|
|
|
- <div class="home-card-item chart">
|
|
|
- <div style="height: 100%" ref="homePieRef"></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
+ <div class="chart-wrapper">
|
|
|
+ <div class="chart-item" style="flex: 2">
|
|
|
+ <div class="chart-title">设备消息</div>
|
|
|
+ <VueUiXy :dataset="dataset" :config="config" />
|
|
|
+ </div>
|
|
|
+ <div class="chart-item">
|
|
|
+ <div class="chart-title">预警类型</div>
|
|
|
+ <VueUiDonut :dataset="pieDataset" :config="pieConfig" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
<el-row :gutter="15" class="home-card-three">
|
|
|
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
|
|
|
<div class="home-card-item" style="height: auto;">
|
|
@@ -92,38 +86,45 @@
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
import { toRefs, reactive, onMounted, ref, watch, nextTick, onActivated, getCurrentInstance, onUnmounted } from 'vue';
|
|
|
-import * as echarts from 'echarts';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
import { useStore } from '/@/store/index';
|
|
|
-import { VueUiXy } from "vue-data-ui";
|
|
|
+import { VueUiXy, VueUiDonut } from "vue-data-ui";
|
|
|
import "vue-data-ui/style.css";
|
|
|
-import { getLineData } from "/@/utils/dataUiOptions";
|
|
|
-
|
|
|
+import { getLineData, getPieData } from "/@/utils/dataUiOptions";
|
|
|
import api from '/@/api/datahub';
|
|
|
import dayjs from 'dayjs';
|
|
|
-
|
|
|
import EditDic from '../alarm/log/component/edit.vue';
|
|
|
import DetailDic from '../alarm/log/component/detail.vue';
|
|
|
|
|
|
-let global: any = {
|
|
|
- homeChartOne: null,
|
|
|
- homeChartTwo: null,
|
|
|
- homeCharThree: null,
|
|
|
- dispose: [null, '', undefined]
|
|
|
-};
|
|
|
-
|
|
|
// 页面是显示状态
|
|
|
let isActice = true
|
|
|
-const config = ref({
|
|
|
- type: "line",
|
|
|
- style: {
|
|
|
- maxHeight: 250,
|
|
|
- },
|
|
|
- height: 250,
|
|
|
- width: 1000,
|
|
|
-});
|
|
|
|
|
|
-const dataset = ref<any[]>([]);
|
|
|
+//#region 线图
|
|
|
+
|
|
|
+// 获取默认图形配置数据
|
|
|
+const chartData = getLineData({
|
|
|
+ xAxis: [],
|
|
|
+ legend: ['消息量', '预警量'],
|
|
|
+ datas: [[], []]
|
|
|
+})
|
|
|
+
|
|
|
+const config = ref<any>(chartData.config);
|
|
|
+const dataset = ref<any[]>(chartData.dataset);
|
|
|
+
|
|
|
+//#endregion
|
|
|
+
|
|
|
+//#region 饼图
|
|
|
+
|
|
|
+// 获取默认图形配置数据
|
|
|
+const pieData = getPieData({
|
|
|
+ legend: [' '],
|
|
|
+ datas: [[]]
|
|
|
+})
|
|
|
+
|
|
|
+const pieConfig = ref<any>(pieData.config);
|
|
|
+const pieDataset = ref<any[]>(pieData.dataset);
|
|
|
+
|
|
|
+//#endregion
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
isActice = false
|
|
@@ -148,9 +149,6 @@ watch(() => alarm_type.value, (list) => {
|
|
|
|
|
|
const editDicRef = ref();
|
|
|
const detailRef = ref();
|
|
|
-const homeLineRef = ref();
|
|
|
-const homePieRef = ref();
|
|
|
-const store = useStore();
|
|
|
const router = useRouter();
|
|
|
const state = reactive({
|
|
|
loading: false,
|
|
@@ -233,204 +231,10 @@ const state = reactive({
|
|
|
bgColor: '',
|
|
|
color: '#303133',
|
|
|
},
|
|
|
- lineChartXAxisData: [],
|
|
|
- lineChartMsgTotalData: [],
|
|
|
- lineChartAlarmTotalData: [],
|
|
|
- pieChartLegend: [],
|
|
|
- pieChartLevel: [],
|
|
|
- pieChartData: []
|
|
|
});
|
|
|
|
|
|
const { loading, tableData, homeOne } = toRefs(state)
|
|
|
|
|
|
-// 折线图
|
|
|
-const initLineChart = () => {
|
|
|
- if (!global.dispose.some((b: any) => b === global.homeChartOne)) global.homeChartOne.dispose();
|
|
|
- global.homeChartOne = <any>echarts.init(homeLineRef.value, state.charts.theme);
|
|
|
- const option = {
|
|
|
- backgroundColor: state.charts.bgColor,
|
|
|
- title: {
|
|
|
- text: '设备消息',
|
|
|
- x: 5,
|
|
|
- textStyle: { fontSize: '15', color: state.charts.color },
|
|
|
- },
|
|
|
- grid: { top: 70, right: 20, bottom: 30, left: 50 },
|
|
|
- tooltip: { trigger: 'axis' },
|
|
|
- legend: { data: ['消息量', '预警量'], right: 0 },
|
|
|
- xAxis: {
|
|
|
- data: state.lineChartXAxisData
|
|
|
- },
|
|
|
- yAxis: [
|
|
|
- {
|
|
|
- type: 'value',
|
|
|
- name: '条数',
|
|
|
- splitLine: { show: true, lineStyle: { type: 'dashed', color: 'rgba(0, 0, 0, 0.03)' } },
|
|
|
- axisLabel: {
|
|
|
- margin: 2,
|
|
|
- formatter: function (value: any) {
|
|
|
- if (value >= 10000 && value < 10000000) {
|
|
|
- value = value / 10000 + "W";
|
|
|
- } else if (value >= 10000000) {
|
|
|
- value = value / 10000000 + "KW";
|
|
|
- }
|
|
|
- return value;
|
|
|
- }
|
|
|
- },
|
|
|
- },
|
|
|
- ],
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: '消息量',
|
|
|
- type: 'line',
|
|
|
- symbolSize: 0,
|
|
|
- symbol: 'circle',
|
|
|
- smooth: true,
|
|
|
- data: state.lineChartMsgTotalData,
|
|
|
- lineStyle: { color: '#4285F4', width: 3 },
|
|
|
- itemStyle: { color: '#4285F4', borderColor: '#4285F4' },
|
|
|
- areaStyle: {
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
- { offset: 0, color: 'rgba(66, 133, 244, 0.3)' },
|
|
|
- { offset: 1, color: 'rgba(66, 133, 244, 0)' },
|
|
|
- ]),
|
|
|
- },
|
|
|
- },
|
|
|
- {
|
|
|
- name: '预警量',
|
|
|
- type: 'line',
|
|
|
- symbolSize: 6,
|
|
|
- symbol: 'circle',
|
|
|
- smooth: true,
|
|
|
- data: state.lineChartAlarmTotalData,
|
|
|
- lineStyle: { color: '#FBBB04', width: 3 },
|
|
|
- itemStyle: { color: '#FBBB04', borderColor: '#FBBB04' },
|
|
|
- areaStyle: {
|
|
|
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
- { offset: 0, color: 'rgba(251, 187, 4, 0.3)' },
|
|
|
- { offset: 1, color: 'rgba(251, 187, 4, 0)' },
|
|
|
- ]),
|
|
|
- },
|
|
|
- emphasis: {
|
|
|
- itemStyle: {
|
|
|
- color: {
|
|
|
- type: 'radial',
|
|
|
- x: 0.5,
|
|
|
- y: 0.5,
|
|
|
- r: 0.5,
|
|
|
- colorStops: [
|
|
|
- { offset: 0, color: '#9E87FF' },
|
|
|
- { offset: 0.4, color: '#9E87FF' },
|
|
|
- { offset: 0.5, color: '#fff' },
|
|
|
- { offset: 0.7, color: '#fff' },
|
|
|
- { offset: 0.8, color: '#fff' },
|
|
|
- { offset: 1, color: '#fff' },
|
|
|
- ],
|
|
|
- },
|
|
|
- borderColor: '#9E87FF',
|
|
|
- borderWidth: 2,
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- ],
|
|
|
- };
|
|
|
- (<any>global.homeChartOne).setOption(option);
|
|
|
- (<any>state.myCharts).push(global.homeChartOne);
|
|
|
-};
|
|
|
-// 饼图
|
|
|
-const initPieChart = () => {
|
|
|
- if (!global.dispose.some((b: any) => b === global.homeChartTwo)) global.homeChartTwo.dispose();
|
|
|
- global.homeChartTwo = <any>echarts.init(homePieRef.value, state.charts.theme);
|
|
|
- var getname = state.pieChartLegend;
|
|
|
- var getvalue = state.pieChartData;
|
|
|
- var data = [];
|
|
|
-
|
|
|
- for (var i = 0; i < getname.length; i++) {
|
|
|
- data.push({ name: getname[i], value: getvalue[i] });
|
|
|
- }
|
|
|
- const colorList = ['#4285F4', '#2ecc71', '#FBBB04', '#e67e22', '#FF0000'].reverse()
|
|
|
-
|
|
|
- const color = state.pieChartLevel.map(level => colorList[level - 1])
|
|
|
-
|
|
|
- const option = {
|
|
|
- color,
|
|
|
- backgroundColor: state.charts.bgColor,
|
|
|
- title: {
|
|
|
- text: '预警类型',
|
|
|
- x: 5,
|
|
|
- textStyle: { fontSize: '15', color: state.charts.color },
|
|
|
- },
|
|
|
- // tooltip: { trigger: 'item', formatter: '{b} <br/> {c}%' },
|
|
|
- tooltip: { trigger: 'item' },
|
|
|
- graphic: {
|
|
|
- elements: [
|
|
|
- {
|
|
|
- type: 'image',
|
|
|
- z: -1,
|
|
|
- left: '16.5%',
|
|
|
- top: 'center',
|
|
|
- },
|
|
|
- ],
|
|
|
- },
|
|
|
- legend: {
|
|
|
- type: 'scroll',
|
|
|
- orient: 'vertical',
|
|
|
- right: '0%',
|
|
|
- left: '65%',
|
|
|
- top: 'center',
|
|
|
- itemWidth: 14,
|
|
|
- itemHeight: 14,
|
|
|
- data: getname,
|
|
|
- textStyle: {
|
|
|
- rich: {
|
|
|
- name: {
|
|
|
- fontSize: 14,
|
|
|
- fontWeight: 400,
|
|
|
- width: 200,
|
|
|
- height: 35,
|
|
|
- padding: [0, 0, 0, 60],
|
|
|
- color: state.charts.color,
|
|
|
- },
|
|
|
- rate: {
|
|
|
- fontSize: 15,
|
|
|
- fontWeight: 500,
|
|
|
- height: 35,
|
|
|
- width: 40,
|
|
|
- padding: [0, 0, 0, 30],
|
|
|
- color: state.charts.color,
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- series: [
|
|
|
- {
|
|
|
- type: 'pie',
|
|
|
- radius: ['70', '90'],
|
|
|
- center: ['32%', '50%'],
|
|
|
- padAngle: 1,
|
|
|
- label: { show: false },
|
|
|
- labelLine: { show: false },
|
|
|
- data: data,
|
|
|
- },
|
|
|
- ],
|
|
|
- };
|
|
|
- (<any>global.homeChartTwo).setOption(option);
|
|
|
- (<any>state.myCharts).push(global.homeChartTwo);
|
|
|
-};
|
|
|
-// 批量设置 echarts resize
|
|
|
-const initEchartsResizeFun = () => {
|
|
|
- nextTick(() => {
|
|
|
- for (let i = 0; i < state.myCharts.length; i++) {
|
|
|
- setTimeout(() => {
|
|
|
- (<any>state.myCharts[i]).resize();
|
|
|
- }, i * 1000);
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
-// 批量设置 echarts resize
|
|
|
-const initEchartsResize = () => {
|
|
|
- window.addEventListener('resize', initEchartsResizeFun);
|
|
|
-};
|
|
|
-
|
|
|
// 定时获取设备,在线信息,告警数量更新
|
|
|
const getOverviewData = () => {
|
|
|
getProductCount()
|
|
@@ -460,10 +264,6 @@ function getDeviceDataCount() {
|
|
|
Promise.all([api.iotManage.deviceDataCount('year'), api.iotManage.deviceAlertCountByYearMonth(dayjs().format('YYYY'))]).then(([msg, alarm]: any) => {
|
|
|
const msgArr = msg?.data || []
|
|
|
const alarmArr = alarm?.data || []
|
|
|
- // console.log(alarmArr)
|
|
|
- state.lineChartMsgTotalData = msgArr.map((item: any) => item.Value)
|
|
|
- state.lineChartXAxisData = msgArr.map((item: any) => item.Title)
|
|
|
- state.lineChartAlarmTotalData = alarmArr.map((item: any) => item.Value)
|
|
|
|
|
|
const chartData = getLineData({
|
|
|
xAxis: msgArr.map((item: any) => item.Title),
|
|
@@ -485,9 +285,14 @@ function getDeviceAlarmLevelCount() {
|
|
|
// 按告警级别统计 绘制饼图
|
|
|
api.iotManage.deviceAlarmLevelCount('year', dayjs().format('YYYY')).then((res: any) => {
|
|
|
const list = (res.data || []).sort((a: any, b: any) => b.Title - a.Title)
|
|
|
- state.pieChartLegend = list.map((item: any) => alarmTypeMap[item.Title])
|
|
|
- state.pieChartLevel = list.map((item: any) => item.Title)
|
|
|
- state.pieChartData = list.map((item: any) => item.Value)
|
|
|
+
|
|
|
+ const pieData = getPieData({
|
|
|
+ legend: list.map((item: any) => alarmTypeMap[item.Title]),
|
|
|
+ types: list.map((item: any) => item.Title),
|
|
|
+ datas: list.map((item: any) => [item.Value])
|
|
|
+ })
|
|
|
+ pieConfig.value = pieData.config
|
|
|
+ pieDataset.value = pieData.dataset
|
|
|
}).finally(() => loopRquest(getDeviceAlarmLevelCount, 60000))
|
|
|
}
|
|
|
|
|
@@ -575,43 +380,36 @@ const toMore = () => {
|
|
|
};
|
|
|
// 页面加载时
|
|
|
onMounted(() => {
|
|
|
- initEchartsResize();
|
|
|
getOverviewData();
|
|
|
getAlarmList();
|
|
|
});
|
|
|
-// 由于页面缓存原因,keep-alive
|
|
|
-onActivated(initEchartsResizeFun);
|
|
|
-// 监听 vuex 中的 tagsview 开启全屏变化,重新 resize 图表,防止不出现/大小不变等
|
|
|
-watch(() => store.state.tagsViewRoutes.isTagsViewCurrenFull, initEchartsResizeFun);
|
|
|
-watch(() => state.lineChartAlarmTotalData, initLineChart);
|
|
|
-watch(() => state.pieChartData, initPieChart);
|
|
|
-// 监听 vuex 中是否开启深色主题
|
|
|
-watch(
|
|
|
- () => store.state.themeConfig.themeConfig.isIsDark,
|
|
|
- (isIsDark) => {
|
|
|
- nextTick(() => {
|
|
|
- state.charts.theme = isIsDark ? 'dark' : '';
|
|
|
- state.charts.bgColor = isIsDark ? 'transparent' : '';
|
|
|
- state.charts.color = isIsDark ? '#dadada' : '#303133';
|
|
|
- setTimeout(() => {
|
|
|
- initLineChart();
|
|
|
- }, 500);
|
|
|
- setTimeout(() => {
|
|
|
- initPieChart();
|
|
|
- }, 700);
|
|
|
- });
|
|
|
- },
|
|
|
- {
|
|
|
- deep: true,
|
|
|
- immediate: true,
|
|
|
- }
|
|
|
-);
|
|
|
-watch(() => state.lineChartMsgTotalData, initLineChart);
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
$homeNavLengh: 8;
|
|
|
|
|
|
+.chart-wrapper {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: stretch;
|
|
|
+ gap: 16px;
|
|
|
+
|
|
|
+ .chart-item {
|
|
|
+ background-color: var(--el-color-white);
|
|
|
+ padding: 12px 15px;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 200px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .chart-title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ padding-left: 5px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.home-card-top-part {
|
|
|
background-color: var(--el-color-white);
|
|
|
border-radius: 8px;
|
|
@@ -706,7 +504,6 @@ $homeNavLengh: 8;
|
|
|
.home-card-item,
|
|
|
.home-card-top {
|
|
|
width: 100%;
|
|
|
- height: 130px;
|
|
|
border-radius: 8px;
|
|
|
transition: all ease 0.3s;
|
|
|
padding: 10px 20px;
|
|
@@ -763,10 +560,6 @@ $homeNavLengh: 8;
|
|
|
|
|
|
.home-card-two,
|
|
|
.home-card-three {
|
|
|
- .home-card-item {
|
|
|
- height: 300px;
|
|
|
- }
|
|
|
-
|
|
|
.home-card-top {
|
|
|
height: 250px;
|
|
|
|