Преглед на файлове

feat: 告警统计增加最新告警 table,告警统计 图表

yanglzh преди 10 месеца
родител
ревизия
d852c6a058
променени са 3 файла, в които са добавени 228 реда и са изтрити 134 реда
  1. 28 19
      src/api/alarm/index.ts
  2. 4 0
      src/theme/app.scss
  3. 196 115
      src/views/iot/alarm/dashboard/index.vue

+ 28 - 19
src/api/alarm/index.ts

@@ -1,27 +1,36 @@
-import { get, post, del, put } from '/@/utils/request';
+import { get, post, del, put } from "/@/utils/request";
 
 export default {
   common: {
-    trigger_type: (productKey: string) => get('/alarm/rule/trigger_type', { productKey }),
-    trigger_param: (productKey: string) => get('/alarm/rule/trigger_param', { productKey }),
-    trigger_params: (params: object) => get('/alarm/rule/trigger_param', params),
-    operator: (productKey?: string) => get('/alarm/rule/operator', { productKey }),
-    getList: (params: object) => get('/alarm/rule/list', params),
-    add: (data: object) => post('/alarm/rule/add', data),
-    delete: (id: number) => del('/alarm/rule/del', { id }),
-    edit: (data: object) => put('/alarm/rule/edit', data),
-    detail: (id: number) => get('/alarm/rule/detail', { id }),
-    deploy: (data: object) => post('/alarm/rule/deploy', data),
-    undeploy: (data: object) => post('/alarm/rule/undeploy', data),
-    level_edit: (data: object) => put('/alarm/level/edit', data),
-    level_all: (productKey: string) => get('/alarm/level/all', { productKey }),
+    trigger_type: (productKey: string) => get("/alarm/rule/trigger_type", { productKey }),
+    trigger_param: (productKey: string) =>
+      get("/alarm/rule/trigger_param", { productKey }),
+    trigger_params: (params: object) => get("/alarm/rule/trigger_param", params),
+    operator: (productKey?: string) => get("/alarm/rule/operator", { productKey }),
+    getList: (params: object) => get("/alarm/rule/list", params),
+    add: (data: object) => post("/alarm/rule/add", data),
+    delete: (id: number) => del("/alarm/rule/del", { id }),
+    edit: (data: object) => put("/alarm/rule/edit", data),
+    detail: (id: number) => get("/alarm/rule/detail", { id }),
+    deploy: (data: object) => post("/alarm/rule/deploy", data),
+    undeploy: (data: object) => post("/alarm/rule/undeploy", data),
+    level_edit: (data: object) => put("/alarm/level/edit", data),
+    level_all: (productKey: string) => get("/alarm/level/all", { productKey }),
   },
   log: {
-    getList: (params: object) => get('/alarm/log/list', params),
-    detail: (id: number) => get('/alarm/log/detail', { id }),
-    handle: (data: object) => post('/alarm/log/handle', data),
+    getList: (params: object) => get("/alarm/log/list", params),
+    detail: (id: number) => get("/alarm/log/detail", { id }),
+    handle: (data: object) => post("/alarm/log/handle", data),
   },
   dashboard: {
-    getDeviceAlarmTop10: () => get('/alarm/log/getDeviceAlarmTop10'),
+    getDeviceAlarmTop10: () => get("/alarm/log/getDeviceAlarmTop10"),
+    // 部门告警统计
+    getDeptAlarm: () => get("/alarm/log/getDeptAlarm"),
+    // 今日告警信息
+    getCurrentDayInfo: () => get("/alarm/log/getCurrentDayInfo"),
+    // 最新告警
+    getAlarmNewList: () => get("/alarm/log/getAlarmNewList"),
+    // 告警统计
+    getAlarmStatistics: (params: object) => get("/alarm/log/getAlarmStatistics", params),
   },
-}
+};

+ 4 - 0
src/theme/app.scss

@@ -33,6 +33,10 @@
 		border-bottom: none !important;
 		padding: 12px 0 !important;
 	}
+	&--small thead th {
+		border-bottom: none !important;
+		padding: 4px 0 !important;
+	}
 }
 
 html,

+ 196 - 115
src/views/iot/alarm/dashboard/index.vue

@@ -1,74 +1,112 @@
 <template>
