import { useEffect, useState } from 'react' import toast from 'react-hot-toast' import { Check, CheckSquare, Film, FolderLock, Layers, Loader2, Square, Tv, X, } from 'lucide-react' import { adminAPI } from '../api/admin' import { libraryAPI } from '../api/library' import type { Library, User } from '../types' import { libraryDisplayPath } from '../pages/libraryDisplayModel' type AdminUserLibrariesDialogProps = { user: User | null isOpen: boolean onClose: () => void onSaved: (updatedUser: User) => void } export function AdminUserLibrariesDialog({ user, isOpen, onClose, onSaved, }: AdminUserLibrariesDialogProps) { const [loading, setLoading] = useState(false) const [saving, setSaving] = useState(false) const [libraries, setLibraries] = useState([]) const [mode, setMode] = useState<'all' | 'custom'>('all') const [selectedIDs, setSelectedIDs] = useState>(new Set()) useEffect(() => { if (!isOpen || !user) return setLoading(true) libraryAPI .list({ includeHidden: true }) .then((libs) => { setLibraries(libs ?? []) }) .catch(() => { toast.error('加载媒体库列表失败') }) .finally(() => { setLoading(false) }) const initialIDs = user.allowed_library_ids ?? [] if (initialIDs.length > 0) { setMode('custom') setSelectedIDs(new Set(initialIDs)) } else { setMode('all') setSelectedIDs(new Set()) } }, [isOpen, user]) if (!isOpen || !user) return null const toggleLibrary = (libID: string) => { setSelectedIDs((prev) => { const next = new Set(prev) if (next.has(libID)) { next.delete(libID) } else { next.add(libID) } return next }) } const handleSelectAll = () => { setSelectedIDs(new Set(libraries.map((l) => l.id))) } const handleSelectNone = () => { setSelectedIDs(new Set()) } const handleSave = async () => { setSaving(true) try { let payloadIDs: string[] | null = null if (mode === 'custom') { const arr = Array.from(selectedIDs) // 如果勾选了全部,或者勾选为空 if (arr.length === 0) { toast.error('请至少选择一个媒体库,或切换为“允许访问全部媒体库”') setSaving(false) return } if (arr.length < libraries.length) { payloadIDs = arr } } const updated = await adminAPI.updateUserLibraries(user.id, payloadIDs) toast.success( payloadIDs && payloadIDs.length > 0 ? `已成功配置用户【${user.username}】仅可访问 ${payloadIDs.length} 个媒体库` : `已恢复用户【${user.username}】全库访问权限`, ) onSaved(updated) onClose() } catch (err: unknown) { const msg = (err as { response?: { data?: { error?: string } } })?.response?.data?.error ?? '保存配置失败' toast.error(msg) } finally { setSaving(false) } } return (
e.stopPropagation()} > {/* Header */}

配置媒体库访问权限

用户:{user.username} {user.role === 'admin' && ( 管理员拥有所有库访问权限 )}

{/* Content */}
{/* 模式选择 */}
{/* 媒体库列表 */} {mode === 'custom' && (
已选择{' '} {selectedIDs.size} /{' '} {libraries.length} 个媒体库
·
{loading ? (
正在加载媒体库…
) : libraries.length === 0 ? (
暂无可用媒体库
) : (
{libraries.map((lib) => { const isChecked = selectedIDs.has(lib.id) const isTv = lib.type === 'tv' || lib.type === 'anime' || lib.type === 'variety' return (
toggleLibrary(lib.id)} className={`group flex cursor-pointer items-center justify-between rounded-xl border p-3 transition-all ${ isChecked ? 'border-brand-300 bg-brand-50/40 shadow-xs' : 'border-sand-200 bg-white hover:border-sand-300 hover:bg-sand-50/40' }`} >
{isTv ? : }

{lib.name}

{lib.type} · {libraryDisplayPath(lib.path)}

{isChecked && }
) })}
)}
)}
{/* Footer */}
) }