- AuditLogController: 목록/상세 조회, 필터링(액션/테넌트/날짜/검색) - AuditLog 모델: 재고 변동 액션 및 참조 타입 상수 정의 - Blade 뷰: 통계 카드, 필터, 아코디언(Before/After JSON), 상세 페이지 - 메뉴 DB 등록: 시스템 설정 하위에 감사 로그, 삭제된 데이터 백업 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
193 lines
8.1 KiB
PHP
193 lines
8.1 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', '감사 로그 상세')
|
|
|
|
@section('content')
|
|
<!-- 페이지 헤더 -->
|
|
<div class="flex justify-between items-center mb-6">
|
|
<div class="flex items-center gap-4">
|
|
<a href="{{ route('audit-logs.index') }}" class="p-2 text-gray-600 hover:text-gray-800 hover:bg-gray-100 rounded-lg">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
</svg>
|
|
</a>
|
|
<h1 class="text-2xl font-bold text-gray-800">감사 로그 상세 #{{ $log->id }}</h1>
|
|
</div>
|
|
<div class="text-sm text-gray-500">
|
|
{{ $log->created_at->format('Y-m-d H:i:s') }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 기본 정보 카드 -->
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">기본 정보</h2>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<!-- 액션 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">액션</label>
|
|
@php
|
|
$actionColors = [
|
|
'stock_increase' => 'bg-green-100 text-green-800',
|
|
'stock_decrease' => 'bg-red-100 text-red-800',
|
|
'stock_reserve' => 'bg-yellow-100 text-yellow-800',
|
|
'stock_release' => 'bg-blue-100 text-blue-800',
|
|
];
|
|
@endphp
|
|
<span class="px-3 py-1 text-sm font-medium rounded {{ $actionColors[$log->action] ?? 'bg-gray-100 text-gray-800' }}">
|
|
{{ $log->action_label }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- 대상 타입 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">대상 타입</label>
|
|
<p class="text-gray-900 font-medium">{{ $log->target_type }}</p>
|
|
</div>
|
|
|
|
<!-- 대상 ID -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">대상 ID</label>
|
|
<p class="text-gray-900 font-medium">#{{ $log->target_id }}</p>
|
|
</div>
|
|
|
|
<!-- 테넌트 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">테넌트</label>
|
|
<p class="text-gray-900 font-medium">{{ $log->tenant?->company_name ?? '-' }}</p>
|
|
</div>
|
|
|
|
<!-- LOT 번호 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">LOT 번호</label>
|
|
<p class="text-gray-900 font-mono">{{ $log->lot_no ?? '-' }}</p>
|
|
</div>
|
|
|
|
<!-- 수량 변화 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">수량 변화</label>
|
|
<p class="font-medium {{ $log->qty_change > 0 ? 'text-green-600' : ($log->qty_change < 0 ? 'text-red-600' : 'text-gray-500') }}">
|
|
@if($log->qty_change > 0)
|
|
+{{ number_format($log->qty_change, 2) }}
|
|
@elseif($log->qty_change < 0)
|
|
{{ number_format($log->qty_change, 2) }}
|
|
@else
|
|
-
|
|
@endif
|
|
</p>
|
|
</div>
|
|
|
|
<!-- 사유 -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">사유</label>
|
|
<p class="text-gray-900 font-medium">{{ $log->reason_label ?? '-' }}</p>
|
|
</div>
|
|
|
|
<!-- 참조 ID -->
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">참조 ID</label>
|
|
<p class="text-gray-900">
|
|
@if($log->reference_id)
|
|
<span class="text-blue-600">#{{ $log->reference_id }}</span>
|
|
@if($log->reference_type)
|
|
<span class="text-gray-500 text-sm">({{ $log->reference_type }})</span>
|
|
@endif
|
|
@else
|
|
-
|
|
@endif
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 수행자 정보 -->
|
|
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">수행자 정보</h2>
|
|
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">수행자</label>
|
|
<p class="text-gray-900 font-medium">{{ $log->actor?->name ?? '시스템' }}</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">이메일</label>
|
|
<p class="text-gray-900">{{ $log->actor?->email ?? '-' }}</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">IP 주소</label>
|
|
<p class="text-gray-900 font-mono">{{ $log->ip ?? '-' }}</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm text-gray-500 mb-1">User Agent</label>
|
|
<p class="text-gray-900 text-sm truncate" title="{{ $log->ua }}">{{ Str::limit($log->ua, 50) ?? '-' }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 데이터 비교 -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
|
<!-- Before -->
|
|
<div class="bg-white rounded-lg shadow-sm p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">변경 전 (Before)</h2>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto max-h-96">
|
|
<pre class="text-yellow-400 text-sm font-mono whitespace-pre-wrap">{{ json_encode($log->before, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) ?: '(데이터 없음)' }}</pre>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- After -->
|
|
<div class="bg-white rounded-lg shadow-sm p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">변경 후 (After)</h2>
|
|
<div class="bg-gray-900 rounded-lg p-4 overflow-x-auto max-h-96">
|
|
<pre class="text-green-400 text-sm font-mono whitespace-pre-wrap">{{ json_encode($log->after, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) ?: '(데이터 없음)' }}</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 변경 내용 하이라이트 -->
|
|
@if($log->before && $log->after)
|
|
<div class="bg-white rounded-lg shadow-sm p-6">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">변경 내용 요약</h2>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">필드</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">변경 전</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">변경 후</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
@php
|
|
$allKeys = array_unique(array_merge(array_keys($log->before ?? []), array_keys($log->after ?? [])));
|
|
@endphp
|
|
@foreach($allKeys as $key)
|
|
@php
|
|
$beforeVal = $log->before[$key] ?? null;
|
|
$afterVal = $log->after[$key] ?? null;
|
|
$changed = $beforeVal !== $afterVal;
|
|
@endphp
|
|
<tr class="{{ $changed ? 'bg-yellow-50' : '' }}">
|
|
<td class="px-4 py-2 text-sm font-medium text-gray-900">{{ $key }}</td>
|
|
<td class="px-4 py-2 text-sm text-gray-500 font-mono">
|
|
@if(is_array($beforeVal))
|
|
{{ json_encode($beforeVal, JSON_UNESCAPED_UNICODE) }}
|
|
@else
|
|
{{ $beforeVal ?? '-' }}
|
|
@endif
|
|
</td>
|
|
<td class="px-4 py-2 text-sm font-mono {{ $changed ? 'text-green-600 font-medium' : 'text-gray-500' }}">
|
|
@if(is_array($afterVal))
|
|
{{ json_encode($afterVal, JSON_UNESCAPED_UNICODE) }}
|
|
@else
|
|
{{ $afterVal ?? '-' }}
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
@endsection |