Sync OPD history flow and discharge UI refinements

This commit is contained in:
DevSoftTech Server 2026-06-11 19:30:02 +05:30
parent eefda96dca
commit cad5a477bf
6 changed files with 213 additions and 258 deletions

View File

@ -1364,7 +1364,7 @@ class Ipd_discharge extends BaseController
private function isNarrativeTemplateSectionAllowed(string $section): bool
{
return in_array($section, ['diagnosis_remark', 'course_remark'], true);
return in_array($section, ['diagnosis_remark', 'course_remark', 'instruction_other', 'instruction_remark'], true);
}
private function narrativeSectionTable(string $section): ?string

View File

@ -918,6 +918,16 @@ class Patient extends BaseController
return $this->response->setStatusCode(404)->setBody('Patient not found');
}
$request = service('request');
$backUrl = trim((string) $request->getGet('back_url'));
$backTitle = trim((string) $request->getGet('back_title'));
if ($backUrl === '') {
$backUrl = base_url('billing/patient/person_record') . '/' . $pno . '/0';
}
if ($backTitle === '') {
$backTitle = 'Profile';
}
$opdFields = $this->db->getFieldNames('opd_master') ?? [];
$opdSelect = [
'opd_id',
@ -1041,6 +1051,8 @@ class Patient extends BaseController
return view('billing/Patient_Profile_Opd_V', [
'patient' => $patient,
'opdGroups' => $opdGroups,
'backUrl' => $backUrl,
'backTitle' => $backTitle,
]);
}

View File

