hospital-management/templates/operating_theatre/templates/surgical_note_template_form.html
Marwan Alwali b9b8c69129 update
2025-08-31 10:47:23 +03:00

1163 lines
43 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 template.pk %}Edit{% else %}Create{% endif %} Surgical Note Template{% endblock %}
{% block css %}
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
<link href="{% static 'plugins/summernote/summernote-bs5.min.css' %}" rel="stylesheet" />
<style>
.template-form-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 0.5rem;
padding: 2rem;
margin-bottom: 2rem;
}
.form-section {
background: white;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
margin-bottom: 1.5rem;
}
.section-header {
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
padding: 1rem 1.5rem;
font-weight: 600;
color: #495057;
display: flex;
justify-content: between;
align-items: center;
}
.section-content {
padding: 1.5rem;
}
.required-field::after {
content: " *";
color: #dc3545;
}
.template-editor {
border: 1px solid #dee2e6;
border-radius: 0.375rem;
min-height: 400px;
}
.variables-panel {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
padding: 1rem;
margin-bottom: 1rem;
}
.variable-item {
display: flex;
justify-content: between;
align-items: center;
padding: 0.5rem;
background: white;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
margin-bottom: 0.5rem;
cursor: pointer;
transition: background-color 0.2s;
}
.variable-item:hover {
background: #e3f2fd;
}
.variable-item:last-child {
margin-bottom: 0;
}
.variable-code {
font-family: 'Courier New', monospace;
background: #e9ecef;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.variable-description {
font-size: 0.875rem;
color: #6c757d;
}
.preview-section {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
max-height: 500px;
overflow-y: auto;
}
.preview-content {
background: white;
border: 1px solid #dee2e6;
border-radius: 0.25rem;
padding: 1.5rem;
font-family: 'Times New Roman', serif;
line-height: 1.6;
}
.auto-save-indicator {
position: fixed;
top: 20px;
right: 20px;
background: #28a745;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.25rem;
font-size: 0.875rem;
z-index: 1050;
display: none;
}
.field-help {
font-size: 0.875rem;
color: #6c757d;
margin-top: 0.25rem;
}
.tag-input {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
padding: 0.5rem;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
min-height: 45px;
align-items: center;
}
.tag-item {
background: #007bff;
color: white;
padding: 0.25rem 0.75rem;
border-radius: 0.25rem;
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.tag-remove {
cursor: pointer;
font-weight: bold;
}
.tag-input input {
border: none;
outline: none;
flex: 1;
min-width: 100px;
padding: 0.25rem;
}
.editor-toolbar {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-bottom: none;
border-radius: 0.375rem 0.375rem 0 0;
padding: 0.75rem 1rem;
display: flex;
justify-content: between;
align-items: center;
}
.toolbar-group {
display: flex;
gap: 0.5rem;
}
.toolbar-btn {
padding: 0.375rem 0.75rem;
border: 1px solid #dee2e6;
background: white;
border-radius: 0.25rem;
cursor: pointer;
transition: background-color 0.2s;
}
.toolbar-btn:hover {
background: #e9ecef;
}
.toolbar-btn.active {
background: #007bff;
color: white;
border-color: #007bff;
}
@media (max-width: 768px) {
.template-form-header {
padding: 1.5rem;
}
.section-content {
padding: 1rem;
}
.variables-panel {
margin-bottom: 1.5rem;
}
.editor-toolbar {
flex-direction: column;
gap: 1rem;
align-items: stretch;
}
.toolbar-group {
justify-content: center;
}
}
@media print {
.variables-panel, .editor-toolbar, .btn, .form-actions {
display: none !important;
}
.form-section {
border: none;
box-shadow: none;
}
.section-header {
background: none;
border-bottom: 2px solid #000;
color: #000;
}
}
</style>
{% endblock %}
{% block content %}
<div id="content" class="app-content">
<!-- Auto-save indicator -->
<div class="auto-save-indicator" id="auto-save-indicator">
<i class="fas fa-check me-1"></i>Auto-saved
</div>
<!-- Page Header -->
<div class="d-flex align-items-center mb-3">
<div>
<ol class="breadcrumb">
<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_note_template_list' %}">Templates</a></li>
<li class="breadcrumb-item active">{% if template.pk %}Edit{% else %}Create{% endif %} Template</li>
</ol>
<h1 class="page-header mb-0">
<i class="fas fa-clipboard-list me-2"></i>
{% if template.pk %}Edit Template{% else %}Create Template{% endif %}
</h1>
</div>
<div class="ms-auto">
<button type="button" class="btn btn-outline-secondary me-2" onclick="saveDraft()">
<i class="fas fa-save me-1"></i>Save Draft
</button>
<button type="button" class="btn btn-outline-info me-2" onclick="previewTemplate()">
<i class="fas fa-eye me-1"></i>Preview
</button>
<a href="{% url 'operating_theatre:surgical_note_template_list' %}" class="btn btn-outline-primary">
<i class="fas fa-arrow-left me-1"></i>Back to List
</a>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<form method="post" id="template-form" novalidate>
{% csrf_token %}
<!-- Basic Information -->
<div class="form-section">
<div class="section-header">
<i class="fas fa-info-circle me-2"></i>Basic Information
</div>
<div class="section-content">
<div class="row">
<div class="col-md-8">
<div class="form-floating mb-3">
{{ form.name }}
<label for="{{ form.name.id_for_label }}" class="required-field">Template Name</label>
{% if form.name.errors %}
<div class="invalid-feedback d-block">{{ form.name.errors.0 }}</div>
{% endif %}
<div class="field-help">Enter a descriptive name for this template</div>
</div>
</div>
<div class="col-md-4">
<div class="mb-3">
<label for="{{ form.category.id_for_label }}" class="form-label required-field">Category</label>
{{ form.category }}
{% if form.category.errors %}
<div class="invalid-feedback d-block">{{ form.category.errors.0 }}</div>
{% endif %}
<div class="field-help">Select the surgical category</div>
</div>
</div>
</div>
<div class="mb-3">
<label for="{{ form.description.id_for_label }}" class="form-label required-field">Description</label>
{{ form.description }}
{% if form.description.errors %}
<div class="invalid-feedback d-block">{{ form.description.errors.0 }}</div>
{% endif %}
<div class="field-help">Provide a clear description of when to use this template</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.status.id_for_label }}" class="form-label required-field">Status</label>
{{ form.status }}
{% if form.status.errors %}
<div class="invalid-feedback d-block">{{ form.status.errors.0 }}</div>
{% endif %}
<div class="field-help">Set the template availability status</div>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="{{ form.version.id_for_label }}" class="form-label">Version</label>
{{ form.version }}
{% if form.version.errors %}
<div class="invalid-feedback d-block">{{ form.version.errors.0 }}</div>
{% endif %}
<div class="field-help">Version number (auto-incremented if left blank)</div>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Tags</label>
<div class="tag-input" id="tag-input">
{% for tag in template.tags.all %}
<span class="tag-item">
{{ tag.name }}
<span class="tag-remove" onclick="removeTag(this)">&times;</span>
</span>
{% endfor %}
<input type="text" placeholder="Add tags..." onkeypress="handleTagInput(event)">
</div>
<input type="hidden" name="tags" id="tags-hidden">
<div class="field-help">Add tags to help categorize and search for this template</div>
</div>
<div class="mb-3">
<label for="{{ form.keywords.id_for_label }}" class="form-label">Keywords</label>
{{ form.keywords }}
{% if form.keywords.errors %}
<div class="invalid-feedback d-block">{{ form.keywords.errors.0 }}</div>
{% endif %}
<div class="field-help">Comma-separated keywords for search optimization</div>
</div>
</div>
</div>
<!-- Template Content -->
<div class="form-section">
<div class="section-header">
<div>
<i class="fas fa-file-alt me-2"></i>Template Content
</div>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="toggleEditor('wysiwyg')" id="btn-wysiwyg">
<i class="fas fa-eye me-1"></i>Visual
</button>
<button type="button" class="btn btn-outline-secondary" onclick="toggleEditor('code')" id="btn-code">
<i class="fas fa-code me-1"></i>Code
</button>
</div>
</div>
<div class="section-content">
<!-- Editor Toolbar -->
<div class="editor-toolbar">
<div class="toolbar-group">
<button type="button" class="toolbar-btn" onclick="insertVariable('patient_name')" title="Insert Patient Name">
<i class="fas fa-user"></i>
</button>
<button type="button" class="toolbar-btn" onclick="insertVariable('surgery_date')" title="Insert Surgery Date">
<i class="fas fa-calendar"></i>
</button>
<button type="button" class="toolbar-btn" onclick="insertVariable('surgeon_name')" title="Insert Surgeon Name">
<i class="fas fa-user-md"></i>
</button>
<button type="button" class="toolbar-btn" onclick="insertVariable('procedure_name')" title="Insert Procedure Name">
<i class="fas fa-procedures"></i>
</button>
</div>
<div class="toolbar-group">
<button type="button" class="toolbar-btn" onclick="insertSection('preop')" title="Pre-operative Section">
Pre-op
</button>
<button type="button" class="toolbar-btn" onclick="insertSection('procedure')" title="Procedure Section">
Procedure
</button>
<button type="button" class="toolbar-btn" onclick="insertSection('postop')" title="Post-operative Section">
Post-op
</button>
</div>
<div class="toolbar-group">
<button type="button" class="toolbar-btn" onclick="formatText('bold')" title="Bold">
<i class="fas fa-bold"></i>
</button>
<button type="button" class="toolbar-btn" onclick="formatText('italic')" title="Italic">
<i class="fas fa-italic"></i>
</button>
<button type="button" class="toolbar-btn" onclick="formatText('underline')" title="Underline">
<i class="fas fa-underline"></i>
</button>
</div>
</div>
<!-- WYSIWYG Editor -->
<div id="wysiwyg-editor">
{{ form.content }}
</div>
<!-- Code Editor -->
<div id="code-editor" style="display: none;">
<textarea class="form-control template-editor" name="content_raw" rows="20"
placeholder="Enter template content here...">{{ template.content|default:"" }}</textarea>
</div>
{% if form.content.errors %}
<div class="invalid-feedback d-block">{{ form.content.errors.0 }}</div>
{% endif %}
<div class="field-help">Create the template content using variables and formatting</div>
</div>
</div>
<!-- Template Settings -->
<div class="form-section">
<div class="section-header">
<i class="fas fa-cog me-2"></i>Template Settings
</div>
<div class="section-content">
<div class="row">
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.is_default }}
<label class="form-check-label" for="{{ form.is_default.id_for_label }}">
Default Template
</label>
<div class="field-help">Set as default template for this category</div>
</div>
</div>
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.is_public }}
<label class="form-check-label" for="{{ form.is_public.id_for_label }}">
Public Template
</label>
<div class="field-help">Allow other users to access this template</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.requires_approval }}
<label class="form-check-label" for="{{ form.requires_approval.id_for_label }}">
Requires Approval
</label>
<div class="field-help">Notes created from this template need approval</div>
</div>
</div>
<div class="col-md-6">
<div class="form-check mb-3">
{{ form.auto_populate }}
<label class="form-check-label" for="{{ form.auto_populate.id_for_label }}">
Auto-populate Fields
</label>
<div class="field-help">Automatically fill fields from patient data</div>
</div>
</div>
</div>
<div class="mb-3">
<label for="{{ form.change_summary.id_for_label }}" class="form-label">Change Summary</label>
{{ form.change_summary }}
{% if form.change_summary.errors %}
<div class="invalid-feedback d-block">{{ form.change_summary.errors.0 }}</div>
{% endif %}
<div class="field-help">Describe the changes made in this version</div>
</div>
</div>
</div>
<!-- Form Actions -->
<div class="form-actions d-flex justify-content-between align-items-center">
<div>
<button type="button" class="btn btn-outline-secondary" onclick="validateTemplate()">
<i class="fas fa-check-circle me-1"></i>Validate
</button>
<button type="button" class="btn btn-outline-info" onclick="testTemplate()">
<i class="fas fa-flask me-1"></i>Test
</button>
</div>
<div>
<a href="{% url 'operating_theatre:surgical_note_template_list' %}" class="btn btn-outline-secondary me-2">
<i class="fas fa-times me-1"></i>Cancel
</a>
<button type="submit" name="action" value="save_draft" class="btn btn-outline-primary me-2">
<i class="fas fa-save me-1"></i>Save Draft
</button>
<button type="submit" name="action" value="save_active" class="btn btn-success">
<i class="fas fa-check me-1"></i>
{% if template.pk %}Update Template{% else %}Create Template{% endif %}
</button>
</div>
</div>
</form>
</div>
<div class="col-lg-4">
<!-- Template Variables -->
<div class="variables-panel">
<h6 class="mb-3">
<i class="fas fa-code me-2"></i>Available Variables
</h6>
<div class="variable-item" onclick="insertVariable('patient_name')">
<div>
<div class="variable-code">{{patient_name}}</div>
<div class="variable-description">Patient's full name</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('patient_id')">
<div>
<div class="variable-code">{{patient_id}}</div>
<div class="variable-description">Patient ID number</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('surgery_date')">
<div>
<div class="variable-code">{{surgery_date}}</div>
<div class="variable-description">Date of surgery</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('surgeon_name')">
<div>
<div class="variable-code">{{surgeon_name}}</div>
<div class="variable-description">Primary surgeon name</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('procedure_name')">
<div>
<div class="variable-code">{{procedure_name}}</div>
<div class="variable-description">Name of procedure</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('anesthesia_type')">
<div>
<div class="variable-code">{{anesthesia_type}}</div>
<div class="variable-description">Type of anesthesia</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('start_time')">
<div>
<div class="variable-code">{{start_time}}</div>
<div class="variable-description">Surgery start time</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('end_time')">
<div>
<div class="variable-code">{{end_time}}</div>
<div class="variable-description">Surgery end time</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('current_date')">
<div>
<div class="variable-code">{{current_date}}</div>
<div class="variable-description">Current date</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
<div class="variable-item" onclick="insertVariable('current_time')">
<div>
<div class="variable-code">{{current_time}}</div>
<div class="variable-description">Current time</div>
</div>
<i class="fas fa-plus text-primary"></i>
</div>
</div>
<!-- Template Sections -->
<div class="form-section">
<div class="section-header">
<i class="fas fa-list me-2"></i>Quick Sections
</div>
<div class="section-content">
<div class="d-grid gap-2">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="insertSection('preop')">
<i class="fas fa-clipboard-check me-1"></i>Pre-operative Section
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="insertSection('procedure')">
<i class="fas fa-procedures me-1"></i>Procedure Section
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="insertSection('postop')">
<i class="fas fa-heartbeat me-1"></i>Post-operative Section
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="insertSection('complications')">
<i class="fas fa-exclamation-triangle me-1"></i>Complications Section
</button>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="insertSection('signature')">
<i class="fas fa-signature me-1"></i>Signature Section
</button>
</div>
</div>
</div>
<!-- Preview -->
<div class="form-section">
<div class="section-header">
<i class="fas fa-eye me-2"></i>Live Preview
</div>
<div class="section-content">
<div class="preview-section">
<div class="preview-content" id="live-preview">
<p class="text-muted text-center">
<i class="fas fa-eye fa-2x mb-2"></i><br>
Preview will appear here as you type
</p>
</div>
</div>
<div class="text-center">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="refreshPreview()">
<i class="fas fa-sync me-1"></i>Refresh Preview
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Preview Modal -->
<div class="modal fade" id="previewModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-eye me-2"></i>Template Preview
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="preview-modal-content">
<!-- Preview content will be loaded here -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
<i class="fas fa-times me-1"></i>Close
</button>
<button type="button" class="btn btn-primary" onclick="printPreview()">
<i class="fas fa-print me-1"></i>Print Preview
</button>
</div>
</div>
</div>
</div>
<!-- Validation Modal -->
<div class="modal fade" id="validationModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-check-circle me-2"></i>Template Validation
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="validation-content">
<!-- Validation results will be loaded here -->
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">
<i class="fas fa-check me-1"></i>OK
</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
<script src="{% static 'plugins/summernote/summernote-bs5.min.js' %}"></script>
<script>
$(document).ready(function() {
// Initialize Select2
$('.form-select').select2({
theme: 'bootstrap-5',
width: '100%'
});
// Initialize Summernote
$('#id_content').summernote({
height: 400,
toolbar: [
['style', ['style']],
['font', ['bold', 'italic', 'underline', 'clear']],
['fontname', ['fontname']],
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
['insert', ['link', 'picture', 'video']],
['view', ['fullscreen', 'codeview', 'help']]
],
callbacks: {
onChange: function(contents) {
updateLivePreview(contents);
scheduleAutoSave();
}
}
});
// Initialize tags
updateTagsHidden();
// Auto-save functionality
let autoSaveTimer;
$('form input, form textarea, form select').on('input change', function() {
scheduleAutoSave();
});
// Form validation
$('#template-form').on('submit', function(e) {
if (!validateRequiredFields()) {
e.preventDefault();
showValidationErrors();
}
});
});
function scheduleAutoSave() {
clearTimeout(autoSaveTimer);
autoSaveTimer = setTimeout(autoSave, 30000); // Auto-save after 30 seconds
}
function autoSave() {
const formData = new FormData(document.getElementById('template-form'));
formData.append('action', 'auto_save');
fetch(window.location.href, {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAutoSaveIndicator();
}
})
.catch(error => {
console.error('Auto-save failed:', error);
});
}
function showAutoSaveIndicator() {
const indicator = document.getElementById('auto-save-indicator');
indicator.style.display = 'block';
setTimeout(() => {
indicator.style.display = 'none';
}, 2000);
}
function saveDraft() {
const form = document.getElementById('template-form');
const actionInput = document.createElement('input');
actionInput.type = 'hidden';
actionInput.name = 'action';
actionInput.value = 'save_draft';
form.appendChild(actionInput);
form.submit();
}
function toggleEditor(mode) {
const wysiwygEditor = document.getElementById('wysiwyg-editor');
const codeEditor = document.getElementById('code-editor');
const btnWysiwyg = document.getElementById('btn-wysiwyg');
const btnCode = document.getElementById('btn-code');
if (mode === 'wysiwyg') {
wysiwygEditor.style.display = 'block';
codeEditor.style.display = 'none';
btnWysiwyg.classList.add('active');
btnCode.classList.remove('active');
// Sync content from code to WYSIWYG
const codeContent = codeEditor.querySelector('textarea').value;
$('#id_content').summernote('code', codeContent);
} else {
wysiwygEditor.style.display = 'none';
codeEditor.style.display = 'block';
btnWysiwyg.classList.remove('active');
btnCode.classList.add('active');
// Sync content from WYSIWYG to code
const wysiwygContent = $('#id_content').summernote('code');
codeEditor.querySelector('textarea').value = wysiwygContent;
}
}
function insertVariable(variable) {
const variableText = `{${variable}}`;
if (document.getElementById('wysiwyg-editor').style.display !== 'none') {
$('#id_content').summernote('insertText', variableText);
} else {
const textarea = document.querySelector('#code-editor textarea');
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const text = textarea.value;
textarea.value = text.substring(0, start) + variableText + text.substring(end);
textarea.selectionStart = textarea.selectionEnd = start + variableText.length;
textarea.focus();
}
}
function insertSection(sectionType) {
const sections = {
preop: `
PRE-OPERATIVE INFORMATION
========================
Pre-operative Diagnosis: {{preoperative_diagnosis}}
Indication for Surgery: {{indication}}
Anesthesia Type: {{anesthesia_type}}
Patient Position: {{patient_position}}
`,
procedure: `
OPERATIVE PROCEDURE
==================
Procedure: {{procedure_name}}
Technique: {{technique}}
Findings: {{findings}}
Specimens: {{specimens}}
`,
postop: `
POST-OPERATIVE INFORMATION
=========================
Post-operative Diagnosis: {{postoperative_diagnosis}}
Complications: {{complications}}
Estimated Blood Loss: {{estimated_blood_loss}} mL
Post-operative Instructions: {{postoperative_instructions}}
`,
complications: `
COMPLICATIONS
============
Intraoperative Complications: None
Post-operative Complications: None
Management: N/A
`,
signature: `
ELECTRONIC SIGNATURE
===================
Surgeon: {{surgeon_name}}
Date: {{current_date}}
Time: {{current_time}}
Signature: [Electronic Signature]
`
};
const sectionContent = sections[sectionType] || '';
if (document.getElementById('wysiwyg-editor').style.display !== 'none') {
$('#id_content').summernote('insertText', sectionContent);
} else {
const textarea = document.querySelector('#code-editor textarea');
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const text = textarea.value;
textarea.value = text.substring(0, start) + sectionContent + text.substring(end);
textarea.selectionStart = textarea.selectionEnd = start + sectionContent.length;
textarea.focus();
}
}
function formatText(format) {
if (document.getElementById('wysiwyg-editor').style.display !== 'none') {
$('#id_content').summernote('execCommand', format);
}
}
function updateLivePreview(content) {
// Replace variables with sample data for preview
let previewContent = content;
const sampleData = {
'patient_name': 'John Doe',
'patient_id': 'P123456',
'surgery_date': new Date().toLocaleDateString(),
'surgeon_name': 'Dr. Smith',
'procedure_name': 'Sample Procedure',
'anesthesia_type': 'General',
'current_date': new Date().toLocaleDateString(),
'current_time': new Date().toLocaleTimeString()
};
Object.keys(sampleData).forEach(key => {
const regex = new RegExp(`{${key}}`, 'g');
previewContent = previewContent.replace(regex, sampleData[key]);
});
document.getElementById('live-preview').innerHTML = previewContent;
}
function refreshPreview() {
const content = $('#id_content').summernote('code');
updateLivePreview(content);
}
function previewTemplate() {
const content = $('#id_content').summernote('code');
updateLivePreview(content);
document.getElementById('preview-modal-content').innerHTML =
document.getElementById('live-preview').innerHTML;
new bootstrap.Modal(document.getElementById('previewModal')).show();
}
function validateTemplate() {
const errors = [];
const warnings = [];
// Check required fields
const requiredFields = document.querySelectorAll('[required]');
requiredFields.forEach(field => {
if (!field.value.trim()) {
errors.push(`${field.labels[0].textContent} is required`);
}
});
// Check template content
const content = $('#id_content').summernote('code');
if (!content.trim()) {
errors.push('Template content cannot be empty');
}
// Check for common issues
if (content.includes('{{') && !content.includes('}}')) {
warnings.push('Unclosed variable syntax detected');
}
if (content.length < 50) {
warnings.push('Template content seems very short');
}
// Display validation results
let validationContent = '';
if (errors.length === 0 && warnings.length === 0) {
validationContent = `
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
Template validation passed! No issues found.
</div>
`;
} else {
if (errors.length > 0) {
validationContent += `
<div class="alert alert-danger">
<h6><i class="fas fa-exclamation-triangle me-2"></i>Errors:</h6>
<ul class="mb-0">
${errors.map(error => `<li>${error}</li>`).join('')}
</ul>
</div>
`;
}
if (warnings.length > 0) {
validationContent += `
<div class="alert alert-warning">
<h6><i class="fas fa-exclamation-circle me-2"></i>Warnings:</h6>
<ul class="mb-0">
${warnings.map(warning => `<li>${warning}</li>`).join('')}
</ul>
</div>
`;
}
}
document.getElementById('validation-content').innerHTML = validationContent;
new bootstrap.Modal(document.getElementById('validationModal')).show();
}
{#function testTemplate() {#}
{# const content = $('#id_content').summernote('code');#}
{# #}
{# fetch('{% url "operating_theatre:" %}', {#}
{# method: 'POST',#}
{# headers: {#}
{# 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,#}
{# 'Content-Type': 'application/json'#}
{# },#}
{# body: JSON.stringify({ content: content })#}
{# })#}
{# .then(response => response.json())#}
{# .then(data => {#}
{# if (data.success) {#}
{# document.getElementById('preview-modal-content').innerHTML = data.rendered_content;#}
{# new bootstrap.Modal(document.getElementById('previewModal')).show();#}
{# } else {#}
{# showAlert('Error testing template', 'danger');#}
{# }#}
{# })#}
{# .catch(error => {#}
{# showAlert('Error testing template', 'danger');#}
{# });#}
{# }#}
function validateRequiredFields() {
const requiredFields = document.querySelectorAll('[required]');
let isValid = true;
requiredFields.forEach(field => {
if (!field.value.trim()) {
field.classList.add('is-invalid');
isValid = false;
} else {
field.classList.remove('is-invalid');
}
});
return isValid;
}
function showValidationErrors() {
showAlert('Please fill in all required fields', 'danger');
}
function printPreview() {
const printContent = document.getElementById('preview-modal-content').innerHTML;
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<html>
<head>
<title>Template Preview</title>
<style>
body { font-family: 'Times New Roman', serif; line-height: 1.6; }
@media print { .no-print { display: none !important; } }
</style>
</head>
<body>
${printContent}
</body>
</html>
`);
printWindow.document.close();
printWindow.print();
}
// Tag management
function handleTagInput(event) {
if (event.key === 'Enter' || event.key === ',') {
event.preventDefault();
const input = event.target;
const tagText = input.value.trim();
if (tagText && !isTagExists(tagText)) {
addTag(tagText);
input.value = '';
updateTagsHidden();
}
}
}
function addTag(tagText) {
const tagInput = document.getElementById('tag-input');
const input = tagInput.querySelector('input');
const tagElement = document.createElement('span');
tagElement.className = 'tag-item';
tagElement.innerHTML = `
${tagText}
<span class="tag-remove" onclick="removeTag(this)">&times;</span>
`;
tagInput.insertBefore(tagElement, input);
}
function removeTag(element) {
element.parentElement.remove();
updateTagsHidden();
}
function isTagExists(tagText) {
const existingTags = document.querySelectorAll('.tag-item');
return Array.from(existingTags).some(tag =>
tag.textContent.replace('×', '').trim().toLowerCase() === tagText.toLowerCase()
);
}
function updateTagsHidden() {
const tags = Array.from(document.querySelectorAll('.tag-item'))
.map(tag => tag.textContent.replace('×', '').trim());
document.getElementById('tags-hidden').value = tags.join(',');
}
function showAlert(message, type) {
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type} alert-dismissible fade show position-fixed`;
alertDiv.style.cssText = 'top: 20px; right: 20px; z-index: 1060; min-width: 300px;';
alertDiv.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(alertDiv);
setTimeout(() => {
if (alertDiv.parentNode) {
alertDiv.remove();
}
}, 5000);
}
</script>
{% endblock %}