551 lines
26 KiB
HTML
551 lines
26 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{% if object %}Edit Encounter{% else %}New Encounter{% endif %} - {{ block.super }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h1 class="h3 mb-1">
|
|
{% if object %}
|
|
<i class="fas fa-edit me-2"></i>Edit Encounter
|
|
{% else %}
|
|
<i class="fas fa-plus me-2"></i>New Encounter
|
|
{% endif %}
|
|
</h1>
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb mb-0">
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:dashboard' %}">EMR</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:encounter_list' %}">Encounters</a></li>
|
|
{% if object %}
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:encounter_detail' object.pk %}">{{ object.encounter_id|truncatechars:8 }}</a></li>
|
|
<li class="breadcrumb-item active">Edit</li>
|
|
{% else %}
|
|
<li class="breadcrumb-item active">New</li>
|
|
{% endif %}
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
<div class="btn-group">
|
|
<a href="{% if object %}{% url 'emr:encounter_detail' object.pk %}{% else %}{% url 'emr:encounter_list' %}{% endif %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-2"></i>Back
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<div class="row">
|
|
<!-- Main Form -->
|
|
<div class="col-lg-8">
|
|
<!-- Patient and Provider Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-user-md me-2"></i>Patient & Provider Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.patient.id_for_label }}" class="form-label">
|
|
Patient <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.patient }}
|
|
{% if form.patient.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.patient.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Select the patient for this encounter</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.provider.id_for_label }}" class="form-label">
|
|
Primary Provider <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.provider }}
|
|
{% if form.provider.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.provider.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Primary care provider for this encounter</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Encounter Details -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-clipboard-list me-2"></i>Encounter Details
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.encounter_type.id_for_label }}" class="form-label">
|
|
Encounter Type <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.encounter_type }}
|
|
{% if form.encounter_type.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.encounter_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.encounter_class.id_for_label }}" class="form-label">
|
|
Encounter Class <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.encounter_class }}
|
|
{% if form.encounter_class.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.encounter_class.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">HL7 standard encounter classification</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.start_datetime.id_for_label }}" class="form-label">
|
|
Start Date & Time <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.start_datetime }}
|
|
{% if form.start_datetime.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.start_datetime.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.end_datetime.id_for_label }}" class="form-label">
|
|
End Date & Time
|
|
</label>
|
|
{{ form.end_datetime }}
|
|
{% if form.end_datetime.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.end_datetime.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Leave empty if encounter is ongoing</div>
|
|
</div>
|
|
</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 <span class="text-danger">*</span>
|
|
</label>
|
|
{{ form.status }}
|
|
{% if form.status.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ 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>
|
|
{{ form.priority }}
|
|
{% if form.priority.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.priority.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Clinical Information -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-stethoscope me-2"></i>Clinical Information
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label for="{{ form.chief_complaint.id_for_label }}" class="form-label">
|
|
Chief Complaint
|
|
</label>
|
|
{{ form.chief_complaint }}
|
|
{% if form.chief_complaint.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.chief_complaint.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Primary reason for the encounter</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ form.history_present_illness.id_for_label }}" class="form-label">
|
|
History of Present Illness
|
|
</label>
|
|
{{ form.history_present_illness }}
|
|
{% if form.history_present_illness.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.history_present_illness.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.diagnosis_primary.id_for_label }}" class="form-label">
|
|
Primary Diagnosis
|
|
</label>
|
|
{{ form.diagnosis_primary }}
|
|
{% if form.diagnosis_primary.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.diagnosis_primary.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.diagnosis_secondary.id_for_label }}" class="form-label">
|
|
Secondary Diagnoses
|
|
</label>
|
|
{{ form.diagnosis_secondary }}
|
|
{% if form.diagnosis_secondary.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.diagnosis_secondary.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">Separate multiple diagnoses with commas</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Location and Billing -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-map-marker-alt me-2"></i>Location & Billing
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.location.id_for_label }}" class="form-label">
|
|
Location
|
|
</label>
|
|
{{ form.location }}
|
|
{% if form.location.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.location.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.room_number.id_for_label }}" class="form-label">
|
|
Room Number
|
|
</label>
|
|
{{ form.room_number }}
|
|
{% if form.room_number.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.room_number.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.service_type.id_for_label }}" class="form-label">
|
|
Service Type
|
|
</label>
|
|
{{ form.service_type }}
|
|
{% if form.service_type.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.service_type.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label for="{{ form.billing_code.id_for_label }}" class="form-label">
|
|
Billing Code
|
|
</label>
|
|
{{ form.billing_code }}
|
|
{% if form.billing_code.errors %}
|
|
<div class="invalid-feedback d-block">
|
|
{{ form.billing_code.errors.0 }}
|
|
</div>
|
|
{% endif %}
|
|
<div class="form-text">CPT or procedure code for billing</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="col-lg-4">
|
|
<!-- Status & Actions -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-toggle-on me-2"></i>Status & Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if object %}
|
|
<div class="mb-3">
|
|
<label class="form-label text-muted">Encounter ID</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" value="{{ object.encounter_id }}" readonly>
|
|
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('{{ object.encounter_id }}')">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="mb-3">
|
|
<div class="form-check form-switch">
|
|
{{ form.documentation_complete }}
|
|
<label class="form-check-label" for="{{ form.documentation_complete.id_for_label }}">
|
|
Documentation Complete
|
|
</label>
|
|
</div>
|
|
<div class="form-text">Mark when all documentation is finished</div>
|
|
</div>
|
|
|
|
<div class="d-grid gap-2">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save me-2"></i>
|
|
{% if object %}Update Encounter{% else %}Create Encounter{% endif %}
|
|
</button>
|
|
<a href="{% if object %}{% url 'emr:encounter_detail' object.pk %}{% else %}{% url 'emr:encounter_list' %}{% endif %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-times me-2"></i>Cancel
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
{% if object %}
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-bolt me-2"></i>Quick Actions
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="{% url 'emr:add_vital_signs' object.id %}" class="btn btn-outline-success btn-sm">
|
|
<i class="fas fa-heartbeat me-2"></i>Add Vital Signs
|
|
</a>
|
|
<a href="{% url 'emr:add_problem' object.patient.id %}" class="btn btn-outline-warning btn-sm">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>Add Problem
|
|
</a>
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="addClinicalNote()">
|
|
<i class="fas fa-notes-medical me-2"></i>Add Clinical Note
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Help & Guidelines -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="mb-0">
|
|
<i class="fas fa-question-circle me-2"></i>Help & Guidelines
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="accordion" id="helpAccordion">
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#helpEncounterTypes">
|
|
Encounter Types
|
|
</button>
|
|
</h2>
|
|
<div id="helpEncounterTypes" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="mb-0">
|
|
<li><strong>Inpatient:</strong> Admitted to hospital</li>
|
|
<li><strong>Outpatient:</strong> Clinic or office visit</li>
|
|
<li><strong>Emergency:</strong> Emergency department visit</li>
|
|
<li><strong>Telemedicine:</strong> Virtual consultation</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#helpDocumentation">
|
|
Documentation Tips
|
|
</button>
|
|
</h2>
|
|
<div id="helpDocumentation" class="accordion-collapse collapse" data-bs-parent="#helpAccordion">
|
|
<div class="accordion-body">
|
|
<ul class="mb-0">
|
|
<li>Be specific and objective in descriptions</li>
|
|
<li>Include relevant medical history</li>
|
|
<li>Document all procedures and treatments</li>
|
|
<li>Use standard medical terminology</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
// Form validation and enhancement
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Add Bootstrap validation classes
|
|
const form = document.querySelector('form');
|
|
const inputs = form.querySelectorAll('input, select, textarea');
|
|
|
|
inputs.forEach(input => {
|
|
if (!input.classList.contains('form-control') && !input.classList.contains('form-select') && !input.classList.contains('form-check-input')) {
|
|
if (input.type === 'checkbox') {
|
|
input.classList.add('form-check-input');
|
|
} else if (input.tagName === 'SELECT') {
|
|
input.classList.add('form-select');
|
|
} else {
|
|
input.classList.add('form-control');
|
|
}
|
|
}
|
|
|
|
// Add validation feedback
|
|
if (input.hasAttribute('required')) {
|
|
input.addEventListener('invalid', function() {
|
|
input.classList.add('is-invalid');
|
|
});
|
|
|
|
input.addEventListener('input', function() {
|
|
if (input.validity.valid) {
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Set default start datetime to now if creating new encounter
|
|
{% if not object %}
|
|
const startDatetime = document.getElementById('{{ form.start_datetime.id_for_label }}');
|
|
if (startDatetime && !startDatetime.value) {
|
|
const now = new Date();
|
|
const localISOTime = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().slice(0, 16);
|
|
startDatetime.value = localISOTime;
|
|
}
|
|
{% endif %}
|
|
});
|
|
|
|
function copyToClipboard(text) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
const button = event.target.closest('button');
|
|
const originalIcon = button.innerHTML;
|
|
button.innerHTML = '<i class="fas fa-check"></i>';
|
|
button.classList.add('btn-success');
|
|
button.classList.remove('btn-outline-secondary');
|
|
|
|
setTimeout(() => {
|
|
button.innerHTML = originalIcon;
|
|
button.classList.remove('btn-success');
|
|
button.classList.add('btn-outline-secondary');
|
|
}, 2000);
|
|
});
|
|
}
|
|
|
|
function addClinicalNote() {
|
|
// Implementation would depend on your clinical note creation workflow
|
|
alert('Clinical note creation functionality would be implemented here');
|
|
}
|
|
|
|
// Form submission with loading state
|
|
document.querySelector('form').addEventListener('submit', function() {
|
|
const submitBtn = document.querySelector('button[type="submit"]');
|
|
const originalText = submitBtn.innerHTML;
|
|
|
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-2"></i>Saving...';
|
|
submitBtn.disabled = true;
|
|
|
|
// Re-enable if form validation fails
|
|
setTimeout(() => {
|
|
if (document.querySelector('.is-invalid')) {
|
|
submitBtn.innerHTML = originalText;
|
|
submitBtn.disabled = false;
|
|
}
|
|
}, 100);
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.is-invalid {
|
|
border-color: #dc3545;
|
|
}
|
|
|
|
.is-valid {
|
|
border-color: #198754;
|
|
}
|
|
|
|
.invalid-feedback {
|
|
display: block;
|
|
width: 100%;
|
|
margin-top: 0.25rem;
|
|
font-size: 0.875em;
|
|
color: #dc3545;
|
|
}
|
|
|
|
.accordion-button:not(.collapsed) {
|
|
background-color: #e7f1ff;
|
|
color: #0d6efd;
|
|
}
|
|
|
|
.form-check-input:checked {
|
|
background-color: #0d6efd;
|
|
border-color: #0d6efd;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|