diff --git a/frontend/src/components/channels/AvailableChannelsTable.vue b/frontend/src/components/channels/AvailableChannelsTable.vue index 5963daff..e6f75766 100644 --- a/frontend/src/components/channels/AvailableChannelsTable.vue +++ b/frontend/src/components/channels/AvailableChannelsTable.vue @@ -83,6 +83,7 @@ :subscription-type="(g.subscription_type || 'standard') as SubscriptionType" :rate-multiplier="g.rate_multiplier" :user-rate-multiplier="userGroupRates[g.id] ?? null" + always-show-rate />
- diff --git a/frontend/src/components/common/GroupBadge.vue b/frontend/src/components/common/GroupBadge.vue index 83f4b8aa..3303d909 100644 --- a/frontend/src/components/common/GroupBadge.vue +++ b/frontend/src/components/common/GroupBadge.vue @@ -37,13 +37,20 @@ interface Props { userRateMultiplier?: number | null // 用户专属倍率 showRate?: boolean daysRemaining?: number | null // 剩余天数(订阅类型时使用) + /** + * 订阅分组默认在右侧 label 展示"订阅"或剩余天数; + * 开启后订阅分组也改为显示倍率(保留订阅主题色 label,配合可用渠道这类 + * 只关心费率、不关心有效期的场景)。 + */ + alwaysShowRate?: boolean } const props = withDefaults(defineProps(), { subscriptionType: 'standard', showRate: true, daysRemaining: null, - userRateMultiplier: null + userRateMultiplier: null, + alwaysShowRate: false }) const { t } = useI18n() @@ -71,7 +78,8 @@ const showLabel = computed(() => { // Label text const labelText = computed(() => { - if (isSubscription.value) { + const rateLabel = props.rateMultiplier !== undefined ? `${props.rateMultiplier}x` : '' + if (isSubscription.value && !props.alwaysShowRate) { // 如果有剩余天数,显示天数 if (props.daysRemaining !== null && props.daysRemaining !== undefined) { if (props.daysRemaining <= 0) { @@ -82,7 +90,7 @@ const labelText = computed(() => { // 否则显示"订阅" return t('groups.subscription') } - return props.rateMultiplier !== undefined ? `${props.rateMultiplier}x` : '' + return rateLabel }) // Label style based on type and days remaining diff --git a/frontend/src/components/layout/AppSidebar.vue b/frontend/src/components/layout/AppSidebar.vue index d828dc88..9dc107f6 100644 --- a/frontend/src/components/layout/AppSidebar.vue +++ b/frontend/src/components/layout/AppSidebar.vue @@ -640,7 +640,12 @@ const flagAdminPayment = () => adminSettingsStore.paymentEnabled // buildSelfNavItems 构造用户自己的导航项(用户端主菜单和管理员的"我的账户"子菜单共享这组声明)。 // withDashboard=true 时包含仪表盘(用户端),false 时不含(管理员的个人区已经有独立仪表盘入口)。 -function buildSelfNavItems(withDashboard: boolean): NavItem[] { +// includeAvailableChannels=false 时省略"可用渠道"入口——管理员在 admin 区已经有一个显眼入口, +// 重复显示会让管理员同时看到两处"可用渠道"。 +// +// 条目顺序:密钥 → 用量 → 可用渠道 → 渠道状态 → 订阅/支付 → 兑换/资料。 +// 可用渠道紧挨渠道状态之上,让用户"先看自己能用什么、再看对应状态"。 +function buildSelfNavItems(withDashboard: boolean, includeAvailableChannels = true): NavItem[] { const items: NavItem[] = [] if (withDashboard) { items.push({ path: '/dashboard', label: t('nav.dashboard'), icon: DashboardIcon }) @@ -648,11 +653,15 @@ function buildSelfNavItems(withDashboard: boolean): NavItem[] { items.push( { path: '/keys', label: t('nav.apiKeys'), icon: KeyIcon }, { path: '/usage', label: t('nav.usage'), icon: ChartIcon, hideInSimpleMode: true }, + ) + if (includeAvailableChannels) { + items.push({ path: '/available-channels', label: t('nav.availableChannels'), icon: ChannelIcon, hideInSimpleMode: true, featureFlag: flagAvailableChannels }) + } + items.push( { path: '/monitor', label: t('nav.channelStatus'), icon: SignalIcon, featureFlag: flagChannelMonitor }, { 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: '/redeem', label: t('nav.redeem'), icon: GiftIcon, hideInSimpleMode: true }, { path: '/profile', label: t('nav.profile'), icon: UserIcon }, ...customMenuItemsForUser.value.map((item): NavItem => ({