go go alpine

This commit is contained in:
mahdahar 2025-11-28 16:52:44 +07:00
parent 46147de68b
commit 53a9a8db53
6 changed files with 171 additions and 8 deletions

View File

@ -52,6 +52,7 @@ $routes->get('api/request/validate/(:any)', 'Request::show/$1');
$routes->post('api/request/validate/(:any)', 'Request::val/$1'); $routes->post('api/request/validate/(:any)', 'Request::val/$1');
$routes->delete('api/request/validate/(:any)', 'Request::unval/$1'); $routes->delete('api/request/validate/(:any)', 'Request::unval/$1');
$routes->get('api/request', 'Request::index');
$routes->get('api/specimen/(:any)', 'Specimen::show/$1'); $routes->get('api/specimen/(:any)', 'Specimen::show/$1');
$routes->post('api/specimen/collect/(:any)', 'Specimen::collect/$1'); $routes->post('api/specimen/collect/(:any)', 'Specimen::collect/$1');

View File

@ -15,6 +15,11 @@ class Request extends BaseController {
COLLECTIONDATE between '$date1 00:00' and '$date2 23:59' COLLECTIONDATE between '$date1 00:00' and '$date2 23:59'
and ODR_DDATE between '$date1 00:00' and '$date2 23:59'"; and ODR_DDATE between '$date1 00:00' and '$date2 23:59'";
$rows = $db->query($sql)->getResultArray(); $rows = $db->query($sql)->getResultArray();
foreach ($rows as &$row) {
$row['COLLECTIONDATE'] = date('Y-m-d H:i', strtotime($row['COLLECTIONDATE']));
$row['ODR_DDATE'] = date('Y-m-d H:i', strtotime($row['ODR_DDATE']));
$row['REQDATE'] = date('Y-m-d H:i', strtotime($row['REQDATE']));
}
$data['data'] = $rows; $data['data'] = $rows;
return $this->response->setJSON($data); return $this->response->setJSON($data);
} }

View File

