go go alpine
This commit is contained in:
parent
46147de68b
commit
53a9a8db53
@ -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');
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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'>© 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
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
11
public/js/app.js
Normal 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
1
public/js/persist.module.esm.min.js
vendored
Normal 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};
|
||||||
Loading…
x
Reference in New Issue
Block a user