Your Name 964797d2e9 feat: 完善品牌方和代理商前端功能
品牌方功能:
- 项目看板: 添加截止日期编辑功能
- 项目详情: 添加代理商管理、截止日期编辑、最近任务显示代理商
- 项目创建: 代理商选择支持搜索(名称/ID/公司名)
- 代理商管理: 通过ID邀请、添加备注/分配项目/移除操作
- Brief配置: 新增项目级Brief和规则配置页面
- 系统设置: 完善账户安全(密码/2FA/邮箱/手机/设备管理)、数据导出、退出登录

代理商功能:
- 个人中心: 新增代理商ID展示、公司信息(企业验证)、个人信息编辑
- 账户设置: 密码修改、手机/邮箱绑定、两步验证
- 通知设置: 分类型和渠道的通知开关
- 审核历史: 搜索筛选和统计展示
- 帮助反馈: FAQ分类搜索和客服联系

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 17:40:11 +08:00

241 lines
9.4 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 { useState } from 'react'
import { useRouter } from 'next/navigation'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'
import { Button } from '@/components/ui/Button'
import { Input } from '@/components/ui/Input'
import {
ArrowLeft,
Lock,
Shield,
Smartphone,
Mail,
Key,
Eye,
EyeOff,
CheckCircle,
AlertTriangle
} from 'lucide-react'
export default function AgencyAccountSettingsPage() {
const router = useRouter()
const [showOldPassword, setShowOldPassword] = useState(false)
const [showNewPassword, setShowNewPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const [passwordForm, setPasswordForm] = useState({
oldPassword: '',
newPassword: '',
confirmPassword: '',
})
const [isSaving, setIsSaving] = useState(false)
// 模拟账号安全状态
const securityStatus = {
phone: { bound: true, value: '138****8888' },
email: { bound: true, value: 'zhang@starmedia.com' },
twoFactor: { enabled: false },
}
const handleChangePassword = async () => {
if (!passwordForm.oldPassword || !passwordForm.newPassword || !passwordForm.confirmPassword) {
alert('请填写完整密码信息')
return
}
if (passwordForm.newPassword !== passwordForm.confirmPassword) {
alert('两次输入的新密码不一致')
return
}
if (passwordForm.newPassword.length < 8) {
alert('新密码长度不能少于8位')
return
}
setIsSaving(true)
await new Promise(resolve => setTimeout(resolve, 1000))
setIsSaving(false)
alert('密码修改成功')
setPasswordForm({ oldPassword: '', newPassword: '', confirmPassword: '' })
}
return (
<div className="space-y-6">
{/* 顶部导航 */}
<div className="flex items-center gap-4">
<button
type="button"
onClick={() => router.back()}
className="p-2 rounded-lg hover:bg-bg-elevated transition-colors"
>
<ArrowLeft size={20} className="text-text-secondary" />
</button>
<div>
<h1 className="text-2xl font-bold text-text-primary"></h1>
<p className="text-sm text-text-secondary mt-0.5"></p>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* 修改密码 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Lock size={18} className="text-accent-indigo" />
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<label className="text-sm text-text-secondary mb-1.5 block"></label>
<div className="relative">
<Input
type={showOldPassword ? 'text' : 'password'}
value={passwordForm.oldPassword}
onChange={(e) => setPasswordForm({ ...passwordForm, oldPassword: e.target.value })}
placeholder="请输入当前密码"
/>
<button
type="button"
onClick={() => setShowOldPassword(!showOldPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-tertiary hover:text-text-secondary"
>
{showOldPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
</div>
<div>
<label className="text-sm text-text-secondary mb-1.5 block"></label>
<div className="relative">
<Input
type={showNewPassword ? 'text' : 'password'}
value={passwordForm.newPassword}
onChange={(e) => setPasswordForm({ ...passwordForm, newPassword: e.target.value })}
placeholder="请输入新密码至少8位"
/>
<button
type="button"
onClick={() => setShowNewPassword(!showNewPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-tertiary hover:text-text-secondary"
>
{showNewPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
</div>
<div>
<label className="text-sm text-text-secondary mb-1.5 block"></label>
<div className="relative">
<Input
type={showConfirmPassword ? 'text' : 'password'}
value={passwordForm.confirmPassword}
onChange={(e) => setPasswordForm({ ...passwordForm, confirmPassword: e.target.value })}
placeholder="请再次输入新密码"
/>
<button
type="button"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
className="absolute right-3 top-1/2 -translate-y-1/2 text-text-tertiary hover:text-text-secondary"
>
{showConfirmPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
</div>
<Button
variant="primary"
className="w-full"
onClick={handleChangePassword}
disabled={isSaving}
>
{isSaving ? '保存中...' : '确认修改'}
</Button>
</CardContent>
</Card>
{/* 账号安全 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Shield size={18} className="text-accent-green" />
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* 手机绑定 */}
<div className="flex items-center justify-between p-4 rounded-xl bg-bg-elevated">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-accent-indigo/15 flex items-center justify-center">
<Smartphone size={20} className="text-accent-indigo" />
</div>
<div>
<p className="font-medium text-text-primary"></p>
<p className="text-sm text-text-secondary">
{securityStatus.phone.bound ? securityStatus.phone.value : '未绑定'}
</p>
</div>
</div>
<div className="flex items-center gap-2">
{securityStatus.phone.bound ? (
<CheckCircle size={18} className="text-accent-green" />
) : (
<AlertTriangle size={18} className="text-accent-amber" />
)}
<Button variant="secondary" size="sm">
{securityStatus.phone.bound ? '更换' : '绑定'}
</Button>
</div>
</div>
{/* 邮箱绑定 */}
<div className="flex items-center justify-between p-4 rounded-xl bg-bg-elevated">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-accent-blue/15 flex items-center justify-center">
<Mail size={20} className="text-accent-blue" />
</div>
<div>
<p className="font-medium text-text-primary"></p>
<p className="text-sm text-text-secondary">
{securityStatus.email.bound ? securityStatus.email.value : '未绑定'}
</p>
</div>
</div>
<div className="flex items-center gap-2">
{securityStatus.email.bound ? (
<CheckCircle size={18} className="text-accent-green" />
) : (
<AlertTriangle size={18} className="text-accent-amber" />
)}
<Button variant="secondary" size="sm">
{securityStatus.email.bound ? '更换' : '绑定'}
</Button>
</div>
</div>
{/* 两步验证 */}
<div className="flex items-center justify-between p-4 rounded-xl bg-bg-elevated">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-accent-amber/15 flex items-center justify-center">
<Key size={20} className="text-accent-amber" />
</div>
<div>
<p className="font-medium text-text-primary"></p>
<p className="text-sm text-text-secondary">
{securityStatus.twoFactor.enabled ? '已开启' : '未开启,建议开启以增强安全'}
</p>
</div>
</div>
<div className="flex items-center gap-2">
{securityStatus.twoFactor.enabled ? (
<CheckCircle size={18} className="text-accent-green" />
) : (
<AlertTriangle size={18} className="text-accent-amber" />
)}
<Button variant="secondary" size="sm">
{securityStatus.twoFactor.enabled ? '关闭' : '开启'}
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
</div>
)
}