764 lines
31 KiB
HTML
764 lines
31 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Vital Signs - EMR{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
|
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<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">Vital Signs</li>
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">
|
|
Vital Signs Management
|
|
<small>Patient Vital Signs Monitoring</small>
|
|
</h1>
|
|
<!-- END page-header -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Vital Signs Overview</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'emr:vital_signs_create' %}" class="btn btn-xs btn-success me-2">
|
|
<i class="fa fa-plus"></i> Record Vitals
|
|
</a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<!-- Filters and Search -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-3">
|
|
<label class="form-label">Search Patient</label>
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="search-input" placeholder="Patient name or MRN...">
|
|
<button class="btn btn-outline-secondary" type="button" id="search-btn">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Date Range</label>
|
|
<select class="form-select" id="date-filter">
|
|
<option value="">All Dates</option>
|
|
<option value="today">Today</option>
|
|
<option value="yesterday">Yesterday</option>
|
|
<option value="this_week">This Week</option>
|
|
<option value="last_week">Last Week</option>
|
|
<option value="this_month">This Month</option>
|
|
<option value="custom">Custom Range</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Measured By</label>
|
|
<select class="form-select select2" id="staff-filter">
|
|
<option value="">All Staff</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Critical Values</label>
|
|
<select class="form-select" id="critical-filter">
|
|
<option value="">All Measurements</option>
|
|
<option value="critical">Critical Values Only</option>
|
|
<option value="normal">Normal Values Only</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Encounter</label>
|
|
<select class="form-select select2" id="encounter-filter">
|
|
<option value="">All Encounters</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Custom Date Range (hidden by default) -->
|
|
<div class="row mb-3" id="custom-date-range" style="display: none;">
|
|
<div class="col-md-3">
|
|
<label class="form-label">Start Date</label>
|
|
<input type="date" class="form-control" id="start-date">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">End Date</label>
|
|
<input type="date" class="form-control" id="end-date">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label"> </label>
|
|
<button class="btn btn-primary d-block" id="apply-date-filter">Apply</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Stats -->
|
|
<div class="row mb-4">
|
|
<div class="col-lg-3 col-md-6 mb-3">
|
|
<div class="card border-0 bg-primary text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<div class="fs-10px text-white-transparent-5 mb-1">TODAY'S MEASUREMENTS</div>
|
|
<div class="fs-18px fw-900 text-white" id="todays-count">-</div>
|
|
</div>
|
|
<div class="w-50px h-50px bg-white-transparent-2 rounded-circle d-flex align-items-center justify-content-center">
|
|
<i class="fa fa-heartbeat fa-lg text-white"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6 mb-3">
|
|
<div class="card border-0 bg-warning text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<div class="fs-10px text-white-transparent-5 mb-1">CRITICAL VALUES</div>
|
|
<div class="fs-18px fw-900 text-white" id="critical-count">-</div>
|
|
</div>
|
|
<div class="w-50px h-50px bg-white-transparent-2 rounded-circle d-flex align-items-center justify-content-center">
|
|
<i class="fa fa-exclamation-triangle fa-lg text-white"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6 mb-3">
|
|
<div class="card border-0 bg-success text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<div class="fs-10px text-white-transparent-5 mb-1">VERIFIED MEASUREMENTS</div>
|
|
<div class="fs-18px fw-900 text-white" id="verified-count">-</div>
|
|
</div>
|
|
<div class="w-50px h-50px bg-white-transparent-2 rounded-circle d-flex align-items-center justify-content-center">
|
|
<i class="fa fa-check-circle fa-lg text-white"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6 mb-3">
|
|
<div class="card border-0 bg-info text-white">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-fill">
|
|
<div class="fs-10px text-white-transparent-5 mb-1">UNIQUE PATIENTS</div>
|
|
<div class="fs-18px fw-900 text-white" id="patients-count">-</div>
|
|
</div>
|
|
<div class="w-50px h-50px bg-white-transparent-2 rounded-circle d-flex align-items-center justify-content-center">
|
|
<i class="fa fa-users fa-lg text-white"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-secondary" id="bulk-actions-btn" disabled>
|
|
<i class="fa fa-tasks me-2"></i>Bulk Actions
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary dropdown-toggle dropdown-toggle-split"
|
|
data-bs-toggle="dropdown" id="bulk-dropdown" disabled>
|
|
<span class="visually-hidden">Toggle Dropdown</span>
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#" onclick="bulkVerify()">
|
|
<i class="fa fa-check me-2"></i>Verify Selected
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="bulkFlag()">
|
|
<i class="fa fa-flag me-2"></i>Flag for Review
|
|
</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#" onclick="bulkExport()">
|
|
<i class="fa fa-download me-2"></i>Export Selected
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-secondary" onclick="refreshTable()">
|
|
<i class="fa fa-refresh me-2"></i>Refresh
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" onclick="showTrendingChart()">
|
|
<i class="fa fa-chart-line me-2"></i>Trending
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
|
<i class="fa fa-download me-2"></i>Export
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#" onclick="exportData('csv')">
|
|
<i class="fa fa-file-csv me-2"></i>Export as CSV
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="exportData('excel')">
|
|
<i class="fa fa-file-excel me-2"></i>Export as Excel
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="exportData('pdf')">
|
|
<i class="fa fa-file-pdf me-2"></i>Export as PDF
|
|
</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Vital Signs Table -->
|
|
<div class="table-responsive">
|
|
<table id="vitals-table" class="table table-striped table-bordered align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th width="30">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="select-all">
|
|
</div>
|
|
</th>
|
|
<th>Patient</th>
|
|
<th>Date/Time</th>
|
|
<th>Temperature</th>
|
|
<th>Blood Pressure</th>
|
|
<th>Heart Rate</th>
|
|
<th>Respiratory Rate</th>
|
|
<th>O2 Saturation</th>
|
|
<th>Pain Scale</th>
|
|
<th>Measured By</th>
|
|
<th>Status</th>
|
|
<th width="120">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Data will be loaded via AJAX -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- Trending Chart Modal -->
|
|
<div class="modal fade" id="trendingModal" tabindex="-1">
|
|
<div class="modal-dialog modal-xl">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Vital Signs Trending</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row mb-3">
|
|
<div class="col-md-4">
|
|
<label class="form-label">Select Patient</label>
|
|
<select class="form-select select2" id="trending-patient">
|
|
<option value="">Select Patient</option>
|
|
<!-- Options will be loaded dynamically -->
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Time Period</label>
|
|
<select class="form-select" id="trending-period">
|
|
<option value="24h">Last 24 Hours</option>
|
|
<option value="7d">Last 7 Days</option>
|
|
<option value="30d">Last 30 Days</option>
|
|
<option value="90d">Last 90 Days</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label">Vital Sign</label>
|
|
<select class="form-select" id="trending-vital">
|
|
<option value="temperature">Temperature</option>
|
|
<option value="blood_pressure">Blood Pressure</option>
|
|
<option value="heart_rate">Heart Rate</option>
|
|
<option value="respiratory_rate">Respiratory Rate</option>
|
|
<option value="oxygen_saturation">Oxygen Saturation</option>
|
|
<option value="pain_scale">Pain Scale</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div style="height: 400px;">
|
|
<canvas id="trending-chart"></canvas>
|
|
</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="exportChart()">Export Chart</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick View Modal -->
|
|
<div class="modal fade" id="vitalQuickViewModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Vital Signs Quick View</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body" id="vital-quick-view-content">
|
|
<!-- Content will be loaded dynamically -->
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<a href="#" class="btn btn-primary" id="view-full-vital">View Full Details</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'plugins/datatables.net/js/dataTables.min.js' %}"></script>
|
|
<script src="{% static 'plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
|
|
<script src="{% static 'plugins/datatables.net-responsive/js/dataTables.responsive.min.js' %}"></script>
|
|
<script src="{% static 'plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js' %}"></script>
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
<script src="{% static 'plugins/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js' %}"></script>
|
|
<script src="{% static 'plugins/chart.js/dist/Chart.js' %}"></script>
|
|
<script>
|
|
$(document).ready(function() {
|
|
var table;
|
|
var trendingChart;
|
|
|
|
// Initialize DataTable
|
|
table = $('#vitals-table').DataTable({
|
|
processing: true,
|
|
serverSide: true,
|
|
ajax: {
|
|
url: '{% url "emr:vital_signs_list_api" %}',
|
|
data: function(d) {
|
|
d.search_value = $('#search-input').val();
|
|
d.date_range = $('#date-filter').val();
|
|
d.start_date = $('#start-date').val();
|
|
d.end_date = $('#end-date').val();
|
|
d.staff = $('#staff-filter').val();
|
|
d.critical = $('#critical-filter').val();
|
|
d.encounter = $('#encounter-filter').val();
|
|
}
|
|
},
|
|
columns: [
|
|
{
|
|
data: 'id',
|
|
orderable: false,
|
|
render: function(data, type, row) {
|
|
return '<div class="form-check"><input class="form-check-input vital-checkbox" type="checkbox" value="' + data + '"></div>';
|
|
}
|
|
},
|
|
{
|
|
data: 'patient',
|
|
render: function(data, type, row) {
|
|
return '<div class="d-flex align-items-center">' +
|
|
'<div class="flex-fill">' +
|
|
'<div class="fw-bold">' + data.name + '</div>' +
|
|
'<div class="text-muted small">' + data.mrn + '</div>' +
|
|
'</div></div>';
|
|
}
|
|
},
|
|
{
|
|
data: 'measured_datetime',
|
|
render: function(data, type, row) {
|
|
var date = new Date(data);
|
|
return '<div>' +
|
|
'<div>' + date.toLocaleDateString() + '</div>' +
|
|
'<div class="text-muted small">' + date.toLocaleTimeString() + '</div>' +
|
|
'</div>';
|
|
}
|
|
},
|
|
{
|
|
data: 'temperature',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
var critical = row.critical_values.includes('temperature');
|
|
var className = critical ? 'text-danger fw-bold' : '';
|
|
return '<span class="' + className + '">' + data + '°F</span>' +
|
|
(row.temperature_method ? '<br><small class="text-muted">(' + row.temperature_method + ')</small>' : '');
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'blood_pressure',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
var critical = row.critical_values.includes('blood_pressure');
|
|
var className = critical ? 'text-danger fw-bold' : '';
|
|
return '<span class="' + className + '">' + data + '</span>';
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'heart_rate',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
var critical = row.critical_values.includes('heart_rate');
|
|
var className = critical ? 'text-danger fw-bold' : '';
|
|
return '<span class="' + className + '">' + data + ' bpm</span>';
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'respiratory_rate',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
var critical = row.critical_values.includes('respiratory_rate');
|
|
var className = critical ? 'text-danger fw-bold' : '';
|
|
return '<span class="' + className + '">' + data + ' /min</span>';
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'oxygen_saturation',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
var critical = row.critical_values.includes('oxygen_saturation');
|
|
var className = critical ? 'text-danger fw-bold' : '';
|
|
return '<span class="' + className + '">' + data + '%</span>' +
|
|
(row.oxygen_delivery !== 'ROOM_AIR' ? '<br><small class="text-muted">(' + row.oxygen_delivery + ')</small>' : '');
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'pain_scale',
|
|
render: function(data, type, row) {
|
|
if (data !== null) {
|
|
var className = data >= 7 ? 'text-danger fw-bold' : (data >= 4 ? 'text-warning' : '');
|
|
return '<span class="' + className + '">' + data + '/10</span>';
|
|
}
|
|
return '<span class="text-muted">-</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'measured_by',
|
|
render: function(data, type, row) {
|
|
return '<div>' +
|
|
'<div>' + data.name + '</div>' +
|
|
(row.verified_by ? '<div class="text-success small"><i class="fa fa-check"></i> Verified</div>' : '') +
|
|
'</div>';
|
|
}
|
|
},
|
|
{
|
|
data: 'has_critical_values',
|
|
render: function(data, type, row) {
|
|
if (data) {
|
|
return '<span class="badge bg-danger">Critical</span>';
|
|
} else if (row.verified_by) {
|
|
return '<span class="badge bg-success">Verified</span>';
|
|
}
|
|
return '<span class="badge bg-secondary">Normal</span>';
|
|
}
|
|
},
|
|
{
|
|
data: 'id',
|
|
orderable: false,
|
|
render: function(data, type, row) {
|
|
return '<div class="btn-group btn-group-sm">' +
|
|
'<button class="btn btn-outline-primary" onclick="viewVital(' + data + ')" title="View">' +
|
|
'<i class="fa fa-eye"></i></button>' +
|
|
'<button class="btn btn-outline-secondary" onclick="editVital(' + data + ')" title="Edit">' +
|
|
'<i class="fa fa-edit"></i></button>' +
|
|
'<button class="btn btn-outline-success" onclick="verifyVital(' + data + ')" title="Verify">' +
|
|
'<i class="fa fa-check"></i></button>' +
|
|
'</div>';
|
|
}
|
|
}
|
|
],
|
|
order: [[2, 'desc']],
|
|
pageLength: 25,
|
|
responsive: true,
|
|
language: {
|
|
processing: '<div class="d-flex justify-content-center"><div class="spinner-border" role="status"></div></div>'
|
|
}
|
|
});
|
|
|
|
// Initialize Select2
|
|
$('.select2').select2({
|
|
theme: 'bootstrap-5',
|
|
width: '100%'
|
|
});
|
|
|
|
// Load filter options
|
|
loadFilterOptions();
|
|
loadStats();
|
|
|
|
// Filter event handlers
|
|
$('#search-input, #date-filter, #staff-filter, #critical-filter, #encounter-filter').on('change keyup', function() {
|
|
if ($(this).attr('id') === 'date-filter' && $(this).val() === 'custom') {
|
|
$('#custom-date-range').show();
|
|
} else if ($(this).attr('id') === 'date-filter') {
|
|
$('#custom-date-range').hide();
|
|
}
|
|
table.draw();
|
|
});
|
|
|
|
$('#apply-date-filter').on('click', function() {
|
|
table.draw();
|
|
});
|
|
|
|
// Select all checkbox
|
|
$('#select-all').on('change', function() {
|
|
$('.vital-checkbox').prop('checked', this.checked);
|
|
updateBulkActions();
|
|
});
|
|
|
|
// Individual checkbox change
|
|
$(document).on('change', '.vital-checkbox', function() {
|
|
updateBulkActions();
|
|
});
|
|
|
|
// Auto-refresh every 60 seconds
|
|
setInterval(function() {
|
|
table.ajax.reload(null, false);
|
|
loadStats();
|
|
}, 60000);
|
|
});
|
|
|
|
function loadFilterOptions() {
|
|
// Load staff options
|
|
$.ajax({
|
|
url: '{% url "users:staff_list_api" %}',
|
|
success: function(data) {
|
|
var select = $('#staff-filter');
|
|
data.forEach(function(staff) {
|
|
select.append('<option value="' + staff.id + '">' + staff.name + '</option>');
|
|
});
|
|
}
|
|
});
|
|
|
|
// Load encounter options
|
|
$.ajax({
|
|
url: '{% url "emr:encounter_list_api" %}?active_only=true',
|
|
success: function(data) {
|
|
var select = $('#encounter-filter');
|
|
data.results.forEach(function(encounter) {
|
|
select.append('<option value="' + encounter.id + '">' +
|
|
encounter.patient.name + ' - ' + encounter.start_datetime + '</option>');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function loadStats() {
|
|
$.ajax({
|
|
url: '{% url "emr:vital_signs_stats" %}',
|
|
success: function(data) {
|
|
$('#todays-count').text(data.todays_count);
|
|
$('#critical-count').text(data.critical_count);
|
|
$('#verified-count').text(data.verified_count);
|
|
$('#patients-count').text(data.patients_count);
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateBulkActions() {
|
|
var checkedCount = $('.vital-checkbox:checked').length;
|
|
$('#bulk-actions-btn, #bulk-dropdown').prop('disabled', checkedCount === 0);
|
|
}
|
|
|
|
function viewVital(vitalId) {
|
|
window.location.href = '{% url "emr:vital_signs_detail" 0 %}'.replace('0', vitalId);
|
|
}
|
|
|
|
function editVital(vitalId) {
|
|
window.location.href = '{% url "emr:vital_signs_update" 0 %}'.replace('0', vitalId);
|
|
}
|
|
|
|
function verifyVital(vitalId) {
|
|
if (confirm('Verify these vital signs measurements?')) {
|
|
$.ajax({
|
|
url: '{% url "emr:vital_signs_verify" 0 %}'.replace('0', vitalId),
|
|
method: 'POST',
|
|
data: {
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success('Vital signs verified successfully');
|
|
$('#vitals-table').DataTable().ajax.reload();
|
|
} else {
|
|
toastr.error('Failed to verify vital signs');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred while verifying vital signs');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function bulkVerify() {
|
|
var selectedIds = $('.vital-checkbox:checked').map(function() {
|
|
return this.value;
|
|
}).get();
|
|
|
|
if (selectedIds.length === 0) {
|
|
toastr.warning('Please select vital signs to verify');
|
|
return;
|
|
}
|
|
|
|
if (confirm('Verify ' + selectedIds.length + ' vital signs measurement(s)?')) {
|
|
$.ajax({
|
|
url: '{% url "emr:vital_signs_bulk_verify" %}',
|
|
method: 'POST',
|
|
data: {
|
|
'vital_ids': selectedIds,
|
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
toastr.success(response.message);
|
|
$('#vitals-table').DataTable().ajax.reload();
|
|
$('#select-all').prop('checked', false);
|
|
updateBulkActions();
|
|
} else {
|
|
toastr.error('Failed to verify vital signs');
|
|
}
|
|
},
|
|
error: function() {
|
|
toastr.error('An error occurred during bulk verification');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function bulkFlag() {
|
|
var selectedIds = $('.vital-checkbox:checked').map(function() {
|
|
return this.value;
|
|
}).get();
|
|
|
|
if (selectedIds.length === 0) {
|
|
toastr.warning('Please select vital signs to flag');
|
|
return;
|
|
}
|
|
|
|
// Implementation for flagging vital signs for review
|
|
toastr.info('Flagging functionality will be implemented');
|
|
}
|
|
|
|
function bulkExport() {
|
|
var selectedIds = $('.vital-checkbox:checked').map(function() {
|
|
return this.value;
|
|
}).get();
|
|
|
|
if (selectedIds.length === 0) {
|
|
toastr.warning('Please select vital signs to export');
|
|
return;
|
|
}
|
|
|
|
window.location.href = '{% url "emr:vital_signs_export" %}?ids=' + selectedIds.join(',');
|
|
}
|
|
|
|
function exportData(format) {
|
|
window.location.href = '{% url "emr:vital_signs_export" %}?format=' + format;
|
|
}
|
|
|
|
function refreshTable() {
|
|
$('#vitals-table').DataTable().ajax.reload();
|
|
loadStats();
|
|
toastr.info('Table refreshed');
|
|
}
|
|
|
|
function showTrendingChart() {
|
|
$('#trendingModal').modal('show');
|
|
loadTrendingPatients();
|
|
}
|
|
|
|
function loadTrendingPatients() {
|
|
$.ajax({
|
|
url: '{% url "patients:patient_list_api" %}',
|
|
success: function(data) {
|
|
var select = $('#trending-patient');
|
|
select.empty().append('<option value="">Select Patient</option>');
|
|
data.forEach(function(patient) {
|
|
select.append('<option value="' + patient.id + '">' + patient.name + ' (' + patient.mrn + ')</option>');
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function exportChart() {
|
|
if (trendingChart) {
|
|
var url = trendingChart.toBase64Image();
|
|
var link = document.createElement('a');
|
|
link.download = 'vital-signs-trend.png';
|
|
link.href = url;
|
|
link.click();
|
|
}
|
|
}
|
|
|
|
// Trending chart functionality
|
|
$('#trending-patient, #trending-period, #trending-vital').on('change', function() {
|
|
var patientId = $('#trending-patient').val();
|
|
var period = $('#trending-period').val();
|
|
var vital = $('#trending-vital').val();
|
|
|
|
if (patientId && period && vital) {
|
|
loadTrendingData(patientId, period, vital);
|
|
}
|
|
});
|
|
|
|
function loadTrendingData(patientId, period, vital) {
|
|
$.ajax({
|
|
url: '{% url "emr:vital_signs_trending" %}',
|
|
data: {
|
|
'patient_id': patientId,
|
|
'period': period,
|
|
'vital': vital
|
|
},
|
|
success: function(data) {
|
|
renderTrendingChart(data, vital);
|
|
},
|
|
error: function() {
|
|
toastr.error('Failed to load trending data');
|
|
}
|
|
});
|
|
}
|
|
|
|
function renderTrendingChart(data, vital) {
|
|
var ctx = document.getElementById('trending-chart').getContext('2d');
|
|
|
|
if (trendingChart) {
|
|
trendingChart.destroy();
|
|
}
|
|
|
|
trendingChart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: data.labels,
|
|
datasets: [{
|
|
label: vital.replace('_', ' ').toUpperCase(),
|
|
data: data.values,
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: false
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|
|
|