@ -7,6 +7,7 @@
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" /> <link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script> <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link href="https://cdn.jsdelivr.net/npm/daisyui@5/themes.css" rel="stylesheet" type="text/css" /> <link href="https://cdn.jsdelivr.net/npm/daisyui@5/themes.css" rel="stylesheet" type="text/css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/js/all.min.js"></script>
<style> <style>
body { body {
margin: 0; margin: 0;
@ -19,25 +20,164 @@
} }
</style> </style>
</head> </head>
<body> <body class="bg-base-200 min-h-screen flex flex-col">
<nav class="navbar bg-secondary shadow-sm">
<div class='flex-1'> <nav class="navbar bg-secondary shadow-sm text-white">
<a>CMOD</a> <div class='flex-1 '>
<a class=''>CMOD</a>
</div> </div>
<div class="mr-2"> <div class="mr-2">
<a>Hi, lisfse</a> <a>Hi, lisfse</a>
</div> </div>
<div class="dropdown dropdown-end p-0"> <div class="dropdown dropdown-end p-0">
<div tabindex="0" role="button" class="btn btn-sm btn-secondary">Menu</div> <div tabindex="0" role="button" class="btn btn-sm btn-secondary">Menu</div>
<ul tabindex="-1" class="dropdown-content menu bg-base-100 rounded-box z-1 w-46 p-2 shadow-sm"> <ul tabindex="-1" class="dropdown-content menu bg-base-100 rounded-box z-1 w-46 p-2 shadow-sm text-black">
<li><a>Item 1</a></li> <li><a>Item 1</a></li>
<li><a>Item 2</a></li> <li><a>Item 2</a></li>
</ul> </ul>
</div> </div>
</nav> </nav>
<main class="p-4">
<h3 class="text-lg font-bold mb-4">Dashboard</h3> <main class="p-4 flex-1" x-data="dashboard">
<p>This is the main content area.</p> <h3 class="text-lg font-bold mb-1">Dashboard</h3>
<div class="card bg-base-200">
<div class="card-body p-1">
<div class="flex gap-3 mb-2">
<div class="flex-1 flex gap-1 items-center">
<div>Date</div>
<input type="date" class="input input-sm w-39" x-model="filter.date1"/>-
<input type="date" class="input input-sm w-39" x-model="filter.date2"/>
<button class="btn btn-sm btn-primary" @click='fetchList()'><i class='fa fa-search'></i>Search</button>
<button class="btn btn-sm btn-secondary" @click='reset()'><i class='fa fa-refresh'></i>Reset</button>
</div>
<div class="flex gap-1 text-right">
<button class="btn btn-outline btn-sm"><span x-text="counters.Pend"></span> Pending</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.PartColl"></span> P. Collected</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.Coll"></span> Collected</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.PartRecv"></span> P. Received</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.Recv"></span> Received</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.Inc"></span> Incomplete</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.Fin"></span> Final</button>
<button class="btn btn-outline btn-sm"><span x-text="counters.All"></span> Total</button>
</div>
</div>
</div>
</div>
<template x-if="list.length">
<div class="card bg-base-100 w-full">
<div class="card-body p-1">
<table class="table table-sm table-zebra w-full">
<thead>
<tr>
<th style='width:7%;'>Order Datetime</th>
<th style='width:15%;'>Patient Name</th>
<th style='width:7%;'>No Lab</th>
<th style='width:7%;'>No Register</th>
<th style='width:8%;'>Reff</th>
<th style='width:8%;'>Doctor</th>
<th style='width:15%;'>Tests</th>
<th style='width:5%;'>Result To</th>
<th style='width:5%;'>Validation</th>
<th style='width:4%;'>Status</th>
</tr>
</thead>
<tbody>
<template x-for="req in list" :key="req.SP_ACCESSNUMBER">
<tr class="hover:bg-base-300">
<td x-text="req.REQDATE"></td>
<td x-text="req.Name"></td>
<td x-text="req.SP_ACCESSNUMBER"></td>
<td x-text="req.HOSTORDERNUMBER"></td>
<td x-text="req.REFF"></td>
<td x-text="req.DOC"></td>
<td x-text="req.TESTS"></td>
<td x-text="req.ODR_CRESULT_TO"></td>
<td>
<div>1: <span x-text="req.val1user"></span></div>
<div>2: <span x-text="req.val2user"></span></div>
</td>
<td x-text="req.STATS" :class="statusColor[req.STATS]"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</template>
</main> </main>
<footer class='bg-base-100 p-1'>&copy; 2025 - 5Panda</footer>
<script>
window.BASEURL = "<?=base_url();?>";
</script>
<script type="module">
import Alpine from '<?=base_url("js/app.js");?>';
document.addEventListener('alpine:init', () => {
Alpine.data("dashboard", ()=> ({
today: "",
filter: { date1: "", date2: "" },
list: [],
counters: {
Pend: 0,
PartColl: 0,
Coll: 0,
PartRecv: 0,
Recv: 0,
Inc: 0,
Fin: 0,
},
statusColor: {
Pend: 'bg-white text-black font-bold',
PartColl: 'bg-orange-300 text-black font-bold',
Coll: 'bg-orange-500 text-white font-bold',
PartRecv: 'bg-blue-200 text-black font-bold',
Recv: 'bg-blue-500 text-white font-bold',
Inc: 'bg-yellow-500 text-white font-bold',
Fin: 'bg-green-500 text-white font-bold',
},
init() {
this.today = new Date().toISOString().slice(0, 10);
this.filter.date1 = this.today;
this.filter.date2 = this.today;
},
fetchList(){
this.list = [];
let statusOrder = { Pend: 1, PartColl: 2, Coll: 3, PartRecv: 4, Recv: 5, Inc: 6, Fin: 7 };
let param = new URLSearchParams(this.filter).toString();
// reset counters before processing
for (let k in this.counters) { this.counters[k] = 0; }
fetch(`${BASEURL}/api/request?${param}`, {
method: 'GET',
headers: {'Content-Type': 'application/json'},
}).then(res => res.json()).then(data => {
this.list = data.data ?? [];
// count + sort in a single loop
this.list.forEach(item => {
if (this.counters[item.STATS] !== undefined) { this.counters[item.STATS]++; }
});
this.list.sort((a, b) => {
let codeA = statusOrder[a.STATS] ?? 0;
let codeB = statusOrder[b.STATS] ?? 0;
return codeA - codeB;
});
});
},
reset() {
this.filter.date1 = this.today;
this.filter.date2 = this.today;
this.fetchList();
}
}));
});
Alpine.start();
</script>
</body> </body>
</html> </html>

5
public/js/alpine.module.esm.min.js vendored Normal file

File diff suppressed because one or more lines are too long

11
public/js/app.js Normal file
View File

@ -0,0 +1,11 @@
import Alpine from "./alpine.module.esm.min.js";
import persist from './persist.module.esm.min.js';
Alpine.plugin(persist)
window.Alpine = Alpine
Alpine.data("main", () => ({
}));
export default Alpine;

1
public/js/persist.module.esm.min.js vendored Normal file
View File

@ -0,0 +1 @@
function m(t){let a=()=>{let r,l;try{l=localStorage}catch(i){console.error(i),console.warn("Alpine: $persist is using temporary storage since localStorage is unavailable.");let e=new Map;l={getItem:e.get.bind(e),setItem:e.set.bind(e)}}return t.interceptor((i,e,o,s,d)=>{let n=r||`_x_${s}`,u=g(n,l)?f(n,l):i;return o(u),t.effect(()=>{let c=e();p(n,c,l),o(c)}),u},i=>{i.as=e=>(r=e,i),i.using=e=>(l=e,i)})};Object.defineProperty(t,"$persist",{get:()=>a()}),t.magic("persist",a),t.persist=(r,{get:l,set:i},e=localStorage)=>{let o=g(r,e)?f(r,e):l();i(o),t.effect(()=>{let s=l();p(r,s,e),i(s)})}}function g(t,a){return a.getItem(t)!==null}function f(t,a){let r=a.getItem(t,a);if(r!==void 0)return JSON.parse(r)}function p(t,a,r){r.setItem(t,JSON.stringify(a))}var b=m;export{b as default,m as persist};