feat(channels): themed model popover + group-badge with rate, subscription & exclusivity
Pricing popover: - Teleport to body + fixed-position re-measuring on hover/scroll/resize so it escapes the card's overflow-hidden clip that was chopping off the lower half of the panel. - Header + border adopt the platform theme via platformBorderClass / platformBadgeLightClass so each model card reads at a glance. Accessible groups: - Backend AvailableGroupRef / user DTO now expose subscription_type, rate_multiplier and is_exclusive. User-specific rates continue to come from /groups/rates (same pattern as the API keys page). - Table renders groups through the shared GroupBadge, which already deepens subscription-type colors and shows default vs custom rate as <s>default</s> <b>custom</b>. - Exclusive groups are labelled with a purple shield row, public groups with a grey globe row so admins and users can tell at a glance which groups they got via explicit grant vs. public access. i18n keys for exclusive / public / their tooltips added to zh + en.
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
:columns="columnLabels"
|
||||
:rows="filteredChannels"
|
||||
:loading="loading"
|
||||
:user-group-rates="userGroupRates"
|
||||
pricing-key-prefix="availableChannels.pricing"
|
||||
:no-pricing-label="t('availableChannels.noPricing')"
|
||||
:no-models-label="t('availableChannels.noModels')"
|
||||
@@ -55,6 +56,7 @@ import TablePageLayout from '@/components/layout/TablePageLayout.vue'
|
||||
import Icon from '@/components/icons/Icon.vue'
|
||||
import AvailableChannelsTable from '@/components/channels/AvailableChannelsTable.vue'
|
||||
import userChannelsAPI, { type UserAvailableChannel } from '@/api/channels'
|
||||
import userGroupsAPI from '@/api/groups'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { extractApiErrorMessage } from '@/utils/apiError'
|
||||
|
||||
@@ -62,6 +64,7 @@ const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const channels = ref<UserAvailableChannel[]>([])
|
||||
const userGroupRates = ref<Record<number, number>>({})
|
||||
const loading = ref(false)
|
||||
const searchQuery = ref('')
|
||||
|
||||
@@ -101,7 +104,17 @@ const filteredChannels = computed(() => {
|
||||
async function loadChannels() {
|
||||
loading.value = true
|
||||
try {
|
||||
channels.value = await userChannelsAPI.getAvailable()
|
||||
// 渠道列表和用户专属倍率并发拉取。专属倍率失败不阻塞渠道展示——
|
||||
// 失败时只是无法渲染专属倍率角标,降级为仅显示默认倍率。
|
||||
const [list, rates] = await Promise.all([
|
||||
userChannelsAPI.getAvailable(),
|
||||
userGroupsAPI.getUserGroupRates().catch((err: unknown) => {
|
||||
console.error('Failed to load user group rates:', err)
|
||||
return {} as Record<number, number>
|
||||
}),
|
||||
])
|
||||
channels.value = list
|
||||
userGroupRates.value = rates
|
||||
} catch (err: unknown) {
|
||||
appStore.showError(extractApiErrorMessage(err, t('common.error')))
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user