193 lines
6.1 KiB
TypeScript
193 lines
6.1 KiB
TypeScript
import Page from '@/components/page'
|
||
import Image from 'next/image'
|
||
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'
|
||
import {listInitialization} from '@/actions/dashboard'
|
||
import Charts from './_client/charts'
|
||
import UserCenter from './_client/userCenter'
|
||
import soon from './_assets/coming-soon.svg'
|
||
import mask from './_assets/Mask group.webp'
|
||
|
||
export type DashboardPageProps = {}
|
||
|
||
export default async function DashboardPage(props: DashboardPageProps) {
|
||
const resp = await listInitialization({
|
||
page: 1,
|
||
size: 5,
|
||
})
|
||
|
||
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-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)_300px]`,
|
||
`grid-rows-[150px_200px_minmax(150px,1fr)_minmax(150px,1fr)]`,
|
||
)}
|
||
>
|
||
{/* banner */}
|
||
<section className="col-start-1 row-start-1 col-span-3 relative rounded-lg overflow-hidden">
|
||
<Image src={banner} alt="banner image" className="w-full h-full inset-0 absolute object-cover"/>
|
||
<div className="flex flex-col absolute inset-0 justify-center px-8 gap-1">
|
||
<h3 className="text-2xl text-primary font-medium">代理IP资源,先测后买</h3>
|
||
<p className="text-primary font-medium">短效/长效/固定IP代理,一站式服务</p>
|
||
</div>
|
||
</section>
|
||
|
||
{/* 磁贴集 */}
|
||
{initData && (
|
||
<Pins
|
||
short_term={String(initData.short_term)}
|
||
short_term_monthly={String(initData.short_term_monthly)}
|
||
long_term={String(initData.long_term)}
|
||
long_term_monthly={String(initData.long_term_monthly)}
|
||
/>
|
||
)}
|
||
|
||
{/* 图表 */}
|
||
<Charts/>
|
||
|
||
{/* 信息 */}
|
||
<UserCenter/>
|
||
|
||
{/* 通知 */}
|
||
{initData && (
|
||
<Announcements list={initData.list}/>
|
||
)}
|
||
|
||
</Page>
|
||
)
|
||
}
|
||
type DashboardChartProps = {
|
||
short_term: string
|
||
short_term_monthly: string
|
||
long_term: string
|
||
long_term_monthly: string
|
||
}
|
||
function Pins(props: DashboardChartProps) {
|
||
return (
|
||
<>
|
||
|
||
{/* 短效 */}
|
||
<Card className="col-start-1 row-start-2 py-4">
|
||
<CardHeader>
|
||
<CardTitle>
|
||
<Image src={mask} alt="Mask group" width={35} height={35} priority/>
|
||
{' '}
|
||
短效动态套餐
|
||
</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>
|
||
<span className="text-lg">{props.short_term ? props.short_term : '1'}</span>
|
||
</p>
|
||
</div>
|
||
<div className="border-b"></div>
|
||
<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>
|
||
<span className="text-lg">{props.short_term_monthly}</span>
|
||
</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 长效 */}
|
||
<Card className="col-start-2 row-start-2">
|
||
<CardHeader>
|
||
<CardTitle>
|
||
<Image src={mask} alt="Mask group" width={35} height={35} priority/>
|
||
{' '}
|
||
长效动态套餐
|
||
</CardTitle>
|
||
</CardHeader>
|
||
<CardContent className="flex-auto flex flex-col gap-2">
|
||
{/* <Image alt={`coming soon`} src={soon} />
|
||
<p>敬请期待</p> */}
|
||
<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>
|
||
<span className="text-lg">{props.long_term}</span>
|
||
</p>
|
||
</div>
|
||
<div className="border-b"></div>
|
||
<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>
|
||
<span className="text-lg">{props.long_term_monthly}</span>
|
||
</p>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* 固定 */}
|
||
<Card className="col-start-3 row-start-2 py-4">
|
||
<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>
|
||
</>
|
||
)
|
||
}
|
||
|
||
type Props = {
|
||
list: {
|
||
id: number
|
||
title: string
|
||
created_at: Date
|
||
} []
|
||
}
|
||
function Announcements(props: Props) {
|
||
return (
|
||
<Card className="col-start-4 row-start-3 row-span-2">
|
||
<CardHeader>
|
||
<div className="flex justify-between gap-2">
|
||
<CardTitle>公告</CardTitle>
|
||
<span className="text-sm text-weak">查看更多</span>
|
||
</div>
|
||
</CardHeader>
|
||
<CardContent className="flex-auto p-0">
|
||
{!props.list.length
|
||
? (
|
||
<div className="flex flex-col items-center justify-center gap-2 h-full">
|
||
<Image alt="coming soon" src={soon}/>
|
||
<p>暂无公告</p>
|
||
</div>
|
||
)
|
||
: 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>
|
||
)
|
||
}
|