mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
- public /model-plaza page (standalone + admin-embedded) listing groups with discounted effective prices alongside LiteLLM official reference - faceted platform/group/rate filters: cross-dimension options gray out instead of disappearing, platform-tinted chips via accent color-mix - paid-price columns highlighted with per-platform tint band - OptionalJWT middleware so anonymous and signed-in users share one route - admin settings: enable switch, require-auth switch, markdown description
94 lines
3.4 KiB
Vue
94 lines
3.4 KiB
Vue
<template>
|
|
<section
|
|
class="rounded-2xl border bg-white shadow-card dark:bg-dark-800/50"
|
|
:class="[platformBorderStrongClass(group.platform)]"
|
|
>
|
|
<!-- 分组头部:名称/平台/倍率徽章/专属/订阅徽章 + 描述 -->
|
|
<header class="border-b border-gray-100 px-5 py-4 dark:border-dark-700/60">
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<GroupBadge
|
|
:name="group.name"
|
|
:platform="group.platform as GroupPlatform"
|
|
:subscription-type="(group.subscription_type || 'standard') as SubscriptionType"
|
|
:rate-multiplier="group.rate_multiplier"
|
|
:user-rate-multiplier="group.user_rate_multiplier ?? null"
|
|
:peak-rate-enabled="group.peak_rate_enabled"
|
|
:peak-start="group.peak_start"
|
|
:peak-end="group.peak_end"
|
|
:peak-rate-multiplier="group.peak_rate_multiplier"
|
|
always-show-rate
|
|
/>
|
|
<span
|
|
v-if="group.is_exclusive"
|
|
class="inline-flex items-center gap-1 rounded-md bg-purple-50 px-2 py-0.5 text-xs font-medium text-purple-600 dark:bg-purple-900/20 dark:text-purple-400"
|
|
>
|
|
<Icon name="shield" size="xs" class="h-3 w-3" />
|
|
{{ t('modelPlaza.badges.exclusive') }}
|
|
</span>
|
|
<span
|
|
v-if="group.subscription_type === 'subscription'"
|
|
class="inline-flex items-center rounded-md bg-violet-50 px-2 py-0.5 text-xs font-medium text-violet-600 dark:bg-violet-900/20 dark:text-violet-400"
|
|
>
|
|
{{ t('modelPlaza.badges.subscription') }}
|
|
</span>
|
|
</div>
|
|
<p v-if="group.description" class="mt-2 text-sm text-gray-500 dark:text-dark-400">
|
|
{{ group.description }}
|
|
</p>
|
|
<p
|
|
v-if="peakNote"
|
|
class="mt-1.5 inline-flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400"
|
|
>
|
|
<Icon name="clock" size="xs" class="h-3 w-3" />
|
|
{{ peakNote }}
|
|
</p>
|
|
</header>
|
|
|
|
<!-- 模型价格表 -->
|
|
<div class="px-5">
|
|
<PlazaModelPricingTable
|
|
v-if="group.models.length > 0"
|
|
:models="group.models"
|
|
:platform="group.platform"
|
|
:rate-multiplier="group.rate_multiplier"
|
|
:user-rate-multiplier="group.user_rate_multiplier ?? null"
|
|
/>
|
|
<p v-else class="py-4 text-center text-sm text-gray-400 dark:text-dark-500">
|
|
{{ t('modelPlaza.detail.noModels') }}
|
|
</p>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
import Icon from '@/components/icons/Icon.vue'
|
|
import GroupBadge from '@/components/common/GroupBadge.vue'
|
|
import PlazaModelPricingTable from './PlazaModelPricingTable.vue'
|
|
import type { ModelPlazaGroup } from '@/api/modelPlaza'
|
|
import type { GroupPlatform, SubscriptionType } from '@/types'
|
|
import { platformBorderStrongClass } from '@/utils/platformColors'
|
|
import { hasPeakRate, formatPeakRateWindow, serverTimezoneLabel } from '@/utils/peak-rate'
|
|
import { useAppStore } from '@/stores/app'
|
|
|
|
const props = defineProps<{
|
|
group: ModelPlazaGroup
|
|
}>()
|
|
|
|
const { t } = useI18n()
|
|
const appStore = useAppStore()
|
|
|
|
const peakNote = computed(() => {
|
|
if (!hasPeakRate(props.group)) return ''
|
|
const window = formatPeakRateWindow(
|
|
props.group,
|
|
serverTimezoneLabel(appStore.cachedPublicSettings?.server_utc_offset)
|
|
)
|
|
return t('modelPlaza.detail.peakNote', {
|
|
window,
|
|
multiplier: props.group.peak_rate_multiplier
|
|
})
|
|
})
|
|
</script>
|