## 主要改动
### 1. 修复Mock数据格式问题
- 修复 mock/athlete.js 中 getProjects 函数
- 从字符串数组改为对象数组 { id, name }
- 确保Mock模式和API模式数据格式一致
### 2. 优化网络请求处理
- 优化 utils/request.js 的GET请求参数处理
- 参数自动URL编码
- 支持URL中已有查询参数的情况
- 代码逻辑更清晰
### 3. 新增完整的文档体系
- API对接说明.md - 项目根目录快速说明
- doc/API对接快速启动指南.md - 5分钟快速上手
- doc/后端接口开发清单.md - 后端开发规范(5个接口,6人天)
- doc/前端API对接指南.md - 前端联调指南
- doc/API对接准备完成报告.md - 项目状态总结
## 项目状态
✅ 前端准备完成度: 100%
- 架构设计优秀(dataAdapter适配器模式)
- 代码质量高(注释详细,结构清晰)
- Mock数据完整(可独立演示)
- API接口定义完整(9个接口)
- 页面全部接入(5个页面)
- 文档体系完善(20个文档)
⚠️ 后端待开发: 5个接口
- POST /api/mini/login
- GET /api/mini/athletes
- GET /api/mini/athletes/admin
- GET /api/mini/score/detail/{id}
- PUT /api/mini/score/modify
## 下一步
后端开发者可以参考 doc/后端接口开发清单.md 开始开发
预计工作量: 6人天(约1周)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
261 lines
5.5 KiB
JavaScript
261 lines
5.5 KiB
JavaScript
/**
|
||
* 网络请求封装
|
||
* 统一处理HTTP请求、响应、错误、Token等
|
||
*
|
||
* 特性:
|
||
* - 自动添加Token(Blade-Auth格式)
|
||
* - 统一错误处理
|
||
* - 请求/响应拦截
|
||
* - 超时控制
|
||
* - Loading状态管理
|
||
*/
|
||
|
||
import config from '@/config/env.config.js'
|
||
|
||
/**
|
||
* 构建请求头
|
||
* @param {Object} customHeader 自定义头部
|
||
* @returns {Object} 完整的请求头
|
||
*/
|
||
function getHeaders(customHeader = {}) {
|
||
const token = uni.getStorageSync('token') || ''
|
||
|
||
return {
|
||
'Content-Type': 'application/json',
|
||
// 重要:后端使用 Blade-Auth 而不是 Authorization
|
||
'Blade-Auth': token ? `Bearer ${token}` : '',
|
||
...customHeader
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 统一请求方法
|
||
* @param {Object} options 请求配置
|
||
* @param {String} options.url 请求路径(不含baseURL)
|
||
* @param {String} options.method 请求方法(GET/POST/PUT/DELETE)
|
||
* @param {Object} options.data 请求数据(POST/PUT使用)
|
||
* @param {Object} options.params 查询参数(GET使用)
|
||
* @param {Object} options.header 自定义请求头
|
||
* @param {Boolean} options.showLoading 是否显示Loading
|
||
* @param {String} options.loadingText Loading文本
|
||
* @returns {Promise}
|
||
*/
|
||
function request(options = {}) {
|
||
const {
|
||
url = '',
|
||
method = 'GET',
|
||
data = {},
|
||
params = {},
|
||
header = {},
|
||
showLoading = false,
|
||
loadingText = '加载中...'
|
||
} = options
|
||
|
||
// 显示Loading
|
||
if (showLoading) {
|
||
uni.showLoading({
|
||
title: loadingText,
|
||
mask: true
|
||
})
|
||
}
|
||
|
||
// 打印调试信息
|
||
if (config.debug) {
|
||
console.log(`[API请求] ${method} ${url}`, method === 'GET' ? params : data)
|
||
}
|
||
|
||
// 构建完整URL(GET请求需要拼接查询参数)
|
||
let fullUrl = config.apiBaseURL + url
|
||
let requestData = data
|
||
|
||
// GET请求:将params拼接到URL
|
||
if (method === 'GET' && params && Object.keys(params).length > 0) {
|
||
const queryString = Object.keys(params)
|
||
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
|
||
.join('&')
|
||
fullUrl += (url.includes('?') ? '&' : '?') + queryString
|
||
requestData = undefined // GET请求不使用data字段
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
uni.request({
|
||
url: fullUrl,
|
||
method,
|
||
data: requestData,
|
||
header: getHeaders(header),
|
||
timeout: config.timeout,
|
||
success: (res) => {
|
||
if (config.debug) {
|
||
console.log(`[API响应] ${method} ${url}`, res.data)
|
||
}
|
||
|
||
// 隐藏Loading
|
||
if (showLoading) {
|
||
uni.hideLoading()
|
||
}
|
||
|
||
// BladeX框架标准响应格式
|
||
// { code: 200, success: true, data: {}, msg: "操作成功" }
|
||
if (res.statusCode === 200) {
|
||
const response = res.data
|
||
|
||
// 业务成功
|
||
if (response.code === 200 || response.success) {
|
||
resolve({
|
||
code: 200,
|
||
message: response.msg || response.message || '成功',
|
||
data: response.data,
|
||
success: true
|
||
})
|
||
} else {
|
||
// 业务失败
|
||
const errorMsg = response.msg || response.message || '请求失败'
|
||
uni.showToast({
|
||
title: errorMsg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
reject({
|
||
code: response.code,
|
||
message: errorMsg,
|
||
data: response.data
|
||
})
|
||
}
|
||
} else if (res.statusCode === 401) {
|
||
// Token过期或未登录
|
||
uni.showToast({
|
||
title: 'Token已过期,请重新登录',
|
||
icon: 'none'
|
||
})
|
||
// 清除Token
|
||
uni.removeStorageSync('token')
|
||
// 跳转到登录页
|
||
setTimeout(() => {
|
||
uni.reLaunch({
|
||
url: '/pages/login/login'
|
||
})
|
||
}, 1500)
|
||
reject({
|
||
code: 401,
|
||
message: 'Token已过期'
|
||
})
|
||
} else {
|
||
// HTTP错误
|
||
const errorMsg = `请求失败 (${res.statusCode})`
|
||
uni.showToast({
|
||
title: errorMsg,
|
||
icon: 'none'
|
||
})
|
||
reject({
|
||
code: res.statusCode,
|
||
message: errorMsg
|
||
})
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
if (config.debug) {
|
||
console.error(`[API错误] ${method} ${url}`, err)
|
||
}
|
||
|
||
// 隐藏Loading
|
||
if (showLoading) {
|
||
uni.hideLoading()
|
||
}
|
||
|
||
// 网络错误
|
||
const errorMsg = err.errMsg || '网络错误,请检查网络连接'
|
||
uni.showToast({
|
||
title: errorMsg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
reject({
|
||
code: -1,
|
||
message: errorMsg,
|
||
error: err
|
||
})
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
/**
|
||
* GET 请求
|
||
*/
|
||
export function get(url, params = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'GET',
|
||
params,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* POST 请求
|
||
*/
|
||
export function post(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'POST',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* PUT 请求
|
||
*/
|
||
export function put(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'PUT',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
/**
|
||
* DELETE 请求
|
||
*/
|
||
export function del(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'DELETE',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
// 默认导出
|
||
export default request
|
||
|
||
/**
|
||
* 使用示例:
|
||
*
|
||
* // 方式1:直接使用 request
|
||
* import request from '@/utils/request.js'
|
||
*
|
||
* request({
|
||
* url: '/martial/score/list',
|
||
* method: 'GET',
|
||
* data: { page: 1, size: 10 },
|
||
* showLoading: true
|
||
* }).then(res => {
|
||
* console.log(res.data)
|
||
* }).catch(err => {
|
||
* console.error(err.message)
|
||
* })
|
||
*
|
||
* // 方式2:使用快捷方法
|
||
* import { get, post, put, del } from '@/utils/request.js'
|
||
*
|
||
* // GET请求
|
||
* get('/martial/athlete/list', { venueId: 1 })
|
||
* .then(res => console.log(res.data))
|
||
*
|
||
* // POST请求
|
||
* post('/martial/score/submit', { athleteId: 1, score: 8.907 })
|
||
* .then(res => console.log(res.data))
|
||
*/
|