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

200 lines
6.9 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'
export type DashboardPageProps = {}
export default async function DashboardPage(props: DashboardPageProps) {
const resp = await listInitialization()
console.log(resp, 'respresprespresprespresp')
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
// 添加模拟的 usage 数据(如果 API 返回的 usage 为 null
// if (!initData.usage) {
// initData.usage = [
// {time: new Date('2025-03-01'), count: 100, count2: 80},
// {time: new Date('2025-03-02'), count: 150, count2: 120},
// {time: new Date('2025-03-03'), count: 80, count2: 64},
// {time: new Date('2025-03-04'), count: 200, count2: 160},
// {time: new Date('2025-03-05'), count: 120, count2: 96},
// ]
// }
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
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)}
/>
)}
{/* 图表 */}
<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 DashboardChartProps = {
short_term: string
short_term_monthly: string
long_term: string
long_term_monthly: string
}
function Pins(props: DashboardChartProps) {
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_term}</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_term_monthly}</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_term}</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_term_monthly}</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>
<span className="text-sm text-primary font-medium"></span>
</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>
)
}