优化前端控制台样式并更新文档

This commit is contained in:
2026-05-21 00:25:39 +08:00
parent d3f1f97a83
commit 387681a6ab
6 changed files with 235 additions and 60 deletions

View File

@@ -82,7 +82,25 @@
### 3.4 管理控制台模块 ### 3.4 管理控制台模块
后续需要一个前端控制台,至少覆盖: 当前已经建立基于 Vue 3、Vite、Element Plus 的前端控制台基础骨架。
已具备的页面与布局:
- 左侧管理菜单与品牌区
- 工作台入口
- 系统枚举管理页
- 附件管理入口
- 知识库入口
- 知识文档入口
当前样式约定:
- 管理控制台定位为后台工具界面,优先保证信息密度、可扫描性和稳定布局。
- 主内容区域只保留页面自身标题,避免外层布局和页面面板重复展示标题。
- 页面统一使用 `page-panel` 作为内容容器,侧边栏、页面面板、工具栏和表格使用统一边框、背景和主色变量。
- 系统枚举页工具栏采用响应式布局,桌面端保持查询项和操作按钮分区,窄屏时纵向排列。
后续控制台至少继续覆盖:
- 枚举管理 - 枚举管理
- 附件管理 - 附件管理
@@ -159,6 +177,8 @@
6. 补前端控制台 6. 补前端控制台
当前前端控制台已经完成基础骨架和系统枚举页面样式优化,后续重点应转向附件、知识库、知识文档页面的业务闭环。
## 7. 下一步建议 ## 7. 下一步建议
结合当前代码状态,接下来建议重点做: 结合当前代码状态,接下来建议重点做:
@@ -168,6 +188,7 @@
- 完善 `rag_store` / `rag_document` 的增删改查 - 完善 `rag_store` / `rag_document` 的增删改查
- 增加知识库文档上传并自动关联附件 - 增加知识库文档上传并自动关联附件
- 为后续切片与向量化预留任务入口 - 为后续切片与向量化预留任务入口
- 补齐前端附件、知识库、知识文档页面的表单、列表和接口联调
## 8. 文档用途说明 ## 8. 文档用途说明

View File

@@ -3,8 +3,8 @@
Common Agent 是一个规划中的通用 Agent 平台,技术路线基于 Java、Spring Boot 和 Spring AI。 Common Agent 是一个规划中的通用 Agent 平台,技术路线基于 Java、Spring Boot 和 Spring AI。
项目目标是建设一套完整的前后端系统,支持 Agent 编排、工具调用、会话管理、RAG 知识库和平台管理能力。 项目目标是建设一套完整的前后端系统,支持 Agent 编排、工具调用、会话管理、RAG 知识库和平台管理能力。
当前项目处于基础工程阶段。后端骨架、PostgreSQL 配置、MyBatis-Plus、Lombok多环境配置文件已经完成; 当前项目处于基础工程阶段。后端骨架、PostgreSQL 配置、MyBatis-Plus、Lombok多环境配置文件和前端控制台基础页面已经完成;
Agent 运行时、RAG 索引、前端页面和管理功能会在后续阶段逐步实现。 Agent 运行时、RAG 索引和更多管理功能会在后续阶段逐步实现。
## 项目愿景 ## 项目愿景
@@ -31,6 +31,11 @@ Common Agent 希望成为一个可复用的企业级 AI 应用基础平台:
```text ```text
common_agent common_agent
├── frontend
│ ├── src/layouts
│ ├── src/pages
│ ├── src/router
│ └── src/styles
├── src/main/java/com/bruce ├── src/main/java/com/bruce
│ └── CommonAgentApplication.java │ └── CommonAgentApplication.java
├── src/main/resources ├── src/main/resources
@@ -99,10 +104,30 @@ npm run dev
```powershell ```powershell
cd frontend cd frontend
npm run test:unit
npm run type-check npm run type-check
npm run build npm run build
``` ```
## 前端控制台
前端控制台位于 `frontend` 目录,当前使用 Vue 3、Vite、Pinia、Vue Router 和 Element Plus。
当前已有页面:
- 工作台
- 系统枚举
- 附件管理
- 知识库
- 知识文档
当前 UI 规范:
- 左侧为固定管理导航,右侧为主内容区。
- 主内容区不再额外渲染外层页面标题,标题由各业务页面面板自行展示。
- 全局样式集中在 `frontend/src/styles/global.css`,页面专属样式优先放在对应 `.vue` 文件的 scoped style 中。
- 后台页面以清晰、克制、便于扫描为优先目标,避免营销式大面积装饰。
## 规划模块 ## 规划模块
- `agent-core`Agent 执行模型、工具注册、记忆和编排能力。 - `agent-core`Agent 执行模型、工具注册、记忆和编排能力。

