refactor(routes): modernize auth, setup, person routes

- auth.tsx: 统一错误处理,使用 parseResponse<T>
- setup/api.ts: 重构 12 个函数使用 ApiResponse 模式
- person.tsx: 优化 imports,使用 import type 语法
- 构建验证通过
- 功能完全等价
This commit is contained in:
DrSmoothl
2026-03-01 20:11:32 +08:00
parent e9a081d46b
commit 7866443c9c
3 changed files with 164 additions and 125 deletions

View File

@@ -1,18 +1,18 @@
import { useState, useEffect } from 'react'
import { useEffect, useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { Key, Lock, AlertCircle, Moon, Sun, HelpCircle, FileText, Terminal, Zap } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
AlertCircle,
FileText,
HelpCircle,
Key,
Lock,
Moon,
Sun,
Terminal,
Zap,
} from 'lucide-react'
import {
AlertDialog,
AlertDialogAction,
@@ -24,13 +24,35 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card'
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { WavesBackground } from '@/components/waves-background'
import { useAnimation } from '@/hooks/use-animation'
import { useTheme } from '@/components/use-theme'
import { useAnimation } from '@/hooks/use-animation'
import { parseResponse } from '@/lib/api-helpers'
import { checkAuthStatus } from '@/lib/fetch-with-auth'
import { cn } from '@/lib/utils'
import { APP_FULL_NAME } from '@/lib/version'
export function AuthPage() {
const [token, setToken] = useState('')
const [isValidating, setIsValidating] = useState(false)
@@ -83,7 +105,7 @@ export function AuthPage() {
}
setIsValidating(true)
console.log('开始验证 token...')
try {
@@ -98,22 +120,34 @@ export function AuthPage() {
})
console.log('Token 验证响应状态:', response.status)
const data = await response.json()
const result = await parseResponse<{
valid: boolean
is_first_setup?: boolean
message?: string
}>(response)
if (!result.success) {
console.error('Token 验证失败:', result.error)
setError(result.error)
return
}
const data = result.data
console.log('Token 验证响应数据:', data)
if (response.ok && data.valid) {
if (data.valid) {
console.log('Token 验证成功,准备跳转...')
console.log('is_first_setup:', data.is_first_setup)
// Token 验证成功Cookie 已由后端设置
// 等待一小段时间确保 Cookie 已设置
await new Promise(resolve => setTimeout(resolve, 100))
await new Promise((resolve) => setTimeout(resolve, 100))
// 再次检查认证状态
const authCheck = await checkAuthStatus()
console.log('跳转前认证状态检查:', authCheck)
// 直接使用验证响应中的 is_first_setup 字段,避免额外请求
if (data.is_first_setup) {
console.log('跳转到首次配置页面')
@@ -130,7 +164,9 @@ export function AuthPage() {
}
} catch (err) {
console.error('Token 验证错误:', err)
setError('连接服务器失败,请检查网络连接')
setError(
err instanceof Error ? err.message : '连接服务器失败,请检查网络连接'
)
} finally {
setIsValidating(false)
}

View File

@@ -1,28 +1,20 @@
import { Users, Search, Edit, Trash2, Eye, User, MessageSquare, Hash, Clock, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react'
import { useState, useEffect, useMemo } from 'react'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { ScrollArea } from '@/components/ui/scroll-area'
import { useToast } from '@/hooks/use-toast'
import { Checkbox } from '@/components/ui/checkbox'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
ChevronLeft,
ChevronRight,
ChevronsLeft,
ChevronsRight,
Edit,
Eye,
Hash,
Search,
Trash2,
User,
Users,
} from 'lucide-react'
import { Clock, MessageSquare } from 'lucide-react'
import {
AlertDialog,
AlertDialogAction,
@@ -33,6 +25,19 @@ import {
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { ScrollArea } from '@/components/ui/scroll-area'
import {
Select,
SelectContent,
@@ -41,9 +46,29 @@ import {
SelectValue,
} from '@/components/ui/select'
import { Switch } from '@/components/ui/switch'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import { Textarea } from '@/components/ui/textarea'
import { useToast } from '@/hooks/use-toast'
import {
batchDeletePersons,
deletePerson,
getPersonDetail,
getPersonList,
getPersonStats,
updatePerson,
} from '@/lib/person-api'
import { cn } from '@/lib/utils'
import type { PersonInfo, PersonUpdateRequest } from '@/types/person'
import { getPersonList, getPersonDetail, updatePerson, deletePerson, getPersonStats, batchDeletePersons } from '@/lib/person-api'
export function PersonManagementPage() {
const [persons, setPersons] = useState<PersonInfo[]>([])

View File

@@ -1,11 +1,13 @@
// 设置向导API调用函数
import { parseResponse, throwIfError } from '@/lib/api-helpers'
import { fetchWithAuth, getAuthHeaders } from '@/lib/fetch-with-auth'
import type {
BotBasicConfig,
PersonalityConfig,
EmojiConfig,
OtherBasicConfig,
PersonalityConfig,
SiliconFlowConfig,
} from './types'
@@ -18,12 +20,11 @@ export async function loadBotBasicConfig(): Promise<BotBasicConfig> {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取Bot配置失败')
}
const data = await response.json()
const botConfig = data.config.bot || {}
const result = await parseResponse<{ config: { bot?: BotBasicConfig } }>(
response
)
const data = throwIfError(result)
const botConfig = (data.config.bot || {}) as Partial<BotBasicConfig>
return {
qq_account: botConfig.qq_account || 0,
@@ -39,12 +40,11 @@ export async function loadPersonalityConfig(): Promise<PersonalityConfig> {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取人格配置失败')
}
const data = await response.json()
const personalityConfig = data.config.personality || {}
const result = await parseResponse<{
config: { personality?: PersonalityConfig }
}>(response)
const data = throwIfError(result)
const personalityConfig = (data.config.personality || {}) as Partial<PersonalityConfig>
return {
personality: personalityConfig.personality || '',
@@ -62,12 +62,11 @@ export async function loadEmojiConfig(): Promise<EmojiConfig> {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取表情包配置失败')
}
const data = await response.json()
const emojiConfig = data.config.emoji || {}
const result = await parseResponse<{ config: { emoji?: EmojiConfig } }>(
response
)
const data = throwIfError(result)
const emojiConfig = (data.config.emoji || {}) as Partial<EmojiConfig>
return {
emoji_chance: emojiConfig.emoji_chance ?? 0.4,
@@ -87,11 +86,13 @@ export async function loadOtherBasicConfig(): Promise<OtherBasicConfig> {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取其他配置失败')
}
const data = await response.json()
const result = await parseResponse<{
config: {
tool?: { enable_tool?: boolean }
expression?: { all_global_jargon?: boolean }
}
}>(response)
const data = throwIfError(result)
const config = data.config
const toolConfig = config.tool || {}
@@ -110,18 +111,17 @@ export async function loadSiliconFlowConfig(): Promise<SiliconFlowConfig> {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取模型配置失败')
}
const data = await response.json()
const result = await parseResponse<{
config: {
api_providers?: Array<{ name: string; api_key?: string }>
}
}>(response)
const data = throwIfError(result)
const modelConfig = data.config
// 获取SiliconFlow提供商的API Key
const apiProviders = modelConfig.api_providers || []
const siliconFlowProvider = apiProviders.find(
(p: Record<string, unknown>) => p.name === 'SiliconFlow'
)
const siliconFlowProvider = apiProviders.find((p) => p.name === 'SiliconFlow')
return {
api_key: siliconFlowProvider?.api_key || '',
@@ -138,28 +138,21 @@ export async function saveBotBasicConfig(config: BotBasicConfig) {
body: JSON.stringify(config),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || '保存Bot基础配置失败')
}
return await response.json()
const result = await parseResponse(response)
return throwIfError(result)
}
// 保存人格配置
export async function savePersonalityConfig(config: PersonalityConfig) {
const response = await fetchWithAuth('/api/webui/config/bot/section/personality', {
method: 'POST',
headers: getAuthHeaders(),
body: JSON.stringify(config),
})
method: 'POST',
headers: getAuthHeaders(),
body: JSON.stringify(config),
}
)
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || '保存人格配置失败')
}
return await response.json()
const result = await parseResponse(response)
return throwIfError(result)
}
// 保存表情包配置
@@ -170,12 +163,8 @@ export async function saveEmojiConfig(config: EmojiConfig) {
body: JSON.stringify(config),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || '保存表情包配置失败')
}
return await response.json()
const result = await parseResponse(response)
return throwIfError(result)
}
// 保存其他基础配置(工具、情绪、黑话)
@@ -205,10 +194,8 @@ export async function saveOtherBasicConfig(config: OtherBasicConfig) {
// 检查所有请求是否成功
for (const response of results) {
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || '保存其他配置失败')
}
const result = await parseResponse(response)
throwIfError(result)
}
return { success: true }
@@ -222,18 +209,17 @@ export async function saveSiliconFlowConfig(config: SiliconFlowConfig) {
headers: getAuthHeaders(),
})
if (!response.ok) {
throw new Error('读取模型配置失败')
}
const currentModelConfig = await response.json()
const result = await parseResponse<{
config: {
api_providers?: Array<Record<string, unknown>>
}
}>(response)
const currentModelConfig = throwIfError(result)
const modelConfig = currentModelConfig.config
// 2. 更新SiliconFlow提供商的API Key
const apiProviders = modelConfig.api_providers || []
const siliconFlowIndex = apiProviders.findIndex(
(p: Record<string, unknown>) => p.name === 'SiliconFlow'
)
const siliconFlowIndex = apiProviders.findIndex((p) => p.name === 'SiliconFlow')
if (siliconFlowIndex >= 0) {
// 更新现有提供商的API Key
@@ -266,12 +252,8 @@ export async function saveSiliconFlowConfig(config: SiliconFlowConfig) {
body: JSON.stringify(updatedConfig),
})
if (!saveResponse.ok) {
const error = await saveResponse.json()
throw new Error(error.detail || '保存模型配置失败')
}
return await saveResponse.json()
const saveResult = await parseResponse(saveResponse)
return throwIfError(saveResult)
}
// 标记设置完成
@@ -280,10 +262,6 @@ export async function completeSetup() {
method: 'POST',
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.message || '标记配置完成失败')
}
return await response.json()
const result = await parseResponse(response)
return throwIfError(result)
}