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
9618cb56
"backend/internal/vscode:/vscode.git/clone" did not exist on "08ce6de4dbc583a0827b22764d2ca84caa0dc716"
Commit
9618cb56
authored
Jan 12, 2026
by
yangjianbo
Browse files
Merge branch 'main' into test
parents
9c02ab78
8c1958c9
Changes
22
Hide whitespace changes
Inline
Side-by-side
frontend/src/i18n/locales/zh.ts
View file @
9618cb56
...
@@ -2696,6 +2696,27 @@ export default {
...
@@ -2696,6 +2696,27 @@ export default {
securityWarning
:
'
警告:此密钥拥有完整的管理员权限,请妥善保管。
'
,
securityWarning
:
'
警告:此密钥拥有完整的管理员权限,请妥善保管。
'
,
usage
:
'
使用方法:在请求头中添加 x-api-key: <your-admin-api-key>
'
usage
:
'
使用方法:在请求头中添加 x-api-key: <your-admin-api-key>
'
},
},
streamTimeout
:
{
title
:
'
流超时处理
'
,
description
:
'
配置上游响应超时时的账户处理策略,避免问题账户持续被选中
'
,
enabled
:
'
启用流超时处理
'
,
enabledHint
:
'
当上游响应超时时,自动处理问题账户
'
,
timeoutSeconds
:
'
超时阈值(秒)
'
,
timeoutSecondsHint
:
'
流数据间隔超过此时间视为超时(30-300秒)
'
,
action
:
'
处理方式
'
,
actionTempUnsched
:
'
临时不可调度
'
,
actionError
:
'
标记为错误状态
'
,
actionNone
:
'
不处理
'
,
actionHint
:
'
超时后对账户执行的操作
'
,
tempUnschedMinutes
:
'
暂停时长(分钟)
'
,
tempUnschedMinutesHint
:
'
临时不可调度的持续时间(1-60分钟)
'
,
thresholdCount
:
'
触发阈值(次数)
'
,
thresholdCountHint
:
'
累计超时多少次后触发处理(1-10次)
'
,
thresholdWindowMinutes
:
'
阈值窗口(分钟)
'
,
thresholdWindowMinutesHint
:
'
超时计数的时间窗口(1-60分钟)
'
,
saved
:
'
流超时设置保存成功
'
,
saveFailed
:
'
保存流超时设置失败
'
},
saveSettings
:
'
保存设置
'
,
saveSettings
:
'
保存设置
'
,
saving
:
'
保存中...
'
,
saving
:
'
保存中...
'
,
settingsSaved
:
'
设置保存成功
'
,
settingsSaved
:
'
设置保存成功
'
,
...
...
frontend/src/views/admin/SettingsView.vue
View file @
9618cb56
...
@@ -147,6 +147,144 @@
...
@@ -147,6 +147,144 @@
</div>
</div>
</div>
</div>
<!-- Stream Timeout Settings -->
<div
class=
"card"
>
<div
class=
"border-b border-gray-100 px-6 py-4 dark:border-dark-700"
>
<h2
class=
"text-lg font-semibold text-gray-900 dark:text-white"
>
{{
t
(
'
admin.settings.streamTimeout.title
'
)
}}
</h2>
<p
class=
"mt-1 text-sm text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.description
'
)
}}
</p>
</div>
<div
class=
"space-y-5 p-6"
>
<!-- Loading State -->
<div
v-if=
"streamTimeoutLoading"
class=
"flex items-center gap-2 text-gray-500"
>
<div
class=
"h-4 w-4 animate-spin rounded-full border-b-2 border-primary-600"
></div>
{{
t
(
'
common.loading
'
)
}}
</div>
<template
v-else
>
<!-- Enable Stream Timeout -->
<div
class=
"flex items-center justify-between"
>
<div>
<label
class=
"font-medium text-gray-900 dark:text-white"
>
{{
t
(
'
admin.settings.streamTimeout.enabled
'
)
}}
</label>
<p
class=
"text-sm text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.enabledHint
'
)
}}
</p>
</div>
<Toggle
v-model=
"streamTimeoutForm.enabled"
/>
</div>
<!-- Settings - Only show when enabled -->
<div
v-if=
"streamTimeoutForm.enabled"
class=
"space-y-4 border-t border-gray-100 pt-4 dark:border-dark-700"
>
<!-- Action -->
<div>
<label
class=
"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
>
{{
t
(
'
admin.settings.streamTimeout.action
'
)
}}
</label>
<select
v-model=
"streamTimeoutForm.action"
class=
"input w-64"
>
<option
value=
"temp_unsched"
>
{{
t
(
'
admin.settings.streamTimeout.actionTempUnsched
'
)
}}
</option>
<option
value=
"error"
>
{{
t
(
'
admin.settings.streamTimeout.actionError
'
)
}}
</option>
<option
value=
"none"
>
{{
t
(
'
admin.settings.streamTimeout.actionNone
'
)
}}
</option>
</select>
<p
class=
"mt-1.5 text-xs text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.actionHint
'
)
}}
</p>
</div>
<!-- Temp Unsched Minutes (only show when action is temp_unsched) -->
<div
v-if=
"streamTimeoutForm.action === 'temp_unsched'"
>
<label
class=
"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
>
{{
t
(
'
admin.settings.streamTimeout.tempUnschedMinutes
'
)
}}
</label>
<input
v-model.number=
"streamTimeoutForm.temp_unsched_minutes"
type=
"number"
min=
"1"
max=
"60"
class=
"input w-32"
/>
<p
class=
"mt-1.5 text-xs text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.tempUnschedMinutesHint
'
)
}}
</p>
</div>
<!-- Threshold Count -->
<div>
<label
class=
"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
>
{{
t
(
'
admin.settings.streamTimeout.thresholdCount
'
)
}}
</label>
<input
v-model.number=
"streamTimeoutForm.threshold_count"
type=
"number"
min=
"1"
max=
"10"
class=
"input w-32"
/>
<p
class=
"mt-1.5 text-xs text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.thresholdCountHint
'
)
}}
</p>
</div>
<!-- Threshold Window Minutes -->
<div>
<label
class=
"mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300"
>
{{
t
(
'
admin.settings.streamTimeout.thresholdWindowMinutes
'
)
}}
</label>
<input
v-model.number=
"streamTimeoutForm.threshold_window_minutes"
type=
"number"
min=
"1"
max=
"60"
class=
"input w-32"
/>
<p
class=
"mt-1.5 text-xs text-gray-500 dark:text-gray-400"
>
{{
t
(
'
admin.settings.streamTimeout.thresholdWindowMinutesHint
'
)
}}
</p>
</div>
</div>
<!-- Save Button -->
<div
class=
"flex justify-end border-t border-gray-100 pt-4 dark:border-dark-700"
>
<button
type=
"button"
@
click=
"saveStreamTimeoutSettings"
:disabled=
"streamTimeoutSaving"
class=
"btn btn-primary btn-sm"
>
<svg
v-if=
"streamTimeoutSaving"
class=
"mr-1 h-4 w-4 animate-spin"
fill=
"none"
viewBox=
"0 0 24 24"
>
<circle
class=
"opacity-25"
cx=
"12"
cy=
"12"
r=
"10"
stroke=
"currentColor"
stroke-width=
"4"
></circle>
<path
class=
"opacity-75"
fill=
"currentColor"
d=
"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
{{
streamTimeoutSaving
?
t
(
'
common.saving
'
)
:
t
(
'
common.save
'
)
}}
</button>
</div>
</
template
>
</div>
</div>
<!-- Registration Settings -->
<!-- Registration Settings -->
<div
class=
"card"
>
<div
class=
"card"
>
<div
class=
"border-b border-gray-100 px-6 py-4 dark:border-dark-700"
>
<div
class=
"border-b border-gray-100 px-6 py-4 dark:border-dark-700"
>
...
@@ -840,6 +978,17 @@ const adminApiKeyMasked = ref('')
...
@@ -840,6 +978,17 @@ const adminApiKeyMasked = ref('')
const
adminApiKeyOperating
=
ref
(
false
)
const
adminApiKeyOperating
=
ref
(
false
)
const
newAdminApiKey
=
ref
(
''
)
const
newAdminApiKey
=
ref
(
''
)
// Stream Timeout 状态
const
streamTimeoutLoading
=
ref
(
true
)
const
streamTimeoutSaving
=
ref
(
false
)
const
streamTimeoutForm
=
reactive
({
enabled
:
true
,
action
:
'
temp_unsched
'
as
'
temp_unsched
'
|
'
error
'
|
'
none
'
,
temp_unsched_minutes
:
5
,
threshold_count
:
3
,
threshold_window_minutes
:
10
})
type
SettingsForm
=
SystemSettings
&
{
type
SettingsForm
=
SystemSettings
&
{
smtp_password
:
string
smtp_password
:
string
turnstile_secret_key
:
string
turnstile_secret_key
:
string
...
@@ -1129,8 +1278,43 @@ function copyNewKey() {
...
@@ -1129,8 +1278,43 @@ function copyNewKey() {
})
})
}
}
// Stream Timeout 方法
async
function
loadStreamTimeoutSettings
()
{
streamTimeoutLoading
.
value
=
true
try
{
const
settings
=
await
adminAPI
.
settings
.
getStreamTimeoutSettings
()
Object
.
assign
(
streamTimeoutForm
,
settings
)
}
catch
(
error
:
any
)
{
console
.
error
(
'
Failed to load stream timeout settings:
'
,
error
)
}
finally
{
streamTimeoutLoading
.
value
=
false
}
}
async
function
saveStreamTimeoutSettings
()
{
streamTimeoutSaving
.
value
=
true
try
{
const
updated
=
await
adminAPI
.
settings
.
updateStreamTimeoutSettings
({
enabled
:
streamTimeoutForm
.
enabled
,
action
:
streamTimeoutForm
.
action
,
temp_unsched_minutes
:
streamTimeoutForm
.
temp_unsched_minutes
,
threshold_count
:
streamTimeoutForm
.
threshold_count
,
threshold_window_minutes
:
streamTimeoutForm
.
threshold_window_minutes
})
Object
.
assign
(
streamTimeoutForm
,
updated
)
appStore
.
showSuccess
(
t
(
'
admin.settings.streamTimeout.saved
'
))
}
catch
(
error
:
any
)
{
appStore
.
showError
(
t
(
'
admin.settings.streamTimeout.saveFailed
'
)
+
'
:
'
+
(
error
.
message
||
t
(
'
common.unknownError
'
))
)
}
finally
{
streamTimeoutSaving
.
value
=
false
}
}
onMounted
(()
=>
{
onMounted
(()
=>
{
loadSettings
()
loadSettings
()
loadAdminApiKey
()
loadAdminApiKey
()
loadStreamTimeoutSettings
()
})
})
</
script
>
</
script
>
Prev
1
2
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