Files
juip-web/src/admin/dashboard/page.tsx

429 lines
15 KiB
TypeScript
Raw Normal View History

2026-07-30 13:55:28 +08:00
import { useState } from "react"
import {
EditInfoDialog,
type EditInfoValues,
} from "@/components/composites/dialogs/editInfoDialog"
2026-07-30 13:55:28 +08:00
import DataTable from "@/components/data-table"
2026-07-24 18:00:22 +08:00
import Page from "@/components/page"
2026-07-30 13:55:28 +08:00
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import b3 from "../assets/b3.webp"
import b5 from "../assets/b5.webp"
import b6 from "../assets/b6.webp"
import b7 from "../assets/b7.webp"
import b8 from "../assets/b8.webp"
import b9 from "../assets/b9.webp"
import b10 from "../assets/b10.webp"
import b11 from "../assets/b11.webp"
import b12 from "../assets/b12.webp"
import banner from "../assets/banner.webp"
import banner2 from "../assets/banner2.webp"
2026-07-24 18:00:22 +08:00
export default function DashboardPage() {
// ========== 数据定义 ==========
2026-07-30 13:55:28 +08:00
const balanceData = {
balance: 68.0,
hCoin: 68.0,
2026-07-30 13:55:28 +08:00
}
const accountInfo = {
phone: "191****1234",
qq: "123456123",
wechat: "123456123",
email: "123456123@qq.com",
taobao: "123456123",
}
const recentOrders = [
{
date: "2025.04.01",
product: "极光IP",
plan: "天卡(尊享)",
price: 3.0,
connections: 1,
account: "jx1234",
orderAmount: 3.0,
paidAmount: 3.0,
},
{
date: "2025.04.01",
product: "极光IP",
plan: "天卡(尊享)",
price: 3.0,
connections: 1,
account: "jx1234",
orderAmount: 3.0,
paidAmount: 3.0,
},
]
// 设计稿数据 - 全部显示30
2026-07-30 13:55:28 +08:00
const consumptionData = {
today: 30.0,
month: 30.0,
todayRefund: 30.0,
year: 30.0,
todayRecharge: 30.0,
monthRecharge: 30.0,
monthRefund: 30.0,
2026-07-30 13:55:28 +08:00
}
const ipAccountData = {
using: 30,
total: 50,
expired: 20,
yearConsumption: 30,
2026-07-30 13:55:28 +08:00
}
2026-07-30 13:55:28 +08:00
const [editDialogOpen, setEditDialogOpen] = useState(false)
const handleSaveInfo = (data: EditInfoValues) => {
2026-07-30 13:55:28 +08:00
console.log("保存的信息:", data)
}
// ========== 渲染 ==========
2026-07-30 13:55:28 +08:00
return (
<Page
className={cn(
"grid gap-4 p-4",
"grid-cols-1",
"md:grid-cols-[1fr_1fr_1fr_300px]",
"md:grid-rows-[150px_200px_1fr_1fr]",
2026-07-30 13:55:28 +08:00
)}
>
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 md:row-start-1 md:col-start-1 md:col-span-3">
{/* 第一个卡片 */}
<div className="flex items-center justify-between overflow-hidden rounded-lg p-5 bg-linear-to-b from-blue-200 to-blue-50">
2026-07-30 13:55:28 +08:00
<div className="flex flex-col gap-4 min-w-0">
<div>
<span className="text-sm font-medium text-gray-500">
可用余额(元)
</span>
</div>
<div className="flex flex-wrap items-center gap-4 sm:gap-8">
<p className="text-2xl sm:text-3xl font-bold">
{balanceData.balance.toFixed(2)}
2026-07-30 13:55:28 +08:00
</p>
<div className="flex gap-2 sm:gap-4">
<Button
size="sm"
variant="outline"
className="text-xs bg-white text-blue-600 hover:bg-white/90 hover:text-blue-700"
>
去提现
</Button>
<Button
size="sm"
className="text-xs bg-white text-blue-600 hover:bg-white/90 hover:text-blue-700"
>
去充值
</Button>
</div>
</div>
</div>
<img
src={banner}
alt="banner"
className="w-16 h-16 sm:w-24 sm:h-24 object-contain shrink-0"
/>
</div>
{/* 第二个卡片 */}
<div className="flex items-center justify-between overflow-hidden rounded-lg p-5 bg-linear-to-b from-cyan-200 to-cyan-50">
2026-07-30 13:55:28 +08:00
<div className="flex flex-col gap-4 min-w-0">
<div>
<p className="text-sm font-medium text-gray-500">可用H币(个)</p>
</div>
<div className="flex flex-wrap items-center gap-4 sm:gap-8">
<p className="text-2xl sm:text-3xl font-bold">
{balanceData.hCoin.toFixed(2)}
2026-07-30 13:55:28 +08:00
</p>
<Button
size="sm"
variant="outline"
className="text-xs bg-white text-blue-600 hover:bg-white/90 hover:text-blue-700"
>
去充值
</Button>
</div>
</div>
<img
src={banner2}
alt="banner2"
className="w-16 h-16 sm:w-24 sm:h-24 object-contain shrink-0"
/>
</div>
</section>
<div className="md:col-start-4 md:row-start-1 md:row-span-2 bg-white rounded-lg p-4 flex flex-col min-h-0">
<h3 className="font-semibold text-lg shrink-0">账号信息</h3>
<div className="mt-4 flex flex-col sm:flex-row justify-between items-start gap-4 flex-1 min-h-0">
{/* 头像/二维码区域 */}
<div className="flex flex-col items-center gap-3 shrink-0 w-full sm:w-auto">
<span className="text-base font-medium truncate w-full text-center sm:text-left">
{accountInfo.phone}
</span>
<Button
variant="outline"
size="sm"
className="w-20 text-xs bg-white text-blue-600 hover:bg-white/90 hover:text-blue-700 border border-blue-600"
>
去实名
</Button>
<div className="w-20 h-20 border border-gray-200 rounded shrink-0 overflow-hidden">
<img
src="/qrcode-placeholder.png"
alt="账号二维码"
className="w-full h-full object-cover"
/>
</div>
</div>
{/* 信息列表 */}
<div className="flex flex-col gap-2 text-sm flex-1 min-w-0 w-full">
<div className="flex items-start py-1 border-b border-gray-50 last:border-0 min-h-7">
<span className="text-gray-400 w-14 shrink-0">密码</span>
<span className="text-gray-700 font-mono tracking-wide truncate">
********
</span>
</div>
<div className="flex items-start py-1 border-b border-gray-50 last:border-0 min-h-7">
<span className="text-gray-400 w-14 shrink-0">QQ</span>
<span className="text-gray-700 truncate">
{accountInfo.qq || "未绑定"}
</span>
</div>
<div className="flex items-start py-1 border-b border-gray-50 last:border-0 min-h-7">
<span className="text-gray-400 w-14 shrink-0">微信号</span>
<span className="text-gray-700 truncate">
{accountInfo.wechat || "未绑定"}
</span>
</div>
<div className="flex items-start py-1 border-b border-gray-50 last:border-0 min-h-7">
<span className="text-gray-400 w-14 shrink-0">淘宝</span>
<span className="text-gray-700 truncate">
{accountInfo.taobao || "未绑定"}
</span>
</div>
<div className="flex items-start py-1 border-b border-gray-50 last:border-0 min-h-7">
<span className="text-gray-400 w-14 shrink-0">邮箱</span>
<span className="text-gray-700 truncate">
{accountInfo.email || "未绑定"}
</span>
</div>
</div>
</div>
<div className="mt-4 flex justify-end shrink-0">
<Button
variant="outline"
size="sm"
className="text-xs bg-white text-blue-600 hover:bg-white/90 hover:text-blue-700 border-transparent hover:border-blue-200"
onClick={() => setEditDialogOpen(true)}
>
编辑信息
</Button>
</div>
</div>
{/* ====== 第二行:最近订单(占左侧3列) ====== */}
2026-07-30 13:55:28 +08:00
<div className="md:row-start-2 md:col-start-1 md:col-span-3 bg-white rounded-lg p-4 flex flex-col min-h-0">
<h3 className="font-semibold text-lg mb-4 shrink-0">最近订单</h3>
<div className="flex-1 overflow-auto min-h-0">
<DataTable
data={recentOrders}
status="done"
columns={[
{ accessorKey: "date", header: "日期" },
{ accessorKey: "product", header: "产品" },
{ accessorKey: "plan", header: "套餐" },
{
accessorKey: "price",
header: "单价(元)",
cell: ({ row }) => row.original.price.toFixed(2),
},
{ accessorKey: "connections", header: "总连接数" },
{ accessorKey: "account", header: "账号" },
{
accessorKey: "orderAmount",
header: "订单金额(元)",
cell: ({ row }) => row.original.orderAmount.toFixed(2),
},
{
accessorKey: "paidAmount",
header: "实付金额(元)",
cell: ({ row }) => row.original.paidAmount.toFixed(2),
},
]}
/>
</div>
</div>
{/* ====== 第三、四行:消费信息 + IP账号 ====== */}
{/* 消费信息 - 占左侧3列,跨2行 */}
2026-07-30 13:55:28 +08:00
<div className="md:col-start-1 md:row-start-3 md:col-span-3 md:row-span-2 bg-white rounded-lg p-4">
<div className="flex items-center justify-between mb-4">
<h3 className="font-semibold text-lg">消费信息</h3>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{/* 今日消费 */}
2026-07-30 13:55:28 +08:00
<div className="bg-blue-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b3}
alt="今日消费"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">今日消费</p>
<p className="text-lg sm:text-2xl font-bold text-blue-600">
{consumptionData.today}
</p>
</div>
</div>
{/* 当月消费 */}
2026-07-30 13:55:28 +08:00
<div className="bg-cyan-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b5}
alt="当月消费"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">当月消费</p>
<p className="text-lg sm:text-2xl font-bold text-cyan-600">
{consumptionData.month}
</p>
</div>
</div>
{/* 今日退款 */}
2026-07-30 13:55:28 +08:00
<div className="bg-orange-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b6}
alt="今日退款"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">今日退款</p>
<p className="text-lg sm:text-2xl font-bold text-orange-600">
{consumptionData.todayRefund}
</p>
</div>
</div>
{/* 本年消费 */}
2026-07-30 13:55:28 +08:00
<div className="bg-fuchsia-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b7}
alt="本年消费"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">本年消费</p>
<p className="text-lg sm:text-2xl font-bold text-fuchsia-600">
{consumptionData.year}
</p>
</div>
</div>
{/* 今日充值 */}
2026-07-30 13:55:28 +08:00
<div className="bg-amber-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b8}
alt="今日充值"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">今日充值</p>
<p className="text-lg sm:text-2xl font-bold text-amber-600">
{consumptionData.todayRecharge}
</p>
</div>
</div>
{/* 当月充值 */}
2026-07-30 13:55:28 +08:00
<div className="bg-emerald-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b9}
alt="当月充值"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">当月充值</p>
<p className="text-lg sm:text-2xl font-bold text-emerald-600">
{consumptionData.monthRecharge}
</p>
</div>
</div>
{/* 当月退款 */}
2026-07-30 13:55:28 +08:00
<div className="bg-purple-50 rounded-lg p-3 sm:p-4 flex items-center gap-2 sm:gap-3">
<img
src={b6}
alt="当月退款"
className="w-8 h-8 sm:w-10 sm:h-10 shrink-0"
/>
<div className="min-w-0">
<p className="text-xs sm:text-sm text-gray-500">当月退款</p>
<p className="text-lg sm:text-2xl font-bold text-purple-600">
{consumptionData.monthRefund}
</p>
</div>
</div>
</div>
</div>
{/* ====== IP账号(占右侧1列,跨2行) ====== */}
2026-07-30 13:55:28 +08:00
<div className="md:col-start-4 md:row-start-3 md:row-span-2 bg-white rounded-lg p-4">
<h3 className="font-semibold text-lg mb-6">IP账号</h3>
<div className="grid grid-cols-3 gap-4 text-center">
{/* 使用中 */}
2026-07-30 13:55:28 +08:00
<div className="flex flex-col items-center gap-3">
<div className="w-16 h-16 flex items-center justify-center">
<img
src={b10}
alt="使用中"
2026-07-30 13:55:28 +08:00
className="w-10 h-10 object-contain"
/>
</div>
<p className="text-3xl font-bold">{ipAccountData.using}</p>
<p className="text-gray-500 text-sm">使用中</p>
2026-07-30 13:55:28 +08:00
</div>
{/* 总个数 */}
2026-07-30 13:55:28 +08:00
<div className="flex flex-col items-center gap-3">
<div className="w-16 h-16 flex items-center justify-center">
<img
src={b12}
alt="总个数"
2026-07-30 13:55:28 +08:00
className="w-10 h-10 object-contain"
/>
</div>
<p className="text-3xl font-bold">{ipAccountData.total}</p>
<p className="text-gray-500 text-sm">总个数</p>
2026-07-30 13:55:28 +08:00
</div>
{/* 已过期 */}
2026-07-30 13:55:28 +08:00
<div className="flex flex-col items-center gap-3">
<div className="w-16 h-16 flex items-center justify-center">
<img
src={b11}
alt="已过期"
2026-07-30 13:55:28 +08:00
className="w-10 h-10 object-contain"
/>
</div>
<p className="text-3xl font-bold">{ipAccountData.expired}</p>
<p className="text-gray-500 text-sm">已过期</p>
2026-07-30 13:55:28 +08:00
</div>
</div>
</div>
2026-07-30 13:55:28 +08:00
<EditInfoDialog
open={editDialogOpen}
onOpenChange={setEditDialogOpen}
onSave={handleSaveInfo}
/>
</Page>
)
2026-07-24 18:00:22 +08:00
}