Files
sam-manage/app/Models/Admin/AdminRoadmapPlan.php
김보곤 e272f16357 feat: [database] codebridge DB connection 적용 (merge 후 재적용)
- 78개 MNG 전용 모델에 $connection = 'codebridge' 재적용
- config/database.php codebridge connection 포함
2026-03-07 11:28:47 +09:00

232 lines
6.2 KiB
PHP

<?php
namespace App\Models\Admin;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
class AdminRoadmapPlan extends Model
{
use SoftDeletes;
protected $table = 'admin_roadmap_plans';
protected $fillable = [
'title',
'description',
'content',
'category',
'status',
'priority',
'phase',
'start_date',
'end_date',
'progress',
'color',
'sort_order',
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'start_date' => 'date',
'end_date' => 'date',
'progress' => 'integer',
'sort_order' => 'integer',
'created_by' => 'integer',
'updated_by' => 'integer',
'deleted_by' => 'integer',
];
// 상태
public const STATUS_PLANNED = 'planned';
public const STATUS_IN_PROGRESS = 'in_progress';
public const STATUS_COMPLETED = 'completed';
public const STATUS_DELAYED = 'delayed';
public const STATUS_CANCELLED = 'cancelled';
// 카테고리
public const CATEGORY_GENERAL = 'general';
public const CATEGORY_PRODUCT = 'product';
public const CATEGORY_INFRASTRUCTURE = 'infrastructure';
public const CATEGORY_BUSINESS = 'business';
public const CATEGORY_HR = 'hr';
// 우선순위
public const PRIORITY_LOW = 'low';
public const PRIORITY_MEDIUM = 'medium';
public const PRIORITY_HIGH = 'high';
public const PRIORITY_CRITICAL = 'critical';
// Phase
public const PHASE_1 = 'phase_1';
public const PHASE_2 = 'phase_2';
public const PHASE_3 = 'phase_3';
public const PHASE_4 = 'phase_4';
public static function getStatuses(): array
{
return [
self::STATUS_PLANNED => '계획',
self::STATUS_IN_PROGRESS => '진행중',
self::STATUS_COMPLETED => '완료',
self::STATUS_DELAYED => '지연',
self::STATUS_CANCELLED => '취소',
];
}
public static function getCategories(): array
{
return [
self::CATEGORY_GENERAL => '일반',
self::CATEGORY_PRODUCT => '제품',
self::CATEGORY_INFRASTRUCTURE => '인프라',
self::CATEGORY_BUSINESS => '사업',
self::CATEGORY_HR => '인사',
];
}
public static function getPriorities(): array
{
return [
self::PRIORITY_LOW => '낮음',
self::PRIORITY_MEDIUM => '보통',
self::PRIORITY_HIGH => '높음',
self::PRIORITY_CRITICAL => '긴급',
];
}
public static function getPhases(): array
{
return [
self::PHASE_1 => 'Phase 1 — 코어 실증',
self::PHASE_2 => 'Phase 2 — 3~5사 확장',
self::PHASE_3 => 'Phase 3 — SaaS 전환',
self::PHASE_4 => 'Phase 4 — 스케일업',
];
}
public function scopeStatus($query, string $status)
{
return $query->where('status', $status);
}
public function scopeCategory($query, string $category)
{
return $query->where('category', $category);
}
public function scopePhase($query, string $phase)
{
return $query->where('phase', $phase);
}
public function milestones(): HasMany
{
return $this->hasMany(AdminRoadmapMilestone::class, 'plan_id');
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function updater(): BelongsTo
{
return $this->belongsTo(User::class, 'updated_by');
}
public function getStatusLabelAttribute(): string
{
return self::getStatuses()[$this->status] ?? $this->status;
}
public function getStatusColorAttribute(): string
{
return match ($this->status) {
self::STATUS_PLANNED => 'bg-gray-100 text-gray-800',
self::STATUS_IN_PROGRESS => 'bg-blue-100 text-blue-800',
self::STATUS_COMPLETED => 'bg-green-100 text-green-800',
self::STATUS_DELAYED => 'bg-red-100 text-red-800',
self::STATUS_CANCELLED => 'bg-yellow-100 text-yellow-800',
default => 'bg-gray-100 text-gray-800',
};
}
public function getCategoryLabelAttribute(): string
{
return self::getCategories()[$this->category] ?? $this->category;
}
public function getPriorityLabelAttribute(): string
{
return self::getPriorities()[$this->priority] ?? $this->priority;
}
public function getPriorityColorAttribute(): string
{
return match ($this->priority) {
self::PRIORITY_LOW => 'bg-gray-100 text-gray-600',
self::PRIORITY_MEDIUM => 'bg-blue-100 text-blue-700',
self::PRIORITY_HIGH => 'bg-orange-100 text-orange-700',
self::PRIORITY_CRITICAL => 'bg-red-100 text-red-700',
default => 'bg-gray-100 text-gray-600',
};
}
public function getPhaseLabelAttribute(): string
{
return self::getPhases()[$this->phase] ?? $this->phase;
}
public function getCalculatedProgressAttribute(): int
{
$total = $this->milestones()->count();
if ($total === 0) {
return $this->progress;
}
$completed = $this->milestones()->where('status', AdminRoadmapMilestone::STATUS_COMPLETED)->count();
return (int) round(($completed / $total) * 100);
}
public function getMilestoneStatsAttribute(): array
{
return [
'total' => $this->milestones()->count(),
'pending' => $this->milestones()->where('status', AdminRoadmapMilestone::STATUS_PENDING)->count(),
'completed' => $this->milestones()->where('status', AdminRoadmapMilestone::STATUS_COMPLETED)->count(),
];
}
public function getPeriodAttribute(): string
{
if ($this->start_date && $this->end_date) {
return $this->start_date->format('Y.m').' ~ '.$this->end_date->format('Y.m');
}
if ($this->start_date) {
return $this->start_date->format('Y.m').' ~';
}
return '-';
}
}