@@ -81,6 +81,7 @@ interface AccountTableProps {
8181 /** 拖拽排序回调,当用户完成拖拽时触发 */
8282 onReorder ?: ( accountIds : string [ ] ) => void ;
8383 onViewError : ( accountId : string ) => void ;
84+ quotaWindow ?: '5h' | 'weekly' ;
8485}
8586
8687interface SortableRowProps {
@@ -101,6 +102,7 @@ interface SortableRowProps {
101102 onWarmup ?: ( ) => void ;
102103 onUpdateLabel ?: ( label : string ) => void ;
103104 onViewError : ( ) => void ;
105+ quotaWindow ?: '5h' | 'weekly' ;
104106}
105107
106108interface AccountRowContentProps {
@@ -119,6 +121,7 @@ interface AccountRowContentProps {
119121 onWarmup ?: ( ) => void ;
120122 onUpdateLabel ?: ( label : string ) => void ;
121123 onViewError : ( ) => void ;
124+ quotaWindow ?: '5h' | 'weekly' ;
122125}
123126
124127// ============================================================================
@@ -177,6 +180,7 @@ function SortableAccountRow({
177180 onWarmup,
178181 onUpdateLabel,
179182 onViewError,
183+ quotaWindow,
180184} : SortableRowProps ) {
181185 const { t } = useTranslation ( ) ;
182186 const {
@@ -221,10 +225,10 @@ function SortableAccountRow({
221225 < td className = "px-2 py-1 w-10 align-middle" >
222226 < input
223227 type = "checkbox"
224- className = "checkbox checkbox-xs rounded border-2 border-gray-400 dark:border-gray-500 checked:border-blue-600 checked:bg-blue-600 [--chkbg:theme(colors.blue.600)] [--chkfg:white]"
228+ className = "checkbox checkbox-sm rounded border-2 border-gray-400 dark:border-gray-500 checked:border-blue-600 checked:bg-blue-600 [--chkbg:theme(colors.blue.600)] [--chkfg:white]"
225229 checked = { selected }
226230 onChange = { onSelect }
227- onClick = { ( e ) => e . stopPropagation ( ) }
231+ disabled = { isRefreshing }
228232 />
229233 </ td >
230234 < AccountRowContent
@@ -243,6 +247,7 @@ function SortableAccountRow({
243247 onWarmup = { onWarmup }
244248 onUpdateLabel = { onUpdateLabel }
245249 onViewError = { onViewError }
250+ quotaWindow = { quotaWindow }
246251 />
247252 </ tr >
248253 ) ;
@@ -268,6 +273,7 @@ function AccountRowContent({
268273 onWarmup,
269274 onUpdateLabel,
270275 onViewError,
276+ quotaWindow,
271277} : AccountRowContentProps ) {
272278 const { t } = useTranslation ( ) ;
273279 const { config, showAllQuotas } = useConfigStore ( ) ;
@@ -297,7 +303,26 @@ function AccountRowContent({
297303 }
298304 } ;
299305
300- // 使用统一的模型配置
306+ // 解析周配额项 (当处于 weekly 视图时)
307+ const weeklyItems = useMemo ( ( ) => {
308+ if ( quotaWindow !== 'weekly' ) return [ ] ;
309+ return ( account . quota ?. quota_groups || [ ] ) . flatMap ( group => {
310+ return group . buckets
311+ . filter ( b => b . window . toLowerCase ( ) . includes ( 'week' ) || b . bucket_id . toLowerCase ( ) . includes ( 'week' ) )
312+ . map ( b => {
313+ const shortGroupName = group . display_name
314+ . replace ( / m o d e l s ? $ / i, '' )
315+ . replace ( / C l a u d e a n d G P T / i, 'Claude/GPT' ) ;
316+ return {
317+ id : `${ group . display_name } -${ b . bucket_id } ` ,
318+ label : b . display_name ? `${ shortGroupName } (${ b . display_name } )` : `${ shortGroupName } (周)` ,
319+ percentage : Math . round ( ( b . remaining_fraction || 0 ) * 100 ) ,
320+ resetTime : b . reset_time ,
321+ Icon : shortGroupName . toLowerCase ( ) . includes ( 'claude' ) ? Sparkles : Bot ,
322+ } ;
323+ } ) ;
324+ } ) ;
325+ } , [ quotaWindow , account . quota ?. quota_groups ] ) ;
301326
302327 // 获取要显示的模型列表
303328 const pinnedModels = ensurePinnedImageSelector (
@@ -509,23 +534,37 @@ function AccountRowContent({
509534 ) : (
510535 < div className = { cn (
511536 "grid gap-x-2 gap-y-1 py-0" ,
512- displayModels . length === 1 ? "grid-cols-1" : "grid-cols-2"
537+ ( quotaWindow === 'weekly' && weeklyItems . length > 0 )
538+ ? ( weeklyItems . length === 1 ? "grid-cols-1" : "grid-cols-2" )
539+ : ( displayModels . length === 1 ? "grid-cols-1" : "grid-cols-2" )
513540 ) } >
514- { displayModels . map ( ( model ) => {
515- const modelData = model . data ;
516-
517- return (
541+ { quotaWindow === 'weekly' && weeklyItems . length > 0 ? (
542+ weeklyItems . map ( ( item ) => (
518543 < QuotaItem
519- key = { model . id }
520- label = { model . label }
521- percentage = { modelData ?. percentage || 0 }
522- resetTime = { modelData ?. reset_time }
523- isProtected = { isModelProtected ( account . protected_models , model . protectedKey ) }
524- liveLimit = { getLiveLimitForModel ( account , model . id , model . protectedKey ) }
525- Icon = { MODEL_CONFIG [ model . id ] ?. Icon || Bot }
544+ key = { item . id }
545+ label = { item . label }
546+ percentage = { item . percentage }
547+ resetTime = { item . resetTime }
548+ Icon = { item . Icon }
526549 />
527- ) ;
528- } ) }
550+ ) )
551+ ) : (
552+ displayModels . map ( ( model ) => {
553+ const modelData = model . data ;
554+
555+ return (
556+ < QuotaItem
557+ key = { model . id }
558+ label = { model . label }
559+ percentage = { modelData ?. percentage || 0 }
560+ resetTime = { modelData ?. reset_time }
561+ isProtected = { isModelProtected ( account . protected_models , model . protectedKey ) }
562+ liveLimit = { getLiveLimitForModel ( account , model . id , model . protectedKey ) }
563+ Icon = { MODEL_CONFIG [ model . id ] ?. Icon || Bot }
564+ />
565+ ) ;
566+ } )
567+ ) }
529568 </ div >
530569 ) }
531570 </ td >
@@ -686,6 +725,7 @@ function AccountTable({
686725 onWarmup,
687726 onUpdateLabel,
688727 onViewError,
728+ quotaWindow,
689729} : AccountTableProps ) {
690730 const { t } = useTranslation ( ) ;
691731
@@ -756,7 +796,7 @@ function AccountTable({
756796 </ th >
757797 < th className = "px-2 py-1 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-[300px] whitespace-nowrap" > { t ( 'accounts.table.email' ) } </ th >
758798 < th className = "px-2 py-1 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider min-w-[340px] whitespace-nowrap" >
759- { t ( 'accounts.table.quota' ) }
799+ { quotaWindow === 'weekly' ? t ( 'accounts.table.weekly_quota' , '周配额' ) : t ( 'accounts.table.quota' ) }
760800 </ th >
761801 < th className = "px-2 py-1 text-left rtl:text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-[90px] whitespace-nowrap" > { t ( 'accounts.table.last_used' ) } </ th >
762802 < th className = "px-2 py-1 text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider whitespace-nowrap sticky right-0 w-[220px] bg-gray-50 dark:bg-base-200 z-20 shadow-[-12px_0_12px_-12px_rgba(0,0,0,0.1)] dark:shadow-[-12px_0_12px_-12px_rgba(255,255,255,0.05)] text-center" > { t ( 'accounts.table.actions' ) } </ th >
@@ -784,6 +824,7 @@ function AccountTable({
784824 onWarmup = { onWarmup ? ( ) => onWarmup ( account . id ) : undefined }
785825 onUpdateLabel = { onUpdateLabel ? ( label : string ) => onUpdateLabel ( account . id , label ) : undefined }
786826 onViewError = { ( ) => onViewError ( account . id ) }
827+ quotaWindow = { quotaWindow }
787828 />
788829 ) ) }
789830 </ tbody >
@@ -825,6 +866,7 @@ function AccountTable({
825866 onToggleProxy = { ( ) => { } }
826867 isDisabled = { Boolean ( activeAccount . disabled ) }
827868 onViewError = { ( ) => { } }
869+ quotaWindow = { quotaWindow }
828870 />
829871 </ tr >
830872 </ tbody >
0 commit comments