Restore control center copy

This commit is contained in:
2026-06-10 12:17:52 +08:00
parent 8cbace7585
commit b090ecd5f4
@@ -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;