Add-lightweight-control-center-home
This commit is contained in:
@@ -21,6 +21,7 @@ MENU_TREE_CACHE_KEY = "tree:ai_agent_admin"
|
||||
USER_ROUTE_CACHE_PREFIX = "user_route:ai_agent_admin:"
|
||||
|
||||
AI_AGENT_ADMIN_MENU_NAMES = {
|
||||
"ControlCenter",
|
||||
"AIPlatform",
|
||||
"AIAgent",
|
||||
"AIWorkflow",
|
||||
@@ -43,7 +44,18 @@ AI_AGENT_ADMIN_MENU_NAMES = {
|
||||
|
||||
def _filter_ai_agent_admin_menus(menus: List[Menu]) -> List[Menu]:
|
||||
"""Keep only the lightweight admin and AI modules for this product."""
|
||||
return [menu for menu in menus if menu.name in AI_AGENT_ADMIN_MENU_NAMES]
|
||||
filtered = [menu for menu in menus if menu.name in AI_AGENT_ADMIN_MENU_NAMES]
|
||||
for menu in filtered:
|
||||
_normalize_ai_agent_admin_menu(menu)
|
||||
return filtered
|
||||
|
||||
|
||||
def _normalize_ai_agent_admin_menu(menu: Menu) -> None:
|
||||
"""Route legacy low-code home to a lightweight static dashboard."""
|
||||
if menu.name == "ControlCenter":
|
||||
menu.path = "/control-center"
|
||||
menu.component = "_core/control-center/index"
|
||||
menu.query = None
|
||||
|
||||
|
||||
class MenuService(BaseService[Menu, MenuCreate, MenuUpdate]):
|
||||
|
||||
@@ -22,6 +22,7 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
|
||||
'../views/_core/announcement/index.vue',
|
||||
'../views/_core/announcement/list.vue',
|
||||
'../views/_core/authentication/**/*.vue',
|
||||
'../views/_core/control-center/index.vue',
|
||||
'../views/_core/fallback/**/*.vue',
|
||||
'../views/_core/login-log/index.vue',
|
||||
'../views/_core/menu/index.vue',
|
||||
|
||||
@@ -41,6 +41,7 @@ const componentKeys: string[] = Object.keys(
|
||||
'../../views/_core/announcement/index.vue',
|
||||
'../../views/_core/announcement/list.vue',
|
||||
'../../views/_core/authentication/**/*.vue',
|
||||
'../../views/_core/control-center/index.vue',
|
||||
'../../views/_core/fallback/**/*.vue',
|
||||
'../../views/_core/login-log/index.vue',
|
||||
'../../views/_core/menu/index.vue',
|
||||
|
||||
@@ -0,0 +1,734 @@
|
||||
<script setup lang="ts">
|
||||
import type {
|
||||
AgentListItem,
|
||||
KnowledgeBaseListItem,
|
||||
WorkflowListItem,
|
||||
WorkflowRunListItem,
|
||||
} from '#/api/ai-platform/ai-platform';
|
||||
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import {
|
||||
Bot,
|
||||
BookOpen,
|
||||
CircleCheckBig,
|
||||
Clock3,
|
||||
GitBranch,
|
||||
MessageSquare,
|
||||
Play,
|
||||
RefreshCw,
|
||||
Route,
|
||||
Settings,
|
||||
Shield,
|
||||
Sparkles,
|
||||
Users,
|
||||
Workflow,
|
||||
} from '@vben/icons';
|
||||
|
||||
import {
|
||||
ElButton,
|
||||
ElCard,
|
||||
ElEmpty,
|
||||
ElSkeleton,
|
||||
ElTag,
|
||||
ElTimeline,
|
||||
ElTimelineItem,
|
||||
} from 'element-plus';
|
||||
|
||||
import {
|
||||
getAgentListApi,
|
||||
getAllWorkflowRunsApi,
|
||||
getKnowledgeBaseListApi,
|
||||
getWorkflowListApi,
|
||||
} from '#/api/ai-platform/ai-platform';
|
||||
|
||||
defineOptions({ name: 'ControlCenter' });
|
||||
|
||||
const router = useRouter();
|
||||
const loading = ref(false);
|
||||
const loaded = ref(false);
|
||||
const agents = ref<AgentListItem[]>([]);
|
||||
const workflows = ref<WorkflowListItem[]>([]);
|
||||
const knowledgeBases = ref<KnowledgeBaseListItem[]>([]);
|
||||
const runs = ref<WorkflowRunListItem[]>([]);
|
||||
|
||||
const stats = reactive({
|
||||
agentTotal: 0,
|
||||
workflowTotal: 0,
|
||||
knowledgeTotal: 0,
|
||||
runTotal: 0,
|
||||
});
|
||||
|
||||
const publishedAgents = computed(
|
||||
() => agents.value.filter((item) => item.status === 'published').length,
|
||||
);
|
||||
const publishedWorkflows = computed(
|
||||
() => workflows.value.filter((item) => item.status === 'published').length,
|
||||
);
|
||||
const successfulRuns = computed(
|
||||
() => runs.value.filter((item) => item.status === 'success').length,
|
||||
);
|
||||
const failedRuns = computed(
|
||||
() => runs.value.filter((item) => item.status === 'failed').length,
|
||||
);
|
||||
|
||||
const quickEntries = [
|
||||
{
|
||||
desc: '沉淀角色能力、提示词和工具调用策略',
|
||||
icon: Bot,
|
||||
path: '/ai-platform/agent',
|
||||
title: '智能体',
|
||||
},
|
||||
{
|
||||
desc: '编排多 Agent 协作、人工确认和系统调用',
|
||||
icon: Workflow,
|
||||
path: '/ai-platform/workflow',
|
||||
title: '流程编排',
|
||||
},
|
||||
{
|
||||
desc: '管理文档、分段、向量索引和检索日志',
|
||||
icon: BookOpen,
|
||||
path: '/ai-platform/knowledge-base',
|
||||
title: '知识库',
|
||||
},
|
||||
{
|
||||
desc: '进入 Codex 协作入口,串联开发任务',
|
||||
icon: MessageSquare,
|
||||
path: '/agent-chat/codex',
|
||||
title: 'Codex',
|
||||
},
|
||||
];
|
||||
|
||||
const adminEntries = [
|
||||
{ icon: Users, path: '/system/user', title: '用户管理' },
|
||||
{ icon: Shield, path: '/system/role', title: '角色权限' },
|
||||
{ icon: Route, path: '/system/menu', title: '菜单管理' },
|
||||
{ icon: Settings, path: '/system-config', title: '系统配置' },
|
||||
];
|
||||
|
||||
function go(path: string) {
|
||||
router.push(path);
|
||||
}
|
||||
|
||||
function formatTime(value?: string) {
|
||||
if (!value) return '-';
|
||||
return value.replace('T', ' ').slice(0, 19);
|
||||
}
|
||||
|
||||
async function loadDashboard() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const [agentRes, workflowRes, knowledgeRes, runRes] = await Promise.all([
|
||||
getAgentListApi({ page: 1, pageSize: 6 }),
|
||||
getWorkflowListApi({ page: 1, pageSize: 6 }),
|
||||
getKnowledgeBaseListApi({ page: 1, pageSize: 6 }),
|
||||
getAllWorkflowRunsApi({ page: 1, pageSize: 6 }),
|
||||
]);
|
||||
agents.value = agentRes.items || [];
|
||||
workflows.value = workflowRes.items || [];
|
||||
knowledgeBases.value = knowledgeRes.items || [];
|
||||
runs.value = runRes.items || [];
|
||||
stats.agentTotal = agentRes.total || agents.value.length;
|
||||
stats.workflowTotal = workflowRes.total || workflows.value.length;
|
||||
stats.knowledgeTotal = knowledgeRes.total || knowledgeBases.value.length;
|
||||
stats.runTotal = runRes.total || runs.value.length;
|
||||
loaded.value = true;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(loadDashboard);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page auto-content-height title="控制中心">
|
||||
<div class="control-center">
|
||||
<section class="hero-panel">
|
||||
<div>
|
||||
<div class="eyebrow">
|
||||
<Sparkles :size="16" />
|
||||
ZQ-AI Agent Admin
|
||||
</div>
|
||||
<h1>控制中心</h1>
|
||||
<p>
|
||||
{{ stats.agentTotal }} 个智能体、{{ stats.workflowTotal }} 条流程、{{ stats.runTotal }} 次执行记录已汇总。
|
||||
</p>
|
||||
</div>
|
||||
<div class="hero-actions">
|
||||
<ElButton :icon="RefreshCw" :loading="loading" @click="loadDashboard">
|
||||
刷新
|
||||
</ElButton>
|
||||
<ElButton type="primary" :icon="Bot" @click="go('/ai-platform/agent')">
|
||||
创建智能体
|
||||
</ElButton>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="metric-grid">
|
||||
<ElCard shadow="never" class="metric-card">
|
||||
<div class="metric-icon agent"><Bot :size="22" /></div>
|
||||
<div>
|
||||
<span>智能体</span>
|
||||
<strong>{{ stats.agentTotal }}</strong>
|
||||
<small>已发布 {{ publishedAgents }}</small>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" class="metric-card">
|
||||
<div class="metric-icon workflow"><Workflow :size="22" /></div>
|
||||
<div>
|
||||
<span>流程</span>
|
||||
<strong>{{ stats.workflowTotal }}</strong>
|
||||
<small>已发布 {{ publishedWorkflows }}</small>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" class="metric-card">
|
||||
<div class="metric-icon knowledge"><BookOpen :size="22" /></div>
|
||||
<div>
|
||||
<span>知识库</span>
|
||||
<strong>{{ stats.knowledgeTotal }}</strong>
|
||||
<small>{{ knowledgeBases.length }} 个最近维护</small>
|
||||
</div>
|
||||
</ElCard>
|
||||
<ElCard shadow="never" class="metric-card">
|
||||
<div class="metric-icon run"><Play :size="22" /></div>
|
||||
<div>
|
||||
<span>执行记录</span>
|
||||
<strong>{{ stats.runTotal }}</strong>
|
||||
<small>成功 {{ successfulRuns }} / 失败 {{ failedRuns }}</small>
|
||||
</div>
|
||||
</ElCard>
|
||||
</section>
|
||||
|
||||
<section class="content-grid">
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>AI 工作入口</span>
|
||||
<ElButton link type="primary" @click="go('/ai-platform/agent')">
|
||||
查看全部
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<div class="quick-grid">
|
||||
<button
|
||||
v-for="entry in quickEntries"
|
||||
:key="entry.path"
|
||||
class="quick-entry"
|
||||
type="button"
|
||||
@click="go(entry.path)"
|
||||
>
|
||||
<component :is="entry.icon" :size="22" />
|
||||
<span>{{ entry.title }}</span>
|
||||
<small>{{ entry.desc }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</ElCard>
|
||||
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>基础后台</span>
|
||||
<ElButton link type="primary" @click="go('/system/user')">
|
||||
用户权限
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<div class="admin-grid">
|
||||
<button
|
||||
v-for="entry in adminEntries"
|
||||
:key="entry.path"
|
||||
class="admin-entry"
|
||||
type="button"
|
||||
@click="go(entry.path)"
|
||||
>
|
||||
<component :is="entry.icon" :size="18" />
|
||||
<span>{{ entry.title }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</ElCard>
|
||||
</section>
|
||||
|
||||
<section class="content-grid lower">
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>智能体协作</span>
|
||||
<ElButton link type="primary" @click="go('/ai-platform/agent')">
|
||||
管理智能体
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<ElSkeleton v-if="loading && !loaded" :rows="5" animated />
|
||||
<div v-else-if="agents.length" class="list-stack">
|
||||
<button
|
||||
v-for="agent in agents"
|
||||
:key="agent.id"
|
||||
class="list-row"
|
||||
type="button"
|
||||
@click="go(`/ai-platform/agent/editor/${agent.id}`)"
|
||||
>
|
||||
<span>
|
||||
<strong>{{ agent.name }}</strong>
|
||||
<small>{{ agent.description || agent.code }}</small>
|
||||
</span>
|
||||
<ElTag :type="agent.status === 'published' ? 'success' : 'info'">
|
||||
{{ agent.status === 'published' ? '已发布' : '草稿' }}
|
||||
</ElTag>
|
||||
</button>
|
||||
</div>
|
||||
<ElEmpty v-else description="暂无智能体" />
|
||||
</ElCard>
|
||||
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>最近执行</span>
|
||||
<ElButton
|
||||
link
|
||||
type="primary"
|
||||
@click="go('/ai-platform/workflow-runs')"
|
||||
>
|
||||
执行历史
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<ElTimeline v-if="runs.length" class="run-timeline">
|
||||
<ElTimelineItem
|
||||
v-for="run in runs"
|
||||
:key="run.id"
|
||||
:timestamp="formatTime(run.started_at)"
|
||||
:type="run.status === 'success' ? 'success' : run.status === 'failed' ? 'danger' : 'primary'"
|
||||
>
|
||||
<button
|
||||
class="run-item"
|
||||
type="button"
|
||||
@click="go('/ai-platform/workflow-runs')"
|
||||
>
|
||||
<span>
|
||||
<strong>{{ run.workflow_name }}</strong>
|
||||
<small>
|
||||
{{ run.total_steps }} 步 · {{ run.total_tokens }} tokens
|
||||
</small>
|
||||
</span>
|
||||
<ElTag size="small">
|
||||
{{ run.status }}
|
||||
</ElTag>
|
||||
</button>
|
||||
</ElTimelineItem>
|
||||
</ElTimeline>
|
||||
<ElEmpty v-else description="暂无执行记录" />
|
||||
</ElCard>
|
||||
</section>
|
||||
|
||||
<section class="content-grid lower">
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>流程编排</span>
|
||||
<ElButton link type="primary" @click="go('/ai-platform/workflow')">
|
||||
查看流程
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="workflows.length" class="list-stack compact">
|
||||
<button
|
||||
v-for="workflow in workflows"
|
||||
:key="workflow.id"
|
||||
class="list-row"
|
||||
type="button"
|
||||
@click="go(`/ai-platform/workflow/editor/${workflow.id}`)"
|
||||
>
|
||||
<span>
|
||||
<strong>{{ workflow.name }}</strong>
|
||||
<small>{{ workflow.description || workflow.code }}</small>
|
||||
</span>
|
||||
<ElTag type="info">{{ workflow.workflow_type }}</ElTag>
|
||||
</button>
|
||||
</div>
|
||||
<ElEmpty v-else description="暂无流程" />
|
||||
</ElCard>
|
||||
|
||||
<ElCard shadow="never" class="panel-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>知识资产</span>
|
||||
<ElButton
|
||||
link
|
||||
type="primary"
|
||||
@click="go('/ai-platform/knowledge-base')"
|
||||
>
|
||||
查看知识库
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="knowledgeBases.length" class="knowledge-strip">
|
||||
<button
|
||||
v-for="kb in knowledgeBases"
|
||||
:key="kb.id"
|
||||
class="knowledge-item"
|
||||
type="button"
|
||||
@click="go(`/ai-platform/knowledge/detail/${kb.id}`)"
|
||||
>
|
||||
<BookOpen :size="18" />
|
||||
<span>
|
||||
<strong>{{ kb.name }}</strong>
|
||||
<small>
|
||||
{{ kb.document_count }} 文档 · {{ kb.segment_count }} 分段
|
||||
</small>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<ElEmpty v-else description="暂无知识库" />
|
||||
</ElCard>
|
||||
</section>
|
||||
|
||||
<section class="health-band">
|
||||
<div>
|
||||
<CircleCheckBig :size="18" />
|
||||
<span>基础后台状态正常,用户、角色、菜单和公告入口可用。</span>
|
||||
</div>
|
||||
<div>
|
||||
<GitBranch :size="18" />
|
||||
<span>AI 协作资源已加载,智能体、流程和 Codex 入口可用。</span>
|
||||
</div>
|
||||
<div>
|
||||
<Clock3 :size="18" />
|
||||
<span>最近执行记录已同步,刷新后可查看最新运行状态。</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.control-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.hero-panel {
|
||||
align-items: center;
|
||||
background:
|
||||
linear-gradient(135deg, rgb(15 23 42 / 92%), rgb(32 41 64 / 88%)),
|
||||
radial-gradient(circle at 72% 24%, rgb(20 184 166 / 38%), transparent 30%);
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
min-height: 178px;
|
||||
overflow: hidden;
|
||||
padding: 28px 32px;
|
||||
}
|
||||
|
||||
.eyebrow,
|
||||
.hero-actions,
|
||||
.card-header,
|
||||
.health-band div {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
color: rgb(204 251 241);
|
||||
font-size: 13px;
|
||||
gap: 8px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.hero-panel h1 {
|
||||
font-size: 28px;
|
||||
font-weight: 650;
|
||||
line-height: 1.25;
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.hero-panel p {
|
||||
color: rgb(226 232 240);
|
||||
line-height: 1.7;
|
||||
margin: 0;
|
||||
max-width: 680px;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
flex-shrink: 0;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.metric-grid {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.metric-card :deep(.el-card__body) {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.metric-icon {
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
height: 46px;
|
||||
justify-content: center;
|
||||
width: 46px;
|
||||
}
|
||||
|
||||
.metric-icon.agent {
|
||||
background: rgb(219 234 254);
|
||||
color: rgb(37 99 235);
|
||||
}
|
||||
|
||||
.metric-icon.workflow {
|
||||
background: rgb(204 251 241);
|
||||
color: rgb(13 148 136);
|
||||
}
|
||||
|
||||
.metric-icon.knowledge {
|
||||
background: rgb(254 243 199);
|
||||
color: rgb(180 83 9);
|
||||
}
|
||||
|
||||
.metric-icon.run {
|
||||
background: rgb(220 252 231);
|
||||
color: rgb(22 163 74);
|
||||
}
|
||||
|
||||
.metric-card span,
|
||||
.list-row small,
|
||||
.knowledge-item small {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.metric-card strong {
|
||||
display: block;
|
||||
font-size: 28px;
|
||||
line-height: 1.1;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.metric-card small {
|
||||
color: hsl(var(--muted-foreground));
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
grid-template-columns: minmax(0, 1.35fr) minmax(360px, 0.65fr);
|
||||
}
|
||||
|
||||
.content-grid.lower {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.panel-card {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.card-header span {
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.quick-grid {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.quick-entry,
|
||||
.admin-entry,
|
||||
.list-row,
|
||||
.run-item,
|
||||
.knowledge-item {
|
||||
background: hsl(var(--background));
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: 8px;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition:
|
||||
border-color 0.18s ease,
|
||||
box-shadow 0.18s ease,
|
||||
transform 0.18s ease;
|
||||
}
|
||||
|
||||
.quick-entry:hover,
|
||||
.admin-entry:hover,
|
||||
.list-row:hover,
|
||||
.run-item:hover,
|
||||
.knowledge-item:hover {
|
||||
border-color: hsl(var(--primary) / 55%);
|
||||
box-shadow: 0 8px 24px rgb(15 23 42 / 8%);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.quick-entry {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
min-height: 126px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.quick-entry svg {
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
|
||||
.quick-entry span,
|
||||
.admin-entry span,
|
||||
.knowledge-item strong {
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.quick-entry small {
|
||||
color: hsl(var(--muted-foreground));
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.admin-grid {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.admin-entry {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
height: 48px;
|
||||
padding: 0 14px;
|
||||
}
|
||||
|
||||
.admin-entry svg {
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
|
||||
.list-stack {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.list-stack.compact {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.list-row,
|
||||
.run-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
min-height: 62px;
|
||||
padding: 10px 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.list-row span,
|
||||
.run-item span,
|
||||
.knowledge-item span {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.list-row strong,
|
||||
.run-item strong,
|
||||
.knowledge-item strong {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.run-timeline {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.run-item {
|
||||
border: 0;
|
||||
min-height: 50px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.knowledge-strip {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.knowledge-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
min-height: 72px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.knowledge-item svg {
|
||||
color: hsl(var(--primary));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.health-band {
|
||||
background: hsl(var(--card));
|
||||
border: 1px solid hsl(var(--border));
|
||||
border-radius: 8px;
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.health-band div {
|
||||
color: hsl(var(--muted-foreground));
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.health-band svg {
|
||||
color: hsl(var(--primary));
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.metric-grid,
|
||||
.content-grid,
|
||||
.content-grid.lower,
|
||||
.health-band {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.hero-panel {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 18px;
|
||||
padding: 22px;
|
||||
}
|
||||
|
||||
.hero-panel h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.hero-actions,
|
||||
.hero-actions .el-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.metric-grid,
|
||||
.content-grid,
|
||||
.content-grid.lower,
|
||||
.quick-grid,
|
||||
.knowledge-strip,
|
||||
.health-band {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -17,7 +17,7 @@ const defaultPreferences: Preferences = {
|
||||
contentPaddingTop: 0,
|
||||
defaultAvatar:
|
||||
'https://unpkg.com/@vbenjs/static-source@0.1.7/source/avatar-v1.webp',
|
||||
defaultHomePath: '/ai-platform/agent',
|
||||
defaultHomePath: '/control-center',
|
||||
dynamicTitle: true,
|
||||
enableCheckUpdates: true,
|
||||
enablePreferences: true,
|
||||
|
||||
Reference in New Issue
Block a user