wood chen 33d6a51416 refactor(web): Migrate to modern web frontend and simplify admin routes
- Remove legacy static files, templates, and JavaScript
- Update main.go to serve SPA-style web application
- Modify admin route handling to support client-side routing
- Simplify configuration and metrics API endpoints
- Remove server-side template rendering in favor of static file serving
- Update Dockerfile and GitHub Actions to build web frontend
2025-02-15 11:44:09 +08:00

167 lines
4.4 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { useToast } from "@/components/ui/use-toast"
import { useRouter } from "next/navigation"
export default function ConfigPage() {
const [config, setConfig] = useState("")
const [loading, setLoading] = useState(true)
const [saving, setSaving] = useState(false)
const { toast } = useToast()
const router = useRouter()
useEffect(() => {
fetchConfig()
}, [])
const fetchConfig = async () => {
try {
const token = localStorage.getItem("token")
if (!token) {
router.push("/login")
return
}
const response = await fetch("/api/config/get", {
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
})
if (response.status === 401) {
localStorage.removeItem("token")
router.push("/login")
return
}
if (!response.ok) {
throw new Error("获取配置失败")
}
const data = await response.json()
setConfig(JSON.stringify(data, null, 2))
} catch (error) {
const message = error instanceof Error ? error.message : "获取配置失败"
toast({
title: "错误",
description: message,
variant: "destructive",
})
} finally {
setLoading(false)
}
}
const handleSave = async () => {
setSaving(true)
try {
// 验证 JSON 格式
const parsedConfig = JSON.parse(config)
const token = localStorage.getItem("token")
if (!token) {
router.push("/login")
return
}
const response = await fetch("/api/config/save", {
method: "POST",
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${token}`
},
body: JSON.stringify(parsedConfig),
})
if (response.status === 401) {
localStorage.removeItem("token")
router.push("/login")
return
}
if (!response.ok) {
const data = await response.json().catch(() => ({}))
throw new Error(data.message || "保存配置失败")
}
toast({
title: "成功",
description: "配置已保存",
})
} catch (error) {
toast({
title: "错误",
description: error instanceof SyntaxError ? "JSON 格式错误" : error instanceof Error ? error.message : "保存配置失败",
variant: "destructive",
})
} finally {
setSaving(false)
}
}
const handleFormat = () => {
try {
const parsedConfig = JSON.parse(config)
setConfig(JSON.stringify(parsedConfig, null, 2))
toast({
title: "成功",
description: "配置已格式化",
})
} catch {
toast({
title: "错误",
description: "JSON 格式错误",
variant: "destructive",
})
}
}
if (loading) {
return (
<div className="flex h-[calc(100vh-4rem)] items-center justify-center">
<div className="text-center">
<div className="text-lg font-medium">...</div>
<div className="text-sm text-gray-500 mt-1"></div>
</div>
</div>
)
}
return (
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle></CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex gap-2">
<Button onClick={handleSave} disabled={saving}>
{saving ? "保存中..." : "保存配置"}
</Button>
<Button variant="outline" onClick={handleFormat}>
</Button>
<Button variant="outline" onClick={fetchConfig}>
</Button>
</div>
<div className="relative">
<textarea
className="w-full h-[600px] p-4 font-mono text-sm rounded-md border bg-background"
value={config}
onChange={(e) => setConfig(e.target.value)}
spellCheck={false}
placeholder="加载配置失败"
/>
</div>
</div>
</CardContent>
</Card>
</div>
)
}