1.m2pool断网重连 60秒内重连机制 所有页面添加
2.优化响应错误提示 3秒内同一种错误只提示一次
This commit is contained in:
74
mining-pool/src/utils/errorNotificationManager.js
Normal file
74
mining-pool/src/utils/errorNotificationManager.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 错误提示管理器
|
||||
* 用于控制错误提示的频率,避免短时间内重复显示相同类型的错误
|
||||
*/
|
||||
class ErrorNotificationManager {
|
||||
constructor() {
|
||||
// 记录最近显示的错误信息
|
||||
this.recentErrors = new Map();
|
||||
// 默认节流时间 (30秒)
|
||||
this.throttleTime = 3000;
|
||||
// 错误类型映射
|
||||
this.errorTypes = {
|
||||
'Network Error': 'network',
|
||||
'timeout': 'timeout',
|
||||
'Request failed with status code': 'statusCode',
|
||||
// 添加网络状态类型
|
||||
'networkReconnected': 'networkStatus',
|
||||
'NetworkError': 'network'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误类型
|
||||
* @param {String} message 错误信息
|
||||
* @returns {String} 错误类型
|
||||
*/
|
||||
getErrorType(message) {
|
||||
for (const [key, type] of Object.entries(this.errorTypes)) {
|
||||
if (message.includes(key)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否可以显示错误
|
||||
* @param {String} message 错误信息
|
||||
* @returns {Boolean} 是否可以显示
|
||||
*/
|
||||
canShowError(message) {
|
||||
const errorType = this.getErrorType(message);
|
||||
const now = Date.now();
|
||||
|
||||
// 检查同类型的错误是否最近已经显示过
|
||||
if (this.recentErrors.has(errorType)) {
|
||||
const lastTime = this.recentErrors.get(errorType);
|
||||
if (now - lastTime < this.throttleTime) {
|
||||
console.log(`[错误提示] 已抑制重复错误: ${errorType}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后显示时间
|
||||
this.recentErrors.set(errorType, now);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期的错误记录
|
||||
*/
|
||||
cleanup() {
|
||||
const now = Date.now();
|
||||
this.recentErrors.forEach((time, type) => {
|
||||
if (now - time > this.throttleTime) {
|
||||
this.recentErrors.delete(type);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 创建单例实例
|
||||
const errorNotificationManager = new ErrorNotificationManager();
|
||||
export default errorNotificationManager;
|
||||
41
mining-pool/src/utils/loadingRecovery.js
Normal file
41
mining-pool/src/utils/loadingRecovery.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
/**
|
||||
* 自动恢复加载状态的指令
|
||||
* 用法: v-loading-recovery="{ loading: 'loadingProp', recovery: ['method1', 'method2'] }"
|
||||
*/
|
||||
export const loadingRecoveryDirective = {
|
||||
// 当绑定元素插入到 DOM 中时
|
||||
inserted(el, binding, vnode) {
|
||||
const component = vnode.context;
|
||||
const { loading, recovery } = binding.value || {};
|
||||
|
||||
if (!loading || !recovery || !Array.isArray(recovery)) return;
|
||||
|
||||
// 为组件添加加载状态恢复的逻辑
|
||||
const handleNetworkRecovery = () => {
|
||||
// 当网络恢复时,自动设置loading为false
|
||||
if (component[loading]) {
|
||||
component[loading] = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 保存到元素上,以便后续清理
|
||||
el._loadingRecovery = handleNetworkRecovery;
|
||||
window.addEventListener('network-retry-complete', handleNetworkRecovery);
|
||||
|
||||
console.log(`[LoadingRecovery] 添加加载状态恢复: ${loading}`);
|
||||
},
|
||||
|
||||
// 当指令与元素解绑时
|
||||
unbind(el) {
|
||||
// 清理事件监听
|
||||
if (el._loadingRecovery) {
|
||||
window.removeEventListener('network-retry-complete', el._loadingRecovery);
|
||||
delete el._loadingRecovery;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 注册全局指令
|
||||
Vue.directive('loading-recovery', loadingRecoveryDirective);
|
||||
@@ -2,6 +2,8 @@ import axios from 'axios'
|
||||
import errorCode from './errorCode'
|
||||
import { Notification, MessageBox, Message } from 'element-ui'
|
||||
import loadingManager from './loadingManager';
|
||||
import errorNotificationManager from './errorNotificationManager';
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
@@ -19,10 +21,51 @@ let lastNetworkErrorTime = 0; // 上次网络错误提示时间
|
||||
let pendingRequests = new Map();
|
||||
|
||||
|
||||
// 网络状态监听器
|
||||
// 网络状态最后提示时间
|
||||
let lastNetworkStatusTime = {
|
||||
online: 0,
|
||||
offline: 0
|
||||
};
|
||||
|
||||
// 创建一个全局标志,确保每次网络恢复只显示一次提示
|
||||
let networkRecoveryInProgress = false;
|
||||
|
||||
// 网络状态监听器
|
||||
window.addEventListener('online', () => {
|
||||
// 网络恢复时,重试所有待处理的请求
|
||||
const now = Date.now();
|
||||
|
||||
// 避免短时间内多次触发
|
||||
if (networkRecoveryInProgress) {
|
||||
console.log('[网络] 网络恢复处理已在进行中,忽略重复事件');
|
||||
return;
|
||||
}
|
||||
|
||||
networkRecoveryInProgress = true;
|
||||
|
||||
// 严格检查是否应该显示提示
|
||||
if (now - lastNetworkStatusTime.online > 30000) { // 30秒内不重复提示
|
||||
lastNetworkStatusTime.online = now;
|
||||
|
||||
try {
|
||||
if (window.vm && window.vm.$message) {
|
||||
// 确保消息只显示一次
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkReconnected') || '网络已重新连接,正在恢复数据...',
|
||||
type: 'success',
|
||||
duration: 5000,
|
||||
showClose: true,
|
||||
});
|
||||
console.log('[网络] 显示网络恢复提示, 时间:', new Date().toLocaleTimeString());
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[网络] 显示网络恢复提示失败:', e);
|
||||
}
|
||||
} else {
|
||||
console.log('[网络] 抑制重复的网络恢复提示, 间隔过短:', now - lastNetworkStatusTime.online + 'ms');
|
||||
}
|
||||
|
||||
// 网络恢复时,重试所有待处理的请求
|
||||
const pendingPromises = [];
|
||||
|
||||
pendingRequests.forEach(async (request, key) => {
|
||||
@@ -71,27 +114,46 @@ window.addEventListener('online', () => {
|
||||
// 等待所有请求完成
|
||||
Promise.allSettled(pendingPromises).then(() => {
|
||||
// 重置所有 loading 状态
|
||||
loadingManager.resetAllLoadingStates();
|
||||
if (loadingManager) {
|
||||
loadingManager.resetAllLoadingStates();
|
||||
}
|
||||
|
||||
// 手动重置一些关键的 loading 状态
|
||||
if (window.vm) {
|
||||
// 常见的加载状态
|
||||
const commonLoadingProps = [
|
||||
'minerChartLoading', 'reportBlockLoading', 'apiPageLoading',
|
||||
'MiningLoading', 'miniLoading'
|
||||
];
|
||||
|
||||
commonLoadingProps.forEach(prop => {
|
||||
if (typeof window.vm[prop] !== 'undefined') {
|
||||
window.vm[prop] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触发网络重试完成事件
|
||||
window.dispatchEvent(new CustomEvent('network-retry-complete'));
|
||||
|
||||
// 重置网络恢复标志
|
||||
setTimeout(() => {
|
||||
networkRecoveryInProgress = false;
|
||||
}, 5000); // 5秒后允许再次处理网络恢复
|
||||
});
|
||||
|
||||
// 显示网络恢复提示
|
||||
if (window.vm && window.vm.$message) {
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkReconnected') || '网络已重新连接,正在恢复数据...',
|
||||
type: 'success',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
// 使用错误提示管理器控制网络断开提示
|
||||
window.addEventListener('offline', () => {
|
||||
if (window.vm && window.vm.$message) {
|
||||
if (window.vm && window.vm.$message && errorNotificationManager.canShowError('networkOffline')) {
|
||||
window.vm.$message({
|
||||
message: window.vm.$i18n.t('home.networkOffline') || '网络连接已断开,系统将在恢复连接后自动重试',
|
||||
type: 'warning',
|
||||
duration: 3000
|
||||
type: 'error',
|
||||
duration: 5000,
|
||||
showClose: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -273,19 +335,12 @@ service.interceptors.response.use(res => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!superReportError) {
|
||||
superReportError = "error"
|
||||
localStorage.setItem('superReportError', superReportError)
|
||||
let { message } = error;
|
||||
if (message == "Network Error") {
|
||||
// message = "后端接口网络连接异常,请刷新重试";
|
||||
const now = Date.now();
|
||||
if (now - lastNetworkErrorTime > NETWORK_ERROR_THROTTLE_TIME) {
|
||||
lastNetworkErrorTime = now; // 更新最后提示时间
|
||||
//使用错误提示管理器errorNotificationManager
|
||||
if (errorNotificationManager.canShowError(message)) {
|
||||
if (message == "Network Error") {
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.NetworkError`),
|
||||
type: 'error',
|
||||
@@ -293,36 +348,84 @@ service.interceptors.response.use(res => {
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else if (message.includes("timeout")) {
|
||||
// message = "系统接口请求超时,请刷新重试";
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
// message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
Message({
|
||||
message: "系统接口" + message.substr(message.length - 3) + "异常",
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
else if (message.includes("timeout")) {
|
||||
Message({
|
||||
message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
else if (message.includes("Request failed with status code")) {
|
||||
Message({
|
||||
message: "系统接口" + message.substr(message.length - 3) + "异常",
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
} else {
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
Message({
|
||||
message: message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000,
|
||||
showClose: true
|
||||
})
|
||||
|
||||
// 避免完全不提示,可以在控制台记录被抑制的错误
|
||||
console.log('[错误提示] 已抑制重复错误:', message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// let { message } = error;
|
||||
// if (message == "Network Error") {
|
||||
// // message = "后端接口网络连接异常,请刷新重试";
|
||||
// const now = Date.now();
|
||||
// if (now - lastNetworkErrorTime > NETWORK_ERROR_THROTTLE_TIME) {
|
||||
// lastNetworkErrorTime = now; // 更新最后提示时间
|
||||
// Message({
|
||||
// message: window.vm.$i18n.t(`home.NetworkError`),
|
||||
// type: 'error',
|
||||
// duration: 4 * 1000,
|
||||
// showClose: true
|
||||
// });
|
||||
// }
|
||||
|
||||
// }
|
||||
// else if (message.includes("timeout")) {
|
||||
// // message = "系统接口请求超时,请刷新重试";
|
||||
// Message({
|
||||
// message: window.vm.$i18n.t(`home.requestTimeout`),
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000,
|
||||
// showClose: true
|
||||
// })
|
||||
|
||||
// }
|
||||
// else if (message.includes("Request failed with status code")) {
|
||||
// // message = "系统接口" + message.substr(message.length - 3) + "异常";
|
||||
// Message({
|
||||
// message: "系统接口" + message.substr(message.length - 3) + "异常",
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000,
|
||||
// showClose: true
|
||||
// })
|
||||
// } else {
|
||||
|
||||
// Message({
|
||||
// message: message,
|
||||
// type: 'error',
|
||||
// duration: 5 * 1000,
|
||||
// showClose: true
|
||||
// })
|
||||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
34
mining-pool/src/utils/requestWrapper.js
Normal file
34
mining-pool/src/utils/requestWrapper.js
Normal file
@@ -0,0 +1,34 @@
|
||||
//自动记录请求参数,并支持断网重连,创建一个函数装饰器
|
||||
/**
|
||||
* 包装请求方法,自动注册断网重连恢复
|
||||
* @param {Object} component - 组件实例
|
||||
* @param {String} methodName - 方法名
|
||||
* @param {Function} originalMethod - 原始方法
|
||||
* @returns {Function} 包装后的方法
|
||||
*/
|
||||
export function wrapRequestMethod(component, methodName, originalMethod) {
|
||||
return async function(...args) {
|
||||
// 注册为恢复方法(仅当组件支持断网重连恢复)
|
||||
if (component.registerRecoveryMethod) {
|
||||
component.registerRecoveryMethod(methodName, args[0]);
|
||||
}
|
||||
|
||||
// 调用原始方法
|
||||
return await originalMethod.apply(component, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动包装组件中的所有请求方法
|
||||
* @param {Object} component - 组件实例
|
||||
* @param {Array<String>} methodNames - 方法名列表
|
||||
*/
|
||||
export function wrapComponentMethods(component, methodNames) {
|
||||
methodNames.forEach(methodName => {
|
||||
if (typeof component[methodName] === 'function') {
|
||||
const originalMethod = component[methodName];
|
||||
component[methodName] = wrapRequestMethod(component, methodName, originalMethod);
|
||||
console.log(`[RequestWrapper] 包装方法: ${methodName}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user