taskModel = new TaskModel(); $this->assigneeModel = new TaskAssigneeModel(); $this->columnModel = new TaskColumnModel(); } /** * Получить модель задач для использования в DataTable */ public function getModel(): TaskModel { return $this->taskModel; } /** * Создать новую задачу */ public function createTask(array $data, int $userId, array $assigneeIds = []): int { $data['created_by'] = $userId; $taskId = $this->taskModel->insert($data); if ($taskId) { // Добавляем исполнителей foreach ($assigneeIds as $userId) { $this->assigneeModel->addAssignee($taskId, (int)$userId); } // Генерируем событие Events::trigger('tasks.created', $taskId, $data, $userId); } return $taskId; } /** * Обновить задачу */ public function updateTask(int $taskId, array $data, int $userId): bool { $oldTask = $this->taskModel->find($taskId); if (!$oldTask) { return false; } $result = $this->taskModel->update($taskId, $data); if ($result) { Events::trigger('tasks.updated', $taskId, $data, $userId); } return $result; } /** * Изменить колонку задачи (drag-and-drop) */ public function changeColumn(int $taskId, int $newColumnId, int $userId): bool { $task = $this->taskModel->find($taskId); if (!$task) { return false; } $newColumn = $this->columnModel->find($newColumnId); if (!$newColumn) { return false; } $oldColumnId = $task['column_id']; $data = ['column_id' => $newColumnId]; // Если задача завершена (новая колонка не "Завершено"), очищаем completed_at if ($newColumn['name'] !== 'Завершено') { $data['completed_at'] = null; } $result = $this->taskModel->update($taskId, $data); if ($result) { Events::trigger('tasks.column_changed', $taskId, $oldColumnId, $newColumnId, $userId); } return $result; } /** * Завершить задачу */ public function completeTask(int $taskId, int $userId): bool { $task = $this->taskModel->find($taskId); if (!$task) { return false; } $result = $this->taskModel->update($taskId, [ 'completed_at' => date('Y-m-d H:i:s'), ]); if ($result) { Events::trigger('tasks.completed', $taskId, $userId); } return $result; } /** * Возобновить задачу */ public function reopenTask(int $taskId, int $userId): bool { $task = $this->taskModel->find($taskId); if (!$task) { return false; } $result = $this->taskModel->update($taskId, [ 'completed_at' => null, ]); if ($result) { Events::trigger('tasks.reopened', $taskId, $userId); } return $result; } /** * Удалить задачу */ public function deleteTask(int $taskId, int $userId): bool { $task = $this->taskModel->find($taskId); if (!$task) { return false; } $result = $this->taskModel->delete($taskId); if ($result) { Events::trigger('tasks.deleted', $taskId, $userId); } return $result; } /** * Получить задачу по ID */ public function getTask(int $taskId, int $organizationId): ?array { $task = $this->taskModel->getTask($taskId, $organizationId); if (!$task) { return null; } $task['assignees'] = $this->assigneeModel->getAssigneesByTask($taskId); return $task; } /** * Получить задачи для Канбана */ public function getTasksForKanban(int $boardId): array { return $this->taskModel->getTasksGroupedByColumn($boardId); } /** * Получить задачи для календаря */ public function getTasksForCalendar(int $organizationId, string $month): array { return $this->taskModel->getTasksForCalendar($organizationId, $month); } /** * Получить статистику */ public function getStats(int $organizationId): array { return $this->taskModel->getTaskStats($organizationId); } /** * Обновить исполнителей задачи */ public function updateAssignees(int $taskId, array $userIds): bool { // Удаляем старых исполнителей $this->assigneeModel->where('task_id', $taskId)->delete(); // Добавляем новых foreach ($userIds as $userId) { $this->assigneeModel->addAssignee($taskId, (int)$userId); } return true; } /** * Создать задачу из события (например, из сделки CRM) */ public function createFromEvent(string $eventType, array $eventData, int $organizationId): ?int { $taskData = [ 'organization_id' => $organizationId, 'board_id' => $this->getDefaultBoardId($organizationId), 'column_id' => $this->getFirstColumnId($organizationId), 'title' => $eventData['title'] ?? 'Задача', 'description' => $eventData['description'] ?? '', 'priority' => $eventData['priority'] ?? 'medium', 'due_date' => $eventData['due_date'] ?? null, ]; $assignees = $eventData['assignees'] ?? []; return $this->createTask($taskData, $eventData['created_by'] ?? 1, $assignees); } /** * Получить ID дефолтной доски */ protected function getDefaultBoardId(int $organizationId): int { $boardModel = new TaskBoardModel(); $board = $boardModel->getDefaultBoard($organizationId); if (!$board) { // Создаём дефолтную доску return $boardModel->createDefaultBoard($organizationId); } return $board['id']; } /** * Получить ID первой колонки */ protected function getFirstColumnId(int $organizationId): int { $boardId = $this->getDefaultBoardId($organizationId); $columns = $this->columnModel->getColumnsByBoard($boardId); return $columns[0]['id'] ?? 1; } }