856 lines
35 KiB
HTML
856 lines
35 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Clinical Decision Support{% 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">Clinical Decision Support</li>
|
|
</ul>
|
|
|
|
<div class="row align-items-center mb-3">
|
|
<div class="col">
|
|
<h1 class="page-header">Clinical Decision Support</h1>
|
|
<p class="text-muted">AI-powered clinical recommendations and alerts</p>
|
|
</div>
|
|
<div class="col-auto">
|
|
<button class="btn btn-primary" onclick="refreshRecommendations()">
|
|
<i class="fa fa-refresh me-2"></i>Refresh Recommendations
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Selection -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Patient Selection</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="input-group">
|
|
<input type="text" id="patientSearch" class="form-control" placeholder="Search by name, ID, or phone number..." value="{{ patient.first_name }} {{ patient.last_name }}">
|
|
<button class="btn btn-outline-secondary" type="button" onclick="searchPatients()">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
<div id="patientSearchResults" class="mt-2" style="display: none;">
|
|
<!-- Search results will appear here -->
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
{% if patient %}
|
|
<div class="text-end">
|
|
<strong>{{ patient.first_name }} {{ patient.last_name }}</strong><br>
|
|
<small class="text-muted">ID: {{ patient.patient_id }}</small>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if patient %}
|
|
<!-- Patient Summary -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Patient Summary</h4>
|
|
<div class="card-tools">
|
|
<a href="{% url 'patients:patient_detail' patient.patient_id %}" class="btn btn-outline-primary btn-sm">
|
|
<i class="fa fa-eye me-1"></i>View Full Profile
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<p><strong>Age:</strong> {{ patient.age }}</p>
|
|
<p><strong>Gender:</strong> {{ patient.get_gender_display }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>Allergies:</strong> {{ patient.allergies|default:"None documented" }}</p>
|
|
<p><strong>Blood Type:</strong> {{ patient.blood_type|default:"Unknown" }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>Primary Care Provider:</strong> {{ patient.primary_care_provider|default:"Not assigned" }}</p>
|
|
<p><strong>Insurance:</strong> {{ patient.primary_insurance|default:"Not provided" }}</p>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<p><strong>Last Visit:</strong> {{ patient.last_encounter_date|date:"M d, Y"|default:"No visits" }}</p>
|
|
<p><strong>Risk Score:</strong>
|
|
<span class="badge bg-{{ patient.risk_level|default:'secondary' }}">
|
|
{{ patient.risk_score|default:"Not calculated" }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Critical Alerts -->
|
|
{% if critical_alerts %}
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card border-danger">
|
|
<div class="card-header bg-danger text-white">
|
|
<h4 class="card-title mb-0">
|
|
<i class="fa fa-exclamation-triangle me-2"></i>Critical Alerts
|
|
</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% for alert in critical_alerts %}
|
|
<div class="alert alert-danger d-flex align-items-center" role="alert">
|
|
<i class="fa fa-exclamation-circle me-3"></i>
|
|
<div class="flex-grow-1">
|
|
<strong>{{ alert.title }}</strong><br>
|
|
{{ alert.description }}
|
|
{% if alert.recommendation %}
|
|
<br><small><strong>Recommendation:</strong> {{ alert.recommendation }}</small>
|
|
{% endif %}
|
|
</div>
|
|
<div class="ms-3">
|
|
<button class="btn btn-outline-danger btn-sm" onclick="acknowledgeAlert('{{ alert.id }}')">
|
|
<i class="fa fa-check me-1"></i>Acknowledge
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Drug Interactions -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Drug Interactions</h4>
|
|
<div class="card-tools">
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="checkDrugInteractions()">
|
|
<i class="fa fa-refresh me-1"></i>Check
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="drugInteractions">
|
|
{% if drug_interactions %}
|
|
{% for interaction in drug_interactions %}
|
|
<div class="alert alert-{{ interaction.severity|lower }} mb-2">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div>
|
|
<strong>{{ interaction.drug1 }} + {{ interaction.drug2 }}</strong>
|
|
<br><small>{{ interaction.description }}</small>
|
|
</div>
|
|
<span class="badge bg-{{ interaction.severity|lower }}">
|
|
{{ interaction.severity }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No drug interactions detected</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Allergy Alerts -->
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Allergy Alerts</h4>
|
|
<div class="card-tools">
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="checkAllergies()">
|
|
<i class="fa fa-refresh me-1"></i>Check
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="allergyAlerts">
|
|
{% if allergy_alerts %}
|
|
{% for alert in allergy_alerts %}
|
|
<div class="alert alert-warning mb-2">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div>
|
|
<strong>{{ alert.allergen }}</strong>
|
|
<br><small>{{ alert.reaction_type }}</small>
|
|
</div>
|
|
<span class="badge bg-warning">
|
|
{{ alert.severity }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No allergy conflicts detected</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Clinical Recommendations -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Clinical Recommendations</h4>
|
|
<div class="card-tools">
|
|
<div class="btn-group">
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="filterRecommendations('all')">All</button>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="filterRecommendations('preventive')">Preventive</button>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="filterRecommendations('diagnostic')">Diagnostic</button>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="filterRecommendations('treatment')">Treatment</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="clinicalRecommendations">
|
|
{% for recommendation in recommendations %}
|
|
<div class="recommendation-item mb-3 p-3 border rounded" data-category="{{ recommendation.category }}">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1">{{ recommendation.title }}</h6>
|
|
<p class="mb-2">{{ recommendation.description }}</p>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<small class="text-muted">
|
|
<strong>Evidence Level:</strong> {{ recommendation.evidence_level }}<br>
|
|
<strong>Source:</strong> {{ recommendation.source }}
|
|
</small>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<small class="text-muted">
|
|
<strong>Priority:</strong> {{ recommendation.priority }}<br>
|
|
<strong>Category:</strong> {{ recommendation.get_category_display }}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="ms-3">
|
|
<span class="badge bg-{{ recommendation.priority|lower }} mb-2">
|
|
{{ recommendation.priority }}
|
|
</span>
|
|
<br>
|
|
<div class="btn-group-vertical btn-group-sm">
|
|
<button class="btn btn-outline-success" onclick="acceptRecommendation('{{ recommendation.id }}')">
|
|
<i class="fa fa-check"></i> Accept
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="deferRecommendation('{{ recommendation.id }}')">
|
|
<i class="fa fa-clock-o"></i> Defer
|
|
</button>
|
|
<button class="btn btn-outline-danger" onclick="dismissRecommendation('{{ recommendation.id }}')">
|
|
<i class="fa fa-times"></i> Dismiss
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<p class="text-muted">No clinical recommendations available</p>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Diagnostic Suggestions -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Diagnostic Suggestions</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if diagnostic_suggestions %}
|
|
{% for suggestion in diagnostic_suggestions %}
|
|
<div class="mb-3 p-2 border-start border-primary border-3">
|
|
<h6 class="mb-1">{{ suggestion.test_name }}</h6>
|
|
<p class="mb-1 small">{{ suggestion.indication }}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<small class="text-muted">
|
|
Confidence: {{ suggestion.confidence }}%
|
|
</small>
|
|
<button class="btn btn-outline-primary btn-sm" onclick="orderTest('{{ suggestion.test_code }}')">
|
|
<i class="fa fa-plus me-1"></i>Order
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No diagnostic suggestions available</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Treatment Protocols -->
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Treatment Protocols</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if treatment_protocols %}
|
|
{% for protocol in treatment_protocols %}
|
|
<div class="mb-3 p-2 border-start border-success border-3">
|
|
<h6 class="mb-1">{{ protocol.name }}</h6>
|
|
<p class="mb-1 small">{{ protocol.description }}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<small class="text-muted">
|
|
Success Rate: {{ protocol.success_rate }}%
|
|
</small>
|
|
<button class="btn btn-outline-success btn-sm" onclick="applyProtocol('{{ protocol.id }}')">
|
|
<i class="fa fa-check me-1"></i>Apply
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">No treatment protocols suggested</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Risk Assessment -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Risk Assessment</h4>
|
|
<div class="card-tools">
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="calculateRiskScores()">
|
|
<i class="fa fa-calculator me-1"></i>Recalculate
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
{% for risk in risk_assessments %}
|
|
<div class="col-md-4 mb-3">
|
|
<div class="card border-{{ risk.level|lower }}">
|
|
<div class="card-body text-center">
|
|
<h5 class="card-title">{{ risk.name }}</h5>
|
|
<div class="display-6 text-{{ risk.level|lower }}">{{ risk.score }}%</div>
|
|
<p class="card-text">{{ risk.description }}</p>
|
|
<span class="badge bg-{{ risk.level|lower }}">{{ risk.level }} Risk</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="col-12">
|
|
<p class="text-muted">No risk assessments available</p>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Clinical Guidelines -->
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Relevant Clinical Guidelines</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if clinical_guidelines %}
|
|
<div class="row">
|
|
{% for guideline in clinical_guidelines %}
|
|
<div class="col-md-6 mb-3">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{{ guideline.title }}</h6>
|
|
<p class="card-text small">{{ guideline.summary }}</p>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<small class="text-muted">{{ guideline.organization }}</small>
|
|
<a href="{{ guideline.url }}" target="_blank" class="btn btn-outline-primary btn-sm">
|
|
<i class="fa fa-external-link me-1"></i>View
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<p class="text-muted">No relevant clinical guidelines found</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<!-- No Patient Selected -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body text-center py-5">
|
|
<i class="fa fa-user-md fa-3x text-muted mb-3"></i>
|
|
<h4>Select a Patient</h4>
|
|
<p class="text-muted">Please select a patient to view clinical decision support recommendations</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Patient Search Modal -->
|
|
<div class="modal fade" id="patientSearchModal" 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 id="patientSearchModalContent">
|
|
<!-- Search results will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recommendation Details Modal -->
|
|
<div class="modal fade" id="recommendationModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Recommendation Details</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="recommendationDetails">
|
|
<!-- Recommendation details 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="implementRecommendation()">Implement</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script>
|
|
$(document).ready(function() {
|
|
setupEventHandlers();
|
|
{% if patient %}
|
|
loadClinicalData();
|
|
{% endif %}
|
|
});
|
|
|
|
function setupEventHandlers() {
|
|
// Patient search
|
|
$('#patientSearch').on('input', function() {
|
|
var query = $(this).val();
|
|
if (query.length >= 3) {
|
|
searchPatients(query);
|
|
} else {
|
|
$('#patientSearchResults').hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
function searchPatients(query = null) {
|
|
if (!query) {
|
|
query = $('#patientSearch').val();
|
|
}
|
|
|
|
if (query.length < 3) {
|
|
$('#patientSearchResults').hide();
|
|
return;
|
|
}
|
|
|
|
$.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="selectPatient(\'' + 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).show();
|
|
});
|
|
}
|
|
|
|
function selectPatient(patientId) {
|
|
window.location.href = '{% url "emr:clinical_decision_support" %}?patient_id=' + patientId;
|
|
}
|
|
|
|
function loadClinicalData() {
|
|
// Load clinical decision support data
|
|
refreshRecommendations();
|
|
checkDrugInteractions();
|
|
checkAllergies();
|
|
calculateRiskScores();
|
|
}
|
|
|
|
function refreshRecommendations() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
if (!patientId) return;
|
|
|
|
$.get('{% url "emr:get_clinical_recommendations" %}', {patient_id: patientId}, function(data) {
|
|
updateRecommendationsDisplay(data.recommendations);
|
|
toastr.success('Recommendations updated');
|
|
}).fail(function() {
|
|
toastr.error('Failed to load recommendations');
|
|
});
|
|
}
|
|
|
|
function checkDrugInteractions() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
if (!patientId) return;
|
|
|
|
$.get('{% url "emr:check_drug_interactions" %}', {patient_id: patientId}, function(data) {
|
|
updateDrugInteractionsDisplay(data.interactions);
|
|
}).fail(function() {
|
|
toastr.error('Failed to check drug interactions');
|
|
});
|
|
}
|
|
|
|
function checkAllergies() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
if (!patientId) return;
|
|
|
|
$.get('{% url "emr:check_allergies" %}', {patient_id: patientId}, function(data) {
|
|
updateAllergyAlertsDisplay(data.alerts);
|
|
}).fail(function() {
|
|
toastr.error('Failed to check allergies');
|
|
});
|
|
}
|
|
|
|
function calculateRiskScores() {
|
|
var patientId = '{{ patient.patient_id|default:"" }}';
|
|
if (!patientId) return;
|
|
|
|
$.get('{% url "emr:calculate_risk_scores" %}', {patient_id: patientId}, function(data) {
|
|
updateRiskAssessmentDisplay(data.risk_scores);
|
|
toastr.success('Risk scores updated');
|
|
}).fail(function() {
|
|
toastr.error('Failed to calculate risk scores');
|
|
});
|
|
}
|
|
|
|
function filterRecommendations(category) {
|
|
$('.recommendation-item').hide();
|
|
if (category === 'all') {
|
|
$('.recommendation-item').show();
|
|
} else {
|
|
$('.recommendation-item[data-category="' + category + '"]').show();
|
|
}
|
|
|
|
// Update button states
|
|
$('.btn-group .btn').removeClass('active');
|
|
$('button[onclick="filterRecommendations(\'' + category + '\')"]').addClass('active');
|
|
}
|
|
|
|
function acceptRecommendation(recommendationId) {
|
|
$.post('{% url "emr:accept_recommendation" %}', {
|
|
recommendation_id: recommendationId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Recommendation accepted');
|
|
refreshRecommendations();
|
|
} else {
|
|
toastr.error('Failed to accept recommendation');
|
|
}
|
|
});
|
|
}
|
|
|
|
function deferRecommendation(recommendationId) {
|
|
$.post('{% url "emr:defer_recommendation" %}', {
|
|
recommendation_id: recommendationId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.info('Recommendation deferred');
|
|
refreshRecommendations();
|
|
} else {
|
|
toastr.error('Failed to defer recommendation');
|
|
}
|
|
});
|
|
}
|
|
|
|
function dismissRecommendation(recommendationId) {
|
|
$.post('{% url "emr:dismiss_recommendation" %}', {
|
|
recommendation_id: recommendationId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.info('Recommendation dismissed');
|
|
refreshRecommendations();
|
|
} else {
|
|
toastr.error('Failed to dismiss recommendation');
|
|
}
|
|
});
|
|
}
|
|
|
|
function acknowledgeAlert(alertId) {
|
|
$.post('{% url "emr:acknowledge_alert" %}', {
|
|
alert_id: alertId,
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Alert acknowledged');
|
|
location.reload();
|
|
} else {
|
|
toastr.error('Failed to acknowledge alert');
|
|
}
|
|
});
|
|
}
|
|
|
|
function orderTest(testCode) {
|
|
window.location.href = '{% url "laboratory:lab_order_create" %}?test_code=' + testCode + '&patient_id={{ patient.patient_id|default:"" }}';
|
|
}
|
|
|
|
function applyProtocol(protocolId) {
|
|
$.post('{% url "emr:apply_protocol" %}', {
|
|
protocol_id: protocolId,
|
|
patient_id: '{{ patient.patient_id|default:"" }}',
|
|
csrfmiddlewaretoken: '{{ csrf_token }}'
|
|
}, function(data) {
|
|
if (data.success) {
|
|
toastr.success('Protocol applied successfully');
|
|
refreshRecommendations();
|
|
} else {
|
|
toastr.error('Failed to apply protocol');
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateRecommendationsDisplay(recommendations) {
|
|
var html = '';
|
|
|
|
if (recommendations.length === 0) {
|
|
html = '<p class="text-muted">No clinical recommendations available</p>';
|
|
} else {
|
|
recommendations.forEach(function(rec) {
|
|
html += '<div class="recommendation-item mb-3 p-3 border rounded" data-category="' + rec.category + '">' +
|
|
'<div class="d-flex justify-content-between align-items-start">' +
|
|
'<div class="flex-grow-1">' +
|
|
'<h6 class="mb-1">' + rec.title + '</h6>' +
|
|
'<p class="mb-2">' + rec.description + '</p>' +
|
|
'<div class="row">' +
|
|
'<div class="col-md-6">' +
|
|
'<small class="text-muted">' +
|
|
'<strong>Evidence Level:</strong> ' + rec.evidence_level + '<br>' +
|
|
'<strong>Source:</strong> ' + rec.source +
|
|
'</small>' +
|
|
'</div>' +
|
|
'<div class="col-md-6">' +
|
|
'<small class="text-muted">' +
|
|
'<strong>Priority:</strong> ' + rec.priority + '<br>' +
|
|
'<strong>Category:</strong> ' + rec.category +
|
|
'</small>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="ms-3">' +
|
|
'<span class="badge bg-' + rec.priority.toLowerCase() + ' mb-2">' + rec.priority + '</span><br>' +
|
|
'<div class="btn-group-vertical btn-group-sm">' +
|
|
'<button class="btn btn-outline-success" onclick="acceptRecommendation(\'' + rec.id + '\')">' +
|
|
'<i class="fa fa-check"></i> Accept</button>' +
|
|
'<button class="btn btn-outline-secondary" onclick="deferRecommendation(\'' + rec.id + '\')">' +
|
|
'<i class="fa fa-clock-o"></i> Defer</button>' +
|
|
'<button class="btn btn-outline-danger" onclick="dismissRecommendation(\'' + rec.id + '\')">' +
|
|
'<i class="fa fa-times"></i> Dismiss</button>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>';
|
|
});
|
|
}
|
|
|
|
$('#clinicalRecommendations').html(html);
|
|
}
|
|
|
|
function updateDrugInteractionsDisplay(interactions) {
|
|
var html = '';
|
|
|
|
if (interactions.length === 0) {
|
|
html = '<p class="text-muted">No drug interactions detected</p>';
|
|
} else {
|
|
interactions.forEach(function(interaction) {
|
|
html += '<div class="alert alert-' + interaction.severity.toLowerCase() + ' mb-2">' +
|
|
'<div class="d-flex justify-content-between align-items-start">' +
|
|
'<div>' +
|
|
'<strong>' + interaction.drug1 + ' + ' + interaction.drug2 + '</strong>' +
|
|
'<br><small>' + interaction.description + '</small>' +
|
|
'</div>' +
|
|
'<span class="badge bg-' + interaction.severity.toLowerCase() + '">' +
|
|
interaction.severity +
|
|
'</span>' +
|
|
'</div>' +
|
|
'</div>';
|
|
});
|
|
}
|
|
|
|
$('#drugInteractions').html(html);
|
|
}
|
|
|
|
function updateAllergyAlertsDisplay(alerts) {
|
|
var html = '';
|
|
|
|
if (alerts.length === 0) {
|
|
html = '<p class="text-muted">No allergy conflicts detected</p>';
|
|
} else {
|
|
alerts.forEach(function(alert) {
|
|
html += '<div class="alert alert-warning mb-2">' +
|
|
'<div class="d-flex justify-content-between align-items-start">' +
|
|
'<div>' +
|
|
'<strong>' + alert.allergen + '</strong>' +
|
|
'<br><small>' + alert.reaction_type + '</small>' +
|
|
'</div>' +
|
|
'<span class="badge bg-warning">' + alert.severity + '</span>' +
|
|
'</div>' +
|
|
'</div>';
|
|
});
|
|
}
|
|
|
|
$('#allergyAlerts').html(html);
|
|
}
|
|
|
|
function updateRiskAssessmentDisplay(riskScores) {
|
|
// This would update the risk assessment cards
|
|
// Implementation depends on the specific risk score structure
|
|
toastr.info('Risk assessment display updated');
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.card-tools {
|
|
margin-left: auto;
|
|
}
|
|
|
|
.recommendation-item {
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.recommendation-item:hover {
|
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
}
|
|
|
|
.border-3 {
|
|
border-width: 3px !important;
|
|
}
|
|
|
|
.display-6 {
|
|
font-size: 2rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.btn-group-vertical .btn {
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
.btn-group-vertical .btn:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
#patientSearchResults {
|
|
position: absolute;
|
|
z-index: 1000;
|
|
width: 100%;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
background: white;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 0.375rem;
|
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
|
}
|
|
|
|
.list-group-item-action:hover {
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.alert {
|
|
border: 1px solid transparent;
|
|
}
|
|
|
|
.badge {
|
|
font-size: 0.75em;
|
|
}
|
|
|
|
.card-header h4 {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.text-high {
|
|
color: #dc3545;
|
|
}
|
|
|
|
.text-medium {
|
|
color: #fd7e14;
|
|
}
|
|
|
|
.text-low {
|
|
color: #198754;
|
|
}
|
|
|
|
.bg-high {
|
|
background-color: #dc3545 !important;
|
|
}
|
|
|
|
.bg-medium {
|
|
background-color: #fd7e14 !important;
|
|
}
|
|
|
|
.bg-low {
|
|
background-color: #198754 !important;
|
|
}
|
|
|
|
.border-high {
|
|
border-color: #dc3545 !important;
|
|
}
|
|
|
|
.border-medium {
|
|
border-color: #fd7e14 !important;
|
|
}
|
|
|
|
.border-low {
|
|
border-color: #198754 !important;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|