1
0
Files
TaskBoard/backend/app/class/enity/class_task.php
2026-01-19 15:10:37 +07:00

420 lines
16 KiB
PHP
Raw 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.

<?php
class Task extends BaseEntity {
protected $db_name = 'cards_task';
// Свойства задачи
public $id;
public $id_project;
public $id_department;
public $id_label;
public $order;
public $column_id;
public $date;
public $date_closed;
public $id_account;
public $create_id_account; // ID создателя задачи
public $title;
public $descript;
public $descript_full;
public $archive;
// Валидация данных
protected function validate() {
static::$error_message = [];
if (!$this->id) {
$this->addError('id', 'ID задачи не указан');
}
if (!$this->title) {
$this->addError('title', 'Название не может быть пустым');
}
return $this->getErrors();
}
// Валидация данных (для create)
protected function validateCreate() {
static::$error_message = [];
if (!$this->title) {
$this->addError('title', 'Название не может быть пустым');
}
if (!$this->column_id) {
$this->addError('column_id', 'Колонка не указана');
}
if (!$this->id_department) {
$this->addError('id_department', 'Департамент не указан');
}
if (!$this->id_project) {
$this->addError('id_project', 'Проект не указан');
}
return $this->getErrors();
}
// Создание задачи (с файлами)
public function create($files = []) {
// Валидация
if ($errors = $this->validateCreate()) {
return $errors;
}
// Формируем дату создания (одна переменная для БД и ответа)
$date_create = date('Y-m-d H:i:s');
// Вставляем в базу
Database::insert($this->db_name, [
'id_project' => $this->id_project,
'id_department' => $this->id_department,
'id_label' => $this->id_label,
'order' => $this->order ?? 0,
'column_id' => $this->column_id,
'date' => $this->date ?: null,
'id_account' => $this->id_account,
'create_id_account' => $this->create_id_account,
'title' => $this->title,
'descript' => $this->descript ?: null,
'descript_full' => $this->descript_full ?: null,
'archive' => 0,
'date_create' => $date_create,
'file_img' => '[]'
]);
// Получаем ID созданной задачи
$this->id = Database::id();
// Загружаем файлы если есть
$uploaded_files = [];
if (!empty($files)) {
foreach ($files as $file) {
$result = FileUpload::upload('task', $this->id, $file['data'], $file['name']);
if ($result['success']) {
$uploaded_files[] = $result['file'];
}
}
}
return [
'success' => true,
'id' => $this->id,
'date' => $this->date ?: null,
'date_create' => $date_create,
'date_closed' => null,
'files' => $uploaded_files
];
}
// Обновление задачи
public function update() {
// Валидация
if ($errors = $this->validate()) {
return $errors;
}
// Проверка что задача существует и получаем текущие данные
$task = Database::get($this->db_name, ['id', 'column_id', 'order', 'id_project', 'archive'], ['id' => $this->id]);
if (!$task) {
$this->addError('task', 'Задача не найдена');
return $this->getErrors();
}
// Архивные задачи нельзя редактировать
if ((int)$task['archive'] === 1) {
$this->addError('task', 'Архивные задачи нельзя редактировать');
return $this->getErrors();
}
// Получаем текущую колонку
$old_column_id = (int)$task['column_id'];
// Если column_id не передан — оставляем текущий
$new_column_id = $this->column_id !== null ? (int)$this->column_id : $old_column_id;
// Получаем id_ready (колонка "Готово") из проекта
$done_column_id = Project::getReadyColumnId($task['id_project']);
// Формируем данные для обновления
$update_data = [
'id_department' => $this->id_department,
'id_label' => $this->id_label,
'order' => $this->order ?? $task['order'],
'column_id' => $new_column_id,
'date' => $this->date ?: null,
'id_account' => $this->id_account,
'title' => $this->title,
'descript' => $this->descript ?: null,
'descript_full' => $this->descript_full ?: null
];
// Обновляем date_closed при смене колонки
if ($done_column_id && $new_column_id === $done_column_id && $old_column_id !== $done_column_id) {
$update_data['date_closed'] = date('Y-m-d H:i:s');
} elseif ($done_column_id && $old_column_id === $done_column_id && $new_column_id !== $done_column_id) {
$update_data['date_closed'] = null;
}
// Обновляем в БД
Database::update($this->db_name, $update_data, [
'id' => $this->id
]);
return ['success' => true];
}
// Удаление задачи
public static function delete($id) {
// Проверка что задача существует
self::check_task($id);
// Удаляем папку с файлами задачи
FileUpload::deleteFolder('task', $id);
// Удаляем все комментарии задачи и их файлы
$comments = Database::select('comments', ['id'], ['id_task' => $id]);
if ($comments) {
foreach ($comments as $comment) {
FileUpload::deleteFolder('comment', $comment['id']);
}
Database::delete('comments', ['id_task' => $id]);
}
// Удаляем задачу из базы
Database::delete('cards_task', ['id' => $id]);
return ['success' => true];
}
// === МЕТОДЫ ДЛЯ РАБОТЫ С ФАЙЛАМИ ===
// Загрузка файла к задаче
public static function uploadFile($task_id, $file_base64, $file_name) {
// Проверка что задача существует
$task = self::check_task($task_id);
// Архивные задачи нельзя редактировать
if ((int)$task['archive'] === 1) {
RestApi::response([
'success' => false,
'errors' => ['task' => 'Нельзя загружать файлы в архивную задачу']
], 400);
}
return FileUpload::upload('task', $task_id, $file_base64, $file_name);
}
// Удаление файлов задачи
public static function deleteFile($task_id, $file_names) {
// Проверка что задача существует
$task = self::check_task($task_id);
// Архивные задачи нельзя редактировать
if ((int)$task['archive'] === 1) {
RestApi::response([
'success' => false,
'errors' => ['task' => 'Нельзя удалять файлы из архивной задачи']
], 400);
}
return FileUpload::delete('task', $task_id, $file_names);
}
// Изменение порядка и колонки задачи (с пересчётом order)
public static function updateOrder($id, $column_id, $to_index) {
// Проверка что задача существует
$task = self::check_task($id);
$old_column_id = (int)$task['column_id'];
$new_column_id = (int)$column_id;
$archive = (int)$task['archive'];
// Архивные задачи нельзя перемещать
if ($archive === 1) {
RestApi::response([
'success' => false,
'errors' => ['task' => 'Архивные задачи нельзя перемещать']
], 400);
}
// Получаем id_ready (колонка "Готово") из проекта
$done_column_id = Project::getReadyColumnId($task['id_project']);
// Получаем все карточки целевой колонки с тем же статусом архивации (кроме перемещаемой)
$cards = Database::select('cards_task', ['id', 'order'], [
'column_id' => $column_id,
'archive' => $archive,
'id[!]' => $id,
'ORDER' => ['order' => 'ASC']
]) ?? [];
// Вставляем перемещаемую карточку в нужную позицию
array_splice($cards, $to_index, 0, [['id' => $id]]);
// Пересчитываем order для всех карточек
foreach ($cards as $index => $card) {
$update_data = [
'order' => $index,
'column_id' => $column_id
];
// Только для перемещаемой карточки обновляем date_closed
if ($card['id'] == $id && $done_column_id) {
// Перемещаем В колонку "Готово" — устанавливаем дату закрытия
if ($new_column_id === $done_column_id && $old_column_id !== $done_column_id) {
$update_data['date_closed'] = date('Y-m-d H:i:s');
}
// Перемещаем ИЗ колонки "Готово" — обнуляем дату
elseif ($old_column_id === $done_column_id && $new_column_id !== $done_column_id) {
$update_data['date_closed'] = null;
}
}
Database::update('cards_task', $update_data, [
'id' => $card['id']
]);
}
return ['success' => true];
}
// Получение всех задач проекта
// $id_project: ID проекта (обязательный)
// $archive: 0 = неархивные, 1 = архивные, null = все
public function getAll($id_project, $archive = 0) {
$where = [
'id_project' => $id_project
];
if ($archive !== null) {
$where['archive'] = $archive ? 1 : 0;
}
$tasks = Database::select($this->db_name, [
'id',
'id_project',
'id_department',
'id_label',
'id_account',
'create_id_account',
'order',
'column_id',
'date',
'date_create',
'date_closed',
'file_img',
'title',
'descript',
'descript_full',
'archive'
], $where);
// Получаем количество комментариев для всех задач одним запросом
$task_ids = array_column($tasks, 'id');
$comments_counts = [];
if (!empty($task_ids)) {
$counts = Database::query(
"SELECT id_task, COUNT(*) as cnt FROM comments WHERE id_task IN (" . implode(',', $task_ids) . ") GROUP BY id_task"
)->fetchAll(\PDO::FETCH_ASSOC);
foreach ($counts as $row) {
$comments_counts[$row['id_task']] = (int)$row['cnt'];
}
}
// Декодируем JSON и получаем avatar_url из accounts
return array_map(function($task) use ($comments_counts) {
$task['file_img'] = $task['file_img'] ? json_decode($task['file_img'], true) : [];
// Получаем avatar_url из accounts по id_account
if ($task['id_account']) {
$account = Database::get('accounts', ['avatar_url'], ['id' => $task['id_account']]);
$task['avatar_img'] = $account['avatar_url'] ?? null;
} else {
$task['avatar_img'] = null;
}
// Количество комментариев
$task['comments_count'] = $comments_counts[$task['id']] ?? 0;
return $task;
}, $tasks);
}
// Получение колонок проекта
public function getColumns($id_project) {
return Database::select('columns', [
'id',
'name_columns',
'color',
'id_order'
], [
'id_project' => $id_project,
'ORDER' => ['id_order' => 'ASC']
]);
}
// Получение отделов проекта
public function getDepartments($id_project) {
return Database::select('departments', [
'id',
'name_departments',
'color'
], [
'id_project' => $id_project
]);
}
// Получение всех меток
public function getLabels() {
return Database::select('labels', [
'id',
'name_labels',
'icon',
'color'
]);
}
// Проверка и получение задачи (при ошибке — сразу ответ и exit)
public static function check_task($task_id) {
$task = Database::get('cards_task', '*', ['id' => $task_id]);
if (!$task_id || !$task) {
RestApi::response(['success' => false, 'errors' => ['task' => 'Задача не найдена']], 400);
}
return $task;
}
// Установка статуса архивации задачи (только для задач в колонке "Готово")
public static function setArchive($id, $archive = 1) {
// Проверка что задача существует
$task = self::check_task($id);
// Получаем id_ready (колонка "Готово") из проекта
$done_column_id = Project::getReadyColumnId($task['id_project']);
// Архивировать можно только задачи в колонке "Готово"
if ($archive && $done_column_id && (int)$task['column_id'] !== $done_column_id) {
RestApi::response([
'success' => false,
'errors' => ['column' => 'Архивировать можно только задачи из колонки "Готово"']
], 400);
}
// Данные для обновления
$update_data = [
'archive' => $archive ? 1 : 0
];
// При разархивировании — возвращаем в колонку "Готово"
if (!$archive && $done_column_id) {
$update_data['column_id'] = $done_column_id;
}
// Обновляем в БД
Database::update('cards_task', $update_data, [
'id' => $id
]);
return ['success' => true, 'archive' => $archive ? 1 : 0];
}
}
?>