fix(admin): 生产环境隐藏并禁用自动化测试
侧栏与路由按服务端 NODE_ENV 控制;可通过 ALLOW_SMOKE_TESTS=true 临时开启。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24
apps/admin/src/composables/useSmokeTestsAllowed.ts
Normal file
24
apps/admin/src/composables/useSmokeTestsAllowed.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ref } from 'vue';
|
||||
import api from '../api';
|
||||
|
||||
const allowed = ref<boolean | null>(null);
|
||||
let loadPromise: Promise<void> | null = null;
|
||||
|
||||
export function useSmokeTestsAllowed() {
|
||||
async function ensureLoaded() {
|
||||
if (allowed.value !== null) return;
|
||||
if (!loadPromise) {
|
||||
loadPromise = (async () => {
|
||||
try {
|
||||
const { data } = await api.get('/admin/system/smoke-tests');
|
||||
allowed.value = !!data.data?.allowed;
|
||||
} catch {
|
||||
allowed.value = false;
|
||||
}
|
||||
})();
|
||||
}
|
||||
await loadPromise;
|
||||
}
|
||||
|
||||
return { allowed, ensureLoaded };
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { RouterView, RouterLink, useRoute, useRouter } from 'vue-router';
|
||||
import { useAuthStore } from '../stores/auth';
|
||||
import { useAdminLocale } from '../composables/useAdminLocale';
|
||||
import { useSmokeTestsAllowed } from '../composables/useSmokeTestsAllowed';
|
||||
import AdminLocaleSwitcher from '../components/AdminLocaleSwitcher.vue';
|
||||
import AdminNavIcon from '../components/AdminNavIcon.vue';
|
||||
import { resolveAdminBreadcrumb } from '../utils/admin-breadcrumb';
|
||||
@@ -11,23 +12,30 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
const { t } = useAdminLocale();
|
||||
const { allowed: smokeTestsAllowed, ensureLoaded: ensureSmokeTestsAllowed } = useSmokeTestsAllowed();
|
||||
|
||||
const sidebarOpen = ref(false);
|
||||
const isMobileNav = ref(false);
|
||||
|
||||
const adminMenus = computed(() => [
|
||||
{ path: '/', label: t('nav.dashboard'), icon: 'dashboard', matchPrefix: true },
|
||||
{ path: '/matches', label: t('nav.matches'), icon: 'matches', matchPrefix: true },
|
||||
{ path: '/users', label: t('nav.agents_players'), icon: 'users' },
|
||||
{ path: '/finance-logs', label: t('nav.finance_logs'), icon: 'finance' },
|
||||
{ path: '/deposit', label: t('nav.deposit_manage'), icon: 'deposit', matchPrefix: true },
|
||||
{ path: '/cashback', label: t('nav.cashback'), icon: 'cashback' },
|
||||
{ path: '/bets', label: t('nav.bets'), icon: 'bets' },
|
||||
{ path: '/contents', label: t('nav.contents'), icon: 'contents' },
|
||||
{ path: '/media', label: t('nav.media'), icon: 'media' },
|
||||
{ path: '/audit', label: t('nav.audit'), icon: 'audit' },
|
||||
{ path: '/smoke-tests', label: t('nav.smoke_tests'), icon: 'smoke-tests' },
|
||||
]);
|
||||
const adminMenus = computed(() => {
|
||||
const items = [
|
||||
{ path: '/', label: t('nav.dashboard'), icon: 'dashboard', matchPrefix: true },
|
||||
{ path: '/matches', label: t('nav.matches'), icon: 'matches', matchPrefix: true },
|
||||
{ path: '/users', label: t('nav.agents_players'), icon: 'users' },
|
||||
{ path: '/finance-logs', label: t('nav.finance_logs'), icon: 'finance' },
|
||||
{ path: '/deposit', label: t('nav.deposit_manage'), icon: 'deposit', matchPrefix: true },
|
||||
{ path: '/cashback', label: t('nav.cashback'), icon: 'cashback' },
|
||||
{ path: '/bets', label: t('nav.bets'), icon: 'bets' },
|
||||
{ path: '/contents', label: t('nav.contents'), icon: 'contents' },
|
||||
{ path: '/media', label: t('nav.media'), icon: 'media' },
|
||||
{ path: '/audit', label: t('nav.audit'), icon: 'audit' },
|
||||
{ path: '/smoke-tests', label: t('nav.smoke_tests'), icon: 'smoke-tests' },
|
||||
];
|
||||
if (smokeTestsAllowed.value === false) {
|
||||
return items.filter((item) => item.path !== '/smoke-tests');
|
||||
}
|
||||
return items;
|
||||
});
|
||||
|
||||
const agentMenus = computed(() => [
|
||||
{ path: '/', label: t('nav.dashboard'), icon: 'dashboard' },
|
||||
@@ -114,6 +122,9 @@ function logout() {
|
||||
onMounted(() => {
|
||||
syncMobileNav();
|
||||
window.addEventListener('resize', syncMobileNav);
|
||||
if (auth.isAdmin.value) {
|
||||
void ensureSmokeTestsAllowed();
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { useAuthStore } from '../stores/auth';
|
||||
import { useSmokeTestsAllowed } from '../composables/useSmokeTestsAllowed';
|
||||
import { ensureStaffSession } from '../utils/session-hydrate';
|
||||
|
||||
const router = createRouter({
|
||||
@@ -107,7 +108,7 @@ const router = createRouter({
|
||||
{
|
||||
path: 'smoke-tests',
|
||||
component: () => import('../views/SmokeTests.vue'),
|
||||
meta: { adminOnly: true },
|
||||
meta: { adminOnly: true, smokeTestsOnly: true },
|
||||
},
|
||||
{
|
||||
path: 'media',
|
||||
@@ -185,6 +186,12 @@ router.beforeEach(async (to) => {
|
||||
return '/';
|
||||
}
|
||||
|
||||
if (to.meta.smokeTestsOnly) {
|
||||
const { ensureLoaded, allowed } = useSmokeTestsAllowed();
|
||||
await ensureLoaded();
|
||||
if (!allowed.value) return '/';
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { useAdminLocale } from '../composables/useAdminLocale';
|
||||
import { useSmokeTestsAllowed } from '../composables/useSmokeTestsAllowed';
|
||||
import api from '../api';
|
||||
import AdminTableEmpty from '../components/AdminTableEmpty.vue';
|
||||
|
||||
const { t, locale, localeTag } = useAdminLocale();
|
||||
const router = useRouter();
|
||||
const { allowed: smokeTestsAllowed, ensureLoaded: ensureSmokeTestsAllowed } = useSmokeTestsAllowed();
|
||||
|
||||
type SuiteInfo = { id: string; name: string; description: string; caseCount: number };
|
||||
type CaseMeta = { id: string; suite: string; name: string; uatRef?: string };
|
||||
@@ -153,7 +157,14 @@ function statusTagType(status: string) {
|
||||
return 'info';
|
||||
}
|
||||
|
||||
onMounted(loadMeta);
|
||||
onMounted(async () => {
|
||||
await ensureSmokeTestsAllowed();
|
||||
if (!smokeTestsAllowed.value) {
|
||||
router.replace('/');
|
||||
return;
|
||||
}
|
||||
await loadMeta();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user