-	<div class="page">
-		<div class="flex-row" style="gap: 12px">
-			<el-card shadow="nover">
-				<div class="title">今日告警</div>
-				<VueUiSkeleton class="flex1" :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">告警设备top10</div>
-				<VueUiXy v-if="dataset2?.length" :config="config2" :dataset="dataset2" />
-				<VueUiSkeleton v-else :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">最新告警</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-		</div>
-		<div class="flex-row" style="gap: 12px">
-			<el-card shadow="nover">
-				<div class="title">告警统计</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">告警增长趋势</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">部门告警分析</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-		</div>
-		<div class="flex-row" style="gap: 12px">
-			<el-card shadow="nover">
-				<div class="title">告警状态</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">告警等级</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-			<el-card shadow="nover">
-				<div class="title">告警类型</div>
-				<VueUiSkeleton :config="{ type: 'bar' }" />
-			</el-card>
-		</div>
-	</div>
+  <div class="page">
+    <div class="flex-row" style="gap: 12px">
+      <el-card shadow="nover">
+        <div class="title">今日告警</div>
+        <VueUiSkeleton class="flex1" :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">告警设备top10</div>
+        <VueUiXy v-if="dataset2?.length" :config="config2" :dataset="dataset2" />
+        <VueUiSkeleton v-else :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">最新告警</div>
+        <el-table
+          class="flex1"
+          :data="alarmNewList"
+          border
+          style="width: 100%"
+          size="small"
+        >
+          <el-table-column prop="createdAt" label="告警日期" width="140" align="center" />
+          <el-table-column
+            prop="status"
+            :formatter="(row:any) => (row.status ? '已处理' : '未处理')"
+            label="告警状态"
+            width="70"
+            align="center"
+          />
+          <el-table-column
+            prop="level"
+            label="告警等级"
+            :formatter="(row:any) => typeFormat(row.level)"
+            width="100"
+            align="center"
+          />
+          <el-table-column
+            prop="ruleName"
+            label="告警说明"
+            show-overflow-tooltip
+            aign="center"
+          />
+        </el-table>
+      </el-card>
+    </div>
+    <div class="flex-row" style="gap: 12px">
+      <el-card shadow="nover">
+        <div class="title">告警统计</div>
+        <VueUiXy v-if="dataset4?.length" :config="config4" :dataset="dataset4" />
+        <VueUiSkeleton v-else :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">告警增长趋势</div>
+        <VueUiSkeleton :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">部门告警分析</div>
+        <VueUiSkeleton :config="{ type: 'bar' }" />
+      </el-card>
+    </div>
+    <div class="flex-row" style="gap: 12px">
+      <el-card shadow="nover">
+        <div class="title">告警状态</div>
+        <VueUiSkeleton :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">告警等级</div>
+        <VueUiSkeleton :config="{ type: 'bar' }" />
+      </el-card>
+      <el-card shadow="nover">
+        <div class="title">告警类型</div>
+        <VueUiSkeleton :config="{ type: 'bar' }" />
+      </el-card>
+    </div>
+  </div>
 </template>
 
 <script lang="ts" setup>
-import { toRefs, reactive, onMounted, ref } from "vue";
+import { unref, reactive, getCurrentInstance, ref } from "vue";
 import { VueUiXy, VueUiDonut, VueUiSkeleton } from "vue-data-ui";
 import "vue-data-ui/style.css";
 import { getBarData, getLineData, getPieData } from "/@/utils/dataUiOptions";
 import api from "/@/api/alarm";
-import dayjs from "dayjs";
 import { useThemeChange } from "/@/hooks/useCommon";
+import dayjs from "dayjs";
+
+const { proxy } = getCurrentInstance() as any;
+const { alarm_type } = proxy.useDict("alarm_type");
+
+function typeFormat(type: string) {
+  return proxy.selectDictLabel(unref(alarm_type), type);
+}
 
 //#region 线图
 
 // 获取默认图形配置数据
 const chartData = getLineData({
-	xAxis: [],
-	legend: [" "],
-	datas: [[]],
-	responsive: true,
+  xAxis: [],
+  legend: [" "],
+  datas: [[]],
+  responsive: true,
 });
 
 const config = ref<any>({});
 const config2 = ref<any>({});
+const config4 = ref<any>({});
 const dataset = ref<any[]>([]);
 const dataset2 = ref<any[]>([]);
+const dataset4 = ref<any[]>([]);
 
 //#endregion
 
@@ -76,8 +114,8 @@ const dataset2 = ref<any[]>([]);
 
 // 获取默认图形配置数据
 const pieData = getPieData({
-	legend: [" "],
-	datas: [[]],
+  legend: [" "],
+  datas: [[]],
 });
 
 const pieConfig = ref<any>(pieData.config);
