hospital-management/templates/emr/patient_search.html
2025-08-12 13:33:25 +03:00

693 lines
33 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Patient Search{% endblock %}
{% block content %}
<div id="content" class="app-content">
<div class="container">
<ul class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'emr:dashboard' %}">EMR</a></li>
<li class="breadcrumb-item active">Patient Search</li>
</ul>
<div class="row align-items-center mb-3">
<div class="col">
<h1 class="page-header">Patient Search</h1>
<p class="text-muted">Search and locate patient records across the system</p>
</div>
<div class="col-auto">
<a href="{% url 'patients:patient_create' %}" class="btn btn-primary">
<i class="fa fa-plus me-2"></i>New Patient
</a>
</div>
</div>
<!-- Search Form -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Search Criteria</h4>
</div>
<div class="card-body">
<form id="patientSearchForm" method="get">
<div class="row">
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Patient ID</label>
<input type="text" name="patient_id" class="form-control" placeholder="Enter Patient ID" value="{{ request.GET.patient_id }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">First Name</label>
<input type="text" name="first_name" class="form-control" placeholder="Enter First Name" value="{{ request.GET.first_name }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Last Name</label>
<input type="text" name="last_name" class="form-control" placeholder="Enter Last Name" value="{{ request.GET.last_name }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Date of Birth</label>
<input type="date" name="date_of_birth" class="form-control" value="{{ request.GET.date_of_birth }}">
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Phone Number</label>
<input type="text" name="phone" class="form-control" placeholder="Enter Phone Number" value="{{ request.GET.phone }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" name="email" class="form-control" placeholder="Enter Email" value="{{ request.GET.email }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Insurance Number</label>
<input type="text" name="insurance_number" class="form-control" placeholder="Enter Insurance Number" value="{{ request.GET.insurance_number }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Status</label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<option value="active" {% if request.GET.status == 'active' %}selected{% endif %}>Active</option>
<option value="inactive" {% if request.GET.status == 'inactive' %}selected{% endif %}>Inactive</option>
<option value="deceased" {% if request.GET.status == 'deceased' %}selected{% endif %}>Deceased</option>
</select>
</div>
</div>
</div>
<!-- Advanced Search Options -->
<div class="row">
<div class="col-12">
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="advancedSearch" {% if request.GET.advanced %}checked{% endif %}>
<label class="form-check-label" for="advancedSearch">
Show Advanced Search Options
</label>
</div>
</div>
</div>
<div id="advancedOptions" class="row" style="{% if not request.GET.advanced %}display: none;{% endif %}">
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Gender</label>
<select name="gender" class="form-select">
<option value="">All Genders</option>
<option value="M" {% if request.GET.gender == 'M' %}selected{% endif %}>Male</option>
<option value="F" {% if request.GET.gender == 'F' %}selected{% endif %}>Female</option>
<option value="O" {% if request.GET.gender == 'O' %}selected{% endif %}>Other</option>
</select>
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">Age Range</label>
<div class="input-group">
<input type="number" name="age_min" class="form-control" placeholder="Min" value="{{ request.GET.age_min }}">
<span class="input-group-text">to</span>
<input type="number" name="age_max" class="form-control" placeholder="Max" value="{{ request.GET.age_max }}">
</div>
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">City</label>
<input type="text" name="city" class="form-control" placeholder="Enter City" value="{{ request.GET.city }}">
</div>
</div>
<div class="col-md-3">
<div class="mb-3">
<label class="form-label">State/Province</label>
<input type="text" name="state" class="form-control" placeholder="Enter State" value="{{ request.GET.state }}">
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<button type="submit" class="btn btn-primary me-2">
<i class="fa fa-search me-2"></i>Search Patients
</button>
<button type="button" class="btn btn-secondary me-2" onclick="clearSearch()">
<i class="fa fa-times me-2"></i>Clear
</button>
<button type="button" class="btn btn-info" onclick="saveSearch()">
<i class="fa fa-bookmark me-2"></i>Save Search
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Search Results -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">
Search Results
{% if patients %}
<span class="badge bg-primary ms-2">{{ patients|length }} found</span>
{% endif %}
</h4>
<div class="card-tools">
{% if patients %}
<button type="button" class="btn btn-outline-success btn-sm me-2" onclick="exportResults()">
<i class="fa fa-download me-1"></i>Export
</button>
{% endif %}
<button type="button" class="btn btn-outline-primary btn-sm" onclick="refreshResults()">
<i class="fa fa-sync me-1"></i>Refresh
</button>
</div>
</div>
<div class="card-body">
{% if patients %}
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>
<input type="checkbox" id="selectAll" onchange="toggleSelectAll()">
</th>
<th>Patient ID</th>
<th>Name</th>
<th>Date of Birth</th>
<th>Gender</th>
<th>Phone</th>
<th>Email</th>
<th>Status</th>
<th>Last Visit</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for patient in patients %}
<tr>
<td>
<input type="checkbox" class="patient-checkbox" value="{{ patient.patient_id }}">
</td>
<td>
<strong>{{ patient.patient_id }}</strong>
</td>
<td>
<div>
<strong>{{ patient.first_name }} {{ patient.last_name }}</strong>
{% if patient.middle_name %}
<small class="text-muted">({{ patient.middle_name }})</small>
{% endif %}
</div>
{% if patient.preferred_name %}
<small class="text-muted">Preferred: {{ patient.preferred_name }}</small>
{% endif %}
</td>
<td>
{{ patient.date_of_birth|date:"M d, Y" }}
<br>
<small class="text-muted">Age: {{ patient.age }}</small>
</td>
<td>
<span class="badge bg-{% if patient.gender == 'M' %}info{% elif patient.gender == 'F' %}pink{% else %}secondary{% endif %}">
{{ patient.get_gender_display }}
</span>
</td>
<td>
{% if patient.phone_primary %}
{{ patient.phone_primary }}
{% if patient.phone_secondary %}
<br><small class="text-muted">{{ patient.phone_secondary }}</small>
{% endif %}
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</td>
<td>
{% if patient.email %}
{{ patient.email }}
{% else %}
<span class="text-muted">Not provided</span>
{% endif %}
</td>
<td>
<span class="badge bg-{% if patient.status == 'active' %}success{% elif patient.status == 'inactive' %}warning{% else %}danger{% endif %}">
{{ patient.get_status_display }}
</span>
</td>
<td>
{% if patient.last_visit_date %}
{{ patient.last_visit_date|date:"M d, Y" }}
{% else %}
<span class="text-muted">No visits</span>
{% endif %}
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="{% url 'patients:patient_detail' patient.patient_id %}" class="btn btn-outline-primary" title="View Details">
<i class="fa fa-eye"></i>
</a>
<a href="{% url 'emr:patient_chart' patient.patient_id %}" class="btn btn-outline-success" title="View Chart">
<i class="fa fa-chart-line"></i>
</a>
<a href="{% url 'patients:patient_edit' patient.patient_id %}" class="btn btn-outline-warning" title="Edit">
<i class="fa fa-edit"></i>
</a>
<button type="button" class="btn btn-outline-info" onclick="quickActions('{{ patient.patient_id }}')" title="Quick Actions">
<i class="fa fa-ellipsis-v"></i>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if is_paginated %}
<nav aria-label="Patient search pagination">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?{{ request.GET.urlencode }}&page=1">First</a>
</li>
<li class="page-item">
<a class="page-link" href="?{{ request.GET.urlencode }}&page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
<span class="page-link">{{ num }}</span>
</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">
<a class="page-link" href="?{{ request.GET.urlencode }}&page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?{{ request.GET.urlencode }}&page={{ page_obj.next_page_number }}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?{{ request.GET.urlencode }}&page={{ page_obj.paginator.num_pages }}">Last</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
<!-- Bulk Actions -->
<div id="bulkActions" class="mt-3" style="display: none;">
<div class="card bg-light">
<div class="card-body">
<h6>Bulk Actions</h6>
<div class="btn-group">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="bulkExport()">
<i class="fa fa-download me-1"></i>Export Selected
</button>
<button type="button" class="btn btn-outline-info btn-sm" onclick="bulkMessage()">
<i class="fa fa-envelope me-1"></i>Send Message
</button>
<button type="button" class="btn btn-outline-warning btn-sm" onclick="bulkUpdate()">
<i class="fa fa-edit me-1"></i>Update Status
</button>
</div>
</div>
</div>
</div>
{% else %}
<div class="text-center py-5">
{% if request.GET %}
<i class="fa fa-search fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No patients found</h5>
<p class="text-muted">Try adjusting your search criteria or clearing the search to see all patients.</p>
<button type="button" class="btn btn-primary" onclick="clearSearch()">
<i class="fa fa-times me-2"></i>Clear Search
</button>
{% else %}
<i class="fa fa-users fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Search for Patients</h5>
<p class="text-muted">Use the search form above to find patients in the system.</p>
{% endif %}
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Quick Actions Modal -->
<div class="modal fade" id="quickActionsModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Quick Actions</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="d-grid gap-2">
<button type="button" class="btn btn-outline-primary" onclick="scheduleAppointment()">
<i class="fa fa-calendar me-2"></i>Schedule Appointment
</button>
<button type="button" class="btn btn-outline-success" onclick="createEncounter()">
<i class="fa fa-stethoscope me-2"></i>Create Encounter
</button>
<button type="button" class="btn btn-outline-info" onclick="viewHistory()">
<i class="fa fa-history me-2"></i>View Medical History
</button>
<button type="button" class="btn btn-outline-warning" onclick="sendMessage()">
<i class="fa fa-envelope me-2"></i>Send Message
</button>
<button type="button" class="btn btn-outline-secondary" onclick="printSummary()">
<i class="fa fa-print me-2"></i>Print Summary
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Save Search Modal -->
<div class="modal fade" id="saveSearchModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Save Search</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="saveSearchForm">
<div class="modal-body">
{% csrf_token %}
<div class="mb-3">
<label class="form-label">Search Name</label>
<input type="text" name="search_name" class="form-control" placeholder="Enter a name for this search" required>
</div>
<div class="mb-3">
<label class="form-label">Description (Optional)</label>
<textarea name="description" class="form-control" rows="3" placeholder="Describe what this search is for..."></textarea>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="is_public">
<label class="form-check-label">
Share with other users
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-save me-2"></i>Save Search
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
var selectedPatientId = null;
$(document).ready(function() {
setupEventHandlers();
updateBulkActionsVisibility();
});
function setupEventHandlers() {
// Advanced search toggle
$('#advancedSearch').change(function() {
if ($(this).is(':checked')) {
$('#advancedOptions').show();
} else {
$('#advancedOptions').hide();
}
});
// Patient checkbox changes
$('.patient-checkbox').change(function() {
updateBulkActionsVisibility();
updateSelectAllCheckbox();
});
// Save search form
$('#saveSearchForm').submit(function(e) {
e.preventDefault();
submitSaveSearch();
});
}
function toggleSelectAll() {
var isChecked = $('#selectAll').is(':checked');
$('.patient-checkbox').prop('checked', isChecked);
updateBulkActionsVisibility();
}
function updateSelectAllCheckbox() {
var totalCheckboxes = $('.patient-checkbox').length;
var checkedCheckboxes = $('.patient-checkbox:checked').length;
if (checkedCheckboxes === 0) {
$('#selectAll').prop('indeterminate', false).prop('checked', false);
} else if (checkedCheckboxes === totalCheckboxes) {
$('#selectAll').prop('indeterminate', false).prop('checked', true);
} else {
$('#selectAll').prop('indeterminate', true);
}
}
function updateBulkActionsVisibility() {
var checkedCount = $('.patient-checkbox:checked').length;
if (checkedCount > 0) {
$('#bulkActions').show();
} else {
$('#bulkActions').hide();
}
}
function clearSearch() {
window.location.href = '{% url "emr:patient_search" %}';
}
function refreshResults() {
window.location.reload();
}
function exportResults() {
var searchParams = new URLSearchParams(window.location.search);
searchParams.set('export', 'true');
window.open('{% url "emr:patient_search" %}?' + searchParams.toString(), '_blank');
}
function quickActions(patientId) {
selectedPatientId = patientId;
$('#quickActionsModal').modal('show');
}
function scheduleAppointment() {
if (selectedPatientId) {
window.open('{% url "appointments:appointment_create" %}?patient_id=' + selectedPatientId, '_blank');
$('#quickActionsModal').modal('hide');
}
}
function createEncounter() {
if (selectedPatientId) {
window.open('{% url "emr:encounter_create" %}?patient_id=' + selectedPatientId, '_blank');
$('#quickActionsModal').modal('hide');
}
}
function viewHistory() {
if (selectedPatientId) {
window.open('{% url "emr:patient_chart" %}' + selectedPatientId + '/', '_blank');
$('#quickActionsModal').modal('hide');
}
}
function sendMessage() {
if (selectedPatientId) {
window.open('{% url "communications:send_message" %}?patient_id=' + selectedPatientId, '_blank');
$('#quickActionsModal').modal('hide');
}
}
function printSummary() {
if (selectedPatientId) {
window.open('{% url "patients:patient_summary" %}' + selectedPatientId + '/?print=true', '_blank');
$('#quickActionsModal').modal('hide');
}
}
function saveSearch() {
$('#saveSearchModal').modal('show');
}
function submitSaveSearch() {
var formData = new FormData($('#saveSearchForm')[0]);
var searchParams = new URLSearchParams(window.location.search);
formData.append('search_criteria', searchParams.toString());
$.post('{% url "emr:save_patient_search" %}', formData, function(data) {
if (data.success) {
$('#saveSearchModal').modal('hide');
toastr.success('Search saved successfully');
} else {
toastr.error('Failed to save search: ' + data.error);
}
}).fail(function() {
toastr.error('Failed to save search');
});
}
function bulkExport() {
var selectedIds = $('.patient-checkbox:checked').map(function() {
return $(this).val();
}).get();
if (selectedIds.length === 0) {
toastr.warning('Please select patients to export');
return;
}
var form = $('<form method="post" action="{% url "emr:bulk_export_patients" %}">');
form.append('<input type="hidden" name="csrfmiddlewaretoken" value="' + $('[name=csrfmiddlewaretoken]').val() + '">');
selectedIds.forEach(function(id) {
form.append('<input type="hidden" name="patient_ids" value="' + id + '">');
});
$('body').append(form);
form.submit();
form.remove();
}
function bulkMessage() {
var selectedIds = $('.patient-checkbox:checked').map(function() {
return $(this).val();
}).get();
if (selectedIds.length === 0) {
toastr.warning('Please select patients to message');
return;
}
var url = '{% url "communications:bulk_message" %}?patient_ids=' + selectedIds.join(',');
window.open(url, '_blank');
}
function bulkUpdate() {
var selectedIds = $('.patient-checkbox:checked').map(function() {
return $(this).val();
}).get();
if (selectedIds.length === 0) {
toastr.warning('Please select patients to update');
return;
}
var url = '{% url "patients:bulk_update" %}?patient_ids=' + selectedIds.join(',');
window.open(url, '_blank');
}
// Auto-submit search form on Enter key
$('#patientSearchForm input').keypress(function(e) {
if (e.which === 13) {
$('#patientSearchForm').submit();
}
});
</script>
<style>
.card-tools {
margin-left: auto;
}
.btn-group-sm .btn {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.table td {
vertical-align: middle;
}
.badge {
font-size: 0.75rem;
}
.patient-checkbox {
cursor: pointer;
}
#selectAll {
cursor: pointer;
}
.pagination {
margin-bottom: 0;
}
.fa-3x {
font-size: 3em;
}
.bg-pink {
background-color: #e91e63 !important;
}
.input-group-text {
background-color: #f8f9fa;
border-color: #ced4da;
}
#bulkActions {
border-top: 1px solid #dee2e6;
padding-top: 1rem;
}
.d-grid .btn {
text-align: left;
}
.table-hover tbody tr:hover {
background-color: rgba(0, 0, 0, 0.075);
}
</style>
{% endblock %}