diff --git a/src/api/superadminSettings.ts b/src/api/superadminSettings.ts new file mode 100644 index 0000000..efd23de --- /dev/null +++ b/src/api/superadminSettings.ts @@ -0,0 +1,78 @@ +export type SuperAdminSettingRow = { + id?: number + key?: string + value?: string | number | null + title_fa?: string + description?: string + is_active?: boolean | number | string + type?: string + can_edit?: number | boolean | string +} + +const SUPERADMIN_BASES = [ + 'https://adm.montzar.ir', + 'https://adm.montech.ir', + 'https://adm.montest.ir', +] as const + +const SA_RETRY_ROUNDS = 3 +const SA_PROGRAM_SETTINGS_PATH = '/api/public/program-settings' + +function resolveTenantDomain() { + const host = String(window.location.hostname || '').trim() + if (!host || host === 'localhost' || host === '127.0.0.1') { + return 'k.montzar.ir' + } + return host +} + +function parseSettingsPayload(data: unknown): SuperAdminSettingRow[] { + if (Array.isArray(data)) return data as SuperAdminSettingRow[] + if (data && typeof data === 'object') { + const obj = data as Record + if (Array.isArray(obj.settings)) return obj.settings as SuperAdminSettingRow[] + if (Array.isArray(obj.items)) return obj.items as SuperAdminSettingRow[] + if (Array.isArray(obj.data)) return obj.data as SuperAdminSettingRow[] + } + return [] +} + +async function fetchFromUrl(url: string, timeout = 5000): Promise { + const controller = new AbortController() + const timer = window.setTimeout(() => controller.abort(), timeout) + try { + const res = await fetch(url, { + method: 'GET', + cache: 'no-store', + signal: controller.signal, + headers: { Accept: 'application/json' }, + }) + if (!res.ok) { + throw new Error(`HTTP ${res.status}`) + } + const contentType = res.headers.get('content-type') || '' + if (!contentType.includes('application/json')) { + throw new Error('SuperAdmin response is not JSON') + } + return parseSettingsPayload(await res.json()) + } finally { + window.clearTimeout(timer) + } +} + +/** تنظیمات پیشرفته نسخه از سوپرادمین — فقط GET /api/public/program-settings?domain= */ +export async function fetchSuperAdminProgramSettings(): Promise { + const domain = encodeURIComponent(resolveTenantDomain()) + let lastError: unknown + for (let round = 1; round <= SA_RETRY_ROUNDS; round++) { + for (const base of SUPERADMIN_BASES) { + try { + return await fetchFromUrl(`${base}${SA_PROGRAM_SETTINGS_PATH}?domain=${domain}`) + } catch (error) { + lastError = error + } + } + } + console.warn('SuperAdmin program-settings failed after retries:', lastError) + return [] +} diff --git a/src/config-loader.js b/src/config-loader.js index 27b6667..1b6c19d 100644 --- a/src/config-loader.js +++ b/src/config-loader.js @@ -18,8 +18,8 @@ const VERSION_UPDATE_LOCK_KEY = 'version_update_lock'; const VERSION_LAST_RELOAD_KEY = 'version_last_reload'; const AUTH_TOKEN_KEY = 'peransa_token'; - const VERSION_RETRY_ROUNDS = 5; - const CONFIG_RETRY_ROUNDS = 5; + const VERSION_RETRY_ROUNDS = 3; + const CONFIG_RETRY_ROUNDS = 3; const CONFIG_TIMEOUT = 12000; let configTimeoutId; @@ -37,33 +37,50 @@ return host; } + function isDevHost() { + const host = String(window.location.hostname || '').trim(); + return host === 'localhost' || host === '127.0.0.1'; + } + function getVersionUrls() { const domain = encodeURIComponent(resolveTenantDomain()); - - return [ + const urls = [ 'https://adm.montzar.ir/get_version?domain=' + domain, 'https://adm.montech.ir/get_version?domain=' + domain, - 'https://adm.montest.ir/get_version?domain=' + domain, - 'https://tablo.talasevin.ir/get_version', - 'https://abshode-service.montgit.ir/server/get_version', - getProtocol() + '//212.23.201.173:8381/get_version', - getProtocol() + '//91.212.174.137:4040/server/get_version' + 'https://adm.montest.ir/get_version?domain=' + domain ]; + + if (isDevHost()) { + urls.push( + 'https://tablo.talasevin.ir/get_version', + 'https://abshode-service.montgit.ir/server/get_version', + getProtocol() + '//212.23.201.173:8381/get_version', + getProtocol() + '//91.212.174.137:4040/server/get_version' + ); + } + + return urls; } function getConfigUrls() { const protocol = getProtocol(); const domain = encodeURIComponent(resolveTenantDomain()); - - return [ + const urls = [ 'https://adm.montzar.ir/get_user?domain=' + domain, 'https://adm.montech.ir/get_user?domain=' + domain, - 'https://adm.montest.ir/get_user?domain=' + domain, - protocol + '//tablo.talasevin.ir/get_user', - protocol + '//abshode-service.montgit.ir/server/get_user', - protocol + '//212.23.201.173:8381/get_user', - protocol + '//91.212.174.137:4040/server/get_user' + 'https://adm.montest.ir/get_user?domain=' + domain ]; + + if (isDevHost()) { + urls.push( + protocol + '//tablo.talasevin.ir/get_user', + protocol + '//abshode-service.montgit.ir/server/get_user', + protocol + '//212.23.201.173:8381/get_user', + protocol + '//91.212.174.137:4040/server/get_user' + ); + } + + return urls; } function sortUrls(urls, successKey) { @@ -367,8 +384,9 @@ '
' + '
' + '
⚠️
' + - '

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

' + - '' + + '

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

' + + '

برقراری ارتباط با سرور امکان‌پذیر نیست. لطفاً اتصال اینترنت خود را بررسی کرده و صفحه را تازه‌سازی نمایید.

' + + '' + '
'; } @@ -477,9 +495,7 @@ } } - window.__APP_CONFIG__ = {}; - window.__CONFIG_READY__ = true; - finishConfigLoad({}, error); + showServerUnavailable(); } } diff --git a/src/router/routes/setting.ts b/src/router/routes/setting.ts index 3d1e2c1..22d20b0 100644 --- a/src/router/routes/setting.ts +++ b/src/router/routes/setting.ts @@ -1,5 +1,4 @@ import type { RouteRecordRaw } from 'vue-router' -import { isDeployAdmin } from '@/utils/deployAdmin' import { hasSmsPanelAccess } from '@/utils/smsPanelAccess' import { useUserStore } from '@/store/userStore' import { bannerEnabledSetting, trackingSystemsEnabledSetting, appNotificationEnabledSetting } from '@/utils/config' @@ -60,22 +59,10 @@ const Setting: RouteRecordRaw = { } }, { - name: 'advancedConfiguration', + name: 'advancedConfigurationRedirect', path: 'advanced-configuration', - component: () => import('@/pages/menuPages/configuration/index.vue'), - props: { mode: 'system' }, - meta: { - deployAdminOnly: true, - icon: 'vuesax-linear:code-circle', - title: 'تنظیمات پیشرفته', - order: 3 - }, - beforeEnter() { - const userStore = useUserStore() - if (!isDeployAdmin(userStore.userInfo?.mobile)) { - return { name: 'configuration' } - } - } + redirect: { name: 'configuration' }, + meta: { hideMenu: true } }, { name: 'smsPanelMain', diff --git a/src/utils/config.ts b/src/utils/config.ts index 1086738..3479bd0 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -332,9 +332,24 @@ async function bootstrapSettingsFromApi(): Promise { try { const { getConfiguration } = await import('@/api/configuration') + const { fetchSuperAdminProgramSettings } = await import('@/api/superadminSettings') const { parseMainWalletProductIds } = await import('@/components/mobile/utils/wallet') - const rows = await getConfiguration() - const list = Array.isArray(rows) ? rows : [] + const [localRows, saRows] = await Promise.all([ + getConfiguration().catch(() => []), + fetchSuperAdminProgramSettings(), + ]) + const local = Array.isArray(localRows) ? localRows : [] + const merged = [...local] + for (const item of saRows) { + if (!item?.key) continue + const index = merged.findIndex((row) => row.key === item.key) + if (index >= 0) { + merged[index] = { ...merged[index], ...item } + } else { + merged.push(item as (typeof merged)[number]) + } + } + const list = merged const isStoreRow = list.find((item) => item.key === 'is_store') const mainWalletRow = list.find((item) => item.key === 'main_wallet_products') const mainMetalRow = list.find((item) => item.key === 'main_metal')