@@ -45,6 +38,7 @@
+
+
+
+
diff --git a/eai_agentplatform/frontend/src/config/nav.js b/eai_agentplatform/frontend/src/config/nav.js
new file mode 100644
index 0000000..26a9975
--- /dev/null
+++ b/eai_agentplatform/frontend/src/config/nav.js
@@ -0,0 +1,172 @@
+// 统一导航模型。
+//
+// 侧边栏只承载一级导航(navSections 里的每一项)。一级项下面有两种展开方式:
+// - groups:这一项里还分几个 tab(专员 / 工具 / 连接器),SectionTabs 先画一行
+// 组 tab,再画当前组自己的页面 tab。
+// - items:直接就是一行页面 tab。
+// 之前的 sidebarGroups / LibraryTabs / ExamTabs 三份重复清单收敛到这里。
+import { Avatar, EditPen, Files, Menu, Monitor } from '@element-plus/icons-vue'
+import { businessApps } from '@/config/workbench'
+
+// 专员 / 工具 / 连接器 合起来是一个一级项 —— 侧边栏只占一行,进去是三个 tab。
+// 照 WorkBuddy 的「专家·技能·连接器」那一格:那一行本身就是个容器,
+// 名字就是把里面三格念一遍。
+const capabilityGroups = [
+ {
+ key: 'specialists',
+ label: '专员',
+ items: [
+ { label: '我的专员', route: '/apps' },
+ { label: '专员市场', route: '/market' },
+ // 每个专员是「我的专员」选择器里的一张卡片,不在 tab 条里铺开
+ // (hiddenInTabs),但登记在这里:搜索、路由归属、+ 菜单都认得出它们。
+ ...businessApps.map((app) => ({
+ label: app.label,
+ route: app.route,
+ hiddenInTabs: true,
+ })),
+ ],
+ },
+ {
+ key: 'tools',
+ label: '工具',
+ items: [
+ { label: '智能助手', route: '/home' },
+ { label: '文档翻译', route: '/tools/document-translate' },
+ { label: '文案校对', route: '/tools/copy-proofreading' },
+ { label: '语音转写', route: '/tools/audio-transcribe' },
+ { label: '批量提取', route: '/tools/batch-extract' },
+ { label: '合同审查', route: '/tools/contract-review' },
+ { label: '报告生成', route: '/report-gen' },
+ ],
+ },
+ {
+ key: 'connectors',
+ label: '连接器',
+ // 这一格对所有人开放,进去是只读的连接器清单。后续的增删改、凭据轮换、
+ // 健康监控再加 adminOnly 的项,普通用户看到的仍然只有这一条。
+ items: [{ label: '可用连接器', route: '/console' }],
+ },
+]
+
+export const navSections = [
+ {
+ key: 'ai-capability',
+ label: '专员·工具·连接器',
+ icon: Avatar,
+ groups: capabilityGroups,
+ // 三个组摊平。搜索和「当前路由属于哪个一级项」都读这一份,
+ // 不用再去 groups 里翻。
+ items: capabilityGroups.flatMap((group) => group.items),
+ },
+ {
+ key: 'exam',
+ label: 'AI考试',
+ icon: EditPen,
+ items: [
+ { label: '自测练习', route: '/exam/self-test' },
+ { label: '正式考试', route: '/exam/formal' },
+ { label: '我的记录', route: '/exam/my-records' },
+ { label: '错题本', route: '/exam/my-mistakes' },
+ { label: '我的证书', route: '/exam/my-certificates' },
+ { label: '岗位应学', route: '/exam/my-position' },
+ { label: '排行榜', route: '/exam/leaderboard' },
+ ],
+ },
+ {
+ key: 'knowledge',
+ label: '资料库',
+ icon: Files,
+ items: [
+ { label: '素材管理', route: '/knowledge/materials' },
+ { label: '素材审批', route: '/knowledge/audit' },
+ { label: '题库管理', route: '/knowledge/questions' },
+ { label: '成绩查询', route: '/knowledge/exam-records' },
+ { label: '知识库应用', route: '/knowledge-hub' },
+ { label: '知识库管理', route: '/knowledge-management', adminOnly: true },
+ { label: '产品知识', route: '/products' },
+ { label: '销售培训', route: '/courses' },
+ { label: '公司介绍', route: '/company-train' },
+ ],
+ },
+ {
+ key: 'admin',
+ label: '后台管理',
+ icon: Monitor,
+ items: [
+ { label: '工坊', route: '/studio', adminOnly: true },
+ { label: '用户管理', route: '/system/users', adminOnly: true },
+ { label: '部门管理', route: '/system/departments', adminOnly: true },
+ { label: '岗位管理', route: '/system/positions', adminOnly: true },
+ { label: '公司配置', route: '/system/company-config', adminOnly: true },
+ { label: '系统配置', route: '/system/config', adminOnly: true },
+ { label: 'AI 用量', route: '/system/ai-usage', adminOnly: true },
+ ],
+ },
+ {
+ key: 'me',
+ label: '我的',
+ icon: Menu,
+ items: [
+ { label: '工作台总览', route: '/overview' },
+ { label: '我的资料', route: '/exam/my-profile' },
+ ],
+ },
+]
+
+// 一级导航的落地页:有 groups 的落在第一个组的第一项,否则落在第一个二级项。
+export function sectionHomeRoute(section) {
+ if (!section) return '/home'
+ if (section.groups?.length) {
+ const first = section.groups.find((group) => group.items.length)
+ if (first) return first.items[0].route
+ }
+ return section.items?.[0]?.route || '/home'
+}
+
+// 顶部那排胶囊是「一级粒度」的:一个一级项一个胶囊,点它回到这个一级项的首页。
+// 之前是每个具体页面一个胶囊(文档翻译、文案校对…各占一个),走两步就铺满一整排。
+// sectionKey 记下来是给高亮用的 —— 胶囊的 route 是首页,但人可能停在组里任意一页。
+export function sectionTabFor(section) {
+ if (!section) return null
+ return {
+ route: sectionHomeRoute(section),
+ label: section.label,
+ sectionKey: section.key,
+ closable: true,
+ }
+}
+
+// 路由 → 一级导航。先精确匹配二级项,再按前缀兜底 —— 前缀兜底必须排在后面,
+// 否则 /exam/my-profile(属于「我的」)会被「AI考试」的 /exam 前缀抢走。
+export function findSectionByPath(sections, path) {
+ for (const section of sections) {
+ if (section.items.some((item) => item.route === path)) return section
+ }
+ for (const section of sections) {
+ if (section.items.some((item) => path.startsWith(`${item.route}/`))) return section
+ }
+ return null
+}
+
+// 路由 → 它落在哪个 tab 组里(只有分组的一级项才有)。
+export function findGroupByPath(section, path) {
+ if (!section?.groups) return null
+ for (const group of section.groups) {
+ if (group.items.some((item) => item.route === path)) return group
+ }
+ for (const group of section.groups) {
+ if (group.items.some((item) => path.startsWith(`${item.route}/`))) return group
+ }
+ return null
+}
+
+// 搜索用的扁平列表,带上组名当副标题。
+export function sectionEntries(section) {
+ if (section?.groups?.length) {
+ return section.groups.flatMap((group) =>
+ group.items.map((item) => ({ ...item, group: group.label }))
+ )
+ }
+ return (section?.items || []).map((item) => ({ ...item, group: '' }))
+}
diff --git a/eai_agentplatform/frontend/src/config/workbench.js b/eai_agentplatform/frontend/src/config/workbench.js
index 90abbe5..dedd4fd 100644
--- a/eai_agentplatform/frontend/src/config/workbench.js
+++ b/eai_agentplatform/frontend/src/config/workbench.js
@@ -1,3 +1,19 @@
+// 智能助手的模式。输入框上方的胶囊和输入框 + 菜单里的「模式」读的是同一份,
+// 两个入口改的是同一个状态,不会各说各话。
+export const assistantModes = [
+ // 首页大标题下面原来有一行副标题写着同样的话,重复了 —— 去掉那一行,
+ // 把 @ / 这两个真用得上的提示挪进 placeholder,一行说完。
+ { key: 'chat', label: '对话', icon: '💬', desc: '默认对话模式,直接回答你的问题。', placeholder: '@ 引用对话文件,/ 调用技能与指令' },
+ { key: 'task', label: '任务拆解', icon: '📋', desc: '把一件事拆成可执行的步骤。', placeholder: '输入需要拆解的任务...' },
+ { key: 'copy', label: '文案生成', icon: '✏️', desc: '按你要的类型生成文案。', placeholder: '输入需要生成的文案类型...' },
+ { key: 'extract', label: '批量提取', icon: '📊', desc: '从文档里批量抽出字段。', placeholder: '输入包含字段的文档内容...' },
+]
+
+// 连接器:目前只有控制台一页,后续的增删改、凭据轮换、健康监控都落在这里。
+export const connectors = [
+ { key: 'console', label: '控制台', caption: '连接器状态、凭据与健康监控', route: '/console' },
+]
+
// AI 工具(Chat-First 主入口)—— 全部走 ChatLayout 聊天优先界面
export const chatTools = [
{ key: 'smart-assistant', label: '智能助手', caption: '对话 / 任务拆解 / 文案生成', route: '/home' },
@@ -9,25 +25,6 @@ export const chatTools = [
{ key: 'report-generation', label: '报告生成', caption: '日报 / 周报 / 复盘', route: '/report-gen' },
]
-export const topNavItems = [
- { key: 'chat-tools', label: 'AI 工具', title: 'AI 工具', route: '/home' },
- { key: 'ziliaoku', label: '字料库', title: '字料库', route: '/knowledge-hub' },
- { key: 'apps', label: '专员工作区', title: '专员工作区', route: '/home' },
- { key: 'market', label: '专员市场', title: '专员市场', route: '/market', adminOnly: true },
- { key: 'studio', label: '工坊', title: '工坊', route: '/studio', adminOnly: true },
- { key: 'console', label: '控制台', title: '控制台', route: '/console', adminOnly: true },
-]
-
-// 字料库子级 Tab 导航(用于页面内 tab 切换)
-export const ziliaokuTabs = [
- { key: 'chat-search', label: '知识问答', route: '/knowledge-hub' },
- { key: 'knowledge-admin', label: '知识管理', route: '/knowledge-management' },
- { key: 'product', label: '产品知识', route: '/products' },
- { key: 'sales', label: '销售培训', route: '/courses' },
- { key: 'company', label: '公司介绍', route: '/company-train' },
- { key: 'materials', label: '素材审批', route: '/knowledge/material-approve' },
-]
-
export const businessApps = [
{
key: 'contract-review',
@@ -171,55 +168,12 @@ export const businessApps = [
},
]
-export const knowledgeLinks = [
- { label: '知识库应用', route: '/knowledge-hub', caption: 'Chat / Search / Upload' },
- { label: '知识库管理', route: '/knowledge-management', caption: 'Spaces / Docs / Chunks', adminOnly: true },
- { label: '产品知识', route: '/products', caption: '现有知识内容' },
- { label: '销售培训', route: '/courses', caption: '课程与训练' },
- { label: '公司介绍', route: '/company-train', caption: '组织基础资料' },
-]
-
export const backendLinks = [
{ label: '专员市场', route: '/market', adminOnly: true },
{ label: '工坊', route: '/studio', adminOnly: true },
{ label: '控制台', route: '/console', adminOnly: true },
]
-export const secondaryNavItems = {
- market: [
- { label: '已安装专员', route: '/market' },
- { label: '可升级专员', route: '/market' },
- { label: '模板资产', route: '/market' },
- ],
- studio: [
- { label: '画布创建', route: '/studio' },
- { label: 'DW 模板', route: '/studio' },
- { label: '发布记录', route: '/studio' },
- ],
- 'knowledge-app': [
- { label: '对话工作台', route: '/knowledge-hub' },
- { label: '产品知识', route: '/products' },
- { label: '销售培训', route: '/courses' },
- { label: '公司介绍', route: '/company-train' },
- ],
- 'knowledge-admin': [
- { label: '知识空间', route: '/knowledge-management' },
- { label: '文档管理', route: '/knowledge-management' },
- { label: '审批发布', route: '/knowledge-management' },
- { label: '质量运营', route: '/knowledge-management' },
- ],
- console: [
- { label: '连接器健康', route: '/console' },
- { label: '资源用量', route: '/console' },
- { label: '权限管理', route: '/console' },
- { label: '运行日志', route: '/console' },
- ],
-}
-
-export function getSecondaryNav(surface) {
- return secondaryNavItems[surface] || []
-}
-
const appWorkspaceData = {
'contract-review': {
title: '合同审查专员',
@@ -767,10 +721,6 @@ export function getMarketItemsByTier(tier) {
}))
}
-export function getVisibleTopNavItems(isAdmin) {
- return topNavItems.filter((item) => !item.adminOnly || isAdmin)
-}
-
export function getVisibleBackendLinks(isAdmin) {
return backendLinks.filter((item) => !item.adminOnly || isAdmin)
}
diff --git a/eai_agentplatform/frontend/src/layout/MainLayout.vue b/eai_agentplatform/frontend/src/layout/MainLayout.vue
index ee49731..451c937 100644
--- a/eai_agentplatform/frontend/src/layout/MainLayout.vue
+++ b/eai_agentplatform/frontend/src/layout/MainLayout.vue
@@ -3,42 +3,144 @@