feat: replace dashboard renderer home
This commit is contained in:
@@ -16,14 +16,13 @@ import { useAccessStore } from '@vben/stores';
|
|||||||
|
|
||||||
import { useAuthStore } from '#/store';
|
import { useAuthStore } from '#/store';
|
||||||
|
|
||||||
import { refreshTokenApi } from './core';
|
import { refreshTokenApi } from './core/auth';
|
||||||
|
|
||||||
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);
|
||||||
|
|
||||||
async function showMessage(type: 'error' | 'warning', message: string) {
|
async function showMessage(type: 'error' | 'warning', message: string) {
|
||||||
const { ElMessage } = await import(
|
const { ElMessage } =
|
||||||
'element-plus/es/components/message/index'
|
await import('element-plus/es/components/message/index');
|
||||||
);
|
|
||||||
ElMessage[type](message);
|
ElMessage[type](message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,10 @@ const baseModules = import.meta.glob([
|
|||||||
const businessModules = import.meta.glob([
|
const businessModules = import.meta.glob([
|
||||||
'./langs/zh-CN/ai-platform.json',
|
'./langs/zh-CN/ai-platform.json',
|
||||||
'./langs/zh-CN/announcement.json',
|
'./langs/zh-CN/announcement.json',
|
||||||
'./langs/zh-CN/dashboard-design.json',
|
|
||||||
'./langs/zh-CN/menu.json',
|
'./langs/zh-CN/menu.json',
|
||||||
'./langs/zh-CN/message.json',
|
'./langs/zh-CN/message.json',
|
||||||
'./langs/zh-CN/permission.json',
|
'./langs/zh-CN/permission.json',
|
||||||
'./langs/zh-CN/role.json',
|
'./langs/zh-CN/role.json',
|
||||||
'./langs/zh-CN/system-config.json',
|
|
||||||
'./langs/zh-CN/system.json',
|
'./langs/zh-CN/system.json',
|
||||||
'./langs/zh-CN/user.json',
|
'./langs/zh-CN/user.json',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -0,0 +1,859 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type {
|
||||||
|
AgentListItem,
|
||||||
|
KnowledgeBaseListItem,
|
||||||
|
WorkflowListItem,
|
||||||
|
WorkflowRunListItem,
|
||||||
|
} from '#/api/ai-platform/ai-platform';
|
||||||
|
import type { Message } from '#/api/core/message';
|
||||||
|
|
||||||
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Activity,
|
||||||
|
Bell,
|
||||||
|
BookOpen,
|
||||||
|
Bot,
|
||||||
|
Cpu,
|
||||||
|
KeyRound,
|
||||||
|
Megaphone,
|
||||||
|
Menu,
|
||||||
|
Rocket,
|
||||||
|
Settings,
|
||||||
|
ShieldCheck,
|
||||||
|
Users,
|
||||||
|
Workflow,
|
||||||
|
} from '@vben/icons';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ElButton,
|
||||||
|
ElEmpty,
|
||||||
|
ElProgress,
|
||||||
|
ElSkeleton,
|
||||||
|
ElSkeletonItem,
|
||||||
|
ElTag,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getAgentListApi,
|
||||||
|
getAllWorkflowRunsApi,
|
||||||
|
getKnowledgeBaseListApi,
|
||||||
|
getProviderListApi,
|
||||||
|
getWorkflowListApi,
|
||||||
|
} from '#/api/ai-platform/ai-platform';
|
||||||
|
import { getAnnouncementListApi } from '#/api/core/announcement';
|
||||||
|
import { getMessageListApi, getUnreadCountApi } from '#/api/core/message';
|
||||||
|
import {
|
||||||
|
getServerHealthOverviewApi,
|
||||||
|
getServerHealthRealtimeApi,
|
||||||
|
} from '#/api/core/server-health';
|
||||||
|
|
||||||
|
defineOptions({ name: 'AiAgentHome' });
|
||||||
|
|
||||||
|
interface OverviewMetric {
|
||||||
|
accent: string;
|
||||||
|
hint: string;
|
||||||
|
label: string;
|
||||||
|
route: string;
|
||||||
|
value: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface QuickLink {
|
||||||
|
desc: string;
|
||||||
|
icon: any;
|
||||||
|
label: string;
|
||||||
|
route: string;
|
||||||
|
tone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnnouncementLite {
|
||||||
|
created_at?: string;
|
||||||
|
id: string;
|
||||||
|
priority?: number;
|
||||||
|
publisher_name?: string;
|
||||||
|
summary?: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const loading = ref(true);
|
||||||
|
const agentList = ref<AgentListItem[]>([]);
|
||||||
|
const workflowList = ref<WorkflowListItem[]>([]);
|
||||||
|
const knowledgeList = ref<KnowledgeBaseListItem[]>([]);
|
||||||
|
const runList = ref<WorkflowRunListItem[]>([]);
|
||||||
|
const announcements = ref<AnnouncementLite[]>([]);
|
||||||
|
const messages = ref<Message[]>([]);
|
||||||
|
const unreadTotal = ref(0);
|
||||||
|
const providerTotal = ref(0);
|
||||||
|
const cpuPercent = ref(0);
|
||||||
|
const memoryPercent = ref(0);
|
||||||
|
const uptimeText = ref('-');
|
||||||
|
|
||||||
|
const aiLinks: QuickLink[] = [
|
||||||
|
{
|
||||||
|
desc: '编排可复用 Agent,沉淀角色、工具和知识库能力',
|
||||||
|
icon: Bot,
|
||||||
|
label: '智能体',
|
||||||
|
route: '/ai-platform/agent',
|
||||||
|
tone: 'blue',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '用节点流程组织多智能体协作、LLM 调用和人工确认',
|
||||||
|
icon: Workflow,
|
||||||
|
label: '流程编排',
|
||||||
|
route: '/ai-platform/workflow',
|
||||||
|
tone: 'green',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '管理向量知识库、文档分段、检索日志和命中质量',
|
||||||
|
icon: BookOpen,
|
||||||
|
label: '知识库',
|
||||||
|
route: '/ai-platform/knowledge-base',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '维护供应商、模型、Embedding 与 Rerank 能力',
|
||||||
|
icon: Settings,
|
||||||
|
label: '模型配置',
|
||||||
|
route: '/ai-platform/model',
|
||||||
|
tone: 'violet',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const adminLinks: QuickLink[] = [
|
||||||
|
{
|
||||||
|
desc: '账号、组织身份和后台访问入口',
|
||||||
|
icon: Users,
|
||||||
|
label: '用户管理',
|
||||||
|
route: '/system/user',
|
||||||
|
tone: 'blue',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '角色授权和数据范围控制',
|
||||||
|
icon: ShieldCheck,
|
||||||
|
label: '角色管理',
|
||||||
|
route: '/system/role',
|
||||||
|
tone: 'green',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '菜单、按钮和接口权限维护',
|
||||||
|
icon: KeyRound,
|
||||||
|
label: '权限管理',
|
||||||
|
route: '/system/new-permission',
|
||||||
|
tone: 'amber',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: '后台菜单结构和动态路由配置',
|
||||||
|
icon: Menu,
|
||||||
|
label: '菜单管理',
|
||||||
|
route: '/system/menu',
|
||||||
|
tone: 'violet',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const metrics = computed<OverviewMetric[]>(() => [
|
||||||
|
{
|
||||||
|
accent: 'blue',
|
||||||
|
hint: `${agentList.value.filter((item) => item.status === 'published').length} 个已发布`,
|
||||||
|
label: '智能体',
|
||||||
|
route: '/ai-platform/agent',
|
||||||
|
value: agentList.value.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accent: 'green',
|
||||||
|
hint: `${workflowList.value.filter((item) => item.status === 'published').length} 个已发布`,
|
||||||
|
label: '工作流',
|
||||||
|
route: '/ai-platform/workflow',
|
||||||
|
value: workflowList.value.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accent: 'amber',
|
||||||
|
hint: `${providerTotal.value} 个模型供应商`,
|
||||||
|
label: '知识库',
|
||||||
|
route: '/ai-platform/knowledge-base',
|
||||||
|
value: knowledgeList.value.length,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accent: 'violet',
|
||||||
|
hint: `${unreadTotal.value} 条未读消息`,
|
||||||
|
label: '执行记录',
|
||||||
|
route: '/ai-platform/workflow-runs',
|
||||||
|
value: runList.value.length,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const recentRuns = computed(() => runList.value.slice(0, 5));
|
||||||
|
const recentAnnouncements = computed(() => announcements.value.slice(0, 5));
|
||||||
|
const recentMessages = computed(() => messages.value.slice(0, 5));
|
||||||
|
|
||||||
|
function go(route: string) {
|
||||||
|
router.push(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTime(value?: string) {
|
||||||
|
if (!value) return '-';
|
||||||
|
return value.replace('T', ' ').slice(0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runStatusType(status: string) {
|
||||||
|
if (status === 'completed') return 'success';
|
||||||
|
if (status === 'failed' || status === 'stopped') return 'danger';
|
||||||
|
if (status === 'running' || status === 'waiting') return 'warning';
|
||||||
|
return 'info';
|
||||||
|
}
|
||||||
|
|
||||||
|
function runStatusLabel(status: string) {
|
||||||
|
const labels: Record<string, string> = {
|
||||||
|
completed: '已完成',
|
||||||
|
failed: '失败',
|
||||||
|
pending: '等待中',
|
||||||
|
running: '运行中',
|
||||||
|
stopped: '已停止',
|
||||||
|
waiting: '等待输入',
|
||||||
|
};
|
||||||
|
return labels[status] || status;
|
||||||
|
}
|
||||||
|
|
||||||
|
function announcementType(priority?: number) {
|
||||||
|
if (priority === 2) return 'danger';
|
||||||
|
if (priority === 1) return 'warning';
|
||||||
|
return 'info';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadHomeData() {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const results = await Promise.allSettled([
|
||||||
|
getAgentListApi({ page: 1, pageSize: 8 }),
|
||||||
|
getWorkflowListApi({ page: 1, pageSize: 8 }),
|
||||||
|
getKnowledgeBaseListApi({ page: 1, pageSize: 8 }),
|
||||||
|
getAllWorkflowRunsApi({ page: 1, pageSize: 8 }),
|
||||||
|
getAnnouncementListApi({ page: 1, pageSize: 6, status: 'published' }),
|
||||||
|
getMessageListApi({ page: 1, pageSize: 6, status: 'unread' }),
|
||||||
|
getUnreadCountApi(),
|
||||||
|
getProviderListApi({ page: 1, pageSize: 1 }),
|
||||||
|
getServerHealthOverviewApi(),
|
||||||
|
getServerHealthRealtimeApi(),
|
||||||
|
] as const);
|
||||||
|
|
||||||
|
const [
|
||||||
|
agentRes,
|
||||||
|
workflowRes,
|
||||||
|
knowledgeRes,
|
||||||
|
runRes,
|
||||||
|
announcementRes,
|
||||||
|
messageRes,
|
||||||
|
unreadRes,
|
||||||
|
providerRes,
|
||||||
|
overviewRes,
|
||||||
|
realtimeRes,
|
||||||
|
] = results;
|
||||||
|
|
||||||
|
if (agentRes.status === 'fulfilled') {
|
||||||
|
agentList.value = agentRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (workflowRes.status === 'fulfilled') {
|
||||||
|
workflowList.value = workflowRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (knowledgeRes.status === 'fulfilled') {
|
||||||
|
knowledgeList.value = knowledgeRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (runRes.status === 'fulfilled') {
|
||||||
|
runList.value = runRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (announcementRes.status === 'fulfilled') {
|
||||||
|
announcements.value = announcementRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (messageRes.status === 'fulfilled') {
|
||||||
|
messages.value = messageRes.value.items || [];
|
||||||
|
}
|
||||||
|
if (unreadRes.status === 'fulfilled') {
|
||||||
|
unreadTotal.value = unreadRes.value.total || 0;
|
||||||
|
}
|
||||||
|
if (providerRes.status === 'fulfilled') {
|
||||||
|
providerTotal.value = providerRes.value.total || 0;
|
||||||
|
}
|
||||||
|
if (overviewRes.status === 'fulfilled') {
|
||||||
|
uptimeText.value = overviewRes.value.boot_time?.uptime_formatted || '-';
|
||||||
|
cpuPercent.value = overviewRes.value.cpu_info?.cpu_percent || 0;
|
||||||
|
memoryPercent.value =
|
||||||
|
overviewRes.value.memory_info?.virtual?.percent || 0;
|
||||||
|
}
|
||||||
|
if (realtimeRes.status === 'fulfilled') {
|
||||||
|
cpuPercent.value = realtimeRes.value.cpu_percent || cpuPercent.value;
|
||||||
|
memoryPercent.value =
|
||||||
|
realtimeRes.value.memory_percent || memoryPercent.value;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(loadHomeData);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="ai-agent-home">
|
||||||
|
<section class="home-hero">
|
||||||
|
<div class="hero-copy">
|
||||||
|
<div class="eyebrow">
|
||||||
|
<Activity class="size-4" />
|
||||||
|
AI Agent Admin
|
||||||
|
</div>
|
||||||
|
<h1>智能体协作控制中心</h1>
|
||||||
|
<p>
|
||||||
|
聚焦智能体、流程编排、LLM、知识库和基础权限治理,保留 zq_ai_admin
|
||||||
|
的后台操作密度,移除在线开发链路的构建负担。
|
||||||
|
</p>
|
||||||
|
<div class="hero-actions">
|
||||||
|
<ElButton
|
||||||
|
type="primary"
|
||||||
|
:icon="Rocket"
|
||||||
|
@click="go('/ai-platform/agent')"
|
||||||
|
>
|
||||||
|
进入智能体
|
||||||
|
</ElButton>
|
||||||
|
<ElButton :icon="Workflow" @click="go('/ai-platform/workflow')">
|
||||||
|
编排工作流
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ops-panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
<Cpu class="size-4" />
|
||||||
|
运行状态
|
||||||
|
</div>
|
||||||
|
<div class="ops-row">
|
||||||
|
<span>CPU</span>
|
||||||
|
<ElProgress :percentage="Math.round(cpuPercent)" :stroke-width="8" />
|
||||||
|
</div>
|
||||||
|
<div class="ops-row">
|
||||||
|
<span>内存</span>
|
||||||
|
<ElProgress
|
||||||
|
:percentage="Math.round(memoryPercent)"
|
||||||
|
:stroke-width="8"
|
||||||
|
color="#16a34a"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="ops-foot">
|
||||||
|
<span>运行时长</span>
|
||||||
|
<strong>{{ uptimeText }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<ElSkeleton v-if="loading" animated :rows="8">
|
||||||
|
<template #template>
|
||||||
|
<div class="skeleton-grid">
|
||||||
|
<ElSkeletonItem v-for="item in 8" :key="item" variant="rect" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElSkeleton>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<section class="metric-grid">
|
||||||
|
<button
|
||||||
|
v-for="metric in metrics"
|
||||||
|
:key="metric.label"
|
||||||
|
class="metric-card"
|
||||||
|
:class="`tone-${metric.accent}`"
|
||||||
|
type="button"
|
||||||
|
@click="go(metric.route)"
|
||||||
|
>
|
||||||
|
<span>{{ metric.label }}</span>
|
||||||
|
<strong>{{ metric.value }}</strong>
|
||||||
|
<small>{{ metric.hint }}</small>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="content-grid">
|
||||||
|
<div class="section-block span-7">
|
||||||
|
<div class="section-head">
|
||||||
|
<div>
|
||||||
|
<h2>AI 协作入口</h2>
|
||||||
|
<p>围绕 Agent 多角色协作和工作流执行的核心能力。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="link-grid">
|
||||||
|
<button
|
||||||
|
v-for="link in aiLinks"
|
||||||
|
:key="link.route"
|
||||||
|
class="link-item"
|
||||||
|
:class="`tone-${link.tone}`"
|
||||||
|
type="button"
|
||||||
|
@click="go(link.route)"
|
||||||
|
>
|
||||||
|
<component :is="link.icon" class="size-5" />
|
||||||
|
<span>{{ link.label }}</span>
|
||||||
|
<small>{{ link.desc }}</small>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-block span-5">
|
||||||
|
<div class="section-head">
|
||||||
|
<div>
|
||||||
|
<h2>最近执行</h2>
|
||||||
|
<p>快速定位失败和等待输入的流程。</p>
|
||||||
|
</div>
|
||||||
|
<ElButton
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="go('/ai-platform/workflow-runs')"
|
||||||
|
>
|
||||||
|
查看全部
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
<div v-if="recentRuns.length > 0" class="run-list">
|
||||||
|
<button
|
||||||
|
v-for="run in recentRuns"
|
||||||
|
:key="run.id"
|
||||||
|
class="run-item"
|
||||||
|
type="button"
|
||||||
|
@click="go('/ai-platform/workflow-runs')"
|
||||||
|
>
|
||||||
|
<span>{{ run.workflow_name || run.id }}</span>
|
||||||
|
<ElTag :type="runStatusType(run.status)" size="small">
|
||||||
|
{{ runStatusLabel(run.status) }}
|
||||||
|
</ElTag>
|
||||||
|
<small>{{ formatTime(run.started_at) }}</small>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ElEmpty v-else description="暂无执行记录" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-block span-5">
|
||||||
|
<div class="section-head">
|
||||||
|
<div>
|
||||||
|
<h2>基础管理</h2>
|
||||||
|
<p>保留后台系统稳定运行所需的基础治理模块。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="admin-list">
|
||||||
|
<button
|
||||||
|
v-for="link in adminLinks"
|
||||||
|
:key="link.route"
|
||||||
|
class="admin-item"
|
||||||
|
type="button"
|
||||||
|
@click="go(link.route)"
|
||||||
|
>
|
||||||
|
<component :is="link.icon" class="size-4" />
|
||||||
|
<span>{{ link.label }}</span>
|
||||||
|
<small>{{ link.desc }}</small>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section-block span-7">
|
||||||
|
<div class="section-head">
|
||||||
|
<div>
|
||||||
|
<h2>消息与公告</h2>
|
||||||
|
<p>公告管理、消息中心和未读提醒。</p>
|
||||||
|
</div>
|
||||||
|
<div class="head-actions">
|
||||||
|
<ElButton
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
@click="go('/message/announcement')"
|
||||||
|
>
|
||||||
|
公告管理
|
||||||
|
</ElButton>
|
||||||
|
<ElButton link type="primary" @click="go('/message/list')">
|
||||||
|
消息中心
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="notice-columns">
|
||||||
|
<div>
|
||||||
|
<div class="sub-title">
|
||||||
|
<Megaphone class="size-4" />
|
||||||
|
最新公告
|
||||||
|
</div>
|
||||||
|
<div v-if="recentAnnouncements.length > 0" class="compact-list">
|
||||||
|
<button
|
||||||
|
v-for="item in recentAnnouncements"
|
||||||
|
:key="item.id"
|
||||||
|
type="button"
|
||||||
|
@click="go('/message/announcement')"
|
||||||
|
>
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<ElTag :type="announcementType(item.priority)" size="small">
|
||||||
|
{{
|
||||||
|
item.priority === 2
|
||||||
|
? '紧急'
|
||||||
|
: item.priority === 1
|
||||||
|
? '重要'
|
||||||
|
: '普通'
|
||||||
|
}}
|
||||||
|
</ElTag>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ElEmpty v-else description="暂无公告" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="sub-title">
|
||||||
|
<Bell class="size-4" />
|
||||||
|
未读消息
|
||||||
|
</div>
|
||||||
|
<div v-if="recentMessages.length > 0" class="compact-list">
|
||||||
|
<button
|
||||||
|
v-for="item in recentMessages"
|
||||||
|
:key="item.id"
|
||||||
|
type="button"
|
||||||
|
@click="go('/message/list')"
|
||||||
|
>
|
||||||
|
<span>{{ item.title }}</span>
|
||||||
|
<small>{{ formatTime(item.created_at) }}</small>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ElEmpty v-else description="暂无未读消息" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ai-agent-home {
|
||||||
|
min-height: calc(100vh - 120px);
|
||||||
|
padding: 18px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 12% 8%, rgb(37 99 235 / 8%), transparent 28%),
|
||||||
|
linear-gradient(180deg, var(--el-bg-color-page), var(--el-bg-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.home-hero {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) 340px;
|
||||||
|
gap: 18px;
|
||||||
|
align-items: stretch;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy,
|
||||||
|
.ops-panel,
|
||||||
|
.section-block,
|
||||||
|
.metric-card {
|
||||||
|
background: var(--el-bg-color);
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 6px 20px rgb(15 23 42 / 6%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
padding: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eyebrow,
|
||||||
|
.panel-title,
|
||||||
|
.sub-title {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy h1 {
|
||||||
|
margin: 14px 0 10px;
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy p {
|
||||||
|
max-width: 68ch;
|
||||||
|
margin: 0;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ops-panel {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ops-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 46px minmax(0, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 18px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ops-foot {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-top: 16px;
|
||||||
|
margin-top: 18px;
|
||||||
|
color: var(--el-text-color-regular);
|
||||||
|
border-top: 1px solid var(--el-border-color-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card,
|
||||||
|
.link-item,
|
||||||
|
.admin-item,
|
||||||
|
.run-item,
|
||||||
|
.compact-list button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
display: grid;
|
||||||
|
gap: 7px;
|
||||||
|
padding: 16px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card span,
|
||||||
|
.section-head p,
|
||||||
|
.metric-card small,
|
||||||
|
.link-item small,
|
||||||
|
.admin-item small,
|
||||||
|
.run-item small,
|
||||||
|
.compact-list small {
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card strong {
|
||||||
|
font-size: 26px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-5 {
|
||||||
|
grid-column: span 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-7 {
|
||||||
|
grid-column: span 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-block {
|
||||||
|
min-height: 260px;
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head h2 {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-head p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item,
|
||||||
|
.admin-item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto minmax(0, 1fr);
|
||||||
|
gap: 5px 10px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 14px;
|
||||||
|
text-align: left;
|
||||||
|
background: var(--el-fill-color-extra-light);
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-item small {
|
||||||
|
grid-column: 2;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-list,
|
||||||
|
.run-list,
|
||||||
|
.compact-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-item {
|
||||||
|
grid-template-columns: auto 88px minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-item,
|
||||||
|
.compact-list button {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
gap: 6px 10px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 11px 12px;
|
||||||
|
text-align: left;
|
||||||
|
background: var(--el-fill-color-extra-light);
|
||||||
|
border: 1px solid var(--el-border-color-lighter);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-item span,
|
||||||
|
.compact-list span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.run-item small {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-columns {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-blue {
|
||||||
|
--tone-color: 37 99 235;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-green {
|
||||||
|
--tone-color: 22 163 74;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-amber {
|
||||||
|
--tone-color: 217 119 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tone-violet {
|
||||||
|
--tone-color: 124 58 237;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card,
|
||||||
|
.link-item {
|
||||||
|
border-color: rgb(var(--tone-color) / 18%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card strong,
|
||||||
|
.link-item svg {
|
||||||
|
color: rgb(var(--tone-color));
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card:hover,
|
||||||
|
.link-item:hover,
|
||||||
|
.admin-item:hover,
|
||||||
|
.run-item:hover,
|
||||||
|
.compact-list button:hover {
|
||||||
|
border-color: var(--el-color-primary-light-5);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card,
|
||||||
|
.link-item,
|
||||||
|
.admin-item,
|
||||||
|
.run-item,
|
||||||
|
.compact-list button {
|
||||||
|
transition:
|
||||||
|
border-color 0.18s ease,
|
||||||
|
transform 0.18s ease,
|
||||||
|
box-shadow 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skeleton-grid :deep(.el-skeleton__item) {
|
||||||
|
height: 130px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.home-hero,
|
||||||
|
.notice-columns {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.span-5,
|
||||||
|
.span-7 {
|
||||||
|
grid-column: span 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.ai-agent-home {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-copy h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-grid,
|
||||||
|
.link-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-item {
|
||||||
|
grid-template-columns: auto minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-item small {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-actions,
|
||||||
|
.head-actions {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
import type { DashboardConfig } from '#/components/dashboard-design';
|
|
||||||
|
|
||||||
const AI_AGENT_HOME_CODE = 'main_home';
|
|
||||||
|
|
||||||
const widgetStyle = {
|
|
||||||
backgroundColor: '',
|
|
||||||
borderColor: '',
|
|
||||||
borderRadius: 8,
|
|
||||||
borderStyle: 'solid',
|
|
||||||
borderWidth: 0,
|
|
||||||
padding: 16,
|
|
||||||
shadowBlur: 4,
|
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
|
||||||
shadowEnabled: true,
|
|
||||||
shadowOffsetX: 0,
|
|
||||||
shadowOffsetY: 1,
|
|
||||||
titleAlign: 'left',
|
|
||||||
titleColor: '',
|
|
||||||
titleFontSize: 14,
|
|
||||||
titleFontWeight: 'normal',
|
|
||||||
titleShow: true,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
const aiAgentAdminHomeConfig: DashboardConfig = {
|
|
||||||
id: 'ai-agent-admin-main-home',
|
|
||||||
name: '控制中心',
|
|
||||||
columns: 12,
|
|
||||||
rowHeight: 68,
|
|
||||||
margin: [12, 12],
|
|
||||||
backgroundColor: '',
|
|
||||||
widgets: [
|
|
||||||
{
|
|
||||||
id: 'welcome',
|
|
||||||
i: 'welcome',
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
w: 9,
|
|
||||||
h: 2,
|
|
||||||
minW: 4,
|
|
||||||
minH: 2,
|
|
||||||
type: 'welcome-card',
|
|
||||||
title: '欢迎回来',
|
|
||||||
props: {
|
|
||||||
title: '欢迎回来',
|
|
||||||
subtitle: '聚焦智能体协作、流程编排、知识库和基础权限治理',
|
|
||||||
showTime: true,
|
|
||||||
showWeather: false,
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'weather',
|
|
||||||
i: 'weather',
|
|
||||||
x: 9,
|
|
||||||
y: 0,
|
|
||||||
w: 3,
|
|
||||||
h: 2,
|
|
||||||
minW: 2,
|
|
||||||
minH: 2,
|
|
||||||
type: 'weather',
|
|
||||||
title: '今日天气',
|
|
||||||
props: {
|
|
||||||
title: '今日天气',
|
|
||||||
cityName: '北京',
|
|
||||||
latitude: 39.9042,
|
|
||||||
longitude: 116.4074,
|
|
||||||
autoLocate: false,
|
|
||||||
refreshInterval: 30,
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ai-collaboration',
|
|
||||||
i: 'ai-collaboration',
|
|
||||||
x: 0,
|
|
||||||
y: 2,
|
|
||||||
w: 7,
|
|
||||||
h: 3,
|
|
||||||
minW: 6,
|
|
||||||
minH: 2,
|
|
||||||
type: 'quick-links',
|
|
||||||
title: 'AI 协作',
|
|
||||||
props: {
|
|
||||||
title: 'AI 协作',
|
|
||||||
columns: 4,
|
|
||||||
rows: 2,
|
|
||||||
menus: [
|
|
||||||
{
|
|
||||||
id: 'ai-agent',
|
|
||||||
title: '智能体',
|
|
||||||
icon: 'lucide:square-user',
|
|
||||||
path: '/ai-platform/agent',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ai-workflow',
|
|
||||||
title: '流程编排',
|
|
||||||
icon: 'lucide:workflow',
|
|
||||||
path: '/ai-platform/workflow',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ai-workflow-runs',
|
|
||||||
title: '执行历史',
|
|
||||||
icon: 'lucide:history',
|
|
||||||
path: '/ai-platform/workflow-runs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ai-knowledge',
|
|
||||||
title: '知识库',
|
|
||||||
icon: 'lucide:library-big',
|
|
||||||
path: '/ai-platform/knowledge-base',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ai-model',
|
|
||||||
title: '模型配置',
|
|
||||||
icon: 'lucide:settings',
|
|
||||||
path: '/ai-platform/model',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'codex-agent',
|
|
||||||
title: 'Codex 助手',
|
|
||||||
icon: 'lucide:code-2',
|
|
||||||
path: '/agent-chat/codex',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'base-admin',
|
|
||||||
i: 'base-admin',
|
|
||||||
x: 7,
|
|
||||||
y: 2,
|
|
||||||
w: 5,
|
|
||||||
h: 3,
|
|
||||||
minW: 4,
|
|
||||||
minH: 2,
|
|
||||||
type: 'quick-links',
|
|
||||||
title: '基础管理',
|
|
||||||
props: {
|
|
||||||
title: '基础管理',
|
|
||||||
columns: 3,
|
|
||||||
rows: 2,
|
|
||||||
menus: [
|
|
||||||
{
|
|
||||||
id: 'system-user',
|
|
||||||
title: '用户管理',
|
|
||||||
icon: 'lucide:users',
|
|
||||||
path: '/system/user',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'system-role',
|
|
||||||
title: '角色管理',
|
|
||||||
icon: 'lucide:shield-check',
|
|
||||||
path: '/system/role',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'system-permission',
|
|
||||||
title: '权限管理',
|
|
||||||
icon: 'lucide:key-round',
|
|
||||||
path: '/system/new-permission',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'system-menu',
|
|
||||||
title: '菜单管理',
|
|
||||||
icon: 'lucide:menu',
|
|
||||||
path: '/system/menu',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'announcement',
|
|
||||||
title: '公告管理',
|
|
||||||
icon: 'lucide:megaphone',
|
|
||||||
path: '/message/announcement',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'message',
|
|
||||||
title: '消息中心',
|
|
||||||
icon: 'lucide:bell',
|
|
||||||
path: '/message/list',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'announcement-list',
|
|
||||||
i: 'announcement-list',
|
|
||||||
x: 0,
|
|
||||||
y: 5,
|
|
||||||
w: 4,
|
|
||||||
h: 4,
|
|
||||||
minW: 3,
|
|
||||||
minH: 3,
|
|
||||||
type: 'announcement-list',
|
|
||||||
title: '最新公告',
|
|
||||||
props: {
|
|
||||||
title: '最新公告',
|
|
||||||
limit: 6,
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'notice-list',
|
|
||||||
i: 'notice-list',
|
|
||||||
x: 4,
|
|
||||||
y: 5,
|
|
||||||
w: 4,
|
|
||||||
h: 4,
|
|
||||||
minW: 3,
|
|
||||||
minH: 3,
|
|
||||||
type: 'notice-list',
|
|
||||||
title: '消息通知',
|
|
||||||
props: {
|
|
||||||
title: '消息通知',
|
|
||||||
limit: 6,
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'server-monitor',
|
|
||||||
i: 'server-monitor',
|
|
||||||
x: 8,
|
|
||||||
y: 5,
|
|
||||||
w: 4,
|
|
||||||
h: 4,
|
|
||||||
minW: 4,
|
|
||||||
minH: 3,
|
|
||||||
type: 'server-monitor',
|
|
||||||
title: '运行监控',
|
|
||||||
props: {
|
|
||||||
title: '运行监控',
|
|
||||||
refreshInterval: 5000,
|
|
||||||
},
|
|
||||||
style: widgetStyle,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
function isAiAgentAdminHomeCode(code: string) {
|
|
||||||
return code === AI_AGENT_HOME_CODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createAiAgentAdminHomeConfig() {
|
|
||||||
return JSON.parse(JSON.stringify(aiAgentAdminHomeConfig)) as DashboardConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
export { createAiAgentAdminHomeConfig, isAiAgentAdminHomeCode };
|
|
||||||
@@ -1,24 +1,18 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { ElEmpty, ElMessage, ElScrollbar } from 'element-plus';
|
import { ElEmpty, ElMessage, ElScrollbar } from 'element-plus';
|
||||||
|
|
||||||
import { getPageByCodeApi } from '#/api/core/page-manager';
|
import AiAgentHome from './AiAgentHome.vue';
|
||||||
import DashboardRenderer from '#/components/dashboard-design/DashboardRenderer.vue';
|
|
||||||
|
|
||||||
import {
|
|
||||||
createAiAgentAdminHomeConfig,
|
|
||||||
isAiAgentAdminHomeCode,
|
|
||||||
} from './ai-agent-home-config';
|
|
||||||
|
|
||||||
defineOptions({ name: 'PageRender' });
|
defineOptions({ name: 'PageRender' });
|
||||||
|
|
||||||
|
const AI_AGENT_HOME_CODE = 'main_home';
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const pageConfig = ref<string>('');
|
|
||||||
const pageName = ref('');
|
|
||||||
const pageCode = ref('');
|
const pageCode = ref('');
|
||||||
|
const isHomePage = computed(() => pageCode.value === AI_AGENT_HOME_CODE);
|
||||||
|
|
||||||
function getPageCode(): string {
|
function getPageCode(): string {
|
||||||
if (route.query.pageCode) {
|
if (route.query.pageCode) {
|
||||||
@@ -49,19 +43,9 @@ async function loadPageData() {
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isAiAgentAdminHomeCode(code)) {
|
if (!isHomePage.value) {
|
||||||
const config = createAiAgentAdminHomeConfig();
|
ElMessage.warning('轻量版已停用在线页面渲染');
|
||||||
pageName.value = config.name;
|
|
||||||
pageConfig.value = JSON.stringify(config);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = await getPageByCodeApi(code);
|
|
||||||
pageName.value = page.name;
|
|
||||||
pageConfig.value =
|
|
||||||
page.page_config && Object.keys(page.page_config).length > 0
|
|
||||||
? JSON.stringify(page.page_config)
|
|
||||||
: '';
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
ElMessage.error(error?.message || '加载页面失败');
|
ElMessage.error(error?.message || '加载页面失败');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -83,9 +67,16 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ElScrollbar class="rounded-[8px] py-3">
|
<ElScrollbar class="rounded-[8px] py-3">
|
||||||
<div v-loading="loading" class="h-[calc(100vh-120px)] rounded-[8px] px-3">
|
<div
|
||||||
<DashboardRenderer v-if="pageConfig" :config="pageConfig" />
|
v-loading="loading"
|
||||||
<ElEmpty v-else-if="!loading" description="暂无页面配置" />
|
class="min-h-[calc(100vh-120px)] rounded-[8px] px-3"
|
||||||
|
>
|
||||||
|
<AiAgentHome v-if="isHomePage" />
|
||||||
|
<ElEmpty
|
||||||
|
v-else-if="!loading"
|
||||||
|
description="轻量版已移除在线页面渲染"
|
||||||
|
class="py-20"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ElScrollbar>
|
</ElScrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user