Files
sam-manage/resources/views/approvals/partials/_step-progress.blade.php
김보곤 12c9ad620a feat: [approval] 결재관리 Phase 1 MVP 구현
- 모델 4개: Approval, ApprovalStep, ApprovalForm, ApprovalLine
- ApprovalService: 목록/CRUD/워크플로우(상신/승인/반려/회수) 비즈니스 로직
- ApprovalApiController: JSON API 엔드포인트 (기안함/결재함/완료함/참조함)
- ApprovalController: Blade 뷰 컨트롤러 (HX-Redirect 처리)
- 뷰 8개: drafts, pending, completed, references, create, edit, show
- partials: _status-badge, _step-progress, _approval-line-editor
- api.php/web.php 라우트 등록
2026-02-27 23:17:41 +09:00

56 lines
3.1 KiB
PHP

{{-- 결재 진행 단계 시각화 --}}
@props(['steps' => [], 'currentStep' => 0])
<div class="flex items-center gap-1 overflow-x-auto py-4">
@foreach($steps as $index => $step)
@php
$isApprover = in_array($step['step_type'] ?? 'approval', ['approval', 'agreement']);
$statusConfig = match($step['status'] ?? 'pending') {
'approved' => ['icon' => '&#10003;', 'bg' => 'bg-green-500', 'border' => 'border-green-500', 'text' => 'text-green-700'],
'rejected' => ['icon' => '&#10007;', 'bg' => 'bg-red-500', 'border' => 'border-red-500', 'text' => 'text-red-700'],
'skipped' => ['icon' => '&#8212;', 'bg' => 'bg-gray-400', 'border' => 'border-gray-400', 'text' => 'text-gray-500'],
default => ['icon' => ($step['step_order'] ?? $index + 1), 'bg' => 'bg-white', 'border' => 'border-gray-300', 'text' => 'text-gray-500'],
};
$isCurrent = $isApprover && ($step['status'] ?? 'pending') === 'pending' && ($step['step_order'] ?? 0) == $currentStep;
if ($isCurrent) {
$statusConfig['bg'] = 'bg-blue-500';
$statusConfig['border'] = 'border-blue-500';
$statusConfig['text'] = 'text-blue-700';
$statusConfig['icon'] = ($step['step_order'] ?? $index + 1);
}
$typeLabel = match($step['step_type'] ?? 'approval') {
'approval' => '결재',
'agreement' => '합의',
'reference' => '참조',
default => '',
};
@endphp
@if($index > 0)
<div class="shrink-0" style="width: 24px; height: 2px; background-color: {{ in_array($step['status'] ?? 'pending', ['approved']) ? '#22c55e' : '#d1d5db' }};"></div>
@endif
<div class="flex flex-col items-center shrink-0" style="min-width: 70px;">
{{-- 원형 아이콘 --}}
<div class="flex items-center justify-center rounded-full border-2 {{ $statusConfig['border'] }} {{ in_array($step['status'] ?? 'pending', ['approved', 'rejected', 'skipped']) || $isCurrent ? $statusConfig['bg'] . ' text-white' : $statusConfig['bg'] }}"
style="width: 36px; height: 36px; font-size: 14px; font-weight: 600;">
{!! $statusConfig['icon'] !!}
</div>
{{-- 결재자명 --}}
<span class="text-xs mt-1 {{ $statusConfig['text'] }} font-medium whitespace-nowrap">
{{ $step['approver_name'] ?? ($step['approver']['name'] ?? '미지정') }}
</span>
{{-- 유형 + 직급 --}}
<span class="text-xs text-gray-400 whitespace-nowrap">
{{ $typeLabel }}{{ !empty($step['approver_position']) ? ' · ' . $step['approver_position'] : '' }}
</span>
{{-- 처리일시 --}}
@if(!empty($step['acted_at']))
<span class="text-xs text-gray-400 whitespace-nowrap">
{{ \Carbon\Carbon::parse($step['acted_at'])->format('m/d H:i') }}
</span>
@endif
</div>
@endforeach
</div>