import React, { useState, useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import type { Asset, AssetCategory, AssetCategoryDef, AssetFileType } from '@/types'; import { assetsAPI } from '@/api'; import { formatBjTime } from '@/utils/datetime'; import './AssetsPage.css'; const fileTypeLabels: Record = { word: { label: 'Word', bg: '#E8F1FF', color: '#2563EB' }, excel: { label: 'Excel', bg: '#E8F8EE', color: '#219B5E' }, ppt: { label: 'PPT', bg: '#FEF2E2', color: '#D97706' }, pdf: { label: 'PDF', bg: '#FDEBEB', color: '#DC2626' }, txt: { label: 'TXT', bg: '#F1F3F7', color: '#64748B' }, md: { label: 'MD', bg: '#E8EEF8', color: '#3B82F6' }, doc: { label: 'DOC', bg: '#E6F4EA', color: '#0D9488' }, other: { label: '其他', bg: '#F1F3F7', color: '#64748B' }, }; // SVG Icons const CloseIcon = () => ( ); const DownloadIcon = () => ( ); const TrashIcon = () => ( ); const getFileTypeInfo = (ft?: string) => { return fileTypeLabels[ft || 'other'] || fileTypeLabels.other; }; function formatSize(bytes?: number): string { if (!bytes) return '--'; if (bytes < 1024) return `${bytes}B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`; return `${(bytes / (1024 * 1024)).toFixed(1)}MB`; } function formatDate(dateStr: string): string { return formatBjTime(dateStr); } // 将文件扩展名或API返回的file_type映射到前端fileType标签 function mapFileTypeToLabel(ft: string): string { const mapping: Record = { pdf: 'pdf', docx: 'word', doc: 'word', xlsx: 'excel', xls: 'excel', pptx: 'ppt', ppt: 'ppt', csv: 'txt', md: 'md', txt: 'txt', word: 'word', excel: 'excel', }; return mapping[ft] || 'other'; } // Preview Modal Component interface PreviewModalProps { asset: Asset; onClose: () => void; onDelete: (id: string) => void; } const PreviewModal: React.FC = ({ asset, onClose, onDelete }) => { const [editing, setEditing] = useState(false); const [editContent, setEditContent] = useState(''); const [showOnlinePreview, setShowOnlinePreview] = useState(false); const navigate = useNavigate(); const isTextFile = asset.category === 'file' && ['txt', 'other', 'md', 'doc'].includes(asset.fileType || ''); const isImage = asset.category === 'image'; const isVideo = asset.category === 'video'; const isAudio = asset.category === 'audio'; const isTextEditable = asset.category === 'file' && (asset.fileType === 'txt' || asset.fileType === 'other' || asset.fileType === 'md' || asset.fileType === 'doc'); const isOfficeDoc = asset.category === 'file' && ['word', 'excel', 'ppt'].includes(asset.fileType || ''); const isPdf = asset.category === 'file' && asset.fileType === 'pdf'; const handleDownload = () => { // Simulate download - in production would use asset.url const a = document.createElement('a'); a.href = '#' + asset.id; a.download = asset.name; a.click(); }; const handleStartEdit = () => { setEditContent(asset.description || ''); setEditing(true); }; const handleSaveEdit = () => { // In production, would call assetsAPI.updateAsset setEditing(false); }; // 在线预览内容渲染 const renderOnlinePreview = () => { if (!showOnlinePreview) return null; const ft = asset.fileType || 'other'; // PDF 使用浏览器原生预览 if (ft === 'pdf' && asset.url) { return (
在线预览:{asset.name}