gdc_cmod/app/Views/shared/dialog_audit.php
mahdahar 3cf4cc7f3f feat: Implement audit trail system for dual-level validation workflow
This commit adds comprehensive audit logging for specimen requests and sample collection activities across all roles.
Changes Summary:
New Features:
- Added AUDIT_EVENTS table schema for tracking validation and sample collection events
- Created ApiRequestsAuditController with /api/requests/(:any)/audit endpoint to retrieve audit history
- Added dialog_audit.php view component for displaying audit trails in UI
- Integrated audit logging into validation workflow (VAL1, VAL2, UNVAL events)
Database:
- Created AUDIT_EVENTS table with columns: ACCESSNUMBER, EVENT_TYPE, USERID, EVENT_AT, REASON
- Supports tracking validation events and sample collection actions
Controllers:
- RequestsController: Now inserts audit records for all validation operations
- ApiRequestsAuditController: New API controller returning validation and sample collection history
Routes:
- Added GET /api/requests/(:any)/audit endpoint for retrieving audit trail
- Removed DELETE /api/samples/collect/(:any) endpoint (uncollect functionality)
Views Refactoring:
- Consolidated dashboard layouts into shared components:
  - layout.php (from layout_dashboard.php)
  - script_requests.php (from script_dashboard.php)
  - script_validation.php (from script_validate.php)
  - content_requests.php (from dashboard_table.php)
  - content_validation.php (from dashboard_validate.php)
- Added content_validation_new.php for enhanced validation interface
2026-01-23 16:41:12 +07:00

90 lines
3.7 KiB
PHP

<dialog class="modal" :open="isDialogAuditOpen">
<template x-if="auditAccessnumber">
<div class="modal-box w-11/12 max-w-4xl h-[80vh] flex flex-col p-0 overflow-hidden bg-base-100">
<div class="flex justify-between items-center p-3 bg-base-200 border-b border-base-300">
<h3 class="font-bold text-lg flex items-center gap-2">
<i class="fa fa-history text-primary"></i>
Audit Trail
<span class="badge badge-ghost text-xs" x-text="auditAccessnumber"></span>
</h3>
<button class="btn btn-sm btn-circle btn-ghost" @click="closeAuditDialog()">
<i class="fa fa-times"></i>
</button>
</div>
<div class="flex-1 overflow-y-auto p-4 bg-base-100">
<div class="flex gap-2 mb-4">
<button @click="auditTab = 'all'"
:class="auditTab === 'all' ? 'btn-active btn-primary text-white' : 'btn-ghost'"
class="btn btn-sm join-item">All</button>
<button @click="auditTab = 'validation'"
:class="auditTab === 'validation' ? 'btn-active btn-primary text-white' : 'btn-ghost'"
class="btn btn-sm join-item">Validation</button>
<button @click="auditTab = 'sample'"
:class="auditTab === 'sample' ? 'btn-active btn-primary text-white' : 'btn-ghost'"
class="btn btn-sm join-item">Sample</button>
</div>
<div class="space-y-3">
<template x-if="!auditData">
<div class="text-center py-10">
<span class="loading loading-spinner loading-lg text-primary"></span>
<p class="mt-2">Loading audit data...</p>
</div>
</template>
<template x-if="auditData && getAllAuditEvents.length === 0">
<div class="text-center py-10 text-base-content/50">
<i class="fa fa-inbox text-4xl mb-2"></i>
<p>No audit events found</p>
</div>
</template>
<template x-if="auditData && getAllAuditEvents.length > 0">
<div class="relative border-l-2 border-base-300 ml-3 space-y-4">
<template x-for="event in getFilteredAuditEvents" :key="event.id">
<div class="ml-6 relative">
<div class="absolute -left-9 w-6 h-6 rounded-full flex items-center justify-center"
:class="{
'bg-success': event.category === 'validation' && event.type !== 'UNVAL',
'bg-info': event.category === 'sample',
'bg-error': event.category === 'validation' && event.type === 'UNVAL'
}">
<i class="fa text-xs text-white"
:class="{
'fa-check': event.category === 'validation' && event.type !== 'UNVAL',
'fa-vial': event.category === 'sample',
'fa-times': event.category === 'validation' && event.type === 'UNVAL'
}"></i>
</div>
<div class="bg-base-200 rounded-lg p-3 shadow-sm">
<div class="flex justify-between items-start">
<div>
<span class="badge badge-sm mb-1"
:class="{
'badge-success': event.category === 'validation' && event.type !== 'UNVAL',
'badge-info': event.category === 'sample',
'badge-error': event.category === 'validation' && event.type === 'UNVAL'
}"
x-text="event.type"></span>
<p class="font-medium text-sm" x-text="event.description"></p>
<template x-if="event.reason">
<p class="text-xs text-error mt-1" x-text="'Reason: ' + event.reason"></p>
</template>
</div>
<div class="text-right text-xs text-base-content/60">
<p x-text="event.datetime"></p>
<p x-text="event.user"></p>
</div>
</div>
</div>
</div>
</template>
</div>
</template>
</div>
</div>
</div>
</template>
</dialog>