1242 lines
68 KiB
HTML
1242 lines
68 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Patient Transfer{% 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 'inpatients:dashboard' %}">Inpatients</a></li>
|
|
<li class="breadcrumb-item active">Patient Transfer</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Patient Transfer</h1>
|
|
<p class="text-muted">Manage patient transfers between departments, wards, and facilities</p>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="btn-group">
|
|
<button class="btn btn-primary" onclick="initiateTransfer()">
|
|
<i class="fa fa-exchange-alt me-2"></i>New Transfer
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="viewPendingTransfers()">
|
|
<i class="fa fa-clock me-2"></i>Pending Transfers
|
|
</button>
|
|
<button class="btn btn-outline-info" onclick="transferHistory()">
|
|
<i class="fa fa-history me-2"></i>Transfer History
|
|
</button>
|
|
<button class="btn btn-outline-success" onclick="generateReport()">
|
|
<i class="fa fa-chart-bar me-2"></i>Reports
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transfer Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h4 class="mb-0">{{ today_transfers }}</h4>
|
|
<p class="mb-0">Today's Transfers</p>
|
|
</div>
|
|
<div class="ms-3">
|
|
<i class="fa fa-exchange-alt fa-2x"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-warning text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h4 class="mb-0">{{ pending_transfers }}</h4>
|
|
<p class="mb-0">Pending</p>
|
|
</div>
|
|
<div class="ms-3">
|
|
<i class="fa fa-clock fa-2x"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-success text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h4 class="mb-0">{{ completed_transfers }}</h4>
|
|
<p class="mb-0">Completed</p>
|
|
</div>
|
|
<div class="ms-3">
|
|
<i class="fa fa-check fa-2x"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-danger text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h4 class="mb-0">{{ urgent_transfers }}</h4>
|
|
<p class="mb-0">Urgent</p>
|
|
</div>
|
|
<div class="ms-3">
|
|
<i class="fa fa-exclamation-triangle fa-2x"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transfer Management Tabs -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<ul class="nav nav-tabs card-header-tabs" id="transferTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active" id="new-transfer-tab" data-bs-toggle="tab" data-bs-target="#new-transfer" type="button" role="tab">
|
|
<i class="fa fa-plus me-2"></i>New Transfer
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="pending-tab" data-bs-toggle="tab" data-bs-target="#pending" type="button" role="tab">
|
|
<i class="fa fa-clock me-2"></i>Pending Transfers
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="active-tab" data-bs-toggle="tab" data-bs-target="#active" type="button" role="tab">
|
|
<i class="fa fa-spinner me-2"></i>Active Transfers
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" id="history-tab" data-bs-toggle="tab" data-bs-target="#history" type="button" role="tab">
|
|
<i class="fa fa-history me-2"></i>Transfer History
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="tab-content" id="transferTabContent">
|
|
<!-- New Transfer Tab -->
|
|
<div class="tab-pane fade show active" id="new-transfer" role="tabpanel">
|
|
<form id="transferForm" class="needs-validation" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<!-- Patient Selection -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-user me-2"></i>Patient Information
|
|
</h5>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<div class="mb-3">
|
|
<label class="form-label">Patient <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="patient_id" id="patientSelect" required>
|
|
<option value="">Select patient...</option>
|
|
{% for patient in inpatients %}
|
|
<option value="{{ patient.id }}" data-details="{{ patient.details_json }}">
|
|
{{ patient.patient.get_full_name }} - {{ patient.current_bed.bed_number }} ({{ patient.current_bed.ward.name }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
<div class="invalid-feedback">Please select a patient.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Current Location</label>
|
|
<input type="text" class="form-control" id="currentLocation" readonly>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Details Display -->
|
|
<div id="patientDetails" class="row mb-4" style="display: none;">
|
|
<div class="col-12">
|
|
<div class="alert alert-info">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<strong>Patient ID:</strong> <span id="displayPatientId"></span>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<strong>Current Bed:</strong> <span id="displayCurrentBed"></span>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<strong>Admission Date:</strong> <span id="displayAdmissionDate"></span>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<strong>Attending Physician:</strong> <span id="displayPhysician"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transfer Details -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-exchange-alt me-2"></i>Transfer Details
|
|
</h5>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Transfer Type <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="transfer_type" id="transferType" required>
|
|
<option value="">Select type...</option>
|
|
<option value="internal">Internal Transfer</option>
|
|
<option value="external">External Transfer</option>
|
|
<option value="emergency">Emergency Transfer</option>
|
|
<option value="discharge">Discharge Transfer</option>
|
|
</select>
|
|
<div class="invalid-feedback">Please select transfer type.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Priority <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="priority" id="priority" required>
|
|
<option value="">Select priority...</option>
|
|
<option value="routine">Routine</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="emergency">Emergency</option>
|
|
<option value="critical">Critical</option>
|
|
</select>
|
|
<div class="invalid-feedback">Please select priority.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Scheduled Date & Time <span class="text-danger">*</span></label>
|
|
<input type="datetime-local" class="form-control" name="scheduled_datetime" id="scheduledDateTime" required>
|
|
<div class="invalid-feedback">Please select scheduled date and time.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Destination -->
|
|
<div class="row mb-4" id="destinationSection">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-map-marker-alt me-2"></i>Destination
|
|
</h5>
|
|
</div>
|
|
|
|
<!-- Internal Transfer Destination -->
|
|
<div id="internalDestination" style="display: none;">
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Destination Department <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="destination_department" id="destinationDepartment">
|
|
<option value="">Select department...</option>
|
|
{% for dept in departments %}
|
|
<option value="{{ dept.id }}">{{ dept.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Destination Ward <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="destination_ward" id="destinationWard" disabled>
|
|
<option value="">Select ward...</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Destination Bed</label>
|
|
<select class="form-select" name="destination_bed" id="destinationBed" disabled>
|
|
<option value="">Select bed...</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- External Transfer Destination -->
|
|
<div id="externalDestination" style="display: none;">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Destination Facility <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" name="destination_facility" id="destinationFacility" placeholder="Enter destination facility name">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Facility Address</label>
|
|
<input type="text" class="form-control" name="facility_address" id="facilityAddress" placeholder="Enter facility address">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Contact Person</label>
|
|
<input type="text" class="form-control" name="contact_person" id="contactPerson" placeholder="Enter contact person name">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Contact Phone</label>
|
|
<input type="tel" class="form-control" name="contact_phone" id="contactPhone" placeholder="Enter contact phone number">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Medical Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-stethoscope me-2"></i>Medical Information
|
|
</h5>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Requesting Physician <span class="text-danger">*</span></label>
|
|
<select class="form-select" name="requesting_physician" id="requestingPhysician" required>
|
|
<option value="">Select physician...</option>
|
|
{% for physician in physicians %}
|
|
<option value="{{ physician.id }}">{{ physician.get_full_name }} - {{ physician.specialization }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<div class="invalid-feedback">Please select requesting physician.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Receiving Physician</label>
|
|
<select class="form-select" name="receiving_physician" id="receivingPhysician">
|
|
<option value="">Select physician...</option>
|
|
{% for physician in physicians %}
|
|
<option value="{{ physician.id }}">{{ physician.get_full_name }} - {{ physician.specialization }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Reason for Transfer <span class="text-danger">*</span></label>
|
|
<textarea class="form-control" name="transfer_reason" id="transferReason" rows="3" placeholder="Enter reason for transfer" required></textarea>
|
|
<div class="invalid-feedback">Please enter reason for transfer.</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Current Diagnosis</label>
|
|
<input type="text" class="form-control" name="current_diagnosis" id="currentDiagnosis" placeholder="Enter current diagnosis">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">ICD-10 Code</label>
|
|
<input type="text" class="form-control" name="icd10_code" id="icd10Code" placeholder="Enter ICD-10 code">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Clinical Status -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-heartbeat me-2"></i>Clinical Status
|
|
</h5>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Vital Signs Status</label>
|
|
<select class="form-select" name="vital_signs_status" id="vitalSignsStatus">
|
|
<option value="stable">Stable</option>
|
|
<option value="unstable">Unstable</option>
|
|
<option value="critical">Critical</option>
|
|
<option value="improving">Improving</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Mobility Status</label>
|
|
<select class="form-select" name="mobility_status" id="mobilityStatus">
|
|
<option value="ambulatory">Ambulatory</option>
|
|
<option value="wheelchair">Wheelchair</option>
|
|
<option value="stretcher">Stretcher</option>
|
|
<option value="bed_bound">Bed Bound</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Oxygen Requirements</label>
|
|
<select class="form-select" name="oxygen_requirements" id="oxygenRequirements">
|
|
<option value="none">None</option>
|
|
<option value="nasal_cannula">Nasal Cannula</option>
|
|
<option value="face_mask">Face Mask</option>
|
|
<option value="ventilator">Ventilator</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">IV Access</label>
|
|
<select class="form-select" name="iv_access" id="ivAccess">
|
|
<option value="none">None</option>
|
|
<option value="peripheral">Peripheral IV</option>
|
|
<option value="central">Central Line</option>
|
|
<option value="picc">PICC Line</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Special Requirements -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h5 class="text-primary mb-3">
|
|
<i class="fa fa-exclamation-circle me-2"></i>Special Requirements
|
|
</h5>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" name="isolation_required" id="isolationRequired">
|
|
<label class="form-check-label" for="isolationRequired">
|
|
Isolation Precautions
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" name="special_equipment" id="specialEquipment">
|
|
<label class="form-check-label" for="specialEquipment">
|
|
Special Equipment Required
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input" type="checkbox" name="nursing_escort" id="nursingEscort">
|
|
<label class="form-check-label" for="nursingEscort">
|
|
Nursing Escort Required
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Special Instructions</label>
|
|
<textarea class="form-control" name="special_instructions" id="specialInstructions" rows="3" placeholder="Enter any special instructions for the transfer"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Equipment/Medications to Transfer</label>
|
|
<textarea class="form-control" name="equipment_medications" id="equipmentMedications" rows="2" placeholder="List equipment and medications that need to be transferred with patient"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form Actions -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex justify-content-end gap-2">
|
|
<button type="button" class="btn btn-secondary" onclick="resetForm()">
|
|
<i class="fa fa-undo me-2"></i>Reset
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary" onclick="saveAsDraft()">
|
|
<i class="fa fa-save me-2"></i>Save as Draft
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-exchange-alt me-2"></i>Submit Transfer Request
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Pending Transfers Tab -->
|
|
<div class="tab-pane fade" id="pending" role="tabpanel">
|
|
<div class="row mb-3">
|
|
<div class="col-md-4">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" placeholder="Search pending transfers..." id="pendingSearch">
|
|
<button class="btn btn-outline-secondary" type="button">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select" id="pendingPriority">
|
|
<option value="">All Priorities</option>
|
|
<option value="critical">Critical</option>
|
|
<option value="emergency">Emergency</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="routine">Routine</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select class="form-select" id="pendingType">
|
|
<option value="">All Types</option>
|
|
<option value="internal">Internal</option>
|
|
<option value="external">External</option>
|
|
<option value="emergency">Emergency</option>
|
|
<option value="discharge">Discharge</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-success w-100" onclick="bulkApprove()">
|
|
<i class="fa fa-check me-2"></i>Bulk Approve
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>
|
|
<input type="checkbox" id="selectAllPending">
|
|
</th>
|
|
<th>Patient</th>
|
|
<th>From</th>
|
|
<th>To</th>
|
|
<th>Type</th>
|
|
<th>Priority</th>
|
|
<th>Requested</th>
|
|
<th>Scheduled</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for transfer in pending_transfers %}
|
|
<tr class="{% if transfer.priority == 'critical' %}table-danger{% elif transfer.priority == 'urgent' %}table-warning{% endif %}">
|
|
<td>
|
|
<input type="checkbox" class="transfer-checkbox" value="{{ transfer.id }}">
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.patient.get_full_name }}</strong>
|
|
<br><small class="text-muted">{{ transfer.patient.patient_id }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.from_location }}</strong>
|
|
<br><small class="text-muted">{{ transfer.from_department }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.to_location }}</strong>
|
|
<br><small class="text-muted">{{ transfer.to_department }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ transfer.get_transfer_type_display }}</span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{{ transfer.priority_color }}">
|
|
{{ transfer.get_priority_display }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.requested_date|date:"M d, Y" }}</strong>
|
|
<br><small class="text-muted">{{ transfer.requested_by.get_full_name }}</small>
|
|
</div>
|
|
</td>
|
|
<td>{{ transfer.scheduled_datetime|date:"M d, Y H:i" }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button class="btn btn-outline-primary" onclick="viewTransfer('{{ transfer.id }}')" title="View">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
<button class="btn btn-outline-success" onclick="approveTransfer('{{ transfer.id }}')" title="Approve">
|
|
<i class="fa fa-check"></i>
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="editTransfer('{{ transfer.id }}')" title="Edit">
|
|
<i class="fa fa-edit"></i>
|
|
</button>
|
|
<button class="btn btn-outline-danger" onclick="rejectTransfer('{{ transfer.id }}')" title="Reject">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="9" class="text-center py-4">
|
|
<i class="fa fa-clock fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No pending transfers</h5>
|
|
<p class="text-muted">All transfer requests have been processed.</p>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Active Transfers Tab -->
|
|
<div class="tab-pane fade" id="active" role="tabpanel">
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" placeholder="Search active transfers..." id="activeSearch">
|
|
<button class="btn btn-outline-secondary" type="button">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select class="form-select" id="activeStatus">
|
|
<option value="">All Status</option>
|
|
<option value="in_progress">In Progress</option>
|
|
<option value="en_route">En Route</option>
|
|
<option value="arrived">Arrived</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-info w-100" onclick="refreshActiveTransfers()">
|
|
<i class="fa fa-sync me-2"></i>Refresh Status
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Patient</th>
|
|
<th>Transfer Route</th>
|
|
<th>Started</th>
|
|
<th>ETA</th>
|
|
<th>Status</th>
|
|
<th>Escort</th>
|
|
<th>Progress</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for transfer in active_transfers %}
|
|
<tr>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.patient.get_full_name }}</strong>
|
|
<br><small class="text-muted">{{ transfer.patient.patient_id }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<i class="fa fa-arrow-right text-muted"></i>
|
|
<strong>{{ transfer.from_location }}</strong> → <strong>{{ transfer.to_location }}</strong>
|
|
</div>
|
|
</td>
|
|
<td>{{ transfer.started_datetime|date:"M d, Y H:i" }}</td>
|
|
<td>{{ transfer.estimated_arrival|date:"H:i" }}</td>
|
|
<td>
|
|
<span class="badge bg-{{ transfer.status_color }}">
|
|
{{ transfer.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if transfer.escort_staff %}
|
|
{{ transfer.escort_staff.get_full_name }}
|
|
{% else %}
|
|
<span class="text-muted">None</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="progress" style="height: 20px;">
|
|
<div class="progress-bar" role="progressbar" style="width: {{ transfer.progress_percentage }}%">
|
|
{{ transfer.progress_percentage }}%
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button class="btn btn-outline-primary" onclick="trackTransfer('{{ transfer.id }}')" title="Track">
|
|
<i class="fa fa-map-marker-alt"></i>
|
|
</button>
|
|
<button class="btn btn-outline-info" onclick="updateStatus('{{ transfer.id }}')" title="Update Status">
|
|
<i class="fa fa-edit"></i>
|
|
</button>
|
|
<button class="btn btn-outline-success" onclick="completeTransfer('{{ transfer.id }}')" title="Complete">
|
|
<i class="fa fa-check"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="8" class="text-center py-4">
|
|
<i class="fa fa-spinner fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No active transfers</h5>
|
|
<p class="text-muted">No transfers are currently in progress.</p>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Transfer History Tab -->
|
|
<div class="tab-pane fade" id="history" role="tabpanel">
|
|
<div class="row mb-3">
|
|
<div class="col-md-3">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" placeholder="Search transfer history..." id="historySearch">
|
|
<button class="btn btn-outline-secondary" type="button">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select" id="historyPeriod">
|
|
<option value="7">Last 7 days</option>
|
|
<option value="30" selected>Last 30 days</option>
|
|
<option value="90">Last 90 days</option>
|
|
<option value="365">Last year</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select" id="historyStatus">
|
|
<option value="">All Status</option>
|
|
<option value="completed">Completed</option>
|
|
<option value="cancelled">Cancelled</option>
|
|
<option value="rejected">Rejected</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select" id="historyType">
|
|
<option value="">All Types</option>
|
|
<option value="internal">Internal</option>
|
|
<option value="external">External</option>
|
|
<option value="emergency">Emergency</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-outline-success w-100" onclick="exportHistory()">
|
|
<i class="fa fa-download me-2"></i>Export History
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Patient</th>
|
|
<th>Transfer Route</th>
|
|
<th>Date</th>
|
|
<th>Type</th>
|
|
<th>Duration</th>
|
|
<th>Status</th>
|
|
<th>Completed By</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for transfer in transfer_history %}
|
|
<tr>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.patient.get_full_name }}</strong>
|
|
<br><small class="text-muted">{{ transfer.patient.patient_id }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<i class="fa fa-arrow-right text-muted"></i>
|
|
<strong>{{ transfer.from_location }}</strong> → <strong>{{ transfer.to_location }}</strong>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
<strong>{{ transfer.completed_datetime|date:"M d, Y" }}</strong>
|
|
<br><small class="text-muted">{{ transfer.completed_datetime|time:"H:i" }}</small>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ transfer.get_transfer_type_display }}</span>
|
|
</td>
|
|
<td>{{ transfer.duration_minutes }} min</td>
|
|
<td>
|
|
<span class="badge bg-{{ transfer.status_color }}">
|
|
{{ transfer.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
{% if transfer.completed_by %}
|
|
{{ transfer.completed_by.get_full_name }}
|
|
{% else %}
|
|
<span class="text-muted">System</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button class="btn btn-outline-primary" onclick="viewTransferHistory('{{ transfer.id }}')" title="View Details">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
<button class="btn btn-outline-info" onclick="printTransferReport('{{ transfer.id }}')" title="Print Report">
|
|
<i class="fa fa-print"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="8" class="text-center py-4">
|
|
<i class="fa fa-history fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">No transfer history</h5>
|
|
<p class="text-muted">No completed transfers found for the selected period.</p>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
$(document).ready(function() {
|
|
setupEventHandlers();
|
|
setDefaultDateTime();
|
|
setupValidation();
|
|
});
|
|
|
|
function setupEventHandlers() {
|
|
// Patient selection
|
|
$('#patientSelect').on('change', function() {
|
|
var selectedOption = $(this).find('option:selected');
|
|
if (selectedOption.val()) {
|
|
var details = selectedOption.data('details');
|
|
displayPatientDetails(details);
|
|
$('#currentLocation').val(selectedOption.text().split(' - ')[1]);
|
|
} else {
|
|
hidePatientDetails();
|
|
$('#currentLocation').val('');
|
|
}
|
|
});
|
|
|
|
// Transfer type change
|
|
$('#transferType').on('change', function() {
|
|
var type = $(this).val();
|
|
toggleDestinationFields(type);
|
|
|
|
if (type === 'emergency') {
|
|
$('#priority').val('emergency');
|
|
}
|
|
});
|
|
|
|
// Department selection for internal transfers
|
|
$('#destinationDepartment').on('change', function() {
|
|
loadDepartmentWards($(this).val());
|
|
});
|
|
|
|
// Ward selection for internal transfers
|
|
$('#destinationWard').on('change', function() {
|
|
loadWardBeds($(this).val());
|
|
});
|
|
|
|
// Form submission
|
|
$('#transferForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
if (this.checkValidity()) {
|
|
submitTransfer();
|
|
}
|
|
$(this).addClass('was-validated');
|
|
});
|
|
|
|
// Select all checkbox
|
|
$('#selectAllPending').on('change', function() {
|
|
$('.transfer-checkbox').prop('checked', $(this).prop('checked'));
|
|
});
|
|
}
|
|
|
|
function setDefaultDateTime() {
|
|
var now = new Date();
|
|
now.setHours(now.getHours() + 1); // Default to 1 hour from now
|
|
var datetime = now.toISOString().slice(0, 16);
|
|
$('#scheduledDateTime').val(datetime);
|
|
}
|
|
|
|
function setupValidation() {
|
|
// Custom validation for destination fields
|
|
$('#destinationDepartment, #destinationWard').on('change', function() {
|
|
if ($(this).val()) {
|
|
$(this).removeClass('is-invalid').addClass('is-valid');
|
|
}
|
|
});
|
|
}
|
|
|
|
function displayPatientDetails(details) {
|
|
if (details) {
|
|
$('#displayPatientId').text(details.patient_id || 'N/A');
|
|
$('#displayCurrentBed').text(details.current_bed || 'N/A');
|
|
$('#displayAdmissionDate').text(details.admission_date || 'N/A');
|
|
$('#displayPhysician').text(details.attending_physician || 'N/A');
|
|
$('#patientDetails').show();
|
|
}
|
|
}
|
|
|
|
function hidePatientDetails() {
|
|
$('#patientDetails').hide();
|
|
}
|
|
|
|
function toggleDestinationFields(transferType) {
|
|
$('#internalDestination, #externalDestination').hide();
|
|
|
|
if (transferType === 'internal' || transferType === 'emergency') {
|
|
$('#internalDestination').show();
|
|
$('#destinationDepartment').prop('required', true);
|
|
$('#destinationWard').prop('required', true);
|
|
$('#destinationFacility').prop('required', false);
|
|
} else if (transferType === 'external') {
|
|
$('#externalDestination').show();
|
|
$('#destinationFacility').prop('required', true);
|
|
$('#destinationDepartment').prop('required', false);
|
|
$('#destinationWard').prop('required', false);
|
|
}
|
|
}
|
|
|
|
function loadDepartmentWards(departmentId) {
|
|
if (!departmentId) {
|
|
$('#destinationWard').prop('disabled', true).html('<option value="">Select ward...</option>');
|
|
return;
|
|
}
|
|
|
|
$.get('{% url "inpatients:get_department_wards" %}', {department_id: departmentId}, function(data) {
|
|
var wardSelect = $('#destinationWard');
|
|
wardSelect.html('<option value="">Select ward...</option>');
|
|
|
|
if (data.success && data.wards.length > 0) {
|
|
data.wards.forEach(function(ward) {
|
|
wardSelect.append(`<option value="${ward.id}">${ward.name} (${ward.available_beds} beds available)</option>`);
|
|
});
|
|
wardSelect.prop('disabled', false);
|
|
} else {
|
|
wardSelect.append('<option value="">No wards available</option>');
|
|
wardSelect.prop('disabled', true);
|
|
}
|
|
});
|
|
}
|
|
|
|
function loadWardBeds(wardId) {
|
|
if (!wardId) {
|
|
$('#destinationBed').prop('disabled', true).html('<option value="">Select bed...</option>');
|
|
return;
|
|
}
|
|
|
|
$.get('{% url "inpatients:get_available_beds" %}', {ward_id: wardId}, function(data) {
|
|
var bedSelect = $('#destinationBed');
|
|
bedSelect.html('<option value="">Select bed...</option>');
|
|
|
|
if (data.success && data.beds.length > 0) {
|
|
data.beds.forEach(function(bed) {
|
|
bedSelect.append(`<option value="${bed.id}">${bed.bed_number} - ${bed.room_number} (${bed.bed_type})</option>`);
|
|
});
|
|
bedSelect.prop('disabled', false);
|
|
} else {
|
|
bedSelect.append('<option value="">No beds available</option>');
|
|
bedSelect.prop('disabled', true);
|
|
}
|
|
});
|
|
}
|
|
|
|
function submitTransfer() {
|
|
var formData = $('#transferForm').serialize();
|
|
|
|
$.post('{% url "inpatients:submit_transfer" %}', formData, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Transfer request submitted successfully');
|
|
if (data.transfer_id) {
|
|
window.location.href = '{% url "inpatients:transfer_detail" 0 %}'.replace('0', data.transfer_id);
|
|
} else {
|
|
resetForm();
|
|
$('#pending-tab').click();
|
|
}
|
|
} else {
|
|
toastr.error('Failed to submit transfer request: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function saveAsDraft() {
|
|
var formData = $('#transferForm').serialize() + '&save_as_draft=true';
|
|
|
|
$.post('{% url "inpatients:save_transfer_draft" %}', formData, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Transfer request saved as draft');
|
|
} else {
|
|
toastr.error('Failed to save draft: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function resetForm() {
|
|
$('#transferForm')[0].reset();
|
|
$('#transferForm').removeClass('was-validated');
|
|
hidePatientDetails();
|
|
$('#currentLocation').val('');
|
|
$('#destinationWard, #destinationBed').prop('disabled', true).html('<option value="">Select...</option>');
|
|
$('#internalDestination, #externalDestination').hide();
|
|
setDefaultDateTime();
|
|
}
|
|
|
|
// Navigation functions
|
|
function initiateTransfer() {
|
|
$('#new-transfer-tab').click();
|
|
resetForm();
|
|
}
|
|
|
|
function viewPendingTransfers() {
|
|
$('#pending-tab').click();
|
|
}
|
|
|
|
function transferHistory() {
|
|
$('#history-tab').click();
|
|
}
|
|
|
|
function generateReport() {
|
|
window.location.href = '{% url "inpatients:transfer_reports" %}';
|
|
}
|
|
|
|
// Transfer management functions
|
|
function viewTransfer(transferId) {
|
|
window.location.href = '{% url "inpatients:transfer_detail" 0 %}'.replace('0', transferId);
|
|
}
|
|
|
|
function approveTransfer(transferId) {
|
|
if (confirm('Are you sure you want to approve this transfer?')) {
|
|
$.post('{% url "inpatients:approve_transfer" %}', {
|
|
transfer_id: transferId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Transfer approved');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to approve transfer: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function editTransfer(transferId) {
|
|
window.location.href = '{% url "inpatients:transfer_edit" 0 %}'.replace('0', transferId);
|
|
}
|
|
|
|
function rejectTransfer(transferId) {
|
|
var reason = prompt('Reason for rejection:');
|
|
if (reason) {
|
|
$.post('{% url "inpatients:reject_transfer" %}', {
|
|
transfer_id: transferId,
|
|
reason: reason,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Transfer rejected');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to reject transfer: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function bulkApprove() {
|
|
var selectedTransfers = $('.transfer-checkbox:checked').map(function() {
|
|
return $(this).val();
|
|
}).get();
|
|
|
|
if (selectedTransfers.length === 0) {
|
|
toastr.warning('Please select transfers to approve');
|
|
return;
|
|
}
|
|
|
|
if (confirm(`Are you sure you want to approve ${selectedTransfers.length} transfer(s)?`)) {
|
|
$.post('{% url "inpatients:bulk_approve_transfers" %}', {
|
|
transfer_ids: selectedTransfers,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success(`${data.approved_count} transfer(s) approved`);
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to approve transfers: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Active transfer functions
|
|
function trackTransfer(transferId) {
|
|
window.location.href = '{% url "inpatients:track_transfer" 0 %}'.replace('0', transferId);
|
|
}
|
|
|
|
function updateStatus(transferId) {
|
|
window.location.href = '{% url "inpatients:update_transfer_status" 0 %}'.replace('0', transferId);
|
|
}
|
|
|
|
function completeTransfer(transferId) {
|
|
if (confirm('Are you sure you want to mark this transfer as completed?')) {
|
|
$.post('{% url "inpatients:complete_transfer" %}', {
|
|
transfer_id: transferId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Transfer completed');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to complete transfer: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function refreshActiveTransfers() {
|
|
location.reload();
|
|
}
|
|
|
|
// History functions
|
|
function viewTransferHistory(transferId) {
|
|
window.location.href = '{% url "inpatients:transfer_history_detail" 0 %}'.replace('0', transferId);
|
|
}
|
|
|
|
function printTransferReport(transferId) {
|
|
window.open('{% url "inpatients:print_transfer_report" 0 %}'.replace('0', transferId), '_blank');
|
|
}
|
|
|
|
function exportHistory() {
|
|
var period = $('#historyPeriod').val();
|
|
var status = $('#historyStatus').val();
|
|
var type = $('#historyType').val();
|
|
|
|
var params = new URLSearchParams({
|
|
period: period,
|
|
status: status,
|
|
type: type
|
|
});
|
|
|
|
window.location.href = '{% url "inpatients:export_transfer_history" %}?' + params.toString();
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.nav-tabs .nav-link {
|
|
border: none;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.nav-tabs .nav-link.active {
|
|
background-color: transparent;
|
|
border-bottom: 2px solid #0d6efd;
|
|
color: #0d6efd;
|
|
}
|
|
|
|
.form-control:focus, .form-select:focus {
|
|
border-color: #86b7fe;
|
|
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
|
|
}
|
|
|
|
.was-validated .form-control:valid, .was-validated .form-select:valid {
|
|
border-color: #198754;
|
|
}
|
|
|
|
.was-validated .form-control:invalid, .was-validated .form-select:invalid {
|
|
border-color: #dc3545;
|
|
}
|
|
|
|
.table-danger {
|
|
background-color: rgba(220, 53, 69, 0.1);
|
|
}
|
|
|
|
.table-warning {
|
|
background-color: rgba(255, 193, 7, 0.1);
|
|
}
|
|
|
|
.badge {
|
|
font-size: 0.75em;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.btn-group-sm .btn {
|
|
padding: 0.25rem 0.5rem;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.alert {
|
|
border: none;
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
.progress {
|
|
background-color: #e9ecef;
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
.progress-bar {
|
|
background-color: #0d6efd;
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
.card-header-tabs {
|
|
margin-bottom: -1px;
|
|
}
|
|
|
|
.card-header-tabs .nav-link {
|
|
border: none;
|
|
border-bottom: 2px solid transparent;
|
|
}
|
|
|
|
.card-header-tabs .nav-link.active {
|
|
border-bottom-color: #0d6efd;
|
|
background-color: transparent;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.btn-group {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.btn-group .btn {
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.table-responsive {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.nav-tabs {
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.nav-tabs .nav-link {
|
|
font-size: 0.875rem;
|
|
padding: 0.5rem 0.75rem;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|