@ -1,3 +1,13 @@
<?php
$patient = $patient ?? (object) [];
$opdGroups = (isset($opdGroups) && is_array($opdGroups)) ? $opdGroups : [];
$backUrl = trim((string) ($backUrl ?? ''));
$backTitle = trim((string) ($backTitle ?? 'Profile'));
if ($backUrl === '') {
$backUrl = base_url('billing/patient/person_record') . '/' . (int) ($patient->id ?? 0) . '/0';
}
?>
<div class="pagetitle">
<h1>OPD History</h1>
<nav>
@ -10,97 +20,132 @@
<section class="section profile">
<div class="card">
<div class="card-header">
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
<h3 class="card-title mb-0">OPD History</h3>
<button type="button" class="btn btn-outline-secondary btn-sm"
onclick="load_form('<?= esc($backUrl, 'js') ?>','<?= esc($backTitle, 'js') ?>')">
Back
</button>
</div>
<div class="card-body">
<p class="mb-3">Patient: <strong><?= esc($patient->p_fname ?? '') ?></strong></p>
<style>
.opd-history-file-card {
border: 1px solid #dee2e6;
border-radius: .5rem;
overflow: hidden;
background: #fff;
height: 100%;
}
.opd-history-file-preview {
display: block;
width: 100%;
height: auto;
object-fit: contain;
cursor: zoom-in;
}
.opd-history-pdf-link {
display: flex;
align-items: center;
justify-content: center;
min-height: 260px;
text-align: center;
padding: 1rem;
background: #f8f9fa;
}
</style>
<?php if (empty($opdGroups)) { ?>
<div class="alert alert-info mb-0">No OPD scans found.</div>
<?php } else { ?>
<?php foreach ($opdGroups as $group) { ?>
<div class="border rounded p-3 mb-3">
<div class="d-flex flex-wrap justify-content-between">
<div>
<strong><?= esc($group['opd_code']) ?></strong>
<span class="text-muted ms-2">Dr. <?= esc($group['doc_name']) ?></span>
</div>
<div class="text-muted">
<?= esc($group['opd_date']) ?> <?= esc($group['queue_no']) ?>
</div>
</div>
<div class="mt-2">
<?php if ((int) ($group['rx_session_id'] ?? 0) > 0) { ?>
<a class="btn btn-primary btn-sm" target="_blank"
href="<?= base_url('Opd_prescription/opd_prescription_print/' . (int) $group['opd_id'] . '/' . (int) $group['rx_session_id']) ?>">
Prescription Print
</a>
<?php } ?>
<?php if (!empty($group['bp']) || !empty($group['diastolic']) || !empty($group['pulse']) || !empty($group['temp']) || !empty($group['spo2'])) { ?>
<div class="small text-muted mt-2">
<?php if (!empty($group['bp'])) { ?><span class="me-3"><strong>BP:</strong> <?= esc($group['bp']) ?></span><?php } ?>
<?php if (!empty($group['diastolic'])) { ?><span class="me-3"><strong>Diastolic:</strong> <?= esc($group['diastolic']) ?></span><?php } ?>
<?php if (!empty($group['pulse'])) { ?><span class="me-3"><strong>Pulse:</strong> <?= esc($group['pulse']) ?></span><?php } ?>
<?php if (!empty($group['temp'])) { ?><span class="me-3"><strong>Temp:</strong> <?= esc($group['temp']) ?></span><?php } ?>
<?php if (!empty($group['spo2'])) { ?><span class="me-3"><strong>SPO2:</strong> <?= esc($group['spo2']) ?></span><?php } ?>
<div class="row g-3 align-items-start">
<div class="col-12 col-xl-4">
<div class="d-flex flex-wrap justify-content-between align-items-start gap-2">
<div>
<strong><?= esc($group['opd_code']) ?></strong>
<span class="text-muted ms-2">Dr. <?= esc($group['doc_name']) ?></span>
</div>
<div class="text-muted text-end">
<?= esc($group['opd_date']) ?> <?= esc($group['queue_no']) ?>
</div>
</div>
<?php } ?>
<?php if (!empty($group['complaints']) || !empty($group['diagnosis']) || !empty($group['investigation']) || !empty($group['advice'])) { ?>
<div class="row g-2 mt-2">
<?php if (!empty($group['complaints'])) { ?>
<div class="col-12 col-lg-6">
<div class="mt-2 d-flex flex-wrap gap-2">
<?php if ((int) ($group['rx_session_id'] ?? 0) > 0) { ?>
<a class="btn btn-primary btn-sm" target="_blank"
href="<?= base_url('Opd_prescription/opd_prescription_print/' . (int) $group['opd_id'] . '/' . (int) $group['rx_session_id']) ?>">
Prescription Print
</a>
<?php } ?>
</div>
<?php if (!empty($group['bp']) || !empty($group['diastolic']) || !empty($group['pulse']) || !empty($group['temp']) || !empty($group['spo2'])) { ?>
<div class="small text-muted d-flex flex-wrap gap-3 mt-2">
<?php if (!empty($group['bp'])) { ?><span><strong>BP:</strong> <?= esc($group['bp']) ?></span><?php } ?>
<?php if (!empty($group['diastolic'])) { ?><span><strong>Diastolic:</strong> <?= esc($group['diastolic']) ?></span><?php } ?>
<?php if (!empty($group['pulse'])) { ?><span><strong>Pulse:</strong> <?= esc($group['pulse']) ?></span><?php } ?>
<?php if (!empty($group['temp'])) { ?><span><strong>Temp:</strong> <?= esc($group['temp']) ?></span><?php } ?>
<?php if (!empty($group['spo2'])) { ?><span><strong>SPO2:</strong> <?= esc($group['spo2']) ?></span><?php } ?>
</div>
<?php } ?>
<?php if (!empty($group['complaints']) || !empty($group['diagnosis']) || !empty($group['investigation']) || !empty($group['advice'])) { ?>
<div class="d-grid gap-2 mt-2">
<?php if (!empty($group['complaints'])) { ?>
<div class="border rounded p-2 bg-light small">
<strong>Complaints:</strong> <?= esc($group['complaints']) ?>
</div>
</div>
<?php } ?>
<?php if (!empty($group['diagnosis'])) { ?>
<div class="col-12 col-lg-6">
<?php } ?>
<?php if (!empty($group['diagnosis'])) { ?>
<div class="border rounded p-2 bg-light small">
<strong>Diagnosis:</strong> <?= esc($group['diagnosis']) ?>
</div>
</div>
<?php } ?>
<?php if (!empty($group['investigation'])) { ?>
<div class="col-12 col-lg-6">
<?php } ?>
<?php if (!empty($group['investigation'])) { ?>
<div class="border rounded p-2 bg-light small">
<strong>Investigation:</strong> <?= esc($group['investigation']) ?>
</div>
</div>
<?php } ?>
<?php if (!empty($group['advice'])) { ?>
<div class="col-12 col-lg-6">
<?php } ?>
<?php if (!empty($group['advice'])) { ?>
<div class="border rounded p-2 bg-light small">
<strong>Advice:</strong> <?= esc($group['advice']) ?>
</div>
</div>
<?php } ?>
</div>
<?php } ?>
</div>
<?php if (empty($group['files'])) { ?>
<div class="text-muted mt-2">No scanned files for this OPD.</div>
<?php } else { ?>
<div class="small fw-semibold mt-3 mb-1">Scanned Files</div>
<div class="row g-2 mt-2">
<?php foreach ($group['files'] as $index => $file) { ?>
<div class="col-6 col-md-3">
<?php if ($file['isPdf']) { ?>
<a class="btn btn-outline-secondary btn-sm w-100" href="<?= esc($file['path']) ?>" target="_blank">Open PDF</a>
<?php } else { ?>
<img src="<?= esc($file['path']) ?>" class="img-fluid rounded border opd-thumb"
data-bs-toggle="modal" data-bs-target="#opdScanModal"
data-src="<?= esc($file['path']) ?>" alt="OPD Scan">
<?php } ?>
</div>
<?php } ?>
</div>
<?php } ?>
<div class="col-12 col-xl-8">
<?php if (empty($group['files'])) { ?>
<div class="text-muted mt-2">No scanned files for this OPD.</div>
<?php } else { ?>
<div class="small fw-semibold mb-2">Scanned Files</div>
<div class="row g-3">
<?php foreach ($group['files'] as $index => $file) { ?>
<div class="col-12">
<div class="opd-history-file-card">
<?php if ($file['isPdf']) { ?>
<a class="opd-history-pdf-link" href="<?= esc($file['path']) ?>" target="_blank">
<span>
<strong>Open PDF</strong><br>
<span class="text-muted small">Tap to view the full document</span>
</span>
</a>
<?php } else { ?>
<img src="<?= esc($file['path']) ?>" class="opd-history-file-preview w-100"
data-bs-toggle="modal" data-bs-target="#opdScanModal"
data-src="<?= esc($file['path']) ?>" alt="OPD Scan">
<?php } ?>
</div>
</div>
<?php } ?>
</div>
<?php } ?>
</div>
</div>
</div>
<?php } ?>
<?php } ?>

View File

@ -35,7 +35,8 @@
<div class="d-flex gap-2 flex-wrap justify-content-center">
<button type="button" class="btn btn-danger btn-sm" onclick="load_form('<?= base_url('billing/patient/person_record') ?>/<?=$data[0]->id?>/1');">Profile Edit</button>
<button type="button" class="btn btn-success btn-sm" onclick="load_form('<?= base_url('billing/patient/show_profile_image') ?>/<?=$data[0]->id?>/1');">Edit Picture</button>
<button type="button" class="btn btn-info btn-sm" onclick="load_form('<?= base_url('billing/patient/show_profile_opd') ?>/<?=$data[0]->id?>/1');">Consult History</button>
<?php $consultHistoryBackUrl = base_url('billing/patient/person_record') . '/' . (int) ($data[0]->id ?? 0) . '/0'; ?>
<button type="button" class="btn btn-info btn-sm" onclick="load_form('<?= base_url('billing/patient/show_profile_opd') ?>/<?= (int) ($data[0]->id ?? 0) ?>/1?<?= http_build_query(['back_url' => $consultHistoryBackUrl, 'back_title' => 'Profile']) ?>');">Consult History</button>
</div>
<div class="mt-3 w-100">
<div class="d-grid gap-2">

View File

@ -389,105 +389,25 @@ $historyFields = [
border-color: var(--dc-border);
}
@media (min-width: 768px) {
.discharge-left-col {
flex: 0 0 25%;
max-width: 25%;
}
.discharge-right-col {
flex: 0 0 75%;
max-width: 75%;
}
}
.discharge-form-area form>.card:first-child {
margin-top: 0;
}
.discharge-form-area .card-header {
font-size: 14px;
background: var(--dc-muted-bg);
}
.discharge-form-area .card-body {
padding: 0.95rem;
}
.discharge-page .btn {
border-radius: 0.45rem;
font-weight: 500;
letter-spacing: 0.01em;
}
.discharge-page .btn-sm {
padding: 0.34rem 0.68rem;
font-size: 0.79rem;
line-height: 1.25;
}
.discharge-page .btn-outline-primary {
color: #4154f1;
border-color: #c7d2fe;
background: #f8f9ff;
}
.discharge-page .btn-outline-primary:hover,
.discharge-page .btn-outline-primary:focus {
color: #fff;
background: #4154f1;
border-color: #4154f1;
}
.discharge-page .btn-outline-success {
color: #198754;
border-color: #bfe5d3;
background: #f6fcf9;
}
.discharge-page .btn-outline-success:hover,
.discharge-page .btn-outline-success:focus {
color: #fff;
background: #198754;
border-color: #198754;
}
.discharge-page .btn-outline-info {
color: #0dcaf0;
border-color: #bdeaf4;
background: #f5fdff;
}
.discharge-page .btn-outline-info:hover,
.discharge-page .btn-outline-info:focus {
color: #fff;
background: #0aa2c0;
border-color: #0aa2c0;
}
.discharge-page .btn-outline-warning {
color: #b45309;
border-color: #f4d6a6;
background: #fffaf1;
}
.discharge-page .btn-outline-warning:hover,
.discharge-page .btn-outline-warning:focus {
color: #fff;
background: #d97706;
border-color: #d97706;
}
.discharge-page .btn-outline-danger {
color: #dc3545;
border-color: #f2c4c9;
background: #fff8f8;
}
.discharge-page .btn-outline-danger:hover,
.discharge-page .btn-outline-danger:focus {
color: #fff;
background: #dc3545;
border-color: #dc3545;
}
.discharge-form-area .form-label {
font-size: 13px;
margin-bottom: 4px;
}
.discharge-form-area table th,
.discharge-form-area table td {
vertical-align: middle;
font-size: 13px;
}
.discharge-page .table {
@ -612,7 +532,10 @@ $historyFields = [
/ IPD ID : <strong><?= esc((string) ($ipd->ipd_code ?? '')) ?></strong>
</div>
<div class="mb-3 text-end">
<div class="mb-3 text-end d-flex justify-content-end gap-2">
<button type="button" class="btn btn-outline-primary" id="btn_print_top" onclick="window.open('<?= site_url('Ipd_discharge/show_discharge/' . $ipdId . '/1') ?>', '_blank');">
<i class="fas fa-print me-1"></i> Print Discharge Summary
</button>
<button type="button" class="btn btn-primary" id="btn_preview_top" onclick="openDischargePreview('<?= site_url('Ipd_discharge/preview_discharge_report/' . $ipdId . '?regen=1') ?>', 'Discharge Preview');">
<i class="fas fa-eye me-1"></i> Preview Discharge Summary
</button>
@ -625,7 +548,7 @@ $historyFields = [
<?php endif; ?>
<div class="row">
<div class="col-md-3">
<div class="col-md-3 discharge-left-col">
<div class="discharge-side-panel">
<ul class="nav flex-column nav-pills" id="discharge_section_nav" role="tablist" aria-orientation="vertical">
<li class="nav-item"><a href="#section-complaints" class="nav-link discharge-nav-link active" data-target="section-complaints">Presenting Complaints with Duration and Reason for Admission</a></li>
@ -641,13 +564,10 @@ $historyFields = [
<li class="nav-item"><a href="#section-instructions" class="nav-link discharge-nav-link" data-target="section-instructions">Discharge Summary</a></li>
</ul>
<div class="discharge-side-actions">
<button type="button" class="btn btn-primary btn-sm" id="btn_preview_side" onclick="openDischargePreview('<?= site_url('Ipd_discharge/preview_discharge_report/' . $ipdId . '?regen=1') ?>', 'Discharge Preview');">Preview</button>
</div>
</div>
</div>
<div class="col-md-9 discharge-form-area">
<div class="col-md-9 discharge-form-area discharge-right-col">
<form id="discharge_main_form" method="post" action="<?= site_url('Ipd_discharge/ipd_select/' . $ipdId) ?>" class="row g-3">
<?= csrf_field() ?>
@ -791,8 +711,8 @@ $historyFields = [
<input type="hidden" name="complaint_remove_id" id="complaint_remove_id" value="0">
<!-- Healthplix-style inline complaint table (OPD-like) -->
<table class="table table-sm table-bordered align-middle mb-1" id="discharge_complaint_table" style="font-size:.82rem">
<thead class="table-light" style="font-size:.75rem">
<table class="table table-sm table-bordered align-middle mb-1" id="discharge_complaint_table">
<thead class="table-light">
<tr>
<th style="width:28px">#</th>
<th>Complaint</th>
@ -810,7 +730,7 @@ $historyFields = [
<td></td>
<td colspan="4" class="p-1 position-relative">
<input type="text" class="form-control form-control-sm" id="discharge_complaint_lookup"
autocomplete="off" placeholder="fever , cough , headache..." style="font-size:.82rem">
autocomplete="off" placeholder="fever , cough , headache...">
<div id="discharge_complaint_dropdown" class="border rounded bg-white shadow-sm"
style="display:none;position:absolute;left:0;right:0;top:100%;z-index:1060;max-height:260px;overflow-y:auto;"></div>
</td>
@ -1167,8 +1087,6 @@ $historyFields = [
<div class="mt-3">
<label class="form-label">Final Diagnosis (Narrative)
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_discharge_ai_diagnosis">AI Assist</button>
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_discharge_hinglish_diagnosis">Hinglish -> English</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-field-past" data-section="diagnosis_remark" data-target="diagnosis_remark">Past Data</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-load" data-section="diagnosis_remark" data-target="diagnosis_remark">Load Template</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-save" data-section="diagnosis_remark" data-target="diagnosis_remark">Save as Template</button>
@ -1238,8 +1156,6 @@ $historyFields = [
<div class="mt-3">
<label class="form-label">Course / Treatment in Hospital (Narrative)
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_discharge_ai_course">AI Assist</button>
<button type="button" class="btn btn-outline-primary btn-sm" id="btn_discharge_hinglish_course">Hinglish -> English</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-field-past" data-section="course_remark" data-target="course_remark">Past Data</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-load" data-section="course_remark" data-target="course_remark">Load Template</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-save" data-section="course_remark" data-target="course_remark">Save as Template</button>
@ -1288,7 +1204,7 @@ $historyFields = [
<div class="row g-3">
<!-- Medicine List Table -->
<div class="col-md-7">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead>
@ -1331,7 +1247,7 @@ $historyFields = [
</div>
<!-- Add Medicine Form -->
<div class="col-md-5">
<div class="col-md-12">
<div class="card border">
<div class="card-header py-2 bg-light d-flex justify-content-between align-items-center">
<strong>Prescribed:</strong>
@ -1342,8 +1258,8 @@ $historyFields = [
<div class="card-body">
<input type="hidden" id="discharge_med_item_id" value="0">
<input type="hidden" id="discharge_med_id" value="0">
<div class="mb-2">
<div class="row g-2 mb-2">
<div class="col-8">
<label class="form-label small">Medicine Name (Brand)</label>
<input type="text" id="discharge_med_name" list="discharge_med_suggest" class="form-control form-control-sm" placeholder="Type medicine name" autocomplete="off">
<datalist id="discharge_med_suggest"></datalist>
@ -1356,11 +1272,11 @@ $historyFields = [
<div id="discharge_substitute_rows" style="max-height:200px;overflow-y:auto;"></div>
</div>
<div class="mb-2">
<div class="col-4">
<label class="form-label small">Type</label>
<input type="text" id="discharge_med_type" class="form-control form-control-sm" placeholder="TAB,CAP,SYR,INJ">
</div>
</div>
<div class="row g-2 mb-2">
<div class="col-4">
<label class="form-label small">Dose:</label>
@ -1414,14 +1330,12 @@ $historyFields = [
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_when" data-fill-value="BF">Before Food</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_when" data-fill-value="AF">After Food</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_when" data-fill-value="WF">With Food</button>
</div>
<div class="mb-2">
&nbsp;
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_freq" data-fill-value="OD">OD</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_freq" data-fill-value="BD">BD</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_freq" data-fill-value="TDS">TDS</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_dosage_freq" data-fill-value="HS">HS</button>
</div>
<div class="mb-2">
&nbsp;
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_no_of_days" data-fill-value="3 Days">3 Days</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_no_of_days" data-fill-value="5 Days">5 Days</button>
<button type="button" class="btn btn-outline-secondary btn-sm discharge-quick-btn" data-fill-target="discharge_no_of_days" data-fill-value="7 Days">7 Days</button>
@ -1489,13 +1403,21 @@ $historyFields = [
</div>
<div class="col-md-12">
<label class="form-label">Other Advice</label>
<label class="form-label">Other Advice
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-load" data-section="instruction_other" data-target="instruction_other">Load Template</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-save" data-section="instruction_other" data-target="instruction_other">Save as Template</button>
</label>
<textarea class="form-control" name="instruction_other" id="instruction_other" rows="2" placeholder="Additional custom advice..."><?= esc($instructionOther) ?></textarea>
<div id="discharge_instruction_other_status" class="complaint-status text-muted"></div>
</div>
<div class="col-md-12">
<label class="form-label">Discharge Summary</label>
<label class="form-label">Discharge Summary
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-load" data-section="instruction_remark" data-target="instruction_remark">Load Template</button>
<button type="button" class="btn btn-outline-secondary btn-sm btn-discharge-template-save" data-section="instruction_remark" data-target="instruction_remark">Save as Template</button>
</label>
<textarea class="form-control" name="instruction_remark" id="instruction_remark" rows="3"><?= esc((string) ($instruction_remark ?? '')) ?></textarea>
<div id="discharge_instruction_remark_status" class="complaint-status text-muted"></div>
</div>
<div class="col-md-6">
<label class="form-label">Review After (days/text)</label>
@ -2075,7 +1997,6 @@ $historyFields = [
removeBtn.type = 'button';
removeBtn.className = 'btn btn-sm text-danger p-0';
removeBtn.style.lineHeight = '1';
removeBtn.style.fontSize = '.9rem';
removeBtn.innerHTML = '×';
removeBtn.addEventListener('click', function() {
selectedDischargeComplaints.splice(idx, 1);
@ -2439,7 +2360,7 @@ $historyFields = [
codeDisplay = '<span class="badge bg-secondary">' + icd + '</span>';
}
html += '<div class="dropdown-item px-2 py-2" data-id="' + (row.id || 0) + '" data-name="' + name.replace(/"/g, '&quot;') + '" style="cursor:pointer;font-size:.9rem;border-bottom:1px solid #f0f0f0;">';
html += '<div class="dropdown-item px-2 py-2" data-id="' + (row.id || 0) + '" data-name="' + name.replace(/"/g, '&quot;') + '" style="cursor:pointer;border-bottom:1px solid #f0f0f0;">';
html += '<div class="fw-semibold">' + name + '</div>';
if (codeDisplay) {
html += '<div class="small mt-1">' + codeDisplay + '</div>';
@ -2546,6 +2467,12 @@ $historyFields = [
if (section === 'course_remark') {
return 'discharge_course_status';
}
if (section === 'instruction_other') {
return 'discharge_instruction_other_status';
}
if (section === 'instruction_remark') {
return 'discharge_instruction_remark_status';
}
return '';
}
@ -2557,6 +2484,32 @@ $historyFields = [
}
}
function getNarrativeFieldText(target) {
if (!target) {
return '';
}
if (window.CKEDITOR && CKEDITOR.instances && CKEDITOR.instances[target]) {
return (CKEDITOR.instances[target].getData() || '').toString();
}
return ($('#' + target).val() || '').toString();
}
function setNarrativeFieldText(target, value) {
if (!target) {
return;
}
var textValue = (value || '').toString();
if (window.CKEDITOR && CKEDITOR.instances && CKEDITOR.instances[target]) {
CKEDITOR.instances[target].setData(textValue);
return;
}
$('#' + target).val(textValue);
}
// Course/Treatment autocomplete with SNOMED/ICD code display
function initCourseAutocomplete() {
var input = document.getElementById('new_course_name');
@ -2603,7 +2556,7 @@ $historyFields = [
codeDisplay = '<span class="badge bg-secondary">' + icd + '</span>';
}
html += '<div class="dropdown-item px-2 py-2" data-id="' + (row.id || 0) + '" data-name="' + name.replace(/"/g, '&quot;') + '" style="cursor:pointer;font-size:.9rem;border-bottom:1px solid #f0f0f0;">';
html += '<div class="dropdown-item px-2 py-2" data-id="' + (row.id || 0) + '" data-name="' + name.replace(/"/g, '&quot;') + '" style="cursor:pointer;border-bottom:1px solid #f0f0f0;">';
html += '<div class="fw-semibold">' + name + '</div>';
if (codeDisplay) {
html += '<div class="small mt-1">' + codeDisplay + '</div>';
@ -2768,7 +2721,7 @@ $historyFields = [
return;
}
$('#' + target).val((data && data.past_text) ? data.past_text : '');
setNarrativeFieldText(target, (data && data.past_text) ? data.past_text : '');
setNarrativeStatus(section, (data && data.error_text) ? data.error_text : 'Past data loaded.', 'success');
}, 'json').fail(function() {
setNarrativeStatus(section, 'Unable to load past data right now.', 'error');
@ -2782,7 +2735,7 @@ $historyFields = [
return;
}
var text = ($('#' + target).val() || '').toString().trim();
var text = getNarrativeFieldText(target).trim();
if (!text) {
setNarrativeStatus(section, 'Type text first, then save as template.', 'error');
return;
@ -2877,7 +2830,7 @@ $historyFields = [
$sel.append('<option value="' + idx + '">' + $('<div>').text(src + name).html() + '</option>');
});
var existingText = ($('#' + target).val() || '').toString().trim();
var existingText = getNarrativeFieldText(target).trim();
$('#ipd_narrative_apply_mode').val(existingText ? 'append' : 'replace');
$('#ipd_narrative_template_preview').val((rows[0] && rows[0].template_text) ? rows[0].template_text : '');
@ -2905,8 +2858,7 @@ $historyFields = [
var mode = ($('#ipd_narrative_apply_mode').val() || 'replace').toString();
var selectedText = (row.template_text || '').toString().trim();
var $target = $('#' + target);
var currentText = ($target.val() || '').toString().trim();
var currentText = getNarrativeFieldText(target).trim();
var finalText = selectedText;
if (mode === 'append' && currentText !== '') {
@ -2917,7 +2869,7 @@ $historyFields = [
}
}
$target.val(finalText);
setNarrativeFieldText(target, finalText);
setNarrativeStatus(section, mode === 'append' ? 'Template appended.' : 'Template loaded.', 'success');
hideModalById('ipdNarrativeTemplateModal');
});
@ -3446,52 +3398,6 @@ $historyFields = [
}
}
function bindAiRewrite(form, btnId, sourceId, mode, statusId, emptyMsg) {
var btn = document.getElementById(btnId);
var source = document.getElementById(sourceId);
if (!btn || !source) {
return;
}
btn.addEventListener('click', function() {
var text = (source.value || '').trim();
if (text === '') {
setSectionStatus(statusId, emptyMsg || 'Type text first.', 'error');
return;
}
if (!window.jQuery) {
return;
}
var csrf = getCsrfPair(form);
var payload = {
text: text,
mode: mode
};
payload[csrf.name] = csrf.value;
$.post('<?= base_url('Opd_prescription/clinical_autotype') ?>', payload, function(data) {
if (data && data.csrfName && data.csrfHash) {
var csrfInput = form.querySelector('input[name="' + data.csrfName + '"]');
if (csrfInput) {
csrfInput.value = data.csrfHash;
}
}
if (!data || parseInt(data.update || '0', 10) !== 1) {
setSectionStatus(statusId, (data && data.error_text) ? data.error_text : 'Unable to process AI text.', 'error');
return;
}
source.value = (data.draft_text || text);
setSectionStatus(statusId, (data.error_text || 'AI text ready.'), 'success');
}, 'json').fail(function() {
setSectionStatus(statusId, 'AI request failed.', 'error');
});
});
}
function initDiagnosisTools() {
var section = document.getElementById('section-diagnosis');
if (!section || section.dataset.toolsBound === '1') {
@ -3505,9 +3411,6 @@ $historyFields = [
}
bindDiagnosisIcdLookup(form);
bindAiRewrite(form, 'btn_discharge_ai_diagnosis', 'diagnosis_remark', 'diagnosis', 'discharge_diagnosis_status', 'Type diagnosis narrative first.');
bindAiRewrite(form, 'btn_discharge_hinglish_diagnosis', 'diagnosis_remark', 'hinglish_to_english', 'discharge_diagnosis_status', 'Type diagnosis narrative first.');
}
function initCourseTools() {
@ -3529,9 +3432,6 @@ $historyFields = [
'discharge_course_status',
'Custom term ready. Click +ADD to save row.'
);
bindAiRewrite(form, 'btn_discharge_ai_course', 'course_remark', 'autotype', 'discharge_course_status', 'Type course narrative first.');
bindAiRewrite(form, 'btn_discharge_hinglish_course', 'course_remark', 'hinglish_to_english', 'discharge_course_status', 'Type course narrative first.');
}
function initInstructionTools() {

View File

@ -73,13 +73,11 @@
margin-top: .4rem;
}
.rx-counter {
font-size: .8rem;
color: #6c757d;
text-align: right;
margin-top: .25rem;
}
.rx-save-status {
font-size: .875rem;
display: flex;
align-items: center;
gap: .4rem;
@ -173,7 +171,6 @@
font-weight: 600;
color: #334155;
margin: 0;
font-size: .88rem;
letter-spacing: .01em;
}
.rx-foldable .rx-fold-body {
@ -482,13 +479,13 @@
<div id="rx_scan_banner" class="rx-scan-banner"></div>
<div class="row g-3 rx-two-panel">
<div class="col-lg-4 rx-left-panel">
<div class="col-lg-3 rx-left-panel">
<div class="rx-meta-box mb-3">
<div class="row g-2 align-items-start">
<div class="col-8">
<div class="rx-meta-line"><strong>Patient Name:</strong> <span style="font-size:1.18rem;font-weight:700;color:#0b3b91;"><?= esc($patientName !== '' ? $patientName : '-') ?></span></div>
<div class="rx-meta-line"><strong>Patient Name:</strong> <span class="fw-bold text-primary"><?= esc($patientName !== '' ? $patientName : '-') ?></span></div>
<?php if ($relationLabel !== '') { ?>
<div class="rx-meta-line" style="font-size:0.88rem;font-weight:400;color:#374151;margin-top:1px;"><?= esc($relationLabel) ?></div>
<div class="rx-meta-line text-body-secondary"><?= esc($relationLabel) ?></div>
<?php } ?>
<div class="rx-meta-line"><strong>UHID:</strong> <?= esc($patient_master[0]->p_code ?? '') ?></div>
<div class="rx-meta-line"><strong>Age:</strong> <?= esc($patient_master[0]->str_age ?? '') ?></div>
@ -607,7 +604,7 @@
</div>
</div>
<div class="col-lg-8 rx-right-panel">
<div class="col-lg-9 rx-right-panel">
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center flex-wrap gap-2">
<div>
@ -853,14 +850,14 @@
<div class="mb-3" id="rx_sec_complaints">
<div class="d-flex align-items-center justify-content-between mb-2">
<h6 class="mb-0">Chief Complaints</h6>
<button type="button" class="btn btn-sm btn-outline-secondary btn-save-autotype-keyword"
<button type="button" class="btn btn-sm btn-outline-secondary btn-save-autotype-keyword"
data-section="complaints" data-target="complaints"
style="font-size:.75rem" title="Save as custom keyword">+keyword</button>
title="Save as custom keyword">+keyword</button>
</div>
<!-- Healthplix-style inline complaint table -->
<table class="table table-sm table-bordered align-middle mb-1" id="complaint_table" style="font-size:.82rem">
<thead class="table-light" style="font-size:.75rem">
<table class="table table-sm table-bordered align-middle mb-1" id="complaint_table">
<thead class="table-light">
<tr>
<th style="width:28px">#</th>
<th>Complaint</th>
@ -918,14 +915,14 @@
<div class="mb-3" id="rx_sec_diagnosis">
<div class="d-flex align-items-center justify-content-between mb-2">
<h6 class="mb-0">Diagnosis</h6>
<button type="button" class="btn btn-sm btn-outline-secondary btn-save-autotype-keyword"
<button type="button" class="btn btn-sm btn-outline-secondary btn-save-autotype-keyword"
data-section="diagnosis" data-target="diagnosis"
style="font-size:.75rem" title="Save as custom keyword">+keyword</button>
title="Save as custom keyword">+keyword</button>
</div>
<!-- Healthplix-style inline diagnosis table -->
<table class="table table-sm table-bordered align-middle mb-1" id="diagnosis_table" style="font-size:.82rem">
<thead class="table-light" style="font-size:.75rem">
<table class="table table-sm table-bordered align-middle mb-1" id="diagnosis_table">
<thead class="table-light">
<tr>
<th style="width:28px">#</th>
<th>Diagnosis</th>