feat(ops): 前端集成实时流量功能
- 添加实时流量API调用方法 - 优化OpsDashboard组件代码
This commit is contained in:
@@ -362,6 +362,45 @@ export async function getAccountAvailabilityStats(platform?: string, groupId?: n
|
||||
return data
|
||||
}
|
||||
|
||||
export interface OpsRateSummary {
|
||||
current: number
|
||||
peak: number
|
||||
avg: number
|
||||
}
|
||||
|
||||
export interface OpsRealtimeTrafficSummary {
|
||||
window: string
|
||||
start_time: string
|
||||
end_time: string
|
||||
platform: string
|
||||
group_id?: number | null
|
||||
qps: OpsRateSummary
|
||||
tps: OpsRateSummary
|
||||
}
|
||||
|
||||
export interface OpsRealtimeTrafficSummaryResponse {
|
||||
enabled: boolean
|
||||
summary: OpsRealtimeTrafficSummary | null
|
||||
timestamp?: string
|
||||
}
|
||||
|
||||
export async function getRealtimeTrafficSummary(
|
||||
window: string,
|
||||
platform?: string,
|
||||
groupId?: number | null
|
||||
): Promise<OpsRealtimeTrafficSummaryResponse> {
|
||||
const params: Record<string, any> = { window }
|
||||
if (platform) {
|
||||
params.platform = platform
|
||||
}
|
||||
if (typeof groupId === 'number' && groupId > 0) {
|
||||
params.group_id = groupId
|
||||
}
|
||||
|
||||
const { data } = await apiClient.get<OpsRealtimeTrafficSummaryResponse>('/admin/ops/realtime-traffic', { params })
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to realtime QPS updates via WebSocket.
|
||||
*
|
||||
@@ -957,6 +996,7 @@ export const opsAPI = {
|
||||
getErrorDistribution,
|
||||
getConcurrencyStats,
|
||||
getAccountAvailabilityStats,
|
||||
getRealtimeTrafficSummary,
|
||||
subscribeQPS,
|
||||
listErrorLogs,
|
||||
getErrorLogDetail,
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
<OpsDashboardHeader
|
||||
v-else-if="opsEnabled"
|
||||
:overview="overview"
|
||||
:ws-status="wsStatus"
|
||||
:ws-reconnect-in-ms="wsReconnectInMs"
|
||||
:ws-has-data="wsHasData"
|
||||
:real-time-qps="realTimeQPS"
|
||||
:real-time-tps="realTimeTPS"
|
||||
:platform="platform"
|
||||
:group-id="groupId"
|
||||
:time-range="timeRange"
|
||||
@@ -116,8 +111,6 @@ import AppLayout from '@/components/layout/AppLayout.vue'
|
||||
import BaseDialog from '@/components/common/BaseDialog.vue'
|
||||
import {
|
||||
opsAPI,
|
||||
OPS_WS_CLOSE_CODES,
|
||||
type OpsWSStatus,
|
||||
type OpsDashboardOverview,
|
||||
type OpsErrorDistributionResponse,
|
||||
type OpsErrorTrendResponse,
|
||||
@@ -174,14 +167,6 @@ const QUERY_KEYS = {
|
||||
const isApplyingRouteQuery = ref(false)
|
||||
const isSyncingRouteQuery = ref(false)
|
||||
|
||||
// WebSocket for realtime QPS/TPS
|
||||
const realTimeQPS = ref(0)
|
||||
const realTimeTPS = ref(0)
|
||||
const wsStatus = ref<OpsWSStatus>('closed')
|
||||
const wsReconnectInMs = ref<number | null>(null)
|
||||
const wsHasData = ref(false)
|
||||
let unsubscribeQPS: (() => void) | null = null
|
||||
|
||||
let dashboardFetchController: AbortController | null = null
|
||||
let dashboardFetchSeq = 0
|
||||
|
||||
@@ -201,50 +186,6 @@ function abortDashboardFetch() {
|
||||
}
|
||||
}
|
||||
|
||||
function stopQPSSubscription(options?: { resetMetrics?: boolean }) {
|
||||
wsStatus.value = 'closed'
|
||||
wsReconnectInMs.value = null
|
||||
if (unsubscribeQPS) unsubscribeQPS()
|
||||
unsubscribeQPS = null
|
||||
|
||||
if (options?.resetMetrics) {
|
||||
realTimeQPS.value = 0
|
||||
realTimeTPS.value = 0
|
||||
wsHasData.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function startQPSSubscription() {
|
||||
stopQPSSubscription()
|
||||
unsubscribeQPS = opsAPI.subscribeQPS(
|
||||
(payload) => {
|
||||
if (payload && typeof payload === 'object' && payload.type === 'qps_update' && payload.data) {
|
||||
realTimeQPS.value = payload.data.qps || 0
|
||||
realTimeTPS.value = payload.data.tps || 0
|
||||
wsHasData.value = true
|
||||
}
|
||||
},
|
||||
{
|
||||
onStatusChange: (status) => {
|
||||
wsStatus.value = status
|
||||
if (status === 'connected') wsReconnectInMs.value = null
|
||||
},
|
||||
onReconnectScheduled: ({ delayMs }) => {
|
||||
wsReconnectInMs.value = delayMs
|
||||
},
|
||||
onFatalClose: (event) => {
|
||||
// Server-side feature flag says realtime is disabled; keep UI consistent and avoid reconnect loops.
|
||||
if (event && event.code === OPS_WS_CLOSE_CODES.REALTIME_DISABLED) {
|
||||
adminSettingsStore.setOpsRealtimeMonitoringEnabledLocal(false)
|
||||
stopQPSSubscription({ resetMetrics: true })
|
||||
}
|
||||
},
|
||||
// QPS updates may be sparse in idle periods; keep the timeout conservative.
|
||||
staleTimeoutMs: 180_000
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const readQueryString = (key: string): string => {
|
||||
const value = route.query[key]
|
||||
if (typeof value === 'string') return value
|
||||
@@ -626,12 +567,6 @@ onMounted(async () => {
|
||||
// Load thresholds configuration
|
||||
loadThresholds()
|
||||
|
||||
if (adminSettingsStore.opsRealtimeMonitoringEnabled) {
|
||||
startQPSSubscription()
|
||||
} else {
|
||||
stopQPSSubscription({ resetMetrics: true })
|
||||
}
|
||||
|
||||
if (opsEnabled.value) {
|
||||
await fetchData()
|
||||
}
|
||||
@@ -648,19 +583,6 @@ async function loadThresholds() {
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
stopQPSSubscription()
|
||||
abortDashboardFetch()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => adminSettingsStore.opsRealtimeMonitoringEnabled,
|
||||
(enabled) => {
|
||||
if (!opsEnabled.value) return
|
||||
if (enabled) {
|
||||
startQPSSubscription()
|
||||
} else {
|
||||
stopQPSSubscription({ resetMetrics: true })
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user