Files
sam-manage/resources/views/approvals/partials/_step-progress.blade.php
김보곤 9b96a3cad1 feat: [approval] Phase 2 결재관리 고급 기능 구현
- 보류/해제: 현재 결재자가 문서를 보류하고 해제
- 전결: 이후 모든 결재를 건너뛰고 최종 승인
- 회수 강화: 회수 사유 입력, 첫 결재자 미처리 시에만 허용
- 복사 재기안: 완료/반려/회수 문서를 복사하여 새 draft 생성
- 참조 열람 추적: 미열람/열람 필터, mark-read API
- ApprovalDelegation 모델 생성 (Phase 3 위임 대결 준비)
- 뱃지 카운트에 reference_unread 추가
2026-02-27 23:42:12 +09:00

67 lines
3.9 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']);
$isPreDecided = ($step['approval_type'] ?? 'normal') === 'pre_decided';
$statusConfig = match($step['status'] ?? 'pending') {
'approved' => $isPreDecided
? ['icon' => '&#9889;', 'bg' => 'bg-indigo-500', 'border' => 'border-indigo-500', 'text' => 'text-indigo-700']
: ['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'],
'on_hold' => ['icon' => '&#9208;', 'bg' => 'bg-amber-500', 'border' => 'border-amber-500', 'text' => 'text-amber-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 => '',
};
$isFilledStatus = in_array($step['status'] ?? 'pending', ['approved', 'rejected', 'skipped', 'on_hold']) || $isCurrent;
@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'] }} {{ $isFilledStatus ? $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['status'] ?? '') === 'skipped' ? 'line-through' : '' }}">
{{ $step['approver_name'] ?? ($step['approver']['name'] ?? '미지정') }}
</span>
{{-- 유형 + 직급 --}}
<span class="text-xs text-gray-400 whitespace-nowrap">
{{ $typeLabel }}{{ !empty($step['approver_position']) ? ' · ' . $step['approver_position'] : '' }}
@if($isPreDecided && ($step['status'] ?? '') === 'approved')
<span class="text-indigo-500 font-medium">전결</span>
@endif
@if(($step['status'] ?? '') === 'on_hold')
<span class="text-amber-500 font-medium">보류</span>
@endif
</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>