Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
5443efd7
Commit
5443efd7
authored
Jan 12, 2026
by
IanShaw027
Browse files
feat(ops): 前端集成实时流量功能
- 添加实时流量API调用方法 - 优化OpsDashboard组件代码
parent
62771583
Changes
2
Show whitespace changes
Inline
Side-by-side
frontend/src/api/admin/ops.ts
View file @
5443efd7
...
...
@@ -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
,
...
...
frontend/src/views/admin/ops/OpsDashboard.vue
View file @
5443efd7
...
...
@@ -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
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment