Files
ftb-project-management/docs/superpowers/specs/2026-06-16-profile-ui-redesign.md
Script Generator d1b4d81a75 feat: 个人中心 UI 改版(Banner + 大头像 + 卡片化)
从孤立白卡改为 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>
2026-06-16 20:26:22 +08:00

6.8 KiB
Raw Blame History

个人中心 UI 改版设计

Context

当前 /profile 页面commit 7c49868)的视觉太单调——内容用 max-w-xl 限宽,单张白卡片孤立漂浮在空白页上,没有头部装饰,整体像一个被推平的弹窗。改为 GitHub/Notion 风格的"个人页":渐变 Banner + 大头像 + Tab 切换的卡片。

决策摘要

决策
整体风格 顶部渐变 Banner + 头像 + 下方 Tab 卡片(方案 A
Banner 高度 h-40160px
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/60Phone/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

取消按钮

  • 个人信息 TabhandleReset 重读 useMemberStore.members.find(m => m.id === user.id) 的字段
  • 密码 Tab清空三个输入 + 清空 errors

Banner 与表单同步

  • 字段改了未保存Banner 仍显老值(不联动)
  • 保存成功 → refreshUser() → Banner 立即更新

数据流

useAuthStore.user
   │
   └─ 触发渲染
         │
         ├─ Banneruser.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(复用)

验证

  1. pnpm type-check 0 错误
  2. pnpm build 14+1 个页面成功
  3. 进入 /profile
    • 顶部渐变 Banner左下圆头像 + 姓名/角色/部门/联系方式
    • 右上角白底红字退出按钮
    • Banner 下 Tab 切换条 + 卡片
  4. 改姓名后保存:
    • 按钮 spinner 一闪
    • 显示绿色"已保存 ✓"3 秒后淡出
    • Banner 上的姓名立即更新refreshUser 生效)
  5. 修改密码spinner + "密码已修改,下次登录生效" 3 秒淡出
  6. 取消按钮:恢复初始值