623 lines
26 KiB
HTML
623 lines
26 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Clinical Note{% else %}New Clinical Note{% endif %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div>
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:dashboard' %}">EMR</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:clinical_note_list' %}">Clinical Notes</a></li>
|
|
<li class="breadcrumb-item active">{% if object %}Edit{% else %}New{% endif %}</li>
|
|
</ol>
|
|
<h1 class="page-header mb-0">
|
|
{% if object %}Edit Clinical Note{% else %}Create Clinical Note{% endif %}
|
|
</h1>
|
|
</div>
|
|
<div class="ms-auto">
|
|
<a href="{% url 'emr:clinical_note_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">
|
|
<i class="fas fa-notes-medical me-2"></i>
|
|
Clinical Note Details
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if messages %}
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.patient.id_for_label }}" class="form-label">Patient *</label>
|
|
<select class="form-select {% if form.patient.errors %}is-invalid{% endif %}"
|
|
id="{{ form.patient.id_for_label }}"
|
|
name="{{ form.patient.name }}"
|
|
required>
|
|
<option value="">Select Patient</option>
|
|
{% for choice in form.patient.field.choices %}
|
|
{% if choice.0 %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.patient.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.patient.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.patient.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.encounter.id_for_label }}" class="form-label">Encounter</label>
|
|
<select class="form-select {% if form.encounter.errors %}is-invalid{% endif %}"
|
|
id="{{ form.encounter.id_for_label }}"
|
|
name="{{ form.encounter.name }}">
|
|
<option value="">Select Encounter (Optional)</option>
|
|
{% for choice in form.encounter.field.choices %}
|
|
{% if choice.0 %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.encounter.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.encounter.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.encounter.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.note_type.id_for_label }}" class="form-label">Note Type *</label>
|
|
<select class="form-select {% if form.note_type.errors %}is-invalid{% endif %}"
|
|
id="{{ form.note_type.id_for_label }}"
|
|
name="{{ form.note_type.name }}"
|
|
required>
|
|
<option value="">Select Note Type</option>
|
|
{% for choice in form.note_type.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.note_type.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.note_type.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.note_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.template.id_for_label }}" class="form-label">Template</label>
|
|
<select class="form-select {% if form.template.errors %}is-invalid{% endif %}"
|
|
id="{{ form.template.id_for_label }}"
|
|
name="{{ form.template.name }}">
|
|
<option value="">Select Template (Optional)</option>
|
|
{% for choice in form.template.field.choices %}
|
|
{% if choice.0 %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.template.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.template.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.template.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.title.id_for_label }}" class="form-label">Title *</label>
|
|
<input type="text"
|
|
class="form-control {% if form.title.errors %}is-invalid{% endif %}"
|
|
id="{{ form.title.id_for_label }}"
|
|
name="{{ form.title.name }}"
|
|
value="{{ form.title.value|default:'' }}"
|
|
placeholder="Enter note title"
|
|
required>
|
|
{% if form.title.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.title.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.content.id_for_label }}" class="form-label">Content *</label>
|
|
<textarea class="form-control {% if form.content.errors %}is-invalid{% endif %}"
|
|
id="{{ form.content.id_for_label }}"
|
|
name="{{ form.content.name }}"
|
|
rows="12"
|
|
placeholder="Enter clinical note content..."
|
|
required>{{ form.content.value|default:'' }}</textarea>
|
|
{% if form.content.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.content.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">
|
|
Use the toolbar above for formatting options. You can also use templates to speed up documentation.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.status.id_for_label }}" class="form-label">Status</label>
|
|
<select class="form-select {% if form.status.errors %}is-invalid{% endif %}"
|
|
id="{{ form.status.id_for_label }}"
|
|
name="{{ form.status.name }}">
|
|
{% for choice in form.status.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.status.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.status.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.priority.id_for_label }}" class="form-label">Priority</label>
|
|
<select class="form-select {% if form.priority.errors %}is-invalid{% endif %}"
|
|
id="{{ form.priority.id_for_label }}"
|
|
name="{{ form.priority.name }}">
|
|
{% for choice in form.priority.field.choices %}
|
|
<option value="{{ choice.0 }}" {% if choice.0 == form.priority.value %}selected{% endif %}>
|
|
{{ choice.1 }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
{% if form.priority.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.priority.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
id="{{ form.is_confidential.id_for_label }}"
|
|
name="{{ form.is_confidential.name }}"
|
|
{% if form.is_confidential.value %}checked{% endif %}>
|
|
<label class="form-check-label" for="{{ form.is_confidential.id_for_label }}">
|
|
Confidential Note
|
|
</label>
|
|
<div class="form-text">
|
|
Confidential notes have restricted access
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="form-check mb-3">
|
|
<input class="form-check-input"
|
|
type="checkbox"
|
|
id="{{ form.requires_cosign.id_for_label }}"
|
|
name="{{ form.requires_cosign.name }}"
|
|
{% if form.requires_cosign.value %}checked{% endif %}>
|
|
<label class="form-check-label" for="{{ form.requires_cosign.id_for_label }}">
|
|
Requires Co-signature
|
|
</label>
|
|
<div class="form-text">
|
|
Note requires approval from supervising physician
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.tags.id_for_label }}" class="form-label">Tags</label>
|
|
<input type="text"
|
|
class="form-control {% if form.tags.errors %}is-invalid{% endif %}"
|
|
id="{{ form.tags.id_for_label }}"
|
|
name="{{ form.tags.name }}"
|
|
value="{{ form.tags.value|default:'' }}"
|
|
placeholder="Enter tags separated by commas">
|
|
{% if form.tags.errors %}
|
|
<div class="invalid-feedback">
|
|
{{ form.tags.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">
|
|
Tags help categorize and search notes (e.g., follow-up, urgent, consultation)
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
{% if object %}
|
|
<a href="{% url 'emr:clinical_note_detail' object.pk %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% else %}
|
|
<a href="{% url 'emr:clinical_note_list' %}" class="btn btn-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-outline-primary me-2" onclick="saveDraft()">
|
|
<i class="fas fa-save me-2"></i>Save as Draft
|
|
</button>
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-check me-2"></i>
|
|
{% if object %}Update Note{% else %}Create Note{% endif %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- Note Templates -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-file-medical me-2"></i>
|
|
Quick Templates
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('soap')">
|
|
<i class="fas fa-notes-medical me-2"></i>SOAP Note
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('progress')">
|
|
<i class="fas fa-chart-line me-2"></i>Progress Note
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('discharge')">
|
|
<i class="fas fa-sign-out-alt me-2"></i>Discharge Summary
|
|
</button>
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="loadTemplate('consultation')">
|
|
<i class="fas fa-user-md me-2"></i>Consultation Note
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-user me-2"></i>
|
|
Patient Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="patient-info">
|
|
<div class="text-center text-muted">
|
|
<i class="fas fa-user fa-2x mb-2"></i>
|
|
<div>Select a patient to view information</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Notes -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-history me-2"></i>
|
|
Recent Notes
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="recent-notes">
|
|
<div class="text-center text-muted">
|
|
<i class="fas fa-notes-medical fa-2x mb-2"></i>
|
|
<div>Select a patient to view recent notes</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Documentation Guidelines -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Documentation Guidelines
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-unstyled mb-0">
|
|
<li class="mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
Use clear, objective language
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
Include relevant clinical details
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
Document patient responses
|
|
</li>
|
|
<li class="mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
Note any changes in condition
|
|
</li>
|
|
<li>
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
Include follow-up plans
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const patientSelect = document.getElementById('{{ form.patient.id_for_label }}');
|
|
const encounterSelect = document.getElementById('{{ form.encounter.id_for_label }}');
|
|
const templateSelect = document.getElementById('{{ form.template.id_for_label }}');
|
|
const contentTextarea = document.getElementById('{{ form.content.id_for_label }}');
|
|
|
|
// Load patient information when patient changes
|
|
patientSelect.addEventListener('change', function() {
|
|
const patientId = this.value;
|
|
if (patientId) {
|
|
loadPatientInfo(patientId);
|
|
loadRecentNotes(patientId);
|
|
loadPatientEncounters(patientId);
|
|
} else {
|
|
clearPatientInfo();
|
|
}
|
|
});
|
|
|
|
// Load template content when template changes
|
|
templateSelect.addEventListener('change', function() {
|
|
const templateId = this.value;
|
|
if (templateId) {
|
|
loadTemplateContent(templateId);
|
|
}
|
|
});
|
|
|
|
// Auto-save functionality
|
|
let autoSaveTimer;
|
|
contentTextarea.addEventListener('input', function() {
|
|
clearTimeout(autoSaveTimer);
|
|
autoSaveTimer = setTimeout(autoSave, 30000); // Auto-save after 30 seconds of inactivity
|
|
});
|
|
});
|
|
|
|
function loadPatientInfo(patientId) {
|
|
// Simulate loading patient information
|
|
const patientInfoDiv = document.getElementById('patient-info');
|
|
patientInfoDiv.innerHTML = `
|
|
<div class="text-center">
|
|
<div class="spinner-border spinner-border-sm text-primary mb-2" role="status"></div>
|
|
<div class="small">Loading patient information...</div>
|
|
</div>
|
|
`;
|
|
|
|
// Simulate API call
|
|
setTimeout(() => {
|
|
patientInfoDiv.innerHTML = `
|
|
<div class="mb-2">
|
|
<strong>Name:</strong> John Doe
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>DOB:</strong> 01/15/1980
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>MRN:</strong> MRN123456
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>Allergies:</strong> Penicillin
|
|
</div>
|
|
<div>
|
|
<strong>Current Medications:</strong> Lisinopril, Metformin
|
|
</div>
|
|
`;
|
|
}, 1000);
|
|
}
|
|
|
|
function loadRecentNotes(patientId) {
|
|
const recentNotesDiv = document.getElementById('recent-notes');
|
|
recentNotesDiv.innerHTML = `
|
|
<div class="text-center">
|
|
<div class="spinner-border spinner-border-sm text-primary mb-2" role="status"></div>
|
|
<div class="small">Loading recent notes...</div>
|
|
</div>
|
|
`;
|
|
|
|
setTimeout(() => {
|
|
recentNotesDiv.innerHTML = `
|
|
<div class="small mb-2">
|
|
<strong>Progress Note</strong> - 2 days ago
|
|
<div class="text-muted">Patient improving, continue current treatment...</div>
|
|
</div>
|
|
<div class="small mb-2">
|
|
<strong>Consultation</strong> - 1 week ago
|
|
<div class="text-muted">Cardiology consultation for chest pain...</div>
|
|
</div>
|
|
<div class="small">
|
|
<strong>Admission Note</strong> - 2 weeks ago
|
|
<div class="text-muted">Admitted for acute exacerbation...</div>
|
|
</div>
|
|
`;
|
|
}, 1000);
|
|
}
|
|
|
|
function loadPatientEncounters(patientId) {
|
|
// Update encounter dropdown with patient's encounters
|
|
const encounterSelect = document.getElementById('{{ form.encounter.id_for_label }}');
|
|
// In a real implementation, this would fetch encounters via AJAX
|
|
}
|
|
|
|
function clearPatientInfo() {
|
|
document.getElementById('patient-info').innerHTML = `
|
|
<div class="text-center text-muted">
|
|
<i class="fas fa-user fa-2x mb-2"></i>
|
|
<div>Select a patient to view information</div>
|
|
</div>
|
|
`;
|
|
|
|
document.getElementById('recent-notes').innerHTML = `
|
|
<div class="text-center text-muted">
|
|
<i class="fas fa-notes-medical fa-2x mb-2"></i>
|
|
<div>Select a patient to view recent notes</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function loadTemplate(templateType) {
|
|
const contentTextarea = document.getElementById('{{ form.content.id_for_label }}');
|
|
const titleInput = document.getElementById('{{ form.title.id_for_label }}');
|
|
|
|
let templateContent = '';
|
|
let templateTitle = '';
|
|
|
|
switch(templateType) {
|
|
case 'soap':
|
|
templateTitle = 'SOAP Note';
|
|
templateContent = `SUBJECTIVE:
|
|
Patient reports...
|
|
|
|
OBJECTIVE:
|
|
Vital Signs:
|
|
Physical Examination:
|
|
|
|
ASSESSMENT:
|
|
1.
|
|
2.
|
|
|
|
PLAN:
|
|
1.
|
|
2. `;
|
|
break;
|
|
case 'progress':
|
|
templateTitle = 'Progress Note';
|
|
templateContent = `PROGRESS NOTE
|
|
|
|
Current Status:
|
|
Patient continues to...
|
|
|
|
Interval History:
|
|
Since last visit...
|
|
|
|
Physical Examination:
|
|
General appearance:
|
|
Vital signs:
|
|
|
|
Assessment and Plan:
|
|
1.
|
|
2. `;
|
|
break;
|
|
case 'discharge':
|
|
templateTitle = 'Discharge Summary';
|
|
templateContent = `DISCHARGE SUMMARY
|
|
|
|
Admission Date:
|
|
Discharge Date:
|
|
Length of Stay:
|
|
|
|
Admitting Diagnosis:
|
|
Discharge Diagnosis:
|
|
|
|
Hospital Course:
|
|
Patient was admitted for...
|
|
|
|
Discharge Medications:
|
|
1.
|
|
2.
|
|
|
|
Follow-up:
|
|
-
|
|
- `;
|
|
break;
|
|
case 'consultation':
|
|
templateTitle = 'Consultation Note';
|
|
templateContent = `CONSULTATION NOTE
|
|
|
|
Reason for Consultation:
|
|
Patient referred for...
|
|
|
|
History of Present Illness:
|
|
|
|
Past Medical History:
|
|
|
|
Physical Examination:
|
|
|
|
Impression:
|
|
1.
|
|
2.
|
|
|
|
Recommendations:
|
|
1.
|
|
2. `;
|
|
break;
|
|
}
|
|
|
|
if (confirm(`Load ${templateTitle} template? This will replace current content.`)) {
|
|
titleInput.value = templateTitle;
|
|
contentTextarea.value = templateContent;
|
|
}
|
|
}
|
|
|
|
function loadTemplateContent(templateId) {
|
|
// In a real implementation, this would fetch template content via AJAX
|
|
console.log('Loading template:', templateId);
|
|
}
|
|
|
|
function saveDraft() {
|
|
const statusSelect = document.getElementById('{{ form.status.id_for_label }}');
|
|
statusSelect.value = 'draft';
|
|
|
|
// Submit form
|
|
document.querySelector('form').submit();
|
|
}
|
|
|
|
function autoSave() {
|
|
// In a real implementation, this would save draft via AJAX
|
|
console.log('Auto-saving draft...');
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|