Files
web/src/app/admin/(dashboard)/page.tsx

196 lines
6.6 KiB
TypeScript
Raw Normal View History

import Page from '@/components/page'
2025-04-19 10:21:53 +08:00
import Image from 'next/image'
2025-06-07 11:28:36 +08:00
import {Card, CardContent, CardHeader, CardTitle} from '@/components/ui/card'
import {format} from 'date-fns'
import {merge} from '@/lib/utils'
import banner from './_assets/banner.webp'
2025-06-07 11:28:36 +08:00
import {listInitialization} from '@/actions/dashboard'
import Charts from './_client/charts'
2025-06-07 11:28:36 +08:00
import UserCenter from './_client/userCenter'
import soon from './_assets/coming-soon.svg'
import mask from './_assets/Mask group.webp'
import {Button} from '@/components/ui/button'
export type DashboardPageProps = {}
2025-06-07 11:28:36 +08:00
export default async function DashboardPage(props: DashboardPageProps) {
2025-06-23 18:59:31 +08:00
const resp = await listInitialization()
2025-06-07 11:28:36 +08:00
if (!resp.success) {
return (
<div className="col-start-4 row-start-3 row-span-2 flex justify-center items-center">
</div>
)
}
const initData = resp.data
return (
<Page className={merge(
`flex-auto grid`,
`grid-cols-1`,
`md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_300px]`,
`md:grid-rows-[150px_200px_minmax(150px,1fr)_minmax(150px,1fr)]`,
2025-06-07 11:28:36 +08:00
)}
>
{/* banner */}
<section className="md:row-start-1 md:col-start-1 md:col-span-3 relative md:rounded-lg overflow-hidden hidden md:block">
<Image src={banner} alt="banner image" className="w-full h-full inset-0 absolute object-cover "/>
2025-06-07 11:28:36 +08:00
<div className="flex flex-col absolute inset-0 justify-center px-8 gap-1">
<h3 className="text-2xl text-balance text-primary font-medium">IP资源</h3>
<p className="text-primary text-balance font-medium">//IP代理</p>
2025-04-19 10:21:53 +08:00
</div>
</section>
{/* 磁贴集 */}
2025-06-07 11:28:36 +08:00
{initData && (
<Pins
2025-06-23 18:59:31 +08:00
short_term={String(initData.free.short.ResourceCount)}
short_term_monthly={String(initData.free.short.ResourceQuotaSum)}
long_term={String(initData.free.long.ResourceCount)}
long_term_monthly={String(initData.free.long.ResourceDailyFreeSum)}
2025-06-07 11:28:36 +08:00
/>
)}
{/* 图表 */}
<div className="col-start-1 row-start-3 col-span-3 row-span-2 hidden md:block"><Charts initialData={initData.usage}/></div>
{/* 信息 */}
<div className=" md:col-start-4 md:row-start-1 md:row-span-2">
<UserCenter/>
</div>
{/* 通知 */}
<div className="md:col-start-4 md:row-start-3 md:row-span-2">
{initData && (
2025-06-23 18:59:31 +08:00
<Announcements list={initData.anno.list}/>
)}
</div>
</Page>
)
}
2025-06-07 11:28:36 +08:00
type DashboardChartProps = {
short_term: string
short_term_monthly: string
long_term: string
long_term_monthly: string
}
function Pins(props: DashboardChartProps) {
return (
2025-06-10 19:09:19 +08:00
<div className="flex md:row-start-2 md:col-start-1 md:col-span-3 gap-4 max-md:flex-col">
2025-06-07 11:28:36 +08:00
{/* 短效 */}
<Card className="flex-1">
2025-06-07 11:28:36 +08:00
<CardHeader>
<CardTitle>
<Image src={mask} alt="Mask group" priority/>
2025-06-07 11:28:36 +08:00
</CardTitle>
</CardHeader>
<CardContent className="flex-auto flex flex-col gap-2">
<div className="flex-1 flex items-center justify-between">
<h4></h4>
<p className="flex flex-col items-end">
<span className="text-sm text-weak"></span>
2025-06-10 19:09:19 +08:00
<span className="text-sm">{props.short_term}</span>
2025-06-07 11:28:36 +08:00
</p>
</div>
<div className="border-b"></div>
<div className="flex-1 flex items-center justify-between">
<h4 className="text-balance"></h4>
2025-06-07 11:28:36 +08:00
<p className="flex flex-col items-end">
<span className="text-sm text-weak"></span>
<span className="text-sm">{props.short_term_monthly}</span>
2025-06-07 11:28:36 +08:00
</p>
</div>
</CardContent>
</Card>
2025-06-07 11:28:36 +08:00
{/* 长效 */}
<Card className="flex-1">
2025-06-07 11:28:36 +08:00
<CardHeader>
<CardTitle>
<Image src={mask} alt="Mask group" priority/>
2025-06-07 11:28:36 +08:00
</CardTitle>
</CardHeader>
<CardContent className="flex-auto flex flex-col gap-2">
<div className="flex-1 flex items-center justify-between">
<h4 className="text-balance"></h4>
2025-06-07 11:28:36 +08:00
<p className="flex flex-col items-end">
<span className="text-sm text-weak" ></span>
<span className="text-sm">{props.long_term}</span>
2025-06-07 11:28:36 +08:00
</p>
</div>
2025-06-07 11:28:36 +08:00
<div className="border-b"></div>
<div className="flex-1 flex items-center justify-between">
<h4 className="text-balance"></h4>
2025-06-07 11:28:36 +08:00
<p className="flex flex-col items-end">
<span className="text-sm text-weak"></span>
<span className="text-sm">{props.long_term_monthly}</span>
2025-06-07 11:28:36 +08:00
</p>
</div>
2025-06-07 11:28:36 +08:00
</CardContent>
</Card>
{/* 固定 */}
<Card className="flex-1 py-4 h-full hidden xl:block ">
2025-06-07 11:28:36 +08:00
<CardHeader className="px-4">
<CardTitle>IP套餐</CardTitle>
</CardHeader>
<CardContent className="flex-auto flex flex-col gap-2 items-center justify-center">
<Image alt="coming soon" src={soon}/>
<p></p>
</CardContent>
</Card>
</div>
)
}
2025-06-07 11:28:36 +08:00
type Props = {
list: {
id: number
title: string
created_at: Date
} []
}
function Announcements(props: Props) {
return (
<Card className="h-full">
<CardHeader>
2025-06-07 11:28:36 +08:00
<div className="flex justify-between gap-2">
<CardTitle></CardTitle>
{/* <Button
theme="text"
className="text-sm text-primary font-medium hover:text-primary bg-transparent border-none p-0 cursor-pointer"
>
</Button> */}
</div>
</CardHeader>
2025-06-07 11:28:36 +08:00
<CardContent className="flex-auto p-0">
{!props.list.length
? (
<div className="flex flex-col items-center justify-center gap-8 ">
<Image alt="coming soon" src={soon}/>
<p></p>
</div>
)
2025-06-07 11:28:36 +08:00
: props.list.map(item => (
<div
key={item.id}
className={merge(
`transition-colors duration-150 ease-in-out`,
`flex flex-col gap-1 px-4 py-2`,
`hover:bg-muted cursor-pointer`,
)}
>
<h4>{item.title}</h4>
<p className="text-sm text-weak">{format(item.created_at, 'yyyy-MM-dd HH:mm')}</p>
</div>
))}
</CardContent>
</Card>
)
}