- 78개 MNG 전용 모델에 $connection = 'codebridge' 재적용 - config/database.php codebridge connection 포함
232 lines
6.2 KiB
PHP
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 '-';
|
|
}
|
|
}
|