feat:감사 로그 뷰어 추가 (시스템 설정 > 감사 로그)
- AuditLogController: 목록/상세 조회, 필터링(액션/테넌트/날짜/검색) - AuditLog 모델: 재고 변동 액션 및 참조 타입 상수 정의 - Blade 뷰: 통계 카드, 필터, 아코디언(Before/After JSON), 상세 페이지 - 메뉴 DB 등록: 시스템 설정 하위에 감사 로그, 삭제된 데이터 백업 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
109
app/Http/Controllers/AuditLogController.php
Normal file
109
app/Http/Controllers/AuditLogController.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Audit\AuditLog;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class AuditLogController extends Controller
|
||||
{
|
||||
/**
|
||||
* 감사 로그 목록
|
||||
*/
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$query = AuditLog::query()
|
||||
->with(['tenant', 'actor'])
|
||||
->orderByDesc('created_at');
|
||||
|
||||
// 대상 타입 필터 (기본: Stock)
|
||||
$targetType = $request->input('target_type', 'Stock');
|
||||
if ($targetType) {
|
||||
$query->where('target_type', $targetType);
|
||||
}
|
||||
|
||||
// 액션 필터
|
||||
if ($request->filled('action')) {
|
||||
$query->where('action', $request->action);
|
||||
}
|
||||
|
||||
// 테넌트 필터
|
||||
if ($request->filled('tenant_id')) {
|
||||
$query->where('tenant_id', $request->tenant_id);
|
||||
}
|
||||
|
||||
// 날짜 범위 필터
|
||||
if ($request->filled('from')) {
|
||||
$query->where('created_at', '>=', $request->from.' 00:00:00');
|
||||
}
|
||||
if ($request->filled('to')) {
|
||||
$query->where('created_at', '<=', $request->to.' 23:59:59');
|
||||
}
|
||||
|
||||
// 검색 (LOT 번호, 참조 ID)
|
||||
if ($request->filled('search')) {
|
||||
$search = $request->search;
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->whereRaw("JSON_EXTRACT(after, '$.lot_no') LIKE ?", ["%{$search}%"])
|
||||
->orWhereRaw("JSON_EXTRACT(after, '$.reference_id') = ?", [$search]);
|
||||
});
|
||||
}
|
||||
|
||||
// 통계
|
||||
$stats = $this->getStats($targetType);
|
||||
|
||||
// 페이지네이션
|
||||
$logs = $query->paginate(50)->withQueryString();
|
||||
|
||||
// 테넌트 목록 (필터용)
|
||||
$tenants = Tenant::orderBy('company_name')->get(['id', 'company_name as name']);
|
||||
|
||||
// 액션 목록
|
||||
$actions = AuditLog::STOCK_ACTIONS;
|
||||
|
||||
return view('audit-logs.index', compact('logs', 'stats', 'tenants', 'actions', 'targetType'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 감사 로그 상세
|
||||
*/
|
||||
public function show(int $id): View
|
||||
{
|
||||
$log = AuditLog::with(['tenant', 'actor'])->findOrFail($id);
|
||||
|
||||
return view('audit-logs.show', compact('log'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 통계 조회
|
||||
*/
|
||||
private function getStats(?string $targetType): array
|
||||
{
|
||||
$baseQuery = AuditLog::query();
|
||||
|
||||
if ($targetType) {
|
||||
$baseQuery->where('target_type', $targetType);
|
||||
}
|
||||
|
||||
$total = (clone $baseQuery)->count();
|
||||
|
||||
$byAction = (clone $baseQuery)
|
||||
->selectRaw('action, COUNT(*) as count')
|
||||
->groupBy('action')
|
||||
->pluck('count', 'action')
|
||||
->toArray();
|
||||
|
||||
// 오늘 기록 수
|
||||
$today = (clone $baseQuery)
|
||||
->whereDate('created_at', today())
|
||||
->count();
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'today' => $today,
|
||||
'by_action' => $byAction,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user