Your Name 2f9b7f05fd feat(creator): 完成达人端前端页面开发
- 新增申诉中心页面(列表、详情、新建申诉)
- 新增申诉次数管理页面(按任务显示配额,支持向代理商申请)
- 新增个人中心页面(达人ID复制、菜单导航)
- 新增个人信息编辑、账户设置、消息通知设置页面
- 新增帮助中心和历史记录页面
- 新增脚本提交和视频提交页面
- 优化消息中心页面(消息详情跳转)
- 优化任务详情页面布局和交互
- 更新 ResponsiveLayout、Sidebar、ReviewSteps 通用组件

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 15:38:01 +08:00

250 lines
9.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.

'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'
// 模拟用户数据
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 [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 (err) {
console.error('复制失败:', err)
}
}
// 处理输入变化
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">
JPGPNG 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>
)
}