Marwan Alwali 610e165e17 update
2025-09-04 19:19:52 +03:00

566 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% load static %}
{% block title %}{% if object %}Edit{% else %}Create{% endif %} Surgical Case - Operating Theatre{% endblock %}
{% block css %}
<link href="{% static 'plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
<link href="{% static 'plugins/bootstrap-timepicker/css/bootstrap-timepicker.min.css' %}" rel="stylesheet" />
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
{% endblock %}
{% block content %}
<!-- Breadcrumb -->
<ol class="breadcrumb float-xl-end">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item"><a href="{% url 'operating_theatre:dashboard' %}">Operating Theatre</a></li>
<li class="breadcrumb-item"><a href="{% url 'operating_theatre:surgical_case_list' %}">Surgical Cases</a></li>
<li class="breadcrumb-item active">{% if object %}Edit{% else %}Create{% endif %} Case</li>
</ol>
<h1 class="page-header">
{% if object %}Edit Surgical Case{% else %}Create Surgical Case{% endif %}
<small>{% if object %}{{ object.case_number }}{% else %}New Surgery Scheduling{% endif %}</small>
</h1>
<div class="row">
<div class="col-xl-8">
<!-- Main panel -->
<div class="panel panel-inverse">
<div class="panel-heading">
<h4 class="panel-title">Case Information</h4>
<div class="panel-heading-btn">
<button type="button" class="btn btn-xs btn-secondary me-2" onclick="saveDraft()">
<i class="fa fa-save"></i> Save Draft
</button>
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
</div>
</div>
<div class="panel-body">
<form method="post" id="case-form" novalidate>
{% csrf_token %}
<!-- Patient -->
<h6 class="border-bottom pb-2 mb-3">Patient Information</h6>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.patient }}
<label for="{{ form.patient.id_for_label }}">Patient <span class="text-danger">*</span></label>
{% if form.patient.errors %}<div class="invalid-feedback d-block">{{ form.patient.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div id="patient-info" class="mt-2" style="display:none;">
<div class="alert alert-info"><div id="patient-details"></div></div>
</div>
</div>
</div>
<!-- Surgery -->
<h6 class="border-bottom pb-2 mb-3">Surgery Information</h6>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.procedure_name }}
<label for="{{ form.procedure_name.id_for_label }}">Procedure Name <span class="text-danger">*</span></label>
{% if form.procedure_name.errors %}<div class="invalid-feedback d-block">{{ form.procedure_name.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.procedure_code }}
<label for="{{ form.procedure_code.id_for_label }}">Procedure Code</label>
{% if form.procedure_code.errors %}<div class="invalid-feedback d-block">{{ form.procedure_code.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.surgery_type }}
<label for="{{ form.surgery_type.id_for_label }}">Surgery Type <span class="text-danger">*</span></label>
{% if form.surgery_type.errors %}<div class="invalid-feedback d-block">{{ form.surgery_type.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.priority }}
<label for="{{ form.priority.id_for_label }}">Priority <span class="text-danger">*</span></label>
{% if form.priority.errors %}<div class="invalid-feedback d-block">{{ form.priority.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.estimated_duration }}
<label for="{{ form.estimated_duration.id_for_label }}">Estimated Duration (minutes) <span class="text-danger">*</span></label>
{% if form.estimated_duration.errors %}<div class="invalid-feedback d-block">{{ form.estimated_duration.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<!-- Scheduling -->
<h6 class="border-bottom pb-2 mb-3">Scheduling Information</h6>
<div class="row mb-3">
<div class="col-md-4">
<div class="form-floating">
{{ form.operating_room }}
<label for="{{ form.operating_room.id_for_label }}">Operating Room <span class="text-danger">*</span></label>
{% if form.operating_room.errors %}<div class="invalid-feedback d-block">{{ form.operating_room.errors.0 }}</div>{% endif %}
</div>
</div>
{# Prefer unified DateTimeField if available #}
{% if form.scheduled_start %}
<div class="col-md-8">
<div class="form-floating">
{{ form.scheduled_start }}
<label for="{{ form.scheduled_start.id_for_label }}">Scheduled Start <span class="text-danger">*</span></label>
{% if form.scheduled_start.errors %}<div class="invalid-feedback d-block">{{ form.scheduled_start.errors.0 }}</div>{% endif %}
</div>
</div>
{% else %}
<div class="col-md-4">
<div class="form-floating">
{{ form.scheduled_date }}
<label for="{{ form.scheduled_date.id_for_label }}">Scheduled Date <span class="text-danger">*</span></label>
{% if form.scheduled_date.errors %}<div class="invalid-feedback d-block">{{ form.scheduled_date.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-4">
<div class="form-floating">
{{ form.scheduled_start_time }}
<label for="{{ form.scheduled_start_time.id_for_label }}">Start Time <span class="text-danger">*</span></label>
{% if form.scheduled_start_time.errors %}<div class="invalid-feedback d-block">{{ form.scheduled_start_time.errors.0 }}</div>{% endif %}
</div>
</div>
{% endif %}
</div>
<!-- Availability banner -->
<div class="row mb-3">
<div class="col-md-12">
<div id="room-availability" class="alert alert-info" style="display:none;">
<i class="fa fa-info-circle me-2"></i><span id="availability-message"></span>
</div>
</div>
</div>
<!-- Team -->
<h6 class="border-bottom pb-2 mb-3">Surgical Team</h6>
<div class="row mb-3">
<div class="col-md-6">
<div class="form-floating">
{{ form.primary_surgeon }}
<label for="{{ form.primary_surgeon.id_for_label }}">Primary Surgeon <span class="text-danger">*</span></label>
{% if form.primary_surgeon.errors %}<div class="invalid-feedback d-block">{{ form.primary_surgeon.errors.0 }}</div>{% endif %}
</div>
</div>
<div class="col-md-6">
<div class="form-floating">
{{ form.anesthesiologist }}
<label for="{{ form.anesthesiologist.id_for_label }}">Anesthesiologist</label>
{% if form.anesthesiologist.errors %}<div class="invalid-feedback d-block">{{ form.anesthesiologist.errors.0 }}</div>{% endif %}
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Additional Team Members</label>
<div id="team-members">
{% if object %}
{% for team_member in object.surgical_team.all %}
<div class="team-member-row mb-2">
<div class="row">
<div class="col-md-5">
<select class="form-select" name="team_member_staff">
<option value="{{ team_member.staff_member.id }}" selected>{{ team_member.staff_member.get_full_name }}</option>
</select>
</div>
<div class="col-md-5">
<input type="text" class="form-control" name="team_member_role" value="{{ team_member.role }}" placeholder="Role">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger" onclick="removeTeamMember(this)"><i class="fa fa-times"></i></button>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addTeamMember()">
<i class="fa fa-plus me-2"></i>Add Team Member
</button>
</div>
<!-- Equipment & Supplies -->
<h6 class="border-bottom pb-2 mb-3">Equipment & Supplies</h6>
<div class="row mb-3">
<div class="col-md-6">
<label class="form-label">Required Equipment</label>
<div id="equipment-list">
{% if object %}
{% for equipment in object.equipment_required.all %}
<div class="equipment-item mb-2">
<div class="input-group">
<select class="form-select" name="equipment">
<option value="{{ equipment.id }}" selected>{{ equipment.name }}</option>
</select>
<button type="button" class="btn btn-outline-danger" onclick="removeEquipment(this)"><i class="fa fa-times"></i></button>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addEquipment()">
<i class="fa fa-plus me-2"></i>Add Equipment
</button>
</div>
<div class="col-md-6">
<label class="form-label">Required Supplies</label>
<div id="supplies-list">
{% if object %}
{% for supply in object.supplies_required.all %}
<div class="supply-item mb-2">
<div class="row">
<div class="col-8">
<select class="form-select" name="supply">
<option value="{{ supply.item.id }}" selected>{{ supply.item.name }}</option>
</select>
</div>
<div class="col-3">
<input type="number" class="form-control" name="supply_quantity" value="{{ supply.quantity }}" placeholder="Qty" min="1">
</div>
<div class="col-1">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeSupply(this)"><i class="fa fa-times"></i></button>
</div>
</div>
</div>
{% endfor %}
{% endif %}
</div>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addSupply()">
<i class="fa fa-plus me-2"></i>Add Supply
</button>
</div>
</div>
<!-- Notes -->
<h6 class="border-bottom pb-2 mb-3">Clinical Notes</h6>
<div class="mb-3">
<label class="form-label">Pre-operative Notes</label>
{{ form.pre_operative_notes }}
{% if form.pre_operative_notes.help_text %}<div class="form-text">{{ form.pre_operative_notes.help_text }}</div>{% endif %}
{% if form.pre_operative_notes.errors %}<div class="invalid-feedback d-block">{{ form.pre_operative_notes.errors.0 }}</div>{% endif %}
</div>
<div class="mb-3">
<label class="form-label">Special Instructions</label>
{{ form.special_instructions }}
{% if form.special_instructions.help_text %}<div class="form-text">{{ form.special_instructions.help_text }}</div>{% endif %}
{% if form.special_instructions.errors %}<div class="invalid-feedback d-block">{{ form.special_instructions.errors.0 }}</div>{% endif %}
</div>
<!-- Actions -->
<div class="d-flex justify-content-between mt-4">
<a href="{% url 'operating_theatre:surgical_case_list' %}" class="btn btn-secondary">
<i class="fa fa-arrow-left me-2"></i>Cancel
</a>
<div>
<button type="button" class="btn btn-info me-2" onclick="saveDraft()">
<i class="fa fa-save me-2"></i>Save Draft
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-check me-2"></i>{% if object %}Update{% else %}Schedule{% endif %} Surgery
</button>
</div>
</div>
</form>
</div>
</div>
<!-- /Main panel -->
</div>
<div class="col-xl-4">
<!-- Guidelines -->
<div class="panel panel-inverse">
<div class="panel-heading"><h4 class="panel-title">Scheduling Guidelines</h4></div>
<div class="panel-body">
<div class="alert alert-info">
<h6 class="alert-heading">Surgery Scheduling Tips</h6>
<ul class="mb-0 small">
<li>Check room availability before scheduling</li>
<li>Ensure all team members are available</li>
<li>Verify equipment and supplies are in stock</li>
<li>Consider patient preparation time</li>
<li>Allow buffer time between surgeries</li>
</ul>
</div>
<div class="alert alert-warning">
<h6 class="alert-heading">Priority Guidelines</h6>
<ul class="mb-0 small">
<li><strong>Emergency:</strong> Life-threatening conditions</li>
<li><strong>Urgent:</strong> Within 2448 hours</li>
<li><strong>Elective:</strong> Scheduled in advance</li>
</ul>
</div>
</div>
</div>
<!-- Room schedule -->
<div class="panel panel-inverse">
<div class="panel-heading"><h4 class="panel-title">Room Schedule</h4></div>
<div class="panel-body">
<div id="room-schedule">
<p class="text-muted mb-0">Select a room and date to view schedule</p>
</div>
</div>
</div>
{% if object %}
<!-- Case status -->
<div class="panel panel-inverse">
<div class="panel-heading"><h4 class="panel-title">Case Status</h4></div>
<div class="panel-body">
<table class="table table-borderless table-sm">
<tr>
<td class="fw-bold" width="110">Status:</td>
<td>
<span class="badge bg-{% if object.status == 'SCHEDULED' %}info{% elif object.status == 'IN_PROGRESS' %}warning{% elif object.status == 'COMPLETED' %}success{% else %}secondary{% endif %}">
{{ object.get_status_display }}
</span>
</td>
</tr>
<tr>
<td class="fw-bold">Created:</td>
<td>{{ object.created_at|date:"M d, Y H:i" }}</td>
</tr>
<tr>
<td class="fw-bold">Case #:</td>
<td><code>{{ object.case_number }}</code></td>
</tr>
{% if object.scheduled_start %}
<tr>
<td class="fw-bold">Scheduled:</td>
<td>{{ object.scheduled_start|date:"M d, Y H:i" }}</td>
</tr>
{% endif %}
</table>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock %}
{% block js %}
<script src="{% static 'plugins/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-timepicker/js/bootstrap-timepicker.min.js' %}"></script>
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
<script>
// --- CSRF via cookie (consistent across app) ---
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
// --- Init widgets (fallbacks for split date/time fields) ---
$(function() {
// Select2 theme
$('select').select2({ theme: 'bootstrap-5', width: '100%' });
// Only init if the inputs exist (supports unified scheduled_start alternative)
if ($('#id_scheduled_date').length) {
$('#id_scheduled_date').datepicker({ format: 'yyyy-mm-dd', startDate: 'today', autoclose: true });
}
if ($('#id_scheduled_start_time').length) {
$('#id_scheduled_start_time').timepicker({ showMeridian: false, defaultTime: '08:00' });
}
// Patient info
$('#id_patient').on('change', function() {
const id = $(this).val();
if (!id) return $('#patient-info').hide();
loadPatientInfo(id);
});
// Room/date/time changes -> availability & schedule
$('#id_operating_room, #id_scheduled_date, #id_scheduled_start_time, #id_scheduled_start, #id_estimated_duration').on('change', function() {
checkRoomAvailability();
loadRoomSchedule();
});
});
// --- Patient details ---
function loadPatientInfo(patientId) {
fetch('{% url "patients:get_patient_info" 0 %}'.replace('0', patientId), { credentials: 'same-origin' })
.then(r => r.json())
.then(data => {
if (!data.success) return;
const p = data.patient;
const html = `
<strong>${p.name}</strong><br>
<small>ID: ${p.patient_id} | DOB: ${p.date_of_birth} | Age: ${p.age}</small><br>
<small>Blood Type: ${p.blood_type || 'Unknown'} | Allergies: ${p.allergies || 'None known'}</small>
`;
$('#patient-details').html(html);
$('#patient-info').show();
})
.catch(() => toastr.error('Failed to load patient information'));
}
// --- Availability check (supports both unified and split datetime inputs) ---
function checkRoomAvailability() {
const roomId = $('#id_operating_room').val();
const duration = $('#id_estimated_duration').val();
// Unified DateTimeField
const scheduledStart = $('#id_scheduled_start').val();
// Split date & time fields
const date = $('#id_scheduled_date').val();
const time = $('#id_scheduled_start_time').val();
let payload = { room_id: roomId, duration, case_id: '{{ object.id|default:"" }}' };
if (scheduledStart) {
payload.scheduled_start = scheduledStart; // ISO or input value as provided by widget
} else if (date && time) {
payload.date = date;
payload.start_time = time;
} else {
$('#room-availability').hide();
return;
}
if (!roomId || !duration) {
$('#room-availability').hide();
return;
}
fetch('{% url "operating_theatre:check_room_availability" %}', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') },
body: JSON.stringify(payload),
credentials: 'same-origin'
})
.then(r => r.json())
.then(data => {
const $banner = $('#room-availability');
if (data.available) {
$('#availability-message').html('Room is available for the selected time slot');
$banner.removeClass('alert-warning alert-danger').addClass('alert-success').show();
} else {
$('#availability-message').html('Room conflict: ' + (data.conflict_reason || 'Unavailable'));
$banner.removeClass('alert-success alert-info').addClass('alert-danger').show();
}
})
.catch(() => {
$('#availability-message').html('Unable to check room availability');
$('#room-availability').removeClass('alert-success alert-info').addClass('alert-warning').show();
});
}
// --- Room schedule preview (server returns HTML snippet) ---
{#function loadRoomSchedule() {#}
{# const roomId = $('#id_operating_room').val();#}
{# const scheduledStart = $('#id_scheduled_start').val();#}
{# const date = $('#id_scheduled_date').val();#}
{##}
{# const query = new URLSearchParams();#}
{# if (roomId) query.set('room_id', roomId);#}
{# if (scheduledStart) query.set('date', scheduledStart.substring(0, 10));#}
{# else if (date) query.set('date', date);#}
{# else { $('#room-schedule').html('<p class="text-muted mb-0">Select a room and date to view schedule</p>'); return; }#}
{##}
{# fetch('{% url "operating_theatre:room_schedule" %}?'+query.toString(), { credentials: 'same-origin' })#}
{# .then(r => r.json())#}
{# .then(data => { $('#room-schedule').html(data.html || '<p class="text-muted mb-0">No schedule found.</p>'); })#}
{# .catch(() => { $('#room-schedule').html('<p class="text-danger mb-0">Unable to load room schedule</p>'); });#}
{# }#}
// --- Dynamic add/remove helpers ---
function addTeamMember() {
const html = `
<div class="team-member-row mb-2">
<div class="row">
<div class="col-md-5">
<select class="form-select" name="team_member_staff">
<option value="">Select staff member...</option>
{% for staff in available_staff %}
<option value="{{ staff.id }}">{{ staff.get_full_name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-5">
<input type="text" class="form-control" name="team_member_role" placeholder="Role (e.g., Scrub Nurse, Resident)">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-outline-danger" onclick="removeTeamMember(this)"><i class="fa fa-times"></i></button>
</div>
</div>
</div>`;
$('#team-members').append(html);
}
function removeTeamMember(btn){ $(btn).closest('.team-member-row').remove(); }
function addEquipment() {
const html = `
<div class="equipment-item mb-2">
<div class="input-group">
<select class="form-select" name="equipment">
<option value="">Select equipment...</option>
{% for equipment in available_equipment %}
<option value="{{ equipment.id }}">{{ equipment.name }}</option>
{% endfor %}
</select>
<button type="button" class="btn btn-outline-danger" onclick="removeEquipment(this)"><i class="fa fa-times"></i></button>
</div>
</div>`;
$('#equipment-list').append(html);
}
function removeEquipment(btn){ $(btn).closest('.equipment-item').remove(); }
function addSupply() {
const html = `
<div class="supply-item mb-2">
<div class="row">
<div class="col-8">
<select class="form-select" name="supply">
<option value="">Select supply...</option>
{% for supply in available_supplies %}
<option value="{{ supply.id }}">{{ supply.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-3">
<input type="number" class="form-control" name="supply_quantity" placeholder="Qty" min="1">
</div>
<div class="col-1">
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeSupply(this)"><i class="fa fa-times"></i></button>
</div>
</div>
</div>`;
$('#supplies-list').append(html);
}
function removeSupply(btn){ $(btn).closest('.supply-item').remove(); }
// --- Save draft (FormData + cookie CSRF) ---
function saveDraft() {
const form = document.getElementById('case-form');
const fd = new FormData(form);
fd.append('save_draft', 'true');
fetch(window.location.href, {
method: 'POST',
body: fd,
headers: { 'X-CSRFToken': getCookie('csrftoken') },
credentials: 'same-origin'
})
.then(r => r.json())
.then(data => data && data.success ? toastr.success('Draft saved successfully') : toastr.error('Error saving draft'))
.catch(() => toastr.error('Failed to save draft'));
}
</script>
{% endblock %}