@@ -317,12 +317,23 @@ <h3 class="font-bold text-xs text-white flex items-center gap-2">
317317 < div class ="flex items-center gap-1.5 flex-wrap " id ="modelTagRow ">
318318 < button class ="mfilter-chip on " data-tag ="all "> 全部</ button >
319319 < button class ="mfilter-chip " data-tag ="go "> GO</ button >
320+ < button class ="mfilter-chip " data-tag ="goat "> GOAT</ button >
320321 < button class ="mfilter-chip " data-tag ="free "> FREE</ button >
321322 < button class ="mfilter-chip " data-tag ="deal "> DEAL</ button >
322323 < button class ="mfilter-chip " data-tag ="vision "> 视觉</ button >
323324 < button class ="mfilter-chip " data-tag ="reason "> 推理</ button >
324325 </ div >
325- < p id ="modelsCount " class ="text-[11px] text-slate-500 text-right "> </ p >
326+ < div class ="flex items-end justify-between gap-x-4 gap-y-1 flex-wrap ">
327+ < p class ="text-[11px] text-slate-500 leading-relaxed ">
328+ 每张卡片底部「档位」行标注该模型在两个套餐下的可用性:
329+ < span class ="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded border font-semibold bg-indigo-500/15 text-indigo-300 border-indigo-500/40 "> GO< i class ="fa-solid fa-check text-[9px] opacity-80 "> </ i > </ span >
330+ / < span class ="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded border font-semibold bg-amber-500/15 text-amber-300 border-amber-500/40 "> < i class ="fa-solid fa-crown text-[9px] "> </ i > GOAT< i class ="fa-solid fa-check text-[9px] opacity-80 "> </ i > </ span >
331+ 为可用,
332+ < span class ="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded border font-semibold bg-slate-800/40 text-slate-400 border-slate-700/70 "> GO< i class ="fa-solid fa-xmark text-[9px] opacity-80 "> </ i > </ span >
333+ 为不可用。
334+ </ p >
335+ < p id ="modelsCount " class ="text-[11px] text-slate-500 text-right "> </ p >
336+ </ div >
326337 </ div >
327338 < div id ="modelsList " class ="grid grid-cols-1 md:grid-cols-3 gap-3 "> </ div >
328339</ section >
@@ -635,9 +646,43 @@ <h3 class="text-base font-bold text-white flex items-center gap-2"><i class="fa-
635646let modelTagFilter = 'all' ;
636647let modelSortMode = 'default' ;
637648let modelQueryTimer = null ;
649+ // 档位键名与显示名,需与 src/utils/plans.ts 的 PLAN_TIERS 保持一致。
650+ const PLAN_LABELS = {
651+ 'individual-free' : 'Free' , 'individual-go' : 'Go' , 'individual-goat' : 'GOAT' ,
652+ 'individual-pro' : 'Pro' , 'individual-pro-v1' : 'Pro (v1)' , 'individual-provider' : 'Provider' ,
653+ 'individual-max' : 'Max' , 'individual-ultra' : 'Ultra' , 'teams-pro' : 'Team Pro' ,
654+ } ;
655+ // 判定「档位可用」只看该档位自己的布尔值;availability 缺失时退回旧的 onGoPlan。
656+ function isPlanOn ( m , key ) {
657+ const a = m && m . availability ;
658+ if ( a && Object . keys ( a ) . length ) return a [ key ] === true ;
659+ return key === 'individual-go' ? ! ! m . onGoPlan : false ;
660+ }
661+ function higherPlanNames ( avail ) {
662+ return [ 'individual-pro' , 'individual-pro-v1' , 'individual-provider' , 'individual-max' , 'individual-ultra' , 'teams-pro' ]
663+ . filter ( k => avail [ k ] === true ) . map ( k => PLAN_LABELS [ k ] || k ) ;
664+ }
665+ const BADGE_TONES = {
666+ rose : 'bg-rose-500/15 text-rose-300 border-rose-500/30' ,
667+ amber : 'bg-amber-500/15 text-amber-300 border-amber-500/30' ,
668+ slate : 'bg-slate-500/15 text-slate-300 border-slate-500/30' ,
669+ } ;
670+ function badge ( text , tone , title ) {
671+ return '<span class="text-[10px] px-2 py-0.5 rounded border font-semibold ' + BADGE_TONES [ tone ] + '"' +
672+ ( title ? ' title="' + esc ( title ) + '"' : '' ) + '>' + text + '</span>' ;
673+ }
674+ // 档位药丸:可用=实心强调色,不可用=灰底。两枚固定占位,卡片高度一致,
675+ // 整列纵向对齐后即可一眼比较 GO / GOAT 的差别。
676+ function planPill ( key , label , on , onTone ) {
677+ const cls = on ? onTone : 'bg-slate-800/40 text-slate-400 border-slate-700/70' ;
678+ return '<span class="inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded border font-semibold ' + cls +
679+ '" title="' + ( PLAN_LABELS [ key ] || key ) + ' 档位:' + ( on ? '可用' : '不可用' ) + '">' +
680+ label + '<i class="fa-solid ' + ( on ? 'fa-check' : 'fa-xmark' ) + ' text-[9px] opacity-80"></i></span>' ;
681+ }
638682function modelMatchesTag ( m , tag ) {
639683 const caps = m . caps || { } ;
640- if ( tag === 'go' ) return ! ! m . onGoPlan ;
684+ if ( tag === 'go' ) return isPlanOn ( m , 'individual-go' ) ;
685+ if ( tag === 'goat' ) return isPlanOn ( m , 'individual-goat' ) ;
641686 if ( tag === 'free' ) return ! ! ( m . deal && m . deal . free ) ;
642687 if ( tag === 'deal' ) return ! ! ( m . deal && m . deal . discountPercent ) ;
643688 if ( tag === 'vision' ) return ! ! ( caps . vision || m . supports_vision ) ;
@@ -678,7 +723,12 @@ <h3 class="text-base font-bold text-white flex items-center gap-2"><i class="fa-
678723 if ( clearBtn ) clearBtn . classList . toggle ( 'hidden' , ! q ) ;
679724 const filtered = sortModels ( allModelsCache . filter ( m => modelMatchesTag ( m , modelTagFilter ) && modelMatchesQuery ( m , q ) ) ) ;
680725 const meta = document . getElementById ( 'modelsCount' ) ;
681- if ( meta ) meta . innerText = '共 ' + allModelsCache . length + ' 个 · 命中 ' + filtered . length + ' 个' ;
726+ if ( meta ) {
727+ const goCount = allModelsCache . filter ( m => isPlanOn ( m , 'individual-go' ) ) . length ;
728+ const goatCount = allModelsCache . filter ( m => isPlanOn ( m , 'individual-goat' ) ) . length ;
729+ meta . innerText = '共 ' + allModelsCache . length + ' 个 · 命中 ' + filtered . length +
730+ ' 个 · Go 档可用 ' + goCount + ' 个 · GOAT 档可用 ' + goatCount + ' 个' ;
731+ }
682732 const c = document . getElementById ( 'modelsList' ) ;
683733 if ( ! filtered . length ) {
684734 c . innerHTML = '<div class="col-span-full text-center py-12 text-slate-500 text-xs"><i class="fa-solid fa-magnifying-glass text-2xl mb-3 block text-slate-600"></i>没有匹配的模型,换个关键词或标签试试</div>' ;
@@ -687,11 +737,17 @@ <h3 class="text-base font-bold text-white flex items-center gap-2"><i class="fa-
687737 c . innerHTML = filtered . map ( m => {
688738 const p = m . pricing || { } ;
689739 const caps = m . caps || { } ;
740+ const avail = m . availability || { } ;
741+ const goOn = isPlanOn ( m , 'individual-go' ) ;
742+ const goatOn = isPlanOn ( m , 'individual-goat' ) ;
743+ const higher = higherPlanNames ( avail ) ;
690744 let tags = '' ;
691- if ( m . onGoPlan ) tags += '<span class="text-[10px] px-2 py-0.5 rounded bg-indigo-500/15 text-indigo-300 border border-indigo-500/30 font-semibold">GO</span>' ;
692- if ( m . deal && m . deal . free ) tags += '<span class="text-[10px] px-2 py-0.5 rounded bg-rose-500/15 text-rose-300 border border-rose-500/30 font-semibold">FREE</span>' ;
693- else if ( m . deal && m . deal . discountPercent ) tags += '<span class="text-[10px] px-2 py-0.5 rounded bg-amber-500/15 text-amber-300 border border-amber-500/30 font-semibold">DEAL ' + m . deal . discountPercent + '%</span>' ;
694- if ( ! tags ) tags = '<span class="text-[10px] px-2 py-0.5 rounded bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 font-semibold">可用</span>' ;
745+ if ( m . deal && m . deal . free ) tags += badge ( 'FREE' , 'rose' ) ;
746+ else if ( m . deal && m . deal . discountPercent ) tags += badge ( 'DEAL ' + m . deal . discountPercent + '%' , 'amber' ) ;
747+ // GO/GOAT 都不可用时,用一枚中性徽章说明它属于更高的付费档位,避免误读成"不可调用"。
748+ if ( ! goOn && ! goatOn && higher . length ) {
749+ tags += badge ( '更高档位' , 'slate' , '仅在这些档位可用:' + higher . join ( ' · ' ) ) ;
750+ }
695751 const capsStr = '文字' + ( caps . text ? '✓' : '✗' ) + ' · 视觉' + ( ( caps . vision || m . supports_vision ) ? '✓' : '✗' ) + ' · 推理' + ( caps . reasoning ? '✓' : '✗' ) ;
696752 return '<div class="p-3 bg-slate-900 border border-slate-800 rounded-lg hover:border-indigo-500/40 transition">' +
697753 '<div class="flex items-start justify-between gap-2">' +
@@ -707,6 +763,11 @@ <h3 class="text-base font-bold text-white flex items-center gap-2"><i class="fa-
707763 '<span>缓存写:<span class="text-slate-200">' + fmtPrice ( p . cacheWrite ) + '</span></span>' +
708764 '<span class="text-slate-500">' + capsStr + '</span>' +
709765 '</div>' +
766+ '<div class="mt-2 pt-2 border-t border-slate-800/70 flex items-center gap-1.5">' +
767+ '<span class="text-[10px] text-slate-500">档位</span>' +
768+ planPill ( 'individual-go' , 'GO' , goOn , 'bg-indigo-500/15 text-indigo-300 border-indigo-500/40' ) +
769+ planPill ( 'individual-goat' , goatOn ? '<i class="fa-solid fa-crown text-[9px]"></i>GOAT' : 'GOAT' , goatOn , 'bg-amber-500/15 text-amber-300 border-amber-500/40' ) +
770+ '</div>' +
710771 '</div>' ;
711772 } ) . join ( '' ) ;
712773}
0 commit comments