mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 07:26:52 +00:00
51
components/ui/dashboard/DashboardBody.js
Normal file
51
components/ui/dashboard/DashboardBody.js
Normal file
@@ -0,0 +1,51 @@
|
||||
'use client'
|
||||
import { UserProfile } from '@clerk/nextjs'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const DashboardMenuList = dynamic(() => import('./DashboardMenuList'))
|
||||
const DashboardItemMembership = dynamic(
|
||||
() => import('./DashboardItemMembership')
|
||||
)
|
||||
const DashboardItemBalance = dynamic(() => import('./DashboardItemBalance'))
|
||||
const DashboardItemHome = dynamic(() => import('./DashboardItemHome'))
|
||||
const DashboardItemOrder = dynamic(() => import('./DashboardItemOrder'))
|
||||
const DashboardItemAffliate = dynamic(() => import('./DashboardItemAffliate'))
|
||||
/**
|
||||
* 仪表盘内容主体
|
||||
* 组件懒加载
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardBody() {
|
||||
const { asPath } = useRouter()
|
||||
// 提取不包含查询参数的路径部分
|
||||
const basePath = asPath.split('?')[0]
|
||||
return (
|
||||
<div className='flex flex-col md:flex-row w-full container gap-x-4 min-h-96 mx-auto mb-12 justify-center'>
|
||||
<div className='side-tabs w-full md:w-72'>
|
||||
<DashboardMenuList />
|
||||
</div>
|
||||
<div className='main-content-wrapper w-full'>
|
||||
{basePath === '/dashboard' && <DashboardItemHome />}
|
||||
{(basePath === '/dashboard/user-profile' ||
|
||||
basePath === '/dashboard/user-profile/security') && (
|
||||
<UserProfile
|
||||
appearance={{
|
||||
elements: {
|
||||
cardBox: 'w-full',
|
||||
rootBox: 'w-full'
|
||||
}
|
||||
}}
|
||||
className='bg-blue-300'
|
||||
routing='path'
|
||||
path='/dashboard/user-profile'
|
||||
/>
|
||||
)}
|
||||
{basePath === '/dashboard/balance' && <DashboardItemBalance />}
|
||||
{basePath === '/dashboard/membership' && <DashboardItemMembership />}
|
||||
{basePath === '/dashboard/order' && <DashboardItemOrder />}
|
||||
{basePath === '/dashboard/affiliate' && <DashboardItemAffliate />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
27
components/ui/dashboard/DashboardButton.js
Normal file
27
components/ui/dashboard/DashboardButton.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import { siteConfig } from '@/lib/config'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
/**
|
||||
* 跳转仪表盘的按钮
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardButton() {
|
||||
const { asPath } = useRouter()
|
||||
const enableDashboardButton = siteConfig('ENABLE_DASHBOARD_BUTTON', false)
|
||||
|
||||
if (!enableDashboardButton) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (asPath?.indexOf('/dashboard') === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className='text-white bg-gray-800 hover:bg-gray-900 hover:ring-4 hover:ring-gray-300 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2 me-2 dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700'>
|
||||
<Link href='/dashboard'>仪表盘</Link>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
53
components/ui/dashboard/DashboardHeader.js
Normal file
53
components/ui/dashboard/DashboardHeader.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import LazyImage from '@/components/LazyImage'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
import formatDate from '@/lib/utils/formatDate'
|
||||
import { SignOutButton } from '@clerk/nextjs'
|
||||
import Link from 'next/link'
|
||||
/**
|
||||
* 仪表盘页头
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardHeader() {
|
||||
const { user } = useGlobal()
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='flex w-full container mx-auto mt-12 mb-12 justify-ends'>
|
||||
{/* 头像昵称 */}
|
||||
<div className='flex items-center gap-4 w-full'>
|
||||
<LazyImage
|
||||
className='w-10 h-10 rounded-full'
|
||||
src={user?.imageUrl}
|
||||
alt={user?.fullName}
|
||||
/>
|
||||
|
||||
<div class='font-medium dark:text-white'>
|
||||
<div className='flex items-center gap-x-2'>
|
||||
<span>{user?.fullName}</span>
|
||||
<Link href='/dashboard/membership'>
|
||||
<span class='bg-gray-100 text-gray-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-gray-700 dark:text-gray-300'>
|
||||
普通用户
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='text-sm text-gray-500 gap-x-2 flex dark:text-gray-400'>
|
||||
<span>{user?.username}</span>
|
||||
<span>{formatDate(user?.createdAt)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 登出按钮 */}
|
||||
<div className='flex items-center'>
|
||||
<SignOutButton redirectUrl='/'>
|
||||
<button className='text-white bg-gray-800 hover:bg-gray-900 hover:ring-4 hover:ring-gray-300 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700'>
|
||||
<span className='text-nowrap'>
|
||||
<i className='fas fa-right-from-bracket' /> Sign Out
|
||||
</span>
|
||||
</button>
|
||||
</SignOutButton>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
187
components/ui/dashboard/DashboardItemAffliate.js
Normal file
187
components/ui/dashboard/DashboardItemAffliate.js
Normal file
@@ -0,0 +1,187 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 联盟行销
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardItemAffliate() {
|
||||
const cards = [
|
||||
{
|
||||
title: '¥0.00',
|
||||
desc: '累计佣金',
|
||||
className: 'bg-blue-600 hover:bg-blue-700 text-white'
|
||||
},
|
||||
{
|
||||
title: '¥0.00',
|
||||
desc: '已提现',
|
||||
className: 'bg-cyan-600 hover:bg-cyan-700 text-white'
|
||||
},
|
||||
{
|
||||
title: '¥0.00',
|
||||
desc: '提现中',
|
||||
className: 'bg-pink-600 hover:bg-pink-700 text-white'
|
||||
},
|
||||
{
|
||||
title: '¥0.00',
|
||||
desc: '可提现',
|
||||
className: 'bg-emerald-600 hover:bg-emerald-700 text-white'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className='bg-white rounded-lg shadow-lg p-6 border'>
|
||||
<div className='grid grid-cols-4 gap-4'>
|
||||
{cards?.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`block max-w-sm p-6 text-center border cursor-pointer rounded-lg shadow ${card.className}`}>
|
||||
<h5 className='mb-2 text-2xl font-bold tracking-tight'>
|
||||
{card.title}
|
||||
</h5>
|
||||
<p className='font-normal'>{card.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<form className='mt-6'>
|
||||
<div className='grid gap-6 mb-6 md:grid-cols-2'>
|
||||
<div>
|
||||
<label
|
||||
for='last_name'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
推广总数
|
||||
</label>
|
||||
<input
|
||||
disabled
|
||||
type='text'
|
||||
id='last_name'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder='123'
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for='company'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
推广链接
|
||||
</label>
|
||||
<input
|
||||
disabled
|
||||
type='text'
|
||||
id='company'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder='https://tangly1024.com'
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
for='website'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
推广佣金提成
|
||||
</label>
|
||||
<input
|
||||
disabled
|
||||
type='url'
|
||||
id='website'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder='5%'
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className='my-6' />
|
||||
|
||||
<div className='grid gap-6 mb-6 md:grid-cols-2'>
|
||||
<div>
|
||||
<label
|
||||
for='first_name'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
提现账号
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
id='first_name'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder='John'
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
for='visitors'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
提现金额
|
||||
</label>
|
||||
<input
|
||||
type='number'
|
||||
id='visitors'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder=''
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex items-start mb-6'>
|
||||
<div className='flex items-center h-5'>
|
||||
<input
|
||||
id='remember'
|
||||
type='checkbox'
|
||||
value=''
|
||||
className='w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-blue-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800'
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
for='remember'
|
||||
className='ms-2 text-sm font-medium text-gray-900 dark:text-gray-300'>
|
||||
我以阅读并同意{' '}
|
||||
<Link
|
||||
href='/terms-of-use'
|
||||
className='text-blue-600 hover:underline dark:text-blue-500'>
|
||||
服务协议
|
||||
</Link>
|
||||
.
|
||||
</label>
|
||||
</div>
|
||||
<div className='flex gap-x-2'>
|
||||
<button
|
||||
type='submit'
|
||||
className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800'>
|
||||
提现RMB
|
||||
</button>
|
||||
<button
|
||||
type='submit'
|
||||
className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800'>
|
||||
提现到余额
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul className='text-gray-600 list-disc pl-6'>
|
||||
<li>推广说明:</li>
|
||||
<li className='font-bold'>这只是一个演示页面,不存在真实功能!</li>
|
||||
<li>
|
||||
如需提现请联系网站管理员,发送您的账号信息和收款码进行人工提现
|
||||
</li>
|
||||
<li>
|
||||
如果用户是通过您的推广链接购买的资源或者开通会员,则按照推广佣金比列奖励到您的佣金中
|
||||
</li>
|
||||
<li>
|
||||
如果用户是通过您的链接新注册的用户,推荐人是您,该用户购买资都会给你佣金
|
||||
</li>
|
||||
<li>
|
||||
如果用户是你的下级,用户使用其他推荐人链接购买,以上下级关系为准,优先给注册推荐人而不是推荐链接
|
||||
</li>
|
||||
<li>推广奖励金额保留一位小数点四舍五入。0.1之类的奖励金额不计算</li>
|
||||
<li>
|
||||
前台无法查看推广订单详情,如需查看详情可联系管理员截图查看详细记录和时间
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
137
components/ui/dashboard/DashboardItemBalance.js
Normal file
137
components/ui/dashboard/DashboardItemBalance.js
Normal file
@@ -0,0 +1,137 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
/**
|
||||
* 余额
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardItemBalance() {
|
||||
const [selectedCard, setSelectedCard] = useState(null)
|
||||
const [amount, setAmount] = useState(0)
|
||||
|
||||
const cards = [
|
||||
{
|
||||
title: '0 积分',
|
||||
desc: '当前余额',
|
||||
className: 'bg-blue-600 hover:bg-blue-700 text-white'
|
||||
},
|
||||
{
|
||||
title: '0 积分',
|
||||
desc: '累计消费',
|
||||
className: 'bg-cyan-600 hover:bg-cyan-700 text-white'
|
||||
},
|
||||
{
|
||||
title: '0',
|
||||
desc: '累计佣金',
|
||||
className: 'bg-pink-600 hover:bg-pink-700 text-white'
|
||||
}
|
||||
]
|
||||
|
||||
const cardData = [
|
||||
{ points: '1积分', price: '¥1' },
|
||||
{ points: '10积分', price: '¥10' },
|
||||
{ points: '50积分', price: '¥50' },
|
||||
{ points: '100积分', price: '¥100' },
|
||||
{ points: '300积分', price: '¥300' },
|
||||
{ points: '500积分', price: '¥500' }
|
||||
]
|
||||
|
||||
const handleCardSelect = index => {
|
||||
setSelectedCard(index)
|
||||
}
|
||||
|
||||
const handleAmountChange = e => {
|
||||
const value = e.target.value
|
||||
setAmount(value)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedCard !== null) {
|
||||
// 如果用户选中了充值卡片,则自动更新支付金额
|
||||
const selectedPrice = cardData[selectedCard]?.price
|
||||
if (selectedPrice) {
|
||||
setAmount(selectedPrice.replace('¥', ''))
|
||||
}
|
||||
}
|
||||
}, [selectedCard])
|
||||
|
||||
return (
|
||||
<div className='bg-white rounded-lg shadow-lg p-6 border'>
|
||||
<div>
|
||||
<h2 className='text-2xl font-bold mb-4'>余额充值中心</h2>
|
||||
<hr className='my-2' />
|
||||
</div>
|
||||
|
||||
{/* 余额卡片 */}
|
||||
<div className='grid grid-cols-3 gap-4'>
|
||||
{cards?.map((card, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`block max-w-sm p-6 text-center border cursor-pointer rounded-lg shadow ${card.className}`}
|
||||
onClick={() => handleCardSelect(index)}>
|
||||
<h5 className='mb-2 text-2xl font-bold tracking-tight'>
|
||||
{card.title}
|
||||
</h5>
|
||||
<p className='font-normal'>{card.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form className='mt-6'>
|
||||
<div className='py-2'>充值项目(充值比例:1元=1积分)</div>
|
||||
{/* 充值选项 */}
|
||||
<div className='grid gap-6 mb-6 grid-cols-4'>
|
||||
{cardData?.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`border rounded-lg text-center bg-gray-50 py-4 cursor-pointer ${
|
||||
selectedCard === index ? 'bg-blue-100' : ''
|
||||
}`}
|
||||
onClick={() => handleCardSelect(index)}>
|
||||
<h3 className='text-yellow-500 font-bold'>{item.points}</h3>
|
||||
<span>{item.price}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<hr className='my-6' />
|
||||
|
||||
<div className='grid gap-6 mb-6 md:grid-cols-2'>
|
||||
<div>
|
||||
<label
|
||||
htmlFor='amount'
|
||||
className='block mb-2 text-sm font-medium text-gray-900 dark:text-white'>
|
||||
充值其它数量
|
||||
</label>
|
||||
<input
|
||||
type='number'
|
||||
id='amount'
|
||||
className='bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500'
|
||||
placeholder='输入数量'
|
||||
value={amount}
|
||||
onChange={handleAmountChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex justify-between w-full'>
|
||||
<div>
|
||||
支付金额:<span className='text-red-500'>¥{amount}</span>
|
||||
</div>
|
||||
<button
|
||||
type='submit'
|
||||
className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800'>
|
||||
在线充值
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul className='text-gray-600 list-disc pl-6'>
|
||||
<li>充值说明:</li>
|
||||
<li className='font-bold'>这只是一个演示页面,不存在真实功能!</li>
|
||||
<li>充值最低额度为1积分</li>
|
||||
<li>充值汇率为1元=1积分,人民币和积分不能互相转换</li>
|
||||
<li>余额永久有效,无时间限制</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
64
components/ui/dashboard/DashboardItemHome.js
Normal file
64
components/ui/dashboard/DashboardItemHome.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 首页组件
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardItemHome() {
|
||||
return (
|
||||
<div className='w-full mx-auto'>
|
||||
{/* 提示消息 */}
|
||||
<div
|
||||
className='p-4 mb-4 text-xl font-bold text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400'
|
||||
role='alert'>
|
||||
<span className='font-medium'>注意!</span>{' '}
|
||||
整个后台都只是页面效果,仅供演示查看,没有对接实际功能。
|
||||
</div>
|
||||
|
||||
{/* 页面说明 */}
|
||||
<div className='mb-8 text-lg text-gray-700 dark:text-gray-300'>
|
||||
<p>
|
||||
欢迎来到用户中心页面!在这里,您可以查看用户的账号信息与业务订单概况。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 进度条 */}
|
||||
<div className='mb-8'>
|
||||
<h3 className='text-xl text-gray-800 dark:text-white'>当前任务进度</h3>
|
||||
<div className='bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 my-2'>
|
||||
<div
|
||||
className='bg-green-500 h-2.5 rounded-full'
|
||||
style={{ width: '75%' }}></div>
|
||||
</div>
|
||||
<p className='text-sm text-gray-500 dark:text-gray-400'>
|
||||
任务进度:75%
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 背景动画块 */}
|
||||
<div className='relative w-full h-64 rounded-lg bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 overflow-hidden'>
|
||||
<div className='absolute inset-0 w-full h-full animate-pulse bg-black opacity-50'></div>
|
||||
<div className='relative z-10 text-center text-white font-bold pt-24'>
|
||||
<h3 className='text-2xl'>实时数据分析</h3>
|
||||
<p className='text-lg'>监控您的系统数据,查看实时变化</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 数据卡片模块 */}
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-8'>
|
||||
<div className='bg-white shadow-lg p-6 rounded-lg hover:scale-105 transition-all transform duration-300'>
|
||||
<h3 className='text-xl text-gray-800 dark:text-white'>今日访问量</h3>
|
||||
<p className='text-3xl text-green-600'>1,245</p>
|
||||
</div>
|
||||
<div className='bg-white shadow-lg p-6 rounded-lg hover:scale-105 transition-all transform duration-300'>
|
||||
<h3 className='text-xl text-gray-800 dark:text-white'>用户总数</h3>
|
||||
<p className='text-3xl text-blue-600'>12,300</p>
|
||||
</div>
|
||||
<div className='bg-white shadow-lg p-6 rounded-lg hover:scale-105 transition-all transform duration-300'>
|
||||
<h3 className='text-xl text-gray-800 dark:text-white'>
|
||||
系统健康状态
|
||||
</h3>
|
||||
<p className='text-3xl text-red-600'>正常</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
125
components/ui/dashboard/DashboardItemMembership.js
Normal file
125
components/ui/dashboard/DashboardItemMembership.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
/**
|
||||
* 会员
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardItemMembership() {
|
||||
const [selectedMembership, setSelectedMembership] = useState(null)
|
||||
const [amount, setAmount] = useState(0)
|
||||
|
||||
const memberships = [
|
||||
{
|
||||
title: '年度会员',
|
||||
points: 98,
|
||||
duration: '365天',
|
||||
benefits: [
|
||||
'日更5到20个热门项目',
|
||||
'全站资源免费获取',
|
||||
'内部会员专属交流群',
|
||||
'可补差价升级',
|
||||
'推广佣金高达40%'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '永久会员',
|
||||
points: 138,
|
||||
duration: '永久',
|
||||
benefits: [
|
||||
'日更5到20个热门项目',
|
||||
'全站资源免费获取',
|
||||
'内部会员专属交流群',
|
||||
'可补差价升级',
|
||||
'推广佣金高达70%'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '站长训练营',
|
||||
points: 1998,
|
||||
duration: '永久',
|
||||
benefits: [
|
||||
'站长学员请联系助理对接',
|
||||
'一对一扶持搭建网站',
|
||||
'提供独家引流技术照做就能成功',
|
||||
'全站素材直接复刻到学员新站',
|
||||
'软件一键同步更新',
|
||||
'学员专属社群及交流群',
|
||||
'设立高额福利的打卡机制(增强学员执行力)'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const handleMembershipSelect = index => {
|
||||
setSelectedMembership(index)
|
||||
setAmount(memberships[index].points)
|
||||
}
|
||||
|
||||
const handleAmountChange = e => {
|
||||
const value = e.target.value
|
||||
setAmount(value)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedMembership !== null) {
|
||||
// 如果用户选中了会员,自动更新支付金额
|
||||
const selectedPoints = memberships[selectedMembership]?.points
|
||||
if (selectedPoints) {
|
||||
setAmount(selectedPoints)
|
||||
}
|
||||
}
|
||||
}, [selectedMembership])
|
||||
|
||||
return (
|
||||
<div className='bg-white rounded-lg shadow-lg p-6 border'>
|
||||
<div>
|
||||
<h2 className='text-2xl font-bold mb-4'>会员注册</h2>
|
||||
<hr className='my-2' />
|
||||
</div>
|
||||
|
||||
{/* 会员卡片 */}
|
||||
<div className='grid grid-cols-3 gap-4'>
|
||||
{memberships.map((membership, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`block max-w-sm p-6 text-center border cursor-pointer rounded-lg shadow ${
|
||||
selectedMembership === index ? 'bg-blue-100' : 'bg-gray-50'
|
||||
}`}
|
||||
onClick={() => handleMembershipSelect(index)}>
|
||||
<h5 className='mb-2 text-2xl font-bold tracking-tight'>
|
||||
{membership.title}
|
||||
</h5>
|
||||
<p className='font-normal'>所需积分:{membership.points} 积分</p>
|
||||
<p className='font-normal'>会员时长:{membership.duration}</p>
|
||||
<ul className='text-gray-600 mt-2'>
|
||||
{membership.benefits.map((benefit, i) => (
|
||||
<li key={i}>{benefit}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<form className='mt-6'>
|
||||
<div className='flex justify-between w-full mb-4'>
|
||||
<div>
|
||||
支付金额:<span className='text-red-500'>¥{amount}</span>
|
||||
</div>
|
||||
<button
|
||||
type='submit'
|
||||
className='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800'>
|
||||
立即开通
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul className='text-gray-600 list-disc pl-6'>
|
||||
<li>开通会员说明:</li>
|
||||
<li className='font-bold'>这只是一个演示页面,不存在真实功能!</li>
|
||||
<li>本站会员账号权限为虚拟数字资源,开通后不可退款</li>
|
||||
<li>开通会员后可享有对应会员特权的商品折扣,免费权限</li>
|
||||
<li>会员特权到期后不享受特权</li>
|
||||
<li>重复购买特权到期时间累计增加</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
246
components/ui/dashboard/DashboardItemOrder.js
Normal file
246
components/ui/dashboard/DashboardItemOrder.js
Normal file
@@ -0,0 +1,246 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
/**
|
||||
* 订单列表
|
||||
*/
|
||||
export default function DashboardItemOrder() {
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
|
||||
const totalPages = 5
|
||||
|
||||
const columns = [
|
||||
{ key: 'name', label: '商品名称' },
|
||||
{ key: 'color', label: '颜色' },
|
||||
{ key: 'category', label: '分类' },
|
||||
{
|
||||
key: 'accessories',
|
||||
label: '配件',
|
||||
render: value => (value ? '是' : '否')
|
||||
},
|
||||
{ key: 'available', label: '库存', render: value => (value ? '有' : '无') },
|
||||
{ key: 'price', label: '价格', render: value => `¥${value}` },
|
||||
{ key: 'weight', label: '重量' },
|
||||
{
|
||||
key: 'action',
|
||||
label: '操作',
|
||||
render: () => (
|
||||
<div className='flex items-center space-x-3'>
|
||||
<a
|
||||
href='#'
|
||||
className='font-medium text-blue-600 dark:text-blue-500 hover:underline'>
|
||||
编辑
|
||||
</a>
|
||||
<a
|
||||
href='#'
|
||||
className='font-medium text-red-600 dark:text-red-500 hover:underline'>
|
||||
删除
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: '苹果 MacBook Pro 17"',
|
||||
color: '银色',
|
||||
category: '笔记本',
|
||||
accessories: true,
|
||||
available: true,
|
||||
price: 2999,
|
||||
weight: '3.0 公斤'
|
||||
},
|
||||
{
|
||||
name: '微软 Surface Pro',
|
||||
color: '白色',
|
||||
category: '笔记本电脑',
|
||||
accessories: false,
|
||||
available: true,
|
||||
price: 1999,
|
||||
weight: '1.0 公斤'
|
||||
},
|
||||
{
|
||||
name: 'Magic Mouse 2',
|
||||
color: '黑色',
|
||||
category: '配件',
|
||||
accessories: true,
|
||||
available: false,
|
||||
price: 99,
|
||||
weight: '0.2 公斤'
|
||||
},
|
||||
{
|
||||
name: '苹果手表',
|
||||
color: '黑色',
|
||||
category: '手表',
|
||||
accessories: true,
|
||||
available: false,
|
||||
price: 199,
|
||||
weight: '0.12 公斤'
|
||||
},
|
||||
{
|
||||
name: 'iPad Pro',
|
||||
color: '金色',
|
||||
category: '平板电脑',
|
||||
accessories: false,
|
||||
available: true,
|
||||
price: 699,
|
||||
weight: '1.3 公斤'
|
||||
}
|
||||
]
|
||||
|
||||
const onPageChange = page => {
|
||||
if (page >= 1 && page <= totalPages) {
|
||||
setCurrentPage(page)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='bg-white rounded-lg shadow-lg p-6 border'>
|
||||
<div className='flex flex-col'>
|
||||
<Table columns={columns} data={data} />
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
onPageChange={onPageChange}
|
||||
/>
|
||||
<ul className='text-gray-600 list-disc pl-6'>
|
||||
<li>订单说明:</li>
|
||||
<li className='font-bold'>这只是一个演示页面,不存在真实功能!</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页组件
|
||||
*/
|
||||
const Pagination = ({ currentPage, totalPages, onPageChange }) => {
|
||||
const pages = Array.from({ length: totalPages }, (_, i) => i + 1)
|
||||
|
||||
return (
|
||||
<nav
|
||||
aria-label='page-navigation'
|
||||
className='w-full flex mx-auto justify-center items-center py-4'>
|
||||
<ul className='inline-flex -space-x-px text-sm'>
|
||||
{/* 上一页 */}
|
||||
<li>
|
||||
<button
|
||||
onClick={() => onPageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1}
|
||||
className={`flex items-center justify-center px-3 h-8 ms-0 leading-tight border border-e-0 rounded-s-lg ${
|
||||
currentPage === 1
|
||||
? 'text-gray-400 bg-gray-200 cursor-not-allowed'
|
||||
: 'text-gray-500 bg-white hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white'
|
||||
}`}>
|
||||
上一页
|
||||
</button>
|
||||
</li>
|
||||
|
||||
{/* 页码列表 */}
|
||||
{pages.map(page => (
|
||||
<li key={page}>
|
||||
<button
|
||||
onClick={() => onPageChange(page)}
|
||||
className={`flex items-center justify-center px-3 h-8 leading-tight border ${
|
||||
currentPage === page
|
||||
? 'text-blue-600 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white'
|
||||
: 'text-gray-500 bg-white hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white'
|
||||
}`}>
|
||||
{page}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
||||
{/* 下一页 */}
|
||||
<li>
|
||||
<button
|
||||
onClick={() => onPageChange(currentPage + 1)}
|
||||
disabled={currentPage === totalPages}
|
||||
className={`flex items-center justify-center px-3 h-8 leading-tight border rounded-e-lg ${
|
||||
currentPage === totalPages
|
||||
? 'text-gray-400 bg-gray-200 cursor-not-allowed'
|
||||
: 'text-gray-500 bg-white hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white'
|
||||
}`}>
|
||||
下一页
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格组件
|
||||
*/
|
||||
const Table = ({ columns, data }) => {
|
||||
return (
|
||||
<div className='relative overflow-x-auto shadow-md sm:rounded-lg'>
|
||||
<table className='w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400'>
|
||||
{/* 表头 */}
|
||||
<thead className='text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400'>
|
||||
<tr>
|
||||
<th scope='col' className='p-4 w-4'>
|
||||
<div className='flex items-center'>
|
||||
<input
|
||||
id='checkbox-all'
|
||||
type='checkbox'
|
||||
className='w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600'
|
||||
/>
|
||||
<label htmlFor='checkbox-all' className='sr-only'>
|
||||
全选
|
||||
</label>
|
||||
</div>
|
||||
</th>
|
||||
{columns.map((column, index) => (
|
||||
<th
|
||||
key={index}
|
||||
scope='col'
|
||||
className={`${
|
||||
column.key === 'name'
|
||||
? 'px-6 py-3 w-[25%]'
|
||||
: 'px-4 py-3 w-[10%]'
|
||||
}`}>
|
||||
{column.label}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
{/* 表格内容 */}
|
||||
<tbody>
|
||||
{data.map((item, index) => (
|
||||
<tr
|
||||
key={index}
|
||||
className='bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600'>
|
||||
<td className='w-4 p-4'>
|
||||
<div className='flex items-center'>
|
||||
<input
|
||||
id={`checkbox-${index}`}
|
||||
type='checkbox'
|
||||
className='w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600'
|
||||
/>
|
||||
<label htmlFor={`checkbox-${index}`} className='sr-only'>
|
||||
选择
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
{columns.map((column, colIndex) => (
|
||||
<td
|
||||
key={colIndex}
|
||||
className={`${
|
||||
column.key === 'name'
|
||||
? 'px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white w-[25%]'
|
||||
: 'px-4 py-4 w-[10%]'
|
||||
}`}>
|
||||
{column.render
|
||||
? column.render(item[column.key])
|
||||
: item[column.key]}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
57
components/ui/dashboard/DashboardMenuList.js
Normal file
57
components/ui/dashboard/DashboardMenuList.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
/**
|
||||
* 仪表盘菜单
|
||||
* @returns
|
||||
*/
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
/**
|
||||
* 仪表盘菜单
|
||||
* @returns
|
||||
*/
|
||||
export default function DashboardMenuList() {
|
||||
const { asPath } = useRouter() // 获取当前路径
|
||||
const dashBoardMenus = [
|
||||
{ title: '仪表盘', icon: 'fas fa-gauge', href: '/dashboard' },
|
||||
{ title: '基础资料', icon: 'fas fa-user', href: '/dashboard/user-profile' },
|
||||
{ title: '我的余额', icon: 'fas fa-coins', href: '/dashboard/balance' },
|
||||
{ title: '我的会员', icon: 'fas fa-gem', href: '/dashboard/membership' },
|
||||
{
|
||||
title: '我的订单',
|
||||
icon: 'fas fa-cart-shopping',
|
||||
href: '/dashboard/order'
|
||||
},
|
||||
{
|
||||
title: '推广中心',
|
||||
icon: 'fas fa-hand-holding-usd',
|
||||
href: '/dashboard/affiliate'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<ul
|
||||
role='menu'
|
||||
className='side-tabs-list bg-white border rounded-lg shadow-lg p-2 space-y-2 mb-6'>
|
||||
{dashBoardMenus.map((item, index) => {
|
||||
// 判断当前菜单是否高亮
|
||||
const isActive = asPath === item.href
|
||||
return (
|
||||
<li
|
||||
role='menuitem'
|
||||
key={index}
|
||||
className={`rounded-lg cursor-pointer block ${
|
||||
isActive ? 'bg-blue-100 text-blue-600' : 'hover:bg-gray-100'
|
||||
}`}>
|
||||
<Link
|
||||
href={item.href}
|
||||
className='block py-2 px-4 w-full items-center justify-center'>
|
||||
<i className={`${item.icon} w-6 mr-2`}></i>
|
||||
<span className='whitespace-nowrap'>{item.title}</span>
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user