"backend/vscode:/vscode.git/clone" did not exist on "b17704d6effc717e5644ad09f61abe9aa2296775"
Commit 9dae6c7a authored by erio's avatar erio
Browse files

feat(sidebar+groups): available-channels above channel-status; show rate for subscription groups

- Sidebar user-side order: /available-channels now sits directly above
  /monitor (渠道状态) for regular users, mirroring the admin section where
  it sits above /admin/channels.
- GroupBadge gains an alwaysShowRate prop. Subscription groups default to
  a "订阅"/days-remaining label; the new flag swaps that for the rate
  multiplier while keeping the subscription theme color, so the Available
  Channels page can surface rates on every group type.
parent ff4ef1b5
......@@ -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
/>
</div>
<div
......@@ -104,6 +105,7 @@
:subscription-type="(g.subscription_type || 'standard') as SubscriptionType"
:rate-multiplier="g.rate_multiplier"
:user-rate-multiplier="userGroupRates[g.id] ?? null"
always-show-rate
/>
</div>
<span v-if="section.groups.length === 0" class="text-xs text-gray-400">-</span>
......
......@@ -37,13 +37,20 @@ interface Props {
userRateMultiplier?: number | null // 用户专属倍率
showRate?: boolean
daysRemaining?: number | null // 剩余天数(订阅类型时使用)
/**
* 订阅分组默认在右侧 label 展示"订阅"或剩余天数;
* 开启后订阅分组也改为显示倍率(保留订阅主题色 label,配合可用渠道这类
* 只关心费率、不关心有效期的场景)。
*/
alwaysShowRate?: boolean
}
const props = withDefaults(defineProps<Props>(), {
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
......
......@@ -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 => ({
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment