diff --git a/TASKS_MODULE_ROADMAP.md b/TASKS_MODULE_ROADMAP.md index 058f441..fe18ad7 100644 --- a/TASKS_MODULE_ROADMAP.md +++ b/TASKS_MODULE_ROADMAP.md @@ -32,24 +32,7 @@ Commit: cee6c63, 5bf25d9, 85a920b, f6aebd8 --- -## Этап 3: Чек-листы - Готово ✅ - -### 3.1 Структура -``` -task_checklists (id, task_id, title, is_completed, order_index, created_at) -``` - -### 3.2 Модель + API -- TaskChecklistModel -- addChecklistItem(), toggleChecklistItem(), deleteChecklistItem() - -### 3.3 View -- Отображение чек-листа в task/show.twig -- Чекбоксы для toggle - -Commit: 4a67f00 - ---- +## Этап 3: Вложения (Attachments) ## Этап 4: Вложения @@ -113,11 +96,10 @@ Events::on('booking.created') → создать задачу "Подготов |------|--------|--------|--------| | 1 | RBAC + валидация | 4ч | ✅ Готово | | 2 | Подзадачи | 8ч | ✅ Готово | -| 3 | Чек-листы | 6ч | ✅ Готово | -| 4 | Вложения | 8ч | В процессе | -| 5 | Комментарии + @mentions | 12ч | - | -| 6 | Зависимости | 6ч | - | -| 7 | CRM → Tasks | 8ч | - | -| 8 | Booking → Tasks | 4ч | - | +| 3 | Вложения | 8ч | В процессе | +| 4 | Комментарии + @mentions | 12ч | - | +| 5 | Зависимости | 6ч | - | +| 6 | CRM → Tasks | 8ч | - | +| 7 | Booking → Tasks | 4ч | - | -**Готово:** 18ч | **Осталось:** ~38ч +**Готово:** 12ч | **Осталось:** ~38ч diff --git a/app/Database/Migrations/2026-02-08-110006_CreateTaskChecklistsTable.php b/app/Database/Migrations/2026-02-08-110006_CreateTaskChecklistsTable.php deleted file mode 100644 index ecaafc8..0000000 --- a/app/Database/Migrations/2026-02-08-110006_CreateTaskChecklistsTable.php +++ /dev/null @@ -1,59 +0,0 @@ -forge->addField([ - 'id' => [ - 'type' => 'INT', - 'constraint' => 11, - 'unsigned' => true, - 'auto_increment' => true, - ], - 'task_id' => [ - 'type' => 'INT', - 'constraint' => 11, - 'unsigned' => true, - 'null' => false, - ], - 'title' => [ - 'type' => 'VARCHAR', - 'constraint' => 255, - 'null' => false, - ], - 'is_completed' => [ - 'type' => 'BOOLEAN', - 'default' => false, - ], - 'order_index' => [ - 'type' => 'INT', - 'constraint' => 11, - 'default' => 0, - ], - 'created_at' => [ - 'type' => 'DATETIME', - 'null' => true, - ], - 'updated_at' => [ - 'type' => 'DATETIME', - 'null' => true, - ], - ]); - - $this->forge->addKey('id', true); - $this->forge->addKey('task_id'); - $this->forge->addForeignKey('task_id', 'tasks', 'id', '', 'CASCADE'); - - $this->forge->createTable('task_checklists'); - } - - public function down() - { - $this->forge->dropTable('task_checklists'); - } -} \ No newline at end of file diff --git a/app/Modules/Tasks/Config/Routes.php b/app/Modules/Tasks/Config/Routes.php index 6a66c16..55d31c4 100644 --- a/app/Modules/Tasks/Config/Routes.php +++ b/app/Modules/Tasks/Config/Routes.php @@ -32,11 +32,6 @@ $routes->group('tasks', ['filter' => ['org', 'subscription:tasks'], 'namespace' $routes->post('(:num)/subtasks', 'TasksController::addSubtask/$1'); $routes->post('(:num)/subtasks/(:num)/toggle', 'TasksController::toggleSubtask/$1/$2'); $routes->post('(:num)/subtasks/(:num)/delete', 'TasksController::deleteSubtask/$1/$2'); - - // Checklists API - $routes->post('(:num)/checklists', 'TasksController::addChecklistItem/$1'); - $routes->post('(:num)/checklists/(:num)/toggle', 'TasksController::toggleChecklistItem/$1/$2'); - $routes->post('(:num)/checklists/(:num)/delete', 'TasksController::deleteChecklistItem/$1/$2'); }); // API Routes для Tasks diff --git a/app/Modules/Tasks/Controllers/TasksController.php b/app/Modules/Tasks/Controllers/TasksController.php index af68289..39af6bc 100644 --- a/app/Modules/Tasks/Controllers/TasksController.php +++ b/app/Modules/Tasks/Controllers/TasksController.php @@ -614,108 +614,4 @@ class TasksController extends BaseController 'success' => $result, ]); } - - // ========== Чек-листы (Checklists) ========== - - /** - * API: добавить элемент чек-листа - */ - public function addChecklistItem(int $taskId) - { - if (!$this->access->canEdit('tasks')) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Нет прав для изменения задач' - ]); - } - - $organizationId = $this->requireActiveOrg(); - $userId = $this->getCurrentUserId(); - - $title = trim($this->request->getPost('title')); - if (empty($title)) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Название элемента чек-листа обязательно' - ]); - } - - // Проверяем что задача принадлежит организации - $task = $this->taskService->getTask($taskId, $organizationId); - if (!$task) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Задача не найдена' - ]); - } - - $checklistId = $this->taskService->addChecklistItem($taskId, $title, $userId); - - return $this->response->setJSON([ - 'success' => (bool) $checklistId, - 'checklist_id' => $checklistId, - ]); - } - - /** - * API: переключить статус элемента чек-листа - */ - public function toggleChecklistItem(int $taskId, int $checklistId) - { - if (!$this->access->canEdit('tasks')) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Нет прав для изменения задач' - ]); - } - - $organizationId = $this->requireActiveOrg(); - $userId = $this->getCurrentUserId(); - - // Проверяем что задача принадлежит организации - $task = $this->taskService->getTask($taskId, $organizationId); - if (!$task) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Задача не найдена' - ]); - } - - $result = $this->taskService->toggleChecklistItem($taskId, $checklistId, $userId); - - return $this->response->setJSON([ - 'success' => $result, - ]); - } - - /** - * API: удалить элемент чек-листа - */ - public function deleteChecklistItem(int $taskId, int $checklistId) - { - if (!$this->access->canEdit('tasks')) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Нет прав для изменения задач' - ]); - } - - $organizationId = $this->requireActiveOrg(); - $userId = $this->getCurrentUserId(); - - // Проверяем что задача принадлежит организации - $task = $this->taskService->getTask($taskId, $organizationId); - if (!$task) { - return $this->response->setJSON([ - 'success' => false, - 'error' => 'Задача не найдена' - ]); - } - - $result = $this->taskService->deleteChecklistItem($taskId, $checklistId, $userId); - - return $this->response->setJSON([ - 'success' => $result, - ]); - } } diff --git a/app/Modules/Tasks/Models/TaskChecklistModel.php b/app/Modules/Tasks/Models/TaskChecklistModel.php deleted file mode 100644 index c1b3f4c..0000000 --- a/app/Modules/Tasks/Models/TaskChecklistModel.php +++ /dev/null @@ -1,74 +0,0 @@ -where('task_id', $taskId) - ->orderBy('order_index', 'ASC') - ->findAll(); - } - - /** - * Получить следующий порядковый номер для элемента чек-листа - */ - public function getNextOrder(int $taskId): int - { - $max = $this->selectMax('order_index') - ->where('task_id', $taskId) - ->first(); - - return ($max['order_index'] ?? 0) + 1; - } - - /** - * Переключить статус элемента чек-листа - */ - public function toggle(int $checklistId): bool - { - $checklist = $this->find($checklistId); - if (!$checklist) { - return false; - } - - return $this->update($checklistId, [ - 'is_completed' => !$checklist['is_completed'], - ]); - } - - /** - * Получить количество незавершённых элементов чек-листа - */ - public function getIncompleteCount(int $taskId): int - { - return $this->where('task_id', $taskId) - ->where('is_completed', false) - ->countAllResults(); - } -} \ No newline at end of file diff --git a/app/Modules/Tasks/Services/TaskService.php b/app/Modules/Tasks/Services/TaskService.php index b5f5c2b..6699429 100644 --- a/app/Modules/Tasks/Services/TaskService.php +++ b/app/Modules/Tasks/Services/TaskService.php @@ -6,7 +6,6 @@ use App\Modules\Tasks\Models\TaskModel; use App\Modules\Tasks\Models\TaskAssigneeModel; use App\Modules\Tasks\Models\TaskColumnModel; use App\Modules\Tasks\Models\TaskSubtaskModel; -use App\Modules\Tasks\Models\TaskChecklistModel; use CodeIgniter\Events\Events; class TaskService @@ -15,7 +14,6 @@ class TaskService protected TaskAssigneeModel $assigneeModel; protected TaskColumnModel $columnModel; protected TaskSubtaskModel $subtaskModel; - protected TaskChecklistModel $checklistModel; public function __construct() { @@ -23,7 +21,6 @@ class TaskService $this->assigneeModel = new TaskAssigneeModel(); $this->columnModel = new TaskColumnModel(); $this->subtaskModel = new TaskSubtaskModel(); - $this->checklistModel = new TaskChecklistModel(); } /** @@ -183,9 +180,6 @@ class TaskService $task['subtasks'] = $this->subtaskModel->getByTask($taskId); $task['subtasks_count'] = count($task['subtasks']); $task['subtasks_completed'] = count(array_filter($task['subtasks'], fn($s) => $s['is_completed'])); - $task['checklists'] = $this->checklistModel->getByTask($taskId); - $task['checklists_count'] = count($task['checklists']); - $task['checklists_completed'] = count(array_filter($task['checklists'], fn($c) => $c['is_completed'])); return $task; } @@ -355,83 +349,4 @@ class TaskService return $result; } - - // ========== Чек-листы (Checklists) ========== - - /** - * Добавить элемент чек-листа - */ - public function addChecklistItem(int $taskId, string $title, int $userId): int - { - $orderIndex = $this->checklistModel->getNextOrder($taskId); - - $checklistId = $this->checklistModel->insert([ - 'task_id' => $taskId, - 'title' => trim($title), - 'order_index' => $orderIndex, - ]); - - if ($checklistId) { - Events::trigger('task.checklist_item_created', $taskId, $checklistId, $userId); - } - - return $checklistId; - } - - /** - * Переключить статус элемента чек-листа - */ - public function toggleChecklistItem(int $taskId, int $checklistId, int $userId): bool - { - $checklist = $this->checklistModel->find($checklistId); - if (!$checklist || $checklist['task_id'] != $taskId) { - return false; - } - - $result = $this->checklistModel->toggle($checklistId); - - if ($result) { - Events::trigger('task.checklist_item_toggled', $taskId, $checklistId, !$checklist['is_completed'], $userId); - } - - return $result; - } - - /** - * Удалить элемент чек-листа - */ - public function deleteChecklistItem(int $taskId, int $checklistId, int $userId): bool - { - $checklist = $this->checklistModel->find($checklistId); - if (!$checklist || $checklist['task_id'] != $taskId) { - return false; - } - - $result = $this->checklistModel->delete($checklistId); - - if ($result) { - Events::trigger('task.checklist_item_deleted', $taskId, $checklistId, $userId); - } - - return $result; - } - - /** - * Обновить элемент чек-листа - */ - public function updateChecklistItem(int $taskId, int $checklistId, array $data, int $userId): bool - { - $checklist = $this->checklistModel->find($checklistId); - if (!$checklist || $checklist['task_id'] != $taskId) { - return false; - } - - $result = $this->checklistModel->update($checklistId, $data); - - if ($result) { - Events::trigger('task.checklist_item_updated', $taskId, $checklistId, $data, $userId); - } - - return $result; - } } diff --git a/app/Modules/Tasks/Views/tasks/show.twig b/app/Modules/Tasks/Views/tasks/show.twig index ca9fa08..d2a16aa 100644 --- a/app/Modules/Tasks/Views/tasks/show.twig +++ b/app/Modules/Tasks/Views/tasks/show.twig @@ -140,51 +140,6 @@ - {# Чек-лист #} -
Чек-лист пуст
- {% endif %} - - -