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