feat(前端状态): 添加运维监控状态管理和路由
- 新增 adminSettings store 管理 ops 配置状态 - 注册 adminSettings store 到全局 store - 添加 ops 监控相关路由(dashboard, alerts, realtime, settings)
This commit is contained in:
@@ -163,6 +163,18 @@ const routes: RouteRecordRaw[] = [
|
||||
descriptionKey: 'admin.dashboard.description'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/admin/ops',
|
||||
name: 'AdminOps',
|
||||
component: () => import('@/views/admin/ops/OpsDashboard.vue'),
|
||||
meta: {
|
||||
requiresAuth: true,
|
||||
requiresAdmin: true,
|
||||
title: 'Ops Monitoring',
|
||||
titleKey: 'admin.ops.title',
|
||||
descriptionKey: 'admin.ops.description'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/admin/users',
|
||||
name: 'AdminUsers',
|
||||
|
||||
130
frontend/src/stores/adminSettings.ts
Normal file
130
frontend/src/stores/adminSettings.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { adminAPI } from '@/api'
|
||||
|
||||
export const useAdminSettingsStore = defineStore('adminSettings', () => {
|
||||
const loaded = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
const readCachedBool = (key: string, defaultValue: boolean): boolean => {
|
||||
try {
|
||||
const raw = localStorage.getItem(key)
|
||||
if (raw === 'true') return true
|
||||
if (raw === 'false') return false
|
||||
} catch {
|
||||
// ignore localStorage failures
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
const writeCachedBool = (key: string, value: boolean) => {
|
||||
try {
|
||||
localStorage.setItem(key, value ? 'true' : 'false')
|
||||
} catch {
|
||||
// ignore localStorage failures
|
||||
}
|
||||
}
|
||||
|
||||
const readCachedString = (key: string, defaultValue: string): string => {
|
||||
try {
|
||||
const raw = localStorage.getItem(key)
|
||||
if (typeof raw === 'string' && raw.length > 0) return raw
|
||||
} catch {
|
||||
// ignore localStorage failures
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
const writeCachedString = (key: string, value: string) => {
|
||||
try {
|
||||
localStorage.setItem(key, value)
|
||||
} catch {
|
||||
// ignore localStorage failures
|
||||
}
|
||||
}
|
||||
|
||||
// Default open, but honor cached value to reduce UI flicker on first paint.
|
||||
const opsMonitoringEnabled = ref(readCachedBool('ops_monitoring_enabled_cached', true))
|
||||
const opsRealtimeMonitoringEnabled = ref(readCachedBool('ops_realtime_monitoring_enabled_cached', true))
|
||||
const opsQueryModeDefault = ref(readCachedString('ops_query_mode_default_cached', 'auto'))
|
||||
|
||||
async function fetch(force = false): Promise<void> {
|
||||
if (loaded.value && !force) return
|
||||
if (loading.value) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const settings = await adminAPI.settings.getSettings()
|
||||
opsMonitoringEnabled.value = settings.ops_monitoring_enabled ?? true
|
||||
writeCachedBool('ops_monitoring_enabled_cached', opsMonitoringEnabled.value)
|
||||
|
||||
opsRealtimeMonitoringEnabled.value = settings.ops_realtime_monitoring_enabled ?? true
|
||||
writeCachedBool('ops_realtime_monitoring_enabled_cached', opsRealtimeMonitoringEnabled.value)
|
||||
|
||||
opsQueryModeDefault.value = settings.ops_query_mode_default || 'auto'
|
||||
writeCachedString('ops_query_mode_default_cached', opsQueryModeDefault.value)
|
||||
|
||||
loaded.value = true
|
||||
} catch (err) {
|
||||
// Keep cached/default value: do not "flip" the UI based on a transient fetch failure.
|
||||
loaded.value = true
|
||||
console.error('[adminSettings] Failed to fetch settings:', err)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function setOpsMonitoringEnabledLocal(value: boolean) {
|
||||
opsMonitoringEnabled.value = value
|
||||
writeCachedBool('ops_monitoring_enabled_cached', value)
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
function setOpsRealtimeMonitoringEnabledLocal(value: boolean) {
|
||||
opsRealtimeMonitoringEnabled.value = value
|
||||
writeCachedBool('ops_realtime_monitoring_enabled_cached', value)
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
function setOpsQueryModeDefaultLocal(value: string) {
|
||||
opsQueryModeDefault.value = value || 'auto'
|
||||
writeCachedString('ops_query_mode_default_cached', opsQueryModeDefault.value)
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
// Keep UI consistent if we learn that ops is disabled via feature-gated 404s.
|
||||
// (event is dispatched from the axios interceptor)
|
||||
let eventHandlerCleanup: (() => void) | null = null
|
||||
|
||||
function initializeEventListeners() {
|
||||
if (eventHandlerCleanup) return
|
||||
|
||||
try {
|
||||
const handler = () => {
|
||||
setOpsMonitoringEnabledLocal(false)
|
||||
}
|
||||
window.addEventListener('ops-monitoring-disabled', handler)
|
||||
eventHandlerCleanup = () => {
|
||||
window.removeEventListener('ops-monitoring-disabled', handler)
|
||||
}
|
||||
} catch {
|
||||
// ignore window access failures (SSR)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
initializeEventListeners()
|
||||
}
|
||||
|
||||
return {
|
||||
loaded,
|
||||
loading,
|
||||
opsMonitoringEnabled,
|
||||
opsRealtimeMonitoringEnabled,
|
||||
opsQueryModeDefault,
|
||||
fetch,
|
||||
setOpsMonitoringEnabledLocal,
|
||||
setOpsRealtimeMonitoringEnabledLocal,
|
||||
setOpsQueryModeDefaultLocal
|
||||
}
|
||||
})
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
export { useAuthStore } from './auth'
|
||||
export { useAppStore } from './app'
|
||||
export { useAdminSettingsStore } from './adminSettings'
|
||||
export { useSubscriptionStore } from './subscriptions'
|
||||
export { useOnboardingStore } from './onboarding'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user