Files
agent-frontend-web/docs/superpowers/specs/2026-08-06-frontend-sidebar-user-area-design.md
T
2026-08-07 13:56:29 +08:00

116 lines
4.9 KiB
Markdown
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.
# Frontend 会话列表底部用户区域块 — Design Spec
**日期:** 2026-08-06
**状态:** Approved
## 背景
`src/views/frontend/index.vue` 是核心 AI 对话页面,左侧是 `ConversationSidebar`(会话列表)。当前侧边栏底部没有任何用户相关的入口:用户无法在不离开页面的情况下查看自己的头像/昵称、退出登录、或跳转到智能体广场。
## 目标
在会话列表底部新增一个区域块,提供:
1. 用户头像 + 昵称展示,点击打开「个人资料」修改弹窗(可改头像、昵称)
2. 「退出」按钮(二次确认后退出登录)
3. 「前往智能体广场」按钮
侧边栏收起时,该区域块仅显示一个小头像,点击弹出菜单。
## 非目标
- 不修改智能体广场页本身
- 不修改会话列表的样式或行为
- 不引入新的退出 / 上传头像后端接口
## 方案概览
新增两个组件,`ConversationSidebar` 引入并放在底部。
### 新增文件
- `src/views/frontend/components/UserArea.vue`
- 展示用户头像 + 昵称、退出按钮、前往智能体广场按钮
- 接收 `collapsed` prop(来自 `ConversationSidebar`
- 展开时:完整展示三块内容;收起时:仅显示小圆形头像,点击弹出 dropdown 菜单
- 通过 `defineExpose` 暴露 `openInfoDialog()` 方法,父组件 `ConversationSidebar` 用 ref 调用(与现有 `defineExpose({ refresh: fetchSessions, ... })` 风格一致)
- `src/views/frontend/components/UserInfoDialog.vue`
- Element Plus `el-dialog`,标题"个人资料",宽 500px
- 内容:头像裁剪上传区(vue-cropper 固定 1:1+ 昵称输入框
- 接收 `modelValue` / `user` propsemit `update:modelValue``saved`
- 保存时调用:
- `uploadAvatar()``PUT /system/user/profile/avatar`
- `updateUserProfile({ nickName })``PUT /system/user/profile`
- 保存成功后更新 `useUserStore()``avatar``nickName`,并 emit `saved`,父组件 ElMessage 成功提示
### 修改文件
- `src/views/frontend/components/ConversationSidebar.vue`
-`sidebar-content` 内的 `<el-scrollbar>` 下方引入 `<UserArea ref="userAreaRef" :collapsed="collapsed" />`
-`<el-scrollbar>``height``calc(100vh - 160px)` 改为 `calc(100vh - 240px)`(预留底部 user-area 高度)
-`sidebar-content` 改为 flex 布局,使 `<el-scrollbar>` 占中间,`<UserArea>` 占底部固定高度
## 组件契约
### UserArea.vue
| 名称 | 类型 | 说明 |
| --- | --- | --- |
| Props | | |
| collapsed | Boolean | 侧边栏是否收起 |
| Methods (expose) | | |
| openInfoDialog() | () => void | 打开个人资料弹窗 |
### UserInfoDialog.vue
| 名称 | 类型 | 说明 |
| --- | --- | --- |
| Props | | |
| modelValue | Boolean | 弹窗显隐(v-model |
| user | Object | 当前用户 `{ avatar, nickName }` |
| Emit | | |
| update:modelValue | (val: Boolean) | 显隐变化 |
| saved | (user: Object) | 保存成功后回调 |
## 数据流
1. `ConversationSidebar` 通过 `useUserStore()` 取用户信息,传给 `UserArea``UserInfoDialog`
2. 用户点击头像 → `UserArea.openInfoDialog()` → 内部把 `infoDialogVisible.value = true``<UserInfoDialog v-model="infoDialogVisible" :user="user" @saved="onSaved" />`
3. `UserInfoDialog` 内部:
- 选择本地图片 → `vue-cropper` 裁剪 → 用户点"保存"
-`uploadAvatar(formData)` → 成功后调 `updateUserProfile({ nickName })` → 更新 store
4. `UserInfoDialog` 关闭后 `ConversationSidebar` 触发 `ElMessage.success('修改成功')`
## 错误处理
- 上传头像失败:`ElMessage.error('头像上传失败')`,弹窗保持打开以便重试
- 更新昵称失败:`ElMessage.error('修改失败')`
- 退出失败:`ElMessage.error('退出失败,请稍后重试')`
- 网络异常:依赖 `request.js` 的统一错误处理
## 视觉规范
- 与现有侧边栏保持一致色系:`#e4e7ed` 分割线、`#409eff` 主色、`#f56c6c` 危险色
- 头像 36×36 圆形(收起时 28×28)
- 昵称省略号截断 `text-overflow: ellipsis`
- 按钮文字与图标间距 6px
- 顶部细分割线:`border-top: 1px solid #e4e7ed`
## 测试
- 手动测试:本地 `yarn dev`,访问 `/frontend/index`
- 头像昵称正确展示
- 点击头像 → 弹窗打开 → 修改头像/昵称 → 保存 → 列表头像昵称同步刷新
- 点击退出 → 确认 → 跳转到 `/login`
- 点击「前往智能体广场」 → 跳转到 `/frontend/marketplace`
- 收起侧边栏 → 仅显示小头像 → hover 出 tooltip → 点击出 dropdown 菜单
## 风险
- 头像上传接口需要登录态,已通过 `request.js` 自动带 token 处理
- 弹窗高度可能在小屏幕溢出,宽度固定 500px,自适应垂直
## 后续可扩展(不在本次范围)
- 收起状态下的 dropdown 也可改成 popover
- 头像昵称展示支持在线状态