'use client' import {useEffect, useState, useContext, useRef} from 'react' import Page from '@/components/page' import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs' import {Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle} from '@/components/ui/card' import {Form, FormField, FormLabel} from '@/components/ui/form' import {Button} from '@/components/ui/button' import {Input} from '@/components/ui/input' import {useForm} from 'react-hook-form' import {zodResolver} from '@hookform/resolvers/zod' import * as z from 'zod' import {AuthContext} from '@/components/providers/AuthProvider' import {Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger} from '@/components/ui/dialog' import {toast} from 'sonner' import {Alert, AlertDescription, AlertTitle} from '@/components/ui/alert' import {CheckCircle, AlertCircle, Shield, Wallet, CreditCard, QrCode, UserIcon} from 'lucide-react' import * as qrcode from 'qrcode' import Link from 'next/link' import RechargeModal from '@/components/composites/purchase/_client/recharge' import {User} from '@/lib/models' export type ProfilePageProps = {} export default function ProfilePage(props: ProfilePageProps) { const authCtx = useContext(AuthContext) const profile = authCtx.profile // 默认选中的Tab const [activeTab, setActiveTab] = useState('basic') if (!profile) { return (
加载中 正在加载个人信息,请稍候...
) } return (
基本信息 安全设置 余额管理 实名认证
{/* 侧边栏:客服经理信息 */}
账户概览

用户名

{profile.name || profile.username}

手机号

{profile.phone ? maskPhone(profile.phone) : '未设置'}

账户余额

¥{profile.balance || 0}

实名认证

{profile.id_token ? ( <> 已认证 ) : ( <> 未认证 )}

{profile.contact_wechat && ( 专属客服经理

扫描上方二维码添加客服经理微信
获取更多帮助与支持

)}
) } // 基本信息组件 function BasicInfoTab(props: { profile: User refreshProfile: () => Promise }) { const {profile, refreshProfile} = props const basicInfoSchema = z.object({ name: z.string().min(2, '名称至少需要2个字符'), email: z.string().email('请输入有效的邮箱地址').or(z.string().length(0)), }) type BasicInfoShema = z.infer const form = useForm({ resolver: zodResolver(basicInfoSchema), defaultValues: { name: profile.name || '', email: profile.email || '', }, }) const [isSubmitting, setIsSubmitting] = useState(false) const onSubmit = async (data: BasicInfoShema) => { setIsSubmitting(true) try { // 这里会调用更新用户信息的API // 示例: await updateUserProfile(data) toast.success('基本信息更新成功') await refreshProfile() } catch (error) { toast.error('更新失败', { description: (error as Error).message || '请稍后重试', }) } finally { setIsSubmitting(false) } } return (
{({id, field}) => ( )} {({id, field}) => ( )}
) } // 安全设置组件 function SecurityTab(props: { profile: User refreshProfile: () => Promise }) { const {profile, refreshProfile} = props const [showPhoneDialog, setShowPhoneDialog] = useState(false) const [showPasswordDialog, setShowPasswordDialog] = useState(false) return (

手机号

{profile.phone ? maskPhone(profile.phone) : '未设置手机号'}

密码

定期修改密码可以保障您的账户安全

账号保护

开启登录保护,提升账号安全

{/* 修改手机号对话框 */} {/* 修改密码对话框 */}
) } // 余额管理组件 function BalanceTab(props: { profile: User refreshProfile: () => Promise }) { const {profile} = props // 交易历史记录示例数据 const transactions = [ {id: 1, type: '充值', amount: 100, date: '2025-04-18', status: '成功'}, {id: 2, type: '购买套餐', amount: -50, date: '2025-04-15', status: '成功'}, {id: 3, type: '系统赠送', amount: 10, date: '2025-04-10', status: '成功'}, ] return (

当前余额: ¥{profile.balance || 0}

您可以随时充值或查看交易记录

近期交易记录

类型
金额
日期
状态
{transactions.map(tx => (
{tx.type}
= 0 ? 'text-green-600' : 'text-red-600'}> {tx.amount >= 0 ? `+${tx.amount}` : tx.amount}
{tx.date}
{tx.status}
))}
) } // 实名认证组件 function IdentifyTab(props: { profile: User refreshProfile: () => Promise }) { const {profile} = props return (
{profile.id_token ? (

您已完成实名认证

认证信息已通过验证,可以正常使用所有功能

认证姓名

{maskName(profile.name)}

身份证号

{maskIdNumber(profile.id_no)}

) : (

您尚未完成实名认证

根据相关法律法规要求,使用HTTP代理服务需要先完成实名认证

)} 重要提示 为响应国家相关规定,使用HTTP代理需完成实名认证。 认证服务由支付宝提供,您的个人信息将受到严格保护,仅用于账户安全认证。
) } // 修改手机号对话框 function ChangePhoneDialog(props: { open: boolean onOpenChange: (open: boolean) => void currentPhone?: string refreshProfile: () => Promise }) { const {open, onOpenChange, currentPhone, refreshProfile} = props const phoneChangeSchema = z.object({ newPhone: z.string().length(11, '请输入11位手机号码'), verifyCode: z.string().min(4, '请输入验证码'), }) type PhoneChangeSchema = z.infer const form = useForm({ resolver: zodResolver(phoneChangeSchema), defaultValues: { newPhone: '', verifyCode: '', }, }) const [isSubmitting, setIsSubmitting] = useState(false) const [countdown, setCountdown] = useState(0) const onSubmit = async (data: PhoneChangeSchema) => { setIsSubmitting(true) try { // 这里调用修改手机号的API // 示例: await changePhone(data.newPhone, data.verifyCode) toast.success('手机号更新成功') await refreshProfile() onOpenChange(false) } catch (error) { toast.error('更新失败', { description: (error as Error).message || '请稍后重试', }) } finally { setIsSubmitting(false) } } const sendVerifyCode = () => { const newPhone = form.getValues('newPhone') if (!newPhone || newPhone.length !== 11) { form.setError('newPhone', {message: '请输入有效的手机号码'}) return } // 这里调用发送验证码的API // 示例: await sendSmsCode(newPhone) toast.success('验证码已发送') // 开始倒计时 setCountdown(60) const timer = setInterval(() => { setCountdown(prev => { if (prev <= 1) { clearInterval(timer) return 0 } return prev - 1 }) }, 1000) } return ( 修改手机号
{currentPhone && (
当前手机号
)} {({id, field}) => ( )} {({id, field}) => (
)}
) } // 修改密码对话框 function ChangePasswordDialog(props: { open: boolean onOpenChange: (open: boolean) => void refreshProfile: () => Promise }) { const {open, onOpenChange, refreshProfile} = props const passwordChangeSchema = z.object({ oldPassword: z.string().min(6, '密码至少需要6个字符'), newPassword: z.string().min(6, '密码至少需要6个字符'), confirmPassword: z.string().min(6, '密码至少需要6个字符'), }).refine(data => data.newPassword === data.confirmPassword, { message: '两次输入的新密码不一致', path: ['confirmPassword'], }) type PasswordChangeSchema = z.infer const form = useForm({ resolver: zodResolver(passwordChangeSchema), defaultValues: { oldPassword: '', newPassword: '', confirmPassword: '', }, }) const [isSubmitting, setIsSubmitting] = useState(false) const onSubmit = async (data: PasswordChangeSchema) => { setIsSubmitting(true) try { // 这里调用修改密码的API // 示例: await changePassword(data.oldPassword, data.newPassword) toast.success('密码修改成功') onOpenChange(false) } catch (error) { toast.error('修改失败', { description: (error as Error).message || '请稍后重试', }) } finally { setIsSubmitting(false) } } return ( 修改密码
{({id, field}) => ( )} {({id, field}) => ( )} {({id, field}) => ( )}
) } // 客服经理二维码组件 function ServiceManagerQRCode(props: { wechat?: string }) { const {wechat} = props const canvasRef = useRef(null) useEffect(() => { if (wechat && canvasRef.current) { qrcode.toCanvas(canvasRef.current, wechat, { width: 180, margin: 0, }).catch(err => { console.error(err) }) } }, [wechat]) return (
) } // 工具函数:遮盖手机号 function maskPhone(phone?: string) { if (!phone) return '' return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') } // 工具函数:遮盖姓名 function maskName(name?: string) { if (!name) return '' if (name.length <= 2) { return name.charAt(0) + '*' } const stars = '*'.repeat(name.length - 2) return name.charAt(0) + stars + name.charAt(name.length - 1) } // 工具函数:遮盖身份证号 function maskIdNumber(idNumber?: string) { if (!idNumber) return '' return idNumber.replace(/^(.{4})(.*)(.{4})$/, '$1**********$3') }