gongxiangp2/components/home/MaterialGrid.tsx
chenpei 752b7bf999 fix: 修复批量上传和视频扩展名问题
主要修复:

- 修复批量上传闭包陷阱,防止文件丢失

- 添加 fileName 参数传递原始文件名,保留正确扩展名

- 添加取消检查回调,改进批量上传取消功能

其他改进:

- 优化搜索功能和管理后台

- 添加 FRP 故障诊断文档

- 更新环境验证和网络检测
2026-02-03 11:12:50 +08:00

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 }