Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 42 additions & 19 deletions backend/internal/handler/admin/setting_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func (h *SettingHandler) GetSettings(c *gin.Context) {
TablePageSizeOptions: settings.TablePageSizeOptions,
CustomMenuItems: dto.ParseCustomMenuItems(settings.CustomMenuItems),
CustomEndpoints: dto.ParseCustomEndpoints(settings.CustomEndpoints),
DefaultProxyID: settings.DefaultProxyID,
DefaultConcurrency: settings.DefaultConcurrency,
DefaultBalance: settings.DefaultBalance,
RiskControlEnabled: settings.RiskControlEnabled,
Expand Down Expand Up @@ -442,6 +443,7 @@ type UpdateSettingsRequest struct {
TablePageSizeOptions []int `json:"table_page_size_options"`
CustomMenuItems *[]dto.CustomMenuItem `json:"custom_menu_items"`
CustomEndpoints *[]dto.CustomEndpoint `json:"custom_endpoints"`
DefaultProxyID *int64 `json:"default_proxy_id"`

// 默认配置
DefaultConcurrency int `json:"default_concurrency"`
Expand Down Expand Up @@ -1348,25 +1350,35 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
TablePageSizeOptions: req.TablePageSizeOptions,
CustomMenuItems: customMenuJSON,
CustomEndpoints: customEndpointsJSON,
DefaultConcurrency: req.DefaultConcurrency,
DefaultBalance: req.DefaultBalance,
AffiliateRebateRate: affiliateRebateRate,
AffiliateRebateFreezeHours: affiliateRebateFreezeHours,
AffiliateRebateDurationDays: affiliateRebateDurationDays,
AffiliateRebatePerInviteeCap: affiliateRebatePerInviteeCap,
DefaultUserRPMLimit: req.DefaultUserRPMLimit,
DefaultSubscriptions: defaultSubscriptions,
EnableModelFallback: req.EnableModelFallback,
FallbackModelAnthropic: req.FallbackModelAnthropic,
FallbackModelOpenAI: req.FallbackModelOpenAI,
FallbackModelGemini: req.FallbackModelGemini,
FallbackModelAntigravity: req.FallbackModelAntigravity,
EnableIdentityPatch: req.EnableIdentityPatch,
IdentityPatchPrompt: req.IdentityPatchPrompt,
MinClaudeCodeVersion: req.MinClaudeCodeVersion,
MaxClaudeCodeVersion: req.MaxClaudeCodeVersion,
AllowUngroupedKeyScheduling: req.AllowUngroupedKeyScheduling,
BackendModeEnabled: req.BackendModeEnabled,
DefaultProxyID: func() *int64 {
if req.DefaultProxyID != nil {
if *req.DefaultProxyID <= 0 {
return nil
}
value := *req.DefaultProxyID
return &value
}
return previousSettings.DefaultProxyID
}(),
DefaultConcurrency: req.DefaultConcurrency,
DefaultBalance: req.DefaultBalance,
AffiliateRebateRate: affiliateRebateRate,
AffiliateRebateFreezeHours: affiliateRebateFreezeHours,
AffiliateRebateDurationDays: affiliateRebateDurationDays,
AffiliateRebatePerInviteeCap: affiliateRebatePerInviteeCap,
DefaultUserRPMLimit: req.DefaultUserRPMLimit,
DefaultSubscriptions: defaultSubscriptions,
EnableModelFallback: req.EnableModelFallback,
FallbackModelAnthropic: req.FallbackModelAnthropic,
FallbackModelOpenAI: req.FallbackModelOpenAI,
FallbackModelGemini: req.FallbackModelGemini,
FallbackModelAntigravity: req.FallbackModelAntigravity,
EnableIdentityPatch: req.EnableIdentityPatch,
IdentityPatchPrompt: req.IdentityPatchPrompt,
MinClaudeCodeVersion: req.MinClaudeCodeVersion,
MaxClaudeCodeVersion: req.MaxClaudeCodeVersion,
AllowUngroupedKeyScheduling: req.AllowUngroupedKeyScheduling,
BackendModeEnabled: req.BackendModeEnabled,
OpsMonitoringEnabled: func() bool {
if req.OpsMonitoringEnabled != nil {
return *req.OpsMonitoringEnabled
Expand Down Expand Up @@ -1720,6 +1732,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) {
TablePageSizeOptions: updatedSettings.TablePageSizeOptions,
CustomMenuItems: dto.ParseCustomMenuItems(updatedSettings.CustomMenuItems),
CustomEndpoints: dto.ParseCustomEndpoints(updatedSettings.CustomEndpoints),
DefaultProxyID: updatedSettings.DefaultProxyID,
DefaultConcurrency: updatedSettings.DefaultConcurrency,
DefaultBalance: updatedSettings.DefaultBalance,
AffiliateRebateRate: updatedSettings.AffiliateRebateRate,
Expand Down Expand Up @@ -2047,6 +2060,9 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings,
if before.HideCcsImportButton != after.HideCcsImportButton {
changed = append(changed, "hide_ccs_import_button")
}
if !equalInt64Ptr(before.DefaultProxyID, after.DefaultProxyID) {
changed = append(changed, "default_proxy_id")
}
if before.DefaultConcurrency != after.DefaultConcurrency {
changed = append(changed, "default_concurrency")
}
Expand Down Expand Up @@ -2298,6 +2314,13 @@ func defaultSubscriptionsValueOrDefault(input *[]dto.DefaultSubscriptionSetting,
return result
}

func equalInt64Ptr(a, b *int64) bool {
if a == nil || b == nil {
return a == nil && b == nil
}
return *a == *b
}

func systemSettingsResponseData(settings dto.SystemSettings, authSourceDefaults *service.AuthSourceDefaultSettings) map[string]any {
data := make(map[string]any)
raw, err := json.Marshal(settings)
Expand Down
1 change: 1 addition & 0 deletions backend/internal/handler/dto/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type SystemSettings struct {
TablePageSizeOptions []int `json:"table_page_size_options"`
CustomMenuItems []CustomMenuItem `json:"custom_menu_items"`
CustomEndpoints []CustomEndpoint `json:"custom_endpoints"`
DefaultProxyID *int64 `json:"default_proxy_id"`

DefaultConcurrency int `json:"default_concurrency"`
DefaultBalance float64 `json:"default_balance"`
Expand Down
2 changes: 1 addition & 1 deletion backend/internal/repository/billing_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func jitteredTTL() time.Duration {
if billingCacheJitter <= 0 {
return billingCacheTTL
}
jitter := time.Duration(rand.IntN(int(billingCacheJitter)))
jitter := time.Duration(rand.Int64N(int64(billingCacheJitter)))
return billingCacheTTL - jitter
}

Expand Down
1 change: 1 addition & 0 deletions backend/internal/service/domain_constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ const (
SettingKeyTablePageSizeOptions = "table_page_size_options" // 表格可选每页条数(JSON 数组)
SettingKeyCustomMenuItems = "custom_menu_items" // 自定义菜单项(JSON 数组)
SettingKeyCustomEndpoints = "custom_endpoints" // 自定义端点列表(JSON 数组)
SettingKeyDefaultProxyID = "default_proxy_id" // 添加账号时默认选中的代理 ID

// 默认配置
SettingKeyDefaultConcurrency = "default_concurrency" // 新用户默认并发量
Expand Down
2 changes: 1 addition & 1 deletion backend/internal/service/gateway_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ func TestParseGatewayRequest_MaxTokensBoundary(t *testing.T) {
{
name: "超大值不 panic",
body: `{"max_tokens":9999999999999999}`,
wantMaxTokens: 10000000000000000, // float64 精度导致 9999999999999999 → 1e16
wantMaxTokens: 0, // 超出 math.MaxInt 时应被忽略,但不能 panic
},
{
name: "null 值被忽略",
Expand Down
4 changes: 2 additions & 2 deletions backend/internal/service/gemini_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const (
)

const (
GB = 1024 * 1024 * 1024
TB = 1024 * GB
GB int64 = 1024 * 1024 * 1024
TB int64 = 1024 * GB

StorageTierUnlimited = 100 * TB // 100TB
StorageTierAIPremium = 2 * TB // 2TB
Expand Down
9 changes: 9 additions & 0 deletions backend/internal/service/setting_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,11 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
updates[SettingKeyTablePageSizeOptions] = string(tablePageSizeOptionsJSON)
updates[SettingKeyCustomMenuItems] = settings.CustomMenuItems
updates[SettingKeyCustomEndpoints] = settings.CustomEndpoints
if settings.DefaultProxyID != nil && *settings.DefaultProxyID > 0 {
updates[SettingKeyDefaultProxyID] = strconv.FormatInt(*settings.DefaultProxyID, 10)
} else {
updates[SettingKeyDefaultProxyID] = ""
}

// 默认配置
updates[SettingKeyDefaultConcurrency] = strconv.Itoa(settings.DefaultConcurrency)
Expand Down Expand Up @@ -2233,6 +2238,7 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
SettingKeyTablePageSizeOptions: "[10,20,50,100]",
SettingKeyCustomMenuItems: "[]",
SettingKeyCustomEndpoints: "[]",
SettingKeyDefaultProxyID: "",
SettingKeyWeChatConnectEnabled: "false",
SettingKeyWeChatConnectAppID: "",
SettingKeyWeChatConnectAppSecret: "",
Expand Down Expand Up @@ -2412,6 +2418,9 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
CustomEndpoints: settings[SettingKeyCustomEndpoints],
BackendModeEnabled: settings[SettingKeyBackendModeEnabled] == "true",
}
if defaultProxyID, err := strconv.ParseInt(strings.TrimSpace(settings[SettingKeyDefaultProxyID]), 10, 64); err == nil && defaultProxyID > 0 {
result.DefaultProxyID = &defaultProxyID
}
result.TableDefaultPageSize, result.TablePageSizeOptions = parseTablePreferences(
settings[SettingKeyTableDefaultPageSize],
settings[SettingKeyTablePageSizeOptions],
Expand Down
33 changes: 33 additions & 0 deletions backend/internal/service/setting_service_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,39 @@ func TestSettingService_UpdateSettings_TablePreferences(t *testing.T) {
require.Equal(t, "[20,100]", repo.updates[SettingKeyTablePageSizeOptions])
}

func TestSettingService_UpdateSettings_DefaultProxyID(t *testing.T) {
repo := &settingUpdateRepoStub{}
svc := NewSettingService(repo, &config.Config{})
defaultProxyID := int64(42)

err := svc.UpdateSettings(context.Background(), &SystemSettings{
DefaultProxyID: &defaultProxyID,
})
require.NoError(t, err)
require.Equal(t, "42", repo.updates[SettingKeyDefaultProxyID])

err = svc.UpdateSettings(context.Background(), &SystemSettings{
DefaultProxyID: nil,
})
require.NoError(t, err)
require.Equal(t, "", repo.updates[SettingKeyDefaultProxyID])
}

func TestSettingService_ParseSettings_DefaultProxyID(t *testing.T) {
svc := NewSettingService(&settingUpdateRepoStub{}, &config.Config{})

got := svc.parseSettings(map[string]string{
SettingKeyDefaultProxyID: "88",
})
require.NotNil(t, got.DefaultProxyID)
require.EqualValues(t, 88, *got.DefaultProxyID)

got = svc.parseSettings(map[string]string{
SettingKeyDefaultProxyID: "",
})
require.Nil(t, got.DefaultProxyID)
}

func TestSettingService_UpdateSettings_PaymentVisibleMethodsAndAdvancedScheduler(t *testing.T) {
repo := &settingUpdateRepoStub{}
svc := NewSettingService(repo, &config.Config{})
Expand Down
1 change: 1 addition & 0 deletions backend/internal/service/settings_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type SystemSettings struct {
TablePageSizeOptions []int
CustomMenuItems string // JSON array of custom menu items
CustomEndpoints string // JSON array of custom endpoints
DefaultProxyID *int64

DefaultConcurrency int
DefaultBalance float64
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/api/admin/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ export interface SystemSettings {
backend_mode_enabled: boolean;
custom_menu_items: CustomMenuItem[];
custom_endpoints: CustomEndpoint[];
default_proxy_id?: number | null;
// SMTP settings
smtp_host: string;
smtp_port: number;
Expand Down Expand Up @@ -593,6 +594,7 @@ export interface UpdateSettingsRequest {
backend_mode_enabled?: boolean;
custom_menu_items?: CustomMenuItem[];
custom_endpoints?: CustomEndpoint[];
default_proxy_id?: number | null;
smtp_host?: string;
smtp_port?: number;
smtp_username?: string;
Expand Down
Loading
Loading