Major Updates:
1. Extended Audit Trail System
- Added tube received events tracking from SP_TUBES table (TUBESTATUS=4)
- New audit tab "Receive" in dialog_audit.php to display tube reception history
- ApiRequestsAuditController now fetches and returns tube received events with:
* Sample type, tube status, collection date, and user information
- Audit events sorted chronologically combining validation, sampling, and receiving events
2. Enhanced PDF Generation Workflow
- Created new PdfHelper library with methods for PDF generation and posting to spooler
- Reports can now be generated via GET /report/{accessnumber}/pdf endpoint
- Updated PDF spooler API endpoint from port 3030 to 3000
- Added retry PDF button with spinner animation for failed generations
- Fixed PDF status check to use correct spooler endpoint
3. Validation UI Improvements
- Added toast notification showing PDF queued after second validation (val2)
- Retry PDF button appears when val1 and val2 are complete
- Toast notifications success/error states with auto-dismiss after 2 seconds
- Loading state with spinning icon during PDF retry operation
4. Report Template Fixes
- Fixed typo in Val2 By display (added missing ":")
- Consistent formatting with Val1 By : and Val2 By :
5. Documentation Updates
- TODO.md updated with:
* Auto generate PDF (in progress)
* Print Eng Result (pending)
* Add Receive to Audit (completed)
6. Cleanup
- Removed legacy Node.js spooler implementation (node_spooler directory)
- Deleted P0_log.txt (SQL setup scripts no longer needed in repo)
- Cleaned up .gitignore to remove stale node_spooler entries
Files Changed:
- app/Controllers/ApiRequestsAuditController.php (tube received audit)
- app/Controllers/ReportController.php (port update: 3030 → 3000)
- app/Libraries/PdfHelper.php (new library)
- app/Views/report/template.php (typo fix)
- app/Views/shared/content_requests.php (retry PDF button)
- app/Views/shared/dialog_audit.php (receive tab)
- app/Views/shared/script_requests.php (retry handler, tube events)
- app/Views/shared/script_validation.php (enhanced toast)
- TODO.md (pending/completed tasks)
- .gitignore (cleanup)
- Deleted: node_spooler/* (legacy implementation)
- Deleted: P0_log.txt (no longer needed)
96 lines
4.0 KiB
PHP
96 lines
4.0 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 = 'receive'"
|
|
:class="auditTab === 'receive' ? 'btn-active btn-warning text-white' : 'btn-ghost'"
|
|
class="btn btn-sm join-item">Receive</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-warning': event.category === 'receive',
|
|
'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-check-circle': event.category === 'receive',
|
|
'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-warning': event.category === 'receive',
|
|
'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>
|