feat(ops): 前端集成实时流量功能
- 添加实时流量API调用方法 - 优化OpsDashboard组件代码
This commit is contained in:
@@ -362,6 +362,45 @@ export async function getAccountAvailabilityStats(platform?: string, groupId?: n
|
|||||||
return data
|
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.
|
* Subscribe to realtime QPS updates via WebSocket.
|
||||||
*
|
*
|
||||||
@@ -957,6 +996,7 @@ export const opsAPI = {
|
|||||||
getErrorDistribution,
|
getErrorDistribution,
|
||||||
getConcurrencyStats,
|
getConcurrencyStats,
|
||||||
getAccountAvailabilityStats,
|
getAccountAvailabilityStats,
|
||||||
|
getRealtimeTrafficSummary,
|
||||||
subscribeQPS,
|
subscribeQPS,
|
||||||
listErrorLogs,
|
listErrorLogs,
|
||||||
getErrorLogDetail,
|
getErrorLogDetail,
|
||||||
|
|||||||
@@ -13,11 +13,6 @@
|
|||||||
<OpsDashboardHeader
|
<OpsDashboardHeader
|
||||||
v-else-if="opsEnabled"
|
v-else-if="opsEnabled"
|
||||||
:overview="overview"
|
:overview="overview"
|
||||||
:ws-status="wsStatus"
|
|
||||||
:ws-reconnect-in-ms="wsReconnectInMs"
|
|
||||||
:ws-has-data="wsHasData"
|
|
||||||
:real-time-qps="realTimeQPS"
|
|
||||||
:real-time-tps="realTimeTPS"
|
|
||||||
:platform="platform"
|
:platform="platform"
|
||||||
:group-id="groupId"
|
:group-id="groupId"
|
||||||
:time-range="timeRange"
|
:time-range="timeRange"
|
||||||
@@ -116,8 +111,6 @@ import AppLayout from '@/components/layout/AppLayout.vue'
|
|||||||
import BaseDialog from '@/components/common/BaseDialog.vue'
|
import BaseDialog from '@/components/common/BaseDialog.vue'
|
||||||
import {
|
import {
|
||||||
opsAPI,
|
opsAPI,
|
||||||
OPS_WS_CLOSE_CODES,
|
|
||||||
type OpsWSStatus,
|
|
||||||
type OpsDashboardOverview,
|
type OpsDashboardOverview,
|
||||||
type OpsErrorDistributionResponse,
|
type OpsErrorDistributionResponse,
|
||||||
type OpsErrorTrendResponse,
|
type OpsErrorTrendResponse,
|
||||||
@@ -174,14 +167,6 @@ const QUERY_KEYS = {
|
|||||||
const isApplyingRouteQuery = ref(false)
|
const isApplyingRouteQuery = ref(false)
|
||||||
const isSyncingRouteQuery = 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 dashboardFetchController: AbortController | null = null
|
||||||
let dashboardFetchSeq = 0
|
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 readQueryString = (key: string): string => {
|
||||||
const value = route.query[key]
|
const value = route.query[key]
|
||||||
if (typeof value === 'string') return value
|
if (typeof value === 'string') return value
|
||||||
@@ -626,12 +567,6 @@ onMounted(async () => {
|
|||||||
// Load thresholds configuration
|
// Load thresholds configuration
|
||||||
loadThresholds()
|
loadThresholds()
|
||||||
|
|
||||||
if (adminSettingsStore.opsRealtimeMonitoringEnabled) {
|
|
||||||
startQPSSubscription()
|
|
||||||
} else {
|
|
||||||
stopQPSSubscription({ resetMetrics: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opsEnabled.value) {
|
if (opsEnabled.value) {
|
||||||
await fetchData()
|
await fetchData()
|
||||||
}
|
}
|
||||||
@@ -648,19 +583,6 @@ async function loadThresholds() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
stopQPSSubscription()
|
|
||||||
abortDashboardFetch()
|
abortDashboardFetch()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
|
||||||
() => adminSettingsStore.opsRealtimeMonitoringEnabled,
|
|
||||||
(enabled) => {
|
|
||||||
if (!opsEnabled.value) return
|
|
||||||
if (enabled) {
|
|
||||||
startQPSSubscription()
|
|
||||||
} else {
|
|
||||||
stopQPSSubscription({ resetMetrics: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user