@@ -86,74 +124,117 @@ const pieDataset = ref<any[]>(pieData.dataset);
 // 监听暗黑模式变化,将 vue-data-ui 的 config 传进来,就能自动更新主题
 useThemeChange([config, pieConfig]);
 
-getData()
+const todayCount = reactive({
+  currentDayCount: "-",
+  currentMonthCount: "-",
+});
+
+const alarmNewList = ref<any[]>([]);
+
+getData();
 
 function getData() {
-	// 告警设备top10
-	api.dashboard.getDeviceAlarmTop10().then((res: any) => {
-		const list = res || []
-		const chartData = getBarData({
-			xAxis: list.map((item: any) => item.deviceName),
-			legend: ['告警设备top10'],
-			datas: [list.map((item: any) => item.alarmCount)],
-			width: 300,
-			height: 300,
-			responsive: true
-		})
-		config2.value = chartData.config
-		dataset2.value = chartData.dataset
-	})
+  // 今日告警信息
+  api.dashboard.getCurrentDayInfo().then((res: any) => {
+    const list = res.alarmList || [];
+    todayCount.currentDayCount = res.currentDayCount;
+    todayCount.currentMonthCount = res.currentMonthCount;
+
+    console.log(res);
+    console.log(list);
+  });
+  // 最新告警
+  api.dashboard.getAlarmNewList().then((res: any) => {
+    console.log(res);
+    alarmNewList.value = res || [];
+  });
+  // 告警统计
+  api.dashboard
+    .getAlarmStatistics({
+      startDate: dayjs().subtract(7, "day").format("YYYY-MM-DD"),
+      endDate: dayjs().format("YYYY-MM-DD"),
+    })
+    .then((res: any) => {
+      console.log(res);
+      const list = res || [];
+      const chartData = getBarData({
+        xAxis: list.map((item: any) => item.alarmDate),
+        legend: ["告警统计"],
+        datas: [list.map((item: any) => item.alarmCount)],
+        width: 300,
+        height: 300,
+        modulo: 3,
+        responsive: true,
+      });
+      console.log(chartData);
+      config4.value = chartData.config;
+      dataset4.value = chartData.dataset;
+    });
+  // 告警设备top10
+  api.dashboard.getDeviceAlarmTop10().then((res: any) => {
+    const list = res || [];
+    const chartData = getBarData({
+      xAxis: list.map((item: any) => item.deviceName),
+      legend: ["告警设备top10"],
+      datas: [list.map((item: any) => item.alarmCount)],
+      width: 300,
+      height: 300,
+      responsive: true,
+    });
+    config2.value = chartData.config;
+    dataset2.value = chartData.dataset;
+  });
 }
 </script>
 
 <style scoped lang="scss">
 .page {
-	display: flex;
-	flex-direction: column;
-	justify-content: space-between;
-	gap: 12px;
-
-	.vue-ui-skeleton {
-		height: 100%;
-
-		& ::v-deep>svg {
-			height: 100%;
-		}
-	}
-
-	.title {
-		font-size: 14px;
-		color: #333;
-		font-weight: 500;
-		line-height: 1;
-	}
-
-	.flex-row {
-		flex: 1;
-
-		.el-card {
-			height: 100%;
-			flex: 1;
-
-			& ::v-deep .el-card__body {
-				padding: 1.5vh 1vw;
-				height: 100%;
-				gap: 10px;
-				display: flex;
-				flex-direction: column;
-				justify-content: space-between;
-
-				.vue-ui-xy,
-				.vue-ui-skeleton {
-					flex: 1;
-					height: 100%;
-				}
-
-				.vue-ui-skeleton {
-					overflow: hidden;
-				}
-			}
-		}
-	}
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  gap: 12px;
+
+  .vue-ui-skeleton {
+    height: 100%;
+
+    & ::v-deep > svg {
+      height: 100%;
+    }
+  }
+
+  .title {
+    font-size: 14px;
+    color: #333;
+    font-weight: 500;
+    line-height: 1;
+  }
+
+  .flex-row {
+    flex: 1;
+
+    .el-card {
+      height: 100%;
+      flex: 1;
+
+      & ::v-deep .el-card__body {
+        padding: 1.5vh 1vw;
+        height: 100%;
+        gap: 10px;
+        display: flex;
+        flex-direction: column;
+        justify-content: space-between;
+
+        .vue-ui-xy,
+        .vue-ui-skeleton {
+          flex: 1;
+          height: 100%;
+        }
+
+        .vue-ui-skeleton {
+          overflow: hidden;
+        }
+      }
+    }
+  }
 }
 </style>