2025-04-11 17:34:42 +08:00
|
|
|
|
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'
|
2025-05-07 16:48:51 +08:00
|
|
|
|
import banner from './_assets/banner.webp'
|
2025-06-07 11:28:36 +08:00
|
|
|
|
import {listInitialization} from '@/actions/dashboard'
|
2025-06-05 16:41:30 +08:00
|
|
|
|
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'
|
2025-06-30 16:08:08 +08:00
|
|
|
|
import {Button} from '@/components/ui/button'
|
2025-05-07 16:48:51 +08:00
|
|
|
|
|
2025-04-07 15:42:09 +08:00
|
|
|
|
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
|
2025-06-30 16:08:08 +08:00
|
|
|
|
|
2025-04-07 15:42:09 +08:00
|
|
|
|
return (
|
2025-05-06 19:04:52 +08:00
|
|
|
|
<Page className={merge(
|
|
|
|
|
|
`flex-auto grid`,
|
2025-06-10 12:51:35 +08:00
|
|
|
|
`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
|
|
|
|
)}
|
|
|
|
|
|
>
|
2025-04-07 15:42:09 +08:00
|
|
|
|
{/* banner */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<section className="md:row-start-1 md:col-start-1 md:col-span-3 relative md:rounded-lg overflow-hidden hidden md:block">
|
2025-06-27 10:57:50 +08:00
|
|
|
|
<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">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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>
|
2025-04-07 15:42:09 +08:00
|
|
|
|
</section>
|
|
|
|
|
|
|
2025-05-07 16:48:51 +08:00
|
|
|
|
{/* 磁贴集 */}
|
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
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2025-04-07 15:42:09 +08:00
|
|
|
|
|
|
|
|
|
|
{/* 图表 */}
|
2025-06-25 14:43:44 +08:00
|
|
|
|
<div className="col-start-1 row-start-3 col-span-3 row-span-2 hidden md:block"><Charts initialData={initData.usage}/></div>
|
2025-05-07 16:48:51 +08:00
|
|
|
|
|
|
|
|
|
|
{/* 信息 */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<div className=" md:col-start-4 md:row-start-1 md:row-span-2">
|
|
|
|
|
|
<UserCenter/>
|
|
|
|
|
|
</div>
|
2025-05-07 16:48:51 +08:00
|
|
|
|
|
|
|
|
|
|
{/* 通知 */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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}/>
|
2025-06-10 12:51:35 +08:00
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
2025-05-07 16:48:51 +08:00
|
|
|
|
|
|
|
|
|
|
</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
|
|
|
|
{/* 短效 */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<Card className="flex-1">
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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>
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<span className="text-sm">{props.short_term_monthly}</span>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
2025-05-06 19:04:52 +08:00
|
|
|
|
|
2025-06-07 11:28:36 +08:00
|
|
|
|
{/* 长效 */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<Card className="flex-1">
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<CardHeader>
|
|
|
|
|
|
<CardTitle>
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<h4 className="text-balance">包时</h4>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<p className="flex flex-col items-end">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<span className="text-sm text-weak" >当日可提取数量</span>
|
|
|
|
|
|
<span className="text-sm">{props.long_term}</span>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
</p>
|
2025-05-06 19:04:52 +08:00
|
|
|
|
</div>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<div className="border-b"></div>
|
|
|
|
|
|
<div className="flex-1 flex items-center justify-between">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<h4 className="text-balance">包量</h4>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<p className="flex flex-col items-end">
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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>
|
2025-05-06 19:04:52 +08:00
|
|
|
|
</div>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 固定 */}
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<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>
|
2025-06-10 12:51:35 +08:00
|
|
|
|
|
|
|
|
|
|
</div>
|
2025-05-06 19:04:52 +08:00
|
|
|
|
)
|
|
|
|
|
|
}
|
2025-05-07 16:48:51 +08:00
|
|
|
|
|
2025-06-07 11:28:36 +08:00
|
|
|
|
type Props = {
|
|
|
|
|
|
list: {
|
|
|
|
|
|
id: number
|
|
|
|
|
|
title: string
|
|
|
|
|
|
created_at: Date
|
|
|
|
|
|
} []
|
|
|
|
|
|
}
|
|
|
|
|
|
function Announcements(props: Props) {
|
2025-05-07 16:48:51 +08:00
|
|
|
|
return (
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<Card className="h-full">
|
2025-05-07 16:48:51 +08:00
|
|
|
|
<CardHeader>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<div className="flex justify-between gap-2">
|
2025-06-05 16:41:30 +08:00
|
|
|
|
<CardTitle>公告</CardTitle>
|
2025-06-30 16:08:08 +08:00
|
|
|
|
{/* <Button
|
|
|
|
|
|
theme="text"
|
|
|
|
|
|
className="text-sm text-primary font-medium hover:text-primary bg-transparent border-none p-0 cursor-pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
查看更多
|
|
|
|
|
|
</Button> */}
|
2025-06-05 16:41:30 +08:00
|
|
|
|
</div>
|
2025-05-07 16:48:51 +08:00
|
|
|
|
</CardHeader>
|
2025-06-07 11:28:36 +08:00
|
|
|
|
<CardContent className="flex-auto p-0">
|
|
|
|
|
|
{!props.list.length
|
2025-05-07 16:48:51 +08:00
|
|
|
|
? (
|
2025-06-10 12:51:35 +08:00
|
|
|
|
<div className="flex flex-col items-center justify-center gap-8 ">
|
2025-06-07 11:49:57 +08:00
|
|
|
|
<Image alt="coming soon" src={soon}/>
|
|
|
|
|
|
<p>暂无公告</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)
|
2025-06-07 11:28:36 +08:00
|
|
|
|
: props.list.map(item => (
|
2025-06-07 11:49:57 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
))}
|
2025-05-07 16:48:51 +08:00
|
|
|
|
</CardContent>
|
|
|
|
|
|
</Card>
|
|
|
|
|
|
)
|
2025-05-19 11:04:40 +08:00
|
|
|
|
}
|