/** * 任务-页面详情组件 */ 'use client'; import { useState, useEffect, useRef } from 'react'; import { parseDownloadError } from '@/lib/download-errors'; import { detailInkButtonClass, detailMetaLabelClass, detailMetaValueClass, detailOutlineButtonClass, detailPanelClass, detailSectionTitleClass, detailThumbActiveClass, detailThumbIdleClass, } from '@/components/detail/detail-styles'; interface Asset { id: string; assetType: string; fileUrl: string; fileName: string; fileSize: number; sortOrder: number; } interface TaskPageDetailProps { material: { id: string; taskNo?: string; productModel: string; categoryName: string; sceneName: string; taskStatus?: string; taskFetchedAt?: string; assets: Asset[]; }; canDownloadSource: boolean; onDownload: (type: string, assetId?: string) => Promise; onBack?: () => void; showToast?: (message: string, options?: { variant?: 'success' | 'error' }) => void; } export default function TaskPageDetail({ material, canDownloadSource, onDownload, onBack, showToast, }: TaskPageDetailProps) { const [currentImageIndex, setCurrentImageIndex] = useState(0); const [downloading, setDownloading] = useState(false); const [downloadType, setDownloadType] = useState(''); // 轮播相关状态 const [autoPlayEnabled, setAutoPlayEnabled] = useState(true); // 按类型分组资产 // ⚠️ 注意:preview是S3存储的压缩预览图(小文件),用于网页展示 // zip是本地存储的原图压缩包(大文件),用于下载 const mainImages = material.assets.filter((a) => a.assetType === 'preview').sort((a, b) => a.sortOrder - b.sortOrder); const zipFile = material.assets.find((a) => a.assetType === 'zip'); // 轮播逻辑 const autoPlayTimerRef = useRef(null); useEffect(() => { // 清理之前的定时器 if (autoPlayTimerRef.current) { clearInterval(autoPlayTimerRef.current); } // 只在有多张原图时启用轮播 if (autoPlayEnabled && mainImages.length > 1) { autoPlayTimerRef.current = setInterval(() => { setCurrentImageIndex((prev) => (prev + 1) % mainImages.length); }, 5000); // 5秒轮播 } return () => { if (autoPlayTimerRef.current) { clearInterval(autoPlayTimerRef.current); } }; }, [currentImageIndex, autoPlayEnabled, mainImages.length]); // 格式化文件大小 const formatBytes = (bytes: number) => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; }; return (
{/* 警告:已被外部系统获取 */} {material.taskStatus === 'fetched' && material.taskFetchedAt && (

此素材已被外部系统获取

获取时间:{new Date(material.taskFetchedAt).toLocaleString('zh-CN')}

编辑或删除可能影响外部系统使用

)}
{/* 左侧:预览图展示 */}
{/* 预览图预览区 */} {mainImages.length > 0 && (

预览图 ({currentImageIndex + 1}/{mainImages.length})

{mainImages.length > 1 && ( )}
{`预览图
)} {/* 预览图小卡片展示区 */} {mainImages.length > 0 && (

所有预览图 ({mainImages.length})

{mainImages.map((img, index) => ( ))}
)}
{/* 右侧:基本信息 + 下载按钮 */}
{/* 基本信息卡片 */}

素材详情

任务号

{material.taskNo}

SPU型号

{material.productModel}

店铺

{material.categoryName}

{material.sceneName && (

场景

{material.sceneName}

)}
{/* ZIP 文件信息和下载按钮 - 使用容器实现sticky,保持相对位置 */}
{/* ZIP 源文件 */} {zipFile && (

源文件

{zipFile.fileName}

{formatBytes(zipFile.fileSize)}

{canDownloadSource ? ( ) : ( 无权限 )}
)} {/* 返回上一页按钮 */} {onBack && ( )}
); }