2025-08-12 13:33:25 +03:00

472 lines
20 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Electronic Medical Records - {{ 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">
<i class="fas fa-file-medical me-2"></i>Electronic Medical Records
</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb mb-0">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
<li class="breadcrumb-item active">EMR</li>
</ol>
</nav>
</div>
<div class="btn-group">
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-download me-2"></i>Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="exportEMRData('csv')">
<i class="fas fa-file-csv me-2"></i>Export as CSV
</a></li>
<li><a class="dropdown-item" href="#" onclick="exportEMRData('excel')">
<i class="fas fa-file-excel me-2"></i>Export as Excel
</a></li>
<li><a class="dropdown-item" href="#" onclick="exportEMRData('pdf')">
<i class="fas fa-file-pdf me-2"></i>Export as PDF
</a></li>
</ul>
<button type="button" class="btn btn-primary" onclick="createNewEncounter()">
<i class="fas fa-plus me-2"></i>New Encounter
</button>
</div>
</div>
<!-- Key Metrics -->
<div class="row mb-4" id="emr-stats" hx-get="{% url 'emr:emr_stats' %}" hx-trigger="load, every 30s">
{% include 'emr/partials/emr_stats.html' %}
</div>
<!-- Quick Actions -->
<div class="row mb-4">
<div class="col-lg-3 col-md-6 mb-3">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="bg-primary bg-gradient rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="fas fa-user-md fa-lg text-white"></i>
</div>
<h6 class="card-title">Encounters</h6>
<p class="card-text text-muted small">Manage patient encounters and visits</p>
<a href="{% url 'emr:encounter_list' %}" class="btn btn-primary btn-sm">
<i class="fas fa-list me-1"></i>View Encounters
</a>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="bg-success bg-gradient rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="fas fa-heartbeat fa-lg text-white"></i>
</div>
<h6 class="card-title">Vital Signs</h6>
<p class="card-text text-muted small">Record and monitor vital signs</p>
<a href="{% url 'emr:vital_signs_list' %}" class="btn btn-success btn-sm">
<i class="fas fa-chart-line me-1"></i>View Vitals
</a>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="bg-warning bg-gradient rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="fas fa-list-alt fa-lg text-white"></i>
</div>
<h6 class="card-title">Problem List</h6>
<p class="card-text text-muted small">Manage patient problems and diagnoses</p>
<a href="{% url 'emr:problem_list' %}" class="btn btn-warning btn-sm">
<i class="fas fa-clipboard-list me-1"></i>View Problems
</a>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6 mb-3">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body text-center">
<div class="bg-info bg-gradient rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="fas fa-notes-medical fa-lg text-white"></i>
</div>
<h6 class="card-title">Clinical Notes</h6>
<p class="card-text text-muted small">Create and manage clinical documentation</p>
<a href="{% url 'emr:clinical_note_list' %}" class="btn btn-info btn-sm">
<i class="fas fa-file-alt me-1"></i>View Notes
</a>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="row">
<div class="col-lg-8">
<!-- Recent Encounters -->
<div class="card mb-4">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-clock me-2"></i>Recent Encounters
</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="refreshEncounters()">
<i class="fas fa-sync-alt me-1"></i>Refresh
</button>
<a href="{% url 'emr:encounter_list' %}" class="btn btn-outline-primary">
<i class="fas fa-expand me-1"></i>View All
</a>
</div>
</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Patient</th>
<th>Type</th>
<th>Provider</th>
<th>Date/Time</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for encounter in encounters %}
<tr>
<td>
<div class="d-flex align-items-center">
<div class="avatar-sm bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center me-2">
<span class="text-white small fw-bold">
{{ encounter.patient.first_name.0 }}{{ encounter.patient.last_name.0 }}
</span>
</div>
<div>
<div class="fw-semibold">{{ encounter.patient.get_full_name }}</div>
<small class="text-muted">MRN: {{ encounter.patient.mrn }}</small>
</div>
</div>
</td>
<td>
<span class="badge bg-primary">{{ encounter.get_encounter_type_display }}</span>
</td>
<td>{{ encounter.provider.get_full_name }}</td>
<td>
<div>{{ encounter.start_datetime|date:"M d, Y" }}</div>
<small class="text-muted">{{ encounter.start_datetime|time:"H:i" }}</small>
</td>
<td>
<span class="badge bg-{% if encounter.status == 'FINISHED' %}success{% elif encounter.status == 'CANCELLED' %}danger{% elif encounter.status == 'IN_PROGRESS' %}warning{% else %}secondary{% endif %}">
{{ encounter.get_status_display }}
</span>
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="{% url 'emr:encounter_detail' encounter.pk %}" class="btn btn-outline-primary btn-sm" title="View Details">
<i class="fas fa-eye"></i>
</a>
<button type="button" class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown">
<span class="visually-hidden">Toggle Dropdown</span>
<i class="fas fa-ellipsis-h"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">
<i class="fas fa-edit me-2"></i>Edit
</a></li>
<li><a class="dropdown-item" href="{% url 'emr:add_vital_signs' encounter.id %}">
<i class="fas fa-heartbeat me-2"></i>Add Vitals
</a></li>
<li><a class="dropdown-item" href="#">
<i class="fas fa-notes-medical me-2"></i>Add Note
</a></li>
</ul>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center py-4 text-muted">
<i class="fas fa-inbox fa-2x mb-2"></i>
<div>No recent encounters found</div>
<small>Create a new encounter to get started</small>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<!-- Pending Tasks -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-tasks me-2"></i>Pending Tasks
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<div class="d-flex align-items-center p-3 bg-warning bg-opacity-10 rounded mb-3">
<div class="bg-warning rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fas fa-file-signature text-white"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">{{ unsigned_notes }}</h6>
<small class="text-muted">Unsigned Notes</small>
</div>
<a href="{% url 'emr:clinical_note_list' %}?status=unsigned" class="btn btn-warning btn-sm">
<i class="fas fa-arrow-right"></i>
</a>
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center p-3 bg-danger bg-opacity-10 rounded mb-3">
<div class="bg-danger rounded-circle d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i class="fas fa-clipboard-check text-white"></i>
</div>
<div class="flex-grow-1">
<h6 class="mb-0">{{ pending_documentation }}</h6>
<small class="text-muted">Incomplete Documentation</small>
</div>
<a href="{% url 'emr:encounter_list' %}?documentation_complete=false" class="btn btn-danger btn-sm">
<i class="fas fa-arrow-right"></i>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Quick Search -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-search me-2"></i>Quick Search
</h5>
</div>
<div class="card-body">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Search patients..."
hx-get="{% url 'emr:encounter_search' %}"
hx-trigger="keyup changed delay:300ms"
hx-target="#search-results">
<button class="btn btn-outline-secondary" type="button">
<i class="fas fa-search"></i>
</button>
</div>
<div id="search-results"></div>
</div>
</div>
<!-- Today's Schedule -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-calendar-day me-2"></i>Today's Schedule
</h5>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted">Total Encounters</span>
<span class="badge bg-primary">{{ todays_encounters }}</span>
</div>
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted">Active Now</span>
<span class="badge bg-success">{{ active_encounters }}</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted">Critical Vitals</span>
<span class="badge bg-danger">{{ critical_vitals }}</span>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-history me-2"></i>Recent Activity
</h5>
</div>
<div class="card-body">
<div class="timeline">
<div class="timeline-item">
<div class="timeline-marker bg-primary"></div>
<div class="timeline-content">
<h6 class="timeline-title">New encounter created</h6>
<p class="timeline-text">Patient: John Doe</p>
<small class="text-muted">2 minutes ago</small>
</div>
</div>
<div class="timeline-item">
<div class="timeline-marker bg-success"></div>
<div class="timeline-content">
<h6 class="timeline-title">Vital signs recorded</h6>
<p class="timeline-text">Patient: Jane Smith</p>
<small class="text-muted">15 minutes ago</small>
</div>
</div>
<div class="timeline-item">
<div class="timeline-marker bg-warning"></div>
<div class="timeline-content">
<h6 class="timeline-title">Clinical note signed</h6>
<p class="timeline-text">Dr. Johnson</p>
<small class="text-muted">1 hour ago</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// EMR Dashboard functionality
document.addEventListener('DOMContentLoaded', function() {
// Auto-refresh stats every 30 seconds
setInterval(function() {
const statsContainer = document.getElementById('emr-stats');
if (statsContainer) {
htmx.trigger(statsContainer, 'refresh');
}
}, 30000);
});
function refreshEncounters() {
location.reload();
}
function createNewEncounter() {
// Implementation would depend on your encounter creation workflow
window.location.href = "{% url 'emr:encounter_list' %}";
}
function exportEMRData(format) {
const params = new URLSearchParams();
params.append('format', format);
window.open(`{% url 'emr:dashboard' %}export/?${params}`, '_blank');
}
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
switch (e.key) {
case 'n':
e.preventDefault();
createNewEncounter();
break;
case 'r':
e.preventDefault();
refreshEncounters();
break;
case '/':
e.preventDefault();
document.querySelector('input[placeholder*="Search"]').focus();
break;
}
});
</script>
<style>
.avatar-sm {
width: 32px;
height: 32px;
font-size: 0.75rem;
}
.timeline {
position: relative;
padding-left: 1.5rem;
}
.timeline-item {
position: relative;
padding-bottom: 1.5rem;
}
.timeline-item:not(:last-child)::before {
content: '';
position: absolute;
left: -1.5rem;
top: 1rem;
width: 2px;
height: calc(100% - 0.5rem);
background-color: #dee2e6;
}
.timeline-marker {
position: absolute;
left: -1.75rem;
top: 0.25rem;
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
}
.timeline-content {
margin-left: 0.5rem;
}
.timeline-title {
font-size: 0.875rem;
font-weight: 600;
margin-bottom: 0.25rem;
}
.timeline-text {
font-size: 0.8rem;
color: #6c757d;
margin-bottom: 0.25rem;
}
.bg-gradient {
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
}
.card {
transition: all 0.2s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
}
.table-hover tbody tr:hover {
background-color: rgba(0, 0, 0, 0.02);
}
@media (max-width: 768px) {
.btn-group-sm .btn {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}
.timeline {
padding-left: 1rem;
}
.timeline-marker {
left: -1.25rem;
}
}
</style>
{% endblock %}