start tasks module
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Tasks\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
|
||||
class TaskAssigneeModel extends Model
|
||||
{
|
||||
protected $table = 'task_assignees';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $allowedFields = [
|
||||
'task_id',
|
||||
'user_id',
|
||||
'role',
|
||||
'assigned_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* Получить всех исполнителей задачи
|
||||
*/
|
||||
public function getAssigneesByTask(int $taskId): array
|
||||
{
|
||||
return $this->select('task_assignees.*, users.name as user_name, users.email as user_email')
|
||||
->join('users', 'task_assignees.user_id = users.id', 'left')
|
||||
->where('task_id', $taskId)
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить задачи пользователя
|
||||
*/
|
||||
public function getTasksByUser(int $userId, int $organizationId): array
|
||||
{
|
||||
return $this->select('tasks.*')
|
||||
->join('tasks', 'task_assignees.task_id = tasks.id')
|
||||
->where('task_assignees.user_id', $userId)
|
||||
->where('tasks.organization_id', $organizationId)
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить исполнителя
|
||||
*/
|
||||
public function addAssignee(int $taskId, int $userId, string $role = 'assignee'): int
|
||||
{
|
||||
return $this->insert([
|
||||
'task_id' => $taskId,
|
||||
'user_id' => $userId,
|
||||
'role' => $role,
|
||||
'assigned_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удалить исполнителя
|
||||
*/
|
||||
public function removeAssignee(int $taskId, int $userId): bool
|
||||
{
|
||||
return $this->where('task_id', $taskId)
|
||||
->where('user_id', $userId)
|
||||
->delete() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, является ли пользователь исполнителем
|
||||
*/
|
||||
public function isAssignee(int $taskId, int $userId): bool
|
||||
{
|
||||
return $this->where('task_id', $taskId)
|
||||
->where('user_id', $userId)
|
||||
->countAllResults() > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Tasks\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\Traits\TenantScopedModel;
|
||||
|
||||
class TaskBoardModel extends Model
|
||||
{
|
||||
use TenantScopedModel;
|
||||
|
||||
protected $table = 'task_boards';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $tenantField = 'organization_id';
|
||||
protected $allowedFields = [
|
||||
'organization_id',
|
||||
'name',
|
||||
'description',
|
||||
'is_default',
|
||||
];
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
/**
|
||||
* Получить все доски организации
|
||||
*/
|
||||
public function getBoardsByOrganization(int $organizationId): array
|
||||
{
|
||||
return $this->where('organization_id', $organizationId)
|
||||
->orderBy('is_default', 'DESC')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить доску по ID
|
||||
*/
|
||||
public function getBoard(int $boardId, int $organizationId): ?array
|
||||
{
|
||||
return $this->where('id', $boardId)
|
||||
->where('organization_id', $organizationId)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить дефолтную доску организации
|
||||
*/
|
||||
public function getDefaultBoard(int $organizationId): ?array
|
||||
{
|
||||
return $this->where('organization_id', $organizationId)
|
||||
->where('is_default', 1)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать дефолтную доску для новой организации
|
||||
*/
|
||||
public function createDefaultBoard(int $organizationId): int
|
||||
{
|
||||
$data = [
|
||||
'organization_id' => $organizationId,
|
||||
'name' => 'Мои задачи',
|
||||
'description' => 'Основная доска задач',
|
||||
'is_default' => 1,
|
||||
];
|
||||
|
||||
$boardId = $this->insert($data);
|
||||
|
||||
if ($boardId) {
|
||||
// Создаём дефолтные колонки
|
||||
$columnModel = new TaskColumnModel();
|
||||
$columnModel->createDefaultColumns($boardId);
|
||||
}
|
||||
|
||||
return $boardId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Tasks\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\Traits\TenantScopedModel;
|
||||
|
||||
class TaskColumnModel extends Model
|
||||
{
|
||||
use TenantScopedModel;
|
||||
|
||||
protected $table = 'task_columns';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useAutoIncrement = true;
|
||||
protected $returnType = 'array';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $tenantField = 'organization_id';
|
||||
protected $allowedFields = [
|
||||
'board_id',
|
||||
'name',
|
||||
'color',
|
||||
'order_index',
|
||||
'is_default',
|
||||
];
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
|
||||
/**
|
||||
* Получить колонки доски
|
||||
*/
|
||||
public function getColumnsByBoard(int $boardId): array
|
||||
{
|
||||
return $this->where('board_id', $boardId)
|
||||
->orderBy('order_index', 'ASC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить следующий порядковый номер для колонки
|
||||
*/
|
||||
public function getNextOrderIndex(int $boardId): int
|
||||
{
|
||||
$max = $this->selectMax('order_index')
|
||||
->where('board_id', $boardId)
|
||||
->first();
|
||||
|
||||
return ($max['order_index'] ?? 0) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать дефолтные колонки для новой доски
|
||||
*/
|
||||
public function createDefaultColumns(int $boardId): bool
|
||||
{
|
||||
$defaultColumns = [
|
||||
[
|
||||
'board_id' => $boardId,
|
||||
'name' => 'К выполнению',
|
||||
'color' => '#6B7280',
|
||||
'order_index' => 1,
|
||||
'is_default' => 0,
|
||||
],
|
||||
[
|
||||
'board_id' => $boardId,
|
||||
'name' => 'В работе',
|
||||
'color' => '#3B82F6',
|
||||
'order_index' => 2,
|
||||
'is_default' => 0,
|
||||
],
|
||||
[
|
||||
'board_id' => $boardId,
|
||||
'name' => 'На проверке',
|
||||
'color' => '#F59E0B',
|
||||
'order_index' => 3,
|
||||
'is_default' => 0,
|
||||
],
|
||||
[
|
||||
'board_id' => $boardId,
|
||||
'name' => 'Завершено',
|
||||
'color' => '#10B981',
|
||||
'order_index' => 4,
|
||||
'is_default' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
return $this->insertBatch($defaultColumns);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace App\Modules\Tasks\Models;
|
||||
|
||||
use CodeIgniter\Model;
|
||||
use App\Models\Traits\TenantScopedModel;
|
||||
|
||||
class TaskModel extends Model
|
||||
{
|
||||
use TenantScopedModel;
|
||||
|
||||
protected $table = 'tasks';
|
||||
protected $primaryKey = 'id';
|
||||
protected $useSoftDeletes = false;
|
||||
protected $useTimestamps = true;
|
||||
protected $createdField = 'created_at';
|
||||
protected $updatedField = 'updated_at';
|
||||
protected $returnType = 'array';
|
||||
protected $tenantField = 'organization_id';
|
||||
protected $allowedFields = [
|
||||
'organization_id',
|
||||
'board_id',
|
||||
'column_id',
|
||||
'title',
|
||||
'description',
|
||||
'priority',
|
||||
'due_date',
|
||||
'completed_at',
|
||||
'order_index',
|
||||
'created_by',
|
||||
];
|
||||
|
||||
/**
|
||||
* Получить задачи с JOIN-ами для таблицы
|
||||
*/
|
||||
public function getForTable(int $organizationId): array
|
||||
{
|
||||
return $this->select('
|
||||
tasks.id,
|
||||
tasks.title,
|
||||
tasks.description,
|
||||
tasks.priority,
|
||||
tasks.due_date,
|
||||
tasks.completed_at,
|
||||
tasks.created_at,
|
||||
tc.name as column_name,
|
||||
tc.color as column_color,
|
||||
u.name as created_by_name
|
||||
')
|
||||
->join('task_columns tc', 'tasks.column_id = tc.id', 'left')
|
||||
->join('users u', 'tasks.created_by = u.id', 'left')
|
||||
->where('tasks.organization_id', $organizationId)
|
||||
->orderBy('tasks.created_at', 'DESC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить задачи, сгруппированные по колонкам (для Канбана)
|
||||
*/
|
||||
public function getTasksGroupedByColumn(int $boardId): array
|
||||
{
|
||||
$tasks = $this->select('tasks.*, tc.name as column_name, tc.color as column_color')
|
||||
->join('task_columns tc', 'tasks.column_id = tc.id', 'left')
|
||||
->where('tasks.board_id', $boardId)
|
||||
->orderBy('tc.order_index', 'ASC')
|
||||
->orderBy('tasks.order_index', 'ASC')
|
||||
->orderBy('tasks.created_at', 'DESC')
|
||||
->findAll();
|
||||
|
||||
$grouped = [];
|
||||
foreach ($tasks as $task) {
|
||||
$columnId = $task['column_id'] ?? 0;
|
||||
if (!isset($grouped[$columnId])) {
|
||||
$grouped[$columnId] = [
|
||||
'column_name' => $task['column_name'] ?? 'Без колонки',
|
||||
'column_color' => $task['column_color'] ?? '#6B7280',
|
||||
'tasks' => [],
|
||||
];
|
||||
}
|
||||
$grouped[$columnId]['tasks'][] = $task;
|
||||
}
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить задачи для календаря
|
||||
*/
|
||||
public function getTasksForCalendar(int $organizationId, string $month): array
|
||||
{
|
||||
return $this->select('tasks.*, tc.color as column_color, tc.name as column_name')
|
||||
->join('task_columns tc', 'tasks.column_id = tc.id', 'left')
|
||||
->where('tasks.organization_id', $organizationId)
|
||||
->where('tasks.due_date >=', date('Y-m-01', strtotime($month)))
|
||||
->where('tasks.due_date <=', date('Y-m-t', strtotime($month)))
|
||||
->where('tasks.completed_at', null)
|
||||
->orderBy('tasks.due_date', 'ASC')
|
||||
->findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить задачу по ID
|
||||
*/
|
||||
public function getTask(int $taskId, int $organizationId): ?array
|
||||
{
|
||||
return $this->select('tasks.*, tc.name as column_name, tc.color as column_color')
|
||||
->join('task_columns tc', 'tasks.column_id = tc.id', 'left')
|
||||
->where('tasks.id', $taskId)
|
||||
->where('tasks.organization_id', $organizationId)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получить статистику по задачам
|
||||
*/
|
||||
public function getTaskStats(int $organizationId): array
|
||||
{
|
||||
$total = $this->select('COUNT(*) as count')
|
||||
->where('organization_id', $organizationId)
|
||||
->countAllResults();
|
||||
|
||||
$completed = $this->select('COUNT(*) as count')
|
||||
->where('organization_id', $organizationId)
|
||||
->where('completed_at IS NOT NULL')
|
||||
->countAllResults();
|
||||
|
||||
$overdue = $this->select('COUNT(*) as count')
|
||||
->where('organization_id', $organizationId)
|
||||
->where('completed_at', null)
|
||||
->where('due_date <', date('Y-m-d'))
|
||||
->countAllResults();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'completed' => $completed,
|
||||
'overdue' => $overdue,
|
||||
'pending' => $total - $completed,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user