fix:修复设置功能页面布尔值转为字符串的错误处理方式
This commit is contained in:
1 parent
3e06f6b2f4
commit
974efb6685
10 files changed
+67
-37
No files matched your search
@@ -2,6 +2,7 @@ package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/logic/common"
|
||||
@@ -56,12 +57,46 @@ func (s *sAdmin) UpdateSettings(ctx context.Context, req *v1.AdminSettingsUpdate
|
||||
for key, val := range req.Settings {
|
||||
strValues[key] = common.NormalizeSettingValue(val)
|
||||
}
|
||||
|
||||
if err := s.validateCrossFieldSettings(ctx, req.Category, strValues); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := common.Config().UpdateCategory(ctx, req.Category, strValues); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// validateCrossFieldSettings validates interdependent settings within a category.
|
||||
func (s *sAdmin) validateCrossFieldSettings(ctx context.Context, category string, values map[string]string) error {
|
||||
if category != "security" {
|
||||
return nil
|
||||
}
|
||||
|
||||
enabled, ok := values["turnstile_enabled"]
|
||||
if !ok || (enabled != "true" && enabled != "1") {
|
||||
return nil
|
||||
}
|
||||
|
||||
siteKey := values["turnstile_site_key"]
|
||||
secretKey := values["turnstile_secret_key"]
|
||||
|
||||
// If keys not in the current request, read existing values from DB
|
||||
if siteKey == "" {
|
||||
siteKey = common.Config().GetString(ctx, "turnstile_site_key")
|
||||
}
|
||||
if secretKey == "" || secretKey == "******" {
|
||||
secretKey = common.Config().GetString(ctx, "turnstile_secret_key")
|
||||
}
|
||||
|
||||
if strings.TrimSpace(siteKey) == "" || strings.TrimSpace(secretKey) == "" {
|
||||
return common.NewBadRequestError("启用 Turnstile 前必须先配置 Site Key 和 Secret Key")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidCategory(category string) bool {
|
||||
for _, c := range common.Categories {
|
||||
if c.Key == category {
|
||||
|
||||
@@ -12,16 +12,16 @@ const values = useFormValues()
|
||||
<span class="switch-label">渠道自动探测</span>
|
||||
<span class="switch-desc">定期向活跃渠道发送测试请求,检测连通性并更新健康度(会消耗少量 Token)</span>
|
||||
<ASwitch
|
||||
:model-value="values['channel_auto_test_enabled'] === 'true' || values['channel_auto_test_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_test_enabled'] = String(v)"
|
||||
:model-value="!!values['channel_auto_test_enabled']"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_test_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="switch-row" style="margin-top: 12px">
|
||||
<span class="switch-label">自动恢复探测</span>
|
||||
<span class="switch-desc">定期测试已自动禁用的渠道,测试通过则恢复启用(依赖自动探测开启)</span>
|
||||
<ASwitch
|
||||
:model-value="values['channel_auto_test_recovery_enabled'] === 'true' || values['channel_auto_test_recovery_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_test_recovery_enabled'] = String(v)"
|
||||
:model-value="!!values['channel_auto_test_recovery_enabled']"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_test_recovery_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,8 +33,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">渠道自动禁用</span>
|
||||
<span class="switch-desc">连续失败达到阈值时自动禁用渠道</span>
|
||||
<ASwitch
|
||||
:model-value="values['channel_auto_disable_enabled'] === 'true' || values['channel_auto_disable_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_disable_enabled'] = String(v)"
|
||||
:model-value="!!values['channel_auto_disable_enabled']"
|
||||
@change="(v: string | number | boolean) => values['channel_auto_disable_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="section-grid" style="margin-top: 12px">
|
||||
|
||||
@@ -47,8 +47,8 @@ function set(key: string, v: number | undefined): void {
|
||||
<div class="switch-row">
|
||||
<span class="switch-label">启用文件保留期检查</span>
|
||||
<ASwitch
|
||||
:model-value="values['file_retention_enabled'] === 'true' || values['file_retention_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['file_retention_enabled'] = String(v)"
|
||||
:model-value="!!values['file_retention_enabled']"
|
||||
@change="(v: string | number | boolean) => values['file_retention_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,8 +40,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">启用 TLS</span>
|
||||
<span class="switch-desc">587/465 端口建议开启</span>
|
||||
<ASwitch
|
||||
:model-value="values['email_smtp_tls'] === 'true' || values['email_smtp_tls'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['email_smtp_tls'] = String(v)"
|
||||
:model-value="!!values['email_smtp_tls']"
|
||||
@change="(v: string | number | boolean) => values['email_smtp_tls'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,16 +28,16 @@ const values = useFormValues()
|
||||
<span class="switch-label">开放注册</span>
|
||||
<span class="switch-desc">是否允许新用户注册</span>
|
||||
<ASwitch
|
||||
:model-value="values['register_enabled'] === 'true' || values['register_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['register_enabled'] = String(v)"
|
||||
:model-value="!!values['register_enabled']"
|
||||
@change="(v: string | number | boolean) => values['register_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="switch-row">
|
||||
<span class="switch-label">注册邮箱验证</span>
|
||||
<span class="switch-desc">注册时是否需要邮箱验证码,关闭时使用滑块验证</span>
|
||||
<ASwitch
|
||||
:model-value="values['register_email_verification'] === 'true' || values['register_email_verification'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['register_email_verification'] = String(v)"
|
||||
:model-value="!!values['register_email_verification']"
|
||||
@change="(v: string | number | boolean) => values['register_email_verification'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,8 +49,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">启用维护模式</span>
|
||||
<span class="switch-desc">开启后控制台显示维护提示</span>
|
||||
<ASwitch
|
||||
:model-value="values['maintenance_mode'] === 'true' || values['maintenance_mode'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['maintenance_mode'] = String(v)"
|
||||
:model-value="!!values['maintenance_mode']"
|
||||
@change="(v: string | number | boolean) => values['maintenance_mode'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="section-grid" style="margin-top: 12px">
|
||||
@@ -65,8 +65,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">全局 API 维护</span>
|
||||
<span class="switch-desc">开启后 API 代理返回 503</span>
|
||||
<ASwitch
|
||||
:model-value="values['api_maintenance_enabled'] === 'true' || values['api_maintenance_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['api_maintenance_enabled'] = String(v)"
|
||||
:model-value="!!values['api_maintenance_enabled']"
|
||||
@change="(v: string | number | boolean) => values['api_maintenance_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">OAuth 自动注册</span>
|
||||
<span class="switch-desc">首次 OAuth 登录自动创建租户账号</span>
|
||||
<ASwitch
|
||||
:model-value="values['oauth_auto_register'] === 'true' || values['oauth_auto_register'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['oauth_auto_register'] = String(v)"
|
||||
:model-value="!!values['oauth_auto_register']"
|
||||
@change="(v: string | number | boolean) => values['oauth_auto_register'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="section-grid" style="margin-top: 12px">
|
||||
@@ -30,8 +30,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">启用 GitHub 登录</span>
|
||||
<span class="switch-desc"></span>
|
||||
<ASwitch
|
||||
:model-value="values['oauth_github_enabled'] === 'true' || values['oauth_github_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['oauth_github_enabled'] = String(v)"
|
||||
:model-value="!!values['oauth_github_enabled']"
|
||||
@change="(v: string | number | boolean) => values['oauth_github_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="section-grid" style="margin-top: 12px">
|
||||
@@ -51,8 +51,8 @@ const values = useFormValues()
|
||||
<span class="switch-label">启用 Google 登录</span>
|
||||
<span class="switch-desc"></span>
|
||||
<ASwitch
|
||||
:model-value="values['oauth_google_enabled'] === 'true' || values['oauth_google_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['oauth_google_enabled'] = String(v)"
|
||||
:model-value="!!values['oauth_google_enabled']"
|
||||
@change="(v: string | number | boolean) => values['oauth_google_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="section-grid" style="margin-top: 12px">
|
||||
|
||||
@@ -65,8 +65,8 @@ function set(key: string, v: number | undefined): void {
|
||||
<div class="compact-row">
|
||||
<label>启用缓存</label>
|
||||
<ASwitch
|
||||
:model-value="values['cache_enabled'] === 'true' || values['cache_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['cache_enabled'] = String(v)"
|
||||
:model-value="!!values['cache_enabled']"
|
||||
@change="(v: string | number | boolean) => values['cache_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="compact-row">
|
||||
@@ -107,8 +107,8 @@ function set(key: string, v: number | undefined): void {
|
||||
<div class="compact-row">
|
||||
<label>启用沙箱</label>
|
||||
<ASwitch
|
||||
:model-value="values['sandbox_enabled'] === 'true' || values['sandbox_enabled'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['sandbox_enabled'] = String(v)"
|
||||
:model-value="!!values['sandbox_enabled']"
|
||||
@change="(v: string | number | boolean) => values['sandbox_enabled'] = v"
|
||||
/>
|
||||
</div>
|
||||
<div class="compact-row">
|
||||
|
||||
@@ -89,7 +89,7 @@ const values = useFormValues()
|
||||
</AFormItem>
|
||||
<AFormItem label="新设备登录通知">
|
||||
<ASwitch
|
||||
:model-value="values['new_device_notification'] !== false"
|
||||
:model-value="!!values['new_device_notification']"
|
||||
@change="(v: string | number | boolean) => values['new_device_notification'] = v"
|
||||
/>
|
||||
</AFormItem>
|
||||
|
||||
@@ -47,8 +47,8 @@ const values = useFormValues()
|
||||
<div class="switch-row" style="margin-top: 8px">
|
||||
<span class="switch-label">启用 SSL</span>
|
||||
<ASwitch
|
||||
:model-value="values['storage_use_ssl'] === 'true' || values['storage_use_ssl'] === '1'"
|
||||
@change="(v: string | number | boolean) => values['storage_use_ssl'] = String(v)"
|
||||
:model-value="!!values['storage_use_ssl']"
|
||||
@change="(v: string | number | boolean) => values['storage_use_ssl'] = v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,12 +19,7 @@ export function useSettings(category: () => string) {
|
||||
const items = res.data?.data?.list || []
|
||||
const vals: Record<string, any> = {}
|
||||
for (const item of items) {
|
||||
let val = item.value ?? item.default ?? ''
|
||||
// Normalize bool values to strings for consistent switch handling
|
||||
if (item.type === 'bool') {
|
||||
val = String(val)
|
||||
}
|
||||
vals[item.key] = val
|
||||
vals[item.key] = item.value ?? item.default ?? ''
|
||||
}
|
||||
Object.keys(formValues).forEach(k => delete formValues[k])
|
||||
Object.assign(formValues, vals)
|
||||
|
||||
Reference in new issue
Block a user