chore: 提交所有工作进度 — SaaS 后端增强、Admin UI、桌面端集成

包含大量 SaaS 平台改进、Admin 管理后台更新、桌面端集成完善、
文档同步、测试文件重构等内容。为 QA 测试准备干净工作树。
This commit is contained in:
iven
2026-03-29 10:46:26 +08:00
parent 9a5fad2b59
commit 5fdf96c3f5
268 changed files with 22011 additions and 3886 deletions

View File

@@ -13,6 +13,8 @@ import {
ArrowLeftRight,
Settings,
FileText,
MessageSquare,
Bot,
LogOut,
ChevronLeft,
Menu,
@@ -22,16 +24,44 @@ import { AuthGuard, useAuth } from '@/components/auth-guard'
import { logout } from '@/lib/auth'
import { cn } from '@/lib/utils'
/** 权限常量 — 与后端 db.rs SEED_ROLES 保持同步 */
const ROLE_PERMISSIONS: Record<string, string[]> = {
super_admin: ['admin:full', 'account:admin', 'provider:manage', 'model:manage', 'relay:admin', 'config:write', 'prompt:read', 'prompt:write', 'prompt:publish', 'prompt:admin'],
admin: ['account:read', 'account:admin', 'provider:manage', 'model:read', 'model:manage', 'relay:use', 'relay:admin', 'config:read', 'config:write', 'prompt:read', 'prompt:write', 'prompt:publish'],
user: ['model:read', 'relay:use', 'config:read', 'prompt:read'],
}
/** 从后端获取权限列表(运行时同步) */
async function fetchRolePermissions(role: string): Promise<string[]> {
try {
const res = await fetch('/api/v1/roles/' + role)
if (res.ok) {
const data = await res.json()
return data.permissions || []
}
return ROLE_PERMISSIONS[role] ?? []
} catch {
return ROLE_PERMISSIONS[role] ?? []
}
}
/** 根据 role 获取权限列表 */
function getPermissionsForRole(role: string): string[] {
return ROLE_PERMISSIONS[role] ?? []
}
const navItems = [
{ href: '/', label: '仪表盘', icon: LayoutDashboard },
{ href: '/accounts', label: '账号管理', icon: Users },
{ href: '/providers', label: '服务商', icon: Server },
{ href: '/models', label: '模型管理', icon: Cpu },
{ href: '/api-keys', label: 'API 密钥', icon: Key },
{ href: '/usage', label: '用量统计', icon: BarChart3 },
{ href: '/relay', label: '中转任务', icon: ArrowLeftRight },
{ href: '/config', label: '系统配置', icon: Settings },
{ href: '/logs', label: '操作日志', icon: FileText },
{ href: '/accounts', label: '账号管理', icon: Users, permission: 'account:admin' },
{ href: '/providers', label: '服务商', icon: Server, permission: 'provider:manage' },
{ href: '/models', label: '模型管理', icon: Cpu, permission: 'model:read' },
{ href: '/agent-templates', label: 'Agent 模板', icon: Bot, permission: 'model:read' },
{ href: '/api-keys', label: 'API 密钥', icon: Key, permission: 'admin:full' },
{ href: '/usage', label: '用量统计', icon: BarChart3, permission: 'admin:full' },
{ href: '/relay', label: '中转任务', icon: ArrowLeftRight, permission: 'relay:use' },
{ href: '/config', label: '系统配置', icon: Settings, permission: 'config:read' },
{ href: '/prompts', label: '提示词管理', icon: MessageSquare, permission: 'prompt:read' },
{ href: '/logs', label: '操作日志', icon: FileText, permission: 'admin:full' },
]
function Sidebar({
@@ -45,11 +75,18 @@ function Sidebar({
const router = useRouter()
const { account } = useAuth()
const permissions = account ? getPermissionsForRole(account.role) : []
function handleLogout() {
logout()
router.replace('/login')
}
const filteredNavItems = navItems.filter((item) => {
if (!item.permission) return true
return permissions.includes(item.permission) || permissions.includes('admin:full')
})
return (
<aside
className={cn(
@@ -75,7 +112,7 @@ function Sidebar({
{/* 导航 */}
<nav className="flex-1 overflow-y-auto scrollbar-thin py-2 px-2">
<ul className="space-y-1">
{navItems.map((item) => {
{filteredNavItems.map((item) => {
const isActive =
item.href === '/'
? pathname === '/'