View File

@@ -7,15 +7,6 @@ import {
Files, Files,
Grid, Grid,
} from '@element-plus/icons-vue'; } from '@element-plus/icons-vue';
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useAppStore } from '@/stores/app';
const route = useRoute();
const appStore = useAppStore();
const pageTitle = computed(() => String(route.meta.title ?? 'Common Agent'));
const menuItems = [ const menuItems = [
{ path: '/dashboard', label: '工作台', icon: DataBoard }, { path: '/dashboard', label: '工作台', icon: DataBoard },
@@ -47,13 +38,6 @@ const menuItems = [
</el-aside> </el-aside>
<el-container> <el-container>
<el-header class="admin-header">
<div>
<h1>{{ pageTitle }}</h1>
<p>{{ appStore.environmentName }}</p>
</div>
</el-header>
<el-main class="admin-main"> <el-main class="admin-main">
<RouterView /> <RouterView />
</el-main> </el-main>

View File

@@ -0,0 +1,29 @@
import { mount } from '@vue/test-utils';
import ElementPlus from 'element-plus';
import { createPinia } from 'pinia';
import { describe, expect, it, vi } from 'vitest';
import AdminLayout from '../AdminLayout.vue';
vi.mock('vue-router', () => ({
useRoute: () => ({ meta: { title: '系统枚举' } }),
}));
describe('AdminLayout', () => {
it('does not render a duplicate page header above the main page content', () => {
const wrapper = mount(AdminLayout, {
global: {
plugins: [createPinia(), ElementPlus],
mocks: {
$route: { path: '/system/enums' },
},
stubs: {
RouterView: { template: '<main data-test="router-view" />' },
},
},
});
expect(wrapper.find('.admin-header').exists()).toBe(false);
expect(wrapper.find('[data-test="router-view"]').exists()).toBe(true);
});
});

View File

@@ -358,28 +358,58 @@ onMounted(loadEnums);
} }
.enum-toolbar { .enum-toolbar {
display: flex; display: grid;
align-items: flex-start; grid-template-columns: minmax(0, 1fr) auto;
justify-content: space-between; align-items: start;
gap: 16px; gap: 16px;
padding: 16px 18px 4px; padding: 18px 22px 8px;
border-bottom: 1px solid #eef2f7;
background: #ffffff;
}
.enum-toolbar :deep(.el-form) {
display: flex;
flex-wrap: wrap;
gap: 0 14px;
} }
.enum-toolbar :deep(.el-form-item) { .enum-toolbar :deep(.el-form-item) {
margin-bottom: 12px; margin-right: 0;
margin-bottom: 10px;
}
.enum-toolbar :deep(.el-form-item__label) {
color: #475467;
font-weight: 600;
} }
.enum-toolbar :deep(.el-input) { .enum-toolbar :deep(.el-input) {
width: 180px; width: 196px;
} }
.enum-table { .enum-table {
width: 100%; width: 100%;
} }
.enum-table :deep(.el-table__header-wrapper th) {
background: #f8fafc;
color: #667085;
font-weight: 700;
}
.enum-table :deep(.el-table__row td) {
color: #344054;
}
.enum-table :deep(.el-table__row:hover td) {
background: #f8fbff;
}
.enum-actions { .enum-actions {
display: flex; display: flex;
justify-content: flex-end;
gap: 8px; gap: 8px;
padding-top: 1px;
} }
.batch-base { .batch-base {
@@ -401,4 +431,37 @@ onMounted(loadEnums);
.batch-table { .batch-table {
width: 100%; width: 100%;
} }
@media (max-width: 1080px) {
.enum-toolbar {
grid-template-columns: 1fr;
}
.enum-actions {
justify-content: flex-start;
}
}
@media (max-width: 768px) {
.enum-toolbar {
padding: 14px 16px 8px;
}
.enum-toolbar :deep(.el-form) {
display: grid;
grid-template-columns: 1fr;
}
.enum-toolbar :deep(.el-input) {
width: 100%;
}
.enum-actions {
flex-wrap: wrap;
}
.batch-base {
grid-template-columns: 1fr;
}
}
</style> </style>

View File

@@ -1,6 +1,13 @@
:root { :root {
--app-bg: #f5f7fb;
--app-border: #e3e8f0;
--app-border-soft: #eef2f7;
--app-primary: #1677ff;
--app-primary-soft: #eaf3ff;
--app-text: #172033;
--app-text-muted: #667085;
color: #1f2937; color: #1f2937;
background: #f4f6f8; background: var(--app-bg);
font-family: font-family:
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif; sans-serif;
@@ -27,90 +34,96 @@ a {
.admin-layout { .admin-layout {
min-height: 100vh; min-height: 100vh;
background: var(--app-bg);
} }
.admin-sidebar { .admin-sidebar {
border-right: 1px solid #d9dee7; border-right: 1px solid var(--app-border);
background: #ffffff; background: #ffffff;
box-shadow: 1px 0 0 rgba(15, 23, 42, 0.02);
} }
.brand { .brand {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
height: 64px; height: 72px;
padding: 0 18px; padding: 0 22px;
border-bottom: 1px solid #e5e9f0; border-bottom: 1px solid var(--app-border-soft);
color: #182433; color: var(--app-text);
font-size: 17px; font-size: 17px;
font-weight: 700; font-weight: 700;
} }
.brand .el-icon {
color: var(--app-primary);
}
.side-menu { .side-menu {
border-right: 0; border-right: 0;
padding: 10px 8px; padding: 14px 12px;
} }
.side-menu .el-menu-item { .side-menu .el-menu-item {
height: 42px; height: 44px;
border-radius: 6px; border-radius: 8px;
margin-bottom: 4px; margin-bottom: 4px;
color: #344054;
font-size: 15px;
} }
.admin-header { .side-menu .el-menu-item:hover {
display: flex; background: #f3f7fd;
align-items: center;
height: 64px;
border-bottom: 1px solid #d9dee7;
background: #ffffff;
} }
.admin-header h1 { .side-menu .el-menu-item.is-active {
margin: 0; background: var(--app-primary-soft);
color: #172033; color: var(--app-primary);
font-size: 18px;
font-weight: 700; font-weight: 700;
letter-spacing: 0;
} }
.admin-header p { .side-menu .el-menu-item .el-icon {
margin: 4px 0 0; font-size: 18px;
color: #667085;
font-size: 12px;
} }
.admin-main { .admin-main {
padding: 20px; min-width: 0;
background: #f4f6f8; padding: 24px;
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0) 180px),
var(--app-bg);
} }
.page-panel { .page-panel {
min-height: calc(100vh - 104px); min-height: calc(100vh - 48px);
border: 1px solid #d9dee7; border: 1px solid var(--app-border);
border-radius: 6px; border-radius: 8px;
background: #ffffff; background: #ffffff;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
} }
.page-panel__header { .page-panel__header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
min-height: 56px; min-height: 64px;
padding: 0 18px; padding: 0 22px;
border-bottom: 1px solid #edf0f4; border-bottom: 1px solid var(--app-border-soft);
background: linear-gradient(180deg, #ffffff, #fbfcff);
} }
.page-panel__header h2 { .page-panel__header h2 {
margin: 0; margin: 0;
color: #1f2937; color: var(--app-text);
font-size: 16px; font-size: 18px;
font-weight: 700; font-weight: 700;
letter-spacing: 0; letter-spacing: 0;
} }
.page-panel__header span { .page-panel__header span {
color: #768195; color: var(--app-text-muted);
font-size: 12px; font-size: 12px;
font-weight: 600;
} }
.not-found { .not-found {
@@ -126,3 +139,43 @@ a {
font-size: 48px; font-size: 48px;
letter-spacing: 0; letter-spacing: 0;
} }
@media (max-width: 768px) {
.admin-layout {
display: block;
}
.admin-sidebar {
width: 100% !important;
border-right: 0;
border-bottom: 1px solid var(--app-border);
}
.brand {
height: 60px;
}
.side-menu {
display: flex;
overflow-x: auto;
padding: 10px 12px;
}
.side-menu .el-menu-item {
flex: 0 0 auto;
margin: 0 6px 0 0;
}
.admin-main {
padding: 14px;
}
.page-panel {
min-height: calc(100vh - 148px);
}
.page-panel__header {
min-height: 58px;
padding: 0 16px;
}
}