feat(前端状态): 添加运维监控状态管理和路由

- 新增 adminSettings store 管理 ops 配置状态
- 注册 adminSettings store 到全局 store
- 添加 ops 监控相关路由(dashboard, alerts, realtime, settings)
This commit is contained in:
IanShaw027
2026-01-09 20:59:02 +08:00
parent 11d063e3c4
commit 337a188660
3 changed files with 143 additions and 0 deletions

View File

@@ -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',

View 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
}
})

View File

@@ -5,6 +5,7 @@
export { useAuthStore } from './auth'
export { useAppStore } from './app'
export { useAdminSettingsStore } from './adminSettings'
export { useSubscriptionStore } from './subscriptions'
export { useOnboardingStore } from './onboarding'