'integer', 'is_urgent' => 'boolean', 'due_date' => 'date', 'sort_order' => 'integer', 'assignee_id' => 'integer', 'created_by' => 'integer', 'updated_by' => 'integer', 'deleted_by' => 'integer', ]; /** * 상태 상수 */ public const STATUS_TODO = 'todo'; public const STATUS_IN_PROGRESS = 'in_progress'; public const STATUS_DONE = 'done'; /** * 우선순위 상수 */ public const PRIORITY_LOW = 'low'; public const PRIORITY_MEDIUM = 'medium'; public const PRIORITY_HIGH = 'high'; /** * 상태 목록 */ public static function getStatuses(): array { return [ self::STATUS_TODO => '예정', self::STATUS_IN_PROGRESS => '진행중', self::STATUS_DONE => '완료', ]; } /** * 우선순위 목록 */ public static function getPriorities(): array { return [ self::PRIORITY_LOW => '낮음', self::PRIORITY_MEDIUM => '보통', self::PRIORITY_HIGH => '높음', ]; } /** * 상태별 필터 */ public function scopeStatus($query, string $status) { return $query->where('status', $status); } /** * 우선순위별 필터 */ public function scopePriority($query, string $priority) { return $query->where('priority', $priority); } /** * 마감일 지난 작업 */ public function scopeOverdue($query) { return $query->whereNotNull('due_date') ->where('due_date', '<', now()->startOfDay()) ->where('status', '!=', self::STATUS_DONE); } /** * 마감일 임박 (3일 이내) */ public function scopeDueSoon($query, int $days = 3) { return $query->whereNotNull('due_date') ->whereBetween('due_date', [now()->startOfDay(), now()->addDays($days)->endOfDay()]) ->where('status', '!=', self::STATUS_DONE); } /** * 관계: 프로젝트 */ public function project(): BelongsTo { return $this->belongsTo(AdminPmProject::class, 'project_id'); } /** * 관계: 담당자 */ public function assignee(): BelongsTo { return $this->belongsTo(User::class, 'assignee_id'); } /** * 관계: 연결된 이슈들 */ public function issues(): HasMany { return $this->hasMany(AdminPmIssue::class, 'task_id'); } /** * 관계: 생성자 */ public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } /** * 관계: 수정자 */ public function updater(): BelongsTo { return $this->belongsTo(User::class, 'updated_by'); } /** * D-day 계산 (마감일까지 남은 일수) */ public function getDdayAttribute(): ?int { if (! $this->due_date) { return null; } return now()->startOfDay()->diffInDays($this->due_date, false); } /** * 마감 상태 (overdue, due_soon, normal, null) */ public function getDueStatusAttribute(): ?string { if (! $this->due_date || $this->status === self::STATUS_DONE) { return null; } $dday = $this->dday; if ($dday < 0) { return 'overdue'; } if ($dday <= 3) { return 'due_soon'; } return 'normal'; } }