bizAccess.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. <template>
  2. <div class="app-container">
  3. <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="0">
  4. <el-form-item>
  5. <el-button type="primary" plain @click="timeSelect(0)">今天</el-button>
  6. <el-button type="primary" plain @click="timeSelect(3)">3天</el-button>
  7. <el-button type="primary" plain @click="timeSelect(7)">7天</el-button>
  8. <el-button type="primary" plain @click="timeSelect(30)">1月</el-button>
  9. </el-form-item>
  10. <el-form-item label="" style="width: 308px;margin-right:10px">
  11. <el-date-picker
  12. v-model="daterangeAlarmTime"
  13. value-format="YYYY-MM-DD"
  14. type="daterange"
  15. range-separator="-"
  16. start-placeholder="开始日期"
  17. end-placeholder="结束日期"
  18. ></el-date-picker>
  19. </el-form-item>
  20. <el-form-item>
  21. <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
  22. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  23. </el-form-item>
  24. </el-form>
  25. <el-row>
  26. <el-col :span="12">
  27. <div ref="chartAccess" style="height: 600px;"></div>
  28. </el-col>
  29. <el-col :span="12">
  30. <template #header>
  31. <Tickets style="width: 1em; height: 1em; vertical-align: middle;"/>
  32. <span style="vertical-align: middle;">{{ title }}</span></template>
  33. <el-table v-loading="loading" :data="leftList" v-show="sl" border style="height:300px;overflow-y: auto;">
  34. <el-table-column label="序号" align="center" width="80">
  35. <template #default="scope">
  36. <span>{{ scope.$index + 1 }}</span>
  37. </template>
  38. </el-table-column>
  39. <el-table-column label="组件名称" align="left" prop="modelName"/>
  40. <el-table-column label="系统压力值TPS/QPS" align="center" prop="access" width="150"/>
  41. <el-table-column label="访问错误次数" align="center" prop="num" width="120"/>
  42. </el-table>
  43. <el-table v-loading="loading" :data="rightList" v-show="sr" border style="height:555px;overflow-y: auto;">
  44. <el-table-column label="序号" align="center" width="120">
  45. <template #default="scope">
  46. <span>{{ scope.$index + 1 }}</span>
  47. </template>
  48. </el-table-column>
  49. <el-table-column label="组件名称" align="left" prop="objName"/>
  50. <el-table-column label="告警数量" align="center" prop="num" width="120"/>
  51. </el-table>
  52. <div ref="asLine" v-show="axx" style="height: 400px;padding-top: 20px;"></div>
  53. </el-col>
  54. </el-row>
  55. </div>
  56. </template>
  57. <script setup name="Record">
  58. import {getBizAccess} from "@/api/alarm/record";
  59. import {useRouter} from "vue-router";
  60. import * as echarts from "echarts";
  61. import moment from "moment";
  62. import {getObjAccess, getObjAlarm} from "../../../api/alarm/record.js";
  63. const {proxy} = getCurrentInstance();
  64. const {alarm_level} = proxy.useDict('alarm_level');
  65. const leftList = ref([]);
  66. const rightList = ref([]);
  67. const open = ref(false);
  68. const sl = ref(true);
  69. const axx = ref(true);
  70. const sr = ref(false);
  71. const loading = ref(true);
  72. const showSearch = ref(true);
  73. const ids = ref([]);
  74. const single = ref(true);
  75. const multiple = ref(true);
  76. const total = ref(0);
  77. const title = ref("");
  78. const daterangeAlarmTime = ref([]);
  79. const router = useRouter();
  80. const chartAccess = ref();
  81. const asLine = ref();
  82. const data = reactive({
  83. form: {},
  84. queryParams: {
  85. start: null,
  86. end: null,
  87. modeId: null
  88. },
  89. });
  90. function handleDetails(row) {
  91. console.log(row, router)
  92. }
  93. const {queryParams, form} = toRefs(data);
  94. function initChart(res) {
  95. let myChart = echarts.init(chartAccess.value);
  96. let img = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjUzOTAwNTEzMjYyIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjIxNjkiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj5AZm9udC1mYWNlIHsgZm9udC1mYW1pbHk6IGZlZWRiYWNrLWljb25mb250OyBzcmM6IHVybCgiLy9hdC5hbGljZG4uY29tL3QvZm9udF8xMDMxMTU4X3U2OXc4eWh4ZHUud29mZjI/dD0xNjMwMDMzNzU5OTQ0IikgZm9ybWF0KCJ3b2ZmMiIpLCB1cmwoIi8vYXQuYWxpY2RuLmNvbS90L2ZvbnRfMTAzMTE1OF91Njl3OHloeGR1LndvZmY/dD0xNjMwMDMzNzU5OTQ0IikgZm9ybWF0KCJ3b2ZmIiksIHVybCgiLy9hdC5hbGljZG4uY29tL3QvZm9udF8xMDMxMTU4X3U2OXc4eWh4ZHUudHRmP3Q9MTYzMDAzMzc1OTk0NCIpIGZvcm1hdCgidHJ1ZXR5cGUiKTsgfQo8L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNNTEyIDBoMzJ2MTYwaC0zMnpNNTEyIDI1NmgzMnYxNjBoLTMyek01MTIgNTEyaDMydjE2MGgtMzJ6TTUxMiA3NjhoMzJ2MTYwaC0zMnoiIGZpbGw9IiNkODFlMDYiIHAtaWQ9IjIxNzAiPjwvcGF0aD48L3N2Zz4=";
  97. let datas = [];
  98. let legendData1 = [];
  99. let legendData2 = [];
  100. let xMax1 = 50;
  101. let xMax2 = 50;
  102. for (let i in res.data) {
  103. let obj = res.data[i];
  104. datas.push(obj.modelName);
  105. legendData1.push({id: obj.modelId, value: obj.access});
  106. legendData2.push({id: obj.modelId, value: obj.num});
  107. if (i == 0) {
  108. dl(obj.modelId, obj.modelName);
  109. }
  110. if (obj.access > xMax1) {
  111. xMax1 = obj.access;
  112. }
  113. if (obj.num > xMax2) {
  114. xMax2 = obj.num;
  115. }
  116. }
  117. let dataheng = [xMax1 + 2, xMax1 + 2, xMax1 + 2, xMax1 + 2, xMax1 + 2];
  118. let option = {
  119. backgroundColor: '#fff',
  120. tooltip: {
  121. show: true,
  122. trigger: 'axis',
  123. axisPointer: {
  124. type: 'shadow',
  125. shadowStyle: {
  126. color: 'rgba(210,219,238,0.2)',
  127. },
  128. },
  129. },
  130. legend: {},
  131. grid: [{
  132. show: false,
  133. left: '0',
  134. top: 0,
  135. bottom: 22,
  136. width: '15%',
  137. },
  138. {
  139. containLabel: true,
  140. top: 0,
  141. left: '20%',
  142. bottom: '0%',
  143. width: '50%',
  144. show: false
  145. },
  146. {
  147. left: '74%',
  148. right: '10%',
  149. top: 0,
  150. bottom: '0%',
  151. containLabel: true,
  152. show: false
  153. },
  154. ],
  155. xAxis: [{
  156. gridIndex: 0,
  157. show: false,
  158. },
  159. {
  160. gridIndex: 1,
  161. show: false,
  162. max: xMax1,
  163. },
  164. {
  165. gridIndex: 2,
  166. show: false,
  167. max: xMax2,
  168. },
  169. ],
  170. yAxis: [{
  171. gridIndex: 0,
  172. type: 'category',
  173. inverse: true,
  174. position: 'right',
  175. axisLine: {
  176. show: false,
  177. },
  178. axisTick: {
  179. show: false,
  180. },
  181. data: datas.map(function (value) {
  182. return {
  183. value: value,
  184. textStyle: {
  185. align: 'right',
  186. },
  187. };
  188. }),
  189. axisLabel: {
  190. fontSize: 14,
  191. align: 'left',
  192. rich: {
  193. a: {
  194. color: '#fff',
  195. backgroundColor: '#49a2ff',
  196. width: 24,
  197. height: 24,
  198. align: 'center',
  199. borderRadius: 3,
  200. },
  201. a1: {
  202. color: '#fff',
  203. backgroundColor: '#f5576c',
  204. width: 24,
  205. height: 24,
  206. align: 'center',
  207. borderRadius: 3,
  208. },
  209. a2: {
  210. color: '#fff',
  211. backgroundColor: '#fee140',
  212. width: 24,
  213. height: 24,
  214. align: 'center',
  215. borderRadius: 3,
  216. },
  217. a3: {
  218. color: '#fff',
  219. backgroundColor: '#96fbc4',
  220. width: 24,
  221. height: 24,
  222. align: 'center',
  223. borderRadius: 3,
  224. },
  225. b: {
  226. color: '#333',
  227. width: 100,
  228. height: 30,
  229. align: 'right',
  230. },
  231. },
  232. formatter: function (params) {
  233. let index = datas.map((item) => item).indexOf(params);
  234. index = index + 1;
  235. if (index < 4) {
  236. return [`{a${index}|${index}}{b|${params}}`].join('\n');
  237. } else {
  238. return [`{a|${index}}{b|${params}}`].join('\n');
  239. }
  240. },
  241. },
  242. },
  243. {
  244. inverse: true,
  245. gridIndex: 1,
  246. data: datas,
  247. // max:10,
  248. axisLabel: {
  249. // margin: 80,
  250. show: false
  251. },
  252. axisLine: {
  253. show: false,
  254. },
  255. axisTick: {
  256. show: false,
  257. },
  258. axisPointer: {
  259. label: {
  260. show: false,
  261. margin: 30,
  262. },
  263. },
  264. },
  265. {
  266. gridIndex: 2,
  267. inverse: true,
  268. data: datas,
  269. // max:10,
  270. axisLine: {
  271. show: false,
  272. },
  273. axisTick: {
  274. show: false,
  275. },
  276. axisLabel: {
  277. show: false,
  278. },
  279. axisPointer: {
  280. label: {
  281. show: false,
  282. margin: 30,
  283. },
  284. },
  285. },
  286. ],
  287. series: [{
  288. type: 'bar',
  289. name: '系统压力值',
  290. stack: '2',
  291. barWidth: 20,
  292. z: 10,
  293. barCategoryGap: 15,
  294. // barGap:i==1?'-100%':'0',
  295. xAxisIndex: 1,
  296. yAxisIndex: 1,
  297. itemStyle: {
  298. color: '#419491',
  299. barBorderRadius: [0, 10, 10, 0],
  300. // barBorderRadius: legendData[i].barBorderRadius,
  301. emphasis: {
  302. color: '#419491',
  303. },
  304. },
  305. // 数字
  306. label: {
  307. show: true,
  308. position: 'inside',
  309. right: 0,
  310. color: '#fff',
  311. formatter: function (params) {
  312. if (params.value == 0) {
  313. return '';
  314. } else {
  315. return params.value;
  316. }
  317. },
  318. },
  319. data: legendData1,
  320. },
  321. //虚线
  322. {
  323. name: '',
  324. type: 'pictorialBar',
  325. xAxisIndex: 1,
  326. yAxisIndex: 1,
  327. symbolSize: [7, 30],
  328. symbolOffset: [15, 0],
  329. symbol: 'image://' + img,
  330. symbolPosition: 'end',
  331. barWidth: "20",
  332. z: 12,
  333. color: '#fe5959',
  334. data: dataheng,
  335. tooltip: {
  336. show: false,
  337. },
  338. },
  339. //右边的柱状图
  340. {
  341. xAxisIndex: 2,
  342. yAxisIndex: 2,
  343. type: 'bar',
  344. name: '告警数量',
  345. stack: '3',
  346. barWidth: 30,
  347. barCategoryGap: 15,
  348. // barGap:i==1?'-100%':'0',
  349. itemStyle: {
  350. color: '#FFB25C',
  351. barBorderRadius: [0, 20, 20, 0],
  352. emphasis: {
  353. color: '#FFB25C',
  354. },
  355. },
  356. // 数字
  357. label: {
  358. show: true,
  359. position: 'inside',
  360. right: 0,
  361. color: '#fff',
  362. formatter: function (params) {
  363. if (params.value == 0) {
  364. return '';
  365. } else {
  366. return params.value;
  367. }
  368. },
  369. },
  370. data: legendData2,
  371. },
  372. ],
  373. };
  374. // 3.配置项和数据给实例化对象
  375. myChart.setOption(option);
  376. myChart.on("click", function (param) {
  377. if (param.seriesIndex == 0) {
  378. dl(param.data.id, param.name);
  379. } else {
  380. dr(param.data.id, param.name);
  381. }
  382. console.log(param);
  383. // console.error(param,param.data.id,param.data.value,param.name);
  384. // let url = '/zabbix/zabbix.php?action=map.view&sysmapid=2&kiosk=1&line';
  385. });
  386. }
  387. function dl(modelId, name) {
  388. title.value = "[" + name + "] 组件压力排行";
  389. sl.value = true;
  390. axx.value = true;
  391. sr.value = false;
  392. queryParams.value.modelId = modelId;
  393. queryParams.value.params = {};
  394. if (null != daterangeAlarmTime && '' != daterangeAlarmTime) {
  395. queryParams.value.start = daterangeAlarmTime.value[0];
  396. queryParams.value.end = daterangeAlarmTime.value[1];
  397. }
  398. getObjAccess(queryParams.value).then(response => {
  399. loading.value = false;
  400. leftList.value = response.data.objs;
  401. line(response.data.datas);
  402. });
  403. }
  404. function dr(modelId, name) {
  405. title.value = "[" + name + "] 组件告警数量排行";
  406. sl.value = false;
  407. axx.value = false;
  408. sr.value = true;
  409. queryParams.value.modelId = modelId;
  410. queryParams.value.params = {};
  411. if (null != daterangeAlarmTime && '' != daterangeAlarmTime) {
  412. queryParams.value.start = daterangeAlarmTime.value[0];
  413. queryParams.value.end = daterangeAlarmTime.value[1];
  414. }
  415. getObjAlarm(queryParams.value).then(response => {
  416. loading.value = false;
  417. rightList.value = response.data;
  418. });
  419. }
  420. function line(data) {
  421. let myChart = echarts.init(asLine.value);
  422. let colorList = [
  423. '#419491',
  424. '#3581F8',
  425. '#FFB25C',
  426. ];
  427. let x_data = [];
  428. let max_data = [];
  429. let avg_data = [];
  430. let err_data = [];
  431. for (let i = 0; i < data.length; i++) {
  432. x_data.push(data[i].time);
  433. max_data.push(data[i].max);
  434. avg_data.push(data[i].avg);
  435. err_data.push(data[i].error);
  436. }
  437. let option = {
  438. backgroundColor: '#FFFFFF',
  439. dataZoom: {
  440. type: 'inside', // 内置型数据区域缩放组件
  441. start: 0, // 默认为0,表示从头开始
  442. end: 50 // 默认为100,表示直到末尾
  443. },
  444. title: {
  445. show: true,
  446. text: '系统压力值趋势',
  447. // subtext:'分配总量:18041核\n释放总量:5288核',
  448. // textStyle: {
  449. // fontFamily: 'PingFangSC-Regular, PingFang SC',
  450. // fontSize: 14,
  451. // fontWeight: 400,
  452. // color: '#848E98'
  453. // },
  454. left: 'left',
  455. top: '3%'
  456. },
  457. legend: {
  458. icon: 'rect',
  459. top: '3%',
  460. right: '10%',
  461. itemWidth: 10,
  462. itemHeight: 10,
  463. itemGap: 20,
  464. textStyle: {
  465. fontFamily: 'PingFangSC-Regular, PingFang SC',
  466. color: '#848E98'
  467. }
  468. },
  469. tooltip: {
  470. trigger: 'axis',
  471. axisPointer: {
  472. label: {
  473. show: true,
  474. backgroundColor: '#fff',
  475. color: '#556677',
  476. borderColor: 'rgba(0,0,0,0)',
  477. shadowColor: 'rgba(0,0,0,0)',
  478. shadowOffsetY: 0
  479. },
  480. lineStyle: {
  481. width: 0
  482. }
  483. },
  484. backgroundColor: '#fff',
  485. textStyle: {
  486. color: '#5c6c7c'
  487. },
  488. padding: [10, 10],
  489. extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
  490. },
  491. grid: {
  492. top: '18%'
  493. },
  494. xAxis: [{
  495. type: 'category',
  496. data: x_data,
  497. axisLine: {
  498. show: false,
  499. lineStyle: {
  500. color: '#000000'
  501. }
  502. },
  503. axisTick: {
  504. show: false
  505. },
  506. axisLabel: {
  507. interval: 'auto',
  508. rotate: 45,
  509. textStyle: {
  510. color: '#B7C3CE'
  511. },
  512. // 默认x轴字体大小
  513. fontSize: 12,
  514. // margin:文字到x轴的距离
  515. margin: 5
  516. }
  517. }],
  518. yAxis: [{
  519. type: 'value',
  520. // name: "核数",
  521. // position: 'left',
  522. // offset: 55,
  523. axisTick: {
  524. show: false
  525. },
  526. axisLine: {
  527. show: false,
  528. },
  529. axisLabel: {
  530. fontSize: 12,
  531. textStyle: {
  532. color: '#B7C3CE'
  533. }
  534. },
  535. splitLine: {
  536. show: true,
  537. lineStyle: {
  538. type: "dashed"
  539. }
  540. }
  541. }],
  542. series: [{
  543. name: '最大值',
  544. type: 'line',
  545. data: max_data,
  546. symbolSize: 1,
  547. symbol: 'circle',
  548. smooth: true,
  549. showSymbol: false,
  550. lineStyle: {
  551. width: 1,
  552. type: 'dotted', //'dotted'虚线 'solid'实线
  553. },
  554. itemStyle: {
  555. normal: {
  556. color: colorList[0],
  557. borderColor: colorList[0]
  558. }
  559. }
  560. }, {
  561. name: '平均值',
  562. type: 'line',
  563. data: avg_data,
  564. symbolSize: 1,
  565. symbol: 'circle',
  566. smooth: true,
  567. showSymbol: false,
  568. lineStyle: {
  569. width: 1,
  570. },
  571. itemStyle: {
  572. normal: {
  573. color: colorList[1],
  574. borderColor: colorList[1]
  575. }
  576. }
  577. },
  578. {
  579. name: '错误次数',
  580. type: 'line',
  581. data: err_data,
  582. symbolSize: 1,
  583. symbol: 'circle',
  584. smooth: true,
  585. showSymbol: false,
  586. lineStyle: {
  587. width: 1,
  588. },
  589. itemStyle: {
  590. normal: {
  591. color: colorList[2],
  592. borderColor: colorList[2]
  593. }
  594. }
  595. }
  596. ]
  597. };
  598. myChart.setOption(option);
  599. }
  600. /** 查询告警记录列表 */
  601. function getList() {
  602. loading.value = true;
  603. queryParams.value.params = {};
  604. if (null != daterangeAlarmTime && '' != daterangeAlarmTime) {
  605. queryParams.value.start = daterangeAlarmTime.value[0];
  606. queryParams.value.end = daterangeAlarmTime.value[1];
  607. }
  608. getBizAccess(queryParams.value).then(response => {
  609. // recordList.value = response.rows;
  610. // total.value = response.total;
  611. loading.value = false;
  612. initChart(response);
  613. });
  614. }
  615. /** 搜索按钮操作 */
  616. function handleQuery() {
  617. queryParams.value.pageNum = 1;
  618. getList();
  619. }
  620. function timeSelect(v) {
  621. let end = new Date();
  622. let start = new Date().setDate(end.getDate() - v);
  623. daterangeAlarmTime.value[0] = moment(start).format('YYYY-MM-DD');
  624. daterangeAlarmTime.value[1] = moment(end).format('YYYY-MM-DD');
  625. }
  626. /** 重置按钮操作 */
  627. function resetQuery() {
  628. daterangeAlarmTime.value = [];
  629. proxy.resetForm("queryRef");
  630. handleQuery();
  631. }
  632. timeSelect(30);
  633. getList();
  634. </script>