index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <template>
  2. <div>
  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="使用率">{{ 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="使用率">{{ 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. <div class="flex-row" style="gap: 16px; align-items: stretch;margin-bottom: 16px">
  46. <el-card shadow="nover" class="flex1">
  47. <template #header>CPU运行情况</template>
  48. <VueUiXy :dataset="dataset4" :config="config4" />
  49. </el-card>
  50. <el-card shadow="nover" class="flex1">
  51. <template #header>内存运行情况</template>
  52. <VueUiXy :dataset="dataset5" :config="config5" />
  53. </el-card>
  54. <el-card shadow="nover" class="flex1">
  55. <template #header>磁盘使用情况</template>
  56. <VueUiXy :dataset="dataset6" :config="config6" />
  57. </el-card>
  58. </div>
  59. <el-card shadow="nover">
  60. <template #header>运行环境信息</template>
  61. <el-descriptions :column="3" border class="flex1">
  62. <el-descriptions-item label="操作系统">{{ hostData.os }}</el-descriptions-item>
  63. <el-descriptions-item label="系统架构">{{ goInfoData.arch }}</el-descriptions-item>
  64. <el-descriptions-item label="架构版本">{{ hostData.kernelArch }}</el-descriptions-item>
  65. <el-descriptions-item label="启动时间">{{ goInfoData.startTime }}</el-descriptions-item>
  66. <el-descriptions-item label="语言环境">{{ goInfoData.goName }}</el-descriptions-item>
  67. <el-descriptions-item label="GO 版本">{{ goInfoData.goVersion }}</el-descriptions-item>
  68. <el-descriptions-item label="运行时长">{{ timeFormat(goInfoData.runTime) }}</el-descriptions-item>
  69. <el-descriptions-item label="磁盘占用">{{ goInfoData.goSize }}</el-descriptions-item>
  70. <el-descriptions-item label="协程数量">{{ goInfoData.goroutine }}</el-descriptions-item>
  71. <el-descriptions-item label="运行内存">{{ goInfoData.goMem }}</el-descriptions-item>
  72. <el-descriptions-item label="项目地址">{{ goInfoData.pwd }}</el-descriptions-item>
  73. <el-descriptions-item label="服务器IP">{{ hostData.intranet_ip }} (内) &nbsp;&nbsp;&nbsp; {{ hostData.public_ip }} (公) </el-descriptions-item>
  74. </el-descriptions>
  75. </el-card>
  76. </div>
  77. </template>
  78. <script lang="ts" setup>
  79. import { ref, toRefs, reactive, onMounted, getCurrentInstance, defineComponent, onUnmounted } from 'vue';
  80. import * as echarts from 'echarts';
  81. import 'echarts-wordcloud';
  82. import dayjs from 'dayjs';
  83. import { getSSEOrigin } from '/@/utils/origin'
  84. import { VueUiGauge, VueUiXy } from "vue-data-ui";
  85. import "vue-data-ui/style.css";
  86. import { getGaugeData, getLine2Data } from "/@/utils/dataUiOptions";
  87. import { useThemeChange } from '/@/hooks/useCommon';
  88. import { deepClone } from '/@/utils/other';
  89. let interval: any = null;
  90. let es: any = null;
  91. const { proxy } = getCurrentInstance() as any;
  92. const sysInfo: any = reactive<any>({
  93. });
  94. const loading = ref(true)
  95. //#region 线图
  96. // 获取默认图形配置数据
  97. const chartData = getGaugeData({
  98. value: 0
  99. })
  100. const config = ref<any>(chartData.config);
  101. const config2 = ref<any>(chartData.config);
  102. const config3 = ref<any>(chartData.config);
  103. const dataset = ref<any>(chartData.dataset);
  104. const dataset2 = ref<any>(chartData.dataset);
  105. const dataset3 = ref<any>(chartData.dataset);
  106. const chartLineData = getLine2Data({
  107. xAxis: [],
  108. legend: [],
  109. datas: [[]]
  110. })
  111. const dataset4 = ref<any>(chartLineData.dataset);
  112. const config4 = ref<any>(chartLineData.config);
  113. const dataset5 = ref<any>(chartLineData.dataset);
  114. const config5 = ref<any>(chartLineData.config);
  115. const dataset6 = ref<any>(chartLineData.dataset);
  116. const config6 = ref<any>(chartLineData.config);
  117. // 监听暗黑模式变化,将 vue-data-ui 的 config 传进来,就能自动更新主题
  118. useThemeChange([config, config2, config3, config4, config5, config6])
  119. //#endregion
  120. let myChart4: any;
  121. let myChart5: any;
  122. let myChart6: any;
  123. const hostData = reactive({
  124. "bootTime": "2022-11-24T11:12:13+08:00",
  125. "hostId": "8be74718-1a53-4208-be22-9c126d891ddd",
  126. "hostname": "iZ2zee04uvnkmhvglw9oghZ",
  127. "intranet_ip": "172.17.47.62",
  128. "kernelArch": "x86_64",
  129. "kernelVersion": "3.10.0-1127.19.1.el7.x86_64",
  130. "os": "linux",
  131. "platform": "centos",
  132. "platformFamily": "rhel",
  133. "platformVersion": "7.7.1908",
  134. "procs": 138,
  135. "public_ip": "101.200.198.249",
  136. "uptime": 6393278,
  137. "virtualizationRole": "guest",
  138. "virtualizationSystem": ""
  139. });
  140. const goInfoData = reactive({
  141. "goOs": "-", "arch": "-", "goVersion": "-", "goMem": "-", "goName": "-", "goSize": "-", "goroutine": '-', "pwd": "-", "rootPath": "-",
  142. "runTime": '', "startTime": "-", "intranet_ip": "-"
  143. });
  144. function goInfo(event: { data: any; }) {
  145. const data = JSON.parse(event.data);
  146. Object.assign(goInfoData, data);
  147. loading.value = false
  148. }
  149. function hostInfo(event: { data: any; }) {
  150. const data = JSON.parse(event.data);
  151. Object.assign(hostData, data);
  152. loading.value = false
  153. }
  154. const myChart4Data: any = {
  155. name: [],
  156. value: [],
  157. }
  158. const myChart5Data: any = {
  159. name: [],
  160. value: [],
  161. }
  162. const myChart6Data: any = {
  163. name: [],
  164. value: [],
  165. }
  166. function setOptChart(dataset: any, config: any, myChartData: any, value: number, color = '') {
  167. myChartData.name.push(dayjs().format('mm:ss'));
  168. myChartData.value.push(value);
  169. if (myChartData.name.length > 10) {
  170. myChartData.name.shift()
  171. myChartData.value.shift()
  172. }
  173. const chartLineData = getLine2Data({
  174. xAxis: myChartData.name,
  175. legend: ['使用率'],
  176. suffix: '%',
  177. color,
  178. datas: [myChartData.value]
  179. })
  180. dataset.value = chartLineData.dataset
  181. config.value = chartLineData.config
  182. }
  183. // 页面加载时
  184. onMounted(() => {
  185. });
  186. function startWs() {
  187. es = new EventSource(getSSEOrigin("/subscribe/sysenv"));
  188. es.addEventListener("host", displayHost);
  189. es.addEventListener("mem", displayMem);
  190. es.addEventListener("cpu", displayCpu);
  191. es.addEventListener("sysLoad", displaySysLoad);
  192. es.addEventListener("disk", displayDisk);
  193. es.addEventListener("go", goInfo);
  194. es.addEventListener("host", hostInfo);
  195. }
  196. startWs();
  197. function displayHost(event: { data: any; }) {
  198. const data = JSON.parse(event.data);
  199. sysInfo.os = data.os
  200. sysInfo.kernelArch = data.kernelArch
  201. sysInfo.sysComputerName = data.hostname
  202. sysInfo.goStartTime = data.bootTime
  203. sysInfo.goRunTime = data.uptime
  204. loading.value = false
  205. }
  206. function displayMem(event: { data: any; }) {
  207. const data = JSON.parse(event.data);
  208. sysInfo.memTotal = data.total
  209. sysInfo.memUsed = data.used
  210. sysInfo.available = data.available
  211. sysInfo.goUsed = data.goUsed
  212. sysInfo.memUsage = Number(data.usedPercent.toFixed(2))
  213. dataset2.value = getGaugeData({ value: sysInfo.memUsage }).dataset
  214. setOptChart(dataset5, config5, myChart5Data, sysInfo.memUsage, '#56B5FF');
  215. loading.value = false
  216. }
  217. function displayCpu(event: { data: any; }) {
  218. const data = JSON.parse(event.data);
  219. sysInfo.cpuNum = data.Number
  220. sysInfo.cpuCores = data.Cores
  221. sysInfo.cpuUsed = Number(data.UsedPercent[0].toFixed(2))
  222. dataset.value = getGaugeData({ value: sysInfo.cpuUsed }).dataset
  223. setOptChart(dataset4, config4, myChart4Data, sysInfo.cpuUsed, '#4FE4F0');
  224. loading.value = false
  225. }
  226. function displaySysLoad(event: { data: any; }) {
  227. const data = JSON.parse(event.data)
  228. sysInfo.cpuAvg5 = data.load5.toFixed(2)
  229. sysInfo.cpuAvg15 = data.load15.toFixed(2)
  230. loading.value = false
  231. }
  232. function displayDisk(event: { data: any; }) {
  233. const data = JSON.parse(event.data)
  234. sysInfo.diskTotal = data.total
  235. sysInfo.diskUsed = data.used
  236. sysInfo.diskUsedPercent = Number(data.usedPercent.toFixed(2))
  237. dataset3.value = getGaugeData({ value: sysInfo.diskUsedPercent }).dataset
  238. setOptChart(dataset6, config6, myChart6Data, sysInfo.diskUsedPercent, '#7387F4');
  239. loading.value = false
  240. }
  241. const memorySizeFormat = (size: any) => {
  242. if (size === null || size === undefined) return ''
  243. size = parseFloat(size);
  244. let rank = 0;
  245. let rankchar = 'Bytes';
  246. while (size > 1024 && rankchar != 'TB') {
  247. size = size / 1024;
  248. rank++;
  249. if (rank == 1) {
  250. rankchar = 'KB';
  251. } else if (rank == 2) {
  252. rankchar = 'MB';
  253. } else if (rank == 3) {
  254. rankchar = 'GB';
  255. } else if (rank == 4) {
  256. rankchar = 'TB';
  257. }
  258. }
  259. return size.toFixed(2) + ' ' + rankchar;
  260. }
  261. const timeFormat = (second: any) => {
  262. if (!second) return '-'
  263. second = parseFloat(second);
  264. let rank = 0;
  265. let rankchar = '秒';
  266. while ((second > 60 && rankchar != '小时' && rankchar != '天') || (second > 24 && rankchar == '小时')) {
  267. if (rankchar == '小时') {
  268. second = second / 24;
  269. } else {
  270. second = second / 60;
  271. }
  272. rank++;
  273. if (rank == 1) {
  274. rankchar = '分';
  275. } else if (rank == 2) {
  276. rankchar = '小时';
  277. } else if (rank == 3) {
  278. rankchar = '天';
  279. }
  280. }
  281. return second.toFixed(2) + ' ' + rankchar;
  282. }
  283. onUnmounted(() => {
  284. if (interval) {
  285. clearInterval(interval);
  286. interval = null;
  287. }
  288. if (es) {
  289. es.close()
  290. }
  291. });
  292. </script>
  293. <style scoped lang="scss">
  294. .el-card {
  295. ::v-deep .el-card__body {
  296. height: 100%;
  297. .flex-row {
  298. height: 100%;
  299. }
  300. }
  301. }
  302. </style>