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
fa68cbad
Unverified
Commit
fa68cbad
authored
Mar 24, 2026
by
InCerryGit
Committed by
GitHub
Mar 24, 2026
Browse files
Merge branch 'Wei-Shaw:main' into main
parents
995ef134
0f033930
Changes
87
Hide whitespace changes
Inline
Side-by-side
frontend/src/i18n/locales/en.ts
View file @
fa68cbad
...
...
@@ -1979,6 +1979,8 @@ export default {
expiresAt: 'Expires At',
actions: 'Actions'
},
allPrivacyModes: 'All Privacy States',
privacyUnset: 'Unset',
privacyTrainingOff: 'Training data sharing disabled',
privacyCfBlocked: 'Blocked by Cloudflare, training may still be on',
privacyFailed: 'Failed to disable training',
...
...
@@ -3494,7 +3496,12 @@ export default {
typeRequest: 'Request',
typeAuth: 'Auth',
typeRouting: 'Routing',
typeInternal
:
'
Internal
'
typeInternal: 'Internal',
endpoint: 'Endpoint',
requestType: 'Type',
requestTypeSync: 'Sync',
requestTypeStream: 'Stream',
requestTypeWs: 'WS'
},
// Error Details Modal
errorDetails: {
...
...
@@ -3580,6 +3587,16 @@ export default {
latency: 'Request Duration',
businessLimited: 'Business Limited',
requestPath: 'Request Path',
inboundEndpoint: 'Inbound Endpoint',
upstreamEndpoint: 'Upstream Endpoint',
requestedModel: 'Requested Model',
upstreamModel: 'Upstream Model',
requestType: 'Request Type',
requestTypeUnknown: 'Unknown',
requestTypeSync: 'Sync',
requestTypeStream: 'Stream',
requestTypeWs: 'WebSocket',
modelMapping: 'Model Mapping',
timings: 'Timings',
auth: 'Auth',
routing: 'Routing',
...
...
frontend/src/i18n/locales/zh.ts
View file @
fa68cbad
...
...
@@ -2017,6 +2017,8 @@ export default {
expiresAt
:
'
过期时间
'
,
actions
:
'
操作
'
},
allPrivacyModes
:
'
全部Privacy状态
'
,
privacyUnset
:
'
未设置
'
,
privacyTrainingOff
:
'
已关闭训练数据共享
'
,
privacyCfBlocked
:
'
被 Cloudflare 拦截,训练可能仍开启
'
,
privacyFailed
:
'
关闭训练数据共享失败
'
,
...
...
@@ -3659,7 +3661,12 @@ export default {
typeRequest
:
'
请求
'
,
typeAuth
:
'
认证
'
,
typeRouting
:
'
路由
'
,
typeInternal
:
'
内部
'
typeInternal
:
'
内部
'
,
endpoint
:
'
端点
'
,
requestType
:
'
类型
'
,
requestTypeSync
:
'
同步
'
,
requestTypeStream
:
'
流式
'
,
requestTypeWs
:
'
WS
'
},
// Error Details Modal
errorDetails
:
{
...
...
@@ -3745,6 +3752,16 @@ export default {
latency
:
'
请求时长
'
,
businessLimited
:
'
业务限制
'
,
requestPath
:
'
请求路径
'
,
inboundEndpoint
:
'
入站端点
'
,
upstreamEndpoint
:
'
上游端点
'
,
requestedModel
:
'
请求模型
'
,
upstreamModel
:
'
上游模型
'
,
requestType
:
'
请求类型
'
,
requestTypeUnknown
:
'
未知
'
,
requestTypeSync
:
'
同步
'
,
requestTypeStream
:
'
流式
'
,
requestTypeWs
:
'
WebSocket
'
,
modelMapping
:
'
模型映射
'
,
timings
:
'
时序信息
'
,
auth
:
'
认证
'
,
routing
:
'
路由
'
,
...
...
frontend/src/views/admin/AccountsView.vue
View file @
fa68cbad
...
...
@@ -581,7 +581,7 @@ const {
handlePageSizeChange
:
baseHandlePageSizeChange
}
=
useTableLoader
<
Account
,
any
>
({
fetchFn
:
adminAPI
.
accounts
.
list
,
initialParams
:
{
platform
:
''
,
type
:
''
,
status
:
''
,
group
:
''
,
search
:
''
}
initialParams
:
{
platform
:
''
,
type
:
''
,
status
:
''
,
privacy_mode
:
''
,
group
:
''
,
search
:
''
}
}
)
const
{
...
...
@@ -758,6 +758,7 @@ const refreshAccountsIncrementally = async () => {
platform
?:
string
type
?:
string
status
?:
string
privacy_mode
?:
string
group
?:
string
search
?:
string
...
...
frontend/src/views/admin/SettingsView.vue
View file @
fa68cbad
...
...
@@ -1655,7 +1655,7 @@
<
button
type
=
"
button
"
@
click
=
"
testSmtpConnection
"
:
disabled
=
"
testingSmtp
"
:
disabled
=
"
testingSmtp
|| loadFailed
"
class
=
"
btn btn-secondary btn-sm
"
>
<
svg
v
-
if
=
"
testingSmtp
"
class
=
"
h-4 w-4 animate-spin
"
fill
=
"
none
"
viewBox
=
"
0 0 24 24
"
>
...
...
@@ -1725,6 +1725,11 @@
v
-
model
=
"
form.smtp_password
"
type
=
"
password
"
class
=
"
input
"
autocomplete
=
"
new-password
"
autocapitalize
=
"
off
"
spellcheck
=
"
false
"
@
keydown
=
"
smtpPasswordManuallyEdited = true
"
@
paste
=
"
smtpPasswordManuallyEdited = true
"
:
placeholder
=
"
form.smtp_password_configured
? t('admin.settings.smtp.passwordConfiguredPlaceholder')
...
...
@@ -1807,7 +1812,7 @@
<
button
type
=
"
button
"
@
click
=
"
sendTestEmail
"
:
disabled
=
"
sendingTestEmail || !testEmailAddress
"
:
disabled
=
"
sendingTestEmail || !testEmailAddress
|| loadFailed
"
class
=
"
btn btn-secondary
"
>
<
svg
...
...
@@ -1853,7 +1858,7 @@
<!--
Save
Button
-->
<
div
v
-
show
=
"
activeTab !== 'backup' && activeTab !== 'data'
"
class
=
"
flex justify-end
"
>
<
button
type
=
"
submit
"
:
disabled
=
"
saving
"
class
=
"
btn btn-primary
"
>
<
button
type
=
"
submit
"
:
disabled
=
"
saving
|| loadFailed
"
class
=
"
btn btn-primary
"
>
<
svg
v
-
if
=
"
saving
"
class
=
"
h-4 w-4 animate-spin
"
fill
=
"
none
"
viewBox
=
"
0 0 24 24
"
>
<
circle
class
=
"
opacity-25
"
...
...
@@ -1924,9 +1929,11 @@ const settingsTabs = [
const
{
copyToClipboard
}
=
useClipboard
()
const
loading
=
ref
(
true
)
const
loadFailed
=
ref
(
false
)
const
saving
=
ref
(
false
)
const
testingSmtp
=
ref
(
false
)
const
sendingTestEmail
=
ref
(
false
)
const
smtpPasswordManuallyEdited
=
ref
(
false
)
const
testEmailAddress
=
ref
(
''
)
const
registrationEmailSuffixWhitelistTags
=
ref
<
string
[]
>
([])
const
registrationEmailSuffixWhitelistDraft
=
ref
(
''
)
...
...
@@ -2201,6 +2208,7 @@ function removeEndpoint(index: number) {
async
function
loadSettings
()
{
loading
.
value
=
true
loadFailed
.
value
=
false
try
{
const
settings
=
await
adminAPI
.
settings
.
getSettings
()
Object
.
assign
(
form
,
settings
)
...
...
@@ -2218,9 +2226,11 @@ async function loadSettings() {
)
registrationEmailSuffixWhitelistDraft
.
value
=
''
form
.
smtp_password
=
''
smtpPasswordManuallyEdited
.
value
=
false
form
.
turnstile_secret_key
=
''
form
.
linuxdo_connect_client_secret
=
''
}
catch
(
error
:
any
)
{
loadFailed
.
value
=
true
appStore
.
showError
(
t
(
'
admin.settings.failedToLoad
'
)
+
'
:
'
+
(
error
.
message
||
t
(
'
common.unknownError
'
))
)
...
...
@@ -2372,6 +2382,7 @@ async function saveSettings() {
)
registrationEmailSuffixWhitelistDraft
.
value
=
''
form
.
smtp_password
=
''
smtpPasswordManuallyEdited
.
value
=
false
form
.
turnstile_secret_key
=
''
form
.
linuxdo_connect_client_secret
=
''
// Refresh cached settings so sidebar/header update immediately
...
...
@@ -2390,11 +2401,12 @@ async function saveSettings() {
async
function
testSmtpConnection
()
{
testingSmtp
.
value
=
true
try
{
const
smtpPasswordForTest
=
smtpPasswordManuallyEdited
.
value
?
form
.
smtp_password
:
''
const
result
=
await
adminAPI
.
settings
.
testSmtpConnection
({
smtp_host
:
form
.
smtp_host
,
smtp_port
:
form
.
smtp_port
,
smtp_username
:
form
.
smtp_username
,
smtp_password
:
form
.
smtp
_p
assword
,
smtp_password
:
smtp
P
assword
ForTest
,
smtp_use_tls
:
form
.
smtp_use_tls
}
)
// API returns
{
message
:
"
...
"
}
on
success
,
errors
are
thrown
as
exceptions
...
...
@@ -2416,12 +2428,13 @@ async function sendTestEmail() {
sendingTestEmail
.
value
=
true
try
{
const
smtpPasswordForSend
=
smtpPasswordManuallyEdited
.
value
?
form
.
smtp_password
:
''
const
result
=
await
adminAPI
.
settings
.
sendTestEmail
({
email
:
testEmailAddress
.
value
,
smtp_host
:
form
.
smtp_host
,
smtp_port
:
form
.
smtp_port
,
smtp_username
:
form
.
smtp_username
,
smtp_password
:
form
.
smtp
_p
assword
,
smtp_password
:
smtp
P
assword
ForSend
,
smtp_from_email
:
form
.
smtp_from_email
,
smtp_from_name
:
form
.
smtp_from_name
,
smtp_use_tls
:
form
.
smtp_use_tls
...
...
frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
View file @
fa68cbad
...
...
@@ -59,7 +59,28 @@
<div
class=
"rounded-xl bg-gray-50 p-4 dark:bg-dark-900"
>
<div
class=
"text-xs font-bold uppercase tracking-wider text-gray-400"
>
{{ t('admin.ops.errorDetail.model') }}
</div>
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
{{ detail.model || '—' }}
<
template
v-if=
"hasModelMapping(detail)"
>
<span
class=
"font-mono"
>
{{
detail
.
requested_model
}}
</span>
<span
class=
"mx-1 text-gray-400"
>
→
</span>
<span
class=
"font-mono text-primary-600 dark:text-primary-400"
>
{{
detail
.
upstream_model
}}
</span>
</
template
>
<
template
v-else
>
{{
displayModel
(
detail
)
||
'
—
'
}}
</
template
>
</div>
</div>
<div
class=
"rounded-xl bg-gray-50 p-4 dark:bg-dark-900"
>
<div
class=
"text-xs font-bold uppercase tracking-wider text-gray-400"
>
{{ t('admin.ops.errorDetail.inboundEndpoint') }}
</div>
<div
class=
"mt-1 break-all font-mono text-sm font-medium text-gray-900 dark:text-white"
>
{{ detail.inbound_endpoint || '—' }}
</div>
</div>
<div
class=
"rounded-xl bg-gray-50 p-4 dark:bg-dark-900"
>
<div
class=
"text-xs font-bold uppercase tracking-wider text-gray-400"
>
{{ t('admin.ops.errorDetail.upstreamEndpoint') }}
</div>
<div
class=
"mt-1 break-all font-mono text-sm font-medium text-gray-900 dark:text-white"
>
{{ detail.upstream_endpoint || '—' }}
</div>
</div>
...
...
@@ -72,6 +93,13 @@
</div>
</div>
<div
class=
"rounded-xl bg-gray-50 p-4 dark:bg-dark-900"
>
<div
class=
"text-xs font-bold uppercase tracking-wider text-gray-400"
>
{{ t('admin.ops.errorDetail.requestType') }}
</div>
<div
class=
"mt-1 text-sm font-medium text-gray-900 dark:text-white"
>
{{ formatRequestTypeLabel(detail.request_type) }}
</div>
</div>
<div
class=
"rounded-xl bg-gray-50 p-4 dark:bg-dark-900"
>
<div
class=
"text-xs font-bold uppercase tracking-wider text-gray-400"
>
{{ t('admin.ops.errorDetail.message') }}
</div>
<div
class=
"mt-1 truncate text-sm font-medium text-gray-900 dark:text-white"
:title=
"detail.message"
>
...
...
@@ -213,6 +241,31 @@ function isUpstreamError(d: OpsErrorDetail | null): boolean {
return
phase
===
'
upstream
'
&&
owner
===
'
provider
'
}
function
formatRequestTypeLabel
(
type
:
number
|
null
|
undefined
):
string
{
switch
(
type
)
{
case
1
:
return
t
(
'
admin.ops.errorDetail.requestTypeSync
'
)
case
2
:
return
t
(
'
admin.ops.errorDetail.requestTypeStream
'
)
case
3
:
return
t
(
'
admin.ops.errorDetail.requestTypeWs
'
)
default
:
return
t
(
'
admin.ops.errorDetail.requestTypeUnknown
'
)
}
}
function
hasModelMapping
(
d
:
OpsErrorDetail
|
null
):
boolean
{
if
(
!
d
)
return
false
const
requested
=
String
(
d
.
requested_model
||
''
).
trim
()
const
upstream
=
String
(
d
.
upstream_model
||
''
).
trim
()
return
!!
requested
&&
!!
upstream
&&
requested
!==
upstream
}
function
displayModel
(
d
:
OpsErrorDetail
|
null
):
string
{
if
(
!
d
)
return
''
const
upstream
=
String
(
d
.
upstream_model
||
''
).
trim
()
if
(
upstream
)
return
upstream
const
requested
=
String
(
d
.
requested_model
||
''
).
trim
()
if
(
requested
)
return
requested
return
String
(
d
.
model
||
''
).
trim
()
}
const
correlatedUpstream
=
ref
<
OpsErrorDetail
[]
>
([])
const
correlatedUpstreamLoading
=
ref
(
false
)
...
...
frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
View file @
fa68cbad
...
...
@@ -17,6 +17,9 @@
<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.type
'
)
}}
</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.endpoint
'
)
}}
</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.platform
'
)
}}
</th>
...
...
@@ -42,7 +45,7 @@
</thead>
<tbody
class=
"divide-y divide-gray-100 dark:divide-dark-700"
>
<tr
v-if=
"rows.length === 0"
>
<td
colspan=
"
9
"
class=
"py-12 text-center text-sm text-gray-400 dark:text-dark-500"
>
<td
colspan=
"
10
"
class=
"py-12 text-center text-sm text-gray-400 dark:text-dark-500"
>
{{
t
(
'
admin.ops.errorLog.noErrors
'
)
}}
</td>
</tr>
...
...
@@ -74,6 +77,18 @@
</span>
</td>
<!-- Endpoint -->
<td
class=
"px-4 py-2"
>
<div
class=
"max-w-[160px]"
>
<el-tooltip
v-if=
"log.inbound_endpoint"
:content=
"formatEndpointTooltip(log)"
placement=
"top"
:show-after=
"500"
>
<span
class=
"truncate font-mono text-[11px] text-gray-700 dark:text-gray-300"
>
{{
log
.
inbound_endpoint
}}
</span>
</el-tooltip>
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
</div>
</td>
<!-- Platform -->
<td
class=
"whitespace-nowrap px-4 py-2"
>
<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"
>
...
...
@@ -83,11 +98,22 @@
<!-- 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
}}
</span>
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
<div
class=
"max-w-[160px]"
>
<template
v-if=
"hasModelMapping(log)"
>
<el-tooltip
:content=
"modelMappingTooltip(log)"
placement=
"top"
:show-after=
"500"
>
<span
class=
"flex items-center gap-1 truncate font-mono text-[11px] text-gray-700 dark:text-gray-300"
>
<span
class=
"truncate"
>
{{
log
.
requested_model
}}
</span>
<span
class=
"flex-shrink-0 text-gray-400"
>
→
</span>
<span
class=
"truncate text-primary-600 dark:text-primary-400"
>
{{
log
.
upstream_model
}}
</span>
</span>
</el-tooltip>
</
template
>
<
template
v-else
>
<span
v-if=
"displayModel(log)"
class=
"truncate font-mono text-[11px] text-gray-700 dark:text-gray-300"
:title=
"displayModel(log)"
>
{{
displayModel
(
log
)
}}
</span>
<span
v-else
class=
"text-xs text-gray-400"
>
-
</span>
</
template
>
</div>
</td>
...
...
@@ -138,6 +164,12 @@
>
{{ log.severity }}
</span>
<span
v-if=
"log.request_type != null && log.request_type > 0"
class=
"rounded bg-gray-100 px-1.5 py-0.5 text-[10px] font-bold text-gray-600 dark:bg-dark-700 dark:text-gray-300"
>
{{ formatRequestType(log.request_type) }}
</span>
</div>
</td>
...
...
@@ -193,6 +225,44 @@ function isUpstreamRow(log: OpsErrorLog): boolean {
return
phase
===
'
upstream
'
&&
owner
===
'
provider
'
}
function
formatEndpointTooltip
(
log
:
OpsErrorLog
):
string
{
const
parts
:
string
[]
=
[]
if
(
log
.
inbound_endpoint
)
parts
.
push
(
`Inbound:
${
log
.
inbound_endpoint
}
`
)
if
(
log
.
upstream_endpoint
)
parts
.
push
(
`Upstream:
${
log
.
upstream_endpoint
}
`
)
return
parts
.
join
(
'
\n
'
)
||
''
}
function
hasModelMapping
(
log
:
OpsErrorLog
):
boolean
{
const
requested
=
String
(
log
.
requested_model
||
''
).
trim
()
const
upstream
=
String
(
log
.
upstream_model
||
''
).
trim
()
return
!!
requested
&&
!!
upstream
&&
requested
!==
upstream
}
function
modelMappingTooltip
(
log
:
OpsErrorLog
):
string
{
const
requested
=
String
(
log
.
requested_model
||
''
).
trim
()
const
upstream
=
String
(
log
.
upstream_model
||
''
).
trim
()
if
(
!
requested
&&
!
upstream
)
return
''
if
(
requested
&&
upstream
)
return
`
${
requested
}
→
${
upstream
}
`
return
upstream
||
requested
}
function
displayModel
(
log
:
OpsErrorLog
):
string
{
const
upstream
=
String
(
log
.
upstream_model
||
''
).
trim
()
if
(
upstream
)
return
upstream
const
requested
=
String
(
log
.
requested_model
||
''
).
trim
()
if
(
requested
)
return
requested
return
String
(
log
.
model
||
''
).
trim
()
}
function
formatRequestType
(
type
:
number
|
null
|
undefined
):
string
{
switch
(
type
)
{
case
1
:
return
t
(
'
admin.ops.errorLog.requestTypeSync
'
)
case
2
:
return
t
(
'
admin.ops.errorLog.requestTypeStream
'
)
case
3
:
return
t
(
'
admin.ops.errorLog.requestTypeWs
'
)
default
:
return
''
}
}
function
getTypeBadge
(
log
:
OpsErrorLog
):
{
label
:
string
;
className
:
string
}
{
const
phase
=
String
(
log
.
phase
||
''
).
toLowerCase
()
const
owner
=
String
(
log
.
error_owner
||
''
).
toLowerCase
()
...
...
@@ -263,4 +333,4 @@ function formatSmartMessage(msg: string): string {
return
msg
.
length
>
200
?
msg
.
substring
(
0
,
200
)
+
'
...
'
:
msg
}
</
script
>
\ No newline at end of file
</
script
>
frontend/src/views/admin/ops/components/OpsSystemLogTable.vue
View file @
fa68cbad
...
...
@@ -344,7 +344,7 @@ onMounted(async () => {
<div
class=
"text-xs font-semibold text-gray-700 dark:text-gray-200"
>
运行时日志配置(实时生效)
</div>
<span
v-if=
"runtimeLoading"
class=
"text-xs text-gray-500"
>
加载中...
</span>
</div>
<div
class=
"grid grid-cols-1 gap-3 md:grid-cols-6"
>
<div
class=
"grid grid-cols-1 gap-3 md:grid-cols-
2 xl:grid-cols-
6"
>
<label
class=
"text-xs text-gray-600 dark:text-gray-300"
>
级别
<select
v-model=
"runtimeConfig.level"
class=
"input mt-1"
>
...
...
@@ -374,21 +374,27 @@ onMounted(async () => {
保留天数
<input
v-model.number=
"runtimeConfig.retention_days"
type=
"number"
min=
"1"
max=
"3650"
class=
"input mt-1"
/>
</label>
<div
class=
"flex items-end gap-2"
>
<label
class=
"inline-flex items-center gap-2 text-xs text-gray-600 dark:text-gray-300"
>
<input
v-model=
"runtimeConfig.caller"
type=
"checkbox"
/>
caller
</label>
<label
class=
"inline-flex items-center gap-2 text-xs text-gray-600 dark:text-gray-300"
>
<input
v-model=
"runtimeConfig.enable_sampling"
type=
"checkbox"
/>
sampling
</label>
<button
type=
"button"
class=
"btn btn-primary btn-sm"
:disabled=
"runtimeSaving"
@
click=
"saveRuntimeConfig"
>
{{
runtimeSaving
?
'
保存中...
'
:
'
保存并生效
'
}}
</button>
<button
type=
"button"
class=
"btn btn-secondary btn-sm"
:disabled=
"runtimeSaving"
@
click=
"resetRuntimeConfig"
>
回滚默认值
</button>
<div
class=
"md:col-span-2 xl:col-span-6"
>
<div
class=
"grid gap-3 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-end"
>
<div
class=
"flex flex-wrap items-center gap-x-4 gap-y-2"
>
<label
class=
"inline-flex items-center gap-2 text-xs text-gray-600 dark:text-gray-300"
>
<input
v-model=
"runtimeConfig.caller"
type=
"checkbox"
/>
caller
</label>
<label
class=
"inline-flex items-center gap-2 text-xs text-gray-600 dark:text-gray-300"
>
<input
v-model=
"runtimeConfig.enable_sampling"
type=
"checkbox"
/>
sampling
</label>
</div>
<div
class=
"flex flex-wrap items-center gap-2 lg:justify-end"
>
<button
type=
"button"
class=
"btn btn-primary btn-sm"
:disabled=
"runtimeSaving"
@
click=
"saveRuntimeConfig"
>
{{
runtimeSaving
?
'
保存中...
'
:
'
保存并生效
'
}}
</button>
<button
type=
"button"
class=
"btn btn-secondary btn-sm"
:disabled=
"runtimeSaving"
@
click=
"resetRuntimeConfig"
>
回滚默认值
</button>
</div>
</div>
</div>
</div>
<p
v-if=
"health.last_error"
class=
"mt-2 text-xs text-red-600 dark:text-red-400"
>
最近写入错误:
{{
health
.
last_error
}}
</p>
...
...
Prev
1
2
3
4
5
Next
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