doska-zadach-otdela/script.js

264 lines
9.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const STATUSES = ['Новая', 'В работе', 'На согласовании', 'Готово'];
const DEMO_TASKS = [
{ id: 1, task: 'Подготовить отчёт по итогам квартала', person: 'Айжан Сәрсен', date: '10.08.2026', priority: 'Высокий', status: 'В работе' },
{ id: 2, task: 'Согласовать бюджет на следующий месяц', person: 'Ерлан Нурбек', date: '12.08.2026', priority: 'Критичный', status: 'Новая' },
{ id: 3, task: 'Провести обучение сотрудников', person: 'Динара Қуат', date: '14.08.2026', priority: 'Средний', status: 'В работе' },
{ id: 4, task: 'Обновить документацию проекта', person: 'Тимур Аскаров', date: '08.08.2026', priority: 'Низкий', status: 'На согласовании' },
{ id: 5, task: 'Настроить автоматическую рассылку', person: 'Айжан Сәрсен', date: '05.08.2026', priority: 'Средний', status: 'Новая' },
{ id: 6, task: 'Подготовить презентацию для руководства', person: 'Ерлан Нурбек', date: '18.08.2026', priority: 'Высокий', status: 'Готово' },
{ id: 7, task: 'Проверить договоры с контрагентами', person: 'Динара Қуат', date: '22.08.2026', priority: 'Средний', status: 'Готово' }
];
let tasks = [];
let log = [];
let filterStatus = null;
function init() {
const saved = localStorage.getItem('tasks');
if (saved) {
tasks = JSON.parse(saved);
} else {
tasks = [...DEMO_TASKS];
saveTasks();
}
const savedLog = localStorage.getItem('taskLog');
if (savedLog) {
log = JSON.parse(savedLog);
} else {
log = [{ when: new Date().toLocaleString('ru-RU'), what: 'Инициализация демо-данных', who: 'Система' }];
saveLog();
}
render();
}
function saveTasks() {
localStorage.setItem('tasks', JSON.stringify(tasks));
}
function saveLog() {
localStorage.setItem('taskLog', JSON.stringify(log));
}
function addLogEntry(what) {
log.unshift({
when: new Date().toLocaleString('ru-RU'),
what: what,
who: 'Пользователь'
});
if (log.length > 50) log.pop();
saveLog();
}
function parseDate(dateStr) {
const parts = dateStr.split('.');
return new Date(parts[2], parts[1] - 1, parts[0]);
}
function isOverdue(task) {
if (task.status === 'Готово') return false;
const taskDate = parseDate(task.date);
const today = new Date();
today.setHours(0, 0, 0, 0);
return taskDate < today;
}
function getStatusClass(status) {
switch (status) {
case 'Новая': return 'status-new';
case 'В работе': return 'status-progress';
case 'На согласовании': return 'status-review';
case 'Готово': return 'status-done';
default: return '';
}
}
function getPriorityClass(priority) {
switch (priority) {
case 'Низкий': return 'priority-low';
case 'Средний': return 'priority-medium';
case 'Высокий': return 'priority-high';
case 'Критичный': return 'priority-critical';
default: return '';
}
}
function updateStats() {
const stats = { total: tasks.length, 'Новая': 0, 'В работе': 0, 'На согласовании': 0, 'Готово': 0 };
tasks.forEach(t => stats[t.status]++);
document.getElementById('stat-total').textContent = stats.total;
document.getElementById('stat-new').textContent = stats['Новая'];
document.getElementById('stat-progress').textContent = stats['В работе'];
document.getElementById('stat-review').textContent = stats['На согласовании'];
document.getElementById('stat-done').textContent = stats['Готово'];
}
function renderChips() {
const container = document.getElementById('chips');
container.innerHTML = STATUSES.map(s =>
`<button class="chip ${filterStatus === s ? 'active' : ''}" data-status="${s}">${s}</button>`
).join('') + `<button class="chip ${filterStatus === null ? 'active' : ''}" data-status="">Все</button>`;
container.querySelectorAll('.chip').forEach(chip => {
chip.addEventListener('click', () => {
filterStatus = chip.dataset.status || null;
renderTasks();
});
});
}
function renderTasks() {
const search = document.getElementById('search').value.toLowerCase();
let filtered = tasks.filter(t => {
const matchesSearch =
t.task.toLowerCase().includes(search) ||
t.person.toLowerCase().includes(search) ||
t.date.toLowerCase().includes(search) ||
t.priority.toLowerCase().includes(search) ||
t.status.toLowerCase().includes(search);
const matchesStatus = filterStatus === null || t.status === filterStatus;
return matchesSearch && matchesStatus;
});
const tbody = document.getElementById('tasks-body');
if (filtered.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="empty-state">Нет задач для отображения</td></tr>';
return;
}
tbody.innerHTML = filtered.map(t => {
const overdue = isOverdue(t);
return `
<tr class="${overdue ? 'overdue' : ''}">
<td>${t.task}</td>
<td>${t.person}</td>
<td>${t.date}</td>
<td><span class="${getPriorityClass(t.priority)}">${t.priority}</span></td>
<td><span class="status-badge ${getStatusClass(t.status)}">${t.status}</span></td>
<td class="actions">
<button class="btn btn-secondary btn-sm" onclick="editTask(${t.id})">✏️ Редактировать</button>
<button class="btn btn-danger btn-sm" onclick="deleteTask(${t.id})">🗑️ Удалить</button>
</td>
</tr>
`;
}).join('');
}
function renderLog() {
const container = document.getElementById('log');
container.innerHTML = log.map(entry =>
`<div class="log-entry"><strong>${entry.what}</strong> — ${entry.who} <span>(${entry.when})</span></div>`
).join('');
}
function render() {
updateStats();
renderChips();
renderTasks();
renderLog();
}
function openModal(editId = null) {
const modal = document.getElementById('modal');
const form = document.getElementById('task-form');
form.reset();
document.getElementById('edit-id').value = '';
document.getElementById('modal-title').textContent = 'Новая задача';
if (editId !== null) {
const task = tasks.find(t => t.id === editId);
if (task) {
document.getElementById('edit-id').value = task.id;
document.getElementById('f-task').value = task.task;
document.getElementById('f-person').value = task.person;
document.getElementById('f-date').value = task.date;
document.getElementById('f-priority').value = task.priority;
document.getElementById('f-status').value = task.status;
document.getElementById('modal-title').textContent = 'Редактирование задачи';
}
}
modal.showModal();
}
function closeModal() {
document.getElementById('modal').close();
}
function saveTask(e) {
e.preventDefault();
const editId = document.getElementById('edit-id').value;
const taskData = {
task: document.getElementById('f-task').value,
person: document.getElementById('f-person').value,
date: document.getElementById('f-date').value,
priority: document.getElementById('f-priority').value,
status: document.getElementById('f-status').value
};
if (editId) {
const id = parseInt(editId);
const index = tasks.findIndex(t => t.id === id);
if (index !== -1) {
tasks[index] = { ...tasks[index], ...taskData };
addLogEntry(`Изменена задача: "${taskData.task}"`);
}
} else {
const newId = Math.max(0, ...tasks.map(t => t.id)) + 1;
tasks.push({ id: newId, ...taskData });
addLogEntry(`Добавлена задача: "${taskData.task}"`);
}
saveTasks();
closeModal();
render();
}
window.editTask = function(id) {
openModal(id);
};
window.deleteTask = function(id) {
const task = tasks.find(t => t.id === id);
if (!task) return;
if (confirm(`Удалить задачу "${task.task}"?`)) {
tasks = tasks.filter(t => t.id !== id);
addLogEntry(`Удалена задача: "${task.task}"`);
saveTasks();
render();
}
};
function exportCSV() {
const headers = ['Задача', 'Исполнитель', 'Срок', 'Приоритет', 'Статус'];
const rows = tasks.map(t => [t.task, t.person, t.date, t.priority, t.status]
.map(v => '"' + String(v ?? '').replace(/"/g, '""') + '"')
.join(';')
);
const csv = '\uFEFF' + [headers.join(';'), ...rows].join('\n');
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'zadachi_otdela.csv';
a.click();
URL.revokeObjectURL(url);
addLogEntry('Выгружен список задач в CSV');
saveLog();
}
function resetDemo() {
if (confirm('Сбросить все данные к демо-версии? Все изменения будут потеряны.')) {
tasks = [...DEMO_TASKS];
log = [{ when: new Date().toLocaleString('ru-RU'), what: 'Сброшено к демо-данным', who: 'Пользователь' }];
saveTasks();
saveLog();
render();
}
}
document.getElementById('btn-add').addEventListener('click', () => openModal());
document.getElementById('btn-cancel').addEventListener('click', closeModal);
document.getElementById('task-form').addEventListener('submit', saveTask);
document.getElementById('search').addEventListener('input', renderTasks);
document.getElementById('btn-export').addEventListener('click', exportCSV);
document.getElementById('btn-reset').addEventListener('click', resetDemo);
init();