799 lines
36 KiB
HTML
799 lines
36 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if form.instance.id %}Edit{% else %}Create{% endif %} Clinical Note{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'plugins/bootstrap-icons/font/bootstrap-icons.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/summernote/dist/summernote-bs4.css' %}" rel="stylesheet" />
|
|
<style>
|
|
.note-editor {
|
|
border-radius: 0.25rem;
|
|
}
|
|
.note-editor.note-frame {
|
|
border: 1px solid var(--bs-gray-300);
|
|
}
|
|
.note-editor.note-frame .note-statusbar {
|
|
border-top: 1px solid var(--bs-gray-300);
|
|
}
|
|
.template-card {
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
border: 1px solid var(--bs-gray-300);
|
|
}
|
|
.template-card:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
|
border-color: var(--bs-primary);
|
|
}
|
|
.template-card.selected {
|
|
border: 2px solid var(--bs-primary);
|
|
background-color: rgba(var(--bs-primary-rgb), 0.05);
|
|
}
|
|
.section-card {
|
|
border: 1px solid var(--bs-gray-300);
|
|
border-radius: 0.25rem;
|
|
margin-bottom: 1rem;
|
|
background-color: rgba(var(--bs-light-rgb), 0.5);
|
|
}
|
|
.section-card .card-header {
|
|
background-color: rgba(var(--bs-light-rgb), 0.8);
|
|
border-bottom: 1px solid var(--bs-gray-300);
|
|
padding: 0.75rem 1rem;
|
|
}
|
|
.section-card .card-body {
|
|
padding: 1rem;
|
|
}
|
|
.section-card .card-footer {
|
|
background-color: rgba(var(--bs-light-rgb), 0.8);
|
|
border-top: 1px solid var(--bs-gray-300);
|
|
padding: 0.75rem 1rem;
|
|
}
|
|
.section-actions {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
}
|
|
.drag-handle {
|
|
cursor: move;
|
|
color: var(--bs-gray-600);
|
|
}
|
|
.help-sidebar {
|
|
position: sticky;
|
|
top: 1rem;
|
|
}
|
|
.help-card {
|
|
border-left: 4px solid var(--bs-info);
|
|
}
|
|
.shortcut-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 0;
|
|
border-bottom: 1px solid var(--bs-gray-200);
|
|
}
|
|
.shortcut-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
.shortcut-key {
|
|
font-family: monospace;
|
|
background-color: var(--bs-gray-200);
|
|
padding: 0.2rem 0.4rem;
|
|
border-radius: 0.25rem;
|
|
}
|
|
.floating-label {
|
|
position: relative;
|
|
}
|
|
.floating-label label {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
padding: 0.75rem 0.75rem;
|
|
pointer-events: none;
|
|
transition: all 0.2s ease;
|
|
transform-origin: 0 0;
|
|
}
|
|
.floating-label input:focus ~ label,
|
|
.floating-label input:not(:placeholder-shown) ~ label,
|
|
.floating-label select:focus ~ label,
|
|
.floating-label select:not([value=""]):valid ~ label {
|
|
transform: translate(0, -0.5rem) scale(0.85);
|
|
color: var(--bs-primary);
|
|
padding: 0 0.2rem;
|
|
background: white;
|
|
}
|
|
.note-type-badge {
|
|
font-size: 0.85rem;
|
|
padding: 0.35em 0.65em;
|
|
}
|
|
.note-type-progress {
|
|
background-color: var(--bs-primary);
|
|
color: white;
|
|
}
|
|
.note-type-admission {
|
|
background-color: var(--bs-danger);
|
|
color: white;
|
|
}
|
|
.note-type-discharge {
|
|
background-color: var(--bs-success);
|
|
color: white;
|
|
}
|
|
.note-type-procedure {
|
|
background-color: var(--bs-warning);
|
|
color: white;
|
|
}
|
|
.note-type-consultation {
|
|
background-color: var(--bs-info);
|
|
color: white;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
|
|
<!-- begin page-header -->
|
|
<h1 class="page-header">{% if form.instance.id %}Edit{% else %}Create{% endif %} Clinical Note <small>Comprehensive clinical documentation</small></h1>
|
|
<!-- end page-header -->
|
|
|
|
<!-- begin row -->
|
|
<div class="row">
|
|
<!-- begin col-9 -->
|
|
<div class="col-xl-9">
|
|
<form method="post" id="clinicalNoteForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Note Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if form.errors %}
|
|
<div class="alert alert-danger">
|
|
<strong>Error!</strong> Please correct the errors below.
|
|
<ul>
|
|
{% for field in form %}
|
|
{% for error in field.errors %}
|
|
<li>{{ field.label }}: {{ error }}</li>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% for error in form.non_field_errors %}
|
|
<li>{{ error }}</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.title }}
|
|
<label for="{{ form.title.id_for_label }}">{{ form.title.label }}</label>
|
|
{% if form.title.help_text %}
|
|
<div class="form-text">{{ form.title.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.note_type }}
|
|
<label for="{{ form.note_type.id_for_label }}">{{ form.note_type.label }}</label>
|
|
{% if form.note_type.help_text %}
|
|
<div class="form-text">{{ form.note_type.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.patient }}
|
|
<label for="{{ form.patient.id_for_label }}">{{ form.patient.label }}</label>
|
|
{% if form.patient.help_text %}
|
|
<div class="form-text">{{ form.patient.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.related_encounter }}
|
|
<label for="{{ form.related_encounter.id_for_label }}">{{ form.related_encounter.label }}</label>
|
|
{% if form.related_encounter.help_text %}
|
|
<div class="form-text">{{ form.related_encounter.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.note_datetime }}
|
|
<label for="{{ form.note_datetime.id_for_label }}">{{ form.note_datetime.label }}</label>
|
|
{% if form.note_datetime.help_text %}
|
|
<div class="form-text">{{ form.note_datetime.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="floating-label">
|
|
{{ form.author }}
|
|
<label for="{{ form.author.id_for_label }}">{{ form.author.label }}</label>
|
|
{% if form.author.help_text %}
|
|
<div class="form-text">{{ form.author.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end panel -->
|
|
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Note Content</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="useStructuredContent" name="use_structured_content" {% if form.instance.structured_content %}checked{% endif %}>
|
|
<label class="form-check-label" for="useStructuredContent">Use structured content format</label>
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-primary" id="addSectionBtn" {% if not form.instance.structured_content %}style="display: none;"{% endif %}>
|
|
<i class="fa fa-plus me-1"></i> Add Section
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Structured Content Sections -->
|
|
<div id="structuredContentContainer" {% if not form.instance.structured_content %}style="display: none;"{% endif %}>
|
|
<div id="sectionsList">
|
|
{% if form.instance.structured_content %}
|
|
{% for section in form.instance.structured_content %}
|
|
<div class="section-card" data-section-id="{{ forloop.counter0 }}">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<span class="drag-handle me-2"><i class="fa fa-grip-vertical"></i></span>
|
|
<input type="text" class="form-control form-control-sm section-title" name="section_title_{{ forloop.counter0 }}" value="{{ section.title }}" placeholder="Section Title" style="width: 300px;">
|
|
</div>
|
|
<div class="section-actions">
|
|
<button type="button" class="btn btn-sm btn-outline-danger remove-section-btn">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<textarea class="form-control section-content summernote" name="section_content_{{ forloop.counter0 }}" rows="5">{{ section.content }}</textarea>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Simple Content -->
|
|
<div id="simpleContentContainer" {% if form.instance.structured_content %}style="display: none;"{% endif %}>
|
|
<textarea class="form-control summernote" id="content" name="content" rows="15">{{ form.instance.content }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end panel -->
|
|
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Related Records</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.related_problems.id_for_label }}" class="form-label">{{ form.related_problems.label }}</label>
|
|
{{ form.related_problems }}
|
|
{% if form.related_problems.help_text %}
|
|
<div class="form-text">{{ form.related_problems.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.related_care_plans.id_for_label }}" class="form-label">{{ form.related_care_plans.label }}</label>
|
|
{{ form.related_care_plans }}
|
|
{% if form.related_care_plans.help_text %}
|
|
<div class="form-text">{{ form.related_care_plans.help_text }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end panel -->
|
|
|
|
<!-- begin form actions -->
|
|
<div class="d-flex justify-content-between mt-3">
|
|
<a href="{% url 'emr:clinical_note_list' %}" class="btn btn-secondary">
|
|
<i class="fa fa-arrow-left me-1"></i> Cancel
|
|
</a>
|
|
<div>
|
|
<button type="submit" name="save_draft" class="btn btn-primary me-2">
|
|
<i class="fa fa-save me-1"></i> Save as Draft
|
|
</button>
|
|
<button type="submit" name="save_sign" class="btn btn-success">
|
|
<i class="fa fa-signature me-1"></i> Save and Sign
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<!-- end form actions -->
|
|
</form>
|
|
</div>
|
|
<!-- end col-9 -->
|
|
|
|
<!-- begin col-3 -->
|
|
<div class="col-xl-3">
|
|
<!-- begin help sidebar -->
|
|
<div class="help-sidebar">
|
|
<!-- begin templates panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Note Templates</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="mb-3">
|
|
<input type="text" class="form-control" id="templateSearch" placeholder="Search templates...">
|
|
</div>
|
|
<div class="list-group" id="templateList">
|
|
{% for template in note_templates %}
|
|
<div class="template-card card mb-2" data-template-id="{{ template.id }}">
|
|
<div class="card-body p-3">
|
|
<h6 class="card-title mb-1">{{ template.title }}</h6>
|
|
<p class="card-text small text-muted mb-1">{{ template.description|truncatechars:50 }}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span class="badge note-type-{{ template.note_type|lower }}">{{ template.get_note_type_display }}</span>
|
|
<small class="text-muted">v{{ template.version }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="alert alert-info">
|
|
<i class="fa fa-info-circle me-2"></i> No templates available.
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end templates panel -->
|
|
|
|
<!-- begin help panel -->
|
|
<div class="panel panel-inverse mt-3">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Help & Shortcuts</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="help-card card mb-3">
|
|
<div class="card-body">
|
|
<h6 class="card-title"><i class="fa fa-lightbulb me-2"></i> Tips</h6>
|
|
<ul class="mb-0">
|
|
<li>Use structured format for organized notes</li>
|
|
<li>Link to problems and care plans for better context</li>
|
|
<li>Use templates to save time</li>
|
|
<li>Save as draft to continue later</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<h6>Keyboard Shortcuts</h6>
|
|
<div class="shortcut-item">
|
|
<span>Save Draft</span>
|
|
<span class="shortcut-key">Ctrl+S</span>
|
|
</div>
|
|
<div class="shortcut-item">
|
|
<span>Add Section</span>
|
|
<span class="shortcut-key">Ctrl+N</span>
|
|
</div>
|
|
<div class="shortcut-item">
|
|
<span>Bold Text</span>
|
|
<span class="shortcut-key">Ctrl+B</span>
|
|
</div>
|
|
<div class="shortcut-item">
|
|
<span>Italic Text</span>
|
|
<span class="shortcut-key">Ctrl+I</span>
|
|
</div>
|
|
<div class="shortcut-item">
|
|
<span>Underline Text</span>
|
|
<span class="shortcut-key">Ctrl+U</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end help panel -->
|
|
|
|
<!-- begin patient info panel -->
|
|
{% if selected_patient %}
|
|
<div class="panel panel-inverse mt-3">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Patient Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="avatar avatar-lg me-3">
|
|
{% if selected_patient.profile_image %}
|
|
<img src="{{ selected_patient.profile_image.url }}" alt="Patient" class="rounded-circle">
|
|
{% else %}
|
|
<div class="avatar-initials rounded-circle bg-primary text-white">
|
|
{{ selected_patient.get_initials }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<h6 class="mb-0">{{ selected_patient.get_full_name }}</h6>
|
|
<small class="text-muted">
|
|
{{ selected_patient.get_age }} years | {{ selected_patient.get_gender_display }}
|
|
</small>
|
|
<br>
|
|
<small class="text-muted">
|
|
MRN: {{ selected_patient.medical_record_number }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="list-group list-group-flush">
|
|
<a href="{% url 'emr:patient_detail' selected_patient.id %}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
Patient Profile
|
|
<i class="fa fa-chevron-right"></i>
|
|
</a>
|
|
<a href="{% url 'emr:encounter_list' %}?patient={{ selected_patient.id }}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
Encounters
|
|
<i class="fa fa-chevron-right"></i>
|
|
</a>
|
|
<a href="{% url 'emr:problem_list' %}?patient={{ selected_patient.id }}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
Problem List
|
|
<i class="fa fa-chevron-right"></i>
|
|
</a>
|
|
<a href="{% url 'emr:vital_signs_list' %}?patient={{ selected_patient.id }}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
|
Vital Signs
|
|
<i class="fa fa-chevron-right"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
<!-- end patient info panel -->
|
|
</div>
|
|
<!-- end help sidebar -->
|
|
</div>
|
|
<!-- end col-3 -->
|
|
</div>
|
|
<!-- end row -->
|
|
|
|
<!-- begin template preview modal -->
|
|
<div class="modal fade" id="templatePreviewModal" tabindex="-1" aria-labelledby="templatePreviewModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="templatePreviewModalLabel">Template Preview</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="templatePreviewContent"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" id="useTemplateBtn">Use Template</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end template preview modal -->
|
|
|
|
<!-- begin section template -->
|
|
<template id="sectionTemplate">
|
|
<div class="section-card" data-section-id="{sectionId}">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<span class="drag-handle me-2"><i class="fa fa-grip-vertical"></i></span>
|
|
<input type="text" class="form-control form-control-sm section-title" name="section_title_{sectionId}" placeholder="Section Title" style="width: 300px;">
|
|
</div>
|
|
<div class="section-actions">
|
|
<button type="button" class="btn btn-sm btn-outline-danger remove-section-btn">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<textarea class="form-control section-content summernote" name="section_content_{sectionId}" rows="5"></textarea>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<!-- end section template -->
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'plugins/summernote/dist/summernote-bs4.min.js' %}"></script>
|
|
<script src="{% static 'plugins/sortablejs/Sortable.min.js' %}"></script>
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize Summernote
|
|
$('.summernote').summernote({
|
|
height: 200,
|
|
toolbar: [
|
|
['style', ['style']],
|
|
['font', ['bold', 'italic', 'underline', 'clear']],
|
|
['fontname', ['fontname']],
|
|
['color', ['color']],
|
|
['para', ['ul', 'ol', 'paragraph']],
|
|
['table', ['table']],
|
|
['insert', ['link']],
|
|
['view', ['fullscreen', 'codeview', 'help']]
|
|
],
|
|
callbacks: {
|
|
onImageUpload: function(files) {
|
|
// Custom image upload handler if needed
|
|
}
|
|
}
|
|
});
|
|
|
|
// Toggle between structured and simple content
|
|
$('#useStructuredContent').change(function() {
|
|
if ($(this).is(':checked')) {
|
|
$('#structuredContentContainer').show();
|
|
$('#simpleContentContainer').hide();
|
|
$('#addSectionBtn').show();
|
|
} else {
|
|
$('#structuredContentContainer').hide();
|
|
$('#simpleContentContainer').show();
|
|
$('#addSectionBtn').hide();
|
|
}
|
|
});
|
|
|
|
// Add new section
|
|
let sectionCounter = $('.section-card').length;
|
|
$('#addSectionBtn').click(function() {
|
|
const sectionTemplate = document.getElementById('sectionTemplate').innerHTML;
|
|
const newSection = sectionTemplate.replace(/{sectionId}/g, sectionCounter);
|
|
$('#sectionsList').append(newSection);
|
|
|
|
// Initialize Summernote for the new section
|
|
$(`[name="section_content_${sectionCounter}"]`).summernote({
|
|
height: 200,
|
|
toolbar: [
|
|
['style', ['style']],
|
|
['font', ['bold', 'italic', 'underline', 'clear']],
|
|
['fontname', ['fontname']],
|
|
['color', ['color']],
|
|
['para', ['ul', 'ol', 'paragraph']],
|
|
['table', ['table']],
|
|
['insert', ['link']],
|
|
['view', ['fullscreen', 'codeview', 'help']]
|
|
]
|
|
});
|
|
|
|
sectionCounter++;
|
|
});
|
|
|
|
// Remove section
|
|
$(document).on('click', '.remove-section-btn', function() {
|
|
$(this).closest('.section-card').remove();
|
|
});
|
|
|
|
// Make sections sortable
|
|
const sectionsList = document.getElementById('sectionsList');
|
|
if (sectionsList) {
|
|
new Sortable(sectionsList, {
|
|
handle: '.drag-handle',
|
|
animation: 150
|
|
});
|
|
}
|
|
|
|
// Template search
|
|
$('#templateSearch').on('input', function() {
|
|
const searchTerm = $(this).val().toLowerCase();
|
|
$('.template-card').each(function() {
|
|
const title = $(this).find('.card-title').text().toLowerCase();
|
|
const description = $(this).find('.card-text').text().toLowerCase();
|
|
if (title.includes(searchTerm) || description.includes(searchTerm)) {
|
|
$(this).show();
|
|
} else {
|
|
$(this).hide();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Template selection
|
|
$('.template-card').click(function() {
|
|
const templateId = $(this).data('template-id');
|
|
|
|
// AJAX call to get template content
|
|
$.ajax({
|
|
url: `/emr/note-templates/${templateId}/preview/`,
|
|
type: 'GET',
|
|
success: function(data) {
|
|
$('#templatePreviewContent').html(data.content);
|
|
$('#templatePreviewModalLabel').text(data.title);
|
|
$('#useTemplateBtn').data('template-id', templateId);
|
|
$('#templatePreviewModal').modal('show');
|
|
},
|
|
error: function() {
|
|
alert('Error loading template preview');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Use template button
|
|
$('#useTemplateBtn').click(function() {
|
|
const templateId = $(this).data('template-id');
|
|
|
|
// AJAX call to get template content
|
|
$.ajax({
|
|
url: `/emr/note-templates/${templateId}/content/`,
|
|
type: 'GET',
|
|
success: function(data) {
|
|
if (data.structured_content) {
|
|
// Switch to structured content mode
|
|
$('#useStructuredContent').prop('checked', true).trigger('change');
|
|
|
|
// Clear existing sections
|
|
$('#sectionsList').empty();
|
|
|
|
// Add sections from template
|
|
sectionCounter = 0;
|
|
data.structured_content.forEach(function(section) {
|
|
const sectionTemplate = document.getElementById('sectionTemplate').innerHTML;
|
|
const newSection = sectionTemplate.replace(/{sectionId}/g, sectionCounter);
|
|
$('#sectionsList').append(newSection);
|
|
|
|
// Set section title and content
|
|
$(`[name="section_title_${sectionCounter}"]`).val(section.title);
|
|
$(`[name="section_content_${sectionCounter}"]`).summernote('code', section.content);
|
|
|
|
sectionCounter++;
|
|
});
|
|
} else {
|
|
// Switch to simple content mode
|
|
$('#useStructuredContent').prop('checked', false).trigger('change');
|
|
|
|
// Set content
|
|
$('#content').summernote('code', data.content);
|
|
}
|
|
|
|
// Set note type if available
|
|
if (data.note_type) {
|
|
$('#id_note_type').val(data.note_type);
|
|
}
|
|
|
|
$('#templatePreviewModal').modal('hide');
|
|
},
|
|
error: function() {
|
|
alert('Error loading template content');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Form submission
|
|
$('#clinicalNoteForm').submit(function() {
|
|
// If using structured content, collect all sections into a hidden field
|
|
if ($('#useStructuredContent').is(':checked')) {
|
|
const structuredContent = [];
|
|
$('.section-card').each(function(index) {
|
|
const sectionId = $(this).data('section-id');
|
|
const title = $(this).find('.section-title').val();
|
|
const content = $(this).find('.section-content').summernote('code');
|
|
|
|
structuredContent.push({
|
|
title: title,
|
|
content: content
|
|
});
|
|
});
|
|
|
|
// Add hidden field with structured content JSON
|
|
$('<input>').attr({
|
|
type: 'hidden',
|
|
name: 'structured_content',
|
|
value: JSON.stringify(structuredContent)
|
|
}).appendTo('#clinicalNoteForm');
|
|
}
|
|
});
|
|
|
|
// Keyboard shortcuts
|
|
$(document).keydown(function(e) {
|
|
// Ctrl+S for save draft
|
|
if (e.ctrlKey && e.keyCode === 83) {
|
|
e.preventDefault();
|
|
$('button[name="save_draft"]').click();
|
|
}
|
|
|
|
// Ctrl+N for add section
|
|
if (e.ctrlKey && e.keyCode === 78) {
|
|
e.preventDefault();
|
|
$('#addSectionBtn').click();
|
|
}
|
|
});
|
|
|
|
// Patient selection change
|
|
$('#id_patient').change(function() {
|
|
const patientId = $(this).val();
|
|
if (patientId) {
|
|
// AJAX call to get patient encounters
|
|
$.ajax({
|
|
url: `/emr/patients/${patientId}/encounters/`,
|
|
type: 'GET',
|
|
success: function(data) {
|
|
// Update encounter dropdown
|
|
const encounterSelect = $('#id_related_encounter');
|
|
encounterSelect.empty();
|
|
encounterSelect.append('<option value="">---------</option>');
|
|
|
|
data.encounters.forEach(function(encounter) {
|
|
encounterSelect.append(`<option value="${encounter.id}">${encounter.encounter_type} - ${encounter.start_time}</option>`);
|
|
});
|
|
}
|
|
});
|
|
|
|
// AJAX call to get patient problems
|
|
$.ajax({
|
|
url: `/emr/patients/${patientId}/problems/`,
|
|
type: 'GET',
|
|
success: function(data) {
|
|
// Update problems multiselect
|
|
const problemsSelect = $('#id_related_problems');
|
|
problemsSelect.empty();
|
|
|
|
data.problems.forEach(function(problem) {
|
|
problemsSelect.append(`<option value="${problem.id}">${problem.problem_name}</option>`);
|
|
});
|
|
}
|
|
});
|
|
|
|
// AJAX call to get patient care plans
|
|
$.ajax({
|
|
url: `/emr/patients/${patientId}/care-plans/`,
|
|
type: 'GET',
|
|
success: function(data) {
|
|
// Update care plans multiselect
|
|
const carePlansSelect = $('#id_related_care_plans');
|
|
carePlansSelect.empty();
|
|
|
|
data.care_plans.forEach(function(carePlan) {
|
|
carePlansSelect.append(`<option value="${carePlan.id}">${carePlan.title}</option>`);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|