hookehuyr

fix: 修复用户头像 API 集成问题

### 修复内容

1. **修复获取个人信息接口字段访问错误**
   - mine/index.vue: 头像显示从 `userInfo.avatar_url` 改为 `userInfo.avatar.src`
   - API 返回 avatar 对象(包含 name, hash, src, height, width, size)
   - 之前错误访问不存在的 avatar_url 字段导致头像无法显示

2. **修复更新个人资料接口参数结构错误**
   - avatar/index.vue: 传递完整 avatar 对象而非 avatar_meta_id
   - API 规范要求 `{ avatar: { name, hash, src, height, width, size } }`
   - 之前只传 `{ avatar_meta_id: xxx }` 不符合接口规范

3. **修复头像上传接口数据映射错误**
   - 根据实际上传接口返回结构正确映射字段
   - name: 从 data.data.file.name 获取
   - hash: 从 data.data.res.hash 获取
   - src: 从 data.data.src 获取
   - height/width: 从 data.data.height/width 获取
   - size: 从 data.data.file.size 获取

### 新增功能

4. **头像设置页面加载时获取用户当前头像**
   - 进入页面时调用 getProfileAPI() 获取用户信息
   - 如果用户已有头像则显示当前头像,否则显示默认头像
   - 提升用户体验,避免每次看到默认头像

### 文档更新

5. **更新 API 文档**
   - src/api/user.js: 更新 updateProfileAPI 的 JSDoc 注释
   - docs/api-specs/user/get_profile.md: 重写为清晰 Markdown 格式
   - docs/api-specs/user/update_profile.md: 重写并添加完整流程说明
   - docs/api-integration-log.md: 更新接口联调明细到 v1.8
   - docs/CHANGELOG.md: 添加详细的变更记录

### 影响文件

