Browse Source

feat: 修改仪表盘首页图形echarts为 vue-data-ui

yanglzh 10 months ago
parent
commit
ada9c9f4ef
3 changed files with 125 additions and 302 deletions
  1. 57 2
      src/utils/dataUiOptions.ts
  2. 0 25
      src/views/iot/iotmanager/chart.vue
  3. 68 275
      src/views/iot/iotmanager/dashboard.vue

+ 57 - 2
src/utils/dataUiOptions.ts

@@ -1,5 +1,5 @@
 
-export function getLineData({ xAxis = [] as any[], datas = [] as number[][], legend = [] as string[], suffix = '', width = 1000, height = 250 }) {
+export function getLineData({ xAxis = [] as any[], datas = [] as number[][], legend = [] as string[], suffix = '', width = 1000, height = 400 }) {
   const colors = ['#6376DD', '#FBBB04']
   const config = {
     "chart": {
@@ -8,7 +8,6 @@ export function getLineData({ xAxis = [] as any[], datas = [] as number[][], leg
       "backgroundColor": "transparent",
       "color": "#888888",
       height,
-      maxHeight: height,
       width,
       "zoom": {
         "show": false
@@ -89,4 +88,60 @@ export function getLineData({ xAxis = [] as any[], datas = [] as number[][], leg
   })
 
   return { config, dataset }
+}
+
+export function getPieData({ datas = [] as number[][], legend = [] as string[], types = [] as number[], width = 500, height = 1300 }) {
+
+  const colorList = ['#4285F4', '#2ecc71', '#FBBB04', '#e67e22', '#FF0000'].reverse()
+
+  const config = {
+    style: {
+      "color": "#888888",
+      chart: {
+        "fontFamily": "inherit",
+        "paddingTop": 0,
+        "backgroundColor": "transparent",
+        "color": "#888888",
+        height,
+        width,
+        "padding": {
+          "top": 0,
+          "right": 0,
+          "bottom": 0,
+          "left": 0
+        },
+        legend: { color: "#888888" },
+        tooltip: {
+          color: "#888888",
+          showPercentage: true,
+          backgroundOpacity: 30,
+        },
+        "title": {
+          "text": " ",
+          "show": false,
+        },
+        "layout": {
+          "labels": {
+            "hollow": {
+              "average": {
+                "show": false,
+              },
+            },
+          },
+        },
+      },
+    },
+    "userOptions": {
+      "show": false
+    },
+  }
+
+
+  // const dataset = [{ "name": "Series 1", "values": [100] }, { "name": "Series 2", "values": [50] }, { "name": "Series 3", "values": [25] }, { "name": "Series 4", "values": [12.5] }]
+
+  const dataset = datas.map((data, i) => {
+    return { "name": legend[i], "values": data, color: colorList[types[i] - 1] }
+  })
+
+  return { config, dataset }
 }

+ 0 - 25
src/views/iot/iotmanager/chart.vue

@@ -1,25 +0,0 @@
-<script setup>
-import { ref } from "vue";
-import { VueUiXy } from "vue-data-ui";
-import "vue-data-ui/style.css";
-import { getLineData } from "/@/utils/dataUiOptions";
-
-const config = ref();
-
-const dataset = ref();
-
-const chartData = getLineData({
-  xAxis: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
-  legend: ['消息量', '预警量'],
-  datas: [
-    [120, 132, 101, 134, 90, 230, 210], [220, 182, 191, 234, 290, 330, 310],
-  ]
-})
-
-config.value = chartData.config
-dataset.value = chartData.dataset
-</script>
-
-<template>
-  <VueUiXy :dataset="dataset" :config="config" />
-</template>

+ 68 - 275
src/views/iot/iotmanager/dashboard.vue

@@ -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;