feat: implement web overview, connections, and settings pages

- Add Overview page with realtime metrics, SRv6 SID display, and TUN alert
- Add Connections page with card/table views and action menus
- Add Settings page with 4 tabs, dynamic item lists, and auto-connect toggle
- Implement HashRouter navigation and SSE live event stream integration
- Integrate Base UI-based shadcn components and Toaster notifications
- Support enableTUN flag and refactor connection table naming conventions
This commit is contained in:
2026-08-23 23:57:41 +08:00
parent e3f575096b
commit 4531e5366b
14 changed files with 2305 additions and 20 deletions
+85
View File
@@ -0,0 +1,85 @@
import { useState, useEffect, useCallback } from 'react'
import type { KLALBControllerConfig } from '@/types/api'
interface UseKlalbConfigResult {
config: KLALBControllerConfig | null
isLoading: boolean
isSaving: boolean
error: string | null
saveSuccess: boolean
fetchConfig: () => Promise<void>
saveConfig: (newConfig: KLALBControllerConfig) => Promise<{ success: boolean; message?: string }>
}
export function useKlalbConfig(): UseKlalbConfigResult {
const [config, setConfig] = useState<KLALBControllerConfig | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [isSaving, setIsSaving] = useState(false)
const [error, setError] = useState<string | null>(null)
const [saveSuccess, setSaveSuccess] = useState(false)
const fetchConfig = useCallback(async () => {
setIsLoading(true)
try {
const res = await fetch('/api/config')
if (res.ok) {
const data = (await res.json()) as KLALBControllerConfig
setConfig(data)
setError(null)
} else {
setError('获取配置失败: 服务器返回异常状态')
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err)
setError(`无法连接到配置接口: ${msg}`)
} finally {
setIsLoading(false)
}
}, [])
const saveConfig = useCallback(
async (newConfig: KLALBControllerConfig): Promise<{ success: boolean; message?: string }> => {
setIsSaving(true)
setSaveSuccess(false)
setError(null)
try {
const res = await fetch('/api/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newConfig),
})
const data = await res.json()
if (res.ok && (data.success || data.success === undefined)) {
setConfig(newConfig)
setSaveSuccess(true)
setTimeout(() => setSaveSuccess(false), 3000)
return { success: true }
}
const errMsg = data.error || data.message || '保存配置失败'
setError(errMsg)
return { success: false, message: errMsg }
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err)
setError(msg)
return { success: false, message: msg }
} finally {
setIsSaving(false)
}
},
[]
)
useEffect(() => {
fetchConfig()
}, [fetchConfig])
return {
config,
isLoading,
isSaving,
error,
saveSuccess,
fetchConfig,
saveConfig,
}
}