From cee3b54b4cf712f1480c3ed37aa6c3d5ee72d8c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?piexlMax=28=E5=A5=87=E6=B7=BC?= Date: Thu, 3 Jul 2025 11:42:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(loading):=20=E4=BF=AE=E5=A4=8Dloading?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E7=AE=A1=E7=90=86=E9=97=AE=E9=A2=98=E5=B9=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B6=85=E6=97=B6=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/utils/request.js | 73 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/web/src/utils/request.js b/web/src/utils/request.js index cc113cbd..c05bab40 100644 --- a/web/src/utils/request.js +++ b/web/src/utils/request.js @@ -14,6 +14,9 @@ const service = axios.create({ let activeAxios = 0 let timer let loadingInstance +let isLoadingVisible = false +let forceCloseTimer + const showLoading = ( option = { target: null @@ -21,13 +24,33 @@ const showLoading = ( ) => { const loadDom = document.getElementById('gva-base-load-dom') activeAxios++ + + // 清除之前的定时器 if (timer) { clearTimeout(timer) } + + // 清除强制关闭定时器 + if (forceCloseTimer) { + clearTimeout(forceCloseTimer) + } + timer = setTimeout(() => { - if (activeAxios > 0) { + // 再次检查activeAxios状态,防止竞态条件 + if (activeAxios > 0 && !isLoadingVisible) { if (!option.target) option.target = loadDom loadingInstance = ElLoading.service(option) + isLoadingVisible = true + + // 设置强制关闭定时器,防止loading永远不关闭(30秒超时) + forceCloseTimer = setTimeout(() => { + if (isLoadingVisible && loadingInstance) { + console.warn('Loading强制关闭:超时30秒') + loadingInstance.close() + isLoadingVisible = false + activeAxios = 0 // 重置计数器 + } + }, 30000) } }, 400) } @@ -35,8 +58,44 @@ const showLoading = ( const closeLoading = () => { activeAxios-- if (activeAxios <= 0) { + activeAxios = 0 // 确保不会变成负数 clearTimeout(timer) - loadingInstance && loadingInstance.close() + + if (forceCloseTimer) { + clearTimeout(forceCloseTimer) + forceCloseTimer = null + } + + if (isLoadingVisible && loadingInstance) { + loadingInstance.close() + isLoadingVisible = false + } + loadingInstance = null + } +} + +// 全局重置loading状态的函数,用于异常情况 +const resetLoading = () => { + activeAxios = 0 + isLoadingVisible = false + + if (timer) { + clearTimeout(timer) + timer = null + } + + if (forceCloseTimer) { + clearTimeout(forceCloseTimer) + forceCloseTimer = null + } + + if (loadingInstance) { + try { + loadingInstance.close() + } catch (e) { + console.warn('关闭loading时出错:', e) + } + loadingInstance = null } } // http request 拦截器 @@ -105,6 +164,8 @@ service.interceptors.response.use( } if (!error.response) { + // 网络错误时重置loading状态 + resetLoading() errorBoxVisible = true ElMessageBox.confirm( ` @@ -196,4 +257,12 @@ service.interceptors.response.use( return error } ) +// 监听页面卸载事件,确保loading被正确清理 +if (typeof window !== 'undefined') { + window.addEventListener('beforeunload', resetLoading) + window.addEventListener('unload', resetLoading) +} + +// 导出service和resetLoading函数 +export { resetLoading } export default service