index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <template>
  2. <div v-loading="loading">
  3. <div class="flex-row" style="gap: 16px; align-items: stretch;margin-bottom: 16px">
  4. <el-card shadow="nover" class="flex1">
  5. <div class="flex-row">
  6. <el-descriptions :column="1" border class="flex1">
  7. <el-descriptions-item label="CPU数">{{ sysInfo.cpuNum }}</el-descriptions-item>
  8. <el-descriptions-item label="核心数">{{ sysInfo.cpuCores }}</el-descriptions-item>
  9. <el-descriptions-item label="使用率">{{ sysInfo.cpuUsed }}%</el-descriptions-item>
  10. <el-descriptions-item label="LA5">{{ sysInfo.cpuAvg5 }}%</el-descriptions-item>
  11. <el-descriptions-item label="LA15">{{ sysInfo.cpuAvg15 }}%</el-descriptions-item>
  12. </el-descriptions>
  13. <div class="flex1">
  14. <VueUiGauge :dataset="dataset" :config="config" />
  15. </div>
  16. </div>
  17. </el-card>
  18. <el-card shadow="nover" class="flex1">
  19. <div class="flex-row">
  20. <el-descriptions :column="1" border class="flex1">
  21. <el-descriptions-item label="内存总数">{{ memorySizeFormat(sysInfo.memTotal) }}</el-descriptions-item>
  22. <el-descriptions-item label="已使用">{{ memorySizeFormat(sysInfo.memUsed) }}</el-descriptions-item>
  23. <el-descriptions-item label="剩余">{{ memorySizeFormat(sysInfo.available) }}</el-descriptions-item>
  24. <el-descriptions-item label="系统使用">{{ memorySizeFormat(sysInfo.goUsed) }}</el-descriptions-item>
  25. <el-descriptions-item label="使用率">{{ memorySizeFormat(sysInfo.memUsage) }}%</el-descriptions-item>
  26. </el-descriptions>
  27. <div class="flex1">
  28. <VueUiGauge :dataset="dataset2" :config="config2" />
  29. </div>
  30. </div>
  31. </el-card>
  32. <el-card shadow="nover" class="flex1">
  33. <div class="flex-row">
  34. <el-descriptions :column="1" border class="flex1">
  35. <el-descriptions-item label="磁盘容量">{{ memorySizeFormat(sysInfo.diskTotal) }}</el-descriptions-item>
  36. <el-descriptions-item label="已使用">{{ memorySizeFormat(sysInfo.diskUsed) }}</el-descriptions-item>
  37. <el-descriptions-item label="使用率">{{ memorySizeFormat(sysInfo.diskUsedPercent) }}%</el-descriptions-item>
  38. </el-descriptions>
  39. <div class="flex1">
  40. <VueUiGauge :dataset="dataset3" :config="config3" />
  41. </div>
  42. </div>
  43. </el-card>
  44. </div>
  45. <el-row :gutter="15">
  46. <el-col :xs="24" :sm="12" :md="8" class="mb-4">
  47. <el-card shadow="nover" class="box-card-height" style="height:auto">
  48. <template #header>
  49. <div class="card-header">
  50. <span>CPU运行情况</span>
  51. </div>
  52. </template>
  53. <div style="height: 250px" ref="chartsWarningRef4"></div>
  54. </el-card>
  55. </el-col>
  56. <el-col :xs="24" :sm="12" :md="8" class="mb-4">
  57. <el-card shadow="nover" class="box-card-height" style="height:auto">
  58. <template #header>
  59. <div class="card-header">
  60. <span>内存运行情况</span>
  61. </div>
  62. </template>
  63. <div style="height: 250px" ref="chartsWarningRef5"></div>
  64. </el-card>
  65. </el-col>
  66. <el-col :xs="24" :sm="12" :md="8" class="mb-4">
  67. <el-card shadow="nover" class="box-card-height" style="height:auto">
  68. <template #header>
  69. <div class="card-header">
  70. <span>磁盘使用情况</span>
  71. </div>
  72. </template>
  73. <div style="height: 250px" ref="chartsWarningRef6"></div>
  74. </el-card>
  75. </el-col>
  76. </el-row>
  77. <div class="flex-row gap-2">
  78. <el-col :xs="24" :sm="24" :md="24">
  79. <el-card shadow="nover" class="box-card-height" style="height:auto">
  80. <template #header>
  81. <div class="card-header">
  82. <span>运行环境信息</span>
  83. </div>
  84. </template>
  85. <el-descriptions :column="3" border class="flex1">
  86. <el-descriptions-item label="操作系统">{{ hostData.os }}</el-descriptions-item>
  87. <el-descriptions-item label="系统架构">{{ goInfoData.arch }}</el-descriptions-item>
  88. <el-descriptions-item label="架构版本">{{ hostData.kernelArch }}</el-descriptions-item>
  89. <el-descriptions-item label="启动时间">{{ goInfoData.startTime }}</el-descriptions-item>
  90. <el-descriptions-item label="语言环境">{{ goInfoData.goName }}</el-descriptions-item>
  91. <el-descriptions-item label="GO 版本">{{ goInfoData.goVersion }}</el-descriptions-item>
  92. <el-descriptions-item label="运行时长">{{ timeFormat(goInfoData.runTime) }}</el-descriptions-item>
  93. <el-descriptions-item label="磁盘占用">{{ goInfoData.goSize }}</el-descriptions-item>
  94. <el-descriptions-item label="协程数量">{{ goInfoData.goroutine }}</el-descriptions-item>
  95. <el-descriptions-item label="运行内存">{{ goInfoData.goMem }}</el-descriptions-item>
  96. <el-descriptions-item label="项目地址">{{ goInfoData.pwd }}</el-descriptions-item>
  97. <el-descriptions-item label="服务器IP">{{ hostData.intranet_ip }} (内) &nbsp;&nbsp;&nbsp; {{ hostData.public_ip }} (公) </el-descriptions-item>
  98. </el-descriptions>
  99. </el-card>
  100. </el-col>
  101. </div>
  102. </div>
  103. </template>
  104. <script lang="ts" setup>
  105. import { ref, toRefs, reactive, onMounted, getCurrentInstance, defineComponent, onUnmounted } from 'vue';
  106. import * as echarts from 'echarts';
  107. import 'echarts-wordcloud';
  108. import dayjs from 'dayjs';
  109. import { getSSEOrigin } from '/@/utils/origin'
  110. import { VueUiGauge } from "vue-data-ui";
  111. import "vue-data-ui/style.css";
  112. import { getGaugeData } from "/@/utils/dataUiOptions";
  113. let interval: any = null;
  114. let es: any = null;
  115. const { proxy } = getCurrentInstance() as any;
  116. const sysInfo: any = reactive<any>({
  117. });
  118. const loading = ref(true)
  119. //#region 线图
  120. // 获取默认图形配置数据
  121. const chartData = getGaugeData({
  122. value: 0
  123. })
  124. const config = ref<any>(chartData.config);
  125. const config2 = ref<any>(chartData.config);
  126. const config3 = ref<any>(chartData.config);
  127. const dataset = ref<any>(chartData.dataset);
  128. const dataset2 = ref<any>(chartData.dataset);
  129. const dataset3 = ref<any>(chartData.dataset);
  130. //#endregion
  131. let myChart4: any;
  132. let myChart5: any;
  133. let myChart6: any;
  134. const hostData = reactive({
  135. "bootTime": "2022-11-24T11:12:13+08:00",
  136. "hostId": "8be74718-1a53-4208-be22-9c126d891ddd",
  137. "hostname": "iZ2zee04uvnkmhvglw9oghZ",
  138. "intranet_ip": "172.17.47.62",
  139. "kernelArch": "x86_64",
  140. "kernelVersion": "3.10.0-1127.19.1.el7.x86_64",
  141. "os": "linux",
  142. "platform": "centos",
  143. "platformFamily": "rhel",
  144. "platformVersion": "7.7.1908",
  145. "procs": 138,
  146. "public_ip": "101.200.198.249",
  147. "uptime": 6393278,
  148. "virtualizationRole": "guest",
  149. "virtualizationSystem": ""
  150. });
  151. const goInfoData = reactive({
  152. "goOs": "-", "arch": "-", "goVersion": "-", "goMem": "-", "goName": "-", "goSize": "-", "goroutine": '-', "pwd": "-", "rootPath": "-",
  153. "runTime": '', "startTime": "-", "intranet_ip": "-"
  154. });
  155. function goInfo(event: { data: any; }) {
  156. const data = JSON.parse(event.data);
  157. Object.assign(goInfoData, data);
  158. loading.value = false
  159. }
  160. function hostInfo(event: { data: any; }) {
  161. const data = JSON.parse(event.data);
  162. Object.assign(hostData, data);
  163. loading.value = false
  164. }
  165. const myChart4Data: any = {
  166. name: [],
  167. value: [],
  168. }
  169. const myChart5Data: any = {
  170. name: [],
  171. value: [],
  172. }
  173. const myChart6Data: any = {
  174. name: [],
  175. value: [],
  176. }
  177. const moveOption = {
  178. tooltip: {
  179. trigger: 'axis',
  180. },
  181. grid: {
  182. top: 5,
  183. bottom: 5,
  184. left: 5,
  185. right: 30,
  186. containLabel: true
  187. },
  188. xAxis: {
  189. type: 'category',
  190. boundaryGap: false,
  191. splitLine: {
  192. show: false
  193. }
  194. },
  195. yAxis: {
  196. type: 'value',
  197. boundaryGap: [0, '100%'],
  198. axisLabel: {
  199. formatter: '{value}%'
  200. },
  201. splitLine: {
  202. show: false
  203. }
  204. },
  205. series: [
  206. {
  207. name: '使用率',
  208. type: 'line',
  209. showSymbol: false,
  210. data: [],
  211. smooth: true,
  212. lineStyle: {
  213. width: 0
  214. },
  215. areaStyle: {}
  216. }
  217. ]
  218. };
  219. function setOptChart1(value: number) {
  220. const chartData = getGaugeData({ value })
  221. config.value = chartData.config
  222. dataset.value = chartData.dataset
  223. }
  224. function setOptChart2(value: number) {
  225. const chartData = getGaugeData({ value })
  226. config2.value = chartData.config
  227. dataset2.value = chartData.dataset
  228. }
  229. function setOptChart3(value: number) {
  230. const chartData = getGaugeData({ value })
  231. config3.value = chartData.config
  232. dataset3.value = chartData.dataset
  233. }
  234. function setOptChart(myChart: any, myChartData: any, value: number) {
  235. myChartData.name.push(dayjs().format('HH:mm:ss'));
  236. myChartData.value.push(value);
  237. if (myChartData.name.length > 20) {
  238. myChartData.name.shift()
  239. myChartData.value.shift()
  240. }
  241. myChart.setOption({
  242. xAxis: {
  243. data: myChartData.name
  244. },
  245. series: [
  246. {
  247. data: myChartData.value
  248. },
  249. ],
  250. });
  251. }
  252. //cpu运行状态
  253. const initChartCPURun = () => {
  254. myChart4 = echarts.init(proxy.$refs.chartsWarningRef4);
  255. moveOption.series[0].areaStyle = {
  256. opacity: 0.8,
  257. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  258. {
  259. offset: 0,
  260. color: 'rgb(128, 255, 165)'
  261. },
  262. {
  263. offset: 1,
  264. color: 'rgb(1, 191, 236)'
  265. }
  266. ])
  267. }
  268. myChart4.setOption(moveOption);
  269. };
  270. //内存运行状态
  271. const initChartRAMRun = () => {
  272. myChart5 = echarts.init(proxy.$refs.chartsWarningRef5);
  273. moveOption.series[0].areaStyle = {
  274. opacity: 0.8,
  275. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  276. {
  277. offset: 0,
  278. color: 'rgb(0, 221, 255)'
  279. },
  280. {
  281. offset: 1,
  282. color: 'rgb(77, 119, 255)'
  283. }
  284. ])
  285. }
  286. myChart5.setOption(moveOption);
  287. };
  288. //磁盘运行状态
  289. const initChartDISKRun = () => {
  290. myChart6 = echarts.init(proxy.$refs.chartsWarningRef6);
  291. moveOption.series[0].areaStyle = {
  292. opacity: 0.8,
  293. color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
  294. {
  295. offset: 0,
  296. color: 'rgb(55, 162, 255)'
  297. },
  298. {
  299. offset: 1,
  300. color: 'rgb(116, 21, 219)'
  301. }
  302. ])
  303. }
  304. myChart6.setOption(moveOption);
  305. };
  306. // 页面加载时
  307. onMounted(() => {
  308. initChartCPURun();
  309. initChartRAMRun();
  310. initChartDISKRun();
  311. });
  312. function startWs() {
  313. es = new EventSource(getSSEOrigin("/subscribe/sysenv"));
  314. es.addEventListener("host", displayHost);
  315. es.addEventListener("mem", displayMem);
  316. es.addEventListener("cpu", displayCpu);
  317. es.addEventListener("sysLoad", displaySysLoad);
  318. es.addEventListener("disk", displayDisk);
  319. es.addEventListener("go", goInfo);
  320. es.addEventListener("host", hostInfo);
  321. }
  322. startWs();
  323. function displayHost(event: { data: any; }) {
  324. const data = JSON.parse(event.data);
  325. sysInfo.os = data.os
  326. sysInfo.kernelArch = data.kernelArch
  327. sysInfo.sysComputerName = data.hostname
  328. sysInfo.goStartTime = data.bootTime
  329. sysInfo.goRunTime = data.uptime
  330. loading.value = false
  331. }
  332. function displayMem(event: { data: any; }) {
  333. const data = JSON.parse(event.data);
  334. setOptChart2(data.usedPercent.toFixed(2));
  335. sysInfo.memTotal = data.total
  336. sysInfo.memUsed = data.used
  337. sysInfo.available = data.available
  338. sysInfo.goUsed = data.goUsed
  339. sysInfo.memUsage = data.usedPercent.toFixed(2)
  340. setOptChart(myChart5, myChart5Data, sysInfo.memUsage);
  341. loading.value = false
  342. }
  343. function displayCpu(event: { data: any; }) {
  344. const data = JSON.parse(event.data);
  345. // console.log(dayjs().format('HH:mm:ss'))
  346. // console.log(data)
  347. sysInfo.cpuNum = data.Number
  348. sysInfo.cpuCores = data.Cores
  349. sysInfo.cpuUsed = data.UsedPercent[0].toFixed(2)
  350. setOptChart1(data.UsedPercent[0].toFixed(2));
  351. setOptChart(myChart4, myChart4Data, sysInfo.cpuUsed);
  352. loading.value = false
  353. }
  354. function displaySysLoad(event: { data: any; }) {
  355. const data = JSON.parse(event.data)
  356. sysInfo.cpuAvg5 = data.load5.toFixed(2)
  357. sysInfo.cpuAvg15 = data.load15.toFixed(2)
  358. loading.value = false
  359. }
  360. function displayDisk(event: { data: any; }) {
  361. const data = JSON.parse(event.data)
  362. sysInfo.diskTotal = data.total
  363. sysInfo.diskUsed = data.used
  364. sysInfo.diskUsedPercent = data.usedPercent.toFixed(2)
  365. setOptChart3(data.usedPercent.toFixed(2));
  366. setOptChart(myChart6, myChart6Data, sysInfo.diskUsedPercent);
  367. loading.value = false
  368. }
  369. const memorySizeFormat = (size: any) => {
  370. if (size === null || size === undefined) return ''
  371. size = parseFloat(size);
  372. let rank = 0;
  373. let rankchar = 'Bytes';
  374. while (size > 1024 && rankchar != 'TB') {
  375. size = size / 1024;
  376. rank++;
  377. if (rank == 1) {
  378. rankchar = 'KB';
  379. } else if (rank == 2) {
  380. rankchar = 'MB';
  381. } else if (rank == 3) {
  382. rankchar = 'GB';
  383. } else if (rank == 4) {
  384. rankchar = 'TB';
  385. }
  386. }
  387. return size.toFixed(2) + ' ' + rankchar;
  388. }
  389. const timeFormat = (second: any) => {
  390. if (!second) return '-'
  391. second = parseFloat(second);
  392. let rank = 0;
  393. let rankchar = '秒';
  394. while ((second > 60 && rankchar != '小时' && rankchar != '天') || (second > 24 && rankchar == '小时')) {
  395. if (rankchar == '小时') {
  396. second = second / 24;
  397. } else {
  398. second = second / 60;
  399. }
  400. rank++;
  401. if (rank == 1) {
  402. rankchar = '分';
  403. } else if (rank == 2) {
  404. rankchar = '小时';
  405. } else if (rank == 3) {
  406. rankchar = '天';
  407. }
  408. }
  409. return second.toFixed(2) + ' ' + rankchar;
  410. }
  411. onUnmounted(() => {
  412. if (interval) {
  413. clearInterval(interval);
  414. interval = null;
  415. }
  416. if (es) {
  417. es.close()
  418. }
  419. });
  420. </script>
  421. <style scoped lang="scss">
  422. .el-card {
  423. ::v-deep .el-card__body {
  424. height: 100%;
  425. .flex-row {
  426. height: 100%;
  427. }
  428. }
  429. }
  430. .mb-4 {
  431. margin-bottom: 15px;
  432. }
  433. .cell {
  434. box-sizing: border-box;
  435. overflow: hidden;
  436. text-overflow: ellipsis;
  437. white-space: normal;
  438. word-break: break-all;
  439. line-height: 36px;
  440. padding-left: 10px;
  441. padding-right: 10px;
  442. }
  443. .cell-card {
  444. box-sizing: border-box;
  445. overflow: hidden;
  446. text-overflow: ellipsis;
  447. white-space: normal;
  448. word-break: break-all;
  449. line-height: 36px;
  450. }
  451. .box-card {
  452. min-height: 380px;
  453. }
  454. .box-card-meter {
  455. height: auto;
  456. min-height: 180px;
  457. }
  458. </style>