从孤立白卡改为 GitHub/Notion 风格个人页: - 顶部 h-40 渐变 Banner(主色到 hover 色),左下 80px 圆头像 + ring 描边 - Banner 内显示姓名/角色·部门/手机·邮箱,右上白底透明退出按钮 - max-w-3xl 卡片居中:标题 + 副标题(如「修改后立即生效」)+ 字段单栏堆叠 - 保存按钮加 spinner(提交中)+ 已保存绿色文字带 Check icon 3 秒淡出 - refreshUser 后 Banner 立即同步新名字/邮箱 - 不考虑移动端 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.8 KiB
6.8 KiB
个人中心 UI 改版设计
Context
当前 /profile 页面(commit 7c49868)的视觉太单调——内容用 max-w-xl 限宽,单张白卡片孤立漂浮在空白页上,没有头部装饰,整体像一个被推平的弹窗。改为 GitHub/Notion 风格的"个人页":渐变 Banner + 大头像 + Tab 切换的卡片。
决策摘要
| 项 | 决策 |
|---|---|
| 整体风格 | 顶部渐变 Banner + 头像 + 下方 Tab 卡片(方案 A) |
| Banner 高度 | h-40(160px) |
| Banner 背景 | bg-gradient-to-br from-[var(--accent)] to-[var(--accent-hover)] |
| 头像 | 80px 圆形,主色背景 + 白字首字母,ring-4 ring-white/20 |
| 退出按钮位置 | Banner 右上角 absolute(白底红描边红字) |
| Tab 风格 | 沿用版本详情页风格(active 主色下划线) |
| 字段布局 | 单栏堆叠(用户决定,避免两栏挤迫) |
| 卡片宽度 | max-w-3xl mx-auto 居中 |
| 保存反馈 | 提交中 spinner + 已保存绿色文字 3 秒淡出 |
| 移动端 | 不考虑(项目仅面向桌面端) |
1. Banner 视觉规格
结构:
┌─────────────────────────────────────────────────────┐
│ [渐变背景 h-40] │
│ [退出登录] │
│ │
│ [80px 圆头像] 张三 │
│ "张" 产品经理 · 产品部 / 前端组 │
│ 📞 138... · ✉ zhang@... │
└─────────────────────────────────────────────────────┘
实现要点:
- 容器
relative h-40 px-8 py-6 rounded-b-3xl bg-gradient-to-br from-[var(--accent)] to-[var(--accent-hover)] text-white - 内部 flex 布局:左侧头像 + 文字组,右上 absolute 退出按钮
- 头像:
h-20 w-20 rounded-full bg-white/15 ring-4 ring-white/20 flex items-center justify-center text-3xl font-semibold,内容是user.name?.[0] - 主名
text-2xl font-semibold - 副名
text-sm text-white/80,格式:"角色名 · 部门层级" - 联系方式
text-xs text-white/60,Phone/Mail icon + 文本 - 退出按钮:
absolute top-5 right-5 h-8 px-3 rounded-lg bg-white/10 border border-white/20 hover:bg-white/20 text-white(白色透明)
2. Tab 内容布局
结构:
[Banner]
┌─ 个人信息 ─┐ ┌─ 修改密码 ─┐
════════════
┌──────────────────────────────────────────┐
│ 基本信息 │
│ 修改后立即生效 │
│ ───────────────────────────────────── │
│ │
│ 姓名 * │
│ [_____________________________________] │
│ │
│ 手机号 * │
│ [_____________________________________] │
│ │
│ 邮箱 * │
│ [_____________________________________] │
│ │
│ 部门 │
│ [产品部 / 前端组] │
│ │
│ 角色 │
│ [产品经理] │
│ │
│ [取消] [保存] │
└──────────────────────────────────────────┘
实现要点:
- Banner 与 Tab 之间留
mt-6间距 - Tab 容器
max-w-3xl mx-auto px-5,无外边框,仅 Tab 按钮带下划线 - 卡片
max-w-3xl mx-auto rounded-2xl border border-[var(--line)] bg-[var(--bg-card)] p-6 - 卡片头:标题
text-base font-semibold+ 副标题text-xs text-[var(--ink-muted)] mt-1 - 标题区下细分割线
border-t border-[var(--line)] pt-5 mt-4 - 字段单栏堆叠
space-y-4 - 必填星号
text-red-500 - 部门、角色字段
disabled bg-zinc-50
密码 Tab:
- 卡片标题"修改密码"+ 副标题"密码修改后下次登录生效"
- 三个字段单栏堆叠(与第 1 节澄清一致)
- 眼睛 icon 切换可见性保留
3. 保存反馈微调
保存按钮三态:
普通: [取消] [保存]
提交中: [取消] [● 保存中...] ← spinner 禁用
成功: 已保存 ✓ [取消] [保存] ← 绿色文字 3 秒淡出
- 提交瞬间设
submitting=true,按钮 disabled + 左侧 Loader2 icon spinning - 成功后
submitting=false+savedAt=Date.now(),3 秒后setTimeout清掉 savedAt - 已保存提示:
text-emerald-600+ Check icon
取消按钮:
- 个人信息 Tab:
handleReset重读useMemberStore.members.find(m => m.id === user.id)的字段 - 密码 Tab:清空三个输入 + 清空 errors
Banner 与表单同步:
- 字段改了未保存:Banner 仍显老值(不联动)
- 保存成功 →
refreshUser()→ Banner 立即更新
数据流
useAuthStore.user
│
└─ 触发渲染
│
├─ Banner(user.name / role.name / dept name 链 / phone / email)
└─ 表单字段(从 useMemberStore.members.find 取最新值)
提交流程:
form submit → updateMember() → refreshUser() → Banner 自动重渲
实施清单
修改:
apps/web/app/profile/page.tsx— 整页重写:Banner + Tab + 卡片布局 + 保存 spinner + 已保存淡出
不变:
apps/web/components/layout/Sidebar.tsx(已正确)apps/web/stores/useAuthStore.ts(已加 refreshUser)apps/web/components/FieldError.tsx(复用)
验证
pnpm type-check0 错误pnpm build14+1 个页面成功- 进入
/profile:- 顶部渐变 Banner,左下圆头像 + 姓名/角色/部门/联系方式
- 右上角白底红字退出按钮
- Banner 下 Tab 切换条 + 卡片
- 改姓名后保存:
- 按钮 spinner 一闪
- 显示绿色"已保存 ✓"3 秒后淡出
- Banner 上的姓名立即更新(refreshUser 生效)
- 修改密码:spinner + "密码已修改,下次登录生效" 3 秒淡出
- 取消按钮:恢复初始值