// files.js - Работа с файлами let currentTaskFiles = []; let currentEditTaskFiles = []; function initializeFileUploads() { // Создание задачи document.getElementById('files').addEventListener('change', function(e) { currentTaskFiles = Array.from(e.target.files); updateFileList(); }); // Редактирование задачи document.getElementById('edit-files').addEventListener('change', function(e) { const newFiles = Array.from(e.target.files); currentEditTaskFiles.push(...newFiles); updateEditFileList(); }); } function updateFileList() { const fileInput = document.getElementById('files'); const fileList = document.getElementById('file-list'); updateFileListForInput(fileInput, fileList); } function updateEditFileList() { const fileInput = document.getElementById('edit-files'); const fileList = document.getElementById('edit-file-list'); // Используем улучшенный рендеринг файлов const files = fileInput.files; const existingFiles = currentEditTaskFiles.filter(file => !(file instanceof File)); if (files.length === 0 && existingFiles.length === 0) { fileList.innerHTML = ''; return; } let html = ''; html += `

Общий размер: ${(totalSize / 1024 / 1024).toFixed(2)} MB / 300 MB

`; fileList.innerHTML = html; } function updateFileListForInput(fileInput, fileList) { const files = fileInput.files; if (files.length === 0) { fileList.innerHTML = ''; return; } let html = ''; html += `

Общий размер: ${(totalSize / 1024 / 1024).toFixed(2)} MB / 300 MB

`; fileList.innerHTML = html; } // Удаление файлов из списка function removeFile(index) { currentTaskFiles.splice(index, 1); updateFileList(); // Обновляем input files const dataTransfer = new DataTransfer(); currentTaskFiles.forEach(file => dataTransfer.items.add(file)); document.getElementById('files').files = dataTransfer.files; } function removeEditFile(index) { currentEditTaskFiles.splice(index, 1); updateEditFileList(); // Обновляем input files const dataTransfer = new DataTransfer(); const newFiles = currentEditTaskFiles.filter(file => file instanceof File); newFiles.forEach(file => dataTransfer.items.add(file)); document.getElementById('edit-files').files = dataTransfer.files; } async function loadTaskFiles(taskId) { try { const response = await fetch(`/api/tasks/${taskId}/files`); const files = await response.json(); const container = document.getElementById(`files-${taskId}`); if (container) { if (files.length === 0) { container.innerHTML = 'Файлы: скрыто'; } else { container.innerHTML = ` Файлы:
${files.map(file => renderFileIcon(file)).join('')}
`; } } } catch (error) { console.error('Ошибка загрузки файлов:', error); } } function renderFileIcon(file) { // Исправляем кодировку имени файла const fixEncoding = (str) => { if (!str) return ''; try { // Пробуем разные способы декодирования if (str.includes('Ð') || str.includes('Ñ')) { // UTF-8 неправильно декодированный как Latin-1 return decodeURIComponent(escape(str)); } return str; } catch (e) { return str; } }; const fileName = fixEncoding(file.original_name); const fileSize = (file.file_size / 1024 / 1024).toFixed(2); const uploadedBy = file.user_name; let iconColor = ''; let iconText = ''; let textClass = ''; // Определяем расширение файла const extension = fileName.includes('.') ? fileName.split('.').pop().toLowerCase() : ''; // Определяем тип файла на основе расширения if (extension) { switch (extension) { case 'pdf': iconColor = '#e74c3c'; iconText = 'PDF'; textClass = 'short'; break; case 'doc': iconColor = '#3498db'; iconText = 'DOC'; textClass = 'short'; break; case 'docx': iconColor = '#3498db'; iconText = 'DOCX'; textClass = 'medium'; break; case 'xls': iconColor = '#2ecc71'; iconText = 'XLS'; textClass = 'short'; break; case 'xlsx': iconColor = '#2ecc71'; iconText = 'XLSX'; textClass = 'medium'; break; case 'csv': iconColor = '#2ecc71'; iconText = 'CSV'; textClass = 'short'; break; case 'ppt': iconColor = '#e67e22'; iconText = 'PPT'; textClass = 'short'; break; case 'pptx': iconColor = '#e67e22'; iconText = 'PPTX'; textClass = 'medium'; break; case 'zip': iconColor = '#f39c12'; iconText = 'ZIP'; textClass = 'short'; break; case 'rar': iconColor = '#f39c12'; iconText = 'RAR'; textClass = 'short'; break; case '7z': iconColor = '#f39c12'; iconText = '7Z'; textClass = 'short'; break; case 'tar': iconColor = '#f39c12'; iconText = 'TAR'; textClass = 'short'; break; case 'gz': iconColor = '#f39c12'; iconText = 'GZ'; textClass = 'short'; break; case 'txt': iconColor = '#95a5a6'; iconText = 'TXT'; textClass = 'short'; break; case 'log': iconColor = '#95a5a6'; iconText = 'LOG'; textClass = 'short'; break; case 'md': iconColor = '#95a5a6'; iconText = 'MD'; textClass = 'short'; break; case 'jpg': iconColor = '#9b59b6'; iconText = 'JPG'; textClass = 'short'; break; case 'jpeg': iconColor = '#9b59b6'; iconText = 'JPEG'; textClass = 'medium'; break; case 'png': iconColor = '#9b59b6'; iconText = 'PNG'; textClass = 'short'; break; case 'gif': iconColor = '#9b59b6'; iconText = 'GIF'; textClass = 'short'; break; case 'bmp': iconColor = '#9b59b6'; iconText = 'BMP'; textClass = 'short'; break; case 'svg': iconColor = '#9b59b6'; iconText = 'SVG'; textClass = 'short'; break; case 'webp': iconColor = '#9b59b6'; iconText = 'WEBP'; textClass = 'medium'; break; case 'mp3': iconColor = '#1abc9c'; iconText = 'MP3'; textClass = 'short'; break; case 'wav': iconColor = '#1abc9c'; iconText = 'WAV'; textClass = 'short'; break; case 'ogg': iconColor = '#1abc9c'; iconText = 'OGG'; textClass = 'short'; break; case 'flac': iconColor = '#1abc9c'; iconText = 'FLAC'; textClass = 'medium'; break; case 'mp4': iconColor = '#d35400'; iconText = 'MP4'; textClass = 'short'; break; case 'avi': iconColor = '#d35400'; iconText = 'AVI'; textClass = 'short'; break; case 'mkv': iconColor = '#d35400'; iconText = 'MKV'; textClass = 'short'; break; case 'mov': iconColor = '#d35400'; iconText = 'MOV'; textClass = 'short'; break; case 'wmv': iconColor = '#d35400'; iconText = 'WMV'; textClass = 'short'; break; case 'exe': iconColor = '#c0392b'; iconText = 'EXE'; textClass = 'short'; break; case 'msi': iconColor = '#c0392b'; iconText = 'MSI'; textClass = 'short'; break; case 'js': iconColor = '#2980b9'; iconText = 'JS'; textClass = 'short'; break; case 'html': iconColor = '#2980b9'; iconText = 'HTML'; textClass = 'medium'; break; case 'css': iconColor = '#2980b9'; iconText = 'CSS'; textClass = 'short'; break; case 'php': iconColor = '#2980b9'; iconText = 'PHP'; textClass = 'short'; break; case 'py': iconColor = '#2980b9'; iconText = 'PY'; textClass = 'short'; break; case 'java': iconColor = '#2980b9'; iconText = 'JAVA'; textClass = 'medium'; break; case 'json': iconColor = '#8e44ad'; iconText = 'JSON'; textClass = 'medium'; break; case 'xml': iconColor = '#8e44ad'; iconText = 'XML'; textClass = 'short'; break; case 'yml': iconColor = '#8e44ad'; iconText = 'YML'; textClass = 'short'; break; case 'yaml': iconColor = '#8e44ad'; iconText = 'YAML'; textClass = 'medium'; break; case 'sql': iconColor = '#27ae60'; iconText = 'SQL'; textClass = 'short'; break; case 'db': iconColor = '#27ae60'; iconText = 'DB'; textClass = 'short'; break; case 'sqlite': iconColor = '#27ae60'; iconText = 'SQLITE'; textClass = 'long'; break; default: // Для других расширений используем расширение или первые 4 символа iconColor = '#7f8c8d'; iconText = extension.length > 4 ? extension.substring(0, 4).toUpperCase() : extension.toUpperCase(); // Определяем класс по длине текста if (iconText.length <= 2) { textClass = 'short'; } else if (iconText.length <= 4) { textClass = 'medium'; } else { textClass = 'long'; } } } else { // Если нет расширения iconColor = '#7f8c8d'; iconText = 'ФАЙЛ'; textClass = 'short'; } // Исправляем кодировку для отображения const safeFileName = fileName; const displayFileName = truncateFileName(safeFileName); return `
${iconText}
${displayFileName}
`; } function truncateFileName(fileName, maxLength = 20) { if (fileName.length <= maxLength) return fileName; const extension = fileName.split('.').pop(); const name = fileName.substring(0, fileName.lastIndexOf('.')); const truncatedName = name.substring(0, maxLength - extension.length - 3) + '...'; return truncatedName + '.' + extension; } // Вспомогательная функция для форматирования размера файла function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }