任务模块
This commit is contained in:
parent
ceef525878
commit
d01304460e
@ -12,6 +12,7 @@ export function setupRequestInterceptors(instance) {
|
||||
// 返回修改后的请求配置,继续发送请求
|
||||
return config
|
||||
}, error => {
|
||||
console.log("请求错误",error)
|
||||
// 将错误以 Promise reject 的方式抛出,供调用方捕获处理
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
//响应拦截器
|
||||
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 axiosInstance from '../../utils/axios'; // 引入已配置的axios实例
|
||||
|
||||
export function setupResponseInterceptors(instance) {
|
||||
// 用于存储正在刷新token的Promise
|
||||
@ -11,16 +12,25 @@ export function setupResponseInterceptors(instance) {
|
||||
|
||||
// 统一处理登录过期的函数
|
||||
const handleTokenExpired = (message = '登录已过期,请重新登录') => {
|
||||
// 显示提示消息
|
||||
ElMessage.error(message);
|
||||
|
||||
// 使用store的logout action清除认证状态
|
||||
store.dispatch('logout');
|
||||
|
||||
// 延迟跳转,让用户有时间看到提示
|
||||
setTimeout(() => {
|
||||
// 显示确认对话框
|
||||
ElMessageBox.confirm(
|
||||
message,
|
||||
'提示',
|
||||
{
|
||||
confirmButtonText: '重新登录',
|
||||
type: 'warning',
|
||||
showCancelButton: false,
|
||||
center: true
|
||||
}
|
||||
).then(() => {
|
||||
// 用户点击确认按钮后执行
|
||||
// 使用store的logout action清除认证状态
|
||||
store.dispatch('logout');
|
||||
// 跳转到登录页
|
||||
window.location.href = '/login';
|
||||
}, 1500);
|
||||
}).catch(() => {
|
||||
// 用户关闭对话框,不做任何操作
|
||||
});
|
||||
};
|
||||
|
||||
instance.interceptors.response.use(
|
||||
@ -35,9 +45,7 @@ export function setupResponseInterceptors(instance) {
|
||||
}
|
||||
return data;
|
||||
},
|
||||
async error => {
|
||||
console.log('响应错误:', error);
|
||||
|
||||
async error => {
|
||||
// 获取原始请求配置
|
||||
const originalRequest = error.config;
|
||||
|
||||
@ -51,10 +59,10 @@ export function setupResponseInterceptors(instance) {
|
||||
const errorResponse = error.response;
|
||||
console.log('错误响应:', errorResponse);
|
||||
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 statusCode = errorResponse.status;
|
||||
|
||||
console.log('错误响应:', statusCode);
|
||||
// 处理403错误(权限不足)
|
||||
if (errorResponse.status === "403") {
|
||||
// 显示权限不足提示,但不重定向
|
||||
@ -63,21 +71,12 @@ export function setupResponseInterceptors(instance) {
|
||||
}
|
||||
|
||||
// 检查是否为令牌错误(检查多种可能的错误信息格式)
|
||||
const isTokenError =
|
||||
statusCode === 401 ||
|
||||
(statusCode === 500 && (
|
||||
errorMessage.includes('令牌') ||
|
||||
errorMessage.includes('token') ||
|
||||
errorMessage.includes('Token') ||
|
||||
errorStack.includes('TokenIllegal') ||
|
||||
errorStack.includes('TheTokenIllegalException') ||
|
||||
(typeof errorData === 'string' && errorData.includes('令牌'))
|
||||
));
|
||||
|
||||
const isTokenError = statusCode === 500
|
||||
|
||||
// 如果是令牌错误,尝试刷新令牌或直接跳转登录页
|
||||
if (isTokenError) {
|
||||
// 如果是401错误且没有在刷新中,尝试刷新令牌
|
||||
if (statusCode === 401 && !originalRequest._retry) {
|
||||
if (statusCode === 401 || statusCode === 500 || statusCode === 403 && !originalRequest._retry ) {
|
||||
// 标记该请求已尝试过重试
|
||||
originalRequest._retry = true;
|
||||
|
||||
@ -88,7 +87,6 @@ export function setupResponseInterceptors(instance) {
|
||||
try {
|
||||
// 从localStorage获取refreshToken
|
||||
const refreshToken = localStorage.getItem('refreshToken');
|
||||
|
||||
if (!refreshToken) {
|
||||
// 无refreshToken,跳转到登录页
|
||||
handleTokenExpired();
|
||||
@ -99,20 +97,26 @@ export function setupResponseInterceptors(instance) {
|
||||
const formData = new FormData();
|
||||
formData.append('refreshToken', refreshToken);
|
||||
|
||||
// 调用刷新token接口
|
||||
const response = await axios.post('/admin/getAccessToken', formData);
|
||||
// 调用刷新token接口,使用配置好的axios实例
|
||||
const response = await axiosInstance.post('/admin/getAccessToken', formData);
|
||||
|
||||
// 获取新的token
|
||||
const { accessToken, refreshToken: newRefreshToken } = response.data.data;
|
||||
// 根据实际返回的数据结构获取token
|
||||
const responseData = response.data;
|
||||
const accessToken = responseData.accessToken;
|
||||
const newRefreshToken = responseData.refreshToken;
|
||||
|
||||
// 更新本地存储
|
||||
localStorage.setItem('accessToken', accessToken);
|
||||
if (newRefreshToken) {
|
||||
localStorage.setItem('refreshToken', newRefreshToken);
|
||||
}
|
||||
localStorage.setItem('refreshToken', newRefreshToken);
|
||||
|
||||
// 更新当前请求的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));
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { createStore } from 'vuex'
|
||||
import { adminApi } from '../api/index.js'
|
||||
import webSocketService from '../utils/webSocket.js'
|
||||
|
||||
export default createStore({
|
||||
state: {
|
||||
@ -31,6 +32,9 @@ export default createStore({
|
||||
localStorage.removeItem('refreshToken')
|
||||
// 清除本地缓存
|
||||
localStorage.removeItem('userInfo')
|
||||
|
||||
// 断开WebSocket连接
|
||||
webSocketService.disconnect()
|
||||
},
|
||||
SET_USER_INFO(state, userInfo) {
|
||||
// 初始化 用户信息
|
||||
@ -44,7 +48,7 @@ export default createStore({
|
||||
try {
|
||||
// 调用登录接口
|
||||
const response = await adminApi.login(data)
|
||||
|
||||
console.log("响应",response)
|
||||
// 检查响应状态
|
||||
if (response.code !== 200) {
|
||||
throw new Error(response.message || '登录失败')
|
||||
@ -52,6 +56,17 @@ export default createStore({
|
||||
|
||||
// 设置 状态
|
||||
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 {
|
||||
// 调用查询接口获取用户信息
|
||||
|
||||
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 { useRouter } from 'vue-router'
|
||||
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
|
||||
@ -81,13 +82,21 @@
|
||||
// 填充数据
|
||||
sendForm.append('password', form.password)
|
||||
sendForm.append('code', form.captcha) // 添加验证码参数
|
||||
|
||||
console.log('准备调用store.dispatch("login")', sendForm)
|
||||
// 调用接口
|
||||
await store.dispatch('login', sendForm)
|
||||
console.log('store.dispatch("login")调用成功')
|
||||
|
||||
// 定义 跳转地址
|
||||
const redirect = router.currentRoute.value.query.redirect || '/'
|
||||
// 执行跳转
|
||||
router.replace(redirect)
|
||||
ElMessage.success('登录成功')
|
||||
const redirect = router.currentRoute.value.query.redirect || '/welcome'
|
||||
console.log("跳转地址",redirect)
|
||||
nextTick(() => {
|
||||
window.location.href = redirect
|
||||
// 执行跳转
|
||||
router.replace(redirect)
|
||||
ElMessage.success('登录成功')
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('登录错误详情:', error)
|
||||
refreshCaptcha()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user