@@ -53,7 +53,7 @@ const UserBindingManagementModal = ({
5353} ) => {
5454 const { t } = useTranslation ( ) ;
5555 const [ bindingLoading , setBindingLoading ] = React . useState ( false ) ;
56- const [ showUnboundOnly , setShowUnboundOnly ] = React . useState ( false ) ;
56+ const [ showBoundOnly , setShowBoundOnly ] = React . useState ( true ) ;
5757 const [ statusInfo , setStatusInfo ] = React . useState ( { } ) ;
5858 const [ customOAuthBindings , setCustomOAuthBindings ] = React . useState ( [ ] ) ;
5959 const [ bindingActionLoading , setBindingActionLoading ] = React . useState ( { } ) ;
@@ -90,7 +90,7 @@ const UserBindingManagementModal = ({
9090
9191 React . useEffect ( ( ) => {
9292 if ( ! visible ) return ;
93- setShowUnboundOnly ( false ) ;
93+ setShowBoundOnly ( true ) ;
9494 setBindingActionLoading ( { } ) ;
9595 loadBindingData ( ) ;
9696 } , [ visible , loadBindingData ] ) ;
@@ -294,8 +294,12 @@ const UserBindingManagementModal = ({
294294 ...customBindingItems . map ( ( item ) => ( { ...item , type : 'custom' } ) ) ,
295295 ] ;
296296
297- const visibleBindingItems = showUnboundOnly
298- ? allBindingItems . filter ( ( item ) => ! item . value )
297+ const boundCount = allBindingItems . filter ( ( item ) =>
298+ Boolean ( item . value ) ,
299+ ) . length ;
300+
301+ const visibleBindingItems = showBoundOnly
302+ ? allBindingItems . filter ( ( item ) => Boolean ( item . value ) )
299303 : allBindingItems ;
300304
301305 return (
@@ -308,86 +312,96 @@ const UserBindingManagementModal = ({
308312 title = {
309313 < div className = 'flex items-center' >
310314 < IconLink className = 'mr-2' />
311- { t ( '绑定信息 ' ) }
315+ { t ( '账户绑定管理 ' ) }
312316 </ div >
313317 }
314318 >
315319 < Spin spinning = { bindingLoading } >
316- < div className = 'flex items-center justify-between mb-4 gap-3 flex-wrap' >
317- < Checkbox
318- checked = { showUnboundOnly }
319- onChange = { ( e ) => setShowUnboundOnly ( Boolean ( e . target . checked ) ) }
320- >
321- { `${ t ( '筛选' ) } ${ t ( '未绑定' ) } ` }
322- </ Checkbox >
323- < Text type = 'tertiary' >
324- { t ( '筛选' ) } · { visibleBindingItems . length }
325- </ Text >
326- </ div >
320+ < div className = 'max-h-[68vh] overflow-y-auto pr-1 pb-2' >
321+ < div className = 'flex items-center justify-between mb-4 gap-3 flex-wrap' >
322+ < Checkbox
323+ checked = { showBoundOnly }
324+ onChange = { ( e ) => setShowBoundOnly ( Boolean ( e . target . checked ) ) }
325+ >
326+ { t ( '仅显示已绑定' ) }
327+ </ Checkbox >
328+ < Text type = 'tertiary' >
329+ { t ( '已绑定' ) } { boundCount } / { allBindingItems . length }
330+ </ Text >
331+ </ div >
327332
328- { visibleBindingItems . length === 0 ? (
329- < Card className = '!rounded-xl border-dashed' >
330- < Text type = 'tertiary' > { t ( '暂无自定义 OAuth 提供商' ) } </ Text >
331- </ Card >
332- ) : (
333- < div className = 'grid grid-cols-1 lg:grid-cols-2 gap-3' >
334- { visibleBindingItems . map ( ( item ) => {
335- const isBound = Boolean ( item . value ) ;
336- const loadingKey =
337- item . type === 'builtin'
338- ? `builtin-${ item . key } `
339- : `custom-${ item . providerId } ` ;
340- const statusText = isBound
341- ? item . value
342- : item . enabled
343- ? t ( '未绑定' )
344- : t ( '未启用' ) ;
333+ { visibleBindingItems . length === 0 ? (
334+ < Card className = '!rounded-xl border-dashed' >
335+ < Text type = 'tertiary' > { t ( '暂无已绑定项' ) } </ Text >
336+ </ Card >
337+ ) : (
338+ < div className = 'grid grid-cols-1 lg:grid-cols-2 gap-4' >
339+ { visibleBindingItems . map ( ( item , index ) => {
340+ const isBound = Boolean ( item . value ) ;
341+ const loadingKey =
342+ item . type === 'builtin'
343+ ? `builtin-${ item . key } `
344+ : `custom-${ item . providerId } ` ;
345+ const statusText = isBound
346+ ? item . value
347+ : item . enabled
348+ ? t ( '未绑定' )
349+ : t ( '未启用' ) ;
350+ const shouldSpanTwoColsOnDesktop =
351+ visibleBindingItems . length % 2 === 1 &&
352+ index === visibleBindingItems . length - 1 ;
345353
346- return (
347- < Card key = { item . key } className = '!rounded-xl' >
348- < div className = 'flex items-center justify-between gap-3' >
349- < div className = 'flex items-center flex-1 min-w-0' >
350- < div className = 'w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0' >
351- { item . icon }
352- </ div >
353- < div className = 'min-w-0 flex-1' >
354- < div className = 'font-medium text-gray-900 flex items-center gap-2' >
355- < span > { item . name } </ span >
356- < Tag size = 'small' color = 'white' >
357- { item . type === 'builtin' ? 'Built-in' : 'Custom' }
358- </ Tag >
354+ return (
355+ < Card
356+ key = { item . key }
357+ className = { `!rounded-xl ${ shouldSpanTwoColsOnDesktop ? 'lg:col-span-2' : '' } ` }
358+ >
359+ < div className = 'flex items-center justify-between gap-3 min-h-[92px]' >
360+ < div className = 'flex items-center flex-1 min-w-0' >
361+ < div className = 'w-10 h-10 rounded-full bg-slate-100 dark:bg-slate-700 flex items-center justify-center mr-3 flex-shrink-0' >
362+ { item . icon }
359363 </ div >
360- < div className = 'text-sm text-gray-500 truncate' >
361- { statusText }
364+ < div className = 'min-w-0 flex-1' >
365+ < div className = 'font-medium text-gray-900 flex items-center gap-2' >
366+ < span > { item . name } </ span >
367+ < Tag size = 'small' color = 'white' >
368+ { item . type === 'builtin'
369+ ? t ( '内置' )
370+ : t ( '自定义' ) }
371+ </ Tag >
372+ </ div >
373+ < div className = 'text-sm text-gray-500 truncate' >
374+ { statusText }
375+ </ div >
362376 </ div >
363377 </ div >
378+ < Button
379+ type = 'danger'
380+ theme = 'borderless'
381+ icon = { < IconDelete /> }
382+ size = 'small'
383+ disabled = { ! isBound }
384+ loading = { Boolean ( bindingActionLoading [ loadingKey ] ) }
385+ onClick = { ( ) => {
386+ if ( item . type === 'builtin' ) {
387+ handleUnbindBuiltInAccount ( item ) ;
388+ return ;
389+ }
390+ handleUnbindCustomOAuthAccount ( {
391+ id : item . providerId ,
392+ name : item . name ,
393+ } ) ;
394+ } }
395+ >
396+ { t ( '解绑' ) }
397+ </ Button >
364398 </ div >
365- < Button
366- type = 'danger'
367- theme = 'borderless'
368- icon = { < IconDelete /> }
369- size = 'small'
370- disabled = { ! isBound }
371- loading = { Boolean ( bindingActionLoading [ loadingKey ] ) }
372- onClick = { ( ) => {
373- if ( item . type === 'builtin' ) {
374- handleUnbindBuiltInAccount ( item ) ;
375- return ;
376- }
377- handleUnbindCustomOAuthAccount ( {
378- id : item . providerId ,
379- name : item . name ,
380- } ) ;
381- } }
382- >
383- { t ( '解绑' ) }
384- </ Button >
385- </ div >
386- </ Card >
387- ) ;
388- } ) }
389- </ div >
390- ) }
399+ </ Card >
400+ ) ;
401+ } ) }
402+ </ div >
403+ ) }
404+ </ div >
391405 </ Spin >
392406 </ Modal >
393407 ) ;
0 commit comments