mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-18 13:29:03 +08:00
feat: Add panel carousel on the overview page (#10394)
This commit is contained in:
parent
c408619042
commit
1883b05f26
3 changed files with 208 additions and 70 deletions
|
|
@ -241,6 +241,18 @@ export namespace Setting {
|
||||||
isBound: boolean;
|
isBound: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
export interface SimpleNodeItem {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
addr: string;
|
||||||
|
description: string;
|
||||||
|
systemVersion: string;
|
||||||
|
securityEntrance: string;
|
||||||
|
cpuUsedPercent: number;
|
||||||
|
cpuTotal: number;
|
||||||
|
memoryTotal: number;
|
||||||
|
memoryUsedPercent: number;
|
||||||
|
}
|
||||||
export interface ReleasesNotes {
|
export interface ReleasesNotes {
|
||||||
Version: string;
|
Version: string;
|
||||||
CreatedAt: string;
|
CreatedAt: string;
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ export const listNodeOptions = (type: string) => {
|
||||||
export const listAllNodes = () => {
|
export const listAllNodes = () => {
|
||||||
return http.get<Array<Setting.NodeItem>>(`/core/nodes/all`);
|
return http.get<Array<Setting.NodeItem>>(`/core/nodes/all`);
|
||||||
};
|
};
|
||||||
|
export const listAllSimpleNodes = () => {
|
||||||
|
return http.get<Array<Setting.SimpleNodeItem>>(`/core/nodes/simple/all`);
|
||||||
|
};
|
||||||
|
|
||||||
export const getLicenseSmsInfo = () => {
|
export const getLicenseSmsInfo = () => {
|
||||||
return http.get<Setting.SmsInfo>(`/core/licenses/sms/info`);
|
return http.get<Setting.SmsInfo>(`/core/licenses/sms/info`);
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@
|
||||||
</CardWithHeader>
|
</CardWithHeader>
|
||||||
<CardWithHeader :header="$t('commons.table.status')" class="card-interval">
|
<CardWithHeader :header="$t('commons.table.status')" class="card-interval">
|
||||||
<template #body>
|
<template #body>
|
||||||
<Status ref="statusRef" style="margin-bottom: 33px" />
|
<SystemStatus ref="statusRef" style="margin-bottom: 33px" />
|
||||||
</template>
|
</template>
|
||||||
</CardWithHeader>
|
</CardWithHeader>
|
||||||
<CardWithHeader
|
<CardWithHeader
|
||||||
|
|
@ -163,73 +163,137 @@
|
||||||
</CardWithHeader>
|
</CardWithHeader>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
|
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="8">
|
||||||
<CardWithHeader :header="$t('home.systemInfo')">
|
<el-carousel
|
||||||
<template #header-r>
|
:key="simpleNodes.length"
|
||||||
<el-button class="h-button-setting" @click="handleCopy" link icon="CopyDocument" />
|
indicator-position="none"
|
||||||
</template>
|
height="346px"
|
||||||
<template #body>
|
:arrow="showSimpleNode() ? 'hover' : 'never'"
|
||||||
<el-scrollbar>
|
>
|
||||||
<el-descriptions :column="1" class="h-systemInfo" border>
|
<el-carousel-item key="systemInfo">
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
<CardWithHeader :header="$t('home.systemInfo')">
|
||||||
<template #label>
|
<template #header-r>
|
||||||
<span class="system-label">{{ $t('home.hostname') }}</span>
|
<el-button class="h-button-setting" @click="handleCopy" link icon="CopyDocument" />
|
||||||
</template>
|
</template>
|
||||||
{{ baseInfo.hostname }}
|
<template #body>
|
||||||
</el-descriptions-item>
|
<el-scrollbar>
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
<el-descriptions :column="1" class="ml-5" border>
|
||||||
<template #label>
|
<el-descriptions-item
|
||||||
<span class="system-label">{{ $t('home.platformVersion') }}</span>
|
class-name="system-content"
|
||||||
</template>
|
label-class-name="system-label"
|
||||||
{{
|
>
|
||||||
baseInfo.platformVersion
|
<template #label>
|
||||||
? baseInfo.platform + '-' + baseInfo.platformVersion
|
<span class="system-label">{{ $t('home.hostname') }}</span>
|
||||||
: baseInfo.platform
|
</template>
|
||||||
}}
|
{{ baseInfo.hostname }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
<el-descriptions-item
|
||||||
<template #label>
|
class-name="system-content"
|
||||||
<span class="system-label">{{ $t('home.kernelVersion') }}</span>
|
label-class-name="system-label"
|
||||||
</template>
|
>
|
||||||
{{ baseInfo.kernelVersion }}
|
<template #label>
|
||||||
</el-descriptions-item>
|
<span class="system-label">{{ $t('home.platformVersion') }}</span>
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
</template>
|
||||||
<template #label>
|
{{
|
||||||
<span class="system-label">{{ $t('home.kernelArch') }}</span>
|
baseInfo.platformVersion
|
||||||
</template>
|
? baseInfo.platform + '-' + baseInfo.platformVersion
|
||||||
{{ baseInfo.kernelArch }}
|
: baseInfo.platform
|
||||||
</el-descriptions-item>
|
}}
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
</el-descriptions-item>
|
||||||
<template #label>
|
<el-descriptions-item
|
||||||
<span class="system-label">{{ $t('home.ip') }}</span>
|
class-name="system-content"
|
||||||
</template>
|
label-class-name="system-label"
|
||||||
{{ baseInfo.ipV4Addr }}
|
>
|
||||||
</el-descriptions-item>
|
<template #label>
|
||||||
<el-descriptions-item
|
<span class="system-label">{{ $t('home.kernelVersion') }}</span>
|
||||||
v-if="baseInfo.httpProxy && baseInfo.httpProxy !== 'noProxy'"
|
</template>
|
||||||
class-name="system-content"
|
{{ baseInfo.kernelVersion }}
|
||||||
label-class-name="system-label"
|
</el-descriptions-item>
|
||||||
>
|
<el-descriptions-item
|
||||||
<template #label>
|
class-name="system-content"
|
||||||
<span class="system-label">{{ $t('home.proxy') }}</span>
|
label-class-name="system-label"
|
||||||
{{ baseInfo.httpProxy }}
|
>
|
||||||
</template>
|
<template #label>
|
||||||
</el-descriptions-item>
|
<span class="system-label">{{ $t('home.kernelArch') }}</span>
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
</template>
|
||||||
<template #label>
|
{{ baseInfo.kernelArch }}
|
||||||
<span class="system-label">{{ $t('home.uptime') }}</span>
|
</el-descriptions-item>
|
||||||
</template>
|
<el-descriptions-item
|
||||||
{{ currentInfo.timeSinceUptime }}
|
class-name="system-content"
|
||||||
</el-descriptions-item>
|
label-class-name="system-label"
|
||||||
<el-descriptions-item class-name="system-content" label-class-name="system-label">
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span class="system-label">{{ $t('home.runningTime') }}</span>
|
<span class="system-label">{{ $t('home.ip') }}</span>
|
||||||
</template>
|
</template>
|
||||||
{{ loadUpTime(currentInfo.uptime) }}
|
{{ baseInfo.ipV4Addr }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
<el-descriptions-item
|
||||||
</el-scrollbar>
|
v-if="baseInfo.httpProxy && baseInfo.httpProxy !== 'noProxy'"
|
||||||
</template>
|
class-name="system-content"
|
||||||
</CardWithHeader>
|
label-class-name="system-label"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span class="system-label">{{ $t('home.proxy') }}</span>
|
||||||
|
{{ baseInfo.httpProxy }}
|
||||||
|
</template>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item
|
||||||
|
class-name="system-content"
|
||||||
|
label-class-name="system-label"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span class="system-label">{{ $t('home.uptime') }}</span>
|
||||||
|
</template>
|
||||||
|
{{ currentInfo.timeSinceUptime }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item
|
||||||
|
class-name="system-content"
|
||||||
|
label-class-name="system-label"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span class="system-label">{{ $t('home.runningTime') }}</span>
|
||||||
|
</template>
|
||||||
|
{{ loadUpTime(currentInfo.uptime) }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-scrollbar>
|
||||||
|
</template>
|
||||||
|
</CardWithHeader>
|
||||||
|
</el-carousel-item>
|
||||||
|
<el-carousel-item key="simpleNode" v-if="showSimpleNode()">
|
||||||
|
<CardWithHeader :header="$t('setting.panel')">
|
||||||
|
<template #body>
|
||||||
|
<el-scrollbar height="266px">
|
||||||
|
<div class="simple-node cursor-pointer" v-for="row in simpleNodes" :key="row.id">
|
||||||
|
<el-row :gutter="5">
|
||||||
|
<el-col :span="21">
|
||||||
|
<div class="name">
|
||||||
|
{{ row.name }}
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
{{ loadSource(row) }}
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="1">
|
||||||
|
<el-button
|
||||||
|
@click="jumpPanel(row)"
|
||||||
|
size="small"
|
||||||
|
class="visit"
|
||||||
|
round
|
||||||
|
plain
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
{{ $t('commons.button.visit') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="h-app-divider" />
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</template>
|
||||||
|
</CardWithHeader>
|
||||||
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
|
||||||
<AppLauncher ref="appRef" class="card-interval" />
|
<AppLauncher ref="appRef" class="card-interval" />
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
@ -242,7 +306,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onBeforeUnmount, ref, reactive } from 'vue';
|
import { onMounted, onBeforeUnmount, ref, reactive } from 'vue';
|
||||||
import Status from '@/views/home/status/index.vue';
|
import SystemStatus from '@/views/home/status/index.vue';
|
||||||
import AppLauncher from '@/views/home/app/index.vue';
|
import AppLauncher from '@/views/home/app/index.vue';
|
||||||
import VCharts from '@/components/v-charts/index.vue';
|
import VCharts from '@/components/v-charts/index.vue';
|
||||||
import LicenseImport from '@/components/license-import/index.vue';
|
import LicenseImport from '@/components/license-import/index.vue';
|
||||||
|
|
@ -254,7 +318,7 @@ import { dateFormatForSecond, computeSize, computeSizeFromKBs, loadUpTime, jumpT
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
|
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
|
||||||
import { getIOOptions, getNetworkOptions } from '@/api/modules/host';
|
import { getIOOptions, getNetworkOptions } from '@/api/modules/host';
|
||||||
import { getSettingInfo, loadUpgradeInfo } from '@/api/modules/setting';
|
import { getSettingInfo, listAllSimpleNodes, loadUpgradeInfo } from '@/api/modules/setting';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { routerToFileWithPath, routerToPath } from '@/utils/router';
|
import { routerToFileWithPath, routerToPath } from '@/utils/router';
|
||||||
|
|
@ -280,6 +344,7 @@ const netBytesRecvs = ref<Array<number>>([]);
|
||||||
const timeIODatas = ref<Array<string>>([]);
|
const timeIODatas = ref<Array<string>>([]);
|
||||||
const timeNetDatas = ref<Array<string>>([]);
|
const timeNetDatas = ref<Array<string>>([]);
|
||||||
|
|
||||||
|
const simpleNodes = ref([]);
|
||||||
const ioOptions = ref();
|
const ioOptions = ref();
|
||||||
const netOptions = ref();
|
const netOptions = ref();
|
||||||
|
|
||||||
|
|
@ -376,6 +441,11 @@ const onLoadNetworkOptions = async () => {
|
||||||
searchInfo.netOption = globalStore.defaultNetwork || (netOptions.value && netOptions.value[0]);
|
searchInfo.netOption = globalStore.defaultNetwork || (netOptions.value && netOptions.value[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onLoadSimpleNode = async () => {
|
||||||
|
const res = await listAllSimpleNodes();
|
||||||
|
simpleNodes.value = res.data || [];
|
||||||
|
};
|
||||||
|
|
||||||
const onLoadIOOptions = async () => {
|
const onLoadIOOptions = async () => {
|
||||||
const res = await getIOOptions();
|
const res = await getIOOptions();
|
||||||
ioOptions.value = res.data;
|
ioOptions.value = res.data;
|
||||||
|
|
@ -407,6 +477,7 @@ const onLoadBaseInfo = async (isInit: boolean, range: string) => {
|
||||||
}
|
}
|
||||||
if (isActive.value && !globalStore.isOnRestart) {
|
if (isActive.value && !globalStore.isOnRestart) {
|
||||||
await onLoadCurrentInfo();
|
await onLoadCurrentInfo();
|
||||||
|
await onLoadSimpleNode();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
clearInterval(Number(timer));
|
clearInterval(Number(timer));
|
||||||
|
|
@ -423,6 +494,14 @@ const quickJump = (item: any) => {
|
||||||
return routerToPath(item.router);
|
return routerToPath(item.router);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showSimpleNode = () => {
|
||||||
|
return globalStore.isMasterProductPro && simpleNodes.value?.length !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const jumpPanel = (row: any) => {
|
||||||
|
window.open(row.addr, '_blank', 'noopener,noreferrer');
|
||||||
|
};
|
||||||
|
|
||||||
const onLoadCurrentInfo = async () => {
|
const onLoadCurrentInfo = async () => {
|
||||||
const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption);
|
const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption);
|
||||||
currentInfo.value.timeSinceUptime = res.data.timeSinceUptime;
|
currentInfo.value.timeSinceUptime = res.data.timeSinceUptime;
|
||||||
|
|
@ -569,6 +648,24 @@ const loadSafeStatus = async () => {
|
||||||
isSafety.value = res.data.securityEntrance;
|
isSafety.value = res.data.securityEntrance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const loadSource = (row: any) => {
|
||||||
|
if (row.status !== 'Healthy') {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
row.cpuTotal +
|
||||||
|
' ' +
|
||||||
|
i18n.global.t('commons.units.core') +
|
||||||
|
' (' +
|
||||||
|
row.cpuUsedPercent?.toFixed(2) +
|
||||||
|
'%) / ' +
|
||||||
|
computeSize(row.memoryTotal) +
|
||||||
|
' (' +
|
||||||
|
row.memoryUsedPercent?.toFixed(2) +
|
||||||
|
'%)'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const onFocus = () => {
|
const onFocus = () => {
|
||||||
isActive.value = true;
|
isActive.value = true;
|
||||||
};
|
};
|
||||||
|
|
@ -588,6 +685,7 @@ const fetchData = () => {
|
||||||
onLoadNetworkOptions();
|
onLoadNetworkOptions();
|
||||||
onLoadIOOptions();
|
onLoadIOOptions();
|
||||||
onLoadBaseInfo(true, 'all');
|
onLoadBaseInfo(true, 'all');
|
||||||
|
onLoadSimpleNode();
|
||||||
};
|
};
|
||||||
|
|
||||||
onBeforeRouteUpdate((to, from, next) => {
|
onBeforeRouteUpdate((to, from, next) => {
|
||||||
|
|
@ -663,6 +761,31 @@ onBeforeUnmount(() => {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.simple-node {
|
||||||
|
padding: 10px 15px 10px 0px;
|
||||||
|
margin: 3px 10px 3px 20px;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 94, 235, 0.03);
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-weight: 500 !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
color: var(--panel-text-color);
|
||||||
|
}
|
||||||
|
.detail {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
.visit {
|
||||||
|
margin-bottom: -25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-app-divider {
|
||||||
|
margin-top: 3px;
|
||||||
|
border: 0;
|
||||||
|
border-top: var(--panel-border);
|
||||||
|
}
|
||||||
|
|
||||||
.monitor-tags {
|
.monitor-tags {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue