Restore control center copy
This commit is contained in:
@@ -8,7 +8,7 @@ import type {
|
|||||||
import type { UserAnnouncement } from '#/api/core/announcement';
|
import type { UserAnnouncement } from '#/api/core/announcement';
|
||||||
import type { Message } from '#/api/core/message';
|
import type { Message } from '#/api/core/message';
|
||||||
|
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { Page } from '@vben/common-ui';
|
import { Page } from '@vben/common-ui';
|
||||||
@@ -39,13 +39,7 @@ import {
|
|||||||
} from '@vben/icons';
|
} from '@vben/icons';
|
||||||
import { useUserStore } from '@vben/stores';
|
import { useUserStore } from '@vben/stores';
|
||||||
|
|
||||||
import {
|
import { ElButton, ElEmpty, ElProgress, ElSkeleton, ElTag } from 'element-plus';
|
||||||
ElButton,
|
|
||||||
ElEmpty,
|
|
||||||
ElProgress,
|
|
||||||
ElSkeleton,
|
|
||||||
ElTag,
|
|
||||||
} from 'element-plus';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getAgentListApi,
|
getAgentListApi,
|
||||||
@@ -73,6 +67,7 @@ const userStore = useUserStore();
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const loaded = ref(false);
|
const loaded = ref(false);
|
||||||
const now = ref(new Date());
|
const now = ref(new Date());
|
||||||
|
const timer = ref<number>();
|
||||||
const agents = ref<AgentListItem[]>([]);
|
const agents = ref<AgentListItem[]>([]);
|
||||||
const workflows = ref<WorkflowListItem[]>([]);
|
const workflows = ref<WorkflowListItem[]>([]);
|
||||||
const knowledgeBases = ref<KnowledgeBaseListItem[]>([]);
|
const knowledgeBases = ref<KnowledgeBaseListItem[]>([]);
|
||||||
@@ -99,26 +94,26 @@ const displayName = computed(() => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const hour = computed(() => now.value.getHours());
|
|
||||||
const greeting = computed(() => {
|
const greeting = computed(() => {
|
||||||
if (hour.value < 6) return '凌晨好';
|
const hour = now.value.getHours();
|
||||||
if (hour.value < 12) return '上午好';
|
if (hour < 6) return '凌晨好';
|
||||||
if (hour.value < 18) return '下午好';
|
if (hour < 12) return '上午好';
|
||||||
|
if (hour < 18) return '下午好';
|
||||||
return '晚上好';
|
return '晚上好';
|
||||||
});
|
});
|
||||||
|
|
||||||
const currentTime = computed(() => {
|
const currentTime = computed(() =>
|
||||||
return now.value.toLocaleTimeString('zh-CN', { hour12: false });
|
now.value.toLocaleTimeString('zh-CN', { hour12: false }),
|
||||||
});
|
);
|
||||||
|
|
||||||
const currentDate = computed(() => {
|
const currentDate = computed(() =>
|
||||||
return now.value.toLocaleDateString('zh-CN', {
|
now.value.toLocaleDateString('zh-CN', {
|
||||||
day: 'numeric',
|
day: 'numeric',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
});
|
}),
|
||||||
});
|
);
|
||||||
|
|
||||||
const publishedAgents = computed(
|
const publishedAgents = computed(
|
||||||
() => agents.value.filter((item) => item.status === 'published').length,
|
() => agents.value.filter((item) => item.status === 'published').length,
|
||||||
@@ -151,7 +146,6 @@ const successRate = computed(() => {
|
|||||||
const collaborationItems = computed(() => [
|
const collaborationItems = computed(() => [
|
||||||
{
|
{
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
desc: '发起需求分诊、任务拆解和角色协作',
|
|
||||||
icon: Send,
|
icon: Send,
|
||||||
path: '/ai-platform/agent',
|
path: '/ai-platform/agent',
|
||||||
title: '我发起的',
|
title: '我发起的',
|
||||||
@@ -159,7 +153,6 @@ const collaborationItems = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
color: 'amber',
|
color: 'amber',
|
||||||
desc: '待人工确认、待补充上下文的节点',
|
|
||||||
icon: ClipboardList,
|
icon: ClipboardList,
|
||||||
path: '/ai-platform/workflow-runs',
|
path: '/ai-platform/workflow-runs',
|
||||||
title: '我的待办',
|
title: '我的待办',
|
||||||
@@ -167,7 +160,6 @@ const collaborationItems = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
color: 'violet',
|
color: 'violet',
|
||||||
desc: '正在运行或最近完成的协作流程',
|
|
||||||
icon: Workflow,
|
icon: Workflow,
|
||||||
path: '/ai-platform/workflow-runs',
|
path: '/ai-platform/workflow-runs',
|
||||||
title: '我的在办',
|
title: '我的在办',
|
||||||
@@ -175,7 +167,6 @@ const collaborationItems = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
color: 'cyan',
|
color: 'cyan',
|
||||||
desc: '已沉淀为可复用的智能体能力',
|
|
||||||
icon: CheckCircle2,
|
icon: CheckCircle2,
|
||||||
path: '/ai-platform/agent',
|
path: '/ai-platform/agent',
|
||||||
title: '我的已办',
|
title: '我的已办',
|
||||||
@@ -183,7 +174,6 @@ const collaborationItems = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
color: 'orange',
|
color: 'orange',
|
||||||
desc: '消息、公告和流程通知',
|
|
||||||
icon: Bell,
|
icon: Bell,
|
||||||
path: '/message/announcement-list',
|
path: '/message/announcement-list',
|
||||||
title: '抄送我的',
|
title: '抄送我的',
|
||||||
@@ -191,7 +181,6 @@ const collaborationItems = computed(() => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
color: 'green',
|
color: 'green',
|
||||||
desc: '进入编排器创建多 Agent 流程',
|
|
||||||
icon: Play,
|
icon: Play,
|
||||||
path: '/ai-platform/workflow',
|
path: '/ai-platform/workflow',
|
||||||
title: '发起流程',
|
title: '发起流程',
|
||||||
@@ -271,28 +260,24 @@ const quickLinks = [
|
|||||||
|
|
||||||
const resourceCards = computed(() => [
|
const resourceCards = computed(() => [
|
||||||
{
|
{
|
||||||
desc: `${publishedAgents.value} 个已发布,可参与协作`,
|
|
||||||
icon: Bot,
|
icon: Bot,
|
||||||
label: '智能体',
|
label: '智能体',
|
||||||
tone: 'blue',
|
tone: 'blue',
|
||||||
value: stats.agentTotal,
|
value: stats.agentTotal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: `${publishedWorkflows.value} 条已发布,可直接运行`,
|
|
||||||
icon: Workflow,
|
icon: Workflow,
|
||||||
label: '流程',
|
label: '流程',
|
||||||
tone: 'cyan',
|
tone: 'cyan',
|
||||||
value: stats.workflowTotal,
|
value: stats.workflowTotal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: `${knowledgeBases.value.length} 个最近维护`,
|
|
||||||
icon: BookOpen,
|
icon: BookOpen,
|
||||||
label: '知识库',
|
label: '知识库',
|
||||||
tone: 'amber',
|
tone: 'amber',
|
||||||
value: stats.knowledgeTotal,
|
value: stats.knowledgeTotal,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: `成功 ${completedRuns.value} / 失败 ${failedRuns.value}`,
|
|
||||||
icon: Play,
|
icon: Play,
|
||||||
label: '执行记录',
|
label: '执行记录',
|
||||||
tone: 'green',
|
tone: 'green',
|
||||||
@@ -304,6 +289,7 @@ const serverCards = computed(() => {
|
|||||||
const overview = serverOverview.value;
|
const overview = serverOverview.value;
|
||||||
const realtime = realtimeStats.value;
|
const realtime = realtimeStats.value;
|
||||||
const memory = realtime?.memory_details || overview?.memory_info.virtual;
|
const memory = realtime?.memory_details || overview?.memory_info.virtual;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
desc: `${overview?.cpu_info.total_cores || '-'} 核心`,
|
desc: `${overview?.cpu_info.total_cores || '-'} 核心`,
|
||||||
@@ -323,9 +309,9 @@ const serverCards = computed(() => {
|
|||||||
value: `${Math.round(realtime?.memory_percent ?? overview?.memory_info.virtual.percent ?? 0)}%`,
|
value: `${Math.round(realtime?.memory_percent ?? overview?.memory_info.virtual.percent ?? 0)}%`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: `累计 ${formatBytes(overview?.disk_info.total_read_bytes)} / ${formatBytes(overview?.disk_info.total_write_bytes)}`,
|
desc: `累计读写 ${formatBytes(overview?.disk_info.total_read_bytes)} / ${formatBytes(overview?.disk_info.total_write_bytes)}`,
|
||||||
icon: Server,
|
icon: Server,
|
||||||
label: '磁盘读/写',
|
label: '磁盘读取',
|
||||||
tone: 'amber',
|
tone: 'amber',
|
||||||
value: `${formatBytes(realtime?.disk_io.read_speed)}/s`,
|
value: `${formatBytes(realtime?.disk_io.read_speed)}/s`,
|
||||||
},
|
},
|
||||||
@@ -370,6 +356,7 @@ function getStatusType(status: string) {
|
|||||||
async function loadDashboard() {
|
async function loadDashboard() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
now.value = new Date();
|
now.value = new Date();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [
|
const [
|
||||||
agentRes,
|
agentRes,
|
||||||
@@ -418,10 +405,14 @@ async function loadDashboard() {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadDashboard();
|
loadDashboard();
|
||||||
window.setInterval(() => {
|
timer.value = window.setInterval(() => {
|
||||||
now.value = new Date();
|
now.value = new Date();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (timer.value) window.clearInterval(timer.value);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -429,10 +420,10 @@ onMounted(() => {
|
|||||||
<div class="workbench">
|
<div class="workbench">
|
||||||
<section class="top-grid">
|
<section class="top-grid">
|
||||||
<div class="welcome-card panel">
|
<div class="welcome-card panel">
|
||||||
<div class="avatar-badge">超</div>
|
<div class="avatar-badge">AI</div>
|
||||||
<div class="welcome-copy">
|
<div class="welcome-copy">
|
||||||
<h2>{{ greeting }},{{ displayName }},欢迎回来</h2>
|
<h2>{{ greeting }},{{ displayName }},欢迎回来</h2>
|
||||||
<p>今天是个好日子,适合让智能体把重复工作接过去。</p>
|
<p>这里汇总智能体、流程编排、公告消息和服务器状态,方便快速进入协作工作。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="time-box">
|
<div class="time-box">
|
||||||
<strong>{{ currentTime }}</strong>
|
<strong>{{ currentTime }}</strong>
|
||||||
@@ -440,14 +431,14 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="weather-card panel">
|
<div class="status-card panel">
|
||||||
<div class="panel-title">
|
<div class="panel-title compact">
|
||||||
<CloudSun :size="17" />
|
<CloudSun :size="17" />
|
||||||
<span>今日状态</span>
|
<span>今日状态</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="weather-body">
|
<div class="status-body">
|
||||||
<strong>{{ successRate }}%</strong>
|
<strong>{{ successRate }}%</strong>
|
||||||
<span>近 6 次流程完成率</span>
|
<span>最近流程完成率</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -540,7 +531,7 @@ onMounted(() => {
|
|||||||
<span>{{ formatTime(item.created_at) }} · {{ item.msg_type }}</span>
|
<span>{{ formatTime(item.created_at) }} · {{ item.msg_type }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ElEmpty v-else description="暂无数据" />
|
<ElEmpty v-else description="暂无消息" />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -551,7 +542,7 @@ onMounted(() => {
|
|||||||
<small>
|
<small>
|
||||||
{{
|
{{
|
||||||
serverOverview
|
serverOverview
|
||||||
? `${serverOverview.basic_info.hostname} (${serverOverview.basic_info.ip_address}) · 运行时间 ${serverOverview.boot_time.uptime_formatted}`
|
? `${serverOverview.basic_info.hostname} (${serverOverview.basic_info.ip_address}) · 运行 ${serverOverview.boot_time.uptime_formatted}`
|
||||||
: '等待服务器采集数据'
|
: '等待服务器采集数据'
|
||||||
}}
|
}}
|
||||||
</small>
|
</small>
|
||||||
@@ -577,7 +568,11 @@ onMounted(() => {
|
|||||||
<div class="panel-title">
|
<div class="panel-title">
|
||||||
<GitBranch :size="17" />
|
<GitBranch :size="17" />
|
||||||
<span>最近执行</span>
|
<span>最近执行</span>
|
||||||
<ElButton link type="primary" @click="go('/ai-platform/workflow-runs')">
|
<ElButton
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="go('/ai-platform/workflow-runs')"
|
||||||
|
>
|
||||||
执行历史
|
执行历史
|
||||||
</ElButton>
|
</ElButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -667,7 +662,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="token-row">
|
<div class="token-row">
|
||||||
<Calendar :size="17" />
|
<Calendar :size="17" />
|
||||||
<span>近 6 次执行消耗 {{ tokenTotal }} tokens</span>
|
<span>最近执行消耗 {{ tokenTotal }} tokens</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -716,7 +711,7 @@ onMounted(() => {
|
|||||||
color: rgb(248 250 252);
|
color: rgb(248 250 252);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-size: 20px;
|
font-size: 18px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -762,20 +757,20 @@ onMounted(() => {
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-card {
|
.status-card {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
min-height: 122px;
|
min-height: 122px;
|
||||||
padding: 18px;
|
padding: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-body {
|
.status-body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
justify-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.weather-body strong {
|
.status-body strong {
|
||||||
color: hsl(var(--primary));
|
color: hsl(var(--primary));
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@@ -800,6 +795,10 @@ onMounted(() => {
|
|||||||
padding: 14px 16px 8px;
|
padding: 14px 16px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-title.compact {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-title > span {
|
.panel-title > span {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-weight: 650;
|
font-weight: 650;
|
||||||
|
|||||||
Reference in New Issue
Block a user