From 512756348b0ae27b7499bc2872e889a2a4d4b9d5 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Tue, 11 Aug 2026 15:51:13 +0330 Subject: [PATCH] feat: full-screen lock when server access is blocked Gate admin boot on server_reachable and show server-unavailable overlay on API 503 for SuperAdmin kill switch. Co-authored-by: Cursor --- src/config-loader.js | 43 +++++++++++++++++++++++-- src/core/utils/useAxios.ts | 9 ++++++ src/utils/serverUnavailable.ts | 57 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/utils/serverUnavailable.ts diff --git a/src/config-loader.js b/src/config-loader.js index 86b88f8..5b2d1ab 100644 --- a/src/config-loader.js +++ b/src/config-loader.js @@ -324,6 +324,11 @@ } function applyConfig(config) { + if (isServerUnreachable(config)) { + showServerUnavailable(); + throw new Error('خطا در برقراری ارتباط با سرور'); + } + window.__APP_CONFIG__ = config || {}; window.__CONFIG_READY__ = true; @@ -344,6 +349,25 @@ } } + function isServerUnreachable(config) { + if (!config || typeof config !== 'object') return false; + if (config.server_reachable === false) return true; + if (config.user && config.user.server_reachable === false) return true; + return false; + } + + function showServerUnavailable() { + var appRoot = document.querySelector('#app') || document.body; + appRoot.innerHTML = + '
' + + '
' + + '
⚠️
' + + '

خطا در برقراری ارتباط با سرور

' + + '

لطفاً چند لحظه دیگر دوباره تلاش کنید.

' + + '' + + '
'; + } + function finishConfigLoad(config, error) { if (configResolve) { configResolve(config); @@ -406,15 +430,24 @@ console.log('Config loaded successfully from', url, config); finishConfigLoad(config); } catch (error) { + if (error && String(error.message || '').includes('خطا در برقراری ارتباط با سرور')) { + showServerUnavailable(); + return; + } console.warn('Config loader: Could not fetch config from any endpoint'); console.warn('Error details:', error && error.message ? error.message : error); console.warn('App will continue with empty/cached config.'); const cachedConfig = readCachedAppConfig(); if (cachedConfig) { - applyConfig(cachedConfig); - finishConfigLoad(cachedConfig, error); - return; + try { + applyConfig(cachedConfig); + finishConfigLoad(cachedConfig, error); + return; + } catch (blockedError) { + showServerUnavailable(); + return; + } } window.__APP_CONFIG__ = {}; @@ -439,6 +472,10 @@ if (!mainScriptLoaded) { console.warn('Config loader: Timeout reached. Loading main.ts with empty/cached config.'); const cachedConfig = readCachedAppConfig(); + if (isServerUnreachable(cachedConfig) || isServerUnreachable(window.__APP_CONFIG__)) { + showServerUnavailable(); + return; + } window.__APP_CONFIG__ = cachedConfig || window.__APP_CONFIG__ || {}; window.__CONFIG_READY__ = true; diff --git a/src/core/utils/useAxios.ts b/src/core/utils/useAxios.ts index fb8b38a..b8dc45b 100644 --- a/src/core/utils/useAxios.ts +++ b/src/core/utils/useAxios.ts @@ -4,6 +4,10 @@ import axios from 'axios' import type { AxiosRequestConfig, AxiosResponse } from 'axios' // import { useRouter, useRoute } from 'vue-router' import { getToken, removeToken } from '@/utils/index' +import { + hideServerUnavailableOverlay, + showServerUnavailableOverlay, +} from '@/utils/serverUnavailable' import { message } from 'ant-design-vue' //import { isToken } from '@/utils/is' //import router from '@/router' @@ -69,6 +73,7 @@ _axios.interceptors.response.use( // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data //console.log('this is fulfilled on interceptors.response', response.data) + hideServerUnavailableOverlay() return response.data }, async function (error) { @@ -79,6 +84,10 @@ _axios.interceptors.response.use( }*/ //console.log('this is error on interceptors.response', error.config.meta) //console.log('1111111111', error.response) + if (error.response && error.response.status == 503) { + showServerUnavailableOverlay('خطا در برقراری ارتباط با سرور') + return Promise.reject(error) + } if (error.response && error.response.status == 401) { ///removeToken() console.log('error') diff --git a/src/utils/serverUnavailable.ts b/src/utils/serverUnavailable.ts new file mode 100644 index 0000000..80ed6cf --- /dev/null +++ b/src/utils/serverUnavailable.ts @@ -0,0 +1,57 @@ +const OVERLAY_ID = 'sa-server-unavailable-overlay' +const MESSAGE = 'خطا در برقراری ارتباط با سرور' + +export function isServerUnreachableConfig(config: unknown): boolean { + if (!config || typeof config !== 'object') return false + const root = config as Record + const user = + root.user && typeof root.user === 'object' + ? (root.user as Record) + : null + + if (root.server_reachable === false) return true + if (user && user.server_reachable === false) return true + return false +} + +export function showServerUnavailableOverlay(message = MESSAGE) { + if (typeof document === 'undefined') return + let root = document.getElementById(OVERLAY_ID) + if (!root) { + root = document.createElement('div') + root.id = OVERLAY_ID + document.body.appendChild(root) + } + + root.innerHTML = ` +
+
+
⚠️
+

${message}

+

+ لطفاً چند لحظه دیگر دوباره تلاش کنید. +

+ +
+
+ ` +} + +export function hideServerUnavailableOverlay() { + if (typeof document === 'undefined') return + const root = document.getElementById(OVERLAY_ID) + if (root) root.remove() +} + +export function assertServerReachableConfig(config: unknown) { + if (isServerUnreachableConfig(config)) { + showServerUnavailableOverlay() + throw new Error(MESSAGE) + } +}