mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
前端优化
This commit is contained in:
@@ -1,203 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import {useQuery} from "@tanstack/react-query"
|
||||
import {Info} from "lucide-react"
|
||||
import ReactMarkdown from "react-markdown"
|
||||
import remarkGfm from "remark-gfm"
|
||||
|
||||
import {EmptyStateWithBorder} from "@/components/layout/empty"
|
||||
import {ErrorInline} from "@/components/layout/error"
|
||||
import {Badge} from "@/components/ui/badge"
|
||||
import {Card, CardContent, CardDescription, CardHeader, CardTitle} from "@/components/ui/card"
|
||||
import {Skeleton} from "@/components/ui/skeleton"
|
||||
import {AboutService, StatusService} from "@/lib/services/openflare"
|
||||
import {formatDateTime} from "@/lib/utils"
|
||||
|
||||
const aboutQueryKey = ["openflare", "about"] as const
|
||||
const publicStatusQueryKey = ["openflare", "public-status"] as const
|
||||
|
||||
function AboutPageSkeleton() {
|
||||
return (
|
||||
<div className="py-6 px-1 space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Skeleton className="size-5 rounded-md" />
|
||||
<Skeleton className="h-8 w-48" />
|
||||
</div>
|
||||
<Card className="border-dashed shadow-none">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-5 w-40" />
|
||||
<Skeleton className="h-4 w-72" />
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 md:grid-cols-3">
|
||||
<Skeleton className="h-20 w-full" />
|
||||
<Skeleton className="h-20 w-full" />
|
||||
<Skeleton className="h-20 w-full" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="border-dashed shadow-none">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-5 w-32" />
|
||||
<Skeleton className="h-4 w-64" />
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function AboutPage() {
|
||||
const aboutQuery = useQuery({
|
||||
queryKey: aboutQueryKey,
|
||||
queryFn: () => AboutService.getAboutContent(),
|
||||
})
|
||||
|
||||
const statusQuery = useQuery({
|
||||
queryKey: publicStatusQueryKey,
|
||||
queryFn: () => StatusService.getPublicStatus(),
|
||||
})
|
||||
|
||||
const isLoading = aboutQuery.isLoading || statusQuery.isLoading
|
||||
|
||||
if (isLoading) {
|
||||
return <AboutPageSkeleton />
|
||||
}
|
||||
|
||||
if (aboutQuery.isError) {
|
||||
return (
|
||||
<div className="py-6 px-1">
|
||||
<ErrorInline
|
||||
message={
|
||||
aboutQuery.error instanceof Error
|
||||
? aboutQuery.error.message
|
||||
: "关于内容加载失败"
|
||||
}
|
||||
onRetry={() => void aboutQuery.refetch()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (statusQuery.isError) {
|
||||
return (
|
||||
<div className="py-6 px-1">
|
||||
<ErrorInline
|
||||
message={
|
||||
statusQuery.error instanceof Error
|
||||
? statusQuery.error.message
|
||||
: "系统状态加载失败"
|
||||
}
|
||||
onRetry={() => void statusQuery.refetch()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const aboutContent = aboutQuery.data?.trim() ?? ""
|
||||
const status = statusQuery.data
|
||||
|
||||
if (!status) {
|
||||
return (
|
||||
<div className="py-6 px-1">
|
||||
<EmptyStateWithBorder
|
||||
title="暂无系统信息"
|
||||
description="未能获取 OpenFlare 的公开状态信息。"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="py-6 px-1 space-y-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<Info className="size-5 text-primary" />
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">关于 OpenFlare</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
公开展示当前系统简介、版本信息与项目入口。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card className="border-dashed shadow-none">
|
||||
<CardHeader className="flex flex-row items-start justify-between gap-4">
|
||||
<div>
|
||||
<CardTitle className="text-base">系统信息</CardTitle>
|
||||
<CardDescription>当前运行实例的公开状态与项目链接。</CardDescription>
|
||||
</div>
|
||||
<Badge variant="secondary">{status.version || "dev"}</Badge>
|
||||
</CardHeader>
|
||||
<CardContent className="grid gap-3 md:grid-cols-3">
|
||||
<div className="rounded-lg border border-dashed px-4 py-3">
|
||||
<p className="text-[10px] uppercase tracking-wider text-muted-foreground">
|
||||
系统名称
|
||||
</p>
|
||||
<p className="mt-2 text-sm font-medium">
|
||||
{status.system_name || "OpenFlare"}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-lg border border-dashed px-4 py-3">
|
||||
<p className="text-[10px] uppercase tracking-wider text-muted-foreground">
|
||||
Server 启动时间
|
||||
</p>
|
||||
<p className="mt-2 text-sm font-medium">
|
||||
{formatDateTime(new Date(status.start_time * 1000))}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-lg border border-dashed px-4 py-3">
|
||||
<p className="text-[10px] uppercase tracking-wider text-muted-foreground">
|
||||
项目仓库
|
||||
</p>
|
||||
<a
|
||||
href="https://github.com/Rain-kl/OpenFlare"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="mt-2 block text-sm font-medium text-primary transition hover:opacity-80"
|
||||
>
|
||||
github.com/Rain-kl/OpenFlare
|
||||
</a>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{aboutContent ? (
|
||||
<Card className="border-dashed shadow-none">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">项目介绍</CardTitle>
|
||||
<CardDescription>
|
||||
以下内容由系统设置中的「关于内容」维护。
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div
|
||||
className={[
|
||||
"prose prose-sm max-w-none dark:prose-invert",
|
||||
"prose-p:text-foreground prose-p:leading-7",
|
||||
"prose-li:text-foreground",
|
||||
"prose-strong:text-foreground",
|
||||
"prose-a:text-primary",
|
||||
].join(" ")}
|
||||
>
|
||||
<ReactMarkdown remarkPlugins={[remarkGfm]}>{aboutContent}</ReactMarkdown>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<EmptyStateWithBorder
|
||||
title="尚未配置关于内容"
|
||||
description="可在设置页的「其他设置」标签中编写 Markdown / HTML 内容,这里会自动同步展示。"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex flex-wrap gap-3 text-sm">
|
||||
<Link href="/" className="text-primary transition hover:opacity-80">
|
||||
返回总览
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -105,6 +105,9 @@ export function AdminSettingsPageClient() {
|
||||
</div>
|
||||
<Tabs defaultValue="security" className="w-full">
|
||||
<TabsList variant="line" className="w-fit inline-flex gap-8 mb-6">
|
||||
<TabsTrigger value="openflare-ops" className="px-0 pb-2 text-xs font-semibold">
|
||||
OpenFlare
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="security" className="px-0 pb-2 text-xs font-semibold">
|
||||
安全设置
|
||||
</TabsTrigger>
|
||||
@@ -123,9 +126,6 @@ export function AdminSettingsPageClient() {
|
||||
<TabsTrigger value="info" className="px-0 pb-2 text-xs font-semibold">
|
||||
系统信息
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="openflare-ops" className="px-0 pb-2 text-xs font-semibold">
|
||||
OpenFlare 运维
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="security" className="focus-visible:outline-none">
|
||||
@@ -152,4 +152,4 @@ export function AdminSettingsPageClient() {
|
||||
</Tabs>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type {LucideIcon} from 'lucide-react';
|
||||
import {
|
||||
ClipboardList,
|
||||
FileText,
|
||||
Gauge,
|
||||
GitBranch,
|
||||
Globe,
|
||||
Info,
|
||||
LayoutDashboard,
|
||||
MapPin,
|
||||
Route,
|
||||
@@ -24,9 +22,9 @@ export interface OpenFlareNavItem {
|
||||
|
||||
/** OpenFlare 业务控制台侧栏导航(子页面通过父级入口或页内链接访问) */
|
||||
export const openflareNavItems: OpenFlareNavItem[] = [
|
||||
{title: '总览', url: '/', icon: LayoutDashboard},
|
||||
{title: '节点', url: '/nodes', icon: Server, childUrls: ['/nodes/detail']},
|
||||
{title: '规则', url: '/proxy-routes', icon: Route, childUrls: ['/proxy-routes/detail']},
|
||||
{title: '数据看板', url: '/', icon: LayoutDashboard},
|
||||
{title: '节点管理', url: '/nodes', icon: Server, childUrls: ['/nodes/detail']},
|
||||
{title: '规则管理', url: '/proxy-routes', icon: Route, childUrls: ['/proxy-routes/detail']},
|
||||
{title: 'Pages', url: '/pages', icon: FileText, childUrls: ['/pages/detail']},
|
||||
{
|
||||
title: '网站',
|
||||
@@ -40,11 +38,9 @@ export const openflareNavItems: OpenFlareNavItem[] = [
|
||||
},
|
||||
{title: 'WAF', url: '/waf', icon: Shield, childUrls: ['/waf/ip-groups']},
|
||||
{title: '源站', url: '/origins', icon: MapPin, childUrls: ['/origins/detail']},
|
||||
{title: '发布', url: '/config-versions', icon: GitBranch},
|
||||
{title: '版本发布', url: '/config-versions', icon: GitBranch},
|
||||
{title: '访问日志', url: '/access-logs', icon: ScrollText},
|
||||
{title: '应用日志', url: '/apply-logs', icon: ClipboardList},
|
||||
{title: '性能', url: '/performance', icon: Gauge},
|
||||
{title: '关于', url: '/about', icon: Info},
|
||||
{title: '性能调优', url: '/performance', icon: Gauge},
|
||||
];
|
||||
|
||||
/** 网站模块页内二级导航 */
|
||||
@@ -68,4 +64,4 @@ export function isOpenFlareConsoleRoute(pathname: string): boolean {
|
||||
}
|
||||
return pathname === item.url || pathname.startsWith(`${item.url}/`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user