diff --git a/frontend/src/api/admin/settings.ts b/frontend/src/api/admin/settings.ts index 38bc01c1b3..713ab175b4 100644 --- a/frontend/src/api/admin/settings.ts +++ b/frontend/src/api/admin/settings.ts @@ -148,6 +148,9 @@ export interface SystemSettings { // Channel Monitor feature switch channel_monitor_enabled: boolean channel_monitor_default_interval_seconds: number + + // Available Channels feature switch + available_channels_enabled: boolean } export interface UpdateSettingsRequest { @@ -259,6 +262,9 @@ export interface UpdateSettingsRequest { // Channel Monitor feature switch channel_monitor_enabled?: boolean channel_monitor_default_interval_seconds?: number + + // Available Channels feature switch + available_channels_enabled?: boolean } /** diff --git a/frontend/src/components/layout/AppSidebar.vue b/frontend/src/components/layout/AppSidebar.vue index 25284276c0..96c19833e3 100644 --- a/frontend/src/components/layout/AppSidebar.vue +++ b/frontend/src/components/layout/AppSidebar.vue @@ -631,6 +631,9 @@ const ChevronDownIcon = { // getter 返回 false = 隐藏;undefined/true = 显示(宽容策略,避免 public settings 未加载闪烁)。 const flagChannelMonitor = () => appStore.cachedPublicSettings?.channel_monitor_enabled const flagPayment = () => appStore.cachedPublicSettings?.payment_enabled +// Opt-in feature:默认关闭,未加载 settings 时也视为关闭(严格 === true 判定) +const flagAvailableChannels = () => + appStore.cachedPublicSettings?.available_channels_enabled === true const flagOpsMonitoring = () => adminSettingsStore.opsMonitoringEnabled const flagAdminPayment = () => adminSettingsStore.paymentEnabled @@ -648,7 +651,7 @@ function buildSelfNavItems(withDashboard: boolean): NavItem[] { { path: '/subscriptions', label: t('nav.mySubscriptions'), icon: CreditCardIcon, hideInSimpleMode: true }, { path: '/purchase', label: t('nav.buySubscription'), icon: RechargeSubscriptionIcon, hideInSimpleMode: true, featureFlag: flagPayment }, { path: '/orders', label: t('nav.myOrders'), icon: OrderListIcon, hideInSimpleMode: true, featureFlag: flagPayment }, - { path: '/available-channels', label: t('nav.availableChannels'), icon: ChannelIcon, hideInSimpleMode: true }, + { path: '/available-channels', label: t('nav.availableChannels'), icon: ChannelIcon, hideInSimpleMode: true, featureFlag: flagAvailableChannels }, { path: '/redeem', label: t('nav.redeem'), icon: GiftIcon, hideInSimpleMode: true }, { path: '/profile', label: t('nav.profile'), icon: UserIcon }, ...customMenuItemsForUser.value.map((item): NavItem => ({ diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index ddf841e071..0b9f1f6993 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -4541,6 +4541,12 @@ export default { defaultInterval: 'Default check interval (seconds)', defaultIntervalHint: 'Pre-fills the interval when creating a new monitor; each monitor can override it. Range 15 – 3600.', }, + availableChannels: { + title: 'Available Channels', + description: 'Show logged-in users an aggregate view of the channels, models and pricing they can access. Disabled by default.', + enabled: 'Enable Available Channels', + enabledHint: 'When off, the sidebar entry is hidden and the endpoint returns an empty list.', + }, }, emailTabDisabledTitle: 'Email Verification Not Enabled', emailTabDisabledHint: 'Enable email verification in the Security tab to configure SMTP settings.', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index e1f0d9670f..da5b3a25ef 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -4714,6 +4714,12 @@ export default { defaultInterval: '默认检测间隔(秒)', defaultIntervalHint: '新建渠道监控时表单的默认值,可被单个渠道覆盖。范围 15 – 3600 秒。', }, + availableChannels: { + title: '可用渠道', + description: '向已登录用户展示他们能访问的渠道、模型和定价聚合视图。默认关闭。', + enabled: '启用可用渠道', + enabledHint: '关闭后用户端侧边栏入口隐藏,接口返回空数组。', + }, }, emailTabDisabledTitle: '邮箱验证未启用', emailTabDisabledHint: '请在「安全与认证」选项卡中启用邮箱验证后,再配置 SMTP 设置。', diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index 256a10e4de..127682e3b6 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -345,6 +345,7 @@ export const useAppStore = defineStore('app', () => { balance_low_notify_threshold: 0, channel_monitor_enabled: true, channel_monitor_default_interval_seconds: 60, + available_channels_enabled: false, } } diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index eb7206459b..27f359f0ec 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -132,6 +132,7 @@ export interface PublicSettings { balance_low_notify_threshold: number channel_monitor_enabled: boolean channel_monitor_default_interval_seconds: number + available_channels_enabled: boolean } export interface AuthResponse { diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index 90968c07bd..b8c247e6bb 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -2416,6 +2416,30 @@ +
+
+

+ {{ t('admin.settings.features.availableChannels.title') }} +

+

+ {{ t('admin.settings.features.availableChannels.description') }} +

+
+
+
+
+ +

+ {{ t('admin.settings.features.availableChannels.enabledHint') }} +

+
+ +
+
+
+ @@ -3145,7 +3169,9 @@ const form = reactive({ account_quota_notify_emails: [] as NotifyEmailEntry[], // Channel Monitor feature switch channel_monitor_enabled: true, - channel_monitor_default_interval_seconds: 60 + channel_monitor_default_interval_seconds: 60, + // Available Channels feature switch + available_channels_enabled: false }) // Proxies for web search emulation ProxySelector @@ -3749,6 +3775,8 @@ async function saveSettings() { // Channel Monitor feature switch channel_monitor_enabled: form.channel_monitor_enabled, channel_monitor_default_interval_seconds: Number(form.channel_monitor_default_interval_seconds) || 60, + // Available Channels feature switch + available_channels_enabled: form.available_channels_enabled, } const updated = await adminAPI.settings.updateSettings(payload)