hookehuyr

docs: 新增头像修改页面接口记录

- 更新接口联调工作记录文档,新增通用模块接口
  - qiniuTokenAPI: 获取七牛上传 Token
  - saveFileAPI: 保存文件信息到服务器
  - uploadImageToQiniuAPI: 完整的图片上传流程(封装接口)
- 更新 CHANGELOG.md,记录头像页面实现情况
- 更新总体进度:14个接口(5个已完成,9个后端开发中)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
......@@ -42,11 +42,34 @@
## 📊 快速统计
- **总变更数**: 58+
- **总变更数**: 59+
- **新增功能**: 26+
- **优化改进**: 28+
- **问题修复**: 13+
- **文档更新**: 12+
- **文档更新**: 13+
---
## [2026-02-03] - 新增头像修改页面接口记录
### 文档
- 更新接口联调工作记录文档 (`docs/api-integration-log.md`)
- 新增通用模块接口记录(3个):
- 获取七牛上传 Token (`qiniuTokenAPI`) - ⏳ 后端开发中
- 保存文件信息 (`saveFileAPI`) - ⏳ 后端开发中
- 上传图片到七牛云 (`uploadImageToQiniuAPI`) - ⏳ 后端开发中
- 更新总体进度:14个接口(5个已完成,9个后端开发中)
---
**详细信息**
- **影响文件**: docs/api-integration-log.md, src/pages/avatar/index.vue, src/api/common.js
- **技术栈**: Vue 3, Taro, 七牛云
- **测试状态**: ⏳ 后端开发中
- **备注**:
- 头像修改页面已实现前端逻辑
- 图片上传流程:选择图片 → 七牛云上传 → 保存到服务器
- 等待后端接口开发完成后联调
---
......
......@@ -4,10 +4,10 @@
## 📊 总体进度
- **总接口数**: 10
- **已完成**: 5 (50%)
- **总接口数**: 14
- **已完成**: 5 (35.7%)
- **联调中**: 0 (0%)
- **后端开发中**: 5 (50%)
- **后端开发中**: 9 (64.3%)
- **有阻塞**: 0
---
......@@ -200,6 +200,104 @@
---
### 通用模块
#### 接口 1: 获取七牛上传 Token
**接口信息**
- **接口名称**: `qiniuTokenAPI`
- **接口路径**: `/srv/?a=upload`
- **请求方法**: POST
- **负责页面**: `src/pages/avatar/index.vue`(待确认)
- **负责人**: 后端团队
**接口文档更新记录**
| 日期 | 版本 | 变更内容 | 变更原因 | 文档链接 |
|------|------|---------|---------|---------|
| 2026-02-03 | v1.0 | 初始版本 | - | [查看](#) |
**页面调试情况**
| 日期 | 调试页面 | 问题记录 | 解决方案 | 状态 |
|------|---------|---------|---------|------|
| 2026-02-03 | - | 后端开发中 | - | ⏳ 后端开发中 |
**接口状态**: ⏳ 后端开发中
**备注**:
- 参数:filename(文件名)、file(图片 base64)
- 返回七牛上传 token、upload_url、filekey
- 后端接口开发中
---
#### 接口 2: 保存文件信息
**接口信息**
- **接口名称**: `saveFileAPI`
- **接口路径**: `/srv/?a=upload&t=save_file`
- **请求方法**: POST
- **负责页面**: `src/pages/avatar/index.vue`(待确认)
- **负责人**: 后端团队
**接口文档更新记录**
| 日期 | 版本 | 变更内容 | 变更原因 | 文档链接 |
|------|------|---------|---------|---------|
| 2026-02-03 | v1.0 | 初始版本 | - | [查看](#) |
**页面调试情况**
| 日期 | 调试页面 | 问题记录 | 解决方案 | 状态 |
|------|---------|---------|---------|------|
| 2026-02-03 | - | 后端开发中 | - | ⏳ 后端开发中 |
**接口状态**: ⏳ 后端开发中
**备注**:
- 参数:format(文件格式)、hash(文件 hash)、height(图片高)、width(图片宽)、filekey(文件 key)
- 七牛上传成功后,将文件信息保存到服务器
- 后端接口开发中
---
#### 接口 3: 上传图片到七牛云(完整流程)
**接口信息**
- **接口名称**: `uploadImageToQiniuAPI`
- **接口路径**: 封装接口(内部调用 `qiniuTokenAPI`、七牛上传、`saveFileAPI`
- **请求方法**: 封装函数
- **负责页面**: `src/pages/avatar/index.vue`
- **负责人**: 后端团队
**接口文档更新记录**
| 日期 | 版本 | 变更内容 | 变更原因 | 文档链接 |
|------|------|---------|---------|---------|
| 2026-02-03 | v1.0 | 初始版本 | - | [查看](#) |
**页面调试情况**
| 日期 | 调试页面 | 问题记录 | 解决方案 | 状态 |
|------|---------|---------|---------|------|
| 2026-02-03 | `src/pages/avatar/index.vue` | 后端开发中 | - | ⏳ 后端开发中 |
**接口状态**: ⏳ 后端开发中
**备注**:
- 完整的上传流程:
1. 读取本地文件为 base64
2. 获取七牛上传 token(调用 `qiniuTokenAPI`
3. 上传到七牛云(调用 `qiniuUploadAPI`
4. 保存文件信息到服务器(调用 `saveFileAPI`
- 参数:filePath(本地文件路径)
- 返回:`{ code: 1, data: { src, hash, format, width, height } }`
- 后端接口开发中
- 实现位置:`src/api/common.js:77-150`
---
### 意见反馈模块
#### 接口 1: 意见反馈列表
......@@ -382,12 +480,12 @@
## 📈 进度追踪
### 本周进度 (2026-01-27 ~ 2026-02-02)
### 本周进度 (2026-01-27 ~ 2026-02-03)
- **新增接口**: 10
- **新增接口**: 14
- **完成联调**: 5
- **联调中**: 0
- **后端开发中**: 5
- **后端开发中**: 9
- **发现问题**: 0
- **解决问题**: 0
......@@ -395,7 +493,7 @@
| 周 | 完成数 | 新增数 | 问题数 |
|----|--------|--------|--------|
| 2026-01-27 ~ 2026-02-02 | 5 | 10 | 0 |
| 2026-01-27 ~ 2026-02-03 | 5 | 14 | 0 |
---
......@@ -403,15 +501,18 @@
### 按状态查看
- [✅ 已完成](#用户中心模块) - 5个接口
- [⏳ 后端开发中](#用户中心模块) - 1个接口
- [⏳ 后端开发中](#通用模块) - 3个接口
- [⏳ 后端开发中](#意见反馈模块) - 2个接口
- [⏳ 后端开发中](#消息模块) - 2个接口
- [⏳ 后端开发中](#用户中心模块) - 1个接口
- [⏳ 后端开发中](#首页模块) - 1个接口
### 按模块查看
- [用户中心](#用户中心模块) - ✅ 5个已完成, ⏳ 1个后端开发中
- [通用](#通用模块) - ⏳ 3个后端开发中
- [意见反馈](#意见反馈模块) - ⏳ 2个后端开发中
- [消息](#消息模块) - ⏳ 2个后端开发中
- [首页](#首页模块) - ⏳ 未开始
- [首页](#首页模块) - ⏳ 1个后端开发中
- [产品详情](#产品模块) - ⏳ 未开始
- [知识库](#知识库模块) - ⏳ 未开始
- [家办](#家办模块) - ⏳ 未开始
......@@ -449,8 +550,8 @@
---
**最后更新时间**: 2026-02-03 15:30
**文档版本**: v1.3
**最后更新时间**: 2026-02-03 18:00
**文档版本**: v1.4
**更新内容**:
- 登录接口联调完成,更新状态为 ✅ 已完成
- 更新总体进度:10个接口(5个已完成,5个后端开发中)
- 新增通用模块接口:获取七牛上传 Token、保存文件信息、上传图片到七牛云(完整流程)
- 更新总体进度:14个接口(5个已完成,9个后端开发中)
......
......@@ -11,6 +11,7 @@ const Api = {
SMS: '/srv/?a=sms',
TOKEN: '/srv/?a=upload',
SAVE_FILE: '/srv/?a=upload&t=save_file',
UPLOAD_IMAGE: '/admin/?m=srv&a=upload', // 上传图片(不带审核)
}
/**
......@@ -50,3 +51,101 @@ export const qiniuUploadAPI = (url, data, config) => uploadFn(fetch.basePost(url
* @returns {Promise<{code:number,data:any,msg:string}>} 标准返回
*/
export const saveFileAPI = (params) => fn(fetch.stringifyPost(Api.SAVE_FILE, params));
/**
* @description: 上传图片到七牛云(完整流程)
* @param {Object} params 请求参数
* @param {string} params.filePath 本地文件路径
* @returns {Promise<{code:number,data:{src:string},msg:string}>} 返回上传结果,data.src 为图片URL
*
* @example
* // 在页面中使用
* import { uploadImageToQiniuAPI } from '@/api/common'
*
* Taro.chooseImage({
* count: 1,
* success: async (res) => {
* const result = await uploadImageToQiniuAPI({
* filePath: res.tempFilePaths[0]
* })
* if (result.code === 1) {
* console.log('图片URL:', result.data.src)
* }
* }
* })
*/
export const uploadImageToQiniuAPI = async (params) => {
try {
// 1. 读取文件为 base64
const base64Data = await new Promise((resolve, reject) => {
Taro.getFileSystemManager().readFile({
filePath: params.filePath,
encoding: 'base64',
success: (res) => resolve(res.data),
fail: (err) => reject(err)
});
});
// 2. 获取七牛上传token
const tokenRes = await qiniuTokenAPI({
filename: params.filePath.split('/').pop(),
file: base64Data
});
if (tokenRes.code !== 1 || !tokenRes.data) {
throw new Error(tokenRes.msg || '获取上传凭证失败');
}
const { token, upload_url, filekey } = tokenRes.data;
// 3. 上传到七牛云
const formData = new FormData();
formData.append('file', base64Data);
formData.append('token', token);
formData.append('key', filekey);
const uploadRes = await qiniuUploadAPI(upload_url, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
if (!uploadRes) {
throw new Error('七牛上传失败');
}
// 4. 保存文件信息到服务器
const saveRes = await saveFileAPI({
format: uploadRes.format,
hash: uploadRes.hash,
height: uploadRes.height || 0,
width: uploadRes.width || 0,
filekey: uploadRes.key
});
if (saveRes.code !== 1) {
throw new Error(saveRes.msg || '保存文件信息失败');
}
return {
code: 1,
data: {
src: uploadRes.src || saveRes.data.src, // 优先使用七牛返回的src,否则使用服务器返回的
hash: uploadRes.hash,
format: uploadRes.format,
width: uploadRes.width,
height: uploadRes.height
},
msg: '上传成功'
};
} catch (err) {
console.error('上传图片失败:', err);
return {
code: 0,
data: null,
msg: err.message || err.msg || '上传失败'
};
}
};
......
......@@ -40,34 +40,125 @@ import IconFont from '@/components/IconFont.vue'
import NavHeader from '@/components/NavHeader.vue'
import Taro from '@tarojs/taro'
import defaultAvatar from '@/assets/images/icon/avatar.svg'
import { uploadImageToQiniuAPI } from '@/api/common'
import { updateProfileAPI } from '@/api/user'
const go = useGo()
const avatarUrl = ref(defaultAvatar)
const tempAvatarUrl = ref('') // 临时存储上传后的头像URL
const uploading = ref(false) // 上传状态
/**
* @description 更换头像
*/
const onChangeAvatar = () => {
Taro.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sizeType: ['compressed'], // 使用压缩图,减少上传时间
sourceType: ['album', 'camera'],
success: function (res) {
// tempFilePath can be used as image src
avatarUrl.value = res.tempFilePaths[0]
success: async (res) => {
const tempFile = res.tempFiles[0]
// 检查文件大小(5MB限制)
if (tempFile.size > 5 * 1024 * 1024) {
Taro.showToast({
title: '图片大小不能超过5MB',
icon: 'none',
})
return
}
// 显示上传进度
Taro.showLoading({ title: '上传中...', mask: true })
uploading.value = true
try {
// 上传到七牛云
const uploadRes = await uploadImageToQiniuAPI({
filePath: tempFile.path
})
Taro.hideLoading()
uploading.value = false
if (uploadRes.code === 1) {
// 上传成功,更新头像显示
avatarUrl.value = uploadRes.data.src
tempAvatarUrl.value = uploadRes.data.src
Taro.showToast({
title: '上传成功',
icon: 'success'
})
} else {
Taro.showToast({
title: uploadRes.msg || '上传失败',
icon: 'none'
})
}
} catch (err) {
Taro.hideLoading()
uploading.value = false
console.error('上传头像失败:', err)
Taro.showToast({
title: '上传失败,请稍后重试',
icon: 'none'
})
}
}
})
}
/**
* @description 取消修改
*/
const onCancel = () => {
Taro.navigateBack()
}
const onSave = () => {
Taro.showLoading({ title: '保存中...' })
setTimeout(() => {
/**
* @description 保存头像
*/
const onSave = async () => {
// 如果没有上传新头像,直接返回
if (!tempAvatarUrl.value) {
Taro.showToast({
title: '请先选择头像',
icon: 'none'
})
return
}
// 保存到服务器
Taro.showLoading({ title: '保存中...', mask: true })
try {
const res = await updateProfileAPI({
avatar_url: tempAvatarUrl.value
})
Taro.hideLoading()
if (res.code === 1) {
Taro.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
Taro.navigateBack()
}, 1500)
} else {
Taro.showToast({
title: res.msg || '保存失败',
icon: 'none'
})
}
} catch (err) {
Taro.hideLoading()
Taro.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => {
Taro.navigateBack()
}, 1500)
}, 1000)
console.error('保存头像失败:', err)
Taro.showToast({
title: '保存失败,请稍后重试',
icon: 'none'
})
}
}
</script>
......