499 lines
24 KiB
HTML
499 lines
24 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ lab_test.test_name }} - Lab Test Details - {{ 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-vial me-2"></i>{{ lab_test.test_name }}
|
|
</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"><a href="{% url 'laboratory:dashboard' %}">Laboratory</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'laboratory:lab_test_list' %}">Lab Tests</a></li>
|
|
<li class="breadcrumb-item active">{{ lab_test.test_name }}</li>
|
|
</ol>
|
|
</nav>
|
|
</div>
|
|
<div class="btn-group">
|
|
{% if perms.laboratory.change_labtest %}
|
|
<a href="{% url 'laboratory:lab_test_update' lab_test.pk %}" class="btn btn-primary">
|
|
<i class="fas fa-edit me-2"></i>Edit Test
|
|
</a>
|
|
{% endif %}
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
|
<i class="fas fa-cog me-2"></i>Actions
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#" onclick="printTestDetails()">
|
|
<i class="fas fa-print me-2"></i>Print Details
|
|
</a></li>
|
|
<li><a class="dropdown-item" href="#" onclick="exportTestData()">
|
|
<i class="fas fa-download me-2"></i>Export Data
|
|
</a></li>
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="{% url 'laboratory:reference_range_create' %}?test={{ lab_test.pk }}">
|
|
<i class="fas fa-plus me-2"></i>Add Reference Range
|
|
</a></li>
|
|
{% if perms.laboratory.delete_labtest %}
|
|
<li><hr class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item text-danger" href="{% url 'laboratory:lab_test_delete' lab_test.pk %}">
|
|
<i class="fas fa-trash me-2"></i>Deactivate Test
|
|
</a></li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<!-- Test Information -->
|
|
<div class="col-lg-8 mb-4">
|
|
<div class="panel panel-inverse" data-sortable-id="index-1">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-info-circle me-2"></i> {{ _("Test Information")}}
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<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-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>#}
|
|
{##}
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Test Code:</td>
|
|
<td>{{ lab_test.test_code }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Category:</td>
|
|
<td>
|
|
<span class="badge bg-primary">{{ lab_test.get_category_display }}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Sample Type:</td>
|
|
<td>{{ lab_test.get_sample_type_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Result Type:</td>
|
|
<td>{{ lab_test.get_result_type_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Unit:</td>
|
|
<td>{{ lab_test.unit|default:"N/A" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-semibold text-muted">TAT (Hours):</td>
|
|
<td>{{ lab_test.turnaround_time_hours }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Price:</td>
|
|
<td class="fw-semibold text-success">${{ lab_test.price|floatformat:2 }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Status:</td>
|
|
<td>
|
|
{% if lab_test.is_active %}
|
|
<span class="badge bg-success">Active</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">Inactive</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Critical Test:</td>
|
|
<td>
|
|
{% if lab_test.is_critical %}
|
|
<span class="badge bg-danger">Yes</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">No</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-semibold text-muted">Created:</td>
|
|
<td>{{ lab_test.created_at|date:"M d, Y" }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{% if lab_test.test_description %}
|
|
<div class="mt-3">
|
|
<h6 class="fw-semibold text-muted">Description:</h6>
|
|
<p class="mb-0">{{ lab_test.test_description }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if lab_test.preparation_instructions %}
|
|
<div class="mt-3">
|
|
<h6 class="fw-semibold text-muted">Preparation Instructions:</h6>
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
{{ lab_test.preparation_instructions }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Stats -->
|
|
<div class="col-lg-4 mb-4">
|
|
<div class="panel panel-inverse" data-sortable-id="index-2">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-chart-bar me-2"></i> {{ _("Test Statistics")}}
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<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-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>#}
|
|
{##}
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row g-3">
|
|
<div class="col-6">
|
|
<div class="text-center p-3 bg-light rounded">
|
|
<div class="h4 mb-1 text-primary">{{ recent_orders.count }}</div>
|
|
<small class="text-muted">Recent Orders</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="text-center p-3 bg-light rounded">
|
|
<div class="h4 mb-1 text-success">{{ reference_ranges.count }}</div>
|
|
<small class="text-muted">Reference Ranges</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="text-center p-3 bg-light rounded">
|
|
<div class="h4 mb-1 text-info">{{ qc_records.count }}</div>
|
|
<small class="text-muted">QC Records</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-6">
|
|
<div class="text-center p-3 bg-light rounded">
|
|
<div class="h4 mb-1 text-warning">${{ lab_test.price|floatformat:0 }}</div>
|
|
<small class="text-muted">Price</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reference Ranges -->
|
|
{% if reference_ranges %}
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="panel panel-inverse" data-sortable-id="index-3">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-ruler me-2"></i>Reference Ranges
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'laboratory:reference_range_create' %}?test={{ lab_test.pk }}" class="btn btn-outline-primary btn-xs">
|
|
<i class="fas fa-plus me-1"></i>Add Range
|
|
</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-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>#}
|
|
{##}
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Gender</th>
|
|
<th>Age Range</th>
|
|
<th>Normal Range</th>
|
|
<th>Critical Low</th>
|
|
<th>Critical High</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for range in reference_ranges %}
|
|
<tr>
|
|
<td>
|
|
<span class="badge bg-{% if range.gender == 'M' %}primary{% elif range.gender == 'F' %}danger{% else %}secondary{% endif %}">
|
|
{{ range.get_gender_display }}
|
|
</span>
|
|
</td>
|
|
<td>{{ range.age_min }} - {{ range.age_max|default:"∞" }} years</td>
|
|
<td class="fw-semibold">{{ range.range_low }} - {{ range.range_high }}</td>
|
|
<td class="text-danger">{{ range.critical_low }}</td>
|
|
<td class="text-danger">{{ range.critical_high }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<a href="{% url 'laboratory:reference_range_detail' range.pk %}" class="btn btn-outline-primary btn-xs">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
{% if perms.laboratory.change_referencerange %}
|
|
<a href="{% url 'laboratory:reference_range_update' range.pk %}" class="btn btn-outline-secondary btn-xs">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Recent Orders and QC Records -->
|
|
<div class="row">
|
|
<!-- Recent Orders -->
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="panel panel-inverse" data-sortable-id="index-4">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-clipboard-list me-2"></i>Recent Orders
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'laboratory:lab_order_list' %}?test={{ lab_test.pk }}" class="btn btn-outline-primary btn-xs">
|
|
<i class="fas fa-list me-1"></i>View All
|
|
</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-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>#}
|
|
{##}
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if recent_orders %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Patient</th>
|
|
<th>Status</th>
|
|
<th>Ordered</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for order in recent_orders %}
|
|
<tr>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="bg-primary bg-gradient rounded-circle d-flex align-items-center justify-content-center me-2" style="width: 32px; height: 32px;">
|
|
<i class="fas fa-user text-white small"></i>
|
|
</div>
|
|
<div>
|
|
<div class="fw-semibold">{{ order.patient.get_full_name }}</div>
|
|
<small class="text-muted">{{ order.patient.mrn }}</small>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{% if order.status == 'COMPLETED' %}success{% elif order.status == 'IN_PROGRESS' %}warning{% elif order.status == 'PENDING' %}info{% else %}secondary{% endif %}">
|
|
{{ order.get_status_display }}
|
|
</span>
|
|
</td>
|
|
<td>{{ order.order_datetime|date:"M d, H:i" }}</td>
|
|
<td>
|
|
<a href="{% url 'laboratory:lab_order_detail' order.pk %}" class="btn btn-outline-primary btn-xs">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-4">
|
|
<i class="fas fa-clipboard-list fa-2x text-muted mb-3"></i>
|
|
<h6 class="text-muted">No recent orders</h6>
|
|
<p class="text-muted">Orders for this test will appear here</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quality Control Records -->
|
|
<div class="col-lg-6 mb-4">
|
|
<div class="panel panel-inverse" data-sortable-id="index-5">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">
|
|
<i class="fas fa-check-circle me-2"></i>Quality Control
|
|
</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'laboratory:quality_control_create' %}?test={{ lab_test.pk }}" class="btn btn-outline-success btn-xs">
|
|
<i class="fas fa-plus me-1"></i>Add QC
|
|
</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-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>#}
|
|
{# <a href="javascript:;" class="btn btn-xs btn-icon btn-danger" data-toggle="panel-remove"><i class="fa fa-times"></i></a>#}
|
|
{##}
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if qc_records %}
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Level</th>
|
|
<th>Result</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for qc in qc_records %}
|
|
<tr>
|
|
<td>{{ qc.run_datetime|date:"M d" }}</td>
|
|
<td>{{ qc.get_control_level_display }}</td>
|
|
<td class="fw-semibold">{{ qc.result.result_value }}</td>
|
|
<td>
|
|
<span class="badge bg-{% if qc.is_within_range %}success{% else %}danger{% endif %}">
|
|
{% if qc.is_within_range %}In Range{% else %}Out of Range{% endif %}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<a href="{% url 'laboratory:quality_control_detail' qc.pk %}" class="btn btn-outline-primary btn-xs">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-4">
|
|
<i class="fas fa-check-circle fa-2x text-muted mb-3"></i>
|
|
<h6 class="text-muted">No QC records</h6>
|
|
<p class="text-muted">Quality control records will appear here</p>
|
|
<a href="{% url 'laboratory:quality_control_create' %}?test={{ lab_test.pk }}" class="btn btn-success">
|
|
<i class="fas fa-plus me-2"></i>Add First QC Record
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function printTestDetails() {
|
|
window.print();
|
|
}
|
|
|
|
function exportTestData() {
|
|
// Export test data functionality
|
|
const testData = {
|
|
test_name: '{{ lab_test.test_name }}',
|
|
test_code: '{{ lab_test.test_code }}',
|
|
category: '{{ lab_test.get_category_display }}',
|
|
price: '{{ lab_test.price }}',
|
|
reference_ranges: {{ reference_ranges|length }},
|
|
recent_orders: {{ recent_orders|length }}
|
|
};
|
|
|
|
const dataStr = JSON.stringify(testData, null, 2);
|
|
const dataBlob = new Blob([dataStr], {type: 'application/json'});
|
|
const url = URL.createObjectURL(dataBlob);
|
|
const link = document.createElement('a');
|
|
link.href = url;
|
|
link.download = '{{ lab_test.test_code }}_data.json';
|
|
link.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
// Auto-refresh for real-time updates
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Refresh statistics every 5 minutes
|
|
setInterval(function() {
|
|
location.reload();
|
|
}, 300000);
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.table th {
|
|
border-top: none;
|
|
font-weight: 600;
|
|
color: #6c757d;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.table td {
|
|
vertical-align: middle;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.badge {
|
|
font-size: 0.75em;
|
|
}
|
|
|
|
.bg-gradient {
|
|
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
|
}
|
|
|
|
@media print {
|
|
.btn, .dropdown, .breadcrumb {
|
|
display: none !important;
|
|
}
|
|
|
|
.card {
|
|
border: 1px solid #dee2e6 !important;
|
|
box-shadow: none !important;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.d-flex.justify-content-between {
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.btn-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.table-responsive {
|
|
font-size: 0.8rem;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|