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

187 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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'
import {ExtraResp} from '@/lib/api'
export type DashboardPageProps = {}
export default async function DashboardPage(props: DashboardPageProps) {
const resp = await listInitialization()
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)]`,
)}
>
{/* 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 "/>
<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>
</div>
</section>
{/* 磁贴集 */}
{initData && (
<Pins {...initData.free}/>
)}
{/* 图表 */}
<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 && (
<Announcements list={initData.anno.list}/>
)}
</div>
</Page>
)
}
type DashboardPinsProps = ExtraResp<typeof listInitialization>['free']
function Pins(props: DashboardPinsProps) {
return (
<div className="flex md:row-start-2 md:col-start-1 md:col-span-3 gap-4 max-md:flex-col">
{/* 短效 */}
<Card className="flex-1">
<CardHeader>
<CardTitle>
<Image src={mask} alt="Mask group" 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-sm">{props.short.resource_daily_free_sum}</span>
</p>
</div>
<div className="border-b"></div>
<div className="flex-1 flex items-center justify-between">
<h4 className="text-balance"></h4>
<p className="flex flex-col items-end">
<span className="text-sm text-weak"></span>
<span className="text-sm">{props.short.resource_quota_sum}</span>
</p>
</div>
</CardContent>
</Card>
{/* 长效 */}
<Card className="flex-1">
<CardHeader>
<CardTitle>
<Image src={mask} alt="Mask group" priority/>
</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>
<p className="flex flex-col items-end">
<span className="text-sm text-weak" ></span>
<span className="text-sm">{props.long.resource_daily_free_sum}</span>
</p>
</div>
<div className="border-b"></div>
<div className="flex-1 flex items-center justify-between">
<h4 className="text-balance"></h4>
<p className="flex flex-col items-end">
<span className="text-sm text-weak"></span>
<span className="text-sm">{props.long.resource_quota_sum}</span>
</p>
</div>
</CardContent>
</Card>
{/* 固定 */}
<Card className="flex-1 py-4 h-full hidden xl:block ">
<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>
)
}
type Props = {
list: {
id: number
title: string
created_at: Date
} []
}
function Announcements(props: Props) {
return (
<Card className="h-full">
<CardHeader>
<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>
<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>
)
: 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>
)
}