From 5ce7ba3cb87926508529c1f16736afa516a00b07 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 14 Mar 2026 02:02:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20tab=E5=90=8D=E7=A7=B0=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E4=BD=99=E9=A2=9D=E5=85=85=E5=80=BC/=E5=A5=97=E9=A4=90?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E3=80=81=E6=9C=89=E6=95=88=E6=9C=9F=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E6=98=BE=E7=A4=BA=E9=85=8D=E7=BD=AE=E5=80=BC=E3=80=81?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=A0=87=E7=AD=BE=E8=B7=9F=E9=9A=8F=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E9=A2=9C=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. MainTabs: "按量付费"→"余额充值","包月套餐"→"套餐订阅" 2. subscription-utils: 去掉所有智能转换,配置什么就显示什么(1月/30天/2周) 3. platform-style: 新增 modelTag 样式字段,每个平台独立颜色 4. ChannelCard: 模型标签颜色跟随平台(橙/绿/蓝/粉/紫)而非统一蓝色 --- src/components/ChannelCard.tsx | 10 +++---- src/components/MainTabs.tsx | 4 +-- src/lib/platform-style.ts | 11 ++++++++ src/lib/subscription-utils.ts | 51 +++++++++++++++------------------- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/components/ChannelCard.tsx b/src/components/ChannelCard.tsx index 654149e..77ac5b4 100644 --- a/src/components/ChannelCard.tsx +++ b/src/components/ChannelCard.tsx @@ -3,7 +3,7 @@ import React from 'react'; import type { Locale } from '@/lib/locale'; import { pickLocaleText } from '@/lib/locale'; -import { PlatformBadge } from '@/lib/platform-style'; +import { PlatformBadge, getPlatformStyle } from '@/lib/platform-style'; export interface ChannelInfo { id: string; @@ -26,6 +26,8 @@ interface ChannelCardProps { export default function ChannelCard({ channel, onTopUp, isDark, locale }: ChannelCardProps) { const usableQuota = (1 / channel.rateMultiplier).toFixed(2); + const platformStyle = getPlatformStyle(channel.platform); + const tagCls = isDark ? platformStyle.modelTag.dark : platformStyle.modelTag.light; return (
- + {model} ))} diff --git a/src/components/MainTabs.tsx b/src/components/MainTabs.tsx index c88aa5b..31e3362 100644 --- a/src/components/MainTabs.tsx +++ b/src/components/MainTabs.tsx @@ -18,9 +18,9 @@ export default function MainTabs({ activeTab, onTabChange, showSubscribeTab, sho const tabs: { key: 'topup' | 'subscribe'; label: string }[] = []; if (showTopUpTab) { - tabs.push({ key: 'topup', label: pickLocaleText(locale, '按量付费', 'Pay-as-you-go') }); + tabs.push({ key: 'topup', label: pickLocaleText(locale, '余额充值', 'Top Up') }); } - tabs.push({ key: 'subscribe', label: pickLocaleText(locale, '包月套餐', 'Subscription') }); + tabs.push({ key: 'subscribe', label: pickLocaleText(locale, '套餐订阅', 'Subscription') }); // 只有一个 tab 时不显示切换器 if (tabs.length <= 1) return null; diff --git a/src/lib/platform-style.ts b/src/lib/platform-style.ts index aa044ea..fed0194 100644 --- a/src/lib/platform-style.ts +++ b/src/lib/platform-style.ts @@ -6,6 +6,8 @@ export interface PlatformStyleEntry { label: string; /** SVG path data (viewBox 0 0 24 24) */ icon: string; + /** Model tag classes: { light: border+bg+text, dark: border+bg+text, dot: bg for the dot } */ + modelTag: { light: string; dark: string; dot: string }; } const PLATFORM_STYLES: Record = { @@ -14,41 +16,48 @@ const PLATFORM_STYLES: Record = { border: 'border-orange-500/20', label: 'Claude', icon: 'M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z', + modelTag: { light: 'border-orange-500/20 bg-gradient-to-r from-orange-500/10 to-amber-500/10 text-orange-600', dark: 'border-orange-500/20 bg-gradient-to-r from-orange-500/10 to-amber-500/10 text-orange-400', dot: 'bg-orange-500' }, }, anthropic: { badge: 'bg-orange-500/10 text-orange-600 dark:text-orange-400 border-orange-500/30', border: 'border-orange-500/20', label: 'Anthropic', icon: 'M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z', + modelTag: { light: 'border-orange-500/20 bg-gradient-to-r from-orange-500/10 to-amber-500/10 text-orange-600', dark: 'border-orange-500/20 bg-gradient-to-r from-orange-500/10 to-amber-500/10 text-orange-400', dot: 'bg-orange-500' }, }, openai: { badge: 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/30', border: 'border-green-500/20', label: 'OpenAI', + modelTag: { light: 'border-green-500/20 bg-gradient-to-r from-green-500/10 to-emerald-500/10 text-green-600', dark: 'border-green-500/20 bg-gradient-to-r from-green-500/10 to-emerald-500/10 text-green-400', dot: 'bg-green-500' }, icon: 'M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z', }, codex: { badge: 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/30', border: 'border-green-500/20', label: 'Codex', + modelTag: { light: 'border-green-500/20 bg-gradient-to-r from-green-500/10 to-emerald-500/10 text-green-600', dark: 'border-green-500/20 bg-gradient-to-r from-green-500/10 to-emerald-500/10 text-green-400', dot: 'bg-green-500' }, icon: 'M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z', }, gemini: { badge: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/30', border: 'border-blue-500/20', label: 'Gemini', + modelTag: { light: 'border-blue-500/20 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 text-blue-600', dark: 'border-blue-500/20 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 text-blue-400', dot: 'bg-blue-500' }, icon: 'M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81', }, google: { badge: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/30', border: 'border-blue-500/20', label: 'Google', + modelTag: { light: 'border-blue-500/20 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 text-blue-600', dark: 'border-blue-500/20 bg-gradient-to-r from-blue-500/10 to-indigo-500/10 text-blue-400', dot: 'bg-blue-500' }, icon: 'M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81', }, sora: { badge: 'bg-pink-500/10 text-pink-600 dark:text-pink-400 border-pink-500/30', border: 'border-pink-500/20', label: 'Sora', + modelTag: { light: 'border-pink-500/20 bg-gradient-to-r from-pink-500/10 to-rose-500/10 text-pink-600', dark: 'border-pink-500/20 bg-gradient-to-r from-pink-500/10 to-rose-500/10 text-pink-400', dot: 'bg-pink-500' }, // four-pointed sparkle star icon: 'M12 2l2.09 6.26L20.18 10l-6.09 1.74L12 18l-2.09-6.26L3.82 10l6.09-1.74L12 2z', }, @@ -56,6 +65,7 @@ const PLATFORM_STYLES: Record = { badge: 'bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/30', border: 'border-purple-500/20', label: 'Antigravity', + modelTag: { light: 'border-purple-500/20 bg-gradient-to-r from-purple-500/10 to-violet-500/10 text-purple-600', dark: 'border-purple-500/20 bg-gradient-to-r from-purple-500/10 to-violet-500/10 text-purple-400', dot: 'bg-purple-500' }, // stylised angular "A" cursor shape icon: 'M12 2L4 22h4l2-5h4l2 5h4L12 2zm0 7l2.5 6h-5L12 9z', }, @@ -66,6 +76,7 @@ const FALLBACK_STYLE: PlatformStyleEntry = { border: 'border-slate-500/20', label: '', icon: '', + modelTag: { light: 'border-slate-500/20 bg-gradient-to-r from-slate-500/10 to-slate-400/10 text-slate-600', dark: 'border-slate-500/20 bg-gradient-to-r from-slate-500/10 to-slate-400/10 text-slate-400', dot: 'bg-slate-500' }, }; export function getPlatformStyle(platform: string): PlatformStyleEntry { diff --git a/src/lib/subscription-utils.ts b/src/lib/subscription-utils.ts index b8ae324..9b32b71 100644 --- a/src/lib/subscription-utils.ts +++ b/src/lib/subscription-utils.ts @@ -18,34 +18,29 @@ export function computeValidityDays(value: number, unit: ValidityUnit, fromDate? } /** - * 智能格式化有效期显示文本。 - * - unit=month, value=1 → 包月 / Monthly - * - unit=month, value=3 → 包3月 / 3 Months - * - unit=week, value=2 → 包2周 / 2 Weeks - * - unit=day, value=30 → 包月 / Monthly (特殊处理) - * - unit=day, value=90 → 包90天 / 90 Days + * 格式化有效期显示文本(配置什么就显示什么,不做转换)。 + * - unit=month, value=1 → 1月 / 1 Month + * - unit=week, value=2 → 2周 / 2 Weeks + * - unit=day, value=30 → 30天 / 30 Days */ export function formatValidityLabel( value: number, unit: ValidityUnit, locale: 'zh' | 'en', ): string { - if (unit === 'month') { - if (value === 1) return locale === 'zh' ? '包月' : 'Monthly'; - return locale === 'zh' ? `包${value}月` : `${value} Months`; - } - if (unit === 'week') { - if (value === 1) return locale === 'zh' ? '包周' : 'Weekly'; - return locale === 'zh' ? `包${value}周` : `${value} Weeks`; - } - // day - return locale === 'zh' ? `${value}天` : `${value} Days`; + const unitLabels: Record = { + day: { zh: '天', en: 'Day', enPlural: 'Days' }, + week: { zh: '周', en: 'Week', enPlural: 'Weeks' }, + month: { zh: '月', en: 'Month', enPlural: 'Months' }, + }; + const u = unitLabels[unit]; + if (locale === 'zh') return `${value}${u.zh}`; + return `${value} ${value === 1 ? u.en : u.enPlural}`; } /** - * 智能格式化有效期后缀(用于价格展示)。 - * - unit=month, value=1 → /月 / /mo - * - unit=month, value=3 → /3月 / /3mo + * 格式化有效期后缀(用于价格展示,配置什么就显示什么)。 + * - unit=month, value=1 → /1月 / /1mo * - unit=week, value=2 → /2周 / /2wk * - unit=day, value=30 → /30天 / /30d */ @@ -54,16 +49,14 @@ export function formatValiditySuffix( unit: ValidityUnit, locale: 'zh' | 'en', ): string { - if (unit === 'month') { - if (value === 1) return locale === 'zh' ? '/月' : '/mo'; - return locale === 'zh' ? `/${value}月` : `/${value}mo`; - } - if (unit === 'week') { - if (value === 1) return locale === 'zh' ? '/周' : '/wk'; - return locale === 'zh' ? `/${value}周` : `/${value}wk`; - } - // day - return locale === 'zh' ? `/${value}天` : `/${value}d`; + const unitLabels: Record = { + day: { zh: '天', en: 'd' }, + week: { zh: '周', en: 'wk' }, + month: { zh: '月', en: 'mo' }, + }; + const u = unitLabels[unit]; + if (locale === 'zh') return `/${value}${u.zh}`; + return `/${value}${u.en}`; } /**