Add Database page with new connection feature

- Reorganize project structure: move frontend to web/ directory
- Add Database page with connection list (name, type, subtables, status, created, actions)
- Integrate Element Plus for UI components with dark theme support
- Add Quicksand font for rounded UI design
- Configure root package.json to run frontend from web/ directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 10:49:46 +08:00
parent 7f5781d4f1
commit 6d5ae6c604
22 changed files with 6774 additions and 32 deletions

View File

@@ -0,0 +1,139 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
const route = useRoute()
interface MenuItem {
name: string
icon: string
badge?: string | number
children?: MenuItem[]
path?: string
}
const mainMenu: MenuItem[] = [
{ name: 'Dashboard', icon: 'fa-gauge', path: '/dashboard' },
{ name: 'Agents', icon: 'fa-robot', badge: 3, path: '/agents' },
{ name: 'Skills', icon: 'fa-wand-magic-sparkles', badge: 21, path: '/mcp' },
{ name: 'Tools', icon: 'fa-tools', badge: 13, path: '/model-apis' },
{ name: 'Database', icon: 'fa-database', path: '/database' },
{ name: 'Knowledge', icon: 'fa-book' },
]
const bottomMenu: MenuItem[] = [
{ name: 'API Keys', icon: 'fa-key' },
{ name: 'Settings', icon: 'fa-gear' },
{ name: 'Team', icon: 'fa-users' },
{ name: 'Service Accounts', icon: 'fa-user-shield' },
{ name: 'Integrations', icon: 'fa-plug' },
]
const bottomMenu2: MenuItem[] = [
{ name: 'Information', icon: 'fa-circle-info' },
{ name: 'Account', icon: 'fa-user' },
]
const activeMenu = computed(() => {
const currentPath = route.path
const menuItem = mainMenu.find(item => item.path === currentPath)
return menuItem ? menuItem.name : 'Dashboard'
})
const navigateTo = (item: MenuItem) => {
if (item.path) {
router.push(item.path)
}
}
</script>
<template>
<aside class="w-64 bg-dark-950 h-screen flex flex-col fixed left-0 top-0 overflow-y-auto scrollbar-hide z-10">
<!-- 顶部Logo与组织信息 -->
<div class="p-5 flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-gradient-to-br from-primary-orange to-red-500 flex items-center justify-center">
<i class="fa-solid fa-basketball text-white"></i>
</div>
<div>
<div class="font-semibold text-base flex items-center gap-1 cursor-pointer">
Organization
<i class="fa-solid fa-chevron-down text-xs text-gray-500"></i>
</div>
<div class="text-sm text-gray-500">Saasfactor</div>
</div>
</div>
<!-- 导航菜单 -->
<nav class="flex-1 px-3 py-2">
<ul class="space-y-1">
<!-- Dashboard 激活项 -->
<li v-for="item in mainMenu" :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>
<!-- 分隔线 -->
<li class="my-4 border-t border-dark-500"></li>
<!-- API Keys -->
<li v-for="item in bottomMenu" :key="item.name">
<a
href="#"
class="flex items-center justify-between px-3 py-2.5 rounded-lg hover:bg-dark-600 text-gray-400 hover:text-white transition-colors text-sm"
>
<div class="flex items-center gap-3">
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
<span>{{ item.name }}</span>
</div>
<div v-if="item.name === 'Settings'" class="flex gap-1">
<span class="w-2 h-2 rounded-full bg-primary-orange"></span>
<span class="w-2 h-2 rounded-full bg-yellow-500"></span>
<span class="w-2 h-2 rounded-full bg-gray-500"></span>
</div>
<div v-else-if="item.name === 'Team'" class="flex gap-1">
<span class="w-2 h-2 rounded-full bg-primary-orange"></span>
<span class="w-2 h-2 rounded-full bg-blue-500"></span>
<span class="w-2 h-2 rounded-full bg-gray-500"></span>
</div>
</a>
</li>
<!-- 分隔线 -->
<li class="my-4 border-t border-dark-500"></li>
<!-- Information -->
<li v-for="item in bottomMenu2" :key="item.name">
<a
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"
>
<i :class="['fa-solid', item.icon, 'w-5', 'text-center']"></i>
<span>{{ item.name }}</span>
</a>
</li>
</ul>
</nav>
<!-- 底部用户信息 -->
<div class="p-4 border-t border-dark-500">
<div class="flex items-center gap-3">
<img src="https://picsum.photos/id/64/40/40" alt="User Avatar" class="w-8 h-8 rounded-full object-cover">
<div>
<div class="font-medium text-sm text-gray-300">Alex Smith</div>
<div class="text-xs text-gray-500">alex@gmail.com</div>
</div>
</div>
</div>
</aside>
</template>