Improve doctor document workflow and print performance
This commit is contained in:
parent
b20d5b3ae8
commit
3c4dff6285
|
|
@ -605,6 +605,7 @@ $routes->post('Opd_prescription/section_template_track_usage', 'Opd_prescription
|
|||
$routes->get('Opd_prescription/section_template_list', 'Opd_prescription::section_template_list');
|
||||
$routes->get('Opd_prescription/section_past_data', 'Opd_prescription::section_past_data');
|
||||
$routes->get('Opd_prescription/template_workspace', 'Opd_prescription::template_workspace', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
|
||||
$routes->get('doctor_work/patient_search', 'DoctorDocument::patient_search', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
|
||||
$routes->get('doctor_work/document_workspace', 'DoctorDocument::workspace', ['filter' => 'permission:doctor_work.template_workspace.access,doctor_work.access']);
|
||||
|
||||
// Legacy-compatible doctor document templates and issue flow.
|
||||
|
|
|
|||
|
|
@ -148,8 +148,15 @@ class DoctorDocument extends BaseController
|
|||
|
||||
$logoFile = defined('H_logo') ? (string) constant('H_logo') : 'logo.png';
|
||||
$logoAbsPath = FCPATH . 'assets/images/' . $logoFile;
|
||||
$logoSrc = $this->buildImageDataUriFromPath($logoAbsPath);
|
||||
if ($logoSrc === '' && is_file($logoAbsPath)) {
|
||||
$logoSrc = str_replace('\\', '/', $logoAbsPath);
|
||||
}
|
||||
if ($logoSrc === '') {
|
||||
$logoSrc = base_url('assets/images/' . $logoFile);
|
||||
}
|
||||
$logoHtml = '<img style="width:100px;vertical-align:top;" src="'
|
||||
. base_url('assets/images/' . $logoFile) . '" />';
|
||||
. $logoSrc . '" />';
|
||||
|
||||
$age = (string) ($doc['age'] ?? '');
|
||||
$gender = (string) ($doc['gender'] ?? '');
|
||||
|
|
@ -158,7 +165,16 @@ class DoctorDocument extends BaseController
|
|||
$drSignImg = '';
|
||||
$drSignFile = (string) ($doc['dr_sign'] ?? $doc['sign_image'] ?? $doc['doctor_sign'] ?? '');
|
||||
if ($drSignFile !== '') {
|
||||
$drSignImg = '<img style="height:40px;" src="' . base_url('assets/images/' . $drSignFile) . '" />';
|
||||
$drSignAbsPath = FCPATH . 'assets/images/' . ltrim($drSignFile, '/\\');
|
||||
$drSignSrc = $this->buildImageDataUriFromPath($drSignAbsPath);
|
||||
if ($drSignSrc === '' && is_file($drSignAbsPath)) {
|
||||
$drSignSrc = str_replace('\\', '/', $drSignAbsPath);
|
||||
}
|
||||
if ($drSignSrc === '') {
|
||||
$drSignSrc = base_url('assets/images/' . $drSignFile);
|
||||
}
|
||||
|
||||
$drSignImg = '<img style="height:40px;" src="' . $drSignSrc . '" />';
|
||||
}
|
||||
|
||||
$map = [
|
||||
|
|
@ -187,6 +203,29 @@ class DoctorDocument extends BaseController
|
|||
return str_replace(array_keys($map), array_values($map), $html);
|
||||
}
|
||||
|
||||
private function buildImageDataUriFromPath(string $absolutePath): string
|
||||
{
|
||||
$absolutePath = trim($absolutePath);
|
||||
if ($absolutePath === '' || ! is_file($absolutePath) || ! is_readable($absolutePath)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$bytes = @file_get_contents($absolutePath);
|
||||
if ($bytes === false || $bytes === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$mime = 'image/png';
|
||||
if (function_exists('mime_content_type')) {
|
||||
$detected = @mime_content_type($absolutePath);
|
||||
if (is_string($detected) && str_starts_with($detected, 'image/')) {
|
||||
$mime = $detected;
|
||||
}
|
||||
}
|
||||
|
||||
return 'data:' . $mime . ';base64,' . base64_encode($bytes);
|
||||
}
|
||||
|
||||
private function hasColumn(string $table, string $column): bool
|
||||
{
|
||||
if (! $this->db->tableExists($table)) {
|
||||
|
|
@ -226,6 +265,128 @@ class DoctorDocument extends BaseController
|
|||
return view('doctor_document/workspace');
|
||||
}
|
||||
|
||||
public function patient_search()
|
||||
{
|
||||
if ($resp = $this->ensureAccess()) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$search = trim((string) $this->request->getGet('q'));
|
||||
$patients = $this->searchDoctorWorkPatients($search);
|
||||
$countsByPatient = $this->getDoctorWorkPatientCounts(array_map(static fn(array $row): int => (int) ($row['id'] ?? 0), $patients));
|
||||
|
||||
foreach ($patients as &$patientRow) {
|
||||
$patientId = (int) ($patientRow['id'] ?? 0);
|
||||
$patientCounts = $countsByPatient[$patientId] ?? [];
|
||||
$patientRow['opd_count'] = (int) ($patientCounts['opd_count'] ?? 0);
|
||||
$patientRow['lab_count'] = (int) ($patientCounts['lab_count'] ?? 0);
|
||||
$patientRow['ipd_count'] = (int) ($patientCounts['ipd_count'] ?? 0);
|
||||
}
|
||||
unset($patientRow);
|
||||
|
||||
return view('doctor_document/patient_search', [
|
||||
'search' => $search,
|
||||
'patients' => $patients,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array<string, mixed>>
|
||||
*/
|
||||
private function searchDoctorWorkPatients(string $search): array
|
||||
{
|
||||
$search = preg_replace('/[^A-Za-z0-9 _.@\-]/', '', trim($search)) ?? '';
|
||||
|
||||
if ($search === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$searchTokens = preg_split('/\s+/', $search) ?: [];
|
||||
$whereParts = ['1=1'];
|
||||
|
||||
foreach ($searchTokens as $token) {
|
||||
$token = trim((string) $token);
|
||||
if ($token === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$escaped = $this->db->escape($token);
|
||||
$likeToken = $this->db->escapeLikeString($token);
|
||||
|
||||
if (is_numeric($token)) {
|
||||
$whereParts[] = "(p.p_code LIKE '%{$likeToken}' ESCAPE '!' OR p.mphone1 = {$escaped} OR p.udai = {$escaped})";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctype_alpha($token)) {
|
||||
$whereParts[] = "(p.p_fname LIKE '%{$likeToken}%' ESCAPE '!' OR p.email1 = {$escaped})";
|
||||
continue;
|
||||
}
|
||||
|
||||
$whereParts[] = "(p.p_code LIKE '{$likeToken}' ESCAPE '!' OR p.email1 = {$escaped})";
|
||||
}
|
||||
|
||||
$sql = "SELECT p.*, DATE_FORMAT(p.last_visit,'%d-%m-%Y') AS Last_Visit
|
||||
FROM patient_master p
|
||||
WHERE " . implode(' AND ', $whereParts) . "
|
||||
GROUP BY p.id
|
||||
ORDER BY p.last_visit DESC
|
||||
LIMIT 100";
|
||||
|
||||
return $this->db->query($sql)->getResultArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $patientIds
|
||||
* @return array<int, array<string, int>>
|
||||
*/
|
||||
private function getDoctorWorkPatientCounts(array $patientIds): array
|
||||
{
|
||||
$patientIds = array_values(array_unique(array_filter(array_map('intval', $patientIds), static fn(int $id): bool => $id > 0)));
|
||||
if ($patientIds === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$countsByPatient = [];
|
||||
foreach ($patientIds as $patientId) {
|
||||
$countsByPatient[$patientId] = [
|
||||
'opd_count' => 0,
|
||||
'lab_count' => 0,
|
||||
'ipd_count' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$countSources = [
|
||||
['table' => 'opd_master', 'column' => 'p_id', 'alias' => 'opd_count'],
|
||||
['table' => 'lab_request', 'column' => 'patient_id', 'alias' => 'lab_count'],
|
||||
['table' => 'ipd_master', 'column' => 'p_id', 'alias' => 'ipd_count'],
|
||||
];
|
||||
|
||||
foreach ($countSources as $source) {
|
||||
if (! $this->hasColumn($source['table'], $source['column'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rows = $this->db->table($source['table'])
|
||||
->select($source['column'] . ' AS patient_id, COUNT(*) AS total_count', false)
|
||||
->whereIn($source['column'], $patientIds)
|
||||
->groupBy($source['column'])
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$patientId = (int) ($row['patient_id'] ?? 0);
|
||||
if ($patientId <= 0 || ! array_key_exists($patientId, $countsByPatient)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$countsByPatient[$patientId][$source['alias']] = (int) ($row['total_count'] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $countsByPatient;
|
||||
}
|
||||
|
||||
public function open_by_key()
|
||||
{
|
||||
if ($resp = $this->ensureAccess()) {
|
||||
|
|
@ -1087,6 +1248,16 @@ class DoctorDocument extends BaseController
|
|||
$patientDoc
|
||||
);
|
||||
|
||||
$logoFile = defined('H_logo') ? (string) constant('H_logo') : 'logo.png';
|
||||
$logoAbsPath = FCPATH . 'assets/images/' . $logoFile;
|
||||
$hospitalLogoSrc = $this->buildImageDataUriFromPath($logoAbsPath);
|
||||
if ($hospitalLogoSrc === '' && is_file($logoAbsPath)) {
|
||||
$hospitalLogoSrc = str_replace('\\', '/', $logoAbsPath);
|
||||
}
|
||||
if ($hospitalLogoSrc === '') {
|
||||
$hospitalLogoSrc = base_url('assets/images/' . $logoFile);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'content' => $content,
|
||||
'print_on_type' => $resolvedPrintType,
|
||||
|
|
@ -1102,6 +1273,7 @@ class DoctorDocument extends BaseController
|
|||
'custom_header_html' => $customHeaderHtml,
|
||||
'custom_footer_html' => $customFooterHtml,
|
||||
'has_selected_print_template' => is_array($selectedPrintTemplate),
|
||||
'hospital_logo_src' => $hospitalLogoSrc,
|
||||
];
|
||||
|
||||
$mpdfTempDir = WRITEPATH . 'cache' . DIRECTORY_SEPARATOR . 'mpdf';
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ $footerMargin = number_format((float) ($print_footer_margin ?? 1.50), 2, '.', ''
|
|||
$customHeaderHtml = (string) ($custom_header_html ?? '');
|
||||
$customFooterHtml = (string) ($custom_footer_html ?? '');
|
||||
$hasSelectedPrintTemplate = ! empty($has_selected_print_template);
|
||||
$hospitalLogoSrc = trim((string) ($hospital_logo_src ?? ''));
|
||||
if ($hospitalLogoSrc === '') {
|
||||
$hospitalLogoSrc = base_url('assets/images/' . (defined('H_logo') ? constant('H_logo') : 'logo.png'));
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
@page {
|
||||
|
|
@ -33,7 +37,7 @@ body, p, td, th, div, span, li {
|
|||
<table cellspacing="0" style="font-size:10px;width:100%;border-style:inset;">
|
||||
<tr>
|
||||
<td style="width:20%;vertical-align:top;">
|
||||
<img style="width:100px;vertical-align:top;" src="<?= esc(base_url('assets/images/' . (defined('H_logo') ? constant('H_logo') : 'logo.png'))) ?>" />
|
||||
<img style="width:100px;vertical-align:top;" src="<?= esc($hospitalLogoSrc) ?>" />
|
||||
</td>
|
||||
<td style="width:70%;vertical-align:top;">
|
||||
<p align="center" style="font-size:26px;"><?= esc(defined('H_Name') ? constant('H_Name') : 'Hospital') ?></p>
|
||||
|
|
|
|||
|
|
@ -2,14 +2,29 @@
|
|||
$patientDoc = $patient_doc ?? [];
|
||||
$patient = $person_info ?? [];
|
||||
$patientDocId = (int) ($patient_doc_id ?? 0);
|
||||
$request = service('request');
|
||||
$backUrl = trim((string) $request->getGet('back_url'));
|
||||
$backTitle = trim((string) $request->getGet('back_title'));
|
||||
if ($backUrl === '') {
|
||||
$backUrl = base_url('doctor_work/document_workspace');
|
||||
}
|
||||
if ($backTitle === '') {
|
||||
$backTitle = 'Doctor Documents Workspace';
|
||||
}
|
||||
$docListQuery = http_build_query([
|
||||
'back_url' => $backUrl,
|
||||
'back_title' => $backTitle,
|
||||
]);
|
||||
$docListUrl = base_url('/Document_Patient/p_doc_record/' . (int) ($patient['id'] ?? 0));
|
||||
$docListUrlWithQuery = $docListUrl . ($docListQuery !== '' ? '?' . $docListQuery : '');
|
||||
?>
|
||||
<div class="pagetitle">
|
||||
<h1>Document Input Preview</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="<?= base_url('dashboard') ?>">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= base_url('/Patient/person_record/' . (int) ($patient['id'] ?? 0)) ?>');">Person</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= base_url('/Document_Patient/p_doc_record/' . (int) ($patient['id'] ?? 0)) ?>');">Document List</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= esc($backUrl, 'js') ?>','<?= esc($backTitle, 'js') ?>');"><?= esc($backTitle) ?></a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= esc($docListUrlWithQuery, 'js') ?>');">Document List</a></li>
|
||||
<li class="breadcrumb-item active">Pre-Data</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
|
@ -24,18 +39,31 @@ $patientDocId = (int) ($patient_doc_id ?? 0);
|
|||
<div style="max-height:560px;overflow-y:auto;">
|
||||
<?php foreach (($doc_format_sub ?? []) as $row): ?>
|
||||
<div class="row g-2 align-items-start mb-3">
|
||||
<?php
|
||||
$inputType = strtolower((string) ($row['input_type'] ?? 'text'));
|
||||
$rawValue = (string) ($row['p_doc_raw_value'] ?? '');
|
||||
$inputValue = $rawValue;
|
||||
if ($inputType === 'date') {
|
||||
if (preg_match('/^(\d{2})\/(\d{2})\/(\d{4})$/', $rawValue, $matches) === 1) {
|
||||
$inputValue = $matches[3] . '-' . $matches[2] . '-' . $matches[1];
|
||||
} elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $rawValue, $matches) === 1) {
|
||||
$inputValue = $matches[1] . '-' . $matches[2] . '-' . $matches[3];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="col-md-3"><label class="form-label mb-0"><?= esc((string) ($row['input_name'] ?? '')) ?></label></div>
|
||||
<div class="col-md-3"><div class="small text-muted"><?= esc((string) ($row['p_doc_raw_value'] ?? '')) ?></div></div>
|
||||
<div class="col-md-3"><div class="small text-muted" id="saved_value_<?= (int) ($row['id'] ?? 0) ?>"><?= esc($rawValue) ?></div></div>
|
||||
<div class="col-md-4">
|
||||
<?php $inputType = strtolower((string) ($row['input_type'] ?? 'text')); ?>
|
||||
<?php if ($inputType === 'textarea'): ?>
|
||||
<textarea class="form-control" id="input_id_<?= (int) ($row['id'] ?? 0) ?>"><?= esc((string) ($row['p_doc_raw_value'] ?? '')) ?></textarea>
|
||||
<textarea class="form-control" id="input_id_<?= (int) ($row['id'] ?? 0) ?>" data-input-type="<?= esc($inputType) ?>"><?= esc($rawValue) ?></textarea>
|
||||
<?php elseif ($inputType === 'date'): ?>
|
||||
<input class="form-control" id="input_id_<?= (int) ($row['id'] ?? 0) ?>" data-input-type="<?= esc($inputType) ?>" type="date" value="<?= esc($inputValue) ?>">
|
||||
<?php else: ?>
|
||||
<input class="form-control" id="input_id_<?= (int) ($row['id'] ?? 0) ?>" type="text" value="<?= esc((string) ($row['p_doc_raw_value'] ?? '')) ?>">
|
||||
<input class="form-control" id="input_id_<?= (int) ($row['id'] ?? 0) ?>" data-input-type="<?= esc($inputType) ?>" type="text" value="<?= esc($rawValue) ?>">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button onclick="update_data_value(<?= (int) ($row['id'] ?? 0) ?>, document.getElementById('input_id_<?= (int) ($row['id'] ?? 0) ?>').value)" type="button" class="btn btn-outline-primary btn-sm">Save</button>
|
||||
<button onclick="update_data_value(<?= (int) ($row['id'] ?? 0) ?>)" type="button" class="btn btn-outline-primary btn-sm">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
|
@ -43,14 +71,38 @@ $patientDocId = (int) ($patient_doc_id ?? 0);
|
|||
|
||||
<div class="d-flex flex-wrap gap-2 mt-3">
|
||||
<button onclick="report_create()" type="button" class="btn btn-primary btn-sm">Report Compile</button>
|
||||
<button onclick="load_form('<?= base_url('/Document_Patient/load_doc/' . $patientDocId) ?>')" type="button" class="btn btn-secondary btn-sm">Edit Document</button>
|
||||
<button onclick="load_form('<?= base_url('/Document_Patient/load_doc/' . $patientDocId) ?>?<?= esc($docListQuery, 'js') ?>')" type="button" class="btn btn-secondary btn-sm">Edit Document</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function update_data_value(test_id, test_value) {
|
||||
function formatInputValueForSave(inputElement) {
|
||||
if (!inputElement) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var rawValue = String(inputElement.value || '').trim();
|
||||
if (rawValue === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ((inputElement.dataset.inputType || '').toLowerCase() !== 'date') {
|
||||
return rawValue;
|
||||
}
|
||||
|
||||
var match = rawValue.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
||||
if (!match) {
|
||||
return rawValue;
|
||||
}
|
||||
|
||||
return match[3] + '/' + match[2] + '/' + match[1];
|
||||
}
|
||||
|
||||
function update_data_value(test_id) {
|
||||
var inputElement = document.getElementById('input_id_' + test_id);
|
||||
var test_value = formatInputValueForSave(inputElement);
|
||||
var csrfName = $('input[name="<?= csrf_token() ?>"]').attr('name');
|
||||
var csrfHash = $('input[name="<?= csrf_token() ?>"]').val();
|
||||
|
||||
|
|
@ -59,7 +111,10 @@ function update_data_value(test_id, test_value) {
|
|||
test_value: test_value,
|
||||
[csrfName]: csrfHash
|
||||
}, function() {
|
||||
alert('Saved');
|
||||
var savedCell = document.getElementById('saved_value_' + test_id);
|
||||
if (savedCell) {
|
||||
savedCell.textContent = test_value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +133,7 @@ function report_create() {
|
|||
}, function(data) {
|
||||
alert(data.error_text || 'Done');
|
||||
if (parseInt(data.update || '0', 10) === 1) {
|
||||
load_form('<?= base_url('/Document_Patient/load_doc') ?>/' + patient_doc_id);
|
||||
load_form('<?= base_url('/Document_Patient/load_doc') ?>/' + patient_doc_id + '?<?= esc($docListQuery, 'js') ?>');
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,29 @@ $docId = (int) ($patientDoc['id'] ?? 0);
|
|||
$html = (string) ($patientDoc['raw_data'] ?? '');
|
||||
$printTemplates = $print_templates ?? [];
|
||||
$defaultPrintTemplateId = (int) ($default_print_template_id ?? 0);
|
||||
$request = service('request');
|
||||
$backUrl = trim((string) $request->getGet('back_url'));
|
||||
$backTitle = trim((string) $request->getGet('back_title'));
|
||||
if ($backUrl === '') {
|
||||
$backUrl = base_url('doctor_work/document_workspace');
|
||||
}
|
||||
if ($backTitle === '') {
|
||||
$backTitle = 'Doctor Documents Workspace';
|
||||
}
|
||||
$docListUrl = base_url('/Document_Patient/p_doc_record/' . (int) ($patient['id'] ?? 0));
|
||||
$docListQuery = http_build_query([
|
||||
'back_url' => $backUrl,
|
||||
'back_title' => $backTitle,
|
||||
]);
|
||||
$docListUrlWithQuery = $docListUrl . ($docListQuery !== '' ? '?' . $docListQuery : '');
|
||||
?>
|
||||
<div class="pagetitle">
|
||||
<h1>Document Editor</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="<?= base_url('dashboard') ?>">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= base_url('/Patient/person_record/' . (int) ($patient['id'] ?? 0)) ?>');">Person</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= base_url('/Document_Patient/p_doc_record/' . (int) ($patient['id'] ?? 0)) ?>');">Document List</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= esc($backUrl, 'js') ?>','<?= esc($backTitle, 'js') ?>');"><?= esc($backTitle) ?></a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= esc($docListUrlWithQuery, 'js') ?>');">Document List</a></li>
|
||||
<li class="breadcrumb-item active">Editor</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
|
@ -121,7 +136,7 @@ $('#updatereport').off('click').on('click', function() {
|
|||
|
||||
$('#editreport').off('click').on('click', function() {
|
||||
var document_id = $('#document_id').val();
|
||||
load_form('<?= base_url('/Document_Patient/load_doc') ?>/' + document_id);
|
||||
load_form('<?= base_url('/Document_Patient/load_doc') ?>/' + document_id + '?<?= esc($docListQuery, 'js') ?>');
|
||||
});
|
||||
|
||||
$(document).off('click', '.btn-print-tpl, .btn-print-tpl-item').on('click', '.btn-print-tpl, .btn-print-tpl-item', function(e) {
|
||||
|
|
@ -137,33 +152,9 @@ $(document).off('click', '.btn-print-tpl, .btn-print-tpl-item').on('click', '.bt
|
|||
|
||||
var url = '<?= base_url('/Document_Patient/create_final') ?>/' + document_id + '?ptid=' + encodeURIComponent(ptid);
|
||||
|
||||
fetch(url, { credentials: 'same-origin' })
|
||||
.then(function(response) {
|
||||
var ct = response.headers.get('Content-Type') || '';
|
||||
if (!response.ok || ct.indexOf('application/pdf') === -1) {
|
||||
return response.text().then(function(txt) {
|
||||
throw new Error('PDF generation failed (HTTP ' + response.status + '). ' + txt.substring(0, 300));
|
||||
});
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then(function(blob) {
|
||||
var blobUrl = URL.createObjectURL(blob);
|
||||
var a = document.createElement('a');
|
||||
a.href = blobUrl;
|
||||
a.target = '_blank';
|
||||
a.rel = 'noopener';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
setTimeout(function() { URL.revokeObjectURL(blobUrl); }, 60000);
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert('Print error: ' + err.message);
|
||||
})
|
||||
.finally(function() {
|
||||
$btn.prop('disabled', origDisabled).html(origHtml);
|
||||
});
|
||||
window.open(url, '_blank');
|
||||
|
||||
$btn.prop('disabled', origDisabled).html(origHtml);
|
||||
});
|
||||
|
||||
$('#Re_Create').off('click').on('click', function() {
|
||||
|
|
|
|||
|
|
@ -5,13 +5,26 @@ $patientName = (string) ($patient['p_fname'] ?? '');
|
|||
$relativeName = (string) ($patient['p_rname'] ?? '');
|
||||
$ageText = (string) ($age_text ?? '-');
|
||||
$genderText = ((int) ($patient['gender'] ?? 0) === 1) ? 'Male' : (((int) ($patient['gender'] ?? 0) === 2) ? 'Female' : 'Other');
|
||||
$request = service('request');
|
||||
$backUrl = trim((string) $request->getGet('back_url'));
|
||||
$backTitle = trim((string) $request->getGet('back_title'));
|
||||
if ($backUrl === '') {
|
||||
$backUrl = base_url('doctor_work/document_workspace');
|
||||
}
|
||||
if ($backTitle === '') {
|
||||
$backTitle = 'Doctor Documents Workspace';
|
||||
}
|
||||
$backQuery = http_build_query([
|
||||
'back_url' => $backUrl,
|
||||
'back_title' => $backTitle,
|
||||
]);
|
||||
?>
|
||||
<div class="pagetitle">
|
||||
<h1>Patient Document Data</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="<?= base_url('dashboard') ?>">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= base_url('/Patient/person_record/' . $patientId) ?>');">Person</a></li>
|
||||
<li class="breadcrumb-item"><a href="javascript:load_form('<?= esc($backUrl, 'js') ?>','<?= esc($backTitle, 'js') ?>');"><?= esc($backTitle) ?></a></li>
|
||||
<li class="breadcrumb-item active">Documents</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
|
@ -31,7 +44,11 @@ $genderText = ((int) ($patient['gender'] ?? 0) === 1) ? 'Male' : (((int) ($patie
|
|||
<strong>/ P Code :</strong><?= esc((string) ($patient['p_code'] ?? '')) ?>
|
||||
</p>
|
||||
<input type="hidden" id="pid" value="<?= $patientId ?>">
|
||||
<input type="hidden" id="doc_back_query" value="<?= esc($backQuery) ?>">
|
||||
<div class="mt-2">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="load_form('<?= esc($backUrl, 'js') ?>','<?= esc($backTitle, 'js') ?>')">
|
||||
Back
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" onclick="load_form('<?= base_url('Report/document_list') ?>', 'Document Issue Report')">
|
||||
Open Document Issue Report
|
||||
</button>
|
||||
|
|
@ -91,7 +108,7 @@ $genderText = ((int) ($patient['gender'] ?? 0) === 1) ? 'Male' : (((int) ($patie
|
|||
<td><?= $n++ ?></td>
|
||||
<td><?= !empty($row['date_issue']) ? esc(date('d-m-Y', strtotime((string) $row['date_issue']))) : '' ?></td>
|
||||
<td><?= esc((string) ($row['doc_name'] ?? '')) ?></td>
|
||||
<td><button type="button" class="btn btn-primary btn-sm" onclick="load_form('<?= base_url('Document_Patient/load_doc/' . (int) ($row['id'] ?? 0)) ?>')">Edit</button></td>
|
||||
<td><button type="button" class="btn btn-primary btn-sm" onclick="load_form('<?= base_url('Document_Patient/load_doc/' . (int) ($row['id'] ?? 0)) ?>?<?= esc($backQuery, 'js') ?>')">Edit</button></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
|
|
@ -122,8 +139,13 @@ $('#createdoc').off('click').on('click', function() {
|
|||
[csrfName]: csrfHash
|
||||
}, function(data) {
|
||||
var id = parseInt((data || '').toString(), 10);
|
||||
var backQuery = $('#doc_back_query').val() || '';
|
||||
if (id > 0) {
|
||||
load_form('<?= base_url('Document_Patient/Pre_Data') ?>/' + id);
|
||||
var url = '<?= base_url('Document_Patient/Pre_Data') ?>/' + id;
|
||||
if (backQuery) {
|
||||
url += '?' + backQuery;
|
||||
}
|
||||
load_form(url);
|
||||
} else {
|
||||
alert('Unable to create document');
|
||||
}
|
||||
|
|
|
|||
157
app/Views/doctor_document/patient_search.php
Normal file
157
app/Views/doctor_document/patient_search.php
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
$search = trim((string) ($search ?? ''));
|
||||
$patients = isset($patients) && is_array($patients) ? $patients : [];
|
||||
$selfUrl = base_url('doctor_work/patient_search');
|
||||
?>
|
||||
|
||||
<div class="pagetitle">
|
||||
<h1>Doctor Patient Search</h1>
|
||||
<nav>
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="<?= base_url('dashboard') ?>">Home</a></li>
|
||||
<li class="breadcrumb-item active">Doctor Patient Search</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Search Patient</h5>
|
||||
<form onsubmit="return loadDoctorPatientSearch(this);" class="row g-2 align-items-end">
|
||||
<div class="col-lg-8">
|
||||
<label class="form-label" for="doctor_patient_search_q">Name / UHID / Mobile / Patient ID</label>
|
||||
<input type="text" class="form-control" id="doctor_patient_search_q" name="q" value="<?= esc($search) ?>" placeholder="Enter patient name, UHID, mobile, or patient id">
|
||||
</div>
|
||||
<div class="col-lg-4 d-flex gap-2 flex-wrap">
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="load_form('<?= esc($selfUrl, 'js') ?>','Doctor Patient Search');">Reset</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="small text-muted mt-2">Each result includes consult history, patient document issue, and summary counts for OPD, lab tests, and IPD admissions.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
||||
<h5 class="card-title mb-0">Patient Results</h5>
|
||||
<span class="badge bg-secondary"><?= count($patients) ?> record(s)</span>
|
||||
</div>
|
||||
|
||||
<?php if ($patients === []) : ?>
|
||||
<div class="alert alert-info mb-0">No patient found for the current search.</div>
|
||||
<?php else : ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped align-middle mb-0" id="doctorPatientSearchTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UHID</th>
|
||||
<th>Patient</th>
|
||||
<th>Age</th>
|
||||
<th>Last Visit</th>
|
||||
<th>History</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($patients as $patient) : ?>
|
||||
<?php
|
||||
$patientId = (int) ($patient['id'] ?? 0);
|
||||
$historyBackUrl = $selfUrl;
|
||||
if ($search !== '') {
|
||||
$historyBackUrl .= '?' . http_build_query(['q' => $search]);
|
||||
}
|
||||
$historyUrl = base_url('billing/patient/show_profile_opd') . '/' . $patientId . '/1?' . http_build_query([
|
||||
'back_url' => $historyBackUrl,
|
||||
'back_title' => 'Doctor Patient Search',
|
||||
]);
|
||||
$documentUrl = base_url('Document_Patient/p_doc_record') . '/' . $patientId;
|
||||
$documentUrl = base_url('Document_Patient/p_doc_record') . '/' . $patientId . '?' . http_build_query([
|
||||
'back_url' => $historyBackUrl,
|
||||
'back_title' => 'Doctor Patient Search',
|
||||
]);
|
||||
$patientRawName = trim((string) ($patient['p_fname'] ?? '') . ' { ' . (string) ($patient['p_rname'] ?? '') . ' }');
|
||||
$patientAge = function_exists('get_age_1')
|
||||
? trim((string) get_age_1($patient['dob'] ?? null, $patient['age'] ?? '', $patient['age_in_month'] ?? '', $patient['estimate_dob'] ?? '', $patient['last_visit'] ?? null))
|
||||
: trim((string) ($patient['age'] ?? ''));
|
||||
?>
|
||||
<tr>
|
||||
<td><?= esc((string) ($patient['p_code'] ?? '')) ?></td>
|
||||
<td><?= esc($patientRawName) ?></td>
|
||||
<td><?= esc($patientAge) ?></td>
|
||||
<td><?= esc((string) ($patient['Last_Visit'] ?? '')) ?></td>
|
||||
<td>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<span class="badge bg-primary-subtle text-primary border">OPD: <?= (int) ($patient['opd_count'] ?? 0) ?></span>
|
||||
<span class="badge bg-success-subtle text-success border">Lab: <?= (int) ($patient['lab_count'] ?? 0) ?></span>
|
||||
<span class="badge bg-warning-subtle text-dark border">IPD: <?= (int) ($patient['ipd_count'] ?? 0) ?></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a href="javascript:load_form('<?= esc($historyUrl, 'js') ?>','Consult History');" class="btn btn-info btn-sm">
|
||||
<i class="bi bi-clock-history"></i> History
|
||||
</a>
|
||||
<a href="javascript:load_form('<?= esc($documentUrl, 'js') ?>','Patient Documents');" class="btn btn-primary btn-sm">
|
||||
<i class="bi bi-file-earmark-text"></i> Issue Document
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function loadDoctorPatientSearch(form) {
|
||||
var query = '';
|
||||
if (form && form.q) {
|
||||
query = String(form.q.value || '').trim();
|
||||
}
|
||||
|
||||
var url = '<?= esc($selfUrl, 'js') ?>';
|
||||
if (query !== '') {
|
||||
url += '?q=' + encodeURIComponent(query);
|
||||
}
|
||||
|
||||
load_form(url, 'Doctor Patient Search');
|
||||
return false;
|
||||
}
|
||||
|
||||
(function() {
|
||||
var table = document.getElementById('doctorPatientSearchTable');
|
||||
if (!table || table.dataset.dtInit === '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.simpleDatatables && window.simpleDatatables.DataTable) {
|
||||
try {
|
||||
new window.simpleDatatables.DataTable(table);
|
||||
table.dataset.dtInit = '1';
|
||||
return;
|
||||
} catch (error) {
|
||||
console.warn('simple-datatables init failed for doctor patient search table', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.jQuery && $.fn && $.fn.DataTable && $.fn.dataTable && $.fn.dataTable.defaults) {
|
||||
try {
|
||||
if (!$.fn.DataTable.isDataTable('#doctorPatientSearchTable')) {
|
||||
$('#doctorPatientSearchTable').DataTable({
|
||||
order: [[3, 'desc']],
|
||||
pageLength: 25
|
||||
});
|
||||
}
|
||||
table.dataset.dtInit = '1';
|
||||
} catch (error) {
|
||||
console.warn('jQuery DataTables init failed for doctor patient search table', error);
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
</div>
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<button type="button" class="btn btn-success" onclick="openPatientDoc()">Open Patient Documents</button>
|
||||
<button type="button" class="btn btn-outline-secondary" onclick="load_form('<?= base_url('doctor_work/patient_search') ?>','Doctor Patient Search')">Search Patient with History</button>
|
||||
<button type="button" class="btn btn-outline-primary" onclick="load_form('<?= base_url('Report/document_list') ?>', 'Document Issue Report')">Document Issue Report</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -372,6 +372,12 @@ if (! $canChargesSettings && $user && method_exists($user, 'inGroup')) {
|
|||
<span>Clinical Templates</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('doctor_work/patient_search') ?>','Doctor Patient Search')">
|
||||
<i class="bi bi-search"></i>
|
||||
<span>Patient Search</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="javascript:load_form('<?= base_url('doctor_work/document_workspace') ?>','Doctor Documents Workspace')">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user