- src/pages/mine/index.vue(头像显示字段修复)
- src/pages/avatar/index.vue(接口参数修复 + 获取当前头像)
- src/api/user.js(API 注释更新)
- docs/api-specs/user/get_profile.md(API 文档重写)
- docs/api-specs/user/update_profile.md(API 文档重写)
- docs/api-integration-log.md(联调日志更新)
- docs/CHANGELOG.md(变更日志更新)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -5,6 +5,75 @@
---
## [2026-02-03] - 修复用户头像接口集成
### 修复
- 修复获取个人信息接口字段访问错误
- `mine/index.vue`: 头像显示从 `userInfo.avatar_url` 改为 `userInfo.avatar.src`
- API 返回 `avatar` 对象(包含 name, hash, src, height, width, size)
- 之前错误访问不存在的 `avatar_url` 字段导致头像无法显示
- 修复更新个人资料接口参数结构错误
- `avatar/index.vue`: 传递完整 `avatar` 对象而非 `avatar_meta_id`
- API 规范要求 `{ avatar: { name, hash, src, height, width, size } }`
- 之前只传 `{ avatar_meta_id: xxx }` 不符合接口规范
- 修复头像上传接口数据映射错误
- 根据实际上传接口返回结构正确映射字段
- `name`: 从 `data.data.file.name` 获取
- `hash`: 从 `data.data.res.hash` 获取
- `src`: 从 `data.data.src` 获取
- `height/width`: 从 `data.data.height/width` 获取
- `size`: 从 `data.data.file.size` 获取
### 新增
- 头像设置页面加载时获取用户当前头像
- 进入页面时调用 `getProfileAPI()` 获取用户信息
- 如果用户已有头像则显示当前头像,否则显示默认头像
- 提升用户体验,避免每次看到默认头像
### 文档
- 更新 `src/api/user.js``updateProfileAPI` 的 JSDoc 注释
- 明确参数结构:`avatar` 对象包含完整字段
- 添加所有字段的类型和说明
---
**详细信息**
- **影响文件**:
- `src/pages/mine/index.vue`(头像显示字段修复)
- `src/pages/avatar/index.vue`(接口参数修复 + 获取当前头像)
- `src/api/user.js`(API 注释更新)
- **技术栈**: Vue 3, Taro 4, Composition API
- **测试状态**: ✅ 已通过
- **备注**:
- 上传接口返回示例:
```json
{
"code": 0,
"data": {
"src": "https://cdn...",
"file": { "name": "...", "size": 3806359 },
"res": { "hash": "...", "image_info": { "width": 1766, "height": 1770 } },
"width": 1766,
"height": 1770
}
}
```
- 更新头像接口请求格式:
```javascript
updateProfileAPI({
avatar: {
name: "文件名",
hash: "文件hash",
src: "https://cdn...",
height: "1770",
width: "1766",
size: 3806359
}
})
```
---
## [2026-02-03] - 产品模块接口集成完成
### 新增
......
......@@ -13,6 +13,15 @@
---
**📝 最近更新** (2026-02-03):
-**修复获取个人信息接口字段访问错误**:修正 avatar 字段结构(对象而非字符串)
-**修复更新个人资料接口参数结构错误**:传递完整 avatar 对象而非 avatar_meta_id
-**修复头像上传接口数据映射错误**:根据实际返回结构正确映射字段
-**新增头像设置页面加载时获取用户当前头像功能**:提升用户体验
-**更新 API 文档**:完善 get_profile 和 update_profile 接口文档
---
## 📝 接口联调明细
### 用户中心模块
......@@ -84,13 +93,14 @@
- **接口名称**: `getProfileAPI`
- **接口路径**: `/srv/?a=user&t=get_profile`
- **请求方法**: GET
- **负责页面**: `src/pages/mine/index.vue`
- **负责页面**: `src/pages/mine/index.vue`, `src/pages/avatar/index.vue`, `src/stores/user.js`
- **负责人**: 后端团队
**接口文档更新记录**
| 日期 | 版本 | 变更内容 | 变更原因 | 文档链接 |
|------|------|---------|---------|---------|
| 2026-02-03 | v1.2 | 修正 avatar 字段结构 | 修复头像显示问题 | [查看](docs/api-specs/user/get_profile.md) |
| 2026-02-03 | v1.1 | 新增 `employee_no` 字段(工号) | 业务需求变更 | [查看](#) |
| 2026-02-03 | v1.0 | 初始版本 | - | [查看](#) |
......@@ -99,20 +109,44 @@
| 日期 | 调试页面 | 问题记录 | 解决方案 | 状态 |
|------|---------|---------|---------|------|
| 2026-02-03 | `src/pages/mine/index.vue` | 页面显示 ID 字段,应显示工号 | 将 `userInfo?.id` 改为 `userInfo?.employee_no` | ✅ 已完成 |
| 2026-02-03 | `src/pages/mine/index.vue` | 头像显示不正确 | `userInfo?.avatar_url` 改为 `userInfo?.avatar.src` | ✅ 已完成 |
| 2026-02-03 | `src/pages/avatar/index.vue` | 新增获取当前头像功能 | 页面加载时调用 `getProfileAPI()` | ✅ 已完成 |
**接口状态**: ✅ 已完成
**备注**:
- **返回用户信息**
- `id` - 用户ID(内部标识)
- `employee_no` - 工号(对外展示)⭐ 新增
- `avatar_url` - 头像URL
- `name` - 姓名
- `avatar_meta_id` - 头像附件ID
- **重要变更**:页面展示工号使用 `employee_no` 字段,而非 `id` 字段
- **返回用户信息结构**
```json
{
"user": {
"id": 123,
"name": "张三",
"employee_no": "EMP001",
"avatar": {
"name": "avatar.png",
"hash": "abc123",
"src": "https://cdn.ipadbiz.cn/manulife/avatar.png", // 头像URL
"height": "200",
"width": "200",
"size": 10240
}
}
}
```
- **重要修复**:v1.2 版本修正了 avatar 字段结构
- 之前文档错误描述为 `avatar_url`(字符串)
- 实际返回 `avatar` 对象(包含完整信息)
- **访问方式**:
- 头像URL: `user.avatar.src`
- 文件名: `user.avatar.name`
- 文件hash: `user.avatar.hash`
- "我的"页面加载时调用
- "修改头像"页面加载时调用(获取当前头像)
- 401 自动跳转登录页(由 request.js 拦截器处理)
- 实现位置:`src/pages/mine/index.vue:fetchUserProfile()`
- 实现位置:
- `src/pages/mine/index.vue:fetchUserProfile()`
- `src/pages/avatar/index.vue:fetchCurrentAvatar()`
- `src/stores/user.js:fetchUserInfo()`
---
......@@ -191,22 +225,50 @@
| 日期 | 版本 | 变更内容 | 变更原因 | 文档链接 |
|------|------|---------|---------|---------|
| 2026-02-03 | v1.2 | 修正请求参数结构 | 修复接口调用错误 | [查看](docs/api-specs/user/update_profile.md) |
| 2026-02-03 | v1.0 | 初始版本 | - | [查看](#) |
**页面调试情况**
| 日期 | 调试页面 | 问题记录 | 解决方案 | 状态 |
|------|---------|---------|---------|------|
| 2026-02-03 | `src/pages/avatar/index.vue` | 后端开发中 | - | ⏳ 后端开发中 |
| 2026-02-03 | `src/pages/avatar/index.vue` | 联调完成 | 改用直接上传方式 | ✅ 已完成 |
| 2026-02-03 | `src/pages/avatar/index.vue` | 参数结构不正确 | 改为传递完整 `avatar` 对象 | 已完成 |
| 2026-02-03 | `src/pages/avatar/index.vue` | 字段映射错误 | 根据实际上传接口返回结构映射字段 | 已完成 |
| 2026-02-03 | `src/pages/avatar/index.vue` | 联调完成 | 接口正常工作,头像更新成功 | 已完成 |
**接口状态**: 已完成
**备注**:
- 参数:avatar_url(头像URL)
- 用于用户修改头像
- 联调完成,接口正常工作
- 实现位置:`src/pages/avatar/index.vue:121-163`
- **请求参数结构**(v1.2 修正):
```javascript
{
avatar: {
name: "文件名",
hash: "文件hash",
src: "https://cdn...", // 头像CDN URL
height: "1770", // 字符串格式
width: "1766", // 字符串格式
size: 3806359 // 整数(字节)
}
}
```
- **重要修复**:v1.2 版本修正了请求参数结构
- 之前文档错误描述参数为 `avatar_meta_id`
- 实际参数为完整的 `avatar` 对象
- **完整流程**:
1. 选择图片 `Taro.chooseImage`
2. 上传到服务器 `Taro.uploadFile` (`/admin/?m=srv&a=upload&image_audit=1`)
3. 映射字段 根据实际上传接口返回结构
4. 保存到服务器 `updateProfileAPI({ avatar: {...} })`
- **字段映射关系**:
- `name`: `data.data.file.name`
- `hash`: `data.data.res.hash`
- `src`: `data.data.src`
- `height`: `data.data.height` `data.data.res.image_info.height`
- `width`: `data.data.width` `data.data.res.image_info.width`
- `size`: `data.data.file.size` `data.data.res.filesize`
- 实现位置:`src/pages/avatar/index.vue:75-186`
- API 文档:[docs/api-specs/user/update_profile.md](docs/api-specs/user/update_profile.md)
---
......@@ -680,17 +742,19 @@
---
**最后更新时间**: 2026-02-03 23:30
**文档版本**: v1.7
**最后更新时间**: 2026-02-03 20:00
**文档版本**: v1.8
**更新内容**:
- 产品模块联调完成:2个接口
- 产品列表(listAPI):✅ 已完成
- 首页热卖产品模块,使用 recommend=hot 参数
- 动态标签渲染(使用 API 返回的 bg_color 和 text_color)
- 产品详情(detailAPI):✅ 已完成
- 产品详情页,使用富文本渲染 product_description
- 附件列表显示(使用 file_size_formatted 字段)
- 移除收藏功能
- 修复问题:
- 产品详情页 nut-loading 组件报错(改用纯 CSS 加载动画)
- 用户中心模块 v1.2 修复:2个接口
- 获取个人信息(getProfileAPI):✅ 已修复
- 修复头像字段结构从 avatar_url 字符串改为 avatar 对象
- 修复 mine 页面头像显示问题(userInfo.avatar?.src)
- 更新个人资料(updateProfileAPI):✅ 已修复
- 修复参数结构从 avatar_meta_id 改为完整 avatar 对象
- 修复上传接口响应数据映射(正确提取 name、hash、src、height、width、size 字段)
- 添加页面加载时获取当前头像功能
- 更新总体进度:16个接口(11个已完成,3个已废弃,2个后端开发中)
**历史版本**:
- v1.7 (2026-02-03 23:30): 产品模块联调完成
- v1.6 (2026-02-02): 意见反馈模块联调完成
......
......@@ -58,30 +58,58 @@ paths:
id:
type: integer
title: 用户ID
avatar_url:
type: string
title: 头像
name:
type: string
title: 姓名
avatar_meta_id:
type: integer
title: 头像的附件ID
employee_no:
type: string
title: 工号
avatar:
type: object
properties:
name:
type: string
title: 文件名
hash:
type: string
title: 文件hash
src:
type: string
title: 文件地址
height:
type: string
title: 文件高度
width:
type: string
title: 文件宽度
size:
type: integer
title: 文件大小
x-apifox-orders:
- name
- hash
- src
- height
- width
- size
title: 头像
required:
- name
- hash
- src
- height
- width
- size
x-apifox-orders:
- id
- name
- avatar_url
- avatar_meta_id
- avatar
- employee_no
title: 用户信息
required:
- id
- avatar_url
- avatar
- name
- avatar_meta_id
- employee_no
x-apifox-orders:
- user
......@@ -100,7 +128,7 @@ paths:
x-apifox-ordering: 0
security: []
x-apifox-folder: 用户
x-apifox-status: testing
x-apifox-status: released
x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-413906668-run
components:
schemas: {}
......
......@@ -43,15 +43,56 @@ paths:
schema:
type: object
properties:
avatar_meta_id:
avatar:
type: object
properties:
name:
type: string
title: 文件名
hash:
type: string
title: 文件hash
src:
type: string
title: 文件地址
height:
type: string
title: 文件高度
width:
type: string
title: 文件宽度
size:
type: integer
title: 头像的附件ID
title: 文件大小
x-apifox-orders:
- name
- hash
- src
- height
- width
- size
title: 头像
required:
- avatar_meta_id
- name
- hash
- src
- height
- width
- size
x-apifox-orders:
- avatar_meta_id
- avatar
title: 头像
required:
- avatar
example:
avatar_meta_id: 834933
avatar:
name: 77777-test.png
hash: FiKJlV6Sq6oQ4HgLIdqCfye6qKOr
src: >-
https://cdn.ipadbiz.cn/space_816560/77777_FiKJlV6Sq6oQ4HgLIdqCfye6qKOr.png
height: '45'
width: '74'
size: 4497
responses:
'200':
description: ''
......@@ -76,7 +117,7 @@ paths:
x-apifox-ordering: 0
security: []
x-apifox-folder: 用户
x-apifox-status: testing
x-apifox-status: released
x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-413906669-run
components:
schemas: {}
......
......@@ -18,10 +18,9 @@ const Api = {
* data: {
* user: {
* id: integer; // 用户ID
* avatar_url: string; // 头像
* name: string; // 姓名
* avatar_meta_id: integer; // 头像的附件ID
* employee_no: string; // 工号
* avatar: object; // 头像
* };
* };
* }>}
......@@ -73,7 +72,13 @@ export const logoutAPI = (params) => fn(fetch.post(Api.Logout, params));
* @description 更新个人资料
* @remark
* @param {Object} params 请求参数
* @param {integer} params.avatar_meta_id
* @param {Object} params.avatar - 头像对象(完整结构)
* @param {string} params.avatar.name - 文件名
* @param {string} params.avatar.hash - 文件hash
* @param {string} params.avatar.src - 文件地址
* @param {string} params.avatar.height - 文件高度
* @param {string} params.avatar.width - 文件宽度
* @param {number} params.avatar.size - 文件大小
* @returns {Promise<{
* code: number; // 状态码
* msg: string; // 消息
......
......@@ -35,18 +35,39 @@
<script setup>
import { ref } from 'vue'
import { useGo } from '@/hooks/useGo'
import IconFont from '@/components/IconFont.vue'
import NavHeader from '@/components/NavHeader.vue'
import Taro from '@tarojs/taro'
import Taro, { useLoad } from '@tarojs/taro'
import defaultAvatar from '@/assets/images/icon/avatar.svg'
import { updateProfileAPI } from '@/api/user'
import { updateProfileAPI, getProfileAPI } from '@/api/user'
import BASE_URL from '@/utils/config'
const go = useGo()
const avatarUrl = ref(defaultAvatar)
const tempAvatarUrl = ref('') // 临时存储上传后的头像URL
const tempAvatarMetaId = ref(null) // 临时存储上传后的头像 meta_id
const tempAvatarData = ref(null) // 临时存储上传后的完整 avatar 对象
/**
* @description 获取用户当前头像
* @description 页面加载时调用,如果用户已有头像则显示
*/
const fetchCurrentAvatar = async () => {
try {
const res = await getProfileAPI()
if (res.code === 1 && res.data?.user?.avatar?.src) {
// 用户已有头像,显示当前头像
avatarUrl.value = res.data.user.avatar.src
}
} catch (err) {
console.error('获取用户头像失败:', err)
// 失败时使用默认头像,不显示错误提示
}
}
/**
* @description 页面加载时获取用户当前头像
*/
useLoad(() => {
fetchCurrentAvatar()
})
/**
* @description 更换头像(参考老来赛项目,直接上传到服务器)
......@@ -93,10 +114,17 @@ const onChangeAvatar = () => {
if (data.code === 0) { // 注意:老来赛后端 code=0 表示成功
avatarUrl.value = data.data.src
tempAvatarUrl.value = data.data.src
// 保存 meta_id,用于后续更新头像
tempAvatarMetaId.value = data.data.meta_id || data.data.id || null
console.log('上传成功,meta_id:', tempAvatarMetaId.value)
// 保存完整的 avatar 对象,用于后续更新
// 根据实际接口返回结构映射字段
tempAvatarData.value = {
name: data.data.file?.name || data.data.title || '',
hash: data.data.res?.hash || '',
src: data.data.src || '',
height: String(data.data.height || data.data.res?.image_info?.height || '0'),
width: String(data.data.width || data.data.res?.image_info?.width || '0'),
size: data.data.file?.size || data.data.res?.filesize || 0
}
console.log('上传成功,avatar 对象:', tempAvatarData.value)
Taro.showToast({
title: '上传成功',
icon: 'success'
......@@ -132,7 +160,7 @@ const onCancel = () => {
*/
const onSave = async () => {
// 如果没有上传新头像,直接返回
if (!tempAvatarUrl.value) {
if (!tempAvatarData.value) {
Taro.showToast({
title: '请先选择头像',
icon: 'none'
......@@ -140,9 +168,9 @@ const onSave = async () => {
return
}
// 检查是否有 meta_id
if (!tempAvatarMetaId.value) {
console.error('缺少 avatar_meta_id,上传响应可能不包含 meta_id 字段')
// 检查 avatar 对象完整性
if (!tempAvatarData.value.src) {
console.error('avatar 对象缺少 src 字段')
Taro.showToast({
title: '上传数据异常,请重试',
icon: 'none'
......@@ -154,9 +182,9 @@ const onSave = async () => {
Taro.showLoading({ title: '保存中...', mask: true })
try {
// ✅ 修复:传递正确的参数 avatar_meta_id
// ✅ 修复:传递完整的 avatar 对象(符合 API 规范)
const res = await updateProfileAPI({
avatar_meta_id: tempAvatarMetaId.value
avatar: tempAvatarData.value
})
Taro.hideLoading()
......
......@@ -12,7 +12,7 @@
>
<!-- Avatar -->
<view class="w-[160rpx] h-[160rpx] rounded-full overflow-hidden border-2 border-white shadow-sm shrink-0">
<img class="w-full h-full object-cover" :src="userInfo?.avatar_url || defaultAvatar" />
<img class="w-full h-full object-cover" :src="userInfo?.avatar?.src || defaultAvatar" />
</view>
<!-- Info -->
......