From 739c0ff9c553acfee6d740e13752c2e2bb3c551a Mon Sep 17 00:00:00 2001 From: wucm667 Date: Thu, 30 Jul 2026 16:28:19 +0800 Subject: [PATCH 1/2] feat(home): add compact home page preset to avoid abuse classification - Add compact_home_enabled setting to provide a minimal landing page - Preserves custom home_content priority over compact mode - Renders only site identity, navigation, and login/dashboard link - Avoids marketing copy that triggers anti-fraud systems - Includes focused backend/frontend tests and i18n support Fixes #5065 --- .../internal/handler/admin/setting_handler.go | 1 + .../handler/admin/setting_handler_audit.go | 3 + .../setting_handler_platform_quota_test.go | 12 ++ .../handler/admin/setting_handler_update.go | 3 + backend/internal/handler/dto/settings.go | 2 + backend/internal/handler/setting_handler.go | 1 + backend/internal/service/domain_constants.go | 1 + backend/internal/service/setting_parse.go | 1 + backend/internal/service/setting_public.go | 4 + .../service/setting_service_public_test.go | 19 +++ .../service/setting_service_update_test.go | 10 ++ backend/internal/service/setting_update.go | 1 + backend/internal/service/settings_view.go | 2 + frontend/src/api/admin/settings.ts | 2 + .../auth/__tests__/WechatOAuthSection.spec.ts | 1 + .../ProfileIdentityBindingsSection.spec.ts | 1 + .../src/i18n/locales/en/admin/settings.ts | 2 + .../src/i18n/locales/zh/admin/settings.ts | 2 + frontend/src/stores/__tests__/app.spec.ts | 2 + frontend/src/stores/app.ts | 1 + frontend/src/types/index.ts | 1 + frontend/src/views/HomeView.vue | 73 ++++++++++- .../views/__tests__/HomeView.compact.spec.ts | 122 ++++++++++++++++++ frontend/src/views/admin/SettingsView.vue | 15 +++ .../admin/__tests__/SettingsView.spec.ts | 17 +++ 25 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 frontend/src/views/__tests__/HomeView.compact.spec.ts diff --git a/backend/internal/handler/admin/setting_handler.go b/backend/internal/handler/admin/setting_handler.go index 703d297fa..8ad27e122 100644 --- a/backend/internal/handler/admin/setting_handler.go +++ b/backend/internal/handler/admin/setting_handler.go @@ -233,6 +233,7 @@ func (h *SettingHandler) GetSettings(c *gin.Context) { ContactInfo: settings.ContactInfo, DocURL: settings.DocURL, HomeContent: settings.HomeContent, + CompactHomeEnabled: settings.CompactHomeEnabled, HideCcsImportButton: settings.HideCcsImportButton, PurchaseSubscriptionEnabled: settings.PurchaseSubscriptionEnabled, PurchaseSubscriptionURL: settings.PurchaseSubscriptionURL, diff --git a/backend/internal/handler/admin/setting_handler_audit.go b/backend/internal/handler/admin/setting_handler_audit.go index 30c2495af..ab91ac9f5 100644 --- a/backend/internal/handler/admin/setting_handler_audit.go +++ b/backend/internal/handler/admin/setting_handler_audit.go @@ -299,6 +299,9 @@ func diffSettings(before *service.SystemSettings, after *service.SystemSettings, if before.HomeContent != after.HomeContent { changed = append(changed, "home_content") } + if before.CompactHomeEnabled != after.CompactHomeEnabled { + changed = append(changed, "compact_home_enabled") + } if before.HideCcsImportButton != after.HideCcsImportButton { changed = append(changed, "hide_ccs_import_button") } diff --git a/backend/internal/handler/admin/setting_handler_platform_quota_test.go b/backend/internal/handler/admin/setting_handler_platform_quota_test.go index 273b34420..39048394e 100644 --- a/backend/internal/handler/admin/setting_handler_platform_quota_test.go +++ b/backend/internal/handler/admin/setting_handler_platform_quota_test.go @@ -64,6 +64,18 @@ func TestDiffSettings_NoChangeWhenEqual(t *testing.T) { } } +func TestDiffSettings_DetectsCompactHomeChange(t *testing.T) { + changed := diffSettings( + &service.SystemSettings{}, + &service.SystemSettings{CompactHomeEnabled: true}, + nil, + nil, + UpdateSettingsRequest{}, + ) + + require.Contains(t, changed, service.SettingKeyCompactHomeEnabled) +} + func TestEqualNullableFloat(t *testing.T) { five := 5.0 five2 := 5.0 diff --git a/backend/internal/handler/admin/setting_handler_update.go b/backend/internal/handler/admin/setting_handler_update.go index 65c90a3a6..54569bc47 100644 --- a/backend/internal/handler/admin/setting_handler_update.go +++ b/backend/internal/handler/admin/setting_handler_update.go @@ -142,6 +142,7 @@ type UpdateSettingsRequest struct { ContactInfo string `json:"contact_info"` DocURL string `json:"doc_url"` HomeContent string `json:"home_content"` + CompactHomeEnabled bool `json:"compact_home_enabled"` HideCcsImportButton bool `json:"hide_ccs_import_button"` PurchaseSubscriptionEnabled *bool `json:"purchase_subscription_enabled"` PurchaseSubscriptionURL *string `json:"purchase_subscription_url"` @@ -1430,6 +1431,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { ContactInfo: req.ContactInfo, DocURL: req.DocURL, HomeContent: req.HomeContent, + CompactHomeEnabled: req.CompactHomeEnabled, HideCcsImportButton: req.HideCcsImportButton, PurchaseSubscriptionEnabled: purchaseEnabled, PurchaseSubscriptionURL: purchaseURL, @@ -1982,6 +1984,7 @@ func (h *SettingHandler) UpdateSettings(c *gin.Context) { ContactInfo: updatedSettings.ContactInfo, DocURL: updatedSettings.DocURL, HomeContent: updatedSettings.HomeContent, + CompactHomeEnabled: updatedSettings.CompactHomeEnabled, HideCcsImportButton: updatedSettings.HideCcsImportButton, PurchaseSubscriptionEnabled: updatedSettings.PurchaseSubscriptionEnabled, PurchaseSubscriptionURL: updatedSettings.PurchaseSubscriptionURL, diff --git a/backend/internal/handler/dto/settings.go b/backend/internal/handler/dto/settings.go index dc34771ca..da4c6abc1 100644 --- a/backend/internal/handler/dto/settings.go +++ b/backend/internal/handler/dto/settings.go @@ -142,6 +142,7 @@ type SystemSettings struct { ContactInfo string `json:"contact_info"` DocURL string `json:"doc_url"` HomeContent string `json:"home_content"` + CompactHomeEnabled bool `json:"compact_home_enabled"` HideCcsImportButton bool `json:"hide_ccs_import_button"` PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"` PurchaseSubscriptionURL string `json:"purchase_subscription_url"` @@ -344,6 +345,7 @@ type PublicSettings struct { ContactInfo string `json:"contact_info"` DocURL string `json:"doc_url"` HomeContent string `json:"home_content"` + CompactHomeEnabled bool `json:"compact_home_enabled"` HideCcsImportButton bool `json:"hide_ccs_import_button"` PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"` PurchaseSubscriptionURL string `json:"purchase_subscription_url"` diff --git a/backend/internal/handler/setting_handler.go b/backend/internal/handler/setting_handler.go index 49f4d5f99..d825d7ef6 100644 --- a/backend/internal/handler/setting_handler.go +++ b/backend/internal/handler/setting_handler.go @@ -67,6 +67,7 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) { ContactInfo: settings.ContactInfo, DocURL: settings.DocURL, HomeContent: settings.HomeContent, + CompactHomeEnabled: settings.CompactHomeEnabled, HideCcsImportButton: settings.HideCcsImportButton, PurchaseSubscriptionEnabled: settings.PurchaseSubscriptionEnabled, PurchaseSubscriptionURL: settings.PurchaseSubscriptionURL, diff --git a/backend/internal/service/domain_constants.go b/backend/internal/service/domain_constants.go index 766b7381e..aa3153d0e 100644 --- a/backend/internal/service/domain_constants.go +++ b/backend/internal/service/domain_constants.go @@ -271,6 +271,7 @@ const ( SettingKeyContactInfo = "contact_info" // 客服联系方式 SettingKeyDocURL = "doc_url" // 文档链接 SettingKeyHomeContent = "home_content" // 首页内容(支持 Markdown/HTML,或 URL 作为 iframe src) + SettingKeyCompactHomeEnabled = "compact_home_enabled" // 是否启用内置简洁首页 SettingKeyHideCcsImportButton = "hide_ccs_import_button" // 是否隐藏 API Keys 页面的导入 CCS 按钮 SettingKeyPurchaseSubscriptionEnabled = "purchase_subscription_enabled" // 是否展示"购买订阅"页面入口 SettingKeyPurchaseSubscriptionURL = "purchase_subscription_url" // "购买订阅"页面 URL(作为 iframe src) diff --git a/backend/internal/service/setting_parse.go b/backend/internal/service/setting_parse.go index a4d409f9c..d5075038b 100644 --- a/backend/internal/service/setting_parse.go +++ b/backend/internal/service/setting_parse.go @@ -330,6 +330,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin ContactInfo: settings[SettingKeyContactInfo], DocURL: settings[SettingKeyDocURL], HomeContent: settings[SettingKeyHomeContent], + CompactHomeEnabled: settings[SettingKeyCompactHomeEnabled] == "true", HideCcsImportButton: settings[SettingKeyHideCcsImportButton] == "true", PurchaseSubscriptionEnabled: settings[SettingKeyPurchaseSubscriptionEnabled] == "true", PurchaseSubscriptionURL: strings.TrimSpace(settings[SettingKeyPurchaseSubscriptionURL]), diff --git a/backend/internal/service/setting_public.go b/backend/internal/service/setting_public.go index 76af91c30..bb2213a11 100644 --- a/backend/internal/service/setting_public.go +++ b/backend/internal/service/setting_public.go @@ -179,6 +179,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings SettingKeyContactInfo, SettingKeyDocURL, SettingKeyHomeContent, + SettingKeyCompactHomeEnabled, SettingKeyHideCcsImportButton, SettingKeyPurchaseSubscriptionEnabled, SettingKeyPurchaseSubscriptionURL, @@ -307,6 +308,7 @@ func (s *SettingService) GetPublicSettings(ctx context.Context) (*PublicSettings ContactInfo: settings[SettingKeyContactInfo], DocURL: settings[SettingKeyDocURL], HomeContent: settings[SettingKeyHomeContent], + CompactHomeEnabled: settings[SettingKeyCompactHomeEnabled] == "true", HideCcsImportButton: settings[SettingKeyHideCcsImportButton] == "true", PurchaseSubscriptionEnabled: settings[SettingKeyPurchaseSubscriptionEnabled] == "true", PurchaseSubscriptionURL: strings.TrimSpace(settings[SettingKeyPurchaseSubscriptionURL]), @@ -495,6 +497,7 @@ type PublicSettingsInjectionPayload struct { ContactInfo string `json:"contact_info"` DocURL string `json:"doc_url"` HomeContent string `json:"home_content"` + CompactHomeEnabled bool `json:"compact_home_enabled"` HideCcsImportButton bool `json:"hide_ccs_import_button"` PurchaseSubscriptionEnabled bool `json:"purchase_subscription_enabled"` PurchaseSubscriptionURL string `json:"purchase_subscription_url"` @@ -567,6 +570,7 @@ func (s *SettingService) GetPublicSettingsForInjection(ctx context.Context) (any ContactInfo: settings.ContactInfo, DocURL: settings.DocURL, HomeContent: settings.HomeContent, + CompactHomeEnabled: settings.CompactHomeEnabled, HideCcsImportButton: settings.HideCcsImportButton, PurchaseSubscriptionEnabled: settings.PurchaseSubscriptionEnabled, PurchaseSubscriptionURL: settings.PurchaseSubscriptionURL, diff --git a/backend/internal/service/setting_service_public_test.go b/backend/internal/service/setting_service_public_test.go index 621620fd0..54bdda77f 100644 --- a/backend/internal/service/setting_service_public_test.go +++ b/backend/internal/service/setting_service_public_test.go @@ -78,6 +78,25 @@ func TestSettingService_GetPublicSettings_ExposesTablePreferences(t *testing.T) require.Equal(t, []int{20, 50, 100}, settings.TablePageSizeOptions) } +func TestSettingService_GetPublicSettings_ExposesCompactHomeEnabled(t *testing.T) { + repo := &settingPublicRepoStub{ + values: map[string]string{ + SettingKeyCompactHomeEnabled: "true", + }, + } + svc := NewSettingService(repo, &config.Config{}) + + settings, err := svc.GetPublicSettings(context.Background()) + + require.NoError(t, err) + require.True(t, settings.CompactHomeEnabled) + + missingSettings, err := NewSettingService(&settingPublicRepoStub{values: map[string]string{}}, &config.Config{}). + GetPublicSettings(context.Background()) + require.NoError(t, err) + require.False(t, missingSettings.CompactHomeEnabled) +} + func TestSettingService_GetPublicSettings_ExposesForceEmailOnThirdPartySignup(t *testing.T) { repo := &settingPublicRepoStub{ values: map[string]string{ diff --git a/backend/internal/service/setting_service_update_test.go b/backend/internal/service/setting_service_update_test.go index b689f5678..750f01728 100644 --- a/backend/internal/service/setting_service_update_test.go +++ b/backend/internal/service/setting_service_update_test.go @@ -228,6 +228,16 @@ func (s *defaultSubGroupReaderStub) GetByID(ctx context.Context, id int64) (*Gro return nil, ErrGroupNotFound } +func TestSettingService_UpdateSettings_PersistsCompactHomeEnabled(t *testing.T) { + repo := &settingUpdateRepoStub{} + svc := NewSettingService(repo, &config.Config{}) + + err := svc.UpdateSettings(context.Background(), &SystemSettings{CompactHomeEnabled: true}) + + require.NoError(t, err) + require.Equal(t, "true", repo.updates[SettingKeyCompactHomeEnabled]) +} + func TestSettingService_UpdateSettings_DefaultSubscriptions_ValidGroup(t *testing.T) { repo := &settingUpdateRepoStub{} groupReader := &defaultSubGroupReaderStub{ diff --git a/backend/internal/service/setting_update.go b/backend/internal/service/setting_update.go index d094f9026..e242c46d2 100644 --- a/backend/internal/service/setting_update.go +++ b/backend/internal/service/setting_update.go @@ -320,6 +320,7 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting updates[SettingKeyContactInfo] = settings.ContactInfo updates[SettingKeyDocURL] = settings.DocURL updates[SettingKeyHomeContent] = settings.HomeContent + updates[SettingKeyCompactHomeEnabled] = strconv.FormatBool(settings.CompactHomeEnabled) updates[SettingKeyHideCcsImportButton] = strconv.FormatBool(settings.HideCcsImportButton) updates[SettingKeyPurchaseSubscriptionEnabled] = strconv.FormatBool(settings.PurchaseSubscriptionEnabled) updates[SettingKeyPurchaseSubscriptionURL] = strings.TrimSpace(settings.PurchaseSubscriptionURL) diff --git a/backend/internal/service/settings_view.go b/backend/internal/service/settings_view.go index 4a6d3906f..a8ddb4908 100644 --- a/backend/internal/service/settings_view.go +++ b/backend/internal/service/settings_view.go @@ -139,6 +139,7 @@ type SystemSettings struct { ContactInfo string DocURL string HomeContent string + CompactHomeEnabled bool HideCcsImportButton bool PurchaseSubscriptionEnabled bool PurchaseSubscriptionURL string @@ -305,6 +306,7 @@ type PublicSettings struct { ContactInfo string DocURL string HomeContent string + CompactHomeEnabled bool HideCcsImportButton bool PurchaseSubscriptionEnabled bool diff --git a/frontend/src/api/admin/settings.ts b/frontend/src/api/admin/settings.ts index 2fceea7b6..b018b925b 100644 --- a/frontend/src/api/admin/settings.ts +++ b/frontend/src/api/admin/settings.ts @@ -440,6 +440,7 @@ export interface SystemSettings { contact_info: string; doc_url: string; home_content: string; + compact_home_enabled: boolean; hide_ccs_import_button: boolean; table_default_page_size: number; table_page_size_options: number[]; @@ -752,6 +753,7 @@ export interface UpdateSettingsRequest { contact_info?: string; doc_url?: string; home_content?: string; + compact_home_enabled?: boolean; hide_ccs_import_button?: boolean; table_default_page_size?: number; table_page_size_options?: number[]; diff --git a/frontend/src/components/auth/__tests__/WechatOAuthSection.spec.ts b/frontend/src/components/auth/__tests__/WechatOAuthSection.spec.ts index 2f269e0bc..5c2673424 100644 --- a/frontend/src/components/auth/__tests__/WechatOAuthSection.spec.ts +++ b/frontend/src/components/auth/__tests__/WechatOAuthSection.spec.ts @@ -73,6 +73,7 @@ function buildPublicSettings(overrides: Partial = {}): WeC contact_info: '', doc_url: '', home_content: '', + compact_home_enabled: false, hide_ccs_import_button: false, payment_enabled: false, table_default_page_size: 20, diff --git a/frontend/src/components/user/profile/__tests__/ProfileIdentityBindingsSection.spec.ts b/frontend/src/components/user/profile/__tests__/ProfileIdentityBindingsSection.spec.ts index 3ad64861e..c1121b1f7 100644 --- a/frontend/src/components/user/profile/__tests__/ProfileIdentityBindingsSection.spec.ts +++ b/frontend/src/components/user/profile/__tests__/ProfileIdentityBindingsSection.spec.ts @@ -250,6 +250,7 @@ describe('ProfileIdentityBindingsSection', () => { contact_info: '', doc_url: '', home_content: '', + compact_home_enabled: false, hide_ccs_import_button: false, payment_enabled: false, table_default_page_size: 20, diff --git a/frontend/src/i18n/locales/en/admin/settings.ts b/frontend/src/i18n/locales/en/admin/settings.ts index 5e54b2221..0ee313ec3 100644 --- a/frontend/src/i18n/locales/en/admin/settings.ts +++ b/frontend/src/i18n/locales/en/admin/settings.ts @@ -548,6 +548,8 @@ export default { homeContentPlaceholder: 'Enter custom content for the home page. Supports Markdown & HTML. If a URL is entered, it will be displayed as an iframe.', homeContentHint: 'Customize the home page content. Supports Markdown/HTML. If you enter a URL (starting with http:// or https://), it will be used as an iframe src to embed an external page. When set, the default status information will no longer be displayed.', homeContentIframeWarning: '⚠️ iframe mode note: Some websites have X-Frame-Options or CSP security policies that prevent embedding in iframes. If the page appears blank or shows an error, please verify the target website allows embedding, or consider using HTML mode to build your own content.', + compactHome: 'Compact Home Page', + compactHomeHint: 'Show a restrained site identity page when no custom home page content is set.', hideCcsImportButton: 'Hide CCS Import Button', hideCcsImportButtonHint: 'When enabled, the "Import to CCS" button will be hidden on the API Keys page' }, diff --git a/frontend/src/i18n/locales/zh/admin/settings.ts b/frontend/src/i18n/locales/zh/admin/settings.ts index 4989305c4..075a220d4 100644 --- a/frontend/src/i18n/locales/zh/admin/settings.ts +++ b/frontend/src/i18n/locales/zh/admin/settings.ts @@ -543,6 +543,8 @@ export default { '自定义首页内容,支持 Markdown/HTML。如果输入的是链接(以 http:// 或 https:// 开头),则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为首页。设置后首页的状态信息将不再显示。', homeContentIframeWarning: '⚠️ iframe 模式提示:部分网站设置了 X-Frame-Options 或 CSP 安全策略,禁止被嵌入到 iframe 中。如果页面显示空白或报错,请确认目标网站允许被嵌入,或考虑使用 HTML 模式自行构建页面内容。', + compactHome: '简洁首页', + compactHomeHint: '未设置自定义首页内容时,展示简洁的站点信息页面。', hideCcsImportButton: '隐藏 CCS 导入按钮', hideCcsImportButtonHint: '启用后将在 API Keys 页面隐藏"导入 CCS"按钮' }, diff --git a/frontend/src/stores/__tests__/app.spec.ts b/frontend/src/stores/__tests__/app.spec.ts index d936f1d2e..d5cee3606 100644 --- a/frontend/src/stores/__tests__/app.spec.ts +++ b/frontend/src/stores/__tests__/app.spec.ts @@ -33,6 +33,7 @@ function createPublicSettings(overrides: Partial = {}): PublicSe contact_info: '', doc_url: '', home_content: '', + compact_home_enabled: false, hide_ccs_import_button: false, payment_enabled: false, risk_control_enabled: false, @@ -452,6 +453,7 @@ describe('useAppStore', () => { contact_info: '', doc_url: '', home_content: '', + compact_home_enabled: false, hide_ccs_import_button: false, purchase_subscription_enabled: false, purchase_subscription_url: '', diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index 9839170a2..6080ddf04 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -342,6 +342,7 @@ export const useAppStore = defineStore('app', () => { contact_info: contactInfo.value, doc_url: docUrl.value, home_content: '', + compact_home_enabled: false, hide_ccs_import_button: false, payment_enabled: false, table_default_page_size: 20, diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 31b4fd891..fbc10f3b8 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -210,6 +210,7 @@ export interface PublicSettings { contact_info: string doc_url: string home_content: string + compact_home_enabled: boolean hide_ccs_import_button: boolean payment_enabled: boolean risk_control_enabled: boolean diff --git a/frontend/src/views/HomeView.vue b/frontend/src/views/HomeView.vue index e01aa53a5..ddb3e87e1 100644 --- a/frontend/src/views/HomeView.vue +++ b/frontend/src/views/HomeView.vue @@ -1,6 +1,6 @@