1
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# 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` props,emit `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
|
||||
- 头像昵称展示支持在线状态
|
||||
Reference in New Issue
Block a user