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 <cursoragent@cursor.com>
This commit is contained in:
+40
-3
@@ -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 =
|
||||
'<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;direction:rtl;font-family:sans-serif;padding:24px;background:#fff;color:#111827;">' +
|
||||
'<div style="width:min(420px,100%);text-align:center;border:1px solid rgba(15,23,42,0.08);border-radius:24px;padding:28px 22px;">' +
|
||||
'<div style="font-size:42px;margin-bottom:12px;">⚠️</div>' +
|
||||
'<h2 style="margin:0 0 12px;font-size:20px;">خطا در برقراری ارتباط با سرور</h2>' +
|
||||
'<p style="margin:0 0 20px;color:rgba(15,23,42,0.62);line-height:2;font-size:14px;">لطفاً چند لحظه دیگر دوباره تلاش کنید.</p>' +
|
||||
'<button type="button" onclick="location.reload()" style="padding:11px 22px;border:0;border-radius:12px;background:#2563eb;color:#fff;cursor:pointer;font-weight:700;">تلاش مجدد</button>' +
|
||||
'</div></div>';
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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<string, unknown>
|
||||
const user =
|
||||
root.user && typeof root.user === 'object'
|
||||
? (root.user as Record<string, unknown>)
|
||||
: 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 = `
|
||||
<div style="position:fixed;inset:0;z-index:2147483000;display:flex;align-items:center;justify-content:center;direction:rtl;font-family:sans-serif;padding:24px;background:#ffffff;color:#111827;">
|
||||
<div style="width:min(420px,100%);text-align:center;background:#fff;border:1px solid rgba(15,23,42,0.08);border-radius:24px;padding:28px 22px;">
|
||||
<div style="font-size:42px;margin-bottom:12px;">⚠️</div>
|
||||
<h2 style="margin:0 0 12px;font-size:20px;">${message}</h2>
|
||||
<p style="margin:0 0 20px;color:rgba(15,23,42,0.62);line-height:2;font-size:14px;">
|
||||
لطفاً چند لحظه دیگر دوباره تلاش کنید.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onclick="location.reload()"
|
||||
style="padding:11px 22px;border:0;border-radius:12px;background:#2563eb;color:white;cursor:pointer;font-weight:700;"
|
||||
>
|
||||
تلاش مجدد
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user