- 모델 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 라우트 등록
56 lines
3.1 KiB
PHP
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' => '✓', 'bg' => 'bg-green-500', 'border' => 'border-green-500', 'text' => 'text-green-700'],
|
|
'rejected' => ['icon' => '✗', 'bg' => 'bg-red-500', 'border' => 'border-red-500', 'text' => 'text-red-700'],
|
|
'skipped' => ['icon' => '—', '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>
|