feat: 新增 Account 和 Script 页面
- 添加 Account 账户页面 - 添加 Script 脚本页面 - 优化侧边栏,添加知识库数量显示 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref, onMounted } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { ElMessageBox } from 'element-plus'
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { fetchKnowledgeBases } from '@/views/knowledge/useKnowledge'
|
||||||
|
import { useDatabase } from '@/views/database/useDatabase'
|
||||||
|
|
||||||
// 下拉菜单展开状态
|
// 下拉菜单展开状态
|
||||||
const userDropdownVisible = ref(false)
|
const userDropdownVisible = ref(false)
|
||||||
@@ -9,6 +11,26 @@ const userDropdownVisible = ref(false)
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
// 获取 Knowledge 数量
|
||||||
|
const knowledgeCount = ref(0)
|
||||||
|
const fetchKnowledgeCount = async () => {
|
||||||
|
try {
|
||||||
|
const data = await fetchKnowledgeBases()
|
||||||
|
knowledgeCount.value = data?.length || 0
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to fetch knowledge count:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取 Database 数量
|
||||||
|
const { databases, fetchDatabases } = useDatabase()
|
||||||
|
const databaseCount = computed(() => databases.value?.length || 0)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchKnowledgeCount()
|
||||||
|
fetchDatabases()
|
||||||
|
})
|
||||||
|
|
||||||
interface MenuItem {
|
interface MenuItem {
|
||||||
name: string
|
name: string
|
||||||
icon: string
|
icon: string
|
||||||
@@ -17,13 +39,13 @@ interface MenuItem {
|
|||||||
path?: string
|
path?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const mainMenu: MenuItem[] = [
|
const mainMenu = computed<MenuItem[]>(() => [
|
||||||
{ name: 'Dashboard', icon: 'fa-gauge', path: '/dashboard' },
|
{ name: 'Dashboard', icon: 'fa-gauge', path: '/dashboard' },
|
||||||
{ name: 'Agents', icon: 'fa-robot', badge: 3, path: '/agents' },
|
{ name: 'Agents', icon: 'fa-robot', badge: 3, path: '/agents' },
|
||||||
{ name: 'Team', icon: 'fa-users', path: '/team' },
|
{ name: 'Script', icon: 'fa-code', path: '/script' },
|
||||||
{ name: 'Database', icon: 'fa-database', path: '/database' },
|
{ name: 'Database', icon: 'fa-database', path: '/database', badge: databaseCount.value },
|
||||||
{ name: 'Knowledge', icon: 'fa-brain', path: '/knowledge' },
|
{ name: 'Knowledge', icon: 'fa-brain', path: '/knowledge', badge: knowledgeCount.value },
|
||||||
]
|
])
|
||||||
|
|
||||||
const middleMenu: MenuItem[] = [
|
const middleMenu: MenuItem[] = [
|
||||||
{ name: 'Skills', icon: 'fa-wand-magic-sparkles', badge: 21, path: '/mcp' },
|
{ name: 'Skills', icon: 'fa-wand-magic-sparkles', badge: 21, path: '/mcp' },
|
||||||
@@ -35,17 +57,23 @@ const bottomMenu: MenuItem[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const bottomMenu2: MenuItem[] = [
|
const bottomMenu2: MenuItem[] = [
|
||||||
{ name: 'Account', icon: 'fa-user' },
|
{ name: 'Account', icon: 'fa-user', path: '/account' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const currentPath = route.path
|
const currentPath = route.path
|
||||||
// Check main menu
|
// Check main menu
|
||||||
const menuItem = mainMenu.find(item => item.path === currentPath)
|
const menuItem = mainMenu.value.find(item => item.path === currentPath)
|
||||||
if (menuItem) return menuItem.name
|
if (menuItem) return menuItem.name
|
||||||
// Check bottom menu
|
// Check middle menu (Skills, Tools)
|
||||||
|
const middleItem = middleMenu.find(item => item.path === currentPath)
|
||||||
|
if (middleItem) return middleItem.name
|
||||||
|
// Check bottom menu (Settings)
|
||||||
const bottomItem = bottomMenu.find(item => item.path === currentPath)
|
const bottomItem = bottomMenu.find(item => item.path === currentPath)
|
||||||
if (bottomItem) return bottomItem.name
|
if (bottomItem) return bottomItem.name
|
||||||
|
// Check bottomMenu2 (Account)
|
||||||
|
const bottomItem2 = bottomMenu2.find(item => item.path === currentPath)
|
||||||
|
if (bottomItem2) return bottomItem2.name
|
||||||
return 'Dashboard'
|
return 'Dashboard'
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -101,8 +129,8 @@ const handleUserCommand = (command: string) => {
|
|||||||
<!-- 导航菜单 -->
|
<!-- 导航菜单 -->
|
||||||
<nav class="flex-1 px-3 py-2">
|
<nav class="flex-1 px-3 py-2">
|
||||||
<ul class="space-y-1">
|
<ul class="space-y-1">
|
||||||
<!-- Dashboard 激活项 -->
|
<!-- Dashboard, Agents -->
|
||||||
<li v-for="item in mainMenu" :key="item.name">
|
<li v-for="item in mainMenu.slice(0, 2)" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
@@ -117,7 +145,26 @@ const handleUserCommand = (command: string) => {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- 分隔线 -->
|
<!-- 分隔线1 -->
|
||||||
|
<li class="my-4 border-t border-dark-500"></li>
|
||||||
|
|
||||||
|
<!-- Database, Knowledge -->
|
||||||
|
<li v-for="item in mainMenu.slice(2)" :key="item.name">
|
||||||
|
<a
|
||||||
|
href="#"
|
||||||
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
|
:class="activeMenu === item.name ? 'bg-dark-600 text-white' : 'text-gray-400 hover:bg-dark-600 hover:text-white'"
|
||||||
|
@click="navigateTo(item)"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
<span v-if="item.badge" class="bg-dark-500 text-xs px-2 py-0.5 rounded-full">{{ item.badge }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- 分隔线2 -->
|
||||||
<li class="my-4 border-t border-dark-500"></li>
|
<li class="my-4 border-t border-dark-500"></li>
|
||||||
|
|
||||||
<!-- Skills & Tools -->
|
<!-- Skills & Tools -->
|
||||||
@@ -136,9 +183,6 @@ const handleUserCommand = (command: string) => {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- 分隔线 -->
|
|
||||||
<li class="my-4 border-t border-dark-500"></li>
|
|
||||||
|
|
||||||
<!-- Settings -->
|
<!-- Settings -->
|
||||||
<li v-for="item in bottomMenu" :key="item.name">
|
<li v-for="item in bottomMenu" :key="item.name">
|
||||||
<a
|
<a
|
||||||
@@ -166,11 +210,14 @@ const handleUserCommand = (command: string) => {
|
|||||||
<li v-for="item in bottomMenu2" :key="item.name">
|
<li v-for="item in bottomMenu2" :key="item.name">
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
class="flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-dark-600 text-gray-400 hover:text-white transition-colors text-sm"
|
class="flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-sm"
|
||||||
|
:class="activeMenu === item.name ? 'bg-dark-600 text-white' : 'text-gray-400 hover:bg-dark-600 hover:text-white'"
|
||||||
@click="navigateTo(item)"
|
@click="navigateTo(item)"
|
||||||
>
|
>
|
||||||
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
|
<div class="flex items-center gap-3">
|
||||||
<span>{{ item.name }}</span>
|
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import Team from '@/views/Team.vue'
|
|||||||
import Skill from '@/views/Skill.vue'
|
import Skill from '@/views/Skill.vue'
|
||||||
import ModelAPIs from '@/views/ModelAPIs.vue'
|
import ModelAPIs from '@/views/ModelAPIs.vue'
|
||||||
import Database from '@/views/Database.vue'
|
import Database from '@/views/Database.vue'
|
||||||
|
import Script from '@/views/Script.vue'
|
||||||
import Knowledge from '@/views/Knowledge.vue'
|
import Knowledge from '@/views/Knowledge.vue'
|
||||||
import Settings from '@/views/Settings.vue'
|
import Settings from '@/views/Settings.vue'
|
||||||
|
import Account from '@/views/Account.vue'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
@@ -47,6 +49,11 @@ const router = createRouter({
|
|||||||
name: 'database',
|
name: 'database',
|
||||||
component: Database
|
component: Database
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/script',
|
||||||
|
name: 'script',
|
||||||
|
component: Script
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/knowledge',
|
path: '/knowledge',
|
||||||
name: 'knowledge',
|
name: 'knowledge',
|
||||||
@@ -56,6 +63,11 @@ const router = createRouter({
|
|||||||
path: '/settings',
|
path: '/settings',
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
component: Settings
|
component: Settings
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/account',
|
||||||
|
name: 'account',
|
||||||
|
component: Account
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
15
web/src/views/Account.vue
Normal file
15
web/src/views/Account.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Account 页面 - 占位
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6 min-h-screen">
|
||||||
|
<div class="flex items-center gap-2 mb-6">
|
||||||
|
<i class="fa-solid fa-user text-gray-400"></i>
|
||||||
|
<span class="font-medium">Account</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
Account management coming soon...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
15
web/src/views/Script.vue
Normal file
15
web/src/views/Script.vue
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// Script 页面 - 占位
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6 min-h-screen">
|
||||||
|
<div class="flex items-center gap-2 mb-6">
|
||||||
|
<i class="fa-solid fa-code text-gray-400"></i>
|
||||||
|
<span class="font-medium">Script</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400">
|
||||||
|
Script management coming soon...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user