hospital-management/templates/quality/indicators/quality_indicator_detail.html
2025-08-12 13:33:25 +03:00

531 lines
24 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{{ object.name }} - Quality Indicator - {{ 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-chart-line me-2"></i>{{ object.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 'quality:dashboard' %}">Quality</a></li>
<li class="breadcrumb-item"><a href="{% url 'quality:quality_indicator_list' %}">Indicators</a></li>
<li class="breadcrumb-item active">{{ object.name|truncatechars:30 }}</li>
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% url 'quality:quality_indicator_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-2"></i>Back to List
</a>
<a href="{% url 'quality:quality_indicator_update' object.pk %}" class="btn btn-primary">
<i class="fas fa-edit me-2"></i>Edit
</a>
<div class="btn-group">
<button type="button" class="btn btn-outline-info dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'quality:quality_measurement_create' %}?indicator={{ object.pk }}">
<i class="fas fa-plus me-2"></i>Add Measurement
</a></li>
<li><a class="dropdown-item" href="#" onclick="exportData()">
<i class="fas fa-download me-2"></i>Export Data
</a></li>
<li><a class="dropdown-item" href="#" onclick="printIndicator()">
<i class="fas fa-print me-2"></i>Print
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item text-danger" href="{% url 'quality:quality_indicator_delete' object.pk %}">
<i class="fas fa-trash me-2"></i>Delete
</a></li>
</ul>
</div>
</div>
</div>
<div class="row">
<!-- Main Content -->
<div class="col-lg-8">
<!-- Indicator Overview -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-info-circle me-2"></i>Indicator Overview
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label text-muted">Description</label>
<p class="mb-0">{{ object.description }}</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Category</label>
<p class="mb-0">
<span class="badge bg-primary">{{ object.get_category_display }}</span>
</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Type</label>
<p class="mb-0">
<span class="badge bg-info">{{ object.get_type_display }}</span>
</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Measurement Unit</label>
<p class="mb-0">{{ object.measurement_unit }}</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Frequency</label>
<p class="mb-0">{{ object.get_frequency_display }}</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Status</label>
<p class="mb-0">
{% if object.is_active %}
<span class="badge bg-success">Active</span>
{% else %}
<span class="badge bg-secondary">Inactive</span>
{% endif %}
{% if object.regulatory_requirement %}
<span class="badge bg-warning text-dark ms-1">Regulatory</span>
{% endif %}
</p>
</div>
<div class="col-md-3 mb-3">
<label class="form-label text-muted">Current Status</label>
<p class="mb-0">
{% if object.current_status == 'within_target' %}
<span class="badge bg-success">Within Target</span>
{% elif object.current_status == 'warning' %}
<span class="badge bg-warning text-dark">Warning</span>
{% elif object.current_status == 'critical' %}
<span class="badge bg-danger">Critical</span>
{% else %}
<span class="badge bg-secondary">No Data</span>
{% endif %}
</p>
</div>
</div>
</div>
</div>
<!-- Targets and Thresholds -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-bullseye me-2"></i>Targets and Thresholds
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div class="text-center p-3 border rounded" style="background: linear-gradient(135deg, #28a745 0%, #20c997 100%);">
<div class="text-white">
<h4 class="mb-1">{{ object.target_value }}</h4>
<small class="opacity-75">Target Value</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="text-center p-3 border rounded" style="background: linear-gradient(135deg, #ffc107 0%, #fd7e14 100%);">
<div class="text-white">
<h4 class="mb-1">{{ object.threshold_warning }}</h4>
<small class="opacity-75">Warning Threshold</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="text-center p-3 border rounded" style="background: linear-gradient(135deg, #dc3545 0%, #e83e8c 100%);">
<div class="text-white">
<h4 class="mb-1">{{ object.threshold_critical }}</h4>
<small class="opacity-75">Critical Threshold</small>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Calculation Method -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-calculator me-2"></i>Calculation Method
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label text-muted">Calculation Method</label>
<div class="bg-light p-3 rounded">
<pre class="mb-0">{{ object.calculation_method }}</pre>
</div>
</div>
<div class="col-md-6 mb-3">
<label class="form-label text-muted">Data Source</label>
<p class="mb-0">{{ object.data_source }}</p>
</div>
</div>
</div>
</div>
<!-- Recent Measurements -->
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-chart-bar me-2"></i>Recent Measurements
</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="refreshMeasurements()">
<i class="fas fa-sync-alt"></i>
</button>
<a href="{% url 'quality:quality_measurement_create' %}?indicator={{ object.pk }}" class="btn btn-outline-primary">
<i class="fas fa-plus me-1"></i>Add Measurement
</a>
</div>
</div>
<div class="card-body p-0">
{% if object.measurements.all %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Date</th>
<th>Value</th>
<th>Status</th>
<th>Numerator</th>
<th>Denominator</th>
<th>Verified By</th>
<th width="100">Actions</th>
</tr>
</thead>
<tbody>
{% for measurement in object.measurements.all|slice:":10" %}
<tr>
<td>{{ measurement.measurement_date|date:"M d, Y" }}</td>
<td>
<strong>{{ measurement.value }}</strong>
<small class="text-muted">{{ object.measurement_unit }}</small>
</td>
<td>
{% if measurement.status == 'within_target' %}
<span class="badge bg-success">Within Target</span>
{% elif measurement.status == 'warning' %}
<span class="badge bg-warning text-dark">Warning</span>
{% elif measurement.status == 'critical' %}
<span class="badge bg-danger">Critical</span>
{% elif measurement.status == 'improving' %}
<span class="badge bg-info">Improving</span>
{% elif measurement.status == 'declining' %}
<span class="badge bg-warning text-dark">Declining</span>
{% else %}
<span class="badge bg-secondary">{{ measurement.get_status_display }}</span>
{% endif %}
</td>
<td>{{ measurement.numerator|default:"-" }}</td>
<td>{{ measurement.denominator|default:"-" }}</td>
<td>
{% if measurement.verified_by %}
<div class="d-flex align-items-center">
<div class="avatar-circle bg-success text-white me-2">
{{ measurement.verified_by.first_name.0 }}{{ measurement.verified_by.last_name.0 }}
</div>
<div>
<div class="fw-semibold">{{ measurement.verified_by.get_full_name }}</div>
<small class="text-muted">{{ measurement.verified_at|date:"M d, Y" }}</small>
</div>
</div>
{% else %}
<span class="text-muted">Not verified</span>
{% endif %}
</td>
<td>
<div class="btn-group btn-group-sm">
<a href="{% url 'quality:quality_measurement_detail' measurement.pk %}"
class="btn btn-outline-primary" title="View Details">
<i class="fas fa-eye"></i>
</a>
{% if not measurement.verified_by %}
<button class="btn btn-outline-success"
title="Verify"
onclick="verifyMeasurement({{ measurement.pk }})">
<i class="fas fa-check"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if object.measurements.count > 10 %}
<div class="card-footer text-center">
<a href="{% url 'quality:quality_measurement_list' %}?indicator={{ object.pk }}" class="btn btn-outline-primary btn-sm">
<i class="fas fa-list me-2"></i>View All Measurements ({{ object.measurements.count }})
</a>
</div>
{% endif %}
{% else %}
<div class="text-center py-5">
<i class="fas fa-chart-bar fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Measurements</h5>
<p class="text-muted mb-3">No measurements have been recorded for this indicator yet.</p>
<a href="{% url 'quality:quality_measurement_create' %}?indicator={{ object.pk }}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add First Measurement
</a>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Quick Stats -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-chart-pie me-2"></i>Quick Stats
</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-6">
<div class="text-center">
<h4 class="text-primary mb-1">{{ object.measurements.count }}</h4>
<small class="text-muted">Total Measurements</small>
</div>
</div>
<div class="col-6">
<div class="text-center">
{% if object.latest_measurement %}
<h4 class="mb-1
{% if object.current_status == 'within_target' %}text-success
{% elif object.current_status == 'warning' %}text-warning
{% elif object.current_status == 'critical' %}text-danger
{% else %}text-muted{% endif %}">
{{ object.latest_measurement.value }}
</h4>
<small class="text-muted">Latest Value</small>
{% else %}
<h4 class="text-muted mb-1">-</h4>
<small class="text-muted">No Data</small>
{% endif %}
</div>
</div>
<div class="col-6">
<div class="text-center">
<h4 class="text-success mb-1">{{ object.measurements.filter.status='within_target'.count }}</h4>
<small class="text-muted">Within Target</small>
</div>
</div>
<div class="col-6">
<div class="text-center">
<h4 class="text-warning mb-1">{{ object.measurements.filter.status='warning'.count }}</h4>
<small class="text-muted">Warning</small>
</div>
</div>
</div>
</div>
</div>
<!-- Responsibility -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-user-check me-2"></i>Responsibility
</h5>
</div>
<div class="card-body">
{% if object.responsible_department %}
<div class="mb-3">
<label class="form-label text-muted">Department</label>
<p class="mb-0">{{ object.responsible_department.name }}</p>
</div>
{% endif %}
{% if object.responsible_user %}
<div class="mb-3">
<label class="form-label text-muted">Responsible Person</label>
<div class="d-flex align-items-center">
<div class="avatar-circle bg-primary text-white me-3">
{{ object.responsible_user.first_name.0 }}{{ object.responsible_user.last_name.0 }}
</div>
<div>
<div class="fw-semibold">{{ object.responsible_user.get_full_name }}</div>
<small class="text-muted">{{ object.responsible_user.email }}</small>
</div>
</div>
</div>
{% endif %}
{% if not object.responsible_department and not object.responsible_user %}
<p class="text-muted mb-0">No specific responsibility assigned</p>
{% endif %}
</div>
</div>
<!-- Metadata -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-info me-2"></i>Metadata
</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label text-muted">Created</label>
<p class="mb-0">{{ object.created_at|date:"M d, Y g:i A" }}</p>
</div>
<div class="mb-3">
<label class="form-label text-muted">Last Updated</label>
<p class="mb-0">{{ object.updated_at|date:"M d, Y g:i A" }}</p>
</div>
{% if object.latest_measurement %}
<div class="mb-0">
<label class="form-label text-muted">Last Measurement</label>
<p class="mb-0">{{ object.latest_measurement.measurement_date|date:"M d, Y" }}</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<script>
// Refresh measurements
function refreshMeasurements() {
location.reload();
}
// Verify measurement
function verifyMeasurement(measurementId) {
if (confirm('Verify this measurement? This action cannot be undone.')) {
fetch(`/quality/measurements/${measurementId}/verify/`, {
method: 'POST',
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error verifying measurement: ' + data.error);
}
});
}
}
// Export data
function exportData() {
window.location.href = `/quality/indicators/${{{ object.pk }}}/export/`;
}
// Print indicator
function printIndicator() {
window.print();
}
</script>
<style>
.avatar-circle {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 1.1rem;
}
.card {
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
border: 1px solid rgba(0, 0, 0, 0.125);
}
.card-header {
background-color: rgba(13, 110, 253, 0.1);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}
.btn {
border-radius: 0.375rem;
transition: all 0.15s ease-in-out;
}
.btn:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.table th {
border-top: none;
font-weight: 600;
color: #495057;
}
.table-hover tbody tr:hover {
background-color: rgba(13, 110, 253, 0.05);
}
.fw-semibold {
font-weight: 600;
}
.badge {
font-size: 0.75rem;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
font-size: 0.875rem;
}
@media (max-width: 768px) {
.d-flex.justify-content-between {
flex-direction: column;
gap: 1rem;
}
.btn-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.card-body {
padding: 1rem;
}
.table-responsive {
font-size: 0.875rem;
}
}
@media print {
.btn, .btn-group, .dropdown {
display: none !important;
}
.card {
border: 1px solid #000 !important;
box-shadow: none !important;
}
}
</style>
{% endblock %}