forked from xiaohei/taiji-pda-v0
- 删除重复文件:components/ui/use-toast.ts 和 components/ui/use-mobile.tsx - 统一 getAuthToken() 函数,在 api-client.ts 中导入并删除重复定义 - 创建 clearAllTokens() 工具函数,统一 token 清除逻辑 - 修复 Toast 延迟时间(从 1000000ms 改为 5000ms) - 修复 TypeScript 类型错误:在 applicationForm 中添加 providerId 字段 - 修复登录路径:使用 super_admin 角色登录超级管理员 - 移除登录前的后端可达性检查(避免浏览器环境问题) - 在管理用户对话框中添加租户角色修改功能(租户/计费管理员/运营管理员) - 移除管理用户对话框中的用户数字段(用户层面不应显示用户数) - 在设置页面添加当前渠道管理员列表显示功能 - 添加获取和创建渠道管理员的 API 方法 - 更新登录方法的角色类型定义,支持所有角色类型
17 KiB
17 KiB
Taiji AI Platform 前端代码优化建议
📌 概述
本文档基于对整个前端项目的代码审查,提出了架构优化、代码质量改进和最佳实践建议。
🔴 高优先级问题
1. API 客户端逻辑错误
问题位置: lib/api-client.ts(第1000+行)
具体问题:
// ❌ 错误的删除Agent接口
static async deleteTool(toolId: string) {
const response = await fetch(
`${API_BASE_URLS.dataIngestion}/api/tools/delete?id=${toolId}`,
{ method: "DELETE", headers: buildHeaders() }
)
return handleResponse(response)
}
为什么这是错的:
- 调用的是 Data Ingestion 服务的删除工具接口,不是 MCP Server 的删除 Agent 接口
- 在前端 Agent 管理页面中被错误使用
- 参数格式不符合 RESTful 最佳实践(应该在路径中,不是查询字符串)
修复方案:
/**
* 删除Agent资源(超级管理员)
*/
static async deleteAdminAgent(agentId: string) {
const response = await fetch(
`${API_BASE_URLS.mcpServer}/api/admin/resources/agents/${agentId}`,
{
method: "DELETE",
headers: buildHeaders(),
}
)
return handleResponse(response)
}
/**
* 删除用户自定义Agent
*/
static async deleteUserAgent(agentId: string) {
const response = await fetch(
`${API_BASE_URLS.mcpServer}/api/user/agents/${agentId}`,
{
method: "DELETE",
headers: buildHeaders(),
}
)
return handleResponse(response)
}
/**
* 删除工具(Data Ingestion 服务)
*/
static async deleteTool(toolId: string) {
const response = await fetch(
`${API_BASE_URLS.dataIngestion}/api/tools/${toolId}`,
{
method: "DELETE",
headers: buildHeaders(),
}
)
return handleResponse(response)
}
影响的文件:
app/admin/dashboard/page.tsx- ResourcesTab 组件app/agent-factory/page.tsx- Agent 删除功能
2. 缺失的 API 实现
问题: 前端代码调用了后端没有实现的 API
2.1 删除渠道接口
前端代码:
// app/admin/dashboard/page.tsx
const handleDeleteChannel = async (channelId: string) => {
// 当前没有实现,但UI中有删除按钮
}
需要实现: DELETE /api/admin/channels/{channelId}
后端建议:
@router.delete("/channels/{channel_id}", tags=["admin"])
async def delete_channel(
channel_id: str,
current_user: User = Depends(get_current_user),
session: AsyncSession = Depends(get_session)
):
"""删除渠道(软删除)"""
# 1. 验证超级管理员权限
# 2. 检查是否有活跃租户
# 3. 软删除渠道(更新status字段)
# 4. 返回成功响应
2.2 更新渠道接口
前端代码:
// app/admin/dashboard/page.tsx
const handleUpdateChannel = async (channelId: string, data: any) => {
// 当前没有实现
}
需要实现: PUT /api/admin/channels/{channelId}
2.3 工作流相关接口
缺失接口:
GET /api/user/workflows- 获取用户工作流列表GET /api/user/workflows/{workflowId}- 获取工作流详情PUT /api/user/workflows/{workflowId}- 更新工作流DELETE /api/user/workflows/{workflowId}- 删除工作流POST /api/user/workflows/{workflowId}/execute- 执行工作流
🟡 中优先级问题
3. API 客户端架构问题
问题: lib/api-client.ts 已有 1443 行,单一责任原则违反
当前状况:
api-client.ts: 1443 行
├── 认证相关: ~200 行
├── 用户接口: ~400 行
├── 渠道接口: ~300 行
├── 管理员接口: ~300 行
└── 工具函数: ~100 行
建议方案 - 分离为多个模块:
lib/
├── api-client.ts (基础工具和导出)
├── api/
│ ├── auth.ts (认证相关)
│ ├── user.ts (用户接口)
│ ├── channel.ts (渠道接口)
│ ├── admin.ts (管理员接口)
│ ├── tools.ts (工具相关)
│ └── providers.ts (供应商相关)
└── types/
├── auth.ts
├── agent.ts
├── billing.ts
└── common.ts
代码示例:
// lib/api/auth.ts
import { APIResponse, buildHeaders, handleResponse, API_BASE_URLS } from '../api-client'
export class AuthAPI {
static async login(
email: string,
password: string,
role: 'user' | 'channel' | 'admin' | 'provider' = 'user'
): Promise<APIResponse<{ token: string; refreshToken?: string; user?: any }>> {
const response = await fetch(`${API_BASE_URLS.mcpServer}/api/auth/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password, role }),
})
return handleResponse(response)
}
static async logout() {
// ...
}
}
// lib/api-client.ts (重构后)
export { AuthAPI } from './api/auth'
export { UserAPI } from './api/user'
export { ChannelAPI } from './api/channel'
export { AdminAPI } from './api/admin'
使用方式:
import { AuthAPI, UserAPI, AdminAPI } from '@/lib/api-client'
// 登录
const result = await AuthAPI.login(email, password)
// 部署Agent
const deployment = await UserAPI.deployAgent(agentId, instances, model)
// 获取平台统计
const stats = await AdminAPI.getDashboardStats()
4. 全局状态管理缺失
问题:
// ❌ 反面例子 - 多个地方重复调用
const [agents, setAgents] = useState<any[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const loadAgents = async () => {
try {
const result = await TaijiAPIClient.getPlatformAgents()
setAgents(result?.data?.data || [])
} catch (error) {
console.error("Failed to load agents:", error)
}
}
loadAgents()
}, [])
这个模式在 agent-factory.tsx, orchestration.tsx, billing.tsx 等多个文件中重复出现。
建议方案 - 使用 Zustand 创建全局状态:
// lib/store/agent-store.ts
import { create } from 'zustand'
import { UserAPI } from '@/lib/api-client'
interface AgentState {
agents: any[]
loading: boolean
error: string | null
// Actions
fetchAgents: () => Promise<void>
deployAgent: (agentId: string, instances: number, model: string) => Promise<void>
getAgentById: (id: string) => any | null
}
export const useAgentStore = create<AgentState>((set, get) => ({
agents: [],
loading: false,
error: null,
fetchAgents: async () => {
set({ loading: true, error: null })
try {
const result = await UserAPI.getPlatformAgents()
set({ agents: result?.data?.data || [] })
} catch (error) {
set({ error: error?.message || 'Failed to fetch agents' })
} finally {
set({ loading: false })
}
},
deployAgent: async (agentId: string, instances: number, model: string) => {
try {
const result = await UserAPI.deployAgent({
agentId,
instances,
model,
gateway: 'MCP'
})
// 部署后刷新列表
await get().fetchAgents()
} catch (error) {
set({ error: error?.message })
}
},
getAgentById: (id: string) => {
return get().agents.find(a => a.id === id)
}
}))
使用方式:
// app/agent-factory/page.tsx
import { useAgentStore } from '@/lib/store/agent-store'
export default function AgentFactoryPage() {
const { agents, loading, fetchAgents, deployAgent } = useAgentStore()
useEffect(() => {
fetchAgents()
}, [fetchAgents])
return (
<div>
{loading ? <Spinner /> : agents.map(agent => (...))}
</div>
)
}
5. 错误处理不统一
问题:
// ❌ 多种错误处理方式混乱
try {
const result = await TaijiAPIClient.login(...)
if (result?.success && result.data?.token) {
// 处理成功
}
} catch (error) {
// 处理异常
console.error("Failed to login:", error)
toast({ ... })
}
建议方案 - 创建统一的错误处理器:
// lib/error-handler.ts
export class APIError extends Error {
constructor(
public code: string,
public message: string,
public statusCode: number = 500,
public details?: any
) {
super(message)
}
}
export function handleAPIError(error: any): APIError {
// 如果是已知的APIError,直接返回
if (error instanceof APIError) {
return error
}
// 如果是响应错误
if (error.response) {
const { status, data } = error.response
return new APIError(
data?.error?.code || 'UNKNOWN_ERROR',
data?.error?.message || data?.detail || 'An error occurred',
status,
data?.error?.details
)
}
// 网络错误
if (error.message?.includes('Failed to fetch')) {
return new APIError(
'NETWORK_ERROR',
'Unable to connect to the server. Please check your connection.',
0
)
}
// 其他错误
return new APIError(
'UNKNOWN_ERROR',
error.message || 'An unexpected error occurred',
500
)
}
// 使用
try {
const result = await AuthAPI.login(email, password)
if (result.success) {
// ...
}
} catch (error) {
const apiError = handleAPIError(error)
toast({
title: "错误",
description: apiError.message,
variant: "destructive"
})
logger.error('Login failed', { error: apiError })
}
6. Token 刷新机制不完善
问题:
// ❌ 当Token过期时,用户必须重新登录
if (response.status === 401) {
// 清除token并重定向到登录
localStorage.removeItem("auth_token")
router.push("/login")
}
建议方案 - 实现自动 Token 刷新:
// lib/api-client.ts
async function handleResponse<T = any>(response: Response): Promise<T> {
// Token过期 (401) 时自动刷新
if (response.status === 401) {
try {
const refreshResult = await refreshToken()
if (refreshResult.success && refreshResult.data?.token) {
// 重试原请求
const retryResponse = await fetch(response.url, {
...response,
headers: {
...response.headers,
Authorization: `Bearer ${refreshResult.data.token}`
}
})
return handleResponse<T>(retryResponse)
}
} catch (error) {
// 刷新失败,重定向到登录
clearAuth()
window.location.href = '/login'
}
}
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: response.statusText }))
throw new APIError(
(error as any).error?.code || 'UNKNOWN',
(error as any).detail || `HTTP error! status: ${response.status}`,
response.status
)
}
return response.json() as Promise<T>
}
🟢 低优先级建议
7. 代码质量改进
7.1 添加类型定义
// 📂 lib/types/index.ts
export interface User {
id: string
email: string
name: string
role: UserRole
subscription_tier: SubscriptionTier
balance: number
status: 'active' | 'inactive' | 'suspended'
}
export interface Agent {
id: string
name: string
type: 'platform' | 'custom'
description: string
category: string
status: 'available' | 'unavailable' | 'error'
capabilities: string[]
required_resources: {
cpu: number
memory: number
}
}
export type UserRole = 'user' | 'channel' | 'admin' | 'super_admin' | 'provider'
export type SubscriptionTier = 'free' | 'pro' | 'enterprise'
7.2 环境变量管理
// 📂 lib/env.ts
const requiredEnvVars = [
'NEXT_PUBLIC_MCP_SERVER_URL',
'NEXT_PUBLIC_DATA_INGESTION_URL',
'NEXT_PUBLIC_API_GATEWAY_URL'
]
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`)
}
}
export const env = {
MCP_SERVER_URL: process.env.NEXT_PUBLIC_MCP_SERVER_URL!,
DATA_INGESTION_URL: process.env.NEXT_PUBLIC_DATA_INGESTION_URL!,
API_GATEWAY_URL: process.env.NEXT_PUBLIC_API_GATEWAY_URL!,
}
7.3 请求拦截器
// 📂 lib/api-interceptor.ts
export class RequestInterceptor {
private static instance: RequestInterceptor
static getInstance() {
if (!this.instance) {
this.instance = new RequestInterceptor()
}
return this.instance
}
async intercept(url: string, options: RequestInit) {
// 1. 添加认证header
const token = getAuthToken()
if (token) {
options.headers = {
...options.headers,
'Authorization': `Bearer ${token}`
}
}
// 2. 添加请求ID用于追踪
const requestId = crypto.randomUUID()
options.headers = {
...options.headers,
'X-Request-ID': requestId
}
// 3. 记录请求
console.log(`[${requestId}] ${options.method} ${url}`)
return { url, options }
}
}
7.4 日志系统
// 📂 lib/logger.ts
export class Logger {
static info(message: string, data?: any) {
console.log(`[INFO] ${new Date().toISOString()} - ${message}`, data)
}
static error(message: string, error?: any) {
console.error(`[ERROR] ${new Date().toISOString()} - ${message}`, error)
}
static warn(message: string, data?: any) {
console.warn(`[WARN] ${new Date().toISOString()} - ${message}`, data)
}
static debug(message: string, data?: any) {
if (process.env.NODE_ENV === 'development') {
console.debug(`[DEBUG] ${new Date().toISOString()} - ${message}`, data)
}
}
}
8. 性能优化建议
8.1 实现缓存策略
// 📂 lib/cache.ts
export class CacheManager {
private static cache = new Map<string, { data: any; expiry: number }>()
static set(key: string, data: any, ttl: number = 5 * 60 * 1000) {
this.cache.set(key, {
data,
expiry: Date.now() + ttl
})
}
static get(key: string) {
const item = this.cache.get(key)
if (!item) return null
if (Date.now() > item.expiry) {
this.cache.delete(key)
return null
}
return item.data
}
static clear(key?: string) {
if (key) {
this.cache.delete(key)
} else {
this.cache.clear()
}
}
}
// 使用
const getPlatformAgents = async () => {
const cacheKey = 'platform_agents'
// 先查缓存
const cached = CacheManager.get(cacheKey)
if (cached) return cached
// 缓存未命中,调用API
const result = await UserAPI.getPlatformAgents()
// 缓存结果(5分钟)
if (result.success) {
CacheManager.set(cacheKey, result.data, 5 * 60 * 1000)
}
return result.data
}
8.2 代码分割优化
// 📂 app/admin/layout.tsx
const AdminDashboard = dynamic(
() => import('./dashboard/page'),
{ loading: () => <Spinner /> }
)
9. 测试建议
9.1 单元测试
// 📂 lib/__tests__/api-client.test.ts
import { AuthAPI } from '@/lib/api-client'
describe('AuthAPI', () => {
it('should login successfully with correct credentials', async () => {
const result = await AuthAPI.login('test@example.com', 'password')
expect(result.success).toBe(true)
expect(result.data?.token).toBeDefined()
})
it('should fail login with incorrect credentials', async () => {
expect(async () => {
await AuthAPI.login('test@example.com', 'wrongpassword')
}).rejects.toThrow()
})
})
9.2 集成测试
// 📂 __tests__/integration/agent-deployment.test.ts
describe('Agent Deployment Flow', () => {
it('should complete full agent deployment flow', async () => {
// 1. 登录
const loginResult = await AuthAPI.login(...)
// 2. 获取Agent列表
const agents = await UserAPI.getPlatformAgents()
// 3. 部署Agent
const deployment = await UserAPI.deployAgent(...)
// 4. 验证部署成功
expect(deployment.success).toBe(true)
})
})
📋 优化实施计划
Phase 1 (第1周) - 高优先级修复
- 分离
api-client.ts为多个模块 - 修复 Agent 删除接口逻辑
- 实现缺失的 API(删除/更新渠道)
- 添加 Token 自动刷新机制
Phase 2 (第2周) - 中优先级改进
- 实现全局状态管理(Zustand)
- 添加统一的错误处理
- 添加日志系统
- 优化 API 调用(缓存、去重)
Phase 3 (第3周) - 代码质量
- 添加完整的类型定义
- 实现请求拦截器
- 添加单元测试
- 性能优化(代码分割、缓存)
Phase 4 (第4周) - 测试和文档
- 集成测试
- 性能测试
- 更新API文档
- 编写开发指南
总结
通过上述优化,可以显著提升项目的:
- ✅ 可维护性: 清晰的架构和分离的关注点
- ✅ 可扩展性: 模块化设计便于添加新功能
- ✅ 性能: 缓存、请求优化、代码分割
- ✅ 可靠性: 统一的错误处理和日志记录
- ✅ 开发效率: 减少重复代码,提高代码复用率
预期工作量: 2-3周
优先级排序: 高→中→低