489 lines
10 KiB
JavaScript
489 lines
10 KiB
JavaScript
/**
|
||
* API服务工具
|
||
* 统一处理网络请求、错误处理、token管理等
|
||
*/
|
||
|
||
const app = getApp();
|
||
|
||
// API配置
|
||
const API_CONFIG = {
|
||
baseUrl: 'https://api.xiaozhi.com', // 生产环境API地址
|
||
timeout: 10000,
|
||
retryCount: 3,
|
||
retryDelay: 1000
|
||
};
|
||
|
||
// 请求状态码
|
||
const STATUS_CODE = {
|
||
SUCCESS: 200,
|
||
UNAUTHORIZED: 401,
|
||
FORBIDDEN: 403,
|
||
NOT_FOUND: 404,
|
||
SERVER_ERROR: 500,
|
||
NETWORK_ERROR: -1
|
||
};
|
||
|
||
// 错误消息映射
|
||
const ERROR_MESSAGES = {
|
||
[STATUS_CODE.UNAUTHORIZED]: '登录已过期,请重新登录',
|
||
[STATUS_CODE.FORBIDDEN]: '没有访问权限',
|
||
[STATUS_CODE.NOT_FOUND]: '请求的资源不存在',
|
||
[STATUS_CODE.SERVER_ERROR]: '服务器内部错误',
|
||
[STATUS_CODE.NETWORK_ERROR]: '网络连接失败,请检查网络设置'
|
||
};
|
||
|
||
/**
|
||
* 基础请求方法
|
||
* @param {Object} options 请求配置
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
function request(options) {
|
||
return new Promise((resolve, reject) => {
|
||
const {
|
||
url,
|
||
method = 'GET',
|
||
data = {},
|
||
header = {},
|
||
needAuth = true,
|
||
showLoading = true,
|
||
loadingText = '加载中...',
|
||
retryCount = 0
|
||
} = options;
|
||
|
||
// 显示加载提示
|
||
if (showLoading) {
|
||
wx.showLoading({
|
||
title: loadingText,
|
||
mask: true
|
||
});
|
||
}
|
||
|
||
// 构建请求头
|
||
const requestHeader = {
|
||
'Content-Type': 'application/json',
|
||
...header
|
||
};
|
||
|
||
// 添加认证token
|
||
if (needAuth && app.globalData.token) {
|
||
requestHeader['Authorization'] = `Bearer ${app.globalData.token}`;
|
||
}
|
||
|
||
// 发起请求
|
||
wx.request({
|
||
url: `${API_CONFIG.baseUrl}${url}`,
|
||
method,
|
||
data,
|
||
header: requestHeader,
|
||
timeout: API_CONFIG.timeout,
|
||
success: (res) => {
|
||
if (showLoading) {
|
||
wx.hideLoading();
|
||
}
|
||
|
||
const { statusCode, data: responseData } = res;
|
||
|
||
// 请求成功
|
||
if (statusCode === STATUS_CODE.SUCCESS) {
|
||
if (responseData.code === 0) {
|
||
resolve(responseData);
|
||
} else {
|
||
// 业务错误
|
||
handleBusinessError(responseData, reject);
|
||
}
|
||
} else {
|
||
// HTTP错误
|
||
handleHttpError(statusCode, reject, options, retryCount);
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
if (showLoading) {
|
||
wx.hideLoading();
|
||
}
|
||
|
||
console.error('Request failed:', error);
|
||
|
||
// 网络错误重试
|
||
if (retryCount < API_CONFIG.retryCount) {
|
||
setTimeout(() => {
|
||
request({
|
||
...options,
|
||
retryCount: retryCount + 1
|
||
}).then(resolve).catch(reject);
|
||
}, API_CONFIG.retryDelay);
|
||
} else {
|
||
handleNetworkError(error, reject);
|
||
}
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 处理业务错误
|
||
* @param {Object} responseData 响应数据
|
||
* @param {Function} reject 拒绝函数
|
||
*/
|
||
function handleBusinessError(responseData, reject) {
|
||
const { code, message } = responseData;
|
||
|
||
// 特殊错误码处理
|
||
switch (code) {
|
||
case 401:
|
||
// token过期,清除登录状态
|
||
app.clearLoginStatus();
|
||
wx.showToast({
|
||
title: '登录已过期',
|
||
icon: 'none'
|
||
});
|
||
// 跳转到登录页
|
||
wx.navigateTo({
|
||
url: '/pages/login/login'
|
||
});
|
||
break;
|
||
case 403:
|
||
wx.showToast({
|
||
title: '权限不足',
|
||
icon: 'none'
|
||
});
|
||
break;
|
||
default:
|
||
wx.showToast({
|
||
title: message || '操作失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
|
||
reject({
|
||
code,
|
||
message,
|
||
type: 'business'
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 处理HTTP错误
|
||
* @param {Number} statusCode 状态码
|
||
* @param {Function} reject 拒绝函数
|
||
* @param {Object} options 请求选项
|
||
* @param {Number} retryCount 重试次数
|
||
*/
|
||
function handleHttpError(statusCode, reject, options, retryCount) {
|
||
const message = ERROR_MESSAGES[statusCode] || '请求失败';
|
||
|
||
// 401错误特殊处理
|
||
if (statusCode === STATUS_CODE.UNAUTHORIZED) {
|
||
app.clearLoginStatus();
|
||
wx.navigateTo({
|
||
url: '/pages/login/login'
|
||
});
|
||
}
|
||
|
||
// 5xx错误重试
|
||
if (statusCode >= 500 && retryCount < API_CONFIG.retryCount) {
|
||
setTimeout(() => {
|
||
request({
|
||
...options,
|
||
retryCount: retryCount + 1
|
||
}).then(resolve).catch(reject);
|
||
}, API_CONFIG.retryDelay);
|
||
return;
|
||
}
|
||
|
||
wx.showToast({
|
||
title: message,
|
||
icon: 'none'
|
||
});
|
||
|
||
reject({
|
||
code: statusCode,
|
||
message,
|
||
type: 'http'
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 处理网络错误
|
||
* @param {Object} error 错误对象
|
||
* @param {Function} reject 拒绝函数
|
||
*/
|
||
function handleNetworkError(error, reject) {
|
||
wx.showToast({
|
||
title: '网络连接失败',
|
||
icon: 'none'
|
||
});
|
||
|
||
reject({
|
||
code: STATUS_CODE.NETWORK_ERROR,
|
||
message: '网络连接失败',
|
||
type: 'network',
|
||
error
|
||
});
|
||
}
|
||
|
||
/**
|
||
* GET请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} params 请求参数
|
||
* @param {Object} options 其他选项
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
function get(url, params = {}, options = {}) {
|
||
const queryString = Object.keys(params)
|
||
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
|
||
.join('&');
|
||
|
||
const requestUrl = queryString ? `${url}?${queryString}` : url;
|
||
|
||
return request({
|
||
url: requestUrl,
|
||
method: 'GET',
|
||
...options
|
||
});
|
||
}
|
||
|
||
/**
|
||
* POST请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} data 请求数据
|
||
* @param {Object} options 其他选项
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
function post(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'POST',
|
||
data,
|
||
...options
|
||
});
|
||
}
|
||
|
||
/**
|
||
* PUT请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} data 请求数据
|
||
* @param {Object} options 其他选项
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
function put(url, data = {}, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'PUT',
|
||
data,
|
||
...options
|
||
});
|
||
}
|
||
|
||
/**
|
||
* DELETE请求
|
||
* @param {String} url 请求地址
|
||
* @param {Object} options 其他选项
|
||
* @returns {Promise} 请求结果
|
||
*/
|
||
function del(url, options = {}) {
|
||
return request({
|
||
url,
|
||
method: 'DELETE',
|
||
...options
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 文件上传
|
||
* @param {String} url 上传地址
|
||
* @param {String} filePath 文件路径
|
||
* @param {Object} formData 表单数据
|
||
* @param {Object} options 其他选项
|
||
* @returns {Promise} 上传结果
|
||
*/
|
||
function upload(url, filePath, formData = {}, options = {}) {
|
||
return new Promise((resolve, reject) => {
|
||
const {
|
||
name = 'file',
|
||
header = {},
|
||
needAuth = true,
|
||
showLoading = true
|
||
} = options;
|
||
|
||
if (showLoading) {
|
||
wx.showLoading({
|
||
title: '上传中...',
|
||
mask: true
|
||
});
|
||
}
|
||
|
||
// 构建请求头
|
||
const requestHeader = { ...header };
|
||
if (needAuth && app.globalData.token) {
|
||
requestHeader['Authorization'] = `Bearer ${app.globalData.token}`;
|
||
}
|
||
|
||
wx.uploadFile({
|
||
url: `${API_CONFIG.baseUrl}${url}`,
|
||
filePath,
|
||
name,
|
||
formData,
|
||
header: requestHeader,
|
||
success: (res) => {
|
||
if (showLoading) {
|
||
wx.hideLoading();
|
||
}
|
||
|
||
try {
|
||
const data = JSON.parse(res.data);
|
||
if (data.code === 0) {
|
||
resolve(data);
|
||
} else {
|
||
handleBusinessError(data, reject);
|
||
}
|
||
} catch (error) {
|
||
reject({
|
||
code: -1,
|
||
message: '响应数据解析失败',
|
||
type: 'parse',
|
||
error
|
||
});
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
if (showLoading) {
|
||
wx.hideLoading();
|
||
}
|
||
handleNetworkError(error, reject);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// 会员相关API
|
||
const memberAPI = {
|
||
// 获取用户信息
|
||
getUserInfo() {
|
||
return get('/api/member/user/info');
|
||
},
|
||
|
||
// 微信登录
|
||
wxLogin(code) {
|
||
return post('/api/member/auth/wx-login', { code }, { needAuth: false });
|
||
},
|
||
|
||
// 获取会员信息
|
||
getMemberInfo() {
|
||
return get('/api/member/info');
|
||
},
|
||
|
||
// 绑定会员
|
||
bindMember(memberData) {
|
||
return post('/api/member/bind', memberData);
|
||
},
|
||
|
||
// 解绑会员
|
||
unbindMember() {
|
||
return post('/api/member/unbind');
|
||
},
|
||
|
||
// 获取会员权益
|
||
getMemberBenefits() {
|
||
return get('/api/member/benefits');
|
||
},
|
||
|
||
// 验证会员权益
|
||
verifyBenefit(benefitType) {
|
||
return post('/api/member/verify-benefit', { benefitType });
|
||
},
|
||
|
||
// 获取会员等级配置
|
||
getMemberLevels() {
|
||
return get('/api/member/levels');
|
||
},
|
||
|
||
// 升级会员
|
||
upgradeMember(targetLevel) {
|
||
return post('/api/member/upgrade', { targetLevel });
|
||
},
|
||
|
||
// 获取绑定历史
|
||
getBindHistory(page = 1, size = 10) {
|
||
return get('/api/member/bind-history', { page, size });
|
||
},
|
||
|
||
// 获取权益使用记录
|
||
getBenefitUsage(page = 1, size = 10) {
|
||
return get('/api/member/benefit-usage', { page, size });
|
||
},
|
||
|
||
// 邀请好友
|
||
inviteFriend(inviteCode) {
|
||
return post('/api/member/invite', { inviteCode });
|
||
},
|
||
|
||
// 获取邀请记录
|
||
getInviteHistory(page = 1, size = 10) {
|
||
return get('/api/member/invite-history', { page, size });
|
||
}
|
||
};
|
||
|
||
// 支付相关API
|
||
const paymentAPI = {
|
||
// 创建支付订单
|
||
createOrder(orderData) {
|
||
return post('/api/payment/create-order', orderData);
|
||
},
|
||
|
||
// 查询订单状态
|
||
queryOrder(orderId) {
|
||
return get(`/api/payment/order/${orderId}`);
|
||
},
|
||
|
||
// 取消订单
|
||
cancelOrder(orderId) {
|
||
return post(`/api/payment/order/${orderId}/cancel`);
|
||
},
|
||
|
||
// 申请退款
|
||
requestRefund(orderId, refundData) {
|
||
return post(`/api/payment/order/${orderId}/refund`, refundData);
|
||
},
|
||
|
||
// 查询退款状态
|
||
queryRefund(refundId) {
|
||
return get(`/api/payment/refund/${refundId}`);
|
||
}
|
||
};
|
||
|
||
// 通用API
|
||
const commonAPI = {
|
||
// 获取系统配置
|
||
getSystemConfig() {
|
||
return get('/api/common/config', {}, { needAuth: false });
|
||
},
|
||
|
||
// 上传图片
|
||
uploadImage(filePath) {
|
||
return upload('/api/common/upload/image', filePath);
|
||
},
|
||
|
||
// 发送验证码
|
||
sendVerifyCode(phone) {
|
||
return post('/api/common/send-verify-code', { phone }, { needAuth: false });
|
||
},
|
||
|
||
// 验证验证码
|
||
verifyCode(phone, code) {
|
||
return post('/api/common/verify-code', { phone, code }, { needAuth: false });
|
||
}
|
||
};
|
||
|
||
module.exports = {
|
||
request,
|
||
get,
|
||
post,
|
||
put,
|
||
del: del,
|
||
upload,
|
||
memberAPI,
|
||
paymentAPI,
|
||
commonAPI,
|
||
API_CONFIG,
|
||
STATUS_CODE
|
||
}; |