prework 1

This commit is contained in:
mahdahar 2025-11-30 20:34:19 +07:00
parent 53a9a8db53
commit c69043cfbf
3 changed files with 96 additions and 145 deletions

View File

@ -0,0 +1,8 @@
<dialog id="form" class="modal" :open="isDialogSampleOpen">
<div class="modal-box w-2/3 max-w-5xl">
<p class='text-right'><button class="btn btn-xs btn-neutral" @click="closeSampleDialog()">X</button></p>
</div>
</dialog>

View File

@ -12,18 +12,21 @@
body { body {
margin: 0; margin: 0;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-size: 0.75rem; font-size: 0.71rem;
} }
.navbar { .navbar {
padding: 0.2rem 1rem; padding: 0.2rem 1rem;
min-height: 0rem; min-height: 0rem;
} }
.card-body {
font-size: 0.71rem !important;
}
</style> </style>
</head> </head>
<body class="bg-base-200 min-h-screen flex flex-col"> <body class="bg-base-200 min-h-screen flex flex-col">
<nav class="navbar bg-secondary shadow-sm text-white"> <nav class="navbar bg-secondary shadow-sm text-white">
<div class='flex-1 '> <div class='flex-1 font-bold'>
<a class=''>CMOD</a> <a class=''>CMOD</a>
</div> </div>
<div class="mr-2"> <div class="mr-2">
@ -38,37 +41,36 @@
</div> </div>
</nav> </nav>
<main class="p-4 flex-1" x-data="dashboard"> <main class="p-4 flex-1 flex flex-col gap-2" x-data="dashboard">
<h3 class="text-lg font-bold mb-1">Dashboard</h3> <div class="card bg-base-100">
<div class="card bg-base-200"> <div class="card-body p-3 max-h-full overflow-y-auto">
<div class="card-body p-1"> <div class="flex gap-1">
<div class="flex gap-3 mb-2"> <div class="flex-1 font-bold text-lg">Dashboard</div>
<div class="flex-1 flex gap-1 items-center"> <div class="flex gap-1">
<button @click="filterKey = 'Pend'" :class="filterKey === 'Pend' ? 'btn-active' : ''" class="btn btn-outline btn-sm"><span x-text="counters.Pend"></span> Pending</button>
<button @click="filterKey = 'Coll'" :class="filterKey === 'Coll' ? 'btn-active' : ''" class="btn btn-outline btn-sm btn-secondary"><span x-text="counters.Coll"></span> Collected</button>
<button @click="filterKey = 'Recv'" :class="filterKey === 'Recv' ? 'btn-active' : ''" class="btn btn-outline btn-sm btn-primary"><span x-text="counters.Recv"></span> Received</button>
<button @click="filterKey = 'Inc'" :class="filterKey === 'Inc' ? 'btn-active' : ''" class="btn btn-outline btn-sm btn-warning"><span x-text="counters.Inc"></span> Incomplete</button>
<button @click="filterKey = 'Fin'" :class="filterKey === 'Fin' ? 'btn-active' : ''" class="btn btn-outline btn-sm btn-success"><span x-text="counters.Fin"></span> Final</button>
<button @click="filterKey = 'Total'" :class="filterKey === 'Total' ? 'btn-active' : ''" class="btn btn-outline btn-sm"><span x-text="counters.Total"></span> Total</button>
</div>
</div>
<div class="flex gap-3 mb-2">
<div class="flex-1 flex gap-2 items-center">
<div>Date</div> <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.date1"/>-
<input type="date" class="input input-sm w-39" x-model="filter.date2"/> <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-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> <button class="btn btn-sm btn-secondary" @click='reset()'><i class='fa fa-refresh'></i>Reset</button>
</div> </div>
<div class="flex gap-1 text-right"> <div class="flex gap-2 items-center">
<button class="btn btn-outline btn-sm"><span x-text="counters.Pend"></span> Pending</button> <div>Filter</div>
<button class="btn btn-outline btn-sm"><span x-text="counters.PartColl"></span> P. Collected</button> <input type="text" class="input input-sm w-39" x-model="filterTable" />
<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>
</div> <template x-if="list.length">
</div> <table class="table table-xs table-zebra w-full">
<thead class="bg-base-100 sticky top-0 z-10">
<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> <tr>
<th style='width:7%;'>Order Datetime</th> <th style='width:7%;'>Order Datetime</th>
<th style='width:15%;'>Patient Name</th> <th style='width:15%;'>Patient Name</th>
@ -83,7 +85,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<template x-for="req in list" :key="req.SP_ACCESSNUMBER"> <template x-for="req in filtered" :key="req.SP_ACCESSNUMBER">
<tr class="hover:bg-base-300"> <tr class="hover:bg-base-300">
<td x-text="req.REQDATE"></td> <td x-text="req.REQDATE"></td>
<td x-text="req.Name"></td> <td x-text="req.Name"></td>
@ -97,14 +99,17 @@
<div>1: <span x-text="req.val1user"></span></div> <div>1: <span x-text="req.val1user"></span></div>
<div>2: <span x-text="req.val2user"></span></div> <div>2: <span x-text="req.val2user"></span></div>
</td> </td>
<td x-text="req.STATS" :class="statusColor[req.STATS]"></td> <td><button x-text="req.STATS" class="btn btn-xs"
:class="statusColor[req.STATS]" @click="openSampleDialog(req.SP_ACCESSNUMBER)"></button></td>
</tr> </tr>
</template> </template>
</tbody> </tbody>
</table> </table>
</template>
</div> </div>
</div> </div>
</template>
<?php echo $this->include('v2/dialog_sample'); ?>
</main> </main>
<footer class='bg-base-100 p-1'>&copy; 2025 - 5Panda</footer> <footer class='bg-base-100 p-1'>&copy; 2025 - 5Panda</footer>
@ -117,32 +122,38 @@
document.addEventListener('alpine:init', () => { document.addEventListener('alpine:init', () => {
Alpine.data("dashboard", ()=> ({ Alpine.data("dashboard", ()=> ({
// dashboard
today: "", today: "",
filter: { date1: "", date2: "" }, filter: { date1: "", date2: "" },
list: [], list: [],
counters: { counters: { Pend: 0, Coll: 0, Recv: 0, Inc: 0, Fin: 0, Total: 0 },
Pend: 0,
PartColl: 0,
Coll: 0,
PartRecv: 0,
Recv: 0,
Inc: 0,
Fin: 0,
},
statusColor: { statusColor: {
Pend: 'bg-white text-black font-bold', Pend: 'bg-white text-black font-bold',
PartColl: 'bg-orange-300 text-black font-bold', PartColl: 'bg-orange-300 text-white font-bold',
Coll: 'bg-orange-500 text-white font-bold', Coll: 'bg-orange-500 text-white font-bold',
PartRecv: 'bg-blue-200 text-black font-bold', PartRecv: 'bg-blue-200 text-black font-bold',
Recv: 'bg-blue-500 text-white font-bold', Recv: 'bg-blue-500 text-white font-bold',
Inc: 'bg-yellow-500 text-white font-bold', Inc: 'bg-yellow-500 text-white font-bold',
Fin: 'bg-green-500 text-white font-bold', Fin: 'bg-green-500 text-white font-bold',
}, },
filterTable :"",
filterKey: 'Total',
statusMap: {
Total: [],
Pend: ['Pend'],
Coll: ['Coll', 'PartColl'],
Recv: ['Recv'],
Inc: ['Inc'],
Fin: ['Fin'],
},
init() { init() {
this.today = new Date().toISOString().slice(0, 10); this.today = new Date().toISOString().slice(0, 10);
this.filter.date1 = this.today; this.filter.date1 = "2025-05-05";
this.filter.date2 = this.today; this.filter.date2 = "2025-05-05";
//this.fetchList();
//this.filter.date1 = this.today;
//this.filter.date2 = this.today;
}, },
fetchList(){ fetchList(){
@ -156,9 +167,15 @@
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
}).then(res => res.json()).then(data => { }).then(res => res.json()).then(data => {
this.list = data.data ?? []; this.list = data.data ?? [];
this.filterKey = 'Total';
// count + sort in a single loop // count + sort in a single loop
this.list.forEach(item => { this.list.forEach(item => {
if (this.counters[item.STATS] !== undefined) { this.counters[item.STATS]++; } if (this.counters[item.STATS] !== undefined) { this.counters[item.STATS]++; this.counters.Total++; }
else {
if(item.STATS == 'PartColl') { this.counters.Coll++; }
else if(item.STATS == 'PartRecv') { this.counters.Recv++; }
this.counters.Total++;
}
}); });
this.list.sort((a, b) => { this.list.sort((a, b) => {
let codeA = statusOrder[a.STATS] ?? 0; let codeA = statusOrder[a.STATS] ?? 0;
@ -172,7 +189,36 @@
this.filter.date1 = this.today; this.filter.date1 = this.today;
this.filter.date2 = this.today; this.filter.date2 = this.today;
this.fetchList(); this.fetchList();
} },
get filtered() {
let data = this.list;
const valid = this.statusMap[this.filterKey]
if (valid.length > 0) {
data = data.filter(i => valid.includes(i.STATS));
}
if (this.filterTable) {
const s = this.filterTable.toLowerCase();
data = data.filter(i =>
Object.values(i).some(v =>
String(v).toLowerCase().includes(s)
)
);
}
return data;
},
// sample dialog
isDialogSampleOpen : false,
openSampleDialog (accessnumber) {
this.isDialogSampleOpen = true;
},
closeSampleDialog () {
this.isDialogSampleOpen = false;
},
})); }));
}); });

View File

@ -1,103 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Collapsible Sidebar (Icons Visible)</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
<style>
body {
overflow-x: hidden;
}
#sidebar {
width: 250px;
position: fixed;
top: 0;
left: 0;
height: 100vh;
background: #343a40;
color: #fff;
transition: all 0.3s;
overflow: hidden;
}
#sidebar.collapsed {
width: 70px;
}
#sidebar .nav-link {
color: #adb5bd;
display: flex;
align-items: center;
gap: 10px;
white-space: nowrap;
overflow: hidden;
transition: all 0.3s;
}
#sidebar.collapsed .nav-link span {
opacity: 0;
visibility: hidden;
width: 0;
}
#sidebar .nav-link.active {
background: #495057;
color: #fff;
}
#content {
margin-left: 250px;
transition: all 0.3s;
padding: 20px;
}
#content.fullwidth {
margin-left: 70px;
}
.toggle-btn {
position: fixed;
top: 15px;
left: 15px;
z-index: 999;
}
</style>
</head>
<body>
<!-- Toggle Button -->
<button class="btn btn-secondary toggle-btn" id="toggleSidebar">
<i class="bi bi-list"></i>
</button>
<!-- Sidebar -->
<div id="sidebar">
<h5 class="p-3 border-bottom text-center text-truncate">
<span class="sidebar-title">My App</span>
</h5>
<nav class="nav flex-column px-2">
<a class="nav-link active" href="#"><i class="bi bi-house-door"></i> <span>Dashboard</span></a>
<a class="nav-link" href="#"><i class="bi bi-people"></i> <span>Users</span></a>
<a class="nav-link" href="#"><i class="bi bi-graph-up"></i> <span>Reports</span></a>
<a class="nav-link" href="#"><i class="bi bi-gear"></i> <span>Settings</span></a>
</nav>
</div>
<!-- Main Content -->
<div id="content">
<h2>Dashboard</h2>
<p>This is your main content area. Click the button to collapse or expand the sidebar. Icons stay visible when collapsed.</p>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
$(function () {
$('#toggleSidebar').on('click', function () {
$('#sidebar').toggleClass('collapsed');
$('#content').toggleClass('fullwidth');
});
$('#sidebar .nav-link').on('click', function () {
$('#sidebar .nav-link').removeClass('active');
$(this).addClass('active');
});
});
</script>
</body>
</html>