fix:将侧边栏兼容移动端
This commit is contained in:
+142
-15
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import router from '@/router'
|
||||
import {getRefreshToken,refreshAccessToken} from "@/api/login.js";
|
||||
|
||||
// 基础URL
|
||||
const baseUrl = 'https://apiservertest.s1f.ren' // SSL证书有问题
|
||||
@@ -10,18 +11,100 @@ const baseUrl = 'https://apiservertest.s1f.ren' // SSL证书有问题
|
||||
// 检查URL是否需要认证
|
||||
const urlNeedAuth = (url) => {
|
||||
// 这里可以添加不需要认证的URL列表
|
||||
const noAuthUrls = ['/v1/user/login', '/v1/user/check/get_code_img', '/v1/user/register']
|
||||
const noAuthUrls = ['/v1/user/login', '/v1/user/check/get_code_img', '/v1/user/register', '/v1/user/refresh_token']
|
||||
return !noAuthUrls.some(noAuthUrl => url.includes(noAuthUrl))
|
||||
}
|
||||
|
||||
// 检查token是否过期
|
||||
const isTokenExpired = () => {
|
||||
const token = localStorage.getItem('token')
|
||||
const expire = localStorage.getItem('tokenExpire')
|
||||
if (!token) return true
|
||||
|
||||
// 这里可以添加token过期检查逻辑,如果有JWT可以解析它
|
||||
// 简单实现,仅检查token是否存在
|
||||
return false
|
||||
// 检查过期时间
|
||||
if (expire) {
|
||||
const expireTime = parseInt(expire) * 1000 // 转换为毫秒
|
||||
const now = Date.now()
|
||||
return now >= expireTime
|
||||
}
|
||||
|
||||
// 没有过期时间时,默认认为Token已过期(因为无法验证有效性)
|
||||
return true
|
||||
}
|
||||
|
||||
// 检查token是否即将过期(5分钟内)
|
||||
const isTokenExpiringSoon = () => {
|
||||
const expire = localStorage.getItem('tokenExpire')
|
||||
if (!expire) return false
|
||||
|
||||
const expireTime = parseInt(expire) * 1000 // 转换为毫秒
|
||||
const now = Date.now()
|
||||
const fiveMinutes = 5 * 60 * 1000 // 5分钟
|
||||
|
||||
// 如果已过期,返回false(由isTokenExpired处理)
|
||||
if (now >= expireTime) return false
|
||||
|
||||
// 如果在5分钟内过期,返回true
|
||||
return (expireTime - now) <= fiveMinutes
|
||||
}
|
||||
|
||||
// 正在刷新token的标志
|
||||
let isRefreshing = false
|
||||
// 等待刷新token的请求队列
|
||||
let refreshSubscribers = []
|
||||
|
||||
// 添加请求到队列
|
||||
const subscribeTokenRefresh = (callback) => {
|
||||
refreshSubscribers.push(callback)
|
||||
}
|
||||
|
||||
// 刷新token后执行队列中的请求
|
||||
const onTokenRefreshed = (newToken) => {
|
||||
refreshSubscribers.forEach(callback => callback(newToken))
|
||||
refreshSubscribers = []
|
||||
}
|
||||
|
||||
// 执行token刷新
|
||||
const doRefreshToken = async () => {
|
||||
try {
|
||||
const domain = window.location.hostname
|
||||
// 获取交换token
|
||||
const refreshTokenRes = await getRefreshToken(domain,{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem('token')}`
|
||||
}
|
||||
})
|
||||
|
||||
if (refreshTokenRes.data?.code === 200 && refreshTokenRes.data?.data?.refresh_token) {
|
||||
// 使用交换token获取新的access token
|
||||
const newTokenRes = await refreshAccessToken(refreshTokenRes.data.data.refresh_token)
|
||||
|
||||
if (newTokenRes.data?.code === 200 && newTokenRes.data?.data?.token) {
|
||||
const { token, expire } = newTokenRes.data.data
|
||||
localStorage.setItem('token', token)
|
||||
if (expire) {
|
||||
localStorage.setItem('tokenExpire', expire.toString())
|
||||
}
|
||||
return token
|
||||
}
|
||||
}
|
||||
// 刷新失败,触发登出逻辑
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('tokenExpire')
|
||||
localStorage.removeItem('userInfo')
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
router.push('/login')
|
||||
return null
|
||||
} catch (error) {
|
||||
console.error('Token刷新失败:', error)
|
||||
// 刷新失败,触发登出逻辑
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('tokenExpire')
|
||||
localStorage.removeItem('userInfo')
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
router.push('/login')
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class Request {
|
||||
@@ -122,19 +205,63 @@ export const http2 = axios.create({
|
||||
headers: {},
|
||||
});
|
||||
|
||||
http2.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('token'); // 假设 token 存储在 localStorage
|
||||
if(urlNeedAuth(config.url) && isTokenExpired()){
|
||||
if (token){
|
||||
localStorage.removeItem('token');
|
||||
ElMessage.warning('登陆过期,请重新登陆')
|
||||
http2.interceptors.request.use(async config => {
|
||||
const token = localStorage.getItem('token')
|
||||
|
||||
// 检查是否需要认证
|
||||
if (urlNeedAuth(config.url)) {
|
||||
// 检查token是否已过期
|
||||
if (isTokenExpired()) {
|
||||
if (token) {
|
||||
localStorage.removeItem('token')
|
||||
localStorage.removeItem('tokenExpire')
|
||||
localStorage.removeItem('userInfo')
|
||||
ElMessage.warning('登录过期,请重新登录')
|
||||
}
|
||||
router.push('/login')
|
||||
return Promise.reject(new Error('Token已过期'))
|
||||
}
|
||||
|
||||
// 检查token是否即将过期,进行无感刷新
|
||||
if (isTokenExpiringSoon() && !isRefreshing) {
|
||||
isRefreshing = true
|
||||
try {
|
||||
const newToken = await doRefreshToken()
|
||||
if (newToken) {
|
||||
console.log('Token已无感刷新')
|
||||
onTokenRefreshed(newToken)
|
||||
config.headers.Authorization = `Bearer ${newToken}`
|
||||
} else {
|
||||
// 刷新失败,doRefreshToken已处理登出逻辑,直接拒绝请求
|
||||
return Promise.reject(new Error('Token刷新失败'))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Token刷新异常:', error)
|
||||
// 刷新异常,doRefreshToken已处理登出逻辑,直接拒绝请求
|
||||
return Promise.reject(error)
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
}
|
||||
} else if (isRefreshing) {
|
||||
// 正在刷新,等待刷新完成
|
||||
return new Promise((resolve, reject) => {
|
||||
subscribeTokenRefresh((newToken) => {
|
||||
if (newToken) {
|
||||
config.headers.Authorization = `Bearer ${newToken}`
|
||||
// 重新发送原始请求
|
||||
resolve(config)
|
||||
} else {
|
||||
reject(new Error('Token刷新失败'))
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// 正常情况,直接使用token
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
router.push('/login')
|
||||
return Promise.reject();
|
||||
}
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
|
||||
config.url = config.url
|
||||
// 不需要认证的请求,不添加token
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
|
||||
+55
-3
@@ -18,7 +18,7 @@ export const formatDate = (dateStr) => {
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`
|
||||
}
|
||||
/**
|
||||
* 时间格式转 Unix 时间戳(毫秒级)
|
||||
* 时间格式转 Unix 时间戳(秒级)
|
||||
* @param {string|Date} time - 输入时间(支持 '2025-10-28 00:00:00'、'2025/10/28'、Date 对象等)
|
||||
* @returns {number|null} 转换后的毫秒级时间戳(失败返回 null)
|
||||
*/
|
||||
@@ -50,10 +50,62 @@ export function timeToTimestamp(time) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Math.floor(timestamp / 1000); // 返回毫秒级时间戳(如 1751107200000)
|
||||
return Math.floor(timestamp / 1000); // 返回秒级时间戳(如 1751107200000)
|
||||
}
|
||||
|
||||
|
||||
export function reducenum(num){
|
||||
return num / 100
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 ISO 格式时间字符串转换为毫秒级时间戳(用于时间选择器)
|
||||
* @param {string|Date|number} time - 输入时间(支持 ISO 格式字符串如 '2023-11-08T01:10:00+08:00'、Date 对象、时间戳等)
|
||||
* @returns {number|null} 转换后的毫秒级时间戳(失败或无效时间返回 null)
|
||||
*/
|
||||
export function isoToMilliseconds(time) {
|
||||
// 处理空值
|
||||
if (!time || time === null || time === undefined) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 处理特殊的无效时间标识
|
||||
if (typeof time === 'string' && (time === '0001-01-01T00:00:00Z' || time === '0001-01-01T00:00:00+00:00')) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 如果已经是数字(时间戳),直接返回
|
||||
if (typeof time === 'number') {
|
||||
// 如果是秒级时间戳(小于 13 位),转换为毫秒
|
||||
if (time < 1000000000000) {
|
||||
return time * 1000
|
||||
}
|
||||
return time
|
||||
}
|
||||
|
||||
// 处理 Date 对象
|
||||
if (time instanceof Date) {
|
||||
const timestamp = time.getTime()
|
||||
return isNaN(timestamp) ? null : timestamp
|
||||
}
|
||||
|
||||
// 处理字符串格式
|
||||
if (typeof time === 'string') {
|
||||
try {
|
||||
const date = new Date(time)
|
||||
const timestamp = date.getTime()
|
||||
|
||||
// 检查是否为有效时间
|
||||
if (isNaN(timestamp)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return timestamp
|
||||
} catch (error) {
|
||||
console.error('时间转换失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user