1055 lines
50 KiB
HTML
1055 lines
50 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Progress Note{% endblock %}
|
|
|
|
{% block content %}
|
|
<div id="content" class="app-content">
|
|
<div class="container">
|
|
<ul class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'emr:dashboard' %}">EMR</a></li>
|
|
<li class="breadcrumb-item active">Progress Note</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Progress Note</h1>
|
|
<p class="text-muted">Document patient progress and clinical observations</p>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="btn-group">
|
|
{% if progress_note %}
|
|
<button class="btn btn-primary" onclick="saveProgressNote()">
|
|
<i class="fa fa-save me-2"></i>Save Note
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="printNote()">
|
|
<i class="fa fa-print me-2"></i>Print
|
|
</button>
|
|
<button class="btn btn-outline-info" onclick="addendum()">
|
|
<i class="fa fa-plus me-2"></i>Addendum
|
|
</button>
|
|
{% else %}
|
|
<button class="btn btn-primary" onclick="createProgressNote()">
|
|
<i class="fa fa-plus me-2"></i>Create Note
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Information -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Patient Information</h4>
|
|
<div class="card-tools">
|
|
<button class="btn btn-outline-primary btn-sm" onclick="selectPatient()">
|
|
<i class="fa fa-search me-1"></i>Select Patient
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if patient %}
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<p><strong>Name:</strong> {{ patient.first_name }} {{ patient.last_name }}</p>
|
|
<p><strong>DOB:</strong> {{ patient.date_of_birth|date:"M d, Y" }}</p>
|
|
<p><strong>Age:</strong> {{ patient.age }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>MRN:</strong> {{ patient.patient_id }}</p>
|
|
<p><strong>Gender:</strong> {{ patient.get_gender_display }}</p>
|
|
<p><strong>Room:</strong> {{ patient.current_room|default:"Outpatient" }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>Attending:</strong> {{ encounter.attending_physician|default:"Not assigned" }}</p>
|
|
<p><strong>Admission Date:</strong> {{ encounter.start_date|date:"M d, Y"|default:"N/A" }}</p>
|
|
<p><strong>Day #:</strong> {{ hospital_day|default:"N/A" }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>Primary Diagnosis:</strong> {{ encounter.primary_diagnosis|default:"Not documented" }}</p>
|
|
<p><strong>Allergies:</strong> {{ patient.allergies|default:"NKDA" }}</p>
|
|
<p><strong>Code Status:</strong> {{ patient.code_status|default:"Full Code" }}</p>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-3">
|
|
<i class="fa fa-user fa-2x text-muted mb-2"></i>
|
|
<p class="text-muted">No patient selected. Please select a patient to create progress note.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if patient %}
|
|
<!-- Progress Note Form -->
|
|
<form id="progressNoteForm">
|
|
{% csrf_token %}
|
|
<input type="hidden" name="patient_id" value="{{ patient.patient_id }}">
|
|
<input type="hidden" name="encounter_id" value="{{ encounter.id }}">
|
|
|
|
<!-- Note Header -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Note Information</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Note Date & Time</label>
|
|
<input type="datetime-local" class="form-control" name="note_datetime"
|
|
value="{{ progress_note.note_datetime|date:'Y-m-d\TH:i'|default:now }}" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Note Type</label>
|
|
<select class="form-select" name="note_type" required>
|
|
<option value="">Select note type...</option>
|
|
<option value="progress" {% if progress_note.note_type == 'progress' %}selected{% endif %}>Progress Note</option>
|
|
<option value="admission" {% if progress_note.note_type == 'admission' %}selected{% endif %}>Admission Note</option>
|
|
<option value="consultation" {% if progress_note.note_type == 'consultation' %}selected{% endif %}>Consultation</option>
|
|
<option value="procedure" {% if progress_note.note_type == 'procedure' %}selected{% endif %}>Procedure Note</option>
|
|
<option value="discharge" {% if progress_note.note_type == 'discharge' %}selected{% endif %}>Discharge Note</option>
|
|
<option value="transfer" {% if progress_note.note_type == 'transfer' %}selected{% endif %}>Transfer Note</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Service</label>
|
|
<select class="form-select" name="service">
|
|
<option value="">Select service...</option>
|
|
<option value="internal_medicine" {% if progress_note.service == 'internal_medicine' %}selected{% endif %}>Internal Medicine</option>
|
|
<option value="surgery" {% if progress_note.service == 'surgery' %}selected{% endif %}>Surgery</option>
|
|
<option value="cardiology" {% if progress_note.service == 'cardiology' %}selected{% endif %}>Cardiology</option>
|
|
<option value="neurology" {% if progress_note.service == 'neurology' %}selected{% endif %}>Neurology</option>
|
|
<option value="orthopedics" {% if progress_note.service == 'orthopedics' %}selected{% endif %}>Orthopedics</option>
|
|
<option value="pediatrics" {% if progress_note.service == 'pediatrics' %}selected{% endif %}>Pediatrics</option>
|
|
<option value="psychiatry" {% if progress_note.service == 'psychiatry' %}selected{% endif %}>Psychiatry</option>
|
|
<option value="emergency" {% if progress_note.service == 'emergency' %}selected{% endif %}>Emergency Medicine</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Provider</label>
|
|
<input type="text" class="form-control" name="provider"
|
|
value="{{ progress_note.provider|default:user.get_full_name }}" required>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Subjective -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Subjective</h4>
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertTemplate('subjective')">
|
|
<i class="fa fa-file-text me-1"></i>Template
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Chief Complaint</label>
|
|
<textarea class="form-control" name="chief_complaint" rows="2">{{ progress_note.chief_complaint|default:'' }}</textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">History of Present Illness</label>
|
|
<textarea class="form-control" name="history_present_illness" rows="4">{{ progress_note.history_present_illness|default:'' }}</textarea>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Review of Systems</label>
|
|
<textarea class="form-control" name="review_of_systems" rows="4">{{ progress_note.review_of_systems|default:'' }}</textarea>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Patient Concerns/Questions</label>
|
|
<textarea class="form-control" name="patient_concerns" rows="4">{{ progress_note.patient_concerns|default:'' }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Objective -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Objective</h4>
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="importVitals()">
|
|
<i class="fa fa-download me-1"></i>Import Vitals
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertTemplate('objective')">
|
|
<i class="fa fa-file-text me-1"></i>Template
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Vital Signs -->
|
|
<div class="mb-4">
|
|
<h5>Vital Signs</h5>
|
|
<div class="row">
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">Temp (°F)</label>
|
|
<input type="number" class="form-control" name="temperature" step="0.1"
|
|
value="{{ progress_note.temperature|default:'' }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">BP (mmHg)</label>
|
|
<input type="text" class="form-control" name="blood_pressure"
|
|
value="{{ progress_note.blood_pressure|default:'' }}" placeholder="120/80">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">HR (bpm)</label>
|
|
<input type="number" class="form-control" name="heart_rate"
|
|
value="{{ progress_note.heart_rate|default:'' }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">RR (rpm)</label>
|
|
<input type="number" class="form-control" name="respiratory_rate"
|
|
value="{{ progress_note.respiratory_rate|default:'' }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">O2 Sat (%)</label>
|
|
<input type="number" class="form-control" name="oxygen_saturation"
|
|
value="{{ progress_note.oxygen_saturation|default:'' }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="mb-3">
|
|
<label class="form-label">Pain (0-10)</label>
|
|
<input type="number" class="form-control" name="pain_score" min="0" max="10"
|
|
value="{{ progress_note.pain_score|default:'' }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Physical Examination -->
|
|
<div class="mb-3">
|
|
<label class="form-label">Physical Examination</label>
|
|
<textarea class="form-control" name="physical_examination" rows="6">{{ progress_note.physical_examination|default:'' }}</textarea>
|
|
</div>
|
|
|
|
<!-- Laboratory/Diagnostic Results -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Laboratory Results</label>
|
|
<textarea class="form-control" name="laboratory_results" rows="4">{{ progress_note.laboratory_results|default:'' }}</textarea>
|
|
<div class="mt-2">
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="importLabResults()">
|
|
<i class="fa fa-download me-1"></i>Import Recent Labs
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Imaging/Diagnostic Results</label>
|
|
<textarea class="form-control" name="imaging_results" rows="4">{{ progress_note.imaging_results|default:'' }}</textarea>
|
|
<div class="mt-2">
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="importImagingResults()">
|
|
<i class="fa fa-download me-1"></i>Import Recent Imaging
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Assessment -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Assessment</h4>
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addProblem()">
|
|
<i class="fa fa-plus me-1"></i>Add Problem
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertTemplate('assessment')">
|
|
<i class="fa fa-file-text me-1"></i>Template
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Clinical Impression</label>
|
|
<textarea class="form-control" name="clinical_impression" rows="3">{{ progress_note.clinical_impression|default:'' }}</textarea>
|
|
</div>
|
|
|
|
<!-- Problem List -->
|
|
<div class="mb-3">
|
|
<label class="form-label">Problem List</label>
|
|
<div id="problemList">
|
|
{% for problem in problems %}
|
|
<div class="problem-item mb-2">
|
|
<div class="row">
|
|
<div class="col-md-1">
|
|
<input type="text" class="form-control form-control-sm" name="problem_number[]"
|
|
value="{{ forloop.counter }}" readonly>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="text" class="form-control form-control-sm" name="problem_diagnosis[]"
|
|
value="{{ problem.diagnosis }}" placeholder="Diagnosis/Problem">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select form-select-sm" name="problem_status[]">
|
|
<option value="active" {% if problem.status == 'active' %}selected{% endif %}>Active</option>
|
|
<option value="improving" {% if problem.status == 'improving' %}selected{% endif %}>Improving</option>
|
|
<option value="stable" {% if problem.status == 'stable' %}selected{% endif %}>Stable</option>
|
|
<option value="worsening" {% if problem.status == 'worsening' %}selected{% endif %}>Worsening</option>
|
|
<option value="resolved" {% if problem.status == 'resolved' %}selected{% endif %}>Resolved</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="text" class="form-control form-control-sm" name="problem_assessment[]"
|
|
value="{{ problem.assessment }}" placeholder="Assessment/Comments">
|
|
</div>
|
|
<div class="col-md-1">
|
|
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeProblem(this)">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="problem-item mb-2">
|
|
<div class="row">
|
|
<div class="col-md-1">
|
|
<input type="text" class="form-control form-control-sm" name="problem_number[]" value="1" readonly>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="text" class="form-control form-control-sm" name="problem_diagnosis[]" placeholder="Diagnosis/Problem">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<select class="form-select form-select-sm" name="problem_status[]">
|
|
<option value="active">Active</option>
|
|
<option value="improving">Improving</option>
|
|
<option value="stable">Stable</option>
|
|
<option value="worsening">Worsening</option>
|
|
<option value="resolved">Resolved</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<input type="text" class="form-control form-control-sm" name="problem_assessment[]" placeholder="Assessment/Comments">
|
|
</div>
|
|
<div class="col-md-1">
|
|
<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeProblem(this)">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Plan -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Plan</h4>
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="insertTemplate('plan')">
|
|
<i class="fa fa-file-text me-1"></i>Template
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">Treatment Plan</label>
|
|
<textarea class="form-control" name="treatment_plan" rows="5">{{ progress_note.treatment_plan|default:'' }}</textarea>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Medications</label>
|
|
<textarea class="form-control" name="medications" rows="4">{{ progress_note.medications|default:'' }}</textarea>
|
|
<div class="mt-2">
|
|
<button type="button" class="btn btn-outline-info btn-sm" onclick="importCurrentMedications()">
|
|
<i class="fa fa-download me-1"></i>Import Current Meds
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Orders</label>
|
|
<textarea class="form-control" name="orders" rows="4">{{ progress_note.orders|default:'' }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Follow-up</label>
|
|
<textarea class="form-control" name="follow_up" rows="3">{{ progress_note.follow_up|default:'' }}</textarea>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Patient Education</label>
|
|
<textarea class="form-control" name="patient_education" rows="3">{{ progress_note.patient_education|default:'' }}</textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Note Status -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Note Status</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Status</label>
|
|
<select class="form-select" name="status">
|
|
<option value="draft" {% if progress_note.status == 'draft' %}selected{% endif %}>Draft</option>
|
|
<option value="pending_review" {% if progress_note.status == 'pending_review' %}selected{% endif %}>Pending Review</option>
|
|
<option value="final" {% if progress_note.status == 'final' %}selected{% endif %}>Final</option>
|
|
<option value="amended" {% if progress_note.status == 'amended' %}selected{% endif %}>Amended</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Electronic Signature</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="electronically_signed"
|
|
{% if progress_note.electronically_signed %}checked{% endif %}>
|
|
<label class="form-check-label">
|
|
Electronically signed by {{ user.get_full_name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Dictated Date</label>
|
|
<input type="date" class="form-control" name="dictated_date"
|
|
value="{{ progress_note.dictated_date|date:'Y-m-d'|default:today }}">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="mb-3">
|
|
<label class="form-label">Transcribed Date</label>
|
|
<input type="date" class="form-control" name="transcribed_date"
|
|
value="{{ progress_note.transcribed_date|date:'Y-m-d'|default:'' }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="saveDraft()">
|
|
<i class="fa fa-save me-2"></i>Save as Draft
|
|
</button>
|
|
<button type="button" class="btn btn-outline-info" onclick="previewNote()">
|
|
<i class="fa fa-eye me-2"></i>Preview
|
|
</button>
|
|
<button type="button" class="btn btn-outline-warning" onclick="spellCheck()">
|
|
<i class="fa fa-spell-check me-2"></i>Spell Check
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<button type="button" class="btn btn-warning" onclick="submitForReview()">
|
|
<i class="fa fa-check me-2"></i>Submit for Review
|
|
</button>
|
|
<button type="button" class="btn btn-success" onclick="finalizeNote()">
|
|
<i class="fa fa-check-circle me-2"></i>Finalize Note
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Selection Modal -->
|
|
<div class="modal fade" id="patientSelectionModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Select Patient</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<input type="text" class="form-control" id="patientSearchInput" placeholder="Search by name, ID, or phone number...">
|
|
</div>
|
|
<div id="patientSearchResults">
|
|
<!-- Search results will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Template Selection Modal -->
|
|
<div class="modal fade" id="templateModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Select Template</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="templateList">
|
|
<!-- Templates will be loaded here -->
|
|
</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">Progress Note Preview</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="previewContent">
|
|
<!-- Preview content will be loaded here -->
|
|
</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" onclick="printPreview()">Print</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
$(document).ready(function() {
|
|
setupEventHandlers();
|
|
setupAutoSave();
|
|
updateProblemNumbers();
|
|
});
|
|
|
|
function setupEventHandlers() {
|
|
// Patient search
|
|
$('#patientSearchInput').on('input', function() {
|
|
var query = $(this).val();
|
|
if (query.length >= 3) {
|
|
searchPatients(query);
|
|
}
|
|
});
|
|
|
|
// Form validation
|
|
$('#progressNoteForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
saveProgressNote();
|
|
});
|
|
}
|
|
|
|
function setupAutoSave() {
|
|
// Auto-save every 3 minutes
|
|
setInterval(function() {
|
|
if ($('#progressNoteForm').length) {
|
|
saveDraft(true); // Silent save
|
|
}
|
|
}, 180000); // 3 minutes
|
|
}
|
|
|
|
function selectPatient() {
|
|
$('#patientSelectionModal').modal('show');
|
|
}
|
|
|
|
function searchPatients(query) {
|
|
$.get('{% url "emr:patient_search_api" %}', {q: query}, function(data) {
|
|
var html = '';
|
|
|
|
if (data.patients.length === 0) {
|
|
html = '<div class="alert alert-info">No patients found matching "' + query + '"</div>';
|
|
} else {
|
|
html = '<div class="list-group">';
|
|
data.patients.forEach(function(patient) {
|
|
html += '<button type="button" class="list-group-item list-group-item-action" onclick="selectPatientForNote(\'' + patient.patient_id + '\')">' +
|
|
'<div class="d-flex w-100 justify-content-between">' +
|
|
'<h6 class="mb-1">' + patient.first_name + ' ' + patient.last_name + '</h6>' +
|
|
'<small>' + patient.patient_id + '</small>' +
|
|
'</div>' +
|
|
'<p class="mb-1">DOB: ' + patient.date_of_birth + ' | Gender: ' + patient.gender + '</p>' +
|
|
'<small>Phone: ' + (patient.phone_primary || 'Not provided') + '</small>' +
|
|
'</button>';
|
|
});
|
|
html += '</div>';
|
|
}
|
|
|
|
$('#patientSearchResults').html(html);
|
|
});
|
|
}
|
|
|
|
function selectPatientForNote(patientId) {
|
|
window.location.href = '{% url "emr:progress_note" %}?patient_id=' + patientId;
|
|
}
|
|
|
|
function createProgressNote() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
if (!patientId) {
|
|
toastr.error('Please select a patient first');
|
|
return;
|
|
}
|
|
|
|
$.post('{% url "emr:create_progress_note" %}', {
|
|
patient_id: patientId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Progress note created');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to create progress note: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function addProblem() {
|
|
var problemCount = $('#problemList .problem-item').length + 1;
|
|
var html = '<div class="problem-item mb-2">' +
|
|
'<div class="row">' +
|
|
'<div class="col-md-1">' +
|
|
'<input type="text" class="form-control form-control-sm" name="problem_number[]" value="' + problemCount + '" readonly>' +
|
|
'</div>' +
|
|
'<div class="col-md-4">' +
|
|
'<input type="text" class="form-control form-control-sm" name="problem_diagnosis[]" placeholder="Diagnosis/Problem">' +
|
|
'</div>' +
|
|
'<div class="col-md-2">' +
|
|
'<select class="form-select form-select-sm" name="problem_status[]">' +
|
|
'<option value="active">Active</option>' +
|
|
'<option value="improving">Improving</option>' +
|
|
'<option value="stable">Stable</option>' +
|
|
'<option value="worsening">Worsening</option>' +
|
|
'<option value="resolved">Resolved</option>' +
|
|
'</select>' +
|
|
'</div>' +
|
|
'<div class="col-md-4">' +
|
|
'<input type="text" class="form-control form-control-sm" name="problem_assessment[]" placeholder="Assessment/Comments">' +
|
|
'</div>' +
|
|
'<div class="col-md-1">' +
|
|
'<button type="button" class="btn btn-outline-danger btn-sm" onclick="removeProblem(this)">' +
|
|
'<i class="fa fa-times"></i>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
$('#problemList').append(html);
|
|
}
|
|
|
|
function removeProblem(button) {
|
|
$(button).closest('.problem-item').remove();
|
|
updateProblemNumbers();
|
|
}
|
|
|
|
function updateProblemNumbers() {
|
|
$('#problemList .problem-item').each(function(index) {
|
|
$(this).find('input[name="problem_number[]"]').val(index + 1);
|
|
});
|
|
}
|
|
|
|
function insertTemplate(section) {
|
|
var currentSection = section;
|
|
|
|
$.get('{% url "emr:get_note_templates" %}', {section: section}, function(data) {
|
|
if (data.success) {
|
|
var html = '<div class="list-group">';
|
|
data.templates.forEach(function(template) {
|
|
html += '<button type="button" class="list-group-item list-group-item-action" onclick="applyTemplate(\'' + template.id + '\', \'' + currentSection + '\')">' +
|
|
'<div class="d-flex w-100 justify-content-between">' +
|
|
'<h6 class="mb-1">' + template.name + '</h6>' +
|
|
'<small>' + template.specialty + '</small>' +
|
|
'</div>' +
|
|
'<p class="mb-1">' + template.description + '</p>' +
|
|
'</button>';
|
|
});
|
|
html += '</div>';
|
|
|
|
$('#templateList').html(html);
|
|
$('#templateModal').modal('show');
|
|
} else {
|
|
toastr.error('Failed to load templates: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function applyTemplate(templateId, section) {
|
|
$.get('{% url "emr:get_template_content" %}', {template_id: templateId}, function(data) {
|
|
if (data.success) {
|
|
// Apply template content to appropriate fields based on section
|
|
if (section === 'subjective') {
|
|
if (data.template.chief_complaint) {
|
|
$('textarea[name="chief_complaint"]').val(data.template.chief_complaint);
|
|
}
|
|
if (data.template.history_present_illness) {
|
|
$('textarea[name="history_present_illness"]').val(data.template.history_present_illness);
|
|
}
|
|
if (data.template.review_of_systems) {
|
|
$('textarea[name="review_of_systems"]').val(data.template.review_of_systems);
|
|
}
|
|
} else if (section === 'objective') {
|
|
if (data.template.physical_examination) {
|
|
$('textarea[name="physical_examination"]').val(data.template.physical_examination);
|
|
}
|
|
} else if (section === 'assessment') {
|
|
if (data.template.clinical_impression) {
|
|
$('textarea[name="clinical_impression"]').val(data.template.clinical_impression);
|
|
}
|
|
} else if (section === 'plan') {
|
|
if (data.template.treatment_plan) {
|
|
$('textarea[name="treatment_plan"]').val(data.template.treatment_plan);
|
|
}
|
|
}
|
|
|
|
$('#templateModal').modal('hide');
|
|
toastr.success('Template applied');
|
|
} else {
|
|
toastr.error('Failed to apply template: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function importVitals() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
|
|
$.get('{% url "emr:get_latest_vitals" %}', {patient_id: patientId}, function(data) {
|
|
if (data.success && data.vitals) {
|
|
var vitals = data.vitals;
|
|
if (vitals.temperature) $('input[name="temperature"]').val(vitals.temperature);
|
|
if (vitals.blood_pressure) $('input[name="blood_pressure"]').val(vitals.blood_pressure);
|
|
if (vitals.heart_rate) $('input[name="heart_rate"]').val(vitals.heart_rate);
|
|
if (vitals.respiratory_rate) $('input[name="respiratory_rate"]').val(vitals.respiratory_rate);
|
|
if (vitals.oxygen_saturation) $('input[name="oxygen_saturation"]').val(vitals.oxygen_saturation);
|
|
if (vitals.pain_score) $('input[name="pain_score"]').val(vitals.pain_score);
|
|
|
|
toastr.success('Latest vitals imported');
|
|
} else {
|
|
toastr.error('No recent vitals found');
|
|
}
|
|
});
|
|
}
|
|
|
|
function importLabResults() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
|
|
$.get('{% url "emr:get_recent_lab_results" %}', {patient_id: patientId}, function(data) {
|
|
if (data.success) {
|
|
$('textarea[name="laboratory_results"]').val(data.lab_summary);
|
|
toastr.success('Recent lab results imported');
|
|
} else {
|
|
toastr.error('No recent lab results found');
|
|
}
|
|
});
|
|
}
|
|
|
|
function importImagingResults() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
|
|
$.get('{% url "emr:get_recent_imaging_results" %}', {patient_id: patientId}, function(data) {
|
|
if (data.success) {
|
|
$('textarea[name="imaging_results"]').val(data.imaging_summary);
|
|
toastr.success('Recent imaging results imported');
|
|
} else {
|
|
toastr.error('No recent imaging results found');
|
|
}
|
|
});
|
|
}
|
|
|
|
function importCurrentMedications() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
|
|
$.get('{% url "emr:get_current_medications" %}', {patient_id: patientId}, function(data) {
|
|
if (data.success) {
|
|
$('textarea[name="medications"]').val(data.medication_summary);
|
|
toastr.success('Current medications imported');
|
|
} else {
|
|
toastr.error('No current medications found');
|
|
}
|
|
});
|
|
}
|
|
|
|
function saveDraft(silent = false) {
|
|
var formData = $('#progressNoteForm').serialize();
|
|
formData += '&status=draft';
|
|
|
|
$.post('{% url "emr:save_progress_note" %}', formData, function(data) {
|
|
if (data.success) {
|
|
if (!silent) {
|
|
toastr.success('Draft saved');
|
|
}
|
|
} else {
|
|
if (!silent) {
|
|
toastr.error('Failed to save draft: ' + data.error);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function saveProgressNote() {
|
|
var formData = $('#progressNoteForm').serialize();
|
|
|
|
$.post('{% url "emr:save_progress_note" %}', formData, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Progress note saved');
|
|
} else {
|
|
toastr.error('Failed to save progress note: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function submitForReview() {
|
|
var formData = $('#progressNoteForm').serialize();
|
|
formData += '&status=pending_review';
|
|
|
|
$.post('{% url "emr:save_progress_note" %}', formData, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Progress note submitted for review');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to submit for review: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function finalizeNote() {
|
|
if (confirm('Are you sure you want to finalize this progress note? This action cannot be undone.')) {
|
|
var formData = $('#progressNoteForm').serialize();
|
|
formData += '&status=final';
|
|
|
|
$.post('{% url "emr:save_progress_note" %}', formData, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Progress note finalized');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to finalize note: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function previewNote() {
|
|
var formData = $('#progressNoteForm').serialize();
|
|
|
|
$.post('{% url "emr:preview_progress_note" %}', formData, function(data) {
|
|
if (data.success) {
|
|
$('#previewContent').html(data.html);
|
|
$('#previewModal').modal('show');
|
|
} else {
|
|
toastr.error('Failed to generate preview: ' + data.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function printNote() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
window.open('{% url "emr:print_progress_note" %}?patient_id=' + patientId, '_blank');
|
|
}
|
|
|
|
function printPreview() {
|
|
var printWindow = window.open('', '_blank');
|
|
printWindow.document.write('<html><head><title>Progress Note</title>');
|
|
printWindow.document.write('<style>body { font-family: Arial, sans-serif; margin: 20px; } .header { text-align: center; margin-bottom: 20px; } .section { margin-bottom: 15px; } .label { font-weight: bold; }</style>');
|
|
printWindow.document.write('</head><body>');
|
|
printWindow.document.write($('#previewContent').html());
|
|
printWindow.document.write('</body></html>');
|
|
printWindow.document.close();
|
|
printWindow.print();
|
|
}
|
|
|
|
function addendum() {
|
|
var noteId = '{{ progress_note.id|default:"" }}';
|
|
if (!noteId) {
|
|
toastr.error('Please save the note first before adding an addendum');
|
|
return;
|
|
}
|
|
|
|
window.location.href = '{% url "emr:create_addendum" %}?note_id=' + noteId;
|
|
}
|
|
|
|
function spellCheck() {
|
|
// Basic spell check implementation
|
|
var textAreas = $('textarea');
|
|
var misspelledWords = [];
|
|
|
|
textAreas.each(function() {
|
|
var text = $(this).val();
|
|
// Simple spell check logic (in real implementation, use a proper spell check library)
|
|
var words = text.split(/\s+/);
|
|
// This is a placeholder - implement actual spell checking
|
|
});
|
|
|
|
toastr.info('Spell check completed');
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.card-tools {
|
|
margin-left: auto;
|
|
}
|
|
|
|
.problem-item {
|
|
border-bottom: 1px solid #dee2e6;
|
|
padding-bottom: 10px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.problem-item:last-child {
|
|
border-bottom: none;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.form-control-sm, .form-select-sm {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.list-group-item-action:hover {
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.card-header h4 {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.form-check-input:checked {
|
|
background-color: #0d6efd;
|
|
border-color: #0d6efd;
|
|
}
|
|
|
|
.btn-group .btn {
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.btn-group .btn:last-child {
|
|
margin-right: 0;
|
|
}
|
|
|
|
#previewContent {
|
|
max-height: 70vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.preview-section {
|
|
margin-bottom: 20px;
|
|
padding: 15px;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 0.375rem;
|
|
}
|
|
|
|
.preview-section h5 {
|
|
color: #0d6efd;
|
|
border-bottom: 1px solid #dee2e6;
|
|
padding-bottom: 5px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.vital-signs-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
|
|
gap: 10px;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.vital-sign-item {
|
|
text-align: center;
|
|
padding: 10px;
|
|
background-color: #f8f9fa;
|
|
border-radius: 0.375rem;
|
|
}
|
|
|
|
.vital-sign-value {
|
|
font-size: 1.2em;
|
|
font-weight: bold;
|
|
color: #0d6efd;
|
|
}
|
|
|
|
.vital-sign-label {
|
|
font-size: 0.875em;
|
|
color: #6c757d;
|
|
}
|
|
|
|
@media print {
|
|
.btn, .card-header, .breadcrumb {
|
|
display: none !important;
|
|
}
|
|
|
|
.card {
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
.card-body {
|
|
padding: 0 !important;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|