|
1 | 1 | <template> |
2 | 2 | <div class="custom-row"> |
3 | 3 | <el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3" align="center"> |
4 | | - <el-popover :hide-after="20" :teleported="false" :width="320" v-if="chartsOption['load']"> |
| 4 | + <el-popover |
| 5 | + :hide-after="20" |
| 6 | + :teleported="false" |
| 7 | + :width="320" |
| 8 | + v-if="chartsOption['load']" |
| 9 | + @hide="onCpuPopoverHide" |
| 10 | + > |
5 | 11 | <el-descriptions :column="1" size="small"> |
6 | 12 | <el-descriptions-item :label="$t('home.loadAverage', [1])"> |
7 | 13 | {{ formatNumber(currentInfo.load1) }} |
|
14 | 20 | </el-descriptions-item> |
15 | 21 | </el-descriptions> |
16 | 22 |
|
17 | | - <el-button link size="small" type="primary" class="float-left mb-2" @click="showTop = !showTop"> |
| 23 | + <el-button link size="small" type="primary" class="float-left mb-2" @click="toggleCpuTop"> |
18 | 24 | {{ $t('home.cpuTop') }} |
19 | | - <el-icon v-if="!showTop"><ArrowRight /></el-icon> |
20 | | - <el-icon v-if="showTop"><ArrowDown /></el-icon> |
| 25 | + <el-icon v-if="!showCpuTop"><ArrowRight /></el-icon> |
| 26 | + <el-icon v-if="showCpuTop"><ArrowDown /></el-icon> |
21 | 27 | </el-button> |
22 | | - <ComplexTable v-if="showTop" :data="currentInfo.topCPUItems"> |
| 28 | + <ComplexTable v-if="showCpuTop" :data="currentInfo.topCPUItems"> |
23 | 29 | <el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" /> |
24 | 30 | <el-table-column :min-width="60" :label="$t('monitor.percent')" prop="percent"> |
25 | 31 | <template #default="{ row }">{{ row.percent.toFixed(2) }}%</template> |
|
45 | 51 | <span class="input-help">{{ loadStatus(currentInfo.loadUsagePercent) }}</span> |
46 | 52 | </el-col> |
47 | 53 | <el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3"> |
48 | | - <el-popover :hide-after="20" :teleported="false" :width="430" v-if="chartsOption['cpu']"> |
| 54 | + <el-popover |
| 55 | + :hide-after="20" |
| 56 | + :teleported="false" |
| 57 | + :width="430" |
| 58 | + v-if="chartsOption['cpu']" |
| 59 | + @hide="onCpuPopoverHide" |
| 60 | + > |
49 | 61 | <el-descriptions :title="baseInfo.cpuModelName" :column="2" size="small"> |
50 | 62 | <el-descriptions-item :label="$t('home.core')"> |
51 | 63 | {{ baseInfo.cpuCores }} |
|
71 | 83 | </div> |
72 | 84 | <br /> |
73 | 85 |
|
74 | | - <el-button link size="small" type="primary" class="mt-1 mb-2" @click="showTop = !showTop"> |
| 86 | + <el-button link size="small" type="primary" class="mt-2 mb-2" @click="toggleCpuTop"> |
75 | 87 | {{ $t('home.cpuTop') }} |
76 | | - <el-icon v-if="!showTop"><ArrowRight /></el-icon> |
77 | | - <el-icon v-if="showTop"><ArrowDown /></el-icon> |
| 88 | + <el-icon v-if="!showCpuTop"><ArrowRight /></el-icon> |
| 89 | + <el-icon v-if="showCpuTop"><ArrowDown /></el-icon> |
78 | 90 | </el-button> |
79 | | - <ComplexTable v-if="showTop" :data="currentInfo.topCPUItems"> |
| 91 | + <ComplexTable v-if="showCpuTop" :data="currentInfo.topCPUItems"> |
80 | 92 | <el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" /> |
81 | 93 | <el-table-column :min-width="60" :label="$t('monitor.percent')" prop="percent"> |
82 | 94 | <template #default="{ row }">{{ row.percent.toFixed(2) }}%</template> |
|
107 | 119 | </div> |
108 | 120 | </el-col> |
109 | 121 | <el-col :xs="6" :sm="6" :md="3" :lg="3" :xl="3" align="center"> |
110 | | - <el-popover :hide-after="20" :teleported="false" :width="480" v-if="chartsOption['memory']"> |
| 122 | + <el-popover |
| 123 | + :hide-after="20" |
| 124 | + :teleported="false" |
| 125 | + :width="480" |
| 126 | + v-if="chartsOption['memory']" |
| 127 | + @hide="onMemPopoverHide" |
| 128 | + > |
111 | 129 | <el-descriptions direction="vertical" :title="$t('home.mem')" class="ml-1" :column="4" size="small"> |
112 | 130 | <el-descriptions-item :label-width="60" :label="$t('home.total')"> |
113 | 131 | {{ computeSize(currentInfo.memoryTotal) }} |
|
154 | 172 | </el-descriptions-item> |
155 | 173 | </el-descriptions> |
156 | 174 |
|
157 | | - <el-button link size="small" type="primary" class="float-left mb-2" @click="showTop = !showTop"> |
| 175 | + <el-button link size="small" type="primary" class="float-left mb-2" @click="toggleMemTop"> |
158 | 176 | {{ $t('home.memTop') }} |
159 | | - <el-icon v-if="!showTop"><ArrowRight /></el-icon> |
160 | | - <el-icon v-if="showTop"><ArrowDown /></el-icon> |
| 177 | + <el-icon v-if="!showMemTop"><ArrowRight /></el-icon> |
| 178 | + <el-icon v-if="showMemTop"><ArrowDown /></el-icon> |
161 | 179 | </el-button> |
162 | | - <ComplexTable v-if="showTop" :data="currentInfo.topMemItems"> |
| 180 | + <ComplexTable v-if="showMemTop" :data="currentInfo.topMemItems"> |
163 | 181 | <el-table-column :min-width="120" show-overflow-tooltip :label="$t('menu.process')" prop="name" /> |
164 | 182 | <el-table-column :min-width="100" :label="$t('monitor.memory')" prop="memory"> |
165 | 183 | <template #default="{ row }"> |
|
334 | 352 | import { Dashboard } from '@/api/interface/dashboard'; |
335 | 353 | import { computeSize } from '@/utils/util'; |
336 | 354 | import i18n from '@/lang'; |
337 | | -import { nextTick, ref } from 'vue'; |
| 355 | +import { nextTick, onBeforeUnmount, ref } from 'vue'; |
338 | 356 | import { routerToFileWithPath, routerToName } from '@/utils/router'; |
339 | 357 | import { stopProcess } from '@/api/modules/process'; |
| 358 | +import { loadTopCPU, loadTopMem } from '@/api/modules/dashboard'; |
340 | 359 | import { MsgSuccess } from '@/utils/message'; |
341 | 360 | const showMore = ref(false); |
342 | 361 | const totalCount = ref(); |
343 | 362 |
|
| 363 | +let cpuPopoverTimer: ReturnType<typeof setTimeout> | null = null; |
| 364 | +let memPopoverTimer: ReturnType<typeof setTimeout> | null = null; |
| 365 | +let cpuLoading = false; |
| 366 | +let memLoading = false; |
| 367 | +
|
344 | 368 | const baseInfo = ref<Dashboard.BaseInfo>({ |
345 | 369 | hostname: '', |
346 | 370 | os: '', |
@@ -405,7 +429,8 @@ const currentInfo = ref<Dashboard.CurrentInfo>({ |
405 | 429 | }); |
406 | 430 |
|
407 | 431 | const cpuShowAll = ref(); |
408 | | -const showTop = ref(); |
| 432 | +const showCpuTop = ref(false); |
| 433 | +const showMemTop = ref(false); |
409 | 434 | const killProcessID = ref(); |
410 | 435 | const confirmConfRef = ref(); |
411 | 436 |
|
@@ -515,6 +540,91 @@ function formatNumber(val: number) { |
515 | 540 | return Number(val.toFixed(2)); |
516 | 541 | } |
517 | 542 |
|
| 543 | +const toggleCpuTop = async () => { |
| 544 | + showCpuTop.value = !showCpuTop.value; |
| 545 | + if (showCpuTop.value) { |
| 546 | + await loadTopCPUData(); |
| 547 | + if (cpuPopoverTimer) { |
| 548 | + clearInterval(Number(cpuPopoverTimer)); |
| 549 | + } |
| 550 | + cpuPopoverTimer = setInterval(loadTopCPUData, 5000); |
| 551 | + } else { |
| 552 | + if (cpuPopoverTimer) { |
| 553 | + clearInterval(Number(cpuPopoverTimer)); |
| 554 | + cpuPopoverTimer = null; |
| 555 | + } |
| 556 | + } |
| 557 | +}; |
| 558 | +
|
| 559 | +const onCpuPopoverHide = () => { |
| 560 | + showCpuTop.value = false; |
| 561 | + if (cpuPopoverTimer) { |
| 562 | + clearInterval(Number(cpuPopoverTimer)); |
| 563 | + cpuPopoverTimer = null; |
| 564 | + } |
| 565 | +}; |
| 566 | +
|
| 567 | +const toggleMemTop = async () => { |
| 568 | + showMemTop.value = !showMemTop.value; |
| 569 | + if (showMemTop.value) { |
| 570 | + await loadTopMemData(); |
| 571 | + if (memPopoverTimer) { |
| 572 | + clearInterval(Number(memPopoverTimer)); |
| 573 | + } |
| 574 | + memPopoverTimer = setInterval(loadTopMemData, 5000); |
| 575 | + } else { |
| 576 | + if (memPopoverTimer) { |
| 577 | + clearInterval(Number(memPopoverTimer)); |
| 578 | + memPopoverTimer = null; |
| 579 | + } |
| 580 | + } |
| 581 | +}; |
| 582 | +
|
| 583 | +const onMemPopoverHide = () => { |
| 584 | + showMemTop.value = false; |
| 585 | + if (memPopoverTimer) { |
| 586 | + clearInterval(Number(memPopoverTimer)); |
| 587 | + memPopoverTimer = null; |
| 588 | + } |
| 589 | +}; |
| 590 | +
|
| 591 | +const loadTopCPUData = async () => { |
| 592 | + if (cpuLoading) return; |
| 593 | + cpuLoading = true; |
| 594 | + try { |
| 595 | + const res = await loadTopCPU(); |
| 596 | + currentInfo.value.topCPUItems = res.data || []; |
| 597 | + } catch (_error) { |
| 598 | + // ignore load errors |
| 599 | + } finally { |
| 600 | + cpuLoading = false; |
| 601 | + } |
| 602 | +}; |
| 603 | +
|
| 604 | +const loadTopMemData = async () => { |
| 605 | + if (memLoading) return; |
| 606 | + memLoading = true; |
| 607 | + try { |
| 608 | + const res = await loadTopMem(); |
| 609 | + currentInfo.value.topMemItems = res.data || []; |
| 610 | + } catch (_error) { |
| 611 | + // ignore load errors |
| 612 | + } finally { |
| 613 | + memLoading = false; |
| 614 | + } |
| 615 | +}; |
| 616 | +
|
| 617 | +onBeforeUnmount(() => { |
| 618 | + if (cpuPopoverTimer) { |
| 619 | + clearInterval(Number(cpuPopoverTimer)); |
| 620 | + cpuPopoverTimer = null; |
| 621 | + } |
| 622 | + if (memPopoverTimer) { |
| 623 | + clearInterval(Number(memPopoverTimer)); |
| 624 | + memPopoverTimer = null; |
| 625 | + } |
| 626 | +}); |
| 627 | +
|
518 | 628 | defineExpose({ |
519 | 629 | acceptParams, |
520 | 630 | }); |
|
0 commit comments