2026-01-04 11:09:06 +08:00
|
|
|
|
import define from './define'
|
2026-01-25 20:22:58 +08:00
|
|
|
|
import { useLocale } from '@/locale/useLocale';
|
2026-01-04 11:09:06 +08:00
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
const { getBackLocale } = useLocale();
|
2026-01-19 17:34:15 +08:00
|
|
|
|
let host = define.baseURL
|
2026-01-25 20:22:58 +08:00
|
|
|
|
const defaultOpt = { load: true }
|
2026-01-04 11:09:06 +08:00
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
// ------------- token刷新核心配置 -------------
|
|
|
|
|
|
const whiteList = ['/login', '/system/auth/refresh-token']
|
|
|
|
|
|
let requestQueue = []
|
|
|
|
|
|
let isRefreshingToken = false
|
|
|
|
|
|
const isRelogin = { show: false }
|
2026-01-04 11:09:06 +08:00
|
|
|
|
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 全局网络状态标记(防止多请求覆盖)
|
|
|
|
|
|
let GLOBAL_IS_NETWORK_ERROR = false;
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 核心:全局拦截登录跳转 ==========
|
|
|
|
|
|
// 拦截所有跳登录页的操作,仅允许非断网场景跳转
|
|
|
|
|
|
function interceptLoginJump() {
|
|
|
|
|
|
// 拦截 reLaunch(最常用的跳登录方式)
|
|
|
|
|
|
const originalReLaunch = uni.reLaunch;
|
|
|
|
|
|
uni.reLaunch = function(options) {
|
|
|
|
|
|
// 如果是跳登录页 + 当前是网络错误 → 阻止跳转
|
|
|
|
|
|
if (options.url && options.url.includes('/pages/login/index') && GLOBAL_IS_NETWORK_ERROR) {
|
|
|
|
|
|
console.log('【拦截】断网时禁止跳登录页');
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '网络已断开,请先连接网络',
|
|
|
|
|
|
icon: 'none',
|
|
|
|
|
|
duration: 3000
|
|
|
|
|
|
});
|
|
|
|
|
|
return; // 终止跳转
|
|
|
|
|
|
}
|
|
|
|
|
|
// 非登录页/非断网场景 → 正常跳转
|
|
|
|
|
|
originalReLaunch.call(uni, options);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 拦截其他跳转方式(兜底)
|
|
|
|
|
|
const interceptors = ['navigateTo', 'redirectTo', 'switchTab'];
|
|
|
|
|
|
interceptors.forEach(method => {
|
|
|
|
|
|
const originalMethod = uni[method];
|
|
|
|
|
|
uni[method] = function(options) {
|
|
|
|
|
|
if (options.url && options.url.includes('/pages/login/index') && GLOBAL_IS_NETWORK_ERROR) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
originalMethod.call(uni, options);
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化拦截器(页面加载时执行一次)
|
|
|
|
|
|
interceptLoginJump();
|
|
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
// ------------- 核心request方法 -------------
|
2026-01-04 11:09:06 +08:00
|
|
|
|
function request(config) {
|
2026-01-25 20:22:58 +08:00
|
|
|
|
config.options = Object.assign(defaultOpt, config.options)
|
|
|
|
|
|
const token = uni.getStorageSync('token') || ''
|
|
|
|
|
|
const refreshToken = uni.getStorageSync('refreshToken') || ''
|
|
|
|
|
|
const tenantId = '1' || uni.getStorageSync('tenantId')
|
|
|
|
|
|
const systemCode = uni.getStorageSync('systemCode') || ''
|
|
|
|
|
|
const locale = getBackLocale()
|
|
|
|
|
|
|
|
|
|
|
|
// 构建请求头
|
|
|
|
|
|
let header = {
|
|
|
|
|
|
"accept": 'application/json, text/plain, */*',
|
|
|
|
|
|
"App-Code": systemCode,
|
|
|
|
|
|
"Content-Type": "application/json;charset=UTF-8",
|
|
|
|
|
|
"Jnpf-Origin": "app",
|
|
|
|
|
|
"Vue-Version": "3",
|
|
|
|
|
|
"Accept-Language": locale,
|
|
|
|
|
|
"tenant-id": tenantId,
|
|
|
|
|
|
...config.header
|
|
|
|
|
|
}
|
|
|
|
|
|
header['App-Code'] = encodeURIComponent(header['App-Code'])
|
|
|
|
|
|
if (token) header['Authorization'] = token
|
|
|
|
|
|
// let url = config.url.indexOf('http') > -1 ? config.url : host + config.url
|
|
|
|
|
|
let url = host + config.url
|
|
|
|
|
|
console.log(url,'url---')
|
2026-01-30 11:48:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 显示加载中
|
2026-01-25 20:22:58 +08:00
|
|
|
|
if (config.options.load) {
|
|
|
|
|
|
uni.showLoading({ title: config.options.loadText || '正在加载' })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 返回Promise
|
2026-01-25 20:22:58 +08:00
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
// 封装核心请求逻辑
|
|
|
|
|
|
const coreRequest = () => {
|
|
|
|
|
|
uni.request({
|
|
|
|
|
|
url: url,
|
|
|
|
|
|
data: config.data || {},
|
|
|
|
|
|
method: config.method || 'GET',
|
|
|
|
|
|
header: header,
|
|
|
|
|
|
timeout: define.timeout,
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
uni.hideLoading();
|
2026-01-30 17:06:39 +08:00
|
|
|
|
GLOBAL_IS_NETWORK_ERROR = false; // 有响应 → 网络正常
|
|
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
if (res.statusCode === 200) {
|
|
|
|
|
|
if (res.data.code == 200 || res.data.code == 0) {
|
|
|
|
|
|
resolve(res.data)
|
|
|
|
|
|
} else if ([401, 600, 601, 602].includes(res.data.code)) {
|
|
|
|
|
|
// 白名单接口不处理
|
|
|
|
|
|
const isWhiteList = whiteList.some(v => config.url.includes(v))
|
|
|
|
|
|
if (isWhiteList) {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
uni.showToast({ title: res.data.msg || '认证失败', icon: 'none' });
|
|
|
|
|
|
reject(res.data.msg);
|
|
|
|
|
|
return;
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 无刷新token → 提示手动登录(不自动跳转)
|
2026-01-25 20:22:58 +08:00
|
|
|
|
if (!refreshToken) {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '登录过期',
|
|
|
|
|
|
content: '您的登录已过期,请重新登录',
|
|
|
|
|
|
showCancelButton: false,
|
|
|
|
|
|
confirmText: '去登录'
|
|
|
|
|
|
}).then(res => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
clearAuthStorage();
|
|
|
|
|
|
uni.reLaunch({ url: '/pages/login/index' }); // 这里会走拦截器,仅网络正常时跳转
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
reject('登录过期,无刷新Token');
|
|
|
|
|
|
return;
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
2026-01-04 11:09:06 +08:00
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
if (isRefreshingToken) {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
requestQueue.push(() => coreRequest());
|
|
|
|
|
|
return;
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
2026-01-04 11:09:06 +08:00
|
|
|
|
|
2026-01-30 17:06:39 +08:00
|
|
|
|
isRefreshingToken = true;
|
2026-01-25 20:22:58 +08:00
|
|
|
|
try {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 刷新token接口
|
|
|
|
|
|
const refreshUrl = `${host}/admin-api/system/auth/refresh-token?refreshToken=${encodeURIComponent(refreshToken)}`;
|
2026-01-25 20:22:58 +08:00
|
|
|
|
const refreshRes = await uni.request({
|
2026-01-30 11:48:35 +08:00
|
|
|
|
url: refreshUrl,
|
|
|
|
|
|
method: 'POST',
|
2026-01-25 20:22:58 +08:00
|
|
|
|
header: {
|
2026-01-30 11:48:35 +08:00
|
|
|
|
'tenant-id': tenantId,
|
2026-01-25 20:22:58 +08:00
|
|
|
|
'Content-Type': 'application/json'
|
|
|
|
|
|
},
|
2026-01-30 11:48:35 +08:00
|
|
|
|
data: {}
|
2026-01-30 17:06:39 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-30 11:48:35 +08:00
|
|
|
|
if (refreshRes.data && (refreshRes.data.code == 0 || refreshRes.data.code == 200)) {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 刷新成功
|
|
|
|
|
|
const newTokenData = refreshRes.data.data;
|
|
|
|
|
|
uni.setStorageSync('token', newTokenData.accessToken);
|
|
|
|
|
|
uni.setStorageSync('refreshToken', newTokenData.refreshToken);
|
|
|
|
|
|
header['Authorization'] = newTokenData.accessToken;
|
|
|
|
|
|
coreRequest();
|
|
|
|
|
|
requestQueue.forEach(cb => cb());
|
|
|
|
|
|
requestQueue = [];
|
2026-01-25 20:22:58 +08:00
|
|
|
|
} else {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 刷新失败 → 提示手动登录
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '登录过期',
|
|
|
|
|
|
content: '刷新登录状态失败,请重新登录',
|
|
|
|
|
|
showCancelButton: false,
|
|
|
|
|
|
confirmText: '去登录'
|
|
|
|
|
|
}).then(res => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
clearAuthStorage();
|
|
|
|
|
|
uni.reLaunch({ url: '/pages/login/index' });
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
reject('刷新Token失败:' + (refreshRes.data?.msg || '接口返回异常'));
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (err) {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 刷新token异常 → 判定为网络错误
|
|
|
|
|
|
GLOBAL_IS_NETWORK_ERROR = true;
|
|
|
|
|
|
uni.showToast({ title: '网络异常,无法刷新登录状态', icon: 'none', duration: 3000 });
|
|
|
|
|
|
reject('网络异常:' + (err.errMsg || err.message));
|
2026-01-25 20:22:58 +08:00
|
|
|
|
} finally {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
isRefreshingToken = false;
|
|
|
|
|
|
requestQueue = [];
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// 普通业务错误
|
|
|
|
|
|
uni.showToast({ title: res.data.msg || '请求出错,请重试', icon: 'none' });
|
|
|
|
|
|
reject(res.data.msg);
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2026-01-30 17:06:39 +08:00
|
|
|
|
// HTTP状态码错误
|
|
|
|
|
|
uni.showToast({ title: `请求失败[${res.statusCode}]`, icon: 'none' });
|
|
|
|
|
|
reject(res.errMsg);
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
|
uni.hideLoading();
|
2026-01-30 17:06:39 +08:00
|
|
|
|
GLOBAL_IS_NETWORK_ERROR = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置刷新状态,防止死锁
|
|
|
|
|
|
isRefreshingToken = false;
|
|
|
|
|
|
requestQueue = [];
|
|
|
|
|
|
|
|
|
|
|
|
// 仅提示网络错误,不跳转
|
|
|
|
|
|
uni.showToast({ title: '网络连接失败,请检查网络', icon: 'none', duration: 3000 });
|
|
|
|
|
|
reject({ isNetworkError: true, errMsg: err.errMsg });
|
2026-01-25 20:22:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
coreRequest()
|
|
|
|
|
|
})
|
2026-01-04 11:09:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 20:22:58 +08:00
|
|
|
|
// ------------- 辅助函数 -------------
|
2026-01-30 11:48:35 +08:00
|
|
|
|
/**
|
2026-01-30 17:06:39 +08:00
|
|
|
|
* 清除登录缓存
|
2026-01-30 11:48:35 +08:00
|
|
|
|
*/
|
2026-01-30 17:06:39 +08:00
|
|
|
|
function clearAuthStorage() {
|
|
|
|
|
|
uni.removeStorageSync('token');
|
|
|
|
|
|
uni.removeStorageSync('refreshToken');
|
|
|
|
|
|
uni.removeStorageSync('cid');
|
|
|
|
|
|
uni.removeStorageSync('userInfo');
|
|
|
|
|
|
uni.removeStorageSync('permissionList');
|
|
|
|
|
|
uni.removeStorageSync('sysVersion');
|
|
|
|
|
|
uni.removeStorageSync('dynamicModelExtra');
|
2026-01-04 11:09:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 17:06:39 +08:00
|
|
|
|
export default request;
|