diff --git a/backend/api/project.php b/backend/api/project.php index 54d8227..1fea511 100644 --- a/backend/api/project.php +++ b/backend/api/project.php @@ -133,6 +133,63 @@ if ($method === 'POST') { RestApi::response($result, $result['success'] ? 200 : 403); } + // ==================== CRUD ОТДЕЛОВ ==================== + + // Добавление отдела + if ($action === 'add_department') { + $project_id = $data['project_id'] ?? null; + $name = trim($data['name'] ?? ''); + $color = $data['color'] ?? '#6366f1'; + if (!$project_id || !$name) { + RestApi::response(['success' => false, 'errors' => ['data' => 'Укажите project_id и name']], 400); + } + $result = Project::addDepartment($project_id, $name, $color, $user_id); + RestApi::response($result, $result['success'] ? 200 : 403); + } + + // Обновление отдела + if ($action === 'update_department') { + $id = $data['id'] ?? null; + $name = isset($data['name']) ? trim($data['name']) : null; + $color = $data['color'] ?? null; + if (!$id) { + RestApi::response(['success' => false, 'errors' => ['id' => 'Укажите ID отдела']], 400); + } + $result = Project::updateDepartment($id, $name, $color, $user_id); + RestApi::response($result, $result['success'] ? 200 : 403); + } + + // Получение количества задач в отделе (для подтверждения удаления) + if ($action === 'get_department_tasks_count') { + $id = $data['id'] ?? null; + if (!$id) { + RestApi::response(['success' => false, 'errors' => ['id' => 'Укажите ID отдела']], 400); + } + $count = Project::getDepartmentTasksCount($id); + RestApi::response(['success' => true, 'count' => $count]); + } + + // Удаление отдела + if ($action === 'delete_department') { + $id = $data['id'] ?? null; + if (!$id) { + RestApi::response(['success' => false, 'errors' => ['id' => 'Укажите ID отдела']], 400); + } + $result = Project::deleteDepartment($id, $user_id); + RestApi::response($result, $result['success'] ? 200 : 403); + } + + // Обновление порядка отделов + if ($action === 'update_departments_order') { + $project_id = $data['project_id'] ?? null; + $ids = $data['ids'] ?? []; + if (!$project_id || empty($ids)) { + RestApi::response(['success' => false, 'errors' => ['data' => 'Укажите project_id и ids']], 400); + } + $result = Project::updateDepartmentsOrder($project_id, $ids, $user_id); + RestApi::response($result, $result['success'] ? 200 : 403); + } + // Метод не указан if (!$action) { RestApi::response(['success' => false, 'error' => 'Укажите метод'], 400); diff --git a/backend/app/class/enity/class_project.php b/backend/app/class/enity/class_project.php index 3477567..fd166db 100644 --- a/backend/app/class/enity/class_project.php +++ b/backend/app/class/enity/class_project.php @@ -76,9 +76,11 @@ class Project extends BaseEntity { return Database::select('departments', [ 'id', 'name_departments', - 'color' + 'color', + 'order_id' ], [ - 'id_project' => $project_id + 'id_project' => $project_id, + 'ORDER' => ['order_id' => 'ASC'] ]); } @@ -366,6 +368,100 @@ class Project extends BaseEntity { public static function setReadyColumn($project_id, $column_id, $user_id) { return ['success' => false, 'errors' => ['column' => 'Изменение финальной колонки запрещено. Финальная колонка всегда последняя.']]; } + + // ==================== CRUD ОТДЕЛОВ ==================== + + // Добавление отдела + public static function addDepartment($project_id, $name, $color, $user_id) { + if (!ProjectAccess::can($project_id, $user_id, 'manage_departments')) { + return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; + } + + // Получаем максимальный order_id для проекта + $maxOrder = (int)(Database::max('departments', 'order_id', ['id_project' => $project_id]) ?? 0); + $newOrderId = $maxOrder + 1; + + Database::insert('departments', [ + 'name_departments' => $name, + 'color' => $color ?: '#6366f1', + 'id_project' => $project_id, + 'order_id' => $newOrderId + ]); + + $departmentId = Database::id(); + return [ + 'success' => true, + 'id' => $departmentId, + 'department' => [ + 'id' => $departmentId, + 'name_departments' => $name, + 'color' => $color ?: '#6366f1', + 'order_id' => $newOrderId + ] + ]; + } + + // Обновление отдела + public static function updateDepartment($id, $name, $color, $user_id) { + // Получаем отдел для проверки проекта + $department = Database::get('departments', ['id_project'], ['id' => $id]); + if (!$department) { + return ['success' => false, 'errors' => ['department' => 'Отдел не найден']]; + } + + if (!ProjectAccess::can($department['id_project'], $user_id, 'manage_departments')) { + return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; + } + + $updateData = []; + if ($name !== null) $updateData['name_departments'] = $name; + if ($color !== null) $updateData['color'] = $color; + + if (!empty($updateData)) { + Database::update('departments', $updateData, ['id' => $id]); + } + + return ['success' => true]; + } + + // Получение количества задач в отделе + public static function getDepartmentTasksCount($department_id) { + return Database::count('cards_task', ['id_department' => $department_id]); + } + + // Удаление отдела (обнуляет id_department у задач) + public static function deleteDepartment($id, $user_id) { + // Получаем отдел для проверки проекта + $department = Database::get('departments', ['id_project'], ['id' => $id]); + if (!$department) { + return ['success' => false, 'errors' => ['department' => 'Отдел не найден']]; + } + + if (!ProjectAccess::can($department['id_project'], $user_id, 'manage_departments')) { + return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; + } + + // Обнуляем id_department у задач (не удаляем сами задачи) + Database::update('cards_task', ['id_department' => null], ['id_department' => $id]); + + // Удаляем отдел + Database::delete('departments', ['id' => $id]); + + return ['success' => true]; + } + + // Обновление порядка отделов + public static function updateDepartmentsOrder($project_id, $ids, $user_id) { + if (!ProjectAccess::can($project_id, $user_id, 'manage_departments')) { + return ['success' => false, 'errors' => ['access' => 'Нет прав на управление отделами']]; + } + + foreach ($ids as $order => $id) { + Database::update('departments', ['order_id' => $order + 1], ['id' => $id, 'id_project' => $project_id]); + } + + return ['success' => true]; + } } ?> diff --git a/front_vue/src/api.js b/front_vue/src/api.js index f844ba8..4bb8fd6 100644 --- a/front_vue/src/api.js +++ b/front_vue/src/api.js @@ -142,6 +142,42 @@ export const projectsApi = { credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'set_ready_column', project_id, column_id }) + }), + // ==================== ОТДЕЛЫ ==================== + // Добавление отдела + addDepartment: (project_id, name, color) => request('/api/project', { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'add_department', project_id, name, color }) + }), + // Обновление отдела + updateDepartment: (id, name, color) => request('/api/project', { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'update_department', id, name, color }) + }), + // Получение количества задач в отделе + getDepartmentTasksCount: (id) => request('/api/project', { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'get_department_tasks_count', id }) + }), + // Удаление отдела + deleteDepartment: (id) => request('/api/project', { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'delete_department', id }) + }), + // Обновление порядка отделов + updateDepartmentsOrder: (project_id, ids) => request('/api/project', { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ action: 'update_departments_order', project_id, ids }) }) } diff --git a/front_vue/src/components/ProjectPanel.vue b/front_vue/src/components/ProjectPanel.vue index 0b617b8..76f4b0a 100644 --- a/front_vue/src/components/ProjectPanel.vue +++ b/front_vue/src/components/ProjectPanel.vue @@ -109,6 +109,92 @@ Добавить колонку + + +
+ + +
+
+ +
+ +
+ + +
+ + +
+ + + + + + + + + + +
+
+ +

+ Отделов пока нет. Добавьте первый отдел. +

+ + +