AssetManager.UniApp/utils/api.js
niannian zheng 58cf092753 feat(策略编辑): 实现策略创建功能并优化API请求
添加策略创建的表单验证和API调用逻辑
移除API请求中对userId的硬编码依赖
使用环境变量配置API基础URL
2026-03-02 15:13:15 +08:00

299 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* API工具类 - 统一封装后端API请求
*/
console.log('📦 api.js 模块加载成功')
// API基础URL
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://localhost:7040/';
// 请求超时时间
const TIMEOUT = 10000;
// 登录锁,防止并发登录
let loginLock = null;
/**
* 获取微信登录码
* @returns {Promise<string>} - 返回微信登录码
*/
const getWechatCode = () => {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin',
success: (res) => {
if (res.code) {
console.log('📱 微信登录码获取成功:', res.code);
resolve(res.code);
} else {
console.error('📱 微信登录码获取失败:', res.errMsg);
reject(new Error(`微信登录码获取失败: ${res.errMsg}`));
}
},
fail: (err) => {
console.error('📱 微信登录失败:', err);
reject(new Error(`微信登录失败: ${err.errMsg}`));
}
});
});
};
/**
* 执行微信登录
* @returns {Promise<object>} - 返回登录结果
*/
const doWechatLogin = async () => {
try {
console.log('🔐 开始执行微信登录');
const code = await getWechatCode();
console.log('🔐 开始调用后端登录接口:', code);
const res = await new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}api/auth/wechat-login`,
method: 'POST',
data: { code },
header: {
'Content-Type': 'application/json'
},
timeout: TIMEOUT,
success: resolve,
fail: reject
});
});
console.log('🔐 后端登录接口响应:', res);
if (res.statusCode === 200 && res.data?.code === 200 && res.data?.data?.token) {
console.log('✅ 微信登录成功获取到token');
uni.setStorageSync('token', res.data.data.token);
return res.data;
} else {
console.error('❌ 微信登录失败:', res.data?.message || '登录失败');
throw new Error(res.data?.message || '微信登录失败');
}
} catch (error) {
console.error('❌ 微信登录异常:', error);
throw error;
}
};
/**
* 带重试机制的请求方法
* @param {string} url - 请求URL
* @param {string} method - 请求方法
* @param {object} data - 请求数据
* @param {object} headers - 请求头
* @param {number} retryCount - 重试次数
* @returns {Promise} - 返回Promise对象
*/
const requestWithRetry = async (url, method = 'GET', data = {}, headers = {}, retryCount = 0) => {
try {
// 获取存储的token
let token = uni.getStorageSync('token');
// 如果没有token先执行微信登录使用登录锁防止并发
if (!token) {
if (loginLock) {
console.log('🔒 等待其他请求完成登录...');
await loginLock;
token = uni.getStorageSync('token');
} else {
console.log('🔒 未检测到token开始微信登录...');
loginLock = doWechatLogin();
await loginLock;
loginLock = null;
token = uni.getStorageSync('token');
console.log('🔒 微信登录成功获取到token');
}
}
// 正确处理URL拼接避免双斜杠
let fullUrl;
if (BASE_URL.endsWith('/') && url.startsWith('/')) {
fullUrl = BASE_URL + url.substring(1);
} else if (!BASE_URL.endsWith('/') && !url.startsWith('/')) {
fullUrl = BASE_URL + '/' + url;
} else {
fullUrl = BASE_URL + url;
}
// 请求开始日志
console.log('🚀 API 请求开始:', {
method,
url: fullUrl,
data: method === 'GET' ? null : data,
hasToken: !!token,
retryCount,
timestamp: new Date().toISOString()
});
const res = await new Promise((resolve, reject) => {
uni.request({
url: fullUrl,
method,
data,
header: {
'Content-Type': 'application/json',
'Authorization': token ? `Bearer ${token}` : '',
...headers
},
timeout: TIMEOUT,
success: resolve,
fail: reject
});
});
// 响应日志
console.log('✅ API 请求成功:', {
method,
url: fullUrl,
statusCode: res.statusCode,
responseTime: new Date().toISOString(),
data: res.data
});
if (res.statusCode === 200) {
return res.data;
} else if (res.statusCode === 401) {
// 未授权清除token并重新登录使用登录锁防止并发
console.log('🔒 登录已过期,开始重新登录...');
uni.removeStorageSync('token');
// 重新登录后重试请求
if (retryCount < 3) {
if (loginLock) {
console.log('🔒 等待其他请求完成登录...');
await loginLock;
} else {
loginLock = doWechatLogin();
await loginLock;
loginLock = null;
}
console.log('🔒 重新登录成功,开始重试请求...');
return await requestWithRetry(url, method, data, headers, retryCount + 1);
} else {
console.error('❌ 达到最大重试次数');
uni.showToast({ title: '系统异常,请稍后重试', icon: 'none', duration: 2000 });
throw new Error('登录已过期,重试次数超限');
}
} else {
console.log('❌ API 请求失败:', {
statusCode: res.statusCode,
message: res.data?.message || `请求失败: ${res.statusCode}`
});
throw new Error(`请求失败: ${res.statusCode}`);
}
} catch (error) {
// 请求失败日志
console.log('❌ API 请求失败:', {
url,
error,
retryCount,
timestamp: new Date().toISOString()
});
// 如果是网络错误且未达到最大重试次数,尝试重试
if (retryCount < 3 && error.message && error.message.includes('网络请求失败')) {
console.log('🔄 网络错误,开始重试...');
return await requestWithRetry(url, method, data, headers, retryCount + 1);
}
// 达到最大重试次数,提示用户
if (retryCount >= 2) {
uni.showToast({ title: '系统异常,请稍后重试', icon: 'none', duration: 2000 });
}
throw error;
}
};
/**
* 基础请求方法
* @param {string} url - 请求URL
* @param {string} method - 请求方法
* @param {object} data - 请求数据
* @param {object} headers - 请求头
* @returns {Promise} - 返回Promise对象
*/
const request = (url, method = 'GET', data = {}, headers = {}) => {
return requestWithRetry(url, method, data, headers);
};
/**
* GET请求
* @param {string} url - 请求URL
* @param {object} params - 请求参数
* @param {object} headers - 请求头
* @returns {Promise} - 返回Promise对象
*/
export const get = (url, params = {}, headers = {}) => {
const queryString = Object.keys(params)
.map(key => `${key}=${encodeURIComponent(params[key])}`)
.join('&');
const fullUrl = queryString ? `${url}?${queryString}` : url;
return request(fullUrl, 'GET', {}, headers);
};
/**
* POST请求
* @param {string} url - 请求URL
* @param {object} data - 请求数据
* @param {object} headers - 请求头
* @returns {Promise} - 返回Promise对象
*/
export const post = (url, data = {}, headers = {}) => {
return request(url, 'POST', data, headers);
};
/**
* API接口封装
*/
console.log('📦 api.js 开始导出api对象')
export const api = {
assets: {
getAssetData: () => {
console.log('📤 发起 getAssetData 请求');
return get('/api/v1/portfolio/assets');
},
getHoldings: () => {
console.log('📤 发起 getHoldings 请求');
return get('/api/v1/portfolio');
}
},
strategies: {
getStrategies: () => {
console.log('📤 发起 getStrategies 请求');
return get('/api/v1/strategies');
},
createStrategy: (data) => {
console.log('📤 发起 createStrategy 请求:', data);
return post('/api/v1/strategies', data);
},
updateStrategy: (id, data) => {
console.log('📤 发起 updateStrategy 请求:', id, data);
return post(`/api/v1/strategies/${id}`, data);
},
deleteStrategy: (id) => {
console.log('📤 发起 deleteStrategy 请求:', id);
return post(`/api/v1/strategies/${id}/delete`, {});
}
},
user: {
getUserInfo: () => {
console.log('📤 发起 getUserInfo 请求');
return get('/api/user/info');
},
getUserStats: () => {
console.log('📤 发起 getUserStats 请求');
return get('/api/user/stats');
}
}
};
console.log('📦 api.js 导出默认api对象')
export default api;