422 lines
15 KiB
HTML
422 lines
15 KiB
HTML
{% load static %}
|
|
|
|
<!-- Surgery Calendar Partial -->
|
|
<div id="surgery-calendar-container">
|
|
<!-- Calendar Controls -->
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div class="btn-group" role="group">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="prev-month">
|
|
<i class="fa fa-chevron-left"></i>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="today">Today</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" id="next-month">
|
|
<i class="fa fa-chevron-right"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<h5 class="mb-0" id="calendar-title">Surgery Schedule</h5>
|
|
|
|
<div class="btn-group" role="group">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-view="month">Month</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-view="agendaWeek">Week</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-view="agendaDay">Day</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Calendar Legend -->
|
|
<div class="row mb-3">
|
|
<div class="col-12">
|
|
<div class="d-flex flex-wrap gap-3">
|
|
<div class="d-flex align-items-center">
|
|
<div class="me-2" style="width: 12px; height: 12px; background-color: #007bff; border-radius: 2px;"></div>
|
|
<small>Scheduled</small>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<div class="me-2" style="width: 12px; height: 12px; background-color: #28a745; border-radius: 2px;"></div>
|
|
<small>In Progress</small>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<div class="me-2" style="width: 12px; height: 12px; background-color: #ffc107; border-radius: 2px;"></div>
|
|
<small>Completed</small>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<div class="me-2" style="width: 12px; height: 12px; background-color: #dc3545; border-radius: 2px;"></div>
|
|
<small>Cancelled</small>
|
|
</div>
|
|
<div class="d-flex align-items-center">
|
|
<div class="me-2" style="width: 12px; height: 12px; background-color: #fd7e14; border-radius: 2px;"></div>
|
|
<small>Emergency</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Calendar -->
|
|
<div id="surgery-calendar" style="min-height: 600px;"></div>
|
|
</div>
|
|
|
|
<!-- Surgery Quick View Modal -->
|
|
<div class="modal fade" id="surgeryQuickViewModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Surgery Details</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body" id="surgery-quick-view-content">
|
|
<!-- Content will be loaded dynamically -->
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<a href="#" class="btn btn-primary" id="view-full-surgery">View Full Details</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Surgery Modal -->
|
|
<div class="modal fade" id="addSurgeryModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Schedule New Surgery</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="quick-surgery-form">
|
|
{% csrf_token %}
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Patient <span class="text-danger">*</span></label>
|
|
<select class="form-select select2" name="patient" required>
|
|
<option value="">Select Patient</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Surgeon <span class="text-danger">*</span></label>
|
|
<select class="form-select select2" name="surgeon" required>
|
|
<option value="">Select Surgeon</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-12 mb-3">
|
|
<label class="form-label">Procedure Name <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" name="procedure_name" required>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-4 mb-3">
|
|
<label class="form-label">Date <span class="text-danger">*</span></label>
|
|
<input type="date" class="form-control" name="scheduled_date" required>
|
|
</div>
|
|
<div class="col-md-4 mb-3">
|
|
<label class="form-label">Start Time <span class="text-danger">*</span></label>
|
|
<input type="time" class="form-control" name="scheduled_start_time" required>
|
|
</div>
|
|
<div class="col-md-4 mb-3">
|
|
<label class="form-label">Duration (minutes)</label>
|
|
<input type="number" class="form-control" name="estimated_duration" min="15" step="15">
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Operating Room</label>
|
|
<select class="form-select" name="operating_room">
|
|
<option value="">Select OR</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label class="form-label">Urgency Level</label>
|
|
<select class="form-select" name="urgency_level">
|
|
<option value="elective">Elective</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="emergency">Emergency</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" id="save-quick-surgery">Schedule Surgery</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
var calendar;
|
|
|
|
// Initialize FullCalendar
|
|
calendar = $('#surgery-calendar').fullCalendar({
|
|
header: false, // We're using custom header
|
|
defaultView: 'month',
|
|
height: 'auto',
|
|
editable: false,
|
|
eventLimit: true,
|
|
eventLimitText: 'more',
|
|
|
|
// Event sources
|
|
events: function(start, end, timezone, callback) {
|
|
$.ajax({
|
|
url: '{% url "inpatients:surgery_calendar_data" %}',
|
|
data: {
|
|
start: start.format(),
|
|
end: end.format()
|
|
},
|
|
success: function(data) {
|
|
callback(data.events);
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to load surgery calendar data');
|
|
callback([]);
|
|
}
|
|
});
|
|
},
|
|
|
|
// Event rendering
|
|
eventRender: function(event, element) {
|
|
// Add tooltip
|
|
element.attr('title', event.title + '\n' +
|
|
'Surgeon: ' + event.surgeon + '\n' +
|
|
'Room: ' + (event.room || 'TBD') + '\n' +
|
|
'Status: ' + event.status);
|
|
|
|
// Add status class
|
|
element.addClass('surgery-event-' + event.status);
|
|
|
|
// Add urgency indicator for emergency surgeries
|
|
if (event.urgency === 'emergency') {
|
|
element.prepend('<i class="fa fa-exclamation-triangle text-warning me-1"></i>');
|
|
}
|
|
},
|
|
|
|
// Event click handler
|
|
eventClick: function(event, jsEvent, view) {
|
|
loadSurgeryQuickView(event.id);
|
|
},
|
|
|
|
// Day click handler for adding new surgeries
|
|
dayClick: function(date, jsEvent, view) {
|
|
if (date.isSameOrAfter(moment(), 'day')) {
|
|
$('#addSurgeryModal input[name="scheduled_date"]').val(date.format('YYYY-MM-DD'));
|
|
$('#addSurgeryModal').modal('show');
|
|
}
|
|
},
|
|
|
|
// View render callback
|
|
viewRender: function(view, element) {
|
|
$('#calendar-title').text(view.title);
|
|
}
|
|
});
|
|
|
|
// Custom navigation buttons
|
|
$('#prev-month').click(function() {
|
|
calendar.fullCalendar('prev');
|
|
});
|
|
|
|
$('#next-month').click(function() {
|
|
calendar.fullCalendar('next');
|
|
});
|
|
|
|
$('#today').click(function() {
|
|
calendar.fullCalendar('today');
|
|
});
|
|
|
|
// View change buttons
|
|
$('[data-view]').click(function() {
|
|
var view = $(this).data('view');
|
|
calendar.fullCalendar('changeView', view);
|
|
$('[data-view]').removeClass('active');
|
|
$(this).addClass('active');
|
|
});
|
|
|
|
// Set default active view
|
|
$('[data-view="month"]').addClass('active');
|
|
|
|
// Load surgery quick view
|
|
function loadSurgeryQuickView(surgeryId) {
|
|
$.ajax({
|
|
url: '{% url "inpatients:surgery_quick_view" 0 %}'.replace('0', surgeryId),
|
|
success: function(data) {
|
|
$('#surgery-quick-view-content').html(data.html);
|
|
$('#view-full-surgery').attr('href', data.detail_url);
|
|
$('#surgeryQuickViewModal').modal('show');
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to load surgery details');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Initialize Select2 for modals
|
|
$('#addSurgeryModal').on('shown.bs.modal', function() {
|
|
$('.select2').select2({
|
|
theme: 'bootstrap-5',
|
|
dropdownParent: $('#addSurgeryModal')
|
|
});
|
|
|
|
// Load patients and surgeons
|
|
loadSelectOptions();
|
|
});
|
|
|
|
// Load select options
|
|
function loadSelectOptions() {
|
|
// Load patients
|
|
$.ajax({
|
|
url: '{% url "patients:patient_list_api" %}',
|
|
success: function(data) {
|
|
var patientSelect = $('select[name="patient"]');
|
|
patientSelect.empty().append('<option value="">Select Patient</option>');
|
|
data.forEach(function(patient) {
|
|
patientSelect.append('<option value="' + patient.id + '">' +
|
|
patient.name + ' (' + patient.mrn + ')</option>');
|
|
});
|
|
}
|
|
});
|
|
|
|
// Load surgeons
|
|
$.ajax({
|
|
url: '{% url "users:surgeon_list_api" %}',
|
|
success: function(data) {
|
|
var surgeonSelect = $('select[name="surgeon"]');
|
|
surgeonSelect.empty().append('<option value="">Select Surgeon</option>');
|
|
data.forEach(function(surgeon) {
|
|
surgeonSelect.append('<option value="' + surgeon.id + '">Dr. ' +
|
|
surgeon.name + '</option>');
|
|
});
|
|
}
|
|
});
|
|
|
|
// Load operating rooms
|
|
$.ajax({
|
|
url: '{% url "inpatients:operating_room_list_api" %}',
|
|
success: function(data) {
|
|
var roomSelect = $('select[name="operating_room"]');
|
|
roomSelect.empty().append('<option value="">Select OR</option>');
|
|
data.forEach(function(room) {
|
|
roomSelect.append('<option value="' + room.id + '">' + room.name + '</option>');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Save quick surgery
|
|
$('#save-quick-surgery').click(function() {
|
|
var formData = $('#quick-surgery-form').serialize();
|
|
|
|
$.ajax({
|
|
url: '{% url "inpatients:surgery_create_quick" %}',
|
|
method: 'POST',
|
|
data: formData,
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success('Surgery scheduled successfully');
|
|
$('#addSurgeryModal').modal('hide');
|
|
calendar.fullCalendar('refetchEvents');
|
|
} else {
|
|
toastr.error('Failed to schedule surgery: ' + response.error);
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred while scheduling the surgery');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Auto-refresh calendar every 5 minutes
|
|
setInterval(function() {
|
|
calendar.fullCalendar('refetchEvents');
|
|
}, 300000);
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
/* Custom calendar styles */
|
|
.surgery-event-scheduled {
|
|
background-color: #007bff !important;
|
|
border-color: #007bff !important;
|
|
}
|
|
|
|
.surgery-event-in_progress {
|
|
background-color: #28a745 !important;
|
|
border-color: #28a745 !important;
|
|
}
|
|
|
|
.surgery-event-completed {
|
|
background-color: #ffc107 !important;
|
|
border-color: #ffc107 !important;
|
|
color: #000 !important;
|
|
}
|
|
|
|
.surgery-event-cancelled {
|
|
background-color: #dc3545 !important;
|
|
border-color: #dc3545 !important;
|
|
}
|
|
|
|
.fc-event {
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.fc-event:hover {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.fc-day-grid-event {
|
|
margin: 1px 2px;
|
|
}
|
|
|
|
.fc-time-grid-event {
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/* Emergency surgery styling */
|
|
.surgery-event-emergency {
|
|
border-left: 4px solid #fd7e14 !important;
|
|
}
|
|
|
|
/* Calendar header styling */
|
|
.fc-toolbar {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.fc-toolbar h2 {
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Modal styling */
|
|
.modal-lg {
|
|
max-width: 800px;
|
|
}
|
|
|
|
#surgery-quick-view-content {
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
/* Responsive adjustments */
|
|
@media (max-width: 768px) {
|
|
.fc-toolbar .fc-left,
|
|
.fc-toolbar .fc-right,
|
|
.fc-toolbar .fc-center {
|
|
float: none;
|
|
display: block;
|
|
clear: both;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.fc-toolbar > * > * {
|
|
float: none;
|
|
margin: 0 5px;
|
|
}
|
|
}
|
|
</style>
|
|
|