Tasks Module Stage 2: Subtasks

- Create task_subtasks table migration
- Create TaskSubtaskModel with CRUD operations
- Add subtask API methods: addSubtask, toggleSubtask, deleteSubtask
- Update TaskService to include subtasks in getTask()
- Add Routes for subtasks API
- Update show.twig with subtasks UI and JavaScript
This commit is contained in:
2026-02-08 14:55:45 +00:00
parent d7fec7169f
commit cee6c636ad
6 changed files with 417 additions and 0 deletions
@@ -510,4 +510,108 @@ class TasksController extends BaseController
return $this->response->setJSON(['success' => $result]);
}
// ========== Подзадачи (Subtasks) ==========
/**
* API: добавить подзадачу
*/
public function addSubtask(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' => 'Задача не найдена'
]);
}
$subtaskId = $this->taskService->addSubtask($taskId, $title, $userId);
return $this->response->setJSON([
'success' => (bool) $subtaskId,
'subtask_id' => $subtaskId,
]);
}
/**
* API: переключить статус подзадачи
*/
public function toggleSubtask(int $taskId, int $subtaskId)
{
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->toggleSubtask($taskId, $subtaskId, $userId);
return $this->response->setJSON([
'success' => $result,
]);
}
/**
* API: удалить подзадачу
*/
public function deleteSubtask(int $taskId, int $subtaskId)
{
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->deleteSubtask($taskId, $subtaskId, $userId);
return $this->response->setJSON([
'success' => $result,
]);
}
}