任务模块
This commit is contained in:
parent
ceef525878
commit
d01304460e
@ -12,6 +12,7 @@ export function setupRequestInterceptors(instance) {
|
|||||||
// 返回修改后的请求配置,继续发送请求
|
// 返回修改后的请求配置,继续发送请求
|
||||||
return config
|
return config
|
||||||
}, error => {
|
}, error => {
|
||||||
|
console.log("请求错误",error)
|
||||||
// 将错误以 Promise reject 的方式抛出,供调用方捕获处理
|
// 将错误以 Promise reject 的方式抛出,供调用方捕获处理
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
//响应拦截器
|
//响应拦截器
|
||||||
import axios from 'axios'; // 引入axios用于创建新请求
|
import axios from 'axios'; // 引入axios用于创建新请求
|
||||||
import { ElMessage } from 'element-plus'; // 引入Element Plus的消息组件
|
import { ElMessage, ElMessageBox } from 'element-plus'; // 引入Element Plus的消息组件
|
||||||
import store from '../../store'; // 引入store用于统一处理登出
|
import store from '../../store'; // 引入store用于统一处理登出
|
||||||
|
import axiosInstance from '../../utils/axios'; // 引入已配置的axios实例
|
||||||
|
|
||||||
export function setupResponseInterceptors(instance) {
|
export function setupResponseInterceptors(instance) {
|
||||||
// 用于存储正在刷新token的Promise
|
// 用于存储正在刷新token的Promise
|
||||||
@ -11,16 +12,25 @@ export function setupResponseInterceptors(instance) {
|
|||||||
|
|
||||||
// 统一处理登录过期的函数
|
// 统一处理登录过期的函数
|
||||||
const handleTokenExpired = (message = '登录已过期,请重新登录') => {
|
const handleTokenExpired = (message = '登录已过期,请重新登录') => {
|
||||||
// 显示提示消息
|
// 显示确认对话框
|
||||||
ElMessage.error(message);
|
ElMessageBox.confirm(
|
||||||
|
message,
|
||||||
// 使用store的logout action清除认证状态
|
'提示',
|
||||||
store.dispatch('logout');
|
{
|
||||||
|
confirmButtonText: '重新登录',
|
||||||
// 延迟跳转,让用户有时间看到提示
|
type: 'warning',
|
||||||
setTimeout(() => {
|
showCancelButton: false,
|
||||||
|
center: true
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 用户点击确认按钮后执行
|
||||||
|
// 使用store的logout action清除认证状态
|
||||||
|
store.dispatch('logout');
|
||||||
|
// 跳转到登录页
|
||||||
window.location.href = '/login';
|
window.location.href = '/login';
|
||||||
}, 1500);
|
}).catch(() => {
|
||||||
|
// 用户关闭对话框,不做任何操作
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
@ -36,8 +46,6 @@ export function setupResponseInterceptors(instance) {
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
async error => {
|
async error => {
|
||||||
console.log('响应错误:', error);
|
|
||||||
|
|
||||||
// 获取原始请求配置
|
// 获取原始请求配置
|
||||||
const originalRequest = error.config;
|
const originalRequest = error.config;
|
||||||
|
|
||||||
@ -51,10 +59,10 @@ export function setupResponseInterceptors(instance) {
|
|||||||
const errorResponse = error.response;
|
const errorResponse = error.response;
|
||||||
console.log('错误响应:', errorResponse);
|
console.log('错误响应:', errorResponse);
|
||||||
const errorData = errorResponse.data || {};
|
const errorData = errorResponse.data || {};
|
||||||
const errorMessage = errorData.message || errorData.error || errorResponse.statusText || '';
|
const errorMessage = errorData.status || errorData.message || errorData.error || errorResponse.statusText || '';
|
||||||
const errorStack = errorData.stack || '';
|
const errorStack = errorData.stack || '';
|
||||||
const statusCode = errorResponse.status;
|
const statusCode = errorResponse.status;
|
||||||
|
console.log('错误响应:', statusCode);
|
||||||
// 处理403错误(权限不足)
|
// 处理403错误(权限不足)
|
||||||
if (errorResponse.status === "403") {
|
if (errorResponse.status === "403") {
|
||||||
// 显示权限不足提示,但不重定向
|
// 显示权限不足提示,但不重定向
|
||||||
@ -63,21 +71,12 @@ export function setupResponseInterceptors(instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否为令牌错误(检查多种可能的错误信息格式)
|
// 检查是否为令牌错误(检查多种可能的错误信息格式)
|
||||||
const isTokenError =
|
const isTokenError = statusCode === 500
|
||||||
statusCode === 401 ||
|
|
||||||
(statusCode === 500 && (
|
|
||||||
errorMessage.includes('令牌') ||
|
|
||||||
errorMessage.includes('token') ||
|
|
||||||
errorMessage.includes('Token') ||
|
|
||||||
errorStack.includes('TokenIllegal') ||
|
|
||||||
errorStack.includes('TheTokenIllegalException') ||
|
|
||||||
(typeof errorData === 'string' && errorData.includes('令牌'))
|
|
||||||
));
|
|
||||||
|
|
||||||
// 如果是令牌错误,尝试刷新令牌或直接跳转登录页
|
// 如果是令牌错误,尝试刷新令牌或直接跳转登录页
|
||||||
if (isTokenError) {
|
if (isTokenError) {
|
||||||
// 如果是401错误且没有在刷新中,尝试刷新令牌
|
// 如果是401错误且没有在刷新中,尝试刷新令牌
|
||||||
if (statusCode === 401 && !originalRequest._retry) {
|
if (statusCode === 401 || statusCode === 500 || statusCode === 403 && !originalRequest._retry ) {
|
||||||
// 标记该请求已尝试过重试
|
// 标记该请求已尝试过重试
|
||||||
originalRequest._retry = true;
|
originalRequest._retry = true;
|
||||||
|
|
||||||
@ -88,7 +87,6 @@ export function setupResponseInterceptors(instance) {
|
|||||||
try {
|
try {
|
||||||
// 从localStorage获取refreshToken
|
// 从localStorage获取refreshToken
|
||||||
const refreshToken = localStorage.getItem('refreshToken');
|
const refreshToken = localStorage.getItem('refreshToken');
|
||||||
|
|
||||||
if (!refreshToken) {
|
if (!refreshToken) {
|
||||||
// 无refreshToken,跳转到登录页
|
// 无refreshToken,跳转到登录页
|
||||||
handleTokenExpired();
|
handleTokenExpired();
|
||||||
@ -99,20 +97,26 @@ export function setupResponseInterceptors(instance) {
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('refreshToken', refreshToken);
|
formData.append('refreshToken', refreshToken);
|
||||||
|
|
||||||
// 调用刷新token接口
|
// 调用刷新token接口,使用配置好的axios实例
|
||||||
const response = await axios.post('/admin/getAccessToken', formData);
|
const response = await axiosInstance.post('/admin/getAccessToken', formData);
|
||||||
|
|
||||||
// 获取新的token
|
// 根据实际返回的数据结构获取token
|
||||||
const { accessToken, refreshToken: newRefreshToken } = response.data.data;
|
const responseData = response.data;
|
||||||
|
const accessToken = responseData.accessToken;
|
||||||
|
const newRefreshToken = responseData.refreshToken;
|
||||||
|
|
||||||
// 更新本地存储
|
// 更新本地存储
|
||||||
localStorage.setItem('accessToken', accessToken);
|
localStorage.setItem('accessToken', accessToken);
|
||||||
if (newRefreshToken) {
|
localStorage.setItem('refreshToken', newRefreshToken);
|
||||||
localStorage.setItem('refreshToken', newRefreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新当前请求的Authorization头
|
// 更新当前请求的Authorization头
|
||||||
originalRequest.headers.Authorization = accessToken;
|
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
|
||||||
|
|
||||||
|
// 更新全局axios和axiosInstance的默认Authorization头,确保后续所有请求都带上新token
|
||||||
|
axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
|
||||||
|
axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
|
||||||
|
|
||||||
|
console.log('新token设置成功:', accessToken);
|
||||||
|
|
||||||
// 执行队列中的所有请求
|
// 执行队列中的所有请求
|
||||||
requests.forEach(cb => cb(accessToken));
|
requests.forEach(cb => cb(accessToken));
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { createStore } from 'vuex'
|
import { createStore } from 'vuex'
|
||||||
import { adminApi } from '../api/index.js'
|
import { adminApi } from '../api/index.js'
|
||||||
|
import webSocketService from '../utils/webSocket.js'
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
state: {
|
state: {
|
||||||
@ -31,6 +32,9 @@ export default createStore({
|
|||||||
localStorage.removeItem('refreshToken')
|
localStorage.removeItem('refreshToken')
|
||||||
// 清除本地缓存
|
// 清除本地缓存
|
||||||
localStorage.removeItem('userInfo')
|
localStorage.removeItem('userInfo')
|
||||||
|
|
||||||
|
// 断开WebSocket连接
|
||||||
|
webSocketService.disconnect()
|
||||||
},
|
},
|
||||||
SET_USER_INFO(state, userInfo) {
|
SET_USER_INFO(state, userInfo) {
|
||||||
// 初始化 用户信息
|
// 初始化 用户信息
|
||||||
@ -44,7 +48,7 @@ export default createStore({
|
|||||||
try {
|
try {
|
||||||
// 调用登录接口
|
// 调用登录接口
|
||||||
const response = await adminApi.login(data)
|
const response = await adminApi.login(data)
|
||||||
|
console.log("响应",response)
|
||||||
// 检查响应状态
|
// 检查响应状态
|
||||||
if (response.code !== 200) {
|
if (response.code !== 200) {
|
||||||
throw new Error(response.message || '登录失败')
|
throw new Error(response.message || '登录失败')
|
||||||
@ -53,6 +57,17 @@ export default createStore({
|
|||||||
// 设置 状态
|
// 设置 状态
|
||||||
commit('SET_TOKEN', response.data)
|
commit('SET_TOKEN', response.data)
|
||||||
|
|
||||||
|
// 添加更多日志,确保token存在
|
||||||
|
console.log("登录成功,准备连接WebSocket")
|
||||||
|
console.log("accessToken值:", response.data.accessToken)
|
||||||
|
|
||||||
|
// 登录成功后连接WebSocket
|
||||||
|
if (response.data.accessToken) {
|
||||||
|
webSocketService.connect(response.data.accessToken)
|
||||||
|
} else {
|
||||||
|
console.error("无法连接WebSocket: accessToken不存在")
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用查询接口获取用户信息
|
// 调用查询接口获取用户信息
|
||||||
const admin = await adminApi.getAdmin()
|
const admin = await adminApi.getAdmin()
|
||||||
|
|||||||
181
src/utils/webSocket.js
Normal file
181
src/utils/webSocket.js
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* WebSocket连接工具类
|
||||||
|
*/
|
||||||
|
|
||||||
|
// WebSocket URL
|
||||||
|
const WS_URL = 'ws://146.56.192.164:9090/ws';
|
||||||
|
|
||||||
|
class WebSocketService {
|
||||||
|
constructor() {
|
||||||
|
this.socket = null;
|
||||||
|
this.isConnected = false;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.maxReconnectAttempts = 5;
|
||||||
|
this.reconnectInterval = 3000; // 3秒
|
||||||
|
this.listeners = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化WebSocket连接
|
||||||
|
*/
|
||||||
|
connect() {
|
||||||
|
if (this.socket && (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING)) {
|
||||||
|
console.log('WebSocket已连接或正在连接中');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取存储在localStorage中的token
|
||||||
|
const token = localStorage.getItem('accessToken');
|
||||||
|
if (!token) {
|
||||||
|
console.error('WebSocket连接失败: 未找到accessToken');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建WebSocket连接,通过传递header中的token
|
||||||
|
this.socket = new WebSocket(WS_URL+'?token='+token);
|
||||||
|
|
||||||
|
// 由于浏览器WebSocket API不允许直接设置headers,我们需要在连接建立后的第一条消息中发送token
|
||||||
|
this.socket.onopen = () => {
|
||||||
|
console.log('WebSocket连接已建立');
|
||||||
|
this.isConnected = true;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
|
||||||
|
// 连接后立即发送认证信息
|
||||||
|
this.sendMessage({
|
||||||
|
type: 'auth',
|
||||||
|
token: token
|
||||||
|
});
|
||||||
|
|
||||||
|
// 触发已注册的连接事件监听器
|
||||||
|
this.triggerEvent('connect');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('收到WebSocket消息:', data);
|
||||||
|
this.triggerEvent('message', data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析WebSocket消息失败:', error);
|
||||||
|
this.triggerEvent('error', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onclose = (event) => {
|
||||||
|
console.log('WebSocket连接已关闭:', event);
|
||||||
|
this.isConnected = false;
|
||||||
|
this.triggerEvent('disconnect');
|
||||||
|
|
||||||
|
// 尝试重连
|
||||||
|
this.attemptReconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.socket.onerror = (error) => {
|
||||||
|
console.error('WebSocket错误:', error);
|
||||||
|
this.triggerEvent('error', error);
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化WebSocket失败:', error);
|
||||||
|
this.triggerEvent('error', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试重新连接
|
||||||
|
*/
|
||||||
|
attemptReconnect() {
|
||||||
|
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
||||||
|
console.log('达到最大重连次数');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
console.log(`尝试第 ${this.reconnectAttempts} 次重连...`);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.connect();
|
||||||
|
}, this.reconnectInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息到WebSocket服务器
|
||||||
|
* @param {Object} data - 要发送的数据
|
||||||
|
*/
|
||||||
|
sendMessage(data) {
|
||||||
|
if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
|
||||||
|
console.error('WebSocket未连接,无法发送消息');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const message = typeof data === 'string' ? data : JSON.stringify(data);
|
||||||
|
this.socket.send(message);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('发送WebSocket消息失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭WebSocket连接
|
||||||
|
*/
|
||||||
|
disconnect() {
|
||||||
|
if (this.socket) {
|
||||||
|
this.socket.close();
|
||||||
|
this.socket = null;
|
||||||
|
this.isConnected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册事件监听器
|
||||||
|
* @param {string} event - 事件名称
|
||||||
|
* @param {Function} callback - 回调函数
|
||||||
|
*/
|
||||||
|
on(event, callback) {
|
||||||
|
if (!this.listeners.has(event)) {
|
||||||
|
this.listeners.set(event, []);
|
||||||
|
}
|
||||||
|
this.listeners.get(event).push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销事件监听器
|
||||||
|
* @param {string} event - 事件名称
|
||||||
|
* @param {Function} callback - 回调函数
|
||||||
|
*/
|
||||||
|
off(event, callback) {
|
||||||
|
if (!this.listeners.has(event)) return;
|
||||||
|
|
||||||
|
const callbacks = this.listeners.get(event);
|
||||||
|
const index = callbacks.indexOf(callback);
|
||||||
|
if (index !== -1) {
|
||||||
|
callbacks.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发事件
|
||||||
|
* @param {string} event - 事件名称
|
||||||
|
* @param {*} data - 事件数据
|
||||||
|
*/
|
||||||
|
triggerEvent(event, data) {
|
||||||
|
if (!this.listeners.has(event)) return;
|
||||||
|
|
||||||
|
const callbacks = this.listeners.get(event);
|
||||||
|
callbacks.forEach(callback => {
|
||||||
|
try {
|
||||||
|
callback(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`执行${event}事件监听器出错:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建单例实例
|
||||||
|
const webSocketService = new WebSocketService();
|
||||||
|
|
||||||
|
export default webSocketService;
|
||||||
@ -29,7 +29,8 @@
|
|||||||
import { ref, reactive, getCurrentInstance, onMounted } from 'vue'
|
import { ref, reactive, getCurrentInstance, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import store from '../../store'
|
import store from '../../store/Index.js'
|
||||||
|
import { nextTick } from 'vue'
|
||||||
|
|
||||||
// 获取 全局变量
|
// 获取 全局变量
|
||||||
const global = getCurrentInstance()?.appContext.config.globalProperties.$global
|
const global = getCurrentInstance()?.appContext.config.globalProperties.$global
|
||||||
@ -81,13 +82,21 @@
|
|||||||
// 填充数据
|
// 填充数据
|
||||||
sendForm.append('password', form.password)
|
sendForm.append('password', form.password)
|
||||||
sendForm.append('code', form.captcha) // 添加验证码参数
|
sendForm.append('code', form.captcha) // 添加验证码参数
|
||||||
|
|
||||||
|
console.log('准备调用store.dispatch("login")', sendForm)
|
||||||
// 调用接口
|
// 调用接口
|
||||||
await store.dispatch('login', sendForm)
|
await store.dispatch('login', sendForm)
|
||||||
|
console.log('store.dispatch("login")调用成功')
|
||||||
|
|
||||||
// 定义 跳转地址
|
// 定义 跳转地址
|
||||||
const redirect = router.currentRoute.value.query.redirect || '/'
|
const redirect = router.currentRoute.value.query.redirect || '/welcome'
|
||||||
// 执行跳转
|
console.log("跳转地址",redirect)
|
||||||
router.replace(redirect)
|
nextTick(() => {
|
||||||
ElMessage.success('登录成功')
|
window.location.href = redirect
|
||||||
|
// 执行跳转
|
||||||
|
router.replace(redirect)
|
||||||
|
ElMessage.success('登录成功')
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('登录错误详情:', error)
|
console.error('登录错误详情:', error)
|
||||||
refreshCaptcha()
|
refreshCaptcha()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user