812 lines
35 KiB
HTML
812 lines
35 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if form.instance.pk %}Edit Transfusion{% else %}Start New Transfusion{% endif %}{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
<style>
|
|
.form-section {
|
|
background: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-bottom: 20px;
|
|
border-left: 4px solid #007bff;
|
|
}
|
|
|
|
.form-section h5 {
|
|
color: #007bff;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.required-field {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.patient-info {
|
|
background: #d4edda;
|
|
border-left: 4px solid #28a745;
|
|
}
|
|
|
|
.blood-unit-info {
|
|
background: #d1ecf1;
|
|
border-left: 4px solid #17a2b8;
|
|
}
|
|
|
|
.safety-checks {
|
|
background: #fff3cd;
|
|
border-left: 4px solid #ffc107;
|
|
}
|
|
|
|
.emergency-section {
|
|
background: #f8d7da;
|
|
border-left: 4px solid #dc3545;
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0% { opacity: 1; }
|
|
50% { opacity: 0.8; }
|
|
100% { opacity: 1; }
|
|
}
|
|
|
|
.compatibility-check {
|
|
background: #e2e3e5;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.safety-checklist {
|
|
background: #f8f9fa;
|
|
border: 2px solid #28a745;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.vital-signs-baseline {
|
|
background: #e9ecef;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.transfusion-preview {
|
|
background: #f8f9fa;
|
|
border: 2px dashed #6c757d;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
text-align: center;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
.rate-calculator {
|
|
background: #e2e3e5;
|
|
border-radius: 8px;
|
|
padding: 15px;
|
|
margin-top: 15px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:dashboard' %}">Blood Bank</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:transfusion_list' %}">Transfusions</a></li>
|
|
{% if form.instance.pk %}
|
|
<li class="breadcrumb-item"><a href="{% url 'blood_bank:transfusion_detail' form.instance.id %}">{{ form.instance.transfusion_id }}</a></li>
|
|
<li class="breadcrumb-item active">Edit</li>
|
|
{% else %}
|
|
<li class="breadcrumb-item active">Start Transfusion</li>
|
|
{% endif %}
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">
|
|
{% if form.instance.pk %}
|
|
Edit Transfusion <small>{{ form.instance.transfusion_id }}</small>
|
|
{% else %}
|
|
Start New Transfusion <small>patient blood administration</small>
|
|
{% endif %}
|
|
</h1>
|
|
<!-- END page-header -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fa fa-heartbeat"></i> Transfusion Information
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<span class="badge bg-info">Transfusion ID: {{ form.instance.transfusion_id|default:'Auto-generated' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<form method="post" id="transfusionForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- BEGIN patient information -->
|
|
<div class="form-section patient-info">
|
|
<h5><i class="fa fa-user-injured"></i> Patient Information</h5>
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="form-group">
|
|
<label for="{{ form.patient.id_for_label }}" class="form-label">
|
|
Patient <span class="required-field">*</span>
|
|
</label>
|
|
<select class="form-select" name="{{ form.patient.name }}" id="{{ form.patient.id_for_label }}" required>
|
|
<option value="">Select patient...</option>
|
|
{% for patient in form.patient.field.queryset %}
|
|
<option value="{{ patient.id }}"
|
|
data-blood-group="{{ patient.blood_group.display_name|default:'Unknown' }}"
|
|
data-age="{{ patient.age }}"
|
|
data-weight="{{ patient.weight|default:'Unknown' }}"
|
|
data-allergies="{{ patient.allergies|default:'None known' }}"
|
|
{% if form.patient.value == patient.id %}selected{% endif %}>
|
|
{{ patient.full_name }} ({{ patient.patient_id }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.patient.errors %}
|
|
<div class="text-danger">{{ form.patient.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Patient Details</label>
|
|
<div id="patientDetails" class="alert alert-info">
|
|
<i class="fa fa-info-circle"></i> Select a patient to view details
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END patient information -->
|
|
|
|
<!-- BEGIN blood unit selection -->
|
|
<div class="form-section blood-unit-info">
|
|
<h5><i class="fa fa-tint"></i> Blood Unit Selection</h5>
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="form-group">
|
|
<label for="{{ form.blood_unit.id_for_label }}" class="form-label">
|
|
Blood Unit <span class="required-field">*</span>
|
|
</label>
|
|
<select class="form-select" name="{{ form.blood_unit.name }}" id="{{ form.blood_unit.id_for_label }}" required>
|
|
<option value="">Select blood unit...</option>
|
|
{% for unit in form.blood_unit.field.queryset %}
|
|
<option value="{{ unit.id }}"
|
|
data-unit-number="{{ unit.unit_number }}"
|
|
data-blood-group="{{ unit.blood_group.display_name }}"
|
|
data-component="{{ unit.component.get_name_display }}"
|
|
data-volume="{{ unit.volume_ml }}"
|
|
data-expiry="{{ unit.expiry_date|date:'Y-m-d' }}"
|
|
data-donor="{{ unit.donor.full_name }}"
|
|
{% if form.blood_unit.value == unit.id %}selected{% endif %}>
|
|
{{ unit.unit_number }} - {{ unit.blood_group.display_name }} ({{ unit.component.get_name_display }})
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.blood_unit.errors %}
|
|
<div class="text-danger">{{ form.blood_unit.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Unit Details</label>
|
|
<div id="unitDetails" class="alert alert-info">
|
|
<i class="fa fa-info-circle"></i> Select a blood unit to view details
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Compatibility check -->
|
|
<div class="compatibility-check">
|
|
<h6><i class="fa fa-shield-alt"></i> Compatibility Check</h6>
|
|
<div id="compatibilityResults">
|
|
<p class="text-muted">Select patient and blood unit to perform compatibility check</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END blood unit selection -->
|
|
|
|
<!-- BEGIN transfusion parameters -->
|
|
<div class="form-section">
|
|
<h5><i class="fa fa-cogs"></i> Transfusion Parameters</h5>
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label for="{{ form.transfusion_rate.id_for_label }}" class="form-label">
|
|
Transfusion Rate (ml/hr)
|
|
</label>
|
|
<input type="number" class="form-control" name="{{ form.transfusion_rate.name }}"
|
|
id="{{ form.transfusion_rate.id_for_label }}"
|
|
value="{{ form.transfusion_rate.value|default:'100' }}" min="10" max="500">
|
|
{% if form.transfusion_rate.errors %}
|
|
<div class="text-danger">{{ form.transfusion_rate.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label for="{{ form.start_time.id_for_label }}" class="form-label">
|
|
Start Time <span class="required-field">*</span>
|
|
</label>
|
|
<input type="datetime-local" class="form-control" name="{{ form.start_time.name }}"
|
|
id="{{ form.start_time.id_for_label }}"
|
|
value="{{ form.start_time.value|date:'Y-m-d\TH:i' }}" required>
|
|
{% if form.start_time.errors %}
|
|
<div class="text-danger">{{ form.start_time.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label class="form-label">Estimated Duration</label>
|
|
<input type="text" class="form-control" id="estimatedDuration" readonly
|
|
placeholder="Will be calculated">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rate calculator -->
|
|
<div class="rate-calculator">
|
|
<h6><i class="fa fa-calculator"></i> Rate Calculator</h6>
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label class="form-label">Patient Weight (kg)</label>
|
|
<input type="number" class="form-control" id="patientWeight" placeholder="Enter weight">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Recommended Rate</label>
|
|
<select class="form-select" id="rateType">
|
|
<option value="slow">Slow (1-2 ml/kg/hr)</option>
|
|
<option value="standard" selected>Standard (3-5 ml/kg/hr)</option>
|
|
<option value="fast">Fast (5-10 ml/kg/hr)</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Calculated Rate</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="calculatedRate" readonly>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="applyCalculatedRate()">
|
|
Apply
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END transfusion parameters -->
|
|
|
|
<!-- BEGIN baseline vital signs -->
|
|
<div class="form-section">
|
|
<h5><i class="fa fa-heartbeat"></i> Baseline Vital Signs</h5>
|
|
<div class="vital-signs-baseline">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="form-group">
|
|
<label for="baselineBloodPressure" class="form-label">
|
|
Blood Pressure <span class="required-field">*</span>
|
|
</label>
|
|
<input type="text" class="form-control" id="baselineBloodPressure"
|
|
placeholder="120/80" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-group">
|
|
<label for="baselineHeartRate" class="form-label">
|
|
Heart Rate (bpm) <span class="required-field">*</span>
|
|
</label>
|
|
<input type="number" class="form-control" id="baselineHeartRate"
|
|
placeholder="72" min="40" max="200" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-group">
|
|
<label for="baselineTemperature" class="form-label">
|
|
Temperature (°C) <span class="required-field">*</span>
|
|
</label>
|
|
<input type="number" step="0.1" class="form-control" id="baselineTemperature"
|
|
placeholder="36.5" min="35" max="42" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="form-group">
|
|
<label for="baselineOxygenSat" class="form-label">
|
|
O2 Saturation (%)
|
|
</label>
|
|
<input type="number" class="form-control" id="baselineOxygenSat"
|
|
placeholder="98" min="70" max="100">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END baseline vital signs -->
|
|
|
|
<!-- BEGIN safety checklist -->
|
|
<div class="form-section safety-checks">
|
|
<h5><i class="fa fa-shield-alt"></i> Pre-Transfusion Safety Checklist</h5>
|
|
<div class="safety-checklist">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<h6>Patient Verification</h6>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="patientIdVerified" required>
|
|
<label class="form-check-label" for="patientIdVerified">
|
|
Patient identity verified (2 identifiers)
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="consentObtained" required>
|
|
<label class="form-check-label" for="consentObtained">
|
|
Informed consent obtained
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="allergiesChecked" required>
|
|
<label class="form-check-label" for="allergiesChecked">
|
|
Allergies and medical history reviewed
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Blood Unit Verification</h6>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="unitNumberVerified" required>
|
|
<label class="form-check-label" for="unitNumberVerified">
|
|
Blood unit number verified
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="bloodGroupVerified" required>
|
|
<label class="form-check-label" for="bloodGroupVerified">
|
|
Blood group compatibility verified
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="expiryChecked" required>
|
|
<label class="form-check-label" for="expiryChecked">
|
|
Expiry date checked and valid
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-md-6">
|
|
<h6>Clinical Assessment</h6>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="vitalSignsRecorded" required>
|
|
<label class="form-check-label" for="vitalSignsRecorded">
|
|
Baseline vital signs recorded
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="ivAccessVerified" required>
|
|
<label class="form-check-label" for="ivAccessVerified">
|
|
IV access verified and patent
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h6>Equipment & Environment</h6>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="equipmentChecked" required>
|
|
<label class="form-check-label" for="equipmentChecked">
|
|
Transfusion equipment checked
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="emergencyEquipment" required>
|
|
<label class="form-check-label" for="emergencyEquipment">
|
|
Emergency equipment available
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END safety checklist -->
|
|
|
|
<!-- BEGIN special instructions -->
|
|
<div class="form-section">
|
|
<h5><i class="fa fa-clipboard-list"></i> Special Instructions & Notes</h5>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="form-group">
|
|
<label for="{{ form.notes.id_for_label }}" class="form-label">Transfusion Notes</label>
|
|
<textarea class="form-control" name="{{ form.notes.name }}"
|
|
id="{{ form.notes.id_for_label }}" rows="3"
|
|
placeholder="Any special instructions, precautions, or observations...">{{ form.notes.value|default:'' }}</textarea>
|
|
{% if form.notes.errors %}
|
|
<div class="text-danger">{{ form.notes.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="{{ form.started_by.id_for_label }}" class="form-label">
|
|
Started By <span class="required-field">*</span>
|
|
</label>
|
|
<select class="form-select" name="{{ form.started_by.name }}" id="{{ form.started_by.id_for_label }}" required>
|
|
<option value="">Select staff member...</option>
|
|
{% for staff in form.started_by.field.queryset %}
|
|
<option value="{{ staff.id }}" {% if form.started_by.value == staff.id %}selected{% endif %}>
|
|
{{ staff.get_full_name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.started_by.errors %}
|
|
<div class="text-danger">{{ form.started_by.errors.0 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-group">
|
|
<label for="witnessedBy" class="form-label">
|
|
Witnessed By <span class="required-field">*</span>
|
|
</label>
|
|
<select class="form-select" id="witnessedBy" name="witnessed_by" required>
|
|
<option value="">Select witness...</option>
|
|
{% for staff in form.started_by.field.queryset %}
|
|
<option value="{{ staff.id }}">{{ staff.get_full_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END special instructions -->
|
|
|
|
<!-- BEGIN transfusion preview -->
|
|
<div class="transfusion-preview">
|
|
<h5><i class="fa fa-eye"></i> Transfusion Preview</h5>
|
|
<div id="transfusionPreview">
|
|
<p class="text-muted">Complete the form to preview transfusion details</p>
|
|
</div>
|
|
</div>
|
|
<!-- END transfusion preview -->
|
|
|
|
<!-- BEGIN form actions -->
|
|
<div class="d-flex justify-content-between mt-4">
|
|
<a href="{% if form.instance.pk %}{% url 'blood_bank:transfusion_detail' form.instance.id %}{% else %}{% url 'blood_bank:transfusion_list' %}{% endif %}"
|
|
class="btn btn-secondary">
|
|
<i class="fa fa-arrow-left"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="button" class="btn btn-info" onclick="validateTransfusion()">
|
|
<i class="fa fa-check"></i> Validate
|
|
</button>
|
|
<button type="submit" class="btn btn-primary" id="submitBtn" disabled>
|
|
<i class="fa fa-play"></i>
|
|
{% if form.instance.pk %}Update Transfusion{% else %}Start Transfusion{% endif %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- END form actions -->
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize Select2
|
|
$('#{{ form.patient.id_for_label }}, #{{ form.blood_unit.id_for_label }}, #{{ form.started_by.id_for_label }}, #witnessedBy').select2({
|
|
theme: 'bootstrap-5'
|
|
});
|
|
|
|
// Set default start time to now
|
|
if (!$('#{{ form.start_time.id_for_label }}').val()) {
|
|
var now = new Date();
|
|
$('#{{ form.start_time.id_for_label }}').val(now.toISOString().slice(0, 16));
|
|
}
|
|
|
|
// Update displays when form changes
|
|
updatePatientDetails();
|
|
updateUnitDetails();
|
|
updateCompatibilityCheck();
|
|
updateTransfusionPreview();
|
|
calculateDuration();
|
|
|
|
// Event listeners
|
|
$('#{{ form.patient.id_for_label }}').on('change', function() {
|
|
updatePatientDetails();
|
|
updateCompatibilityCheck();
|
|
updateTransfusionPreview();
|
|
updatePatientWeight();
|
|
});
|
|
|
|
$('#{{ form.blood_unit.id_for_label }}').on('change', function() {
|
|
updateUnitDetails();
|
|
updateCompatibilityCheck();
|
|
updateTransfusionPreview();
|
|
calculateDuration();
|
|
});
|
|
|
|
$('#{{ form.transfusion_rate.id_for_label }}').on('change', function() {
|
|
calculateDuration();
|
|
updateTransfusionPreview();
|
|
});
|
|
|
|
$('#patientWeight, #rateType').on('change', function() {
|
|
calculateRecommendedRate();
|
|
});
|
|
|
|
// Safety checklist validation
|
|
$('.safety-checklist input[type="checkbox"]').on('change', function() {
|
|
validateSafetyChecklist();
|
|
});
|
|
|
|
// Form validation
|
|
$('#transfusionForm').on('submit', function(e) {
|
|
if (!validateTransfusion()) {
|
|
e.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
|
|
function updatePatientDetails() {
|
|
var patientId = $('#{{ form.patient.id_for_label }}').val();
|
|
if (!patientId) {
|
|
$('#patientDetails').html('<i class="fa fa-info-circle"></i> Select a patient to view details').removeClass().addClass('alert alert-info');
|
|
return;
|
|
}
|
|
|
|
var selectedOption = $('#{{ form.patient.id_for_label }} option:selected');
|
|
var bloodGroup = selectedOption.data('blood-group');
|
|
var age = selectedOption.data('age');
|
|
var weight = selectedOption.data('weight');
|
|
var allergies = selectedOption.data('allergies');
|
|
|
|
var detailsHtml = '<strong>Blood Group:</strong> ' + (bloodGroup || 'Unknown') + '<br>';
|
|
detailsHtml += '<strong>Age:</strong> ' + (age || 'Unknown') + '<br>';
|
|
detailsHtml += '<strong>Weight:</strong> ' + (weight || 'Unknown') + ' kg<br>';
|
|
detailsHtml += '<strong>Allergies:</strong> ' + (allergies || 'None known');
|
|
|
|
$('#patientDetails').html(detailsHtml).removeClass().addClass('alert alert-success');
|
|
}
|
|
|
|
function updateUnitDetails() {
|
|
var unitId = $('#{{ form.blood_unit.id_for_label }}').val();
|
|
if (!unitId) {
|
|
$('#unitDetails').html('<i class="fa fa-info-circle"></i> Select a blood unit to view details').removeClass().addClass('alert alert-info');
|
|
return;
|
|
}
|
|
|
|
var selectedOption = $('#{{ form.blood_unit.id_for_label }} option:selected');
|
|
var unitNumber = selectedOption.data('unit-number');
|
|
var bloodGroup = selectedOption.data('blood-group');
|
|
var component = selectedOption.data('component');
|
|
var volume = selectedOption.data('volume');
|
|
var expiry = selectedOption.data('expiry');
|
|
var donor = selectedOption.data('donor');
|
|
|
|
var detailsHtml = '<strong>Unit:</strong> ' + unitNumber + '<br>';
|
|
detailsHtml += '<strong>Blood Group:</strong> ' + bloodGroup + '<br>';
|
|
detailsHtml += '<strong>Component:</strong> ' + component + '<br>';
|
|
detailsHtml += '<strong>Volume:</strong> ' + volume + ' ml<br>';
|
|
detailsHtml += '<strong>Expiry:</strong> ' + new Date(expiry).toLocaleDateString() + '<br>';
|
|
detailsHtml += '<strong>Donor:</strong> ' + donor;
|
|
|
|
// Check expiry
|
|
var expiryDate = new Date(expiry);
|
|
var today = new Date();
|
|
var alertClass = expiryDate > today ? 'alert-success' : 'alert-danger';
|
|
|
|
$('#unitDetails').html(detailsHtml).removeClass().addClass('alert ' + alertClass);
|
|
}
|
|
|
|
function updateCompatibilityCheck() {
|
|
var patientId = $('#{{ form.patient.id_for_label }}').val();
|
|
var unitId = $('#{{ form.blood_unit.id_for_label }}').val();
|
|
|
|
if (!patientId || !unitId) {
|
|
$('#compatibilityResults').html('<p class="text-muted">Select patient and blood unit to perform compatibility check</p>');
|
|
return;
|
|
}
|
|
|
|
var patientOption = $('#{{ form.patient.id_for_label }} option:selected');
|
|
var unitOption = $('#{{ form.blood_unit.id_for_label }} option:selected');
|
|
|
|
var patientBloodGroup = patientOption.data('blood-group');
|
|
var unitBloodGroup = unitOption.data('blood-group');
|
|
|
|
if (!patientBloodGroup || patientBloodGroup === 'Unknown') {
|
|
$('#compatibilityResults').html('<div class="alert alert-warning"><i class="fa fa-exclamation-triangle"></i> Patient blood group unknown - type and screen required</div>');
|
|
return;
|
|
}
|
|
|
|
// Simple compatibility check (in real implementation, this would be more complex)
|
|
var compatible = patientBloodGroup === unitBloodGroup || unitBloodGroup === 'O-' ||
|
|
(patientBloodGroup.includes('+') && unitBloodGroup.includes('-'));
|
|
|
|
if (compatible) {
|
|
$('#compatibilityResults').html('<div class="alert alert-success"><i class="fa fa-check-circle"></i> Compatible blood groups - crossmatch verification required</div>');
|
|
} else {
|
|
$('#compatibilityResults').html('<div class="alert alert-danger"><i class="fa fa-times-circle"></i> Potential incompatibility detected - immediate verification required</div>');
|
|
}
|
|
}
|
|
|
|
function updatePatientWeight() {
|
|
var patientOption = $('#{{ form.patient.id_for_label }} option:selected');
|
|
var weight = patientOption.data('weight');
|
|
|
|
if (weight && weight !== 'Unknown') {
|
|
$('#patientWeight').val(weight);
|
|
calculateRecommendedRate();
|
|
}
|
|
}
|
|
|
|
function calculateRecommendedRate() {
|
|
var weight = parseFloat($('#patientWeight').val());
|
|
var rateType = $('#rateType').val();
|
|
|
|
if (!weight) {
|
|
$('#calculatedRate').val('');
|
|
return;
|
|
}
|
|
|
|
var multiplier;
|
|
switch(rateType) {
|
|
case 'slow': multiplier = 1.5; break;
|
|
case 'standard': multiplier = 4; break;
|
|
case 'fast': multiplier = 7.5; break;
|
|
default: multiplier = 4;
|
|
}
|
|
|
|
var calculatedRate = Math.round(weight * multiplier);
|
|
$('#calculatedRate').val(calculatedRate + ' ml/hr');
|
|
}
|
|
|
|
function applyCalculatedRate() {
|
|
var calculatedRate = $('#calculatedRate').val();
|
|
if (calculatedRate) {
|
|
var rate = parseInt(calculatedRate.split(' ')[0]);
|
|
$('#{{ form.transfusion_rate.id_for_label }}').val(rate);
|
|
calculateDuration();
|
|
updateTransfusionPreview();
|
|
}
|
|
}
|
|
|
|
function calculateDuration() {
|
|
var unitOption = $('#{{ form.blood_unit.id_for_label }} option:selected');
|
|
var volume = unitOption.data('volume');
|
|
var rate = $('#{{ form.transfusion_rate.id_for_label }}').val();
|
|
|
|
if (volume && rate) {
|
|
var hours = volume / rate;
|
|
var totalMinutes = Math.round(hours * 60);
|
|
var displayHours = Math.floor(totalMinutes / 60);
|
|
var displayMinutes = totalMinutes % 60;
|
|
|
|
var duration = displayHours + 'h ' + displayMinutes + 'm';
|
|
$('#estimatedDuration').val(duration);
|
|
}
|
|
}
|
|
|
|
function updateTransfusionPreview() {
|
|
var patientOption = $('#{{ form.patient.id_for_label }} option:selected');
|
|
var unitOption = $('#{{ form.blood_unit.id_for_label }} option:selected');
|
|
var rate = $('#{{ form.transfusion_rate.id_for_label }}').val();
|
|
var startTime = $('#{{ form.start_time.id_for_label }}').val();
|
|
|
|
if (!patientOption.val() || !unitOption.val()) {
|
|
$('#transfusionPreview').html('<p class="text-muted">Complete the form to preview transfusion details</p>');
|
|
return;
|
|
}
|
|
|
|
var previewHtml = '<div class="row">';
|
|
previewHtml += '<div class="col-md-6">';
|
|
previewHtml += '<h6>Patient: ' + patientOption.text().split(' (')[0] + '</h6>';
|
|
previewHtml += '<p>Blood Group: ' + patientOption.data('blood-group') + '</p>';
|
|
previewHtml += '</div>';
|
|
previewHtml += '<div class="col-md-6">';
|
|
previewHtml += '<h6>Unit: ' + unitOption.data('unit-number') + '</h6>';
|
|
previewHtml += '<p>Component: ' + unitOption.data('component') + '</p>';
|
|
previewHtml += '</div>';
|
|
previewHtml += '</div>';
|
|
|
|
if (rate && startTime) {
|
|
previewHtml += '<hr>';
|
|
previewHtml += '<p><strong>Rate:</strong> ' + rate + ' ml/hr</p>';
|
|
previewHtml += '<p><strong>Start Time:</strong> ' + new Date(startTime).toLocaleString() + '</p>';
|
|
previewHtml += '<p><strong>Estimated Duration:</strong> ' + $('#estimatedDuration').val() + '</p>';
|
|
}
|
|
|
|
$('#transfusionPreview').html(previewHtml);
|
|
}
|
|
|
|
function validateSafetyChecklist() {
|
|
var checkboxes = $('.safety-checklist input[type="checkbox"]');
|
|
var checkedCount = checkboxes.filter(':checked').length;
|
|
var totalCount = checkboxes.length;
|
|
|
|
$('#submitBtn').prop('disabled', checkedCount < totalCount);
|
|
|
|
if (checkedCount === totalCount) {
|
|
$('.safety-checklist').removeClass('border-warning').addClass('border-success');
|
|
} else {
|
|
$('.safety-checklist').removeClass('border-success').addClass('border-warning');
|
|
}
|
|
}
|
|
|
|
function validateTransfusion() {
|
|
var errors = [];
|
|
|
|
// Check required fields
|
|
if (!$('#{{ form.patient.id_for_label }}').val()) {
|
|
errors.push('Please select a patient');
|
|
}
|
|
|
|
if (!$('#{{ form.blood_unit.id_for_label }}').val()) {
|
|
errors.push('Please select a blood unit');
|
|
}
|
|
|
|
if (!$('#{{ form.started_by.id_for_label }}').val()) {
|
|
errors.push('Please select who is starting the transfusion');
|
|
}
|
|
|
|
if (!$('#witnessedBy').val()) {
|
|
errors.push('Please select a witness');
|
|
}
|
|
|
|
// Check baseline vitals
|
|
if (!$('#baselineBloodPressure').val() || !$('#baselineHeartRate').val() || !$('#baselineTemperature').val()) {
|
|
errors.push('Please record baseline vital signs');
|
|
}
|
|
|
|
// Check safety checklist
|
|
var checkboxes = $('.safety-checklist input[type="checkbox"]');
|
|
var checkedCount = checkboxes.filter(':checked').length;
|
|
|
|
if (checkedCount < checkboxes.length) {
|
|
errors.push('Please complete all safety checklist items');
|
|
}
|
|
|
|
// Check compatibility
|
|
var compatibilityAlert = $('#compatibilityResults .alert-danger');
|
|
if (compatibilityAlert.length > 0) {
|
|
errors.push('Blood compatibility issue detected - resolve before proceeding');
|
|
}
|
|
|
|
if (errors.length > 0) {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Validation Errors',
|
|
html: '<ul class="text-start"><li>' + errors.join('</li><li>') + '</li></ul>',
|
|
confirmButtonText: 'OK'
|
|
});
|
|
return false;
|
|
}
|
|
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Validation Passed',
|
|
text: 'All safety checks completed. Ready to start transfusion.',
|
|
timer: 1500,
|
|
showConfirmButton: false
|
|
});
|
|
|
|
return true;
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|