提交新的移动端框架
This commit is contained in:
1 parent
134f711349
commit
9bda3717fe
75 files changed
+5283
-9011
No files matched your search
@@ -0,0 +1,394 @@
|
||||
// 移动端统一请求工具 - 与mobile工程保持一致
|
||||
import {
|
||||
generateAesKey,
|
||||
encryptBase64,
|
||||
decryptBase64,
|
||||
encryptWithAes,
|
||||
decryptWithAes,
|
||||
encrypt,
|
||||
decrypt,
|
||||
} from './crypto.js';
|
||||
import { ENCRYPT_CONFIG, REQUEST_CONFIG } from './config.js';
|
||||
import { sessionCache, userStorage } from './storage.js';
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
*/
|
||||
function getToken() {
|
||||
try {
|
||||
const token = uni.getStorageSync('access_token');
|
||||
console.log(
|
||||
'🔍 获取Token:',
|
||||
token ? `Bearer ${token.substring(0, 20)}...` : '❌ Token为空',
|
||||
);
|
||||
return token ? `Bearer ${token}` : '';
|
||||
} catch (e) {
|
||||
console.error('❌ 获取Token失败:', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理401未授权响应
|
||||
*/
|
||||
function handleUnauthorized(message = '登录已失效,请重新登录') {
|
||||
console.log('🔒 处理401未授权响应:', message);
|
||||
|
||||
// 清除登录信息
|
||||
try {
|
||||
uni.removeStorageSync('access_token');
|
||||
uni.removeStorageSync('userInfo');
|
||||
uni.removeStorageSync('isLoggedIn');
|
||||
console.log('📤 已清除本地登录信息');
|
||||
} catch (e) {
|
||||
console.error('❌ 清除登录信息失败:', e);
|
||||
}
|
||||
|
||||
// 显示提示信息
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// 延迟跳转,确保Toast显示
|
||||
setTimeout(() => {
|
||||
// 获取当前页面路径
|
||||
const pages = getCurrentPages();
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const currentPath = '/' + currentPage.route;
|
||||
|
||||
// 如果当前不是登录页,则跳转到登录页
|
||||
if (currentPath !== '/pages/login/index') {
|
||||
console.log('🔄 从', currentPath, '跳转到登录页');
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/index',
|
||||
fail: (error) => {
|
||||
console.error('❌ 跳转登录页失败:', error);
|
||||
// 如果reLaunch失败,尝试其他方式
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index',
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一请求方法
|
||||
*/
|
||||
export const request = (options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 获取token
|
||||
const token = getToken();
|
||||
|
||||
// 处理请求配置
|
||||
const config = {
|
||||
url: REQUEST_CONFIG.baseURL + options.url,
|
||||
method: options.method || 'GET',
|
||||
data: options.data || {},
|
||||
timeout: options.timeout || REQUEST_CONFIG.timeout,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
authorization: token,
|
||||
clientid: options.clientId || REQUEST_CONFIG.clientId,
|
||||
// 注意:在H5环境中,浏览器会自动设置referer,手动设置会报错
|
||||
// referer: options.referer || REQUEST_CONFIG.referer,
|
||||
...options.header,
|
||||
},
|
||||
};
|
||||
|
||||
// 检查特殊header配置
|
||||
const isToken = options.header?.isToken === false;
|
||||
const isRepeatSubmit = options.header?.repeatSubmit === false;
|
||||
const isEncrypt = options.header?.isEncrypt === 'true';
|
||||
|
||||
// 如果不需要token,移除authorization
|
||||
if (isToken) {
|
||||
delete config.header.authorization;
|
||||
}
|
||||
|
||||
// 防重复提交检查
|
||||
if (!isRepeatSubmit && (config.method === 'POST' || config.method === 'PUT')) {
|
||||
const requestObj = {
|
||||
url: config.url,
|
||||
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
|
||||
time: new Date().getTime(),
|
||||
};
|
||||
|
||||
const sessionObj = sessionCache.get('sessionObj');
|
||||
if (sessionObj) {
|
||||
const s_url = sessionObj.url;
|
||||
const s_data = sessionObj.data;
|
||||
const s_time = sessionObj.time;
|
||||
const interval = REQUEST_CONFIG.repeatSubmitInterval;
|
||||
|
||||
if (
|
||||
s_data === requestObj.data &&
|
||||
requestObj.time - s_time < interval &&
|
||||
s_url === requestObj.url
|
||||
) {
|
||||
const message = '数据正在处理,请勿重复提交';
|
||||
console.warn(`[${s_url}]: ` + message);
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none',
|
||||
});
|
||||
return reject(new Error(message));
|
||||
}
|
||||
}
|
||||
sessionCache.set('sessionObj', requestObj);
|
||||
}
|
||||
|
||||
// 加密处理
|
||||
if (
|
||||
REQUEST_CONFIG.encryptEnabled &&
|
||||
isEncrypt &&
|
||||
(config.method === 'POST' || config.method === 'PUT')
|
||||
) {
|
||||
try {
|
||||
console.log('🔐 开始请求加密处理...');
|
||||
|
||||
// 生成AES密钥
|
||||
const aesKey = generateAesKey();
|
||||
|
||||
// 使用RSA加密AES密钥
|
||||
const encryptedKey = encrypt(encryptBase64(aesKey));
|
||||
if (!encryptedKey) {
|
||||
throw new Error('RSA加密AES密钥失败');
|
||||
}
|
||||
|
||||
// 设置加密头
|
||||
config.header[ENCRYPT_CONFIG.ENCRYPT_HEADER] = encryptedKey;
|
||||
|
||||
// 加密请求数据
|
||||
const dataToEncrypt =
|
||||
typeof config.data === 'object' ? JSON.stringify(config.data) : config.data;
|
||||
config.data = encryptWithAes(dataToEncrypt, aesKey);
|
||||
|
||||
console.log('✅ 请求数据加密完成');
|
||||
} catch (error) {
|
||||
console.error('❌ 请求加密失败:', error);
|
||||
uni.showToast({
|
||||
title: '请求加密失败',
|
||||
icon: 'none',
|
||||
});
|
||||
return reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// FormData处理
|
||||
if (config.data instanceof globalThis.FormData) {
|
||||
delete config.header['Content-Type'];
|
||||
}
|
||||
|
||||
console.log('📤 发送请求:', {
|
||||
url: config.url,
|
||||
method: config.method,
|
||||
hasToken: !!token,
|
||||
isEncrypt: isEncrypt,
|
||||
});
|
||||
|
||||
// 发送请求
|
||||
uni.request({
|
||||
...config,
|
||||
success: (res) => {
|
||||
console.log('📥 收到响应:', {
|
||||
statusCode: res.statusCode,
|
||||
url: config.url,
|
||||
hasEncryptHeader: !!res.header[ENCRYPT_CONFIG.ENCRYPT_HEADER],
|
||||
});
|
||||
|
||||
// 解密处理
|
||||
if (REQUEST_CONFIG.encryptEnabled && res.header[ENCRYPT_CONFIG.ENCRYPT_HEADER]) {
|
||||
try {
|
||||
console.log('🔓 开始响应解密处理...');
|
||||
|
||||
// 获取加密的AES密钥
|
||||
const keyStr = res.header[ENCRYPT_CONFIG.ENCRYPT_HEADER];
|
||||
|
||||
// RSA解密获取AES密钥
|
||||
const base64Str = decrypt(keyStr);
|
||||
if (!base64Str) {
|
||||
throw new Error('RSA解密AES密钥失败');
|
||||
}
|
||||
|
||||
// Base64解码获取AES密钥
|
||||
const aesKey = decryptBase64(base64Str);
|
||||
|
||||
// AES解密响应数据
|
||||
const decryptedData = decryptWithAes(res.data, aesKey);
|
||||
|
||||
// 解析JSON
|
||||
res.data = JSON.parse(decryptedData);
|
||||
|
||||
console.log('✅ 响应数据解密完成');
|
||||
} catch (error) {
|
||||
console.error('❌ 响应解密失败:', error);
|
||||
uni.showToast({
|
||||
title: '响应解密失败',
|
||||
icon: 'none',
|
||||
});
|
||||
return reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理响应
|
||||
if (res.statusCode === 200) {
|
||||
// 检查业务状态码
|
||||
if (res.data && res.data.code !== undefined) {
|
||||
if (res.data.code === 200) {
|
||||
resolve(res.data);
|
||||
} else if (res.data.code === 401) {
|
||||
// 401未授权,跳转到登录页
|
||||
console.log('🔒 Token失效,自动跳转到登录页');
|
||||
handleUnauthorized(res.data.msg || '登录已失效,请重新登录');
|
||||
reject(res.data);
|
||||
} else {
|
||||
// 其他业务错误
|
||||
const errorMsg = res.data.msg || '请求失败';
|
||||
if (res.data.code !== 404) {
|
||||
// 404错误静默处理
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none',
|
||||
});
|
||||
}
|
||||
reject(res.data);
|
||||
}
|
||||
} else {
|
||||
resolve(res.data);
|
||||
}
|
||||
} else if (res.statusCode === 401) {
|
||||
// HTTP 401未授权
|
||||
console.log('🔒 HTTP 401未授权,自动跳转到登录页');
|
||||
handleUnauthorized('登录已失效,请重新登录');
|
||||
reject(res);
|
||||
} else if (res.statusCode === 404) {
|
||||
// 404错误静默处理
|
||||
console.log('404错误被静默处理,不显示用户提示');
|
||||
reject(res);
|
||||
} else {
|
||||
// 其他HTTP状态码错误
|
||||
const errorMsg = `请求失败: ${res.statusCode}`;
|
||||
uni.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none',
|
||||
});
|
||||
reject(res);
|
||||
}
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('❌ 网络请求失败:', error);
|
||||
let message = '网络请求失败';
|
||||
|
||||
if (error.errMsg) {
|
||||
if (error.errMsg.includes('timeout')) {
|
||||
message = '请求超时,请检查网络连接';
|
||||
} else if (error.errMsg.includes('fail')) {
|
||||
message = '网络连接失败,请检查网络';
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: message,
|
||||
icon: 'none',
|
||||
});
|
||||
reject(error);
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// API方法封装
|
||||
export const api = {
|
||||
// 用户登录 - 使用统一的request方法和加密拦截器
|
||||
login: (data) => {
|
||||
console.log('🔐 开始登录流程...');
|
||||
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
method: 'POST',
|
||||
data: {
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
tenantId: data.tenantId || '000000',
|
||||
clientId: data.clientId || REQUEST_CONFIG.clientId,
|
||||
grantType: data.grantType || 'password',
|
||||
},
|
||||
header: {
|
||||
isToken: false, // 登录接口不需要token
|
||||
isEncrypt: 'true', // 启用加密
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
getUserInfo: () => {
|
||||
const token = getToken();
|
||||
console.log(
|
||||
'🎫 获取用户信息,当前token:',
|
||||
token ? token.substring(0, 20) + '...' : '无token',
|
||||
);
|
||||
|
||||
return request({
|
||||
url: '/system/user/getInfo',
|
||||
method: 'GET',
|
||||
});
|
||||
},
|
||||
|
||||
// 获取租户列表
|
||||
getTenantList: (isToken = false) =>
|
||||
request({
|
||||
url: '/auth/tenant/list',
|
||||
method: 'GET',
|
||||
header: {
|
||||
isToken: isToken,
|
||||
},
|
||||
}),
|
||||
|
||||
// 注销登录
|
||||
logout: () =>
|
||||
request({
|
||||
url: '/auth/logout',
|
||||
method: 'POST',
|
||||
}),
|
||||
};
|
||||
|
||||
// 通用下载方法
|
||||
export const download = (url, params, fileName) => {
|
||||
// 显示加载提示
|
||||
uni.showLoading({
|
||||
title: '正在下载数据,请稍候',
|
||||
mask: true,
|
||||
});
|
||||
|
||||
return request({
|
||||
url: url,
|
||||
method: 'POST',
|
||||
data: params,
|
||||
header: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
timeout: 1200000, // 20分钟超时
|
||||
responseType: 'arraybuffer',
|
||||
})
|
||||
.then((resp) => {
|
||||
// 处理下载响应
|
||||
// 注意:uni-app中文件下载需要特殊处理
|
||||
console.log('文件下载完成:', fileName);
|
||||
uni.hideLoading();
|
||||
|
||||
// 这里需要根据平台进行不同的文件保存处理
|
||||
// 具体实现可能需要平台特定的代码
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('下载失败:', error);
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '下载文件出现错误,请联系管理员!',
|
||||
icon: 'none',
|
||||
});
|
||||
});
|
||||
};
|
||||
Reference in new issue
Block a user