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
50132904
"...components/admin/git@web.lueluesay.top:chenxi/sub2api.git" did not exist on "99308ab4fb30925e17f83ba7c435d5599e9b3330"
Commit
50132904
authored
Jan 14, 2026
by
IanShaw027
Browse files
feat(frontend): 优化ops监控UI组件
parent
8cf3e9a6
Changes
4
Show whitespace changes
Inline
Side-by-side
frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
View file @
50132904
...
@@ -101,7 +101,7 @@
...
@@ -101,7 +101,7 @@
</div>
</div>
<!-- Suggestion -->
<!-- Suggestion -->
<div
class=
"rounded-xl bg-gray-50 p-6 dark:bg-dark-900"
>
<div
v-if=
"handlingSuggestion"
class=
"rounded-xl bg-gray-50 p-6 dark:bg-dark-900"
>
<h3
class=
"mb-4 text-sm font-black uppercase tracking-wider text-gray-900 dark:text-white"
>
{{
t
(
'
admin.ops.errorDetail.suggestion
'
)
||
'
Suggestion
'
}}
</h3>
<h3
class=
"mb-4 text-sm font-black uppercase tracking-wider text-gray-900 dark:text-white"
>
{{
t
(
'
admin.ops.errorDetail.suggestion
'
)
||
'
Suggestion
'
}}
</h3>
<div
class=
"text-sm font-medium text-gray-800 dark:text-gray-200 break-words"
>
<div
class=
"text-sm font-medium text-gray-800 dark:text-gray-200 break-words"
>
{{
handlingSuggestion
}}
{{
handlingSuggestion
}}
...
@@ -150,29 +150,6 @@
...
@@ -150,29 +150,6 @@
</div>
</div>
</div>
</div>
<!-- Retry summary -->
<div
class=
"rounded-xl bg-gray-50 p-6 dark:bg-dark-900"
>
<h3
class=
"mb-4 text-sm font-black uppercase tracking-wider text-gray-900 dark:text-white"
>
{{
t
(
'
admin.ops.errorDetail.retrySummary
'
)
||
'
Retry Summary
'
}}
</h3>
<div
class=
"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"
>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
total
</div>
<div
class=
"mt-1 text-sm font-bold text-gray-900 dark:text-white"
>
{{
retryHistory
.
length
}}
</div>
</div>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
succeeded
</div>
<div
class=
"mt-1 text-sm font-bold text-gray-900 dark:text-white"
>
{{
retryHistory
.
filter
(
r
=>
r
.
success
===
true
).
length
}}
</div>
</div>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
failed
</div>
<div
class=
"mt-1 text-sm font-bold text-gray-900 dark:text-white"
>
{{
retryHistory
.
filter
(
r
=>
r
.
success
===
false
).
length
}}
</div>
</div>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
last
</div>
<div
class=
"mt-1 font-mono text-xs text-gray-700 dark:text-gray-200"
>
{{
retryHistory
[
0
]?.
created_at
||
'
—
'
}}
</div>
</div>
</div>
</div>
<!-- Basic Info -->
<!-- Basic Info -->
<div
class=
"rounded-xl bg-gray-50 p-6 dark:bg-dark-900"
>
<div
class=
"rounded-xl bg-gray-50 p-6 dark:bg-dark-900"
>
<h3
class=
"mb-4 text-sm font-black uppercase tracking-wider text-gray-900 dark:text-white"
>
{{
t
(
'
admin.ops.errorDetail.basicInfo
'
)
}}
</h3>
<h3
class=
"mb-4 text-sm font-black uppercase tracking-wider text-gray-900 dark:text-white"
>
{{
t
(
'
admin.ops.errorDetail.basicInfo
'
)
}}
</h3>
...
@@ -186,9 +163,21 @@
...
@@ -186,9 +163,21 @@
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
{{
detail
.
model
||
'
—
'
}}
</div>
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
{{
detail
.
model
||
'
—
'
}}
</div>
</div>
</div>
<div>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
{{
t
(
'
admin.ops.errorDetail.latency
'
)
}}
</div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
{{
t
(
'
admin.ops.errorDetail.group
'
)
}}
</div>
<div
class=
"mt-1 font-mono text-sm font-bold text-gray-900 dark:text-white"
>
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
{{
detail
.
latency_ms
!=
null
?
`${detail.latency_ms
}
ms`
:
'
—
'
}}
<el-tooltip
v-if=
"detail.group_id"
:content=
"'ID: ' + detail.group_id"
placement=
"top"
>
<span>
{{
detail
.
group_name
||
detail
.
group_id
}}
</span>
</el-tooltip>
<span
v-else
>
—
</span>
</div>
</div>
<div>
<div
class=
"text-xs font-bold uppercase text-gray-400"
>
{{
t
(
'
admin.ops.errorDetail.account
'
)
}}
</div>
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
<el-tooltip
v-if=
"detail.account_id"
:content=
"'ID: ' + detail.account_id"
placement=
"top"
>
<span>
{{
detail
.
account_name
||
detail
.
account_id
}}
</span>
</el-tooltip>
<span
v-else
>
—
</span>
</div>
</div>
</div>
</div>
<div>
<div>
...
@@ -203,7 +192,7 @@
...
@@ -203,7 +192,7 @@
{{
detail
.
is_business_limited
?
'
true
'
:
'
false
'
}}
{{
detail
.
is_business_limited
?
'
true
'
:
'
false
'
}}
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
>
<
div
class
=
"
lg:col-span-2
"
>
<
div
class
=
"
text-xs font-bold uppercase text-gray-400
"
>
{{
t
(
'
admin.ops.errorDetail.requestPath
'
)
}}
<
/div
>
<
div
class
=
"
text-xs font-bold uppercase text-gray-400
"
>
{{
t
(
'
admin.ops.errorDetail.requestPath
'
)
}}
<
/div
>
<
div
class
=
"
mt-1 font-mono text-xs text-gray-700 dark:text-gray-200 break-all
"
>
<
div
class
=
"
mt-1 font-mono text-xs text-gray-700 dark:text-gray-200 break-all
"
>
{{
detail
.
request_path
||
'
—
'
}}
{{
detail
.
request_path
||
'
—
'
}}
...
@@ -343,11 +332,17 @@
...
@@ -343,11 +332,17 @@
<
/div
>
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"
mt-2 grid grid-cols-1 gap-2 text-xs text-gray-600 dark:text-gray-300 sm:grid-cols-3
"
>
<
div
class
=
"
mt-2 grid grid-cols-1 gap-2 text-xs text-gray-600 dark:text-gray-300 sm:grid-cols-2
"
>
<
div
><
span
class
=
"
text-gray-400
"
>
account_id
:
<
/span> <span class="font-mono">{{ ev.account_id
??
'—'
}}
</
span
><
/div
>
<
div
>
<
div
><
span
class
=
"
text-gray-400
"
>
status
:
<
/span> <span class="font-mono">{{ ev.upstream_status_code
??
'—'
}}
</
span
><
/div
>
<
span
class
=
"
text-gray-400
"
>
account
:
<
/span>
<
div
class
=
"
break-all
"
>
<
el
-
tooltip
v
-
if
=
"
ev.account_id
"
:
content
=
"
'ID: ' + ev.account_id
"
placement
=
"
top
"
>
<
span
class
=
"
text-gray-400
"
>
request_id
:
<
/span> <span class="font-mono">{{ ev.upstream_request_id || '—'
}}
</
span
>
<
span
class
=
"
font-medium text-gray-900 dark:text-white ml-1
"
>
{{
ev
.
account_name
||
ev
.
account_id
}}
<
/span
>
<
/el-tooltip
>
<
span
v
-
else
class
=
"
ml-1
"
>
—
<
/span
>
<
/div
>
<
div
><
span
class
=
"
text-gray-400
"
>
status
:
<
/span> <span class="font-mono ml-1">{{ ev.upstream_status_code
??
'—'
}}
</
span
><
/div
>
<
div
class
=
"
sm:col-span-2 break-all
"
>
<
span
class
=
"
text-gray-400
"
>
request_id
:
<
/span> <span class="font-mono ml-1">{{ ev.upstream_request_id || '—'
}}
</
span
>
<
/div
>
<
/div
>
<
/div
>
<
/div
>
...
@@ -426,13 +421,29 @@
...
@@ -426,13 +421,29 @@
<
div
v
-
if
=
"
selectedA || selectedB
"
class
=
"
grid grid-cols-1 gap-3 md:grid-cols-2
"
>
<
div
v
-
if
=
"
selectedA || selectedB
"
class
=
"
grid grid-cols-1 gap-3 md:grid-cols-2
"
>
<
div
class
=
"
rounded-xl border border-gray-200 bg-white p-4 dark:border-dark-700 dark:bg-dark-800
"
>
<
div
class
=
"
rounded-xl border border-gray-200 bg-white p-4 dark:border-dark-700 dark:bg-dark-800
"
>
<
div
class
=
"
text-xs font-black text-gray-900 dark:text-white
"
>
{{
selectedA
?
`#${selectedA.id
}
· ${selectedA.mode
}
· ${selectedA.status
}
`
:
'
—
'
}}
<
/div
>
<
div
class
=
"
text-xs font-black text-gray-900 dark:text-white
"
>
{{
selectedA
?
`#${selectedA.id
}
· ${selectedA.mode
}
· ${selectedA.status
}
`
:
'
—
'
}}
<
/div
>
<
div
class
=
"
mt-2 text-xs text-gray-600 dark:text-gray-300
"
>
http
:
<
span
class
=
"
font-mono
"
>
{{
selectedA
?.
http_status_code
??
'
—
'
}}
<
/span> · used: <span class="font-mono">{{ selectedA
?
.used_account_id
??
'—'
}}
</
span
><
/div
>
<
div
class
=
"
mt-2 text-xs text-gray-600 dark:text-gray-300
"
>
http
:
<
span
class
=
"
font-mono
"
>
{{
selectedA
?.
http_status_code
??
'
—
'
}}
<
/span> ·
used
:
<
span
class
=
"
font-mono
"
>
<
el
-
tooltip
v
-
if
=
"
selectedA?.used_account_id
"
:
content
=
"
'ID: ' + selectedA.used_account_id
"
placement
=
"
top
"
>
<
span
class
=
"
font-medium
"
>
{{
selectedA
.
used_account_name
||
selectedA
.
used_account_id
}}
<
/span
>
<
/el-tooltip
>
<
span
v
-
else
>
—
<
/span
>
<
/span
>
<
/div
>
<
pre
class
=
"
mt-3 max-h-[320px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
selectedA
?.
response_preview
||
''
}}
<
/code></
pre
>
<
pre
class
=
"
mt-3 max-h-[320px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
selectedA
?.
response_preview
||
''
}}
<
/code></
pre
>
<
div
v
-
if
=
"
selectedA?.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
selectedA
.
error_message
}}
<
/div
>
<
div
v
-
if
=
"
selectedA?.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
selectedA
.
error_message
}}
<
/div
>
<
/div
>
<
/div
>
<
div
class
=
"
rounded-xl border border-gray-200 bg-white p-4 dark:border-dark-700 dark:bg-dark-800
"
>
<
div
class
=
"
rounded-xl border border-gray-200 bg-white p-4 dark:border-dark-700 dark:bg-dark-800
"
>
<
div
class
=
"
text-xs font-black text-gray-900 dark:text-white
"
>
{{
selectedB
?
`#${selectedB.id
}
· ${selectedB.mode
}
· ${selectedB.status
}
`
:
'
—
'
}}
<
/div
>
<
div
class
=
"
text-xs font-black text-gray-900 dark:text-white
"
>
{{
selectedB
?
`#${selectedB.id
}
· ${selectedB.mode
}
· ${selectedB.status
}
`
:
'
—
'
}}
<
/div
>
<
div
class
=
"
mt-2 text-xs text-gray-600 dark:text-gray-300
"
>
http
:
<
span
class
=
"
font-mono
"
>
{{
selectedB
?.
http_status_code
??
'
—
'
}}
<
/span> · used: <span class="font-mono">{{ selectedB
?
.used_account_id
??
'—'
}}
</
span
><
/div
>
<
div
class
=
"
mt-2 text-xs text-gray-600 dark:text-gray-300
"
>
http
:
<
span
class
=
"
font-mono
"
>
{{
selectedB
?.
http_status_code
??
'
—
'
}}
<
/span> ·
used
:
<
span
class
=
"
font-mono
"
>
<
el
-
tooltip
v
-
if
=
"
selectedB?.used_account_id
"
:
content
=
"
'ID: ' + selectedB.used_account_id
"
placement
=
"
top
"
>
<
span
class
=
"
font-medium
"
>
{{
selectedB
.
used_account_name
||
selectedB
.
used_account_id
}}
<
/span
>
<
/el-tooltip
>
<
span
v
-
else
>
—
<
/span
>
<
/span
>
<
/div
>
<
pre
class
=
"
mt-3 max-h-[320px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
selectedB
?.
response_preview
||
''
}}
<
/code></
pre
>
<
pre
class
=
"
mt-3 max-h-[320px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
selectedB
?.
response_preview
||
''
}}
<
/code></
pre
>
<
div
v
-
if
=
"
selectedB?.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
selectedB
.
error_message
}}
<
/div
>
<
div
v
-
if
=
"
selectedB?.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
selectedB
.
error_message
}}
<
/div
>
<
/div
>
<
/div
>
...
@@ -447,8 +458,20 @@
...
@@ -447,8 +458,20 @@
<
div
class
=
"
mt-2 grid grid-cols-1 gap-2 text-xs text-gray-600 dark:text-gray-300 sm:grid-cols-4
"
>
<
div
class
=
"
mt-2 grid grid-cols-1 gap-2 text-xs text-gray-600 dark:text-gray-300 sm:grid-cols-4
"
>
<
div
><
span
class
=
"
text-gray-400
"
>
success
:
<
/span> <span class="font-mono">{{ a.success
??
'—'
}}
</
span
><
/div
>
<
div
><
span
class
=
"
text-gray-400
"
>
success
:
<
/span> <span class="font-mono">{{ a.success
??
'—'
}}
</
span
><
/div
>
<
div
><
span
class
=
"
text-gray-400
"
>
http
:
<
/span> <span class="font-mono">{{ a.http_status_code
??
'—'
}}
</
span
><
/div
>
<
div
><
span
class
=
"
text-gray-400
"
>
http
:
<
/span> <span class="font-mono">{{ a.http_status_code
??
'—'
}}
</
span
><
/div
>
<
div
><
span
class
=
"
text-gray-400
"
>
pinned
:
<
/span> <span class="font-mono">{{ a.pinned_account_id
??
'—'
}}
</
span
><
/div
>
<
div
>
<
div
><
span
class
=
"
text-gray-400
"
>
used
:
<
/span> <span class="font-mono">{{ a.used_account_id
??
'—'
}}
</
span
><
/div
>
<
span
class
=
"
text-gray-400
"
>
pinned
:
<
/span
>
<
el
-
tooltip
v
-
if
=
"
a.pinned_account_id
"
:
content
=
"
'ID: ' + a.pinned_account_id
"
placement
=
"
top
"
>
<
span
class
=
"
font-mono ml-1
"
>
{{
a
.
pinned_account_name
||
a
.
pinned_account_id
}}
<
/span
>
<
/el-tooltip
>
<
span
v
-
else
class
=
"
font-mono ml-1
"
>
—
<
/span
>
<
/div
>
<
div
>
<
span
class
=
"
text-gray-400
"
>
used
:
<
/span
>
<
el
-
tooltip
v
-
if
=
"
a.used_account_id
"
:
content
=
"
'ID: ' + a.used_account_id
"
placement
=
"
top
"
>
<
span
class
=
"
font-mono ml-1
"
>
{{
a
.
used_account_name
||
a
.
used_account_id
}}
<
/span
>
<
/el-tooltip
>
<
span
v
-
else
class
=
"
font-mono ml-1
"
>
—
<
/span
>
<
/div
>
<
/div
>
<
/div
>
<
pre
v
-
if
=
"
a.response_preview
"
class
=
"
mt-3 max-h-[240px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
a
.
response_preview
}}
<
/code></
pre
>
<
pre
v
-
if
=
"
a.response_preview
"
class
=
"
mt-3 max-h-[240px] overflow-auto rounded-lg bg-gray-50 p-3 text-xs text-gray-800 dark:bg-dark-900 dark:text-gray-100
"
><
code
>
{{
a
.
response_preview
}}
<
/code></
pre
>
<
div
v
-
if
=
"
a.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
a
.
error_message
}}
<
/div
>
<
div
v
-
if
=
"
a.error_message
"
class
=
"
mt-2 text-xs text-red-600 dark:text-red-400
"
>
{{
a
.
error_message
}}
<
/div
>
...
@@ -558,6 +581,7 @@ type UpstreamErrorEvent = {
...
@@ -558,6 +581,7 @@ type UpstreamErrorEvent = {
at_unix_ms
?:
number
at_unix_ms
?:
number
platform
?:
string
platform
?:
string
account_id
?:
number
account_id
?:
number
account_name
?:
string
upstream_status_code
?:
number
upstream_status_code
?:
number
upstream_request_id
?:
string
upstream_request_id
?:
string
kind
?:
string
kind
?:
string
...
...
frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue
View file @
50132904
...
@@ -33,14 +33,6 @@ const statusCode = ref<number | null>(null)
...
@@ -33,14 +33,6 @@ const statusCode = ref<number | null>(null)
const
phase
=
ref
<
string
>
(
''
)
const
phase
=
ref
<
string
>
(
''
)
const
errorOwner
=
ref
<
string
>
(
''
)
const
errorOwner
=
ref
<
string
>
(
''
)
const
resolvedStatus
=
ref
<
string
>
(
'
unresolved
'
)
const
resolvedStatus
=
ref
<
string
>
(
'
unresolved
'
)
const
accountIdInput
=
ref
<
string
>
(
''
)
const
accountId
=
computed
<
number
|
null
>
(()
=>
{
const
raw
=
String
(
accountIdInput
.
value
||
''
).
trim
()
if
(
!
raw
)
return
null
const
n
=
Number
.
parseInt
(
raw
,
10
)
return
Number
.
isFinite
(
n
)
&&
n
>
0
?
n
:
null
})
const
modalTitle
=
computed
(()
=>
{
const
modalTitle
=
computed
(()
=>
{
return
props
.
errorType
===
'
upstream
'
?
t
(
'
admin.ops.errorDetails.upstreamErrors
'
)
:
t
(
'
admin.ops.errorDetails.requestErrors
'
)
return
props
.
errorType
===
'
upstream
'
?
t
(
'
admin.ops.errorDetails.upstreamErrors
'
)
:
t
(
'
admin.ops.errorDetails.requestErrors
'
)
...
@@ -105,7 +97,6 @@ async function fetchErrorLogs() {
...
@@ -105,7 +97,6 @@ async function fetchErrorLogs() {
if
(
q
.
value
.
trim
())
params
.
q
=
q
.
value
.
trim
()
if
(
q
.
value
.
trim
())
params
.
q
=
q
.
value
.
trim
()
if
(
typeof
statusCode
.
value
===
'
number
'
)
params
.
status_codes
=
String
(
statusCode
.
value
)
if
(
typeof
statusCode
.
value
===
'
number
'
)
params
.
status_codes
=
String
(
statusCode
.
value
)
if
(
typeof
accountId
.
value
===
'
number
'
)
params
.
account_id
=
accountId
.
value
const
phaseVal
=
String
(
phase
.
value
||
''
).
trim
()
const
phaseVal
=
String
(
phase
.
value
||
''
).
trim
()
if
(
phaseVal
)
params
.
phase
=
phaseVal
if
(
phaseVal
)
params
.
phase
=
phaseVal
...
@@ -136,7 +127,6 @@ function resetFilters() {
...
@@ -136,7 +127,6 @@ function resetFilters() {
phase
.
value
=
props
.
errorType
===
'
upstream
'
?
'
upstream
'
:
''
phase
.
value
=
props
.
errorType
===
'
upstream
'
?
'
upstream
'
:
''
errorOwner
.
value
=
''
errorOwner
.
value
=
''
resolvedStatus
.
value
=
'
unresolved
'
resolvedStatus
.
value
=
'
unresolved
'
accountIdInput
.
value
=
''
page
.
value
=
1
page
.
value
=
1
fetchErrorLogs
()
fetchErrorLogs
()
}
}
...
@@ -189,15 +179,6 @@ watch(
...
@@ -189,15 +179,6 @@ watch(
fetchErrorLogs
()
fetchErrorLogs
()
}
}
)
)
watch
(
()
=>
accountId
.
value
,
()
=>
{
if
(
!
props
.
show
)
return
page
.
value
=
1
fetchErrorLogs
()
}
)
</
script
>
</
script
>
<
template
>
<
template
>
...
@@ -205,10 +186,9 @@ watch(
...
@@ -205,10 +186,9 @@ watch(
<div
class=
"flex h-full min-h-0 flex-col"
>
<div
class=
"flex h-full min-h-0 flex-col"
>
<!-- Filters -->
<!-- Filters -->
<div
class=
"mb-4 flex-shrink-0 border-b border-gray-200 pb-4 dark:border-dark-700"
>
<div
class=
"mb-4 flex-shrink-0 border-b border-gray-200 pb-4 dark:border-dark-700"
>
<div
class=
"flex flex-col gap-2"
>
<div
class=
"grid grid-cols-7 gap-2"
>
<!-- 第一行: 搜索框 -->
<div
class=
"col-span-2 compact-select"
>
<div
class=
"flex items-center gap-2"
>
<div
class=
"relative group"
>
<div
class=
"relative flex-1 group"
>
<div
class=
"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
>
<div
class=
"pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
>
<svg
<svg
class=
"h-3.5 w-3.5 text-gray-400 transition-colors group-focus-within:text-blue-500"
class=
"h-3.5 w-3.5 text-gray-400 transition-colors group-focus-within:text-blue-500"
...
@@ -228,42 +208,29 @@ watch(
...
@@ -228,42 +208,29 @@ watch(
</div>
</div>
</div>
</div>
<!-- 第二行: 筛选选项 -->
<div
class=
"compact-select"
>
<div
class=
"grid grid-cols-6 gap-2"
>
<Select
:model-value=
"statusCode"
:options=
"statusCodeSelectOptions"
@
update:model-value=
"statusCode = $event as any"
/>
<div
class=
"col-span-1"
>
<Select
:model-value=
"statusCode"
:options=
"statusCodeSelectOptions"
size=
"sm"
@
update:model-value=
"statusCode = $event as any"
/>
</div>
</div>
<div
class=
"co
l-span-1
"
>
<div
class=
"co
mpact-select
"
>
<Select
:model-value=
"phase"
:options=
"phaseSelectOptions"
size=
"sm"
@
update:model-value=
"phase = String($event ?? '')"
/>
<Select
:model-value=
"phase"
:options=
"phaseSelectOptions"
@
update:model-value=
"phase = String($event ?? '')"
/>
</div>
</div>
<div
class=
"co
l-span-1
"
>
<div
class=
"co
mpact-select
"
>
<Select
:model-value=
"errorOwner"
:options=
"ownerSelectOptions"
size=
"sm"
@
update:model-value=
"errorOwner = String($event ?? '')"
/>
<Select
:model-value=
"errorOwner"
:options=
"ownerSelectOptions"
@
update:model-value=
"errorOwner = String($event ?? '')"
/>
</div>
</div>
<div
class=
"co
l-span-1
"
>
<div
class=
"co
mpact-select
"
>
<Select
:model-value=
"resolvedStatus"
:options=
"resolvedSelectOptions"
size=
"sm"
@
update:model-value=
"resolvedStatus = String($event ?? 'unresolved')"
/>
<Select
:model-value=
"resolvedStatus"
:options=
"resolvedSelectOptions"
@
update:model-value=
"resolvedStatus = String($event ?? 'unresolved')"
/>
</div>
</div>
<div
class=
"col-span-1"
>
<div
class=
"flex items-center justify-end"
>
<input
v-model=
"accountIdInput"
type=
"text"
inputmode=
"numeric"
class=
"w-full rounded-lg border-gray-200 bg-gray-50/50 py-1.5 px-3 text-xs font-medium text-gray-700 transition-all focus:border-blue-500 focus:bg-white focus:ring-2 focus:ring-blue-500/10 dark:border-dark-700 dark:bg-dark-900 dark:text-gray-300 dark:focus:bg-dark-800"
:placeholder=
"t('admin.ops.errorDetails.accountIdPlaceholder')"
/>
</div>
<div
class=
"col-span-1 flex items-center justify-end"
>
<button
type=
"button"
class=
"rounded-lg bg-gray-100 px-3 py-1.5 text-xs font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-700 dark:text-gray-300 dark:hover:bg-dark-600"
@
click=
"resetFilters"
>
<button
type=
"button"
class=
"rounded-lg bg-gray-100 px-3 py-1.5 text-xs font-semibold text-gray-700 transition-colors hover:bg-gray-200 dark:bg-dark-700 dark:text-gray-300 dark:hover:bg-dark-600"
@
click=
"resetFilters"
>
{{
t
(
'
common.reset
'
)
}}
{{
t
(
'
common.reset
'
)
}}
</button>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Body -->
<!-- Body -->
<div
class=
"flex min-h-0 flex-1 flex-col"
>
<div
class=
"flex min-h-0 flex-1 flex-col"
>
...
@@ -286,3 +253,9 @@ watch(
...
@@ -286,3 +253,9 @@ watch(
</div>
</div>
</BaseDialog>
</BaseDialog>
</
template
>
</
template
>
<
style
>
.compact-select
.select-trigger
{
@apply
py-1.5
px-3
text-xs
rounded-lg;
}
</
style
>
frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
View file @
50132904
<
template
>
<
template
>
<div
class=
"flex h-full min-h-0 flex-col"
>
<div
class=
"flex h-full min-h-0 flex-col bg-white dark:bg-dark-900"
>
<!-- Loading State -->
<div
v-if=
"loading"
class=
"flex flex-1 items-center justify-center py-10"
>
<div
v-if=
"loading"
class=
"flex flex-1 items-center justify-center py-10"
>
<div
class=
"h-8 w-8 animate-spin rounded-full border-b-2 border-primary-600"
></div>
<div
class=
"h-8 w-8 animate-spin rounded-full border-b-2 border-primary-600"
></div>
</div>
</div>
<!-- Table Container -->
<div
v-else
class=
"flex min-h-0 flex-1 flex-col"
>
<div
v-else
class=
"flex min-h-0 flex-1 flex-col"
>
<div
class=
"min-h-0 flex-1 overflow-auto"
>
<div
class=
"min-h-0 flex-1 overflow-auto
border-b border-gray-200 dark:border-dark-700
"
>
<table
class=
"
min-
w-full
divide-y divide-gray-200 dark:divide-dark-70
0"
>
<table
class=
"w-full
border-separate border-spacing-
0"
>
<thead
class=
"sticky top-0 z-10 bg-gray-50
/50
dark:bg-dark-800
/50
"
>
<thead
class=
"sticky top-0 z-10 bg-gray-50 dark:bg-dark-800"
>
<tr>
<tr>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
{{
t
(
'
admin.ops.errorLog.time
'
)
}}
class=
"whitespace-nowrap px-6 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.timeId
'
)
}}
</th>
</th>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
class=
"whitespace-nowrap px-6 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.type
'
)
}}
{{
t
(
'
admin.ops.errorLog.type
'
)
}}
</th>
</th>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
{{
t
(
'
admin.ops.errorLog.platform
'
)
}}
class=
"whitespace-nowrap px-6 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.context
'
)
}}
</th>
</th>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
{{
t
(
'
admin.ops.errorLog.model
'
)
}}
class=
"whitespace-nowrap px-6 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
</th>
>
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.group
'
)
}}
</th>
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.account
'
)
}}
</th>
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.status
'
)
}}
{{
t
(
'
admin.ops.errorLog.status
'
)
}}
</th>
</th>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-left text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
class=
"px-6 py-4 text-left text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.message
'
)
}}
{{
t
(
'
admin.ops.errorLog.message
'
)
}}
</th>
</th>
<th
<th
class=
"border-b border-gray-200 px-4 py-2.5 text-right text-[11px] font-bold uppercase tracking-wider text-gray-500 dark:border-dark-700 dark:text-dark-400"
>
scope=
"col"
class=
"whitespace-nowrap px-6 py-4 text-right text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.latency
'
)
}}
</th>
<th
scope=
"col"
class=
"whitespace-nowrap px-6 py-4 text-right text-xs font-bold uppercase tracking-wider text-gray-500 dark:text-dark-400"
>
{{
t
(
'
admin.ops.errorLog.action
'
)
}}
{{
t
(
'
admin.ops.errorLog.action
'
)
}}
</th>
</th>
</tr>
</tr>
</thead>
</thead>
<tbody
class=
"divide-y divide-gray-100 dark:divide-dark-700"
>
<tbody
class=
"divide-y divide-gray-100 dark:divide-dark-700"
>
<tr
v-if=
"rows.length === 0"
class=
"bg-white dark:bg-dark-900"
>
<tr
v-if=
"rows.length === 0"
>
<td
colspan=
"
7
"
class=
"py-1
6
text-center text-sm text-gray-400 dark:text-dark-500"
>
<td
colspan=
"
9
"
class=
"py-1
2
text-center text-sm text-gray-400 dark:text-dark-500"
>
{{
t
(
'
admin.ops.errorLog.noErrors
'
)
}}
{{
t
(
'
admin.ops.errorLog.noErrors
'
)
}}
</td>
</td>
</tr>
</tr>
...
@@ -63,83 +50,73 @@
...
@@ -63,83 +50,73 @@
<tr
<tr
v-for=
"log in rows"
v-for=
"log in rows"
:key=
"log.id"
:key=
"log.id"
class=
"group cursor-pointer transition-all duration-200 hover:bg-gray-50/80 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:hover:bg-dark-800/50 dark:focus:ring-offset-dark-900"
class=
"group cursor-pointer transition-colors hover:bg-gray-50/80 dark:hover:bg-dark-800/50"
tabindex=
"0"
role=
"button"
@
click=
"emit('openErrorDetail', log.id)"
@
click=
"emit('openErrorDetail', log.id)"
@
keydown.enter.prevent=
"emit('openErrorDetail', log.id)"
@
keydown.space.prevent=
"emit('openErrorDetail', log.id)"
>
>
<!-- Time
& ID
-->
<!-- Time -->
<td
class=
"px-
6
py-
4
"
>
<td
class=
"
whitespace-nowrap
px-
4
py-
2
"
>
<
div
class=
"flex flex-col gap-0.5
"
>
<
el-tooltip
:content=
"log.request_id || log.client_request_id"
placement=
"top"
:show-after=
"500
"
>
<span
class=
"font-mono text-xs font-
bold
text-gray-900 dark:text-gray-200"
>
<span
class=
"font-mono text-xs font-
medium
text-gray-900 dark:text-gray-200"
>
{{
formatDateTime
(
log
.
created_at
).
split
(
'
'
)[
1
]
}}
{{
formatDateTime
(
log
.
created_at
).
split
(
'
'
)[
1
]
}}
</span>
</span>
<span
</el-tooltip>
class=
"font-mono text-[10px] text-gray-400 transition-colors group-hover:text-primary-600 dark:group-hover:text-primary-400"
:title=
"log.request_id || log.client_request_id"
>
{{
(
log
.
request_id
||
log
.
client_request_id
||
''
).
substring
(
0
,
12
)
}}
</span>
</div>
</td>
</td>
<!-- Type -->
<!-- Type -->
<td
class=
"px-6 py-4"
>
<td
class=
"whitespace-nowrap px-4 py-2"
>
<div
class=
"flex flex-col gap-1"
>
<span
<span
:class=
"[
:class=
"[
'inline-flex items-center rounded
-lg
px-
2
py-
1
text-
xs
font-b
lack
ring-1 ring-inset
shadow-sm
',
'inline-flex items-center rounded px-
1.5
py-
0.5
text-
[10px]
font-b
old
ring-1 ring-inset',
getTypeBadge(log).className
getTypeBadge(log).className
]"
]"
>
>
{{
getTypeBadge
(
log
).
label
}}
{{
getTypeBadge
(
log
).
label
}}
</span>
</span>
<div
class=
"flex flex-wrap gap-x-3 gap-y-1"
>
<div
v-if=
"(log as any).error_owner"
class=
"flex items-center gap-1"
>
<span
class=
"h-1 w-1 rounded-full bg-gray-300"
></span>
<span
class=
"text-[9px] font-black uppercase tracking-tighter text-gray-400"
>
{{
(
log
as
any
).
error_owner
}}
</span>
</div>
<div
v-if=
"(log as any).error_source"
class=
"flex items-center gap-1"
>
<span
class=
"h-1 w-1 rounded-full bg-gray-300"
></span>
<span
class=
"text-[9px] font-black uppercase tracking-tighter text-gray-400"
>
{{
(
log
as
any
).
error_source
}}
</span>
</div>
</div>
</div>
</td>
</td>
<!-- Context (Platform/Model) -->
<!-- Platform -->
<td
class=
"px-6 py-4"
>
<td
class=
"whitespace-nowrap px-4 py-2"
>
<div
class=
"flex flex-col items-start gap-1.5"
>
<span
class=
"inline-flex items-center rounded bg-gray-100 px-1.5 py-0.5 text-[10px] font-bold uppercase text-gray-600 dark:bg-dark-700 dark:text-gray-300"
>
<span
class=
"inline-flex items-center rounded-md bg-gray-100 px-2 py-0.5 text-[10px] font-bold uppercase tracking-tight text-gray-600 dark:bg-dark-700 dark:text-gray-300"
>
{{
log
.
platform
||
'
-
'
}}
{{
log
.
platform
||
'
-
'
}}
</span>
</span>
<span
</td>
v-if=
"log.model"
class=
"max-w-[160px] truncate font-mono text-[10px] text-gray-500 dark:text-dark-400"
<!-- Model -->
:title=
"log.model"
<td
class=
"px-4 py-2"
>
>
<div
class=
"max-w-[120px] truncate"
:title=
"log.model"
>
<span
v-if=
"log.model"
class=
"font-mono text-[11px] text-gray-700 dark:text-gray-300"
>
{{
log
.
model
}}
{{
log
.
model
}}
</span>
</span>
<div
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
v-if=
"log.group_id || log.account_id"
class=
"flex flex-wrap items-center gap-2 font-mono text-[10px] font-semibold text-gray-400 dark:text-dark-500"
>
<span
v-if=
"log.group_id"
>
{{
t
(
'
admin.ops.errorLog.grp
'
)
}}
{{
log
.
group_id
}}
</span>
<span
v-if=
"log.account_id"
>
{{
t
(
'
admin.ops.errorLog.acc
'
)
}}
{{
log
.
account_id
}}
</span>
</div>
</div>
</div>
</td>
</td>
<!-- Status & Severity -->
<!-- Group -->
<td
class=
"px-6 py-4"
>
<td
class=
"px-4 py-2"
>
<div
class=
"flex flex-wrap items-center gap-2"
>
<el-tooltip
v-if=
"log.group_id"
:content=
"'ID: ' + log.group_id"
placement=
"top"
:show-after=
"500"
>
<span
class=
"max-w-[100px] truncate text-xs font-medium text-gray-900 dark:text-gray-200"
>
{{
log
.
group_name
||
'
-
'
}}
</span>
</el-tooltip>
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
</td>
<!-- Account -->
<td
class=
"px-4 py-2"
>
<el-tooltip
v-if=
"log.account_id"
:content=
"'ID: ' + log.account_id"
placement=
"top"
:show-after=
"500"
>
<span
class=
"max-w-[100px] truncate text-xs font-medium text-gray-900 dark:text-gray-200"
>
{{
log
.
account_name
||
'
-
'
}}
</span>
</el-tooltip>
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
</td>
<!-- Status -->
<td
class=
"whitespace-nowrap px-4 py-2"
>
<div
class=
"flex items-center gap-1.5"
>
<span
<span
:class=
"[
:class=
"[
'inline-flex items-center rounded
-lg
px-
2
py-
1
text-
xs
font-b
lack
ring-1 ring-inset
shadow-sm
',
'inline-flex items-center rounded px-
1.5
py-
0.5
text-
[10px]
font-b
old
ring-1 ring-inset',
getStatusClass(log.status_code)
getStatusClass(log.status_code)
]"
]"
>
>
...
@@ -147,44 +124,25 @@
...
@@ -147,44 +124,25 @@
</span>
</span>
<span
<span
v-if=
"log.severity"
v-if=
"log.severity"
:class=
"['rounded
-md
px-
2
py-0.5 text-[10px] font-b
lack shadow-sm
', getSeverityClass(log.severity)]"
:class=
"['rounded px-
1.5
py-0.5 text-[10px] font-b
old
', getSeverityClass(log.severity)]"
>
>
{{
log
.
severity
}}
{{
log
.
severity
}}
</span>
</span>
</div>
</div>
</td>
</td>
<!-- Message -->
<!-- Message
(Response Content)
-->
<td
class=
"px-
6
py-
4
"
>
<td
class=
"px-
4
py-
2
"
>
<div
class=
"max-w-
md lg:max-w-2xl
"
>
<div
class=
"max-w-
[200px]
"
>
<p
class=
"truncate text-
xs font-semibold
text-gray-
7
00 dark:text-gray-
3
00"
:title=
"log.message"
>
<p
class=
"truncate text-
[11px] font-medium
text-gray-
6
00 dark:text-gray-
4
00"
:title=
"log.message"
>
{{
formatSmartMessage
(
log
.
message
)
||
'
-
'
}}
{{
formatSmartMessage
(
log
.
message
)
||
'
-
'
}}
</p>
</p>
<div
class=
"mt-1.5 flex flex-wrap gap-x-3 gap-y-1"
>
<div
v-if=
"log.phase"
class=
"flex items-center gap-1"
>
<span
class=
"h-1 w-1 rounded-full bg-gray-300"
></span>
<span
class=
"text-[9px] font-black uppercase tracking-tighter text-gray-400"
>
{{
log
.
phase
}}
</span>
</div>
<div
v-if=
"log.client_ip"
class=
"flex items-center gap-1"
>
<span
class=
"h-1 w-1 rounded-full bg-gray-300"
></span>
<span
class=
"text-[9px] font-mono font-bold text-gray-400"
>
{{
log
.
client_ip
}}
</span>
</div>
</div>
</div>
</td>
<!-- Latency -->
<td
class=
"px-6 py-4 text-right"
>
<div
class=
"flex flex-col items-end"
>
<span
class=
"font-mono text-xs font-black"
:class=
"getLatencyClass(log.latency_ms ?? null)"
>
{{
log
.
latency_ms
!=
null
?
Math
.
round
(
log
.
latency_ms
)
+
'
ms
'
:
'
--
'
}}
</span>
</div>
</div>
</td>
</td>
<!-- Actions -->
<!-- Actions -->
<td
class=
"px-
6
py-
4
text-right"
@
click.stop
>
<td
class=
"
whitespace-nowrap
px-
4
py-
2
text-right"
@
click.stop
>
<button
type=
"button"
class=
"
btn btn-secondary btn-sm
"
@
click=
"emit('openErrorDetail', log.id)"
>
<button
type=
"button"
class=
"
text-primary-600 hover:text-primary-700 dark:text-primary-400 text-xs font-bold
"
@
click=
"emit('openErrorDetail', log.id)"
>
{{
t
(
'
admin.ops.errorLog.details
'
)
}}
{{
t
(
'
admin.ops.errorLog.details
'
)
}}
</button>
</button>
</td>
</td>
...
@@ -193,6 +151,8 @@
...
@@ -193,6 +151,8 @@
</table>
</table>
</div>
</div>
<!-- Pagination -->
<div
class=
"bg-gray-50/50 dark:bg-dark-800/50"
>
<Pagination
<Pagination
v-if=
"total > 0"
v-if=
"total > 0"
:total=
"total"
:total=
"total"
...
@@ -204,6 +164,7 @@
...
@@ -204,6 +164,7 @@
/>
/>
</div>
</div>
</div>
</div>
</div>
</
template
>
</
template
>
<
script
setup
lang=
"ts"
>
<
script
setup
lang=
"ts"
>
...
@@ -212,39 +173,32 @@ import Pagination from '@/components/common/Pagination.vue'
...
@@ -212,39 +173,32 @@ import Pagination from '@/components/common/Pagination.vue'
import
type
{
OpsErrorLog
}
from
'
@/api/admin/ops
'
import
type
{
OpsErrorLog
}
from
'
@/api/admin/ops
'
import
{
getSeverityClass
,
formatDateTime
}
from
'
../utils/opsFormatters
'
import
{
getSeverityClass
,
formatDateTime
}
from
'
../utils/opsFormatters
'
const
{
t
}
=
useI18n
()
function
getTypeBadge
(
log
:
OpsErrorLog
):
{
label
:
string
;
className
:
string
}
{
function
getTypeBadge
(
log
:
OpsErrorLog
):
{
label
:
string
;
className
:
string
}
{
const
phase
=
String
(
log
.
phase
||
''
).
toLowerCase
()
const
phase
=
String
(
log
.
phase
||
''
).
toLowerCase
()
const
owner
=
String
(
(
log
as
any
)
.
error_owner
||
''
).
toLowerCase
()
const
owner
=
String
(
log
.
error_owner
||
''
).
toLowerCase
()
// Mapping aligned with the design:
// - upstream/provider => 🔴 上游
// - request/client => 🟡 请求
// - auth/client => 🔵 认证
// - routing/platform => 🟣 路由
// - internal/platform => ⚫ 内部
if
(
phase
===
'
upstream
'
&&
owner
===
'
provider
'
)
{
if
(
phase
===
'
upstream
'
&&
owner
===
'
provider
'
)
{
return
{
label
:
'
🔴 上游
'
,
className
:
'
bg-red-50 text-red-700 ring-red-600/20 dark:bg-red-900/30 dark:text-red-400 dark:ring-red-500/30
'
}
return
{
label
:
t
(
'
admin.ops.errorLog.typeUpstream
'
)
,
className
:
'
bg-red-50 text-red-700 ring-red-600/20 dark:bg-red-900/30 dark:text-red-400 dark:ring-red-500/30
'
}
}
}
if
(
phase
===
'
request
'
&&
owner
===
'
client
'
)
{
if
(
phase
===
'
request
'
&&
owner
===
'
client
'
)
{
return
{
label
:
'
🟡 请求
'
,
className
:
'
bg-amber-50 text-amber-700 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-400 dark:ring-amber-500/30
'
}
return
{
label
:
t
(
'
admin.ops.errorLog.typeRequest
'
)
,
className
:
'
bg-amber-50 text-amber-700 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-400 dark:ring-amber-500/30
'
}
}
}
if
(
phase
===
'
auth
'
&&
owner
===
'
client
'
)
{
if
(
phase
===
'
auth
'
&&
owner
===
'
client
'
)
{
return
{
label
:
'
🔵 认证
'
,
className
:
'
bg-blue-50 text-blue-700 ring-blue-600/20 dark:bg-blue-900/30 dark:text-blue-400 dark:ring-blue-500/30
'
}
return
{
label
:
t
(
'
admin.ops.errorLog.typeAuth
'
)
,
className
:
'
bg-blue-50 text-blue-700 ring-blue-600/20 dark:bg-blue-900/30 dark:text-blue-400 dark:ring-blue-500/30
'
}
}
}
if
(
phase
===
'
routing
'
&&
owner
===
'
platform
'
)
{
if
(
phase
===
'
routing
'
&&
owner
===
'
platform
'
)
{
return
{
label
:
'
🟣 路由
'
,
className
:
'
bg-purple-50 text-purple-700 ring-purple-600/20 dark:bg-purple-900/30 dark:text-purple-400 dark:ring-purple-500/30
'
}
return
{
label
:
t
(
'
admin.ops.errorLog.typeRouting
'
)
,
className
:
'
bg-purple-50 text-purple-700 ring-purple-600/20 dark:bg-purple-900/30 dark:text-purple-400 dark:ring-purple-500/30
'
}
}
}
if
(
phase
===
'
internal
'
&&
owner
===
'
platform
'
)
{
if
(
phase
===
'
internal
'
&&
owner
===
'
platform
'
)
{
return
{
label
:
'
⚫ 内部
'
,
className
:
'
bg-gray-100 text-gray-800 ring-gray-600/20 dark:bg-dark-700 dark:text-gray-200 dark:ring-dark-500/40
'
}
return
{
label
:
t
(
'
admin.ops.errorLog.typeInternal
'
)
,
className
:
'
bg-gray-100 text-gray-800 ring-gray-600/20 dark:bg-dark-700 dark:text-gray-200 dark:ring-dark-500/40
'
}
}
}
// Fallback: show phase/owner for unknown combos.
const
fallback
=
phase
||
owner
||
'
unknown
'
const
fallback
=
phase
||
owner
||
'
unknown
'
return
{
label
:
fallback
,
className
:
'
bg-gray-50 text-gray-700 ring-gray-600/10 dark:bg-dark-900 dark:text-gray-300 dark:ring-dark-700
'
}
return
{
label
:
fallback
,
className
:
'
bg-gray-50 text-gray-700 ring-gray-600/10 dark:bg-dark-900 dark:text-gray-300 dark:ring-dark-700
'
}
}
}
const
{
t
}
=
useI18n
()
interface
Props
{
interface
Props
{
rows
:
OpsErrorLog
[]
rows
:
OpsErrorLog
[]
total
:
number
total
:
number
...
@@ -269,14 +223,6 @@ function getStatusClass(code: number): string {
...
@@ -269,14 +223,6 @@ function getStatusClass(code: number): string {
return
'
bg-gray-50 text-gray-700 ring-gray-600/20 dark:bg-gray-900/30 dark:text-gray-400 dark:ring-gray-500/30
'
return
'
bg-gray-50 text-gray-700 ring-gray-600/20 dark:bg-gray-900/30 dark:text-gray-400 dark:ring-gray-500/30
'
}
}
function
getLatencyClass
(
latency
:
number
|
null
):
string
{
if
(
!
latency
)
return
'
text-gray-400
'
if
(
latency
>
10000
)
return
'
text-red-600 font-black
'
if
(
latency
>
5000
)
return
'
text-red-500 font-bold
'
if
(
latency
>
2000
)
return
'
text-orange-500 font-medium
'
return
'
text-gray-600 dark:text-gray-400
'
}
function
formatSmartMessage
(
msg
:
string
):
string
{
function
formatSmartMessage
(
msg
:
string
):
string
{
if
(
!
msg
)
return
''
if
(
!
msg
)
return
''
...
...
frontend/src/views/admin/ops/components/OpsSettingsDialog.vue
View file @
50132904
...
@@ -480,11 +480,31 @@ async function saveAllSettings() {
...
@@ -480,11 +480,31 @@ async function saveAllSettings() {
<div>
<div>
<label
class=
"text-sm font-medium text-gray-700 dark:text-gray-300"
>
忽略 count_tokens 错误
</label>
<label
class=
"text-sm font-medium text-gray-700 dark:text-gray-300"
>
忽略 count_tokens 错误
</label>
<p
class=
"mt-1 text-xs text-gray-500"
>
<p
class=
"mt-1 text-xs text-gray-500"
>
启用后,count_tokens 请求的错误将不
计入运维监控的统计和告警中(但仍会存储在数据库中)
启用后,count_tokens 请求的错误将不
会写入错误日志
</p>
</p>
</div>
</div>
<Toggle
v-model=
"advancedSettings.ignore_count_tokens_errors"
/>
<Toggle
v-model=
"advancedSettings.ignore_count_tokens_errors"
/>
</div>
</div>
<div
class=
"flex items-center justify-between"
>
<div>
<label
class=
"text-sm font-medium text-gray-700 dark:text-gray-300"
>
忽略客户端断连错误
</label>
<p
class=
"mt-1 text-xs text-gray-500"
>
启用后,客户端主动断开连接(context canceled)的错误将不会写入错误日志
</p>
</div>
<Toggle
v-model=
"advancedSettings.ignore_context_canceled"
/>
</div>
<div
class=
"flex items-center justify-between"
>
<div>
<label
class=
"text-sm font-medium text-gray-700 dark:text-gray-300"
>
忽略无可用账号错误
</label>
<p
class=
"mt-1 text-xs text-gray-500"
>
启用后,"No available accounts" 错误将不会写入错误日志(不推荐,这通常是配置问题)
</p>
</div>
<Toggle
v-model=
"advancedSettings.ignore_no_available_accounts"
/>
</div>
</div>
</div>
<!-- 自动刷新 -->
<!-- 自动刷新 -->
...
...
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