переделал ui

This commit is contained in:
2026-03-04 12:09:40 +05:00
parent 3b68dfc042
commit 850a23e962
7 changed files with 1296 additions and 1685 deletions

View File

@@ -8,16 +8,18 @@ function showSection(sectionName) {
document.getElementById(sectionName + '-section').classList.add('active');
if (sectionName === 'tasks') {
loadTasks();
loadTasks(); // из tasks.js
} else if (sectionName === 'logs') {
loadActivityLogs();
} else if (sectionName === 'kanban') {
loadKanbanTasks();
} else if (sectionName === 'mytasks') {
console.log('загружаю loadMyTasks');
window.currentTaskView = 'my_assigned';
loadTasks();
} else if (sectionName === 'runtasks') {
console.log('загружаю loadRunTasks');
window.currentTaskView = 'assigned_to_me';
loadTasks();
}
@@ -27,6 +29,7 @@ function showSection(sectionName) {
loadNotificationSettings();
}
}
// Вызываем добавление стилей при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
addDocumentFieldsStyles();
@@ -99,60 +102,16 @@ function renderDocumentFields(taskId, fields) {
`;
}
// Обновленная функция loadTasks для загрузки полей документа
async function loadTasks() {
try {
const response = await fetch('/api/tasks');
tasks = await response.json();
// Загружаем поля документа для каждой задачи типа "document"
for (const task of tasks) {
if (task.task_type === 'document') {
try {
const docResponse = await fetch(`/api/tasks/${task.id}/document-fields`);
if (docResponse.ok) {
const docData = await docResponse.json();
task.document_fields = docData.data || {};
} else {
task.document_fields = {};
}
} catch (error) {
console.error(`Ошибка загрузки полей документа для задачи ${task.id}:`, error);
task.document_fields = {};
}
}
}
// Определяем активную секцию и рендерим в соответствующий контейнер
const activeSection = document.querySelector('.section.active');
if (activeSection) {
const sectionId = activeSection.id;
if (sectionId === 'mytasks-section') {
renderTasksInContainer('mytasks-list');
} else if (sectionId === 'runtasks-section') {
renderTasksInContainer('runtasks-list');
} else {
renderTasks();
}
} else {
renderTasks();
}
} catch (error) {
console.error('Ошибка загрузки задач:', error);
const container = document.getElementById('tasks-list');
if (container) {
container.innerHTML = '<div class="error">Ошибка загрузки задач</div>';
}
}
}
// ========== УДАЛЕНА функция loadTasks теперь используется общая из tasks.js ==========
// Функция рендеринга задач в общий контейнер (секция "Все задачи")
function renderTasks() {
const container = document.getElementById('tasks-list');
const showDeleted = document.getElementById('show-deleted')?.checked || false;
let filteredTasks = tasks;
let filteredTasks = window.tasks;
if (!showDeleted) {
filteredTasks = tasks.filter(task => task.status === 'active');
filteredTasks = window.tasks.filter(task => task.status === 'active');
}
if (filteredTasks.length === 0) {
@@ -277,6 +236,130 @@ ${task.assignments && task.assignments.length > 0 ?
}).join('');
}
// Функция для рендеринга задач в указанный контейнер (для секций mytasks и runtasks)
function renderTasksInContainer(containerId, tasksArray) {
const container = document.getElementById(containerId);
if (!container) return;
if (!tasksArray || tasksArray.length === 0) {
container.innerHTML = '<div class="loading">Задачи не найдены</div>';
return;
}
container.innerHTML = tasksArray.map(task => {
const isExpanded = expandedTasks.has(task.id);
const overallStatus = getTaskOverallStatus(task);
const statusClass = getStatusClass(overallStatus);
const isDeleted = task.status === 'deleted';
const isClosed = task.closed_at !== null;
const userRole = getUserRoleInTask(task);
const canEdit = canUserEditTask(task);
const isCopy = task.original_task_id !== null;
const timeLeftInfo = getTimeLeftInfo(task);
const documentFields = task.document_fields || {};
// Тот же шаблон, что и в renderTasks
return `
<div class="task-card ${isDeleted ? 'deleted' : ''} ${isClosed ? 'closed' : ''}" data-task-id="${task.id}">
<div class="task-header">
<div class="task-title" onclick="toggleTask(${task.id})" style="cursor: pointer; display: flex; justify-content: space-between; align-items: center;">
<div style="flex: 1;">
<span class="task-number">Задача №${task.id}</span>
<strong>${task.title}</strong>
${isDeleted ? '<span class="deleted-badge">Удалена</span>' : ''}
${isClosed ? '<span class="closed-badge">Закрыта</span>' : ''}
${isCopy ? '<span class="copy-badge">Копия</span>' : ''}
${timeLeftInfo ? `<span class="deadline-badge ${timeLeftInfo.class}">${timeLeftInfo.text}</span>` : ''}
<span class="role-badge ${getRoleBadgeClass(userRole)}">${userRole}</span>
${task.assignments && task.assignments.length > 0 ? `<span class="task-number">${task.assignments.map(a => a.user_login || a.user_name).join(', ')}</span>` : ''}
</div>
<span class="task-status ${statusClass}">
Выполнить до: ${formatDateTime(task.due_date || task.created_at)}
</span>
<div class="expand-icon" style="margin-left: 10px; transition: transform 0.3s; transform: rotate(${isExpanded ? '180deg' : '0deg'});">
</div>
</div>
</div>
<div class="task-content ${isExpanded ? 'expanded' : ''}">
${isExpanded ? `
<div class="task-actions">
${!isDeleted && !isClosed ? `
<button class="copy-btn" onclick="openTaskChat(${task.id})" title="Открыть чат">💬</button>
<button class="add-file-btn" onclick="openAddFileModal(${task.id})" title="Добавить файл">📎</button>
${currentUser && currentUser.login === 'minicrm' ? `<button class="edit-btn" onclick="openEditModal(${task.id})" title="Редактировать">✏️</button>` : ''}
${currentUser && currentUser.login === 'kalugin.o' ? `<button class="manage-assignees-btn" onclick="openManageAssigneesModal(${task.id})" title="Управление исполнителями">👥</button>` : ''}
${currentUser && currentUser.role === 'tasks' && canEdit || currentUser.role === 'admin' ? `<button class="manage-assignees-btn" onclick="assignAdd_openModal(${task.id})" title="Управление исполнителями">🧑‍💼➕Добавить</button>` : ''}
${currentUser && currentUser.role === 'tasks' && canEdit || currentUser.role === 'admin' ? `<button class="manage-assignees-btn" onclick="assignRemove_openModal(${task.id})" title="Управление исполнителями">🧑‍💼❌Удалить</button>` : ''}
<button class="copy-btn" onclick="openCopyModal(${task.id})" title="Создать копию">📋</button>
${currentUser && currentUser.login === 'minicrm' ? `<button class="rework-btn" onclick="openReworkModal(${task.id})" title="Вернуть на доработку">🔄</button>` : ''}
<!-- Кнопка переделки документа для исполнителей -->
${task.task_type === 'document' && userRole === 'Исполнитель' ? `<button class="rework-btn" onclick="openReworkModal(${task.id})" title="Переделать документ">🔄Переделать</button>` : ''}
${!isDeleted && !isClosed && task.task_type !== 'regular' && task.assignments && task.assignments.some(a => parseInt(a.user_id) === currentUser.id) ? `
<button class="rework-btn" onclick="openReworkModal(${task.id})" title="Вернуть на доработку">🔄Доработка</button>
<button class="change-deadline-btn" onclick="openChangeDeadlineModal(${task.id})" title="Изменить срок">📅</button>
` : ''}
${currentUser && currentUser.login === 'minicrm' ? `<button class="close-btn" onclick="closeTask(${task.id})" title="Закрыть задачу">🔒</button>` : ''}
${canEdit ? `<button class="delete-btn" onclick="deleteTask(${task.id})" title="Удалить">🗑️</button>` : ''}
` : ''}
${isClosed && canEdit ? `
<button class="reopen-btn" onclick="reopenTask(${task.id})" title="Открыть задачу">🔓</button>
` : ''}
${isDeleted && currentUser.role === 'admin' ? `
<button class="restore-btn" onclick="restoreTask(${task.id})" title="Восстановить">↶</button>
` : ''}
</div>
` : ''}
${isCopy && task.original_task_title ? `
<div class="task-original">
<small>Оригинал: "${task.original_task_title}" (создал: ${task.original_creator_name})</small>
</div>
` : ''}
<div class="task-description">${task.description || 'Нет описания'}</div>
${task.rework_comment ? `
<div class="rework-comment">
<strong>Комментарий к доработке:</strong> ${task.rework_comment}
</div>
` : ''}
${task.task_type === 'document' ? renderDocumentFields(task.id, documentFields) : ''}
<div class="file-list" id="files-${task.id}">
<strong>Файлы:</strong>
${task.files && task.files.length > 0 ? renderGroupedFilesWithDelete(task) : '<span class="no-files">нет файлов</span>'}
</div>
<div class="task-assignments">
<strong>Исполнители:</strong>
${task.assignments && task.assignments.length > 0 ?
renderAssignmentList(task.assignments, task.id, canEdit) :
'<div>Не назначены</div>'
}
</div>
</div>
<div class="task-meta">
<small>
Создана: ${formatDateTime(task.start_date || task.created_at)}
| Выполнить до: ${formatDateTime(task.due_date || task.created_at)}
| Автор: ${task.creator_name}
| Тип: ${task.task_type ? `<span class="task-type-badge ${task.task_type}">${getTaskTypeDisplayName(task.task_type)}</span>` : ''}
</small>
${task.deleted_at ? `<br><small>Удалена: ${formatDateTime(task.deleted_at)}</small>` : ''}
${task.closed_at ? `<br><small>Закрыта: ${formatDateTime(task.closed_at)}</small>` : ''}
</div>
</div>
`;
}).join('');
}
// Функция для рендеринга списка исполнителей с фильтрацией
function renderAssignmentList(assignments, taskId, canEdit) {
if (!assignments || assignments.length === 0) {
@@ -502,9 +585,9 @@ function toggleTask(taskId) {
if (activeSection) {
const sectionId = activeSection.id;
if (sectionId === 'mytasks-section') {
renderTasksInContainer('mytasks-list');
renderTasksInContainer('mytasks-list', window.tasks);
} else if (sectionId === 'runtasks-section') {
renderTasksInContainer('runtasks-list');
renderTasksInContainer('runtasks-list', window.tasks);
} else if (sectionId === 'tasks-section') {
renderTasks();
}
@@ -1942,6 +2025,7 @@ function renderGroupedFiles(task) {
</div>
`).join('');
}
// ++++++++++++++++++++++++++++++ кнопки изменения срока задачи для исполнителей ++++++++++++++++++++++++++++++
// Функция для открытия модального окна изменения срока задачи
function openChangeDeadlineModal(taskId) {
@@ -2013,7 +2097,6 @@ function openChangeDeadlineModal(taskId) {
}, 10);
}
// Функция закрытия модального окна
function closeChangeDeadlineModal() {
const modal = document.getElementById('change-deadline-modal');
if (modal) {
@@ -2024,7 +2107,6 @@ function closeChangeDeadlineModal() {
}
}
// Функция отправки изменения срока
async function submitDeadlineChange(taskId) {
const newDate = document.getElementById('new-deadline-date').value;
const comment = document.getElementById('deadline-change-comment').value.trim();
@@ -2110,4 +2192,4 @@ async function submitDeadlineChange(taskId) {
}
}
}
// ++++++++++++++++++++++++++++++ кнопки изменения срока задачи для исполнителей ++++++++++++++++++++++++++++++
// ++++++++++++++++++++++++++++++ конец кнопок изменения срока ++++++++++++++++++++++++++++++