diff --git a/app/Http/Controllers/Api/Admin/ApprovalApiController.php b/app/Http/Controllers/Api/Admin/ApprovalApiController.php index 639c21b2..574b0fd2 100644 --- a/app/Http/Controllers/Api/Admin/ApprovalApiController.php +++ b/app/Http/Controllers/Api/Admin/ApprovalApiController.php @@ -494,6 +494,34 @@ public function badgeCounts(): JsonResponse return response()->json(['success' => true, 'data' => $counts]); } + /** + * 완료함 읽음 처리 (일괄) + */ + public function markCompletedAsRead(): JsonResponse + { + $count = $this->service->markCompletedAsRead(auth()->id()); + + return response()->json([ + 'success' => true, + 'message' => $count > 0 ? "{$count}건 읽음 처리되었습니다." : '새로운 완료 건이 없습니다.', + 'data' => ['marked_count' => $count], + ]); + } + + /** + * 개별 문서 기안자 읽음 처리 + */ + public function markReadSingle(int $id): JsonResponse + { + $approval = $this->service->getApproval($id); + + if ($approval->drafter_id === auth()->id() && ! $approval->drafter_read_at) { + $approval->update(['drafter_read_at' => now()]); + } + + return response()->json(['success' => true]); + } + // ========================================================================= // 첨부파일 // ========================================================================= diff --git a/app/Models/Approvals/Approval.php b/app/Models/Approvals/Approval.php index af5b5053..a563e743 100644 --- a/app/Models/Approvals/Approval.php +++ b/app/Models/Approvals/Approval.php @@ -20,6 +20,7 @@ class Approval extends Model 'attachments' => 'array', 'drafted_at' => 'datetime', 'completed_at' => 'datetime', + 'drafter_read_at' => 'datetime', 'current_step' => 'integer', 'is_urgent' => 'boolean', ]; @@ -38,6 +39,7 @@ class Approval extends Model 'department_id', 'drafted_at', 'completed_at', + 'drafter_read_at', 'current_step', 'attachments', 'recall_reason', diff --git a/app/Providers/ViewServiceProvider.php b/app/Providers/ViewServiceProvider.php index e8524567..578e6ae7 100644 --- a/app/Providers/ViewServiceProvider.php +++ b/app/Providers/ViewServiceProvider.php @@ -78,6 +78,7 @@ public function boot(): void $menuBadges['byUrl']['/approval-mgmt/pending'] = ['count' => $counts['pending'], 'color' => '#ef4444']; $menuBadges['byUrl']['/approval-mgmt/drafts'] = ['count' => $counts['draft'], 'color' => '#3b82f6']; $menuBadges['byUrl']['/approval-mgmt/references'] = ['count' => $counts['reference_unread'], 'color' => '#10b981']; + $menuBadges['byUrl']['/approval-mgmt/completed'] = ['count' => $counts['completed_unread'], 'color' => '#f59e0b']; } catch (\Throwable $e) { // 테이블 미존재 등 예외 무시 } diff --git a/app/Services/ApprovalService.php b/app/Services/ApprovalService.php index 625f041a..0da70582 100644 --- a/app/Services/ApprovalService.php +++ b/app/Services/ApprovalService.php @@ -303,6 +303,7 @@ public function approve(int $id, ?string $comment = null): Approval $approval->update([ 'status' => Approval::STATUS_APPROVED, 'completed_at' => now(), + 'drafter_read_at' => null, 'updated_by' => auth()->id(), ]); @@ -344,6 +345,7 @@ public function reject(int $id, string $comment): Approval $approval->update([ 'status' => Approval::STATUS_REJECTED, 'completed_at' => now(), + 'drafter_read_at' => null, 'updated_by' => auth()->id(), ]); @@ -507,6 +509,7 @@ public function preDecide(int $id, ?string $comment = null): Approval $approval->update([ 'status' => Approval::STATUS_APPROVED, 'completed_at' => now(), + 'drafter_read_at' => null, 'updated_by' => auth()->id(), ]); @@ -753,13 +756,30 @@ public function getBadgeCounts(int $userId): array ->where('is_read', false) ->count(); + $completedUnreadCount = Approval::where('drafter_id', $userId) + ->whereIn('status', [Approval::STATUS_APPROVED, Approval::STATUS_REJECTED]) + ->whereNull('drafter_read_at') + ->count(); + return [ 'pending' => $pendingCount, 'draft' => $draftCount, 'reference_unread' => $referenceUnreadCount, + 'completed_unread' => $completedUnreadCount, ]; } + /** + * 완료함 미읽음 일괄 읽음 처리 + */ + public function markCompletedAsRead(int $userId): int + { + return Approval::where('drafter_id', $userId) + ->whereIn('status', [Approval::STATUS_APPROVED, Approval::STATUS_REJECTED]) + ->whereNull('drafter_read_at') + ->update(['drafter_read_at' => now()]); + } + // ========================================================================= // Private 헬퍼 // ========================================================================= diff --git a/resources/views/approvals/completed.blade.php b/resources/views/approvals/completed.blade.php index 374bab2d..c9258c9d 100644 --- a/resources/views/approvals/completed.blade.php +++ b/resources/views/approvals/completed.blade.php @@ -39,12 +39,20 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc