Files
2026-09-16 23:20:08 +07:00

198 lines
11 KiB
PHP

<?php
/**
* Patient & EMR Management View (Glassmorphism)
*/
?>
<div x-data="patientApp" class="space-y-6">
<!-- Header & Search -->
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 glass-card p-6 rounded-2xl border">
<div>
<h1 class="text-2xl font-bold tracking-tight bg-gradient-to-r from-emerald-400 to-cyan-400 bg-clip-text text-transparent">
ทะเบียนผู้ป่วย & เวชระเบียน EMR (Patient Management)
</h1>
<p class="text-sm text-subtle mt-1">จัดการข้อมูลผู้รับบริการ ประวัติการรักษาโรค และเชื่อมต่อฐานข้อมูล HIS โรงพยาบาล</p>
</div>
<div class="flex items-center gap-3">
<div class="relative w-full sm:w-64">
<input type="text" x-model="searchQuery" @input="filterPatients()" placeholder="ค้นหา HN, ชื่อ หรือเลขบัตร 13 หลัก..." class="glass-input pl-9 text-sm">
<i class="bi bi-search text-subtle absolute left-3 top-3"></i>
</div>
<button @click="openNewModal()" class="glass-btn-primary text-sm whitespace-nowrap">
<i class="bi bi-person-plus-fill"></i>
<span>ขึ้นทะเบียนผู้ป่วยใหม่</span>
</button>
</div>
</div>
<!-- Patient Table Card -->
<div class="glass-card p-6 rounded-2xl border overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="border-b border-slate-700/60 text-xs font-semibold text-subtle uppercase">
<th class="py-3 px-4">HN / CID</th>
<th class="py-3 px-4">ชื่อ - นามสกุล</th>
<th class="py-3 px-4">อายุ / เพศ</th>
<th class="py-3 px-4">เบอร์โทรศัพท์</th>
<th class="py-3 px-4">สิทธิการรักษา</th>
<th class="py-3 px-4">โรคประจำตัว / ข้อห้าม</th>
<th class="py-3 px-4 text-right">จัดการ</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-700/40 text-sm">
<template x-for="p in displayPatients" :key="p.id">
<tr class="hover:bg-slate-800/40 transition-colors">
<td class="py-3.5 px-4 font-mono font-bold text-cyan-400">
<div x-text="p.hn">HN-2407001</div>
<div class="text-[11px] text-subtle font-normal" x-text="p.cid">1100000000001</div>
</td>
<td class="py-3.5 px-4 font-semibold" x-text="`${p.first_name_th} ${p.last_name_th}`">คุณสมชาย รักสุขภาพ</td>
<td class="py-3.5 px-4" x-text="`${p.age} ปี / ${p.gender}`">45 ปี / ชาย</td>
<td class="py-3.5 px-4 font-mono" x-text="p.phone">081-234-5678</td>
<td class="py-3.5 px-4">
<span class="px-2.5 py-0.5 rounded-full text-xs font-medium"
:class="p.right_type === 'UC / สปสช.' ? 'bg-emerald-500/20 text-emerald-300' : 'bg-purple-500/20 text-purple-300'"
x-text="p.right_type">UC / สปสช.</span>
</td>
<td class="py-3.5 px-4">
<span class="text-xs" :class="p.contraindications ? 'text-red-400 font-medium' : 'text-subtle'"
x-text="p.contraindications || 'ไม่มีประวัติแพ้ยา'">ความดันโลหิตสูง</span>
</td>
<td class="py-3.5 px-4 text-right space-x-2">
<a :href="`/clinical/soap?patient_id=${p.id}`" class="px-3 py-1 rounded-lg bg-cyan-500/10 text-cyan-400 hover:bg-cyan-500 hover:text-white text-xs font-medium transition-all" title="ดูประวัติ SOAP">
<i class="bi bi-file-earmark-medical"></i> EMR
</a>
<button @click="editPatient(p)" class="p-1.5 rounded-lg text-subtle hover:text-amber-400 transition-colors" title="แก้ไข">
<i class="bi bi-pencil-square"></i>
</button>
</td>
</tr>
</template>
</tbody>
</table>
<div x-show="displayPatients.length === 0" class="text-center py-12 text-subtle">ไม่พบข้อมูลผู้ป่วยที่ค้นหา</div>
</div>
<!-- New / Edit Patient Modal -->
<div x-show="showModal" x-cloak class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div x-show="showModal" x-transition.opacity @click="showModal = false" class="fixed inset-0 bg-black/60 backdrop-blur-sm"></div>
<div x-show="showModal" x-transition class="relative w-full max-w-lg glass-modal p-6 rounded-3xl shadow-2xl border space-y-4">
<div class="flex justify-between items-center pb-3 border-b border-emerald-500/20">
<h3 class="font-bold text-lg" x-text="form.id ? 'แก้ไขข้อมูลผู้ป่วย' : 'ขึ้นทะเบียนผู้ป่วยใหม่'">ขึ้นทะเบียนผู้ป่วย</h3>
<button @click="showModal = false" class="text-subtle hover:text-white"><i class="bi bi-x-lg"></i></button>
</div>
<form @submit.prevent="savePatient()" class="space-y-4 text-sm">
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block mb-1 font-medium">เลขบัตรประชาชน 13 หลัก:</label>
<input type="text" x-model="form.cid" required maxlength="13" class="glass-input font-mono">
</div>
<div>
<label class="block mb-1 font-medium">เบอร์โทรศัพท์:</label>
<input type="text" x-model="form.phone" required class="glass-input font-mono">
</div>
</div>
<div class="grid grid-cols-2 gap-3">
<div>
<label class="block mb-1 font-medium">ชื่อจริง (ภาษาไทย):</label>
<input type="text" x-model="form.first_name_th" required class="glass-input">
</div>
<div>
<label class="block mb-1 font-medium">นามสกุล (ภาษาไทย):</label>
<input type="text" x-model="form.last_name_th" required class="glass-input">
</div>
</div>
<div class="grid grid-cols-3 gap-3">
<div>
<label class="block mb-1 font-medium">อายุ (ปี):</label>
<input type="number" x-model="form.age" required class="glass-input text-center">
</div>
<div>
<label class="block mb-1 font-medium">เพศ:</label>
<select x-model="form.gender" class="glass-input">
<option value="ชาย">ชาย</option>
<option value="หญิง">หญิง</option>
</select>
</div>
<div>
<label class="block mb-1 font-medium">สิทธิการรักษา:</label>
<select x-model="form.right_type" class="glass-input">
<option value="UC / สปสช.">UC / สปสช.</option>
<option value="ประกันสังคม">ประกันสังคม</option>
<option value="ข้าราชการ / สร้.">ข้าราชการ</option>
<option value="ชำระเงินเอง">ชำระเงินเอง</option>
</select>
</div>
</div>
<div>
<label class="block mb-1 font-medium text-red-400">โรคประจำตัว / ข้อห้ามในการนวด:</label>
<input type="text" x-model="form.contraindications" placeholder="เช่น ความดันสูง, ตั้งครรภ์ 3 เดือน, ลิ่มเลือดอุดตัน..." class="glass-input">
</div>
<div class="pt-3 border-t border-slate-700 flex justify-end gap-2">
<button type="button" @click="showModal = false" class="px-4 py-2 rounded-xl border border-slate-600 text-subtle">ยกเลิก</button>
<button type="submit" class="glass-btn-primary px-6 py-2 rounded-xl">บันทึกข้อมูล</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('patientApp', () => ({
searchQuery: '',
showModal: false,
patients: [
{ id: 1, hn: 'HN-2407001', cid: '1100000000001', first_name_th: 'สมชาย', last_name_th: 'รักสุขภาพ', age: 45, gender: 'ชาย', phone: '081-234-5678', right_type: 'UC / สปสช.', contraindications: 'ความดันโลหิตสูง (วัดความดันก่อนนวด)' },
{ id: 2, hn: 'HN-2407002', cid: '1100000000002', first_name_th: 'วิภาวี', last_name_th: 'ดีเลิศ', age: 38, gender: 'หญิง', phone: '089-876-5432', right_type: 'ข้าราชการ / สร้.', contraindications: null },
{ id: 3, hn: 'HN-2407003', cid: '1100000000003', first_name_th: 'อนันต์', last_name_th: 'มั่งคั่ง', age: 62, gender: 'ชาย', phone: '086-111-2222', right_type: 'ชำระเงินเอง', contraindications: 'หมอนรองกระดูกทับเส้นประสาท (ห้ามดัดรุนแรง)' },
{ id: 4, hn: 'HN-2407004', cid: '1100000000004', first_name_th: 'โสภิตา', last_name_th: 'เสน่ห์จันทร์', age: 29, gender: 'หญิง', phone: '082-333-4444', right_type: 'ประกันสังคม', contraindications: null }
],
displayPatients: [],
form: {},
init() {
this.displayPatients = [...this.patients];
},
filterPatients() {
if (!this.searchQuery) {
this.displayPatients = [...this.patients];
return;
}
const q = this.searchQuery.toLowerCase();
this.displayPatients = this.patients.filter(p =>
p.hn.toLowerCase().includes(q) ||
p.cid.includes(q) ||
`${p.first_name_th} ${p.last_name_th}`.toLowerCase().includes(q)
);
},
openNewModal() {
this.form = { id: null, hn: `HN-240700${this.patients.length + 1}`, cid: '', first_name_th: '', last_name_th: '', age: 35, gender: 'ชาย', phone: '', right_type: 'UC / สปสช.', contraindications: '' };
this.showModal = true;
},
editPatient(p) {
this.form = { ...p };
this.showModal = true;
},
savePatient() {
if (!this.form.id) {
this.form.id = this.patients.length + 1;
this.patients.unshift({ ...this.form });
} else {
const idx = this.patients.findIndex(x => x.id === this.form.id);
if (idx !== -1) this.patients[idx] = { ...this.form };
}
this.filterPatients();
this.showModal = false;
this.toast('บันทึกข้อมูลผู้ป่วยเรียบร้อยแล้ว', 'success');
}
}));
});
</script>