主要修复: - 修复批量上传闭包陷阱,防止文件丢失 - 添加 fileName 参数传递原始文件名,保留正确扩展名 - 添加取消检查回调,改进批量上传取消功能 其他改进: - 优化搜索功能和管理后台 - 添加 FRP 故障诊断文档 - 更新环境验证和网络检测
132 lines
3.7 KiB
TypeScript
132 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import React from 'react'
|
|
import MaterialCard, { Material } from './MaterialCard'
|
|
|
|
// 用户会话类型
|
|
interface UserSession {
|
|
id: string
|
|
role: string
|
|
}
|
|
|
|
interface MaterialGridProps {
|
|
materials: Material[]
|
|
displayedCount: number
|
|
session: { user: UserSession } | null
|
|
loading: boolean
|
|
isTransitionLoading: boolean
|
|
// 音频播放状态
|
|
playingAudioId: string | null
|
|
audioElement: HTMLAudioElement | null
|
|
audioProgress: number
|
|
audioCurrentTime: number
|
|
audioDuration: number
|
|
audioRef: React.RefObject<HTMLAudioElement | null>
|
|
// 下载状态
|
|
downloadingId: string | null
|
|
downloadProgress: number
|
|
// 主题色
|
|
themeColor: string
|
|
// 筛选状态(用于空状态提示)
|
|
hasFilters: boolean
|
|
// 搜索关键词(用于高亮)
|
|
searchKeyword?: string
|
|
// 事件处理
|
|
onAudioPlay: (materialId: string, audioUrl: string) => void
|
|
onDownload: (id: string) => void
|
|
onLike: (id: string) => void
|
|
onFavorite: (id: string) => void
|
|
onShare: (id: string) => void
|
|
onEdit: (material: Material) => void
|
|
onDelete: (id: string) => void
|
|
onMaterialClick: (material: Material) => void
|
|
onRetryTranscode: (materialId: string) => void
|
|
showToast: (message: string, options?: { variant?: 'success' | 'error' }) => void
|
|
}
|
|
|
|
export default function MaterialGrid({
|
|
materials,
|
|
displayedCount,
|
|
session,
|
|
loading,
|
|
isTransitionLoading,
|
|
playingAudioId,
|
|
audioElement,
|
|
audioProgress,
|
|
audioCurrentTime,
|
|
audioDuration,
|
|
audioRef,
|
|
downloadingId,
|
|
downloadProgress,
|
|
themeColor,
|
|
hasFilters,
|
|
searchKeyword,
|
|
onAudioPlay,
|
|
onDownload,
|
|
onLike,
|
|
onFavorite,
|
|
onShare,
|
|
onEdit,
|
|
onDelete,
|
|
onMaterialClick,
|
|
onRetryTranscode,
|
|
showToast,
|
|
}: MaterialGridProps) {
|
|
return (
|
|
<div className="relative">
|
|
{/* 过渡加载遮罩 */}
|
|
{isTransitionLoading && (
|
|
<div className="absolute inset-0 z-20 flex items-center justify-center bg-white/60 dark:bg-gray-900/60 backdrop-blur-[1px]">
|
|
<div className="w-6 h-6 border-2 border-gray-300 border-t-gray-900 dark:border-gray-700 dark:border-t-white rounded-full animate-spin" />
|
|
</div>
|
|
)}
|
|
|
|
{/* 加载状态 */}
|
|
{loading ? (
|
|
<div className="text-center py-16">
|
|
<p className="text-gray-500 dark:text-gray-400 text-lg">加载中...</p>
|
|
</div>
|
|
) : materials.length === 0 ? (
|
|
// 空状态
|
|
<div className="text-center py-16">
|
|
<p className="text-gray-500 dark:text-gray-400 text-lg">
|
|
{hasFilters ? '没有找到匹配的素材' : '还没有素材,快来上传第一个吧!'}
|
|
</p>
|
|
</div>
|
|
) : (
|
|
// 素材网格
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
|
{materials.slice(0, displayedCount).map((material) => (
|
|
<MaterialCard
|
|
key={material.id}
|
|
material={material}
|
|
session={session}
|
|
playingAudioId={playingAudioId}
|
|
audioElement={audioElement}
|
|
audioProgress={audioProgress}
|
|
audioCurrentTime={audioCurrentTime}
|
|
audioDuration={audioDuration}
|
|
audioRef={audioRef}
|
|
downloadingId={downloadingId}
|
|
downloadProgress={downloadProgress}
|
|
themeColor={themeColor}
|
|
onAudioPlay={onAudioPlay}
|
|
onDownload={onDownload}
|
|
onLike={onLike}
|
|
onFavorite={onFavorite}
|
|
onShare={onShare}
|
|
onEdit={onEdit}
|
|
onDelete={onDelete}
|
|
onClick={onMaterialClick}
|
|
onRetryTranscode={onRetryTranscode}
|
|
showToast={showToast}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export type { Material }
|