Эх сурвалжийг харах

告警统计相关业务功能

wukai 9 сар өмнө
parent
commit
2e3ff19581

+ 1 - 0
package.json

@@ -21,6 +21,7 @@
     "@vueuse/core": "10.6.1",
     "axios": "0.27.2",
     "echarts": "5.4.3",
+    "moment": "^2.30.1",
     "element-plus": "2.4.3",
     "file-saver": "2.0.5",
     "fuse.js": "6.6.2",

+ 8 - 0
src/api/alarm/record.js

@@ -52,6 +52,14 @@ export function getBizType(query) {
         params: query
     })
 }
+// 业务类型统计
+export function getBizObj(query) {
+    return request({
+        url: "/alarm/record/list/bizObj",
+        method: 'get',
+        params: query
+    })
+}
 
 // 应用组件统计
 export function getBizSort(query) {

+ 6 - 0
src/views/alarm/record/bizAccess.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="0">
+      <el-form-item>
+        <el-button type="primary" plain>今天</el-button>
+        <el-button type="primary" plain>3天</el-button>
+        <el-button type="primary" plain>7天</el-button>
+        <el-button type="primary" plain>1月</el-button>
+      </el-form-item>
       <el-form-item label="" style="width: 308px;margin-right:10px">
         <el-date-picker
             v-model="daterangeAlarmTime"

+ 12 - 2
src/views/alarm/record/bizSort.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="0">
+      <el-form-item>
+        <el-button type="primary" plain>今天</el-button>
+        <el-button type="primary" plain>3天</el-button>
+        <el-button type="primary" plain>7天</el-button>
+        <el-button type="primary" plain>1月</el-button>
+      </el-form-item>
       <el-form-item label="" style="width: 308px;margin-right:10px">
         <el-date-picker
             v-model="daterangeAlarmTime"
@@ -89,7 +95,7 @@ function initChart(res) {
   for (const i in res.data) {
     let obj=res.data[i]
     ydata.push(obj.objName);
-    salvProValue.push(obj.num);
+    salvProValue.push({id:i,value:obj.num});
   }
   let colorList = ['#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093','#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093'];
   let option = {
@@ -276,8 +282,12 @@ function initChart(res) {
   };
 
   myChart.setOption(option)
+  myChart.on("click", function (param) {
+    console.log(param)
+    // console.error(param,param.data.id,param.data.value,param.name);
+    // let url = '/zabbix/zabbix.php?action=map.view&sysmapid=2&kiosk=1&line';
+  });
 }
-
 /** 查询告警记录列表 */
 function getList() {
   loading.value = true;

+ 275 - 35
src/views/alarm/record/bizType.vue

@@ -1,6 +1,12 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="0">
+      <el-form-item>
+        <el-button type="primary" plain @click="timeSelect(0)">今天</el-button>
+        <el-button type="primary" plain @click="timeSelect(3)">3天</el-button>
+        <el-button type="primary" plain @click="timeSelect(7)">7天</el-button>
+        <el-button type="primary" plain @click="timeSelect(30)">1月</el-button>
+      </el-form-item>
       <el-form-item label="" style="width: 308px;margin-right:10px">
         <el-date-picker
             v-model="daterangeAlarmTime"
@@ -16,36 +22,27 @@
         <el-button icon="Refresh" @click="resetQuery">重置</el-button>
       </el-form-item>
     </el-form>
-    <el-card>
-      <div ref="chartType" style="height: 600px;"></div>
-    </el-card>
-<!--    <el-table v-loading="loading" :data="recordList" border >-->
-<!--      <el-table-column label="业务类型" align="center" >-->
-<!--        <template #default="scope">-->
-<!--          <span v-if="biz_type.length">{{ biz_type.find(p=>p.value === scope.row.bizType ).label }}</span>-->
-<!--        </template>-->
-<!--      </el-table-column>-->
-<!--      <el-table-column label="告警值" align="center" prop="num"  />-->
-<!--      <el-table-column label="操作" align="center" prop="alarmTime" width="180">-->
-<!--        <template #default="scope">-->
-<!--          <el-button type="text" plain icon="Position" @click="handleDetails(scope.row)">明细</el-button>-->
-<!--        </template>-->
-<!--      </el-table-column>-->
-<!--    </el-table>-->
-<!--    <pagination-->
-<!--        v-show="total>0"-->
-<!--        :total="total"-->
-<!--        v-model:page="queryParams.pageNum"-->
-<!--        v-model:limit="queryParams.pageSize"-->
-<!--        @pagination="getList"-->
-<!--    />-->
+    <el-row>
+      <el-col :span="12">
+        <el-card>
+          <div ref="chartType" style="height: 600px;"></div>
+        </el-card>
+      </el-col>
+      <el-col :span="12">
+        <el-card>
+          <div ref="chartRightType" style="height: 600px;">请点击左边柱状图</div>
+        </el-card>
+      </el-col>
+    </el-row>
   </div>
 </template>
 
 <script setup name="Record">
-import {getBizType} from "@/api/alarm/record";
+import {getBizType,getBizObj} from "@/api/alarm/record";
 import {useRouter} from "vue-router";
 import * as echarts from 'echarts'
+import moment from 'moment'
+
 const {proxy} = getCurrentInstance();
 const {alarm_level} = proxy.useDict('alarm_level');
 const {biz_type} = proxy.useDict('biz_type');
@@ -56,6 +53,7 @@ const showSearch = ref(true);
 const total = ref(0);
 const title = ref("");
 const chartType = ref();
+const chartRightType = ref();
 const daterangeAlarmTime = ref([]);
 const router = useRouter();
 
@@ -63,30 +61,249 @@ const data = reactive({
   form: {},
   queryParams: {
     start: null,
-    end: null
+    end: null,
+    type:null
   },
 });
 
 const {queryParams, form, rules} = toRefs(data);
 
-function handleDetails(row){
-  console.log(row,router)
+function handleDetails(row) {
+  console.log(row, router)
 }
-function initChart(res){
+
+function initChart(res) {
   const myChart = echarts.init(chartType.value);
-  let colorList = ['#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093','#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093'];
+  let colorList = ['#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093', '#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093'];
+  var ydata = [];
+  var salvProValue = [];
+  for (const i in res.data) {
+    let obj = res.data[i]
+    ydata.push(obj.name);
+    salvProValue.push({id:obj.id,value:obj.num});
+    if (i == 0) {
+      rightData(obj.id,obj.name);
+    }
+  }
+  let option = {
+    title: {
+      show: true,
+      text: '业务类型统计',
+      textStyle: {
+        fontFamily: 'PingFangSC-Regular, PingFang SC',
+        align: 'center',
+        color: '#515961',
+        fontSize: 18,
+      },
+    },
+    backgroundColor: '#fff',
+    grid: {
+      left: '2%',
+      right: '10%',
+      bottom: '2%',
+      top: '2%',
+      containLabel: true,
+    },
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: {
+        type: 'none'
+      },
+      formatter: '{b}:{c}',
+    },
+    xAxis: {
+      show: false,
+      type: 'value',
+    },
+    yAxis: {
+      type: "category",
+      data: ydata,
+      axisLine: {
+        show: false,
+      },
+      axisTick: {
+        show: false,
+      },
+      axisLabel: {
+        margin: 30,
+        width: 16,
+        align: "left",
+        overflow: "truncate",
+        formatter: function (value, index) {
+          let ind = index + 1;
+          if (ind == ydata.length) {
+            return "{one|" + (ydata.length - index) + "} {a|" + value + "}";
+          } else if (ind + 1 == ydata.length) {
+            return "{two|" + (ydata.length - index) + "} {b|" + value + "}";
+          } else if (ind + 2 == ydata.length) {
+            return (
+                "{three|" + (ydata.length - index) + "} {c|" + value + "}"
+            );
+          }
+          if (ydata.length - index > 9) {
+            return (
+                "{five|" + (ydata.length - index) + "} {d|" + value + "}"
+            );
+          }
+          return "{four|" + (ydata.length - index) + "} {d|" + value + "}";
+        },
+        rich: {
+          a: {
+            color: "#59c9f9",
+          },
+          b: {
+            color: "#59c9f9",
+          },
+          c: {
+            color: "#59c9f9",
+          },
+          d: {
+            color: "#59c9f9",
+          },
+          // 第一名
+          one: {
+            backgroundColor: "#E86452",
+            color: "white",
+            width: 12,
+            height: 16,
+            padding: [1, 0, 0, 5],
+            borderRadius: 10,
+            fontSize: 11,
+          },
+          // 第二名
+          two: {
+            backgroundColor: "#FF9845",
+            color: "white",
+            width: 12,
+            height: 16,
+            padding: [1, 0, 0, 5],
+            borderRadius: 10,
+            fontSize: 11,
+          },
+          // 第三名
+          three: {
+            backgroundColor: "#F6BD16",
+            color: "white",
+            width: 12,
+            height: 16,
+            padding: [1, 0, 0, 5],
+            borderRadius: 10,
+            fontSize: 11,
+          },
+          // 一位数
+          four: {
+            backgroundColor: "rgba(0,0,0,0.15)",
+            color: "white",
+            width: 12,
+            height: 16,
+            padding: [1, 0, 0, 5],
+            borderRadius: 10,
+            fontSize: 11,
+          },
+          // 两位数
+          five: {
+            backgroundColor: "rgba(0,0,0,0.15)",
+            color: "white",
+            width: 16,
+            height: 16,
+            padding: [1, 0, 0, 1],
+            borderRadius: 10,
+            fontSize: 11,
+          },
+        },
+      },
+    },
+    series: [
+      {
+        name: 'value',
+        type: 'bar',
+        zlevel: 1,
+        showBackground: true,
+
+        itemStyle: {
+          normal: {
+            barBorderRadius: [0, 20, 20, 0], // 圆角(左上、右上、右下、左下)
+            color: (params) => {
+              return colorList[params.dataIndex]
+            }
+          },
+        },
+        label: {
+          normal: {
+            color: '#000',
+            show: true,
+            position: [0, '-20px'],
+            textStyle: {
+              fontSize: 16,
+            },
+            formatter: '{b}',
+          },
+        },
+        barWidth: 20,
+        data: salvProValue,
+      },
+      {
+        name: '21',
+        type: 'bar',
+        barWidth: 20,
+        barGap: '-100%',
+        data: salvProValue,
+        itemStyle: {
+          normal: {
+            color: '#f5f8ff',
+          },
+          emphasis: {
+            color: '#f5f8ff',
+          },
+        },
+        label: {
+          normal: {
+            color: '#000',
+            show: true,
+            position: 'right',
+            distance: 4,
+            textStyle: {
+              fontSize: 16,
+            },
+            formatter: '{c}',
+          },
+        },
+      },
+    ],
+  };
+
+  myChart.setOption(option);
+  myChart.on("click", function (param) {
+    rightData(param.data.id,param.name);
+    // console.error(param,param.data.id,param.data.value,param.name);
+    // let url = '/zabbix/zabbix.php?action=map.view&sysmapid=2&kiosk=1&line';
+  });
+}
+function initChartRight(res,name) {
+  const myChart = echarts.init(chartRightType.value);
+  let colorList = ['#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093', '#fe8019', '#fec429', '#4a90e2', '#9095a7', '#4cb051', '#ec0019', '#dcb093'];
   var ydata = [];
   var salvProValue = [];
   for (const i in res.data) {
-    let obj=res.data[i]
-    ydata.push(obj.bizType);
-    salvProValue.push(obj.num);
+    let obj = res.data[i]
+    ydata.push(obj.name);
+    salvProValue.push({id:obj.id,value:obj.num});
   }
   let option = {
+    title: {
+      show: true,
+      text: name+' 业务组件统计',
+      textStyle: {
+        fontFamily: 'PingFangSC-Regular, PingFang SC',
+        align: 'center',
+        color: '#515961',
+        fontSize: 18,
+      },
+    },
     backgroundColor: '#fff',
     grid: {
       left: '2%',
-      right: '4%',
+      right: '10%',
       bottom: '2%',
       top: '2%',
       containLabel: true,
@@ -247,7 +464,7 @@ function initChart(res){
           normal: {
             color: '#000',
             show: true,
-            position:'right',
+            position: 'right',
             distance: 4,
             textStyle: {
               fontSize: 16,
@@ -259,8 +476,23 @@ function initChart(res){
     ],
   };
 
-  myChart.setOption(option)
+  myChart.setOption(option);
+  myChart.on("click", function (param) {
+    console.log(param)
+    // console.error(param,param.data.id,param.data.value,param.name);
+    // let url = '/zabbix/zabbix.php?action=map.view&sysmapid=2&kiosk=1&line';
+  });
+}
+
+
+function rightData(type,name){
+  queryParams.value.type=type;
+  getBizObj(queryParams.value).then(response => {
+    loading.value = false;
+    initChartRight(response,name);
+  });
 }
+
 /** 查询告警记录列表 */
 function getList() {
   loading.value = true;
@@ -278,6 +510,14 @@ function getList() {
 /** 搜索按钮操作 */
 function handleQuery() {
   queryParams.value.pageNum = 1;
+  getList();
+}
+
+function timeSelect(v) {
+  let end = new Date();
+  let start = new Date().setDate(end.getDate() - v);
+  daterangeAlarmTime.value[0] = moment(start).format('YYYY-MM-DD');
+  daterangeAlarmTime.value[1] = moment(end).format('YYYY-MM-DD');
 }
 
 /** 重置按钮操作 */

+ 79 - 39
src/views/alarm/record/index.vue

@@ -3,27 +3,13 @@
     <el-row :gutter="10" class="mb8">
       <el-col :span="16">
         <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="0">
-<!--          <el-form-item label="" prop="objId" style="margin-right:10px">-->
-<!--            <el-select v-model="queryParams.objId" placeholder="请选择业务类型" style="width: 260px" clearable filterable remote reserve-keyword :remote-method="remoteMethod">-->
-<!--              <el-option-->
-<!--                  v-for="dict in objList"-->
-<!--                  :key="dict.objId"-->
-<!--                  :label="dict.objName"-->
-<!--                  :value="dict.objId"-->
-<!--              ></el-option>-->
-<!--            </el-select>-->
-<!--          </el-form-item>-->
-<!--          <el-form-item label="" prop="alarmLevel" style="margin-right:10px">-->
-<!--            <el-select v-model="queryParams.alarmLevel" placeholder="告警级别" clearable style="width:100px;">-->
-<!--              <el-option-->
-<!--                  v-for="dict in alarm_level"-->
-<!--                  :key="dict.value"-->
-<!--                  :label="dict.label"-->
-<!--                  :value="dict.value"-->
-<!--              />-->
-<!--            </el-select>-->
-<!--          </el-form-item>-->
-          <el-form-item label="" style="width: 308px;margin-right:10px">
+          <el-form-item>
+            <el-button type="primary" plain @click="timeSelect(0)">今天</el-button>
+            <el-button type="primary" plain @click="timeSelect(3)">3天</el-button>
+            <el-button type="primary" plain @click="timeSelect(7)">7天</el-button>
+            <el-button type="primary" plain @click="timeSelect(30)">1月</el-button>
+          </el-form-item>
+          <el-form-item label="">
             <el-date-picker
                 v-model="daterangeAlarmTime"
                 value-format="YYYY-MM-DD"
@@ -33,6 +19,27 @@
                 end-placeholder="结束日期"
             ></el-date-picker>
           </el-form-item>
+          <el-form-item label="" prop="objId" style="margin-right:10px">
+            <el-select v-model="queryParams.objId" placeholder="请选择告警对象" style="width: 260px" clearable
+                       filterable remote reserve-keyword :remote-method="remoteMethod">
+              <el-option
+                  v-for="dict in objList"
+                  :key="dict.objId"
+                  :label="dict.objName"
+                  :value="dict.objId"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+          <el-form-item label="" prop="alarmLevel" style="margin-right:10px">
+            <el-select v-model="queryParams.alarmType" placeholder="风险状态" clearable style="width:100px;">
+              <el-option
+                  v-for="dict in alarm_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
           <el-form-item style="margin-right:10px">
             <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
             <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -52,17 +59,26 @@
         </el-card>
       </el-col>
     </el-row>
-    <el-table v-loading="loading" :data="recordList" border>
-      <el-table-column label="告警ID" align="left" prop="alarmId" width="80"/>
-      <el-table-column label="告警对象" align="left" prop="bizobj.objName"/>
-      <el-table-column label="告警指标" align="center" prop="bizObjMetrics.metricsName"/>
-      <el-table-column label="告警级别" align="center" prop="alarmLevel">
+    <el-table ref="recordRef" v-loading="loading" :data="recordList" border :default-sort="defaultSort"
+              @sort-change="handleSortChange">
+      <!--      <el-table-column label="告警ID" align="left" prop="alarmId" width="80"/>-->
+      <el-table-column label="风险对象" align="left" prop="objName" sortable="custom"
+                       :sort-orders="['descending', 'ascending']"/>
+      <el-table-column label="风险指标" align="center" prop="metricsName"/>
+      <el-table-column label="风险级别" align="center" prop="alarmLevel" sortable="custom"
+                       :sort-orders="['descending', 'ascending']">
         <template #default="scope">
           <dict-tag :options="alarm_level" :value="scope.row.alarmLevel"/>
         </template>
       </el-table-column>
-      <el-table-column label="告警值" align="center" prop="alarmValue" :formatter="rounding"/>
-      <el-table-column label="告警时间" align="center" prop="alarmTime" width="220">
+      <el-table-column label="风险状态" align="center" prop="alarmType">
+        <template #default="scope">
+          <dict-tag :options="alarm_type" :value="scope.row.alarmType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="风险值" align="center" prop="alarmValue" :formatter="rounding"/>
+      <el-table-column label="事件时间" align="center" prop="alarmTime" width="220" sortable="custom"
+                       :sort-orders="['descending', 'ascending']">
         <template #default="scope">
           <span>{{ parseTime(scope.row.alarmTime, '{y}-{m}-{d} {h}:{mi}:{s}') }}</span>
         </template>
@@ -79,11 +95,14 @@
 </template>
 
 <script setup name="Record">
-import {listRecord,getLevelSort} from "@/api/alarm/record";
+import {getLevelSort, listRecord} from "@/api/alarm/record";
 import {listObj} from "@/api/obj/obj.js"
 import * as echarts from 'echarts'
+import moment from 'moment'
+
 const {proxy} = getCurrentInstance();
 const {alarm_level} = proxy.useDict('alarm_level');
+const {alarm_type} = proxy.useDict('alarm_type');
 
 const recordList = ref([]);
 const loading = ref(true);
@@ -94,6 +113,7 @@ const daterangeAlarmTime = ref([]);
 const objList = ref([]);
 const alarmLeft = ref();
 const alarmRight = ref([]);
+const defaultSort = ref({prop: "alarmTime", order: "descending"});
 
 const data = reactive({
   form: {},
@@ -110,19 +130,19 @@ const data = reactive({
 
 const {queryParams, form, rules} = toRefs(data);
 
-function remoteMethod(keyword){
-  listObj({ pageNum: 1,pageSize: 5,objName: keyword}).then(res=>{
+function remoteMethod(keyword) {
+  listObj({pageNum: 1, pageSize: 5, objName: keyword}).then(res => {
     objList.value = res.rows
   })
 }
 
-function left(){
+function left() {
   let myChart = echarts.init(alarmLeft.value);
-  getLevelSort(queryParams.value).then(res=>{
+  getLevelSort(queryParams.value).then(res => {
     console.log(res);
     const d_data = [];
     for (let i = 0; i < res.data.length; i++) {
-      let d={value:res.data[i].num,name:res.data[i].name}
+      let d = {value: res.data[i].num, name: res.data[i].name}
       d_data.push(d);
     }
     let legend_style = {
@@ -147,7 +167,7 @@ function left(){
       },
       title: {
         show: true,
-        text: '告警级别统计',
+        text: '风险级别统计',
         textStyle: {
           fontFamily: 'PingFangSC-Regular, PingFang SC',
           align: 'center',
@@ -194,15 +214,15 @@ function left(){
         }
       }
       let percent = (x_data.value * 100 / total).toFixed(2);
-      return '{a|' + name + '} {b|' + percent + '%}     {c|'+x_data.value+'}次';
+      return '{a|' + name + '} {b|' + percent + '%}     {c|' + x_data.value + '}次';
     }
   })
 
 }
 
-function right(){
+function right() {
   let myChart = echarts.init(alarmRight.value);
-  var res=[
+  var res = [
     {
       "scores": [
         58.0,
@@ -234,7 +254,7 @@ function right(){
       symbol: 'circle',
       smooth: true,
       showSymbol: false,
-      stack:'total'
+      stack: 'total'
     }
     ss.push(xx);
   }
@@ -342,12 +362,17 @@ function right(){
 
 /** 查询告警记录列表 */
 function getList() {
+  console.error(alarm_type);
   loading.value = true;
   queryParams.value.params = {};
   if (null != daterangeAlarmTime && '' != daterangeAlarmTime) {
     queryParams.value.params["beginAlarmTime"] = daterangeAlarmTime.value[0];
     queryParams.value.params["endAlarmTime"] = daterangeAlarmTime.value[1];
   }
+  if (queryParams.value.orderByColumn == null || queryParams.value.orderByColumn == '') {
+    queryParams.value.orderByColumn = defaultSort.value.prop;
+    queryParams.value.isAsc = defaultSort.value.order;
+  }
   listRecord(queryParams.value).then(response => {
     recordList.value = response.rows;
     total.value = response.total;
@@ -357,6 +382,13 @@ function getList() {
   });
 }
 
+function timeSelect(v) {
+  let end = new Date();
+  let start = new Date().setDate(end.getDate() - v);
+  daterangeAlarmTime.value[0] = moment(start).format('YYYY-MM-DD');
+  daterangeAlarmTime.value[1] = moment(end).format('YYYY-MM-DD');
+}
+
 /** 搜索按钮操作 */
 function handleQuery() {
   queryParams.value.pageNum = 1;
@@ -367,6 +399,7 @@ function handleQuery() {
 function resetQuery() {
   daterangeAlarmTime.value = [];
   proxy.resetForm("queryRef");
+  proxy.$refs["recordRef"].sort(defaultSort.value.prop, defaultSort.value.order);
   handleQuery();
 }
 
@@ -375,5 +408,12 @@ function rounding(row, column) {
   return parseFloat(row[column.property]).toFixed(2)
 }
 
+/** 排序触发事件 */
+function handleSortChange(column, prop, order) {
+  queryParams.value.orderByColumn = column.prop;
+  queryParams.value.isAsc = column.order;
+  getList();
+}
+
 getList();
 </script>