- 创建 Toast 通知组件,替换所有 alert() 调用 - 修复 useReview hook 内存泄漏(setInterval 清理) - 移除所有 console.error 和 console.log 语句 - 为复制操作失败添加用户友好的 toast 提示 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
252 lines
10 KiB
TypeScript
252 lines
10 KiB
TypeScript
'use client'
|
||
|
||
import React, { useState } from 'react'
|
||
import { useRouter } from 'next/navigation'
|
||
import { ArrowLeft, Camera, Check, Copy } from 'lucide-react'
|
||
import { ResponsiveLayout } from '@/components/layout/ResponsiveLayout'
|
||
import { Button } from '@/components/ui/Button'
|
||
import { Input } from '@/components/ui/Input'
|
||
import { cn } from '@/lib/utils'
|
||
import { useToast } from '@/components/ui/Toast'
|
||
|
||
// 模拟用户数据
|
||
const mockUser = {
|
||
name: '李小红',
|
||
initial: '李',
|
||
creatorId: 'CR123456', // 达人ID(系统生成,不可修改)
|
||
phone: '138****8888',
|
||
email: 'lixiaohong@example.com',
|
||
douyinAccount: '@xiaohong_creator',
|
||
bio: '专注美妆护肤分享,与你一起变美~',
|
||
}
|
||
|
||
export default function ProfileEditPage() {
|
||
const router = useRouter()
|
||
const toast = useToast()
|
||
const [isSaving, setIsSaving] = useState(false)
|
||
const [idCopied, setIdCopied] = useState(false)
|
||
const [formData, setFormData] = useState({
|
||
name: mockUser.name,
|
||
phone: mockUser.phone,
|
||
email: mockUser.email,
|
||
douyinAccount: mockUser.douyinAccount,
|
||
bio: mockUser.bio,
|
||
})
|
||
|
||
// 复制达人ID
|
||
const handleCopyId = async () => {
|
||
try {
|
||
await navigator.clipboard.writeText(mockUser.creatorId)
|
||
setIdCopied(true)
|
||
setTimeout(() => setIdCopied(false), 2000)
|
||
} catch {
|
||
toast.error('复制失败,请重试')
|
||
}
|
||
}
|
||
|
||
// 处理输入变化
|
||
const handleInputChange = (field: string, value: string) => {
|
||
setFormData(prev => ({ ...prev, [field]: value }))
|
||
}
|
||
|
||
// 保存
|
||
const handleSave = async () => {
|
||
setIsSaving(true)
|
||
// 模拟保存
|
||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||
setIsSaving(false)
|
||
router.back()
|
||
}
|
||
|
||
return (
|
||
<ResponsiveLayout role="creator">
|
||
<div className="flex flex-col gap-6 h-full">
|
||
{/* 顶部栏 */}
|
||
<div className="flex items-center gap-4">
|
||
<button
|
||
type="button"
|
||
onClick={() => router.back()}
|
||
className="w-10 h-10 rounded-xl bg-bg-elevated flex items-center justify-center hover:bg-bg-elevated/80 transition-colors"
|
||
>
|
||
<ArrowLeft size={20} className="text-text-secondary" />
|
||
</button>
|
||
<div className="flex flex-col gap-1">
|
||
<h1 className="text-2xl lg:text-[28px] font-bold text-text-primary">编辑个人信息</h1>
|
||
<p className="text-sm lg:text-[15px] text-text-secondary">更新您的头像和基本资料</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 内容区 */}
|
||
<div className="flex flex-col lg:flex-row gap-6 flex-1 min-h-0 overflow-y-auto lg:overflow-visible">
|
||
{/* 头像编辑卡片 */}
|
||
<div className="lg:w-[360px] lg:flex-shrink-0">
|
||
<div className="bg-bg-card rounded-2xl p-6 card-shadow flex flex-col items-center gap-5">
|
||
{/* 头像 */}
|
||
<div className="relative">
|
||
<div
|
||
className="w-24 h-24 rounded-full flex items-center justify-center"
|
||
style={{
|
||
background: 'linear-gradient(135deg, #6366F1 0%, #4F46E5 100%)',
|
||
}}
|
||
>
|
||
<span className="text-[40px] font-bold text-white">{mockUser.initial}</span>
|
||
</div>
|
||
{/* 相机按钮 */}
|
||
<button
|
||
type="button"
|
||
className="absolute bottom-0 right-0 w-8 h-8 rounded-full bg-accent-indigo flex items-center justify-center shadow-lg hover:bg-accent-indigo/90 transition-colors"
|
||
>
|
||
<Camera size={16} className="text-white" />
|
||
</button>
|
||
</div>
|
||
<p className="text-sm text-text-secondary">点击更换头像</p>
|
||
|
||
{/* 提示 */}
|
||
<div className="w-full p-4 rounded-xl bg-bg-elevated">
|
||
<p className="text-[13px] text-text-tertiary leading-relaxed">
|
||
支持 JPG、PNG 格式,文件大小不超过 5MB,建议使用正方形图片以获得最佳显示效果。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 表单卡片 */}
|
||
<div className="flex-1 flex flex-col gap-5">
|
||
<div className="bg-bg-card rounded-2xl p-6 card-shadow flex flex-col gap-5">
|
||
{/* 达人ID(只读) */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">达人ID</label>
|
||
<div className="flex gap-3">
|
||
<div className="flex-1 px-4 py-3 rounded-xl border border-border-default bg-bg-elevated/50 flex items-center justify-between">
|
||
<span className="font-mono font-medium text-accent-indigo">{mockUser.creatorId}</span>
|
||
<button
|
||
type="button"
|
||
onClick={handleCopyId}
|
||
className="flex items-center gap-1.5 px-2 py-1 rounded-md hover:bg-bg-elevated transition-colors"
|
||
>
|
||
{idCopied ? (
|
||
<>
|
||
<Check size={14} className="text-accent-green" />
|
||
<span className="text-xs text-accent-green">已复制</span>
|
||
</>
|
||
) : (
|
||
<>
|
||
<Copy size={14} className="text-text-tertiary" />
|
||
<span className="text-xs text-text-tertiary">复制</span>
|
||
</>
|
||
)}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<p className="text-xs text-text-tertiary">系统自动生成的唯一标识,供代理商邀请时使用</p>
|
||
</div>
|
||
|
||
{/* 昵称 */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">昵称</label>
|
||
<Input
|
||
value={formData.name}
|
||
onChange={(e) => handleInputChange('name', e.target.value)}
|
||
placeholder="请输入昵称"
|
||
/>
|
||
</div>
|
||
|
||
{/* 手机号 */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">手机号</label>
|
||
<div className="flex gap-3">
|
||
<Input
|
||
value={formData.phone}
|
||
onChange={(e) => handleInputChange('phone', e.target.value)}
|
||
placeholder="请输入手机号"
|
||
className="flex-1"
|
||
disabled
|
||
/>
|
||
<Button variant="secondary" size="md">
|
||
更换
|
||
</Button>
|
||
</div>
|
||
<p className="text-xs text-text-tertiary">手机号用于登录和接收重要通知</p>
|
||
</div>
|
||
|
||
{/* 邮箱 */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">邮箱</label>
|
||
<Input
|
||
type="email"
|
||
value={formData.email}
|
||
onChange={(e) => handleInputChange('email', e.target.value)}
|
||
placeholder="请输入邮箱"
|
||
/>
|
||
</div>
|
||
|
||
{/* 抖音账号 */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">抖音账号</label>
|
||
<div className="flex gap-3">
|
||
<Input
|
||
value={formData.douyinAccount}
|
||
onChange={(e) => handleInputChange('douyinAccount', e.target.value)}
|
||
placeholder="请输入抖音账号"
|
||
className="flex-1"
|
||
disabled
|
||
/>
|
||
<Button variant="secondary" size="md">
|
||
重新绑定
|
||
</Button>
|
||
</div>
|
||
<p className="text-xs text-text-tertiary">已认证的抖音账号,用于发布视频</p>
|
||
</div>
|
||
|
||
{/* 个人简介 */}
|
||
<div className="flex flex-col gap-2">
|
||
<label className="text-sm font-medium text-text-primary">个人简介</label>
|
||
<textarea
|
||
value={formData.bio}
|
||
onChange={(e) => handleInputChange('bio', e.target.value)}
|
||
placeholder="介绍一下自己吧..."
|
||
rows={3}
|
||
className={cn(
|
||
'w-full px-4 py-3 rounded-xl border border-border-default',
|
||
'bg-bg-elevated text-text-primary text-[15px]',
|
||
'placeholder:text-text-tertiary',
|
||
'focus:outline-none focus:border-accent-indigo focus:ring-2 focus:ring-accent-indigo/20',
|
||
'transition-all resize-none'
|
||
)}
|
||
/>
|
||
<p className="text-xs text-text-tertiary text-right">{formData.bio.length}/100</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 保存按钮 */}
|
||
<div className="flex justify-end gap-3">
|
||
<Button variant="secondary" size="lg" onClick={() => router.back()}>
|
||
取消
|
||
</Button>
|
||
<Button
|
||
variant="primary"
|
||
size="lg"
|
||
onClick={handleSave}
|
||
disabled={isSaving}
|
||
className="min-w-[120px]"
|
||
>
|
||
{isSaving ? (
|
||
<span className="flex items-center gap-2">
|
||
<span className="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin" />
|
||
保存中...
|
||
</span>
|
||
) : (
|
||
<span className="flex items-center gap-2">
|
||
<Check size={18} />
|
||
保存修改
|
||
</span>
|
||
)}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</ResponsiveLayout>
|
||
)
|
||
}
|