Marwan Alwali 0a037d3d9d update
2025-09-01 11:26:11 +03:00

655 lines
30 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Quality Management Dashboard - {{ 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-award me-2"></i>Quality Management Dashboard
</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">Quality Management</li>
</ol>
</nav>
</div>
<div class="btn-group">
<a href="{% url 'quality:incident_report_create' %}" class="btn btn-danger">
<i class="fas fa-exclamation-triangle me-2"></i>Report Incident
</a>
<a href="{% url 'quality:measurement_create' %}" class="btn btn-primary">
<i class="fas fa-chart-line me-2"></i>Record Measurement
</a>
<a href="{% url 'quality:risk_assessment_create' %}" class="btn btn-warning">
<i class="fas fa-shield-alt me-2"></i>Risk Assessment
</a>
</div>
</div>
<!-- Key Performance Indicators -->
<div class="row mb-4" hx-get="{% url 'quality:quality_stats' %}" hx-trigger="load, every 30s">
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #28a745 0%, #20c997 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ indicators_meeting_target|default:0 }}</h2>
<p class="mb-0 opacity-75">Indicators Meeting Target</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-bullseye"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #ffc107 0%, #fd7e14 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ indicators_below_target|default:0 }}</h2>
<p class="mb-0 opacity-75">Indicators Below Target</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-exclamation-triangle"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #0d6efd 0%, #6f42c1 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ total_indicators|default:0 }}</h2>
<p class="mb-0 opacity-75">Total Active Indicators</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-chart-line"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #20c997 0%, #0dcaf0 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ measurements_this_month|default:0 }}</h2>
<p class="mb-0 opacity-75">Measurements This Month</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-chart-bar"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Incident and Risk Statistics -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #dc3545 0%, #e83e8c 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ incidents_this_month|default:0 }}</h2>
<p class="mb-0 opacity-75">Incidents This Month</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-exclamation-circle"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #fd7e14 0%, #ffc107 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ incidents_open|default:0 }}</h2>
<p class="mb-0 opacity-75">Open Incidents</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-folder-open"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #dc3545 0%, #6f42c1 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ high_risk_incidents|default:0 }}</h2>
<p class="mb-0 opacity-75">High Risk Incidents</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-fire"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #6f42c1 0%, #e83e8c 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ risk_assessments_pending|default:0 }}</h2>
<p class="mb-0 opacity-75">Pending Risk Assessments</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-shield-alt"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Audit and Project Statistics -->
<div class="row mb-4">
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #0dcaf0 0%, #20c997 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ audits_active|default:0 }}</h2>
<p class="mb-0 opacity-75">Active Audits</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-search"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #ffc107 0%, #fd7e14 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ audit_findings_open|default:0 }}</h2>
<p class="mb-0 opacity-75">Open Audit Findings</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-clipboard-list"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #28a745 0%, #20c997 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ improvement_projects_active|default:0 }}</h2>
<p class="mb-0 opacity-75">Active Projects</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-project-diagram"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<div class="card h-100" style="background: linear-gradient(135deg, #6f42c1 0%, #0d6efd 100%);">
<div class="card-body text-white">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ recent_measurements|length|default:0 }}</h2>
<p class="mb-0 opacity-75">Recent Measurements</p>
</div>
<div class="fs-1 opacity-50">
<i class="fas fa-ruler"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Activity and Performance -->
<div class="row mb-4">
<div class="col-lg-6 mb-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-exclamation-triangle me-2"></i>Recent Incidents
</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="refreshIncidents()">
<i class="fas fa-sync-alt"></i>
</button>
<a href="{% url 'quality:incident_report_list' %}" class="btn btn-outline-primary">
<i class="fas fa-list me-1"></i>View All
</a>
</div>
</div>
<div class="card-body p-0">
{% if recent_incidents %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Title</th>
<th>Severity</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for incident in recent_incidents %}
<tr>
<td>
<a href="{% url 'quality:incident_report_detail' incident.pk %}" class="text-decoration-none">
<div class="fw-semibold">{{ incident.incident_title|truncatechars:30 }}</div>
<small class="text-muted">{{ incident.location }}</small>
</a>
</td>
<td>
{% if incident.severity == 'CRITICAL' %}
<span class="badge bg-danger">Critical</span>
{% elif incident.severity == 'HIGH' %}
<span class="badge bg-warning text-dark">High</span>
{% elif incident.severity == 'MEDIUM' %}
<span class="badge bg-info">Medium</span>
{% else %}
<span class="badge bg-secondary">Low</span>
{% endif %}
</td>
<td>
{% if incident.status == 'CLOSED' %}
<span class="badge bg-success">Closed</span>
{% elif incident.status == 'INVESTIGATING' %}
<span class="badge bg-warning text-dark">Investigating</span>
{% else %}
<span class="badge bg-primary">{{ incident.get_status_display }}</span>
{% endif %}
</td>
<td>{{ incident.incident_date|date:"M d" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-exclamation-triangle fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Recent Incidents</h5>
<p class="text-muted mb-3">No incidents have been reported recently.</p>
<a href="{% url 'quality:incident_report_create' %}" class="btn btn-danger">
<i class="fas fa-plus me-2"></i>Report Incident
</a>
</div>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-chart-line me-2"></i>Quality Indicator Performance
</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="refreshPerformance()">
<i class="fas fa-sync-alt"></i>
</button>
<a href="{% url 'quality:quality_indicator_list' %}" class="btn btn-outline-primary">
<i class="fas fa-list me-1"></i>View All
</a>
</div>
</div>
<div class="card-body">
{% if indicator_performance %}
{% for indicator in indicator_performance %}
<div class="d-flex align-items-center mb-3">
<div style="min-width: 120px;">
<div class="fw-semibold">{{ indicator.indicator_name|truncatechars:15 }}</div>
<small class="text-muted">{{ indicator.current_value|floatformat:1 }}{{ indicator.measurement_unit }}</small>
</div>
<div class="flex-grow-1 mx-3">
<div class="progress" style="height: 20px;">
{% if indicator.performance_percentage >= 100 %}
<div class="progress-bar bg-success" style="width: {{ indicator.performance_percentage|floatformat:0 }}%"></div>
{% elif indicator.performance_percentage >= 80 %}
<div class="progress-bar bg-warning" style="width: {{ indicator.performance_percentage|floatformat:0 }}%"></div>
{% else %}
<div class="progress-bar bg-danger" style="width: {{ indicator.performance_percentage|floatformat:0 }}%"></div>
{% endif %}
</div>
</div>
<div style="min-width: 50px; text-align: right;">
<strong>{{ indicator.performance_percentage|floatformat:0 }}%</strong>
</div>
</div>
{% endfor %}
{% else %}
<div class="text-center py-5">
<i class="fas fa-chart-line fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Quality Indicators</h5>
<p class="text-muted mb-3">No quality indicators have been configured yet.</p>
<a href="{% url 'quality:quality_indicator_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Create Indicator
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Recent Measurements and Active Projects -->
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card h-100">
<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:measurement_list' %}" class="btn btn-outline-primary">
<i class="fas fa-list me-1"></i>View All
</a>
</div>
</div>
<div class="card-body p-0">
{% if recent_measurements %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Indicator</th>
<th>Value</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{% for measurement in recent_measurements %}
<tr>
<td>
<a href="{% url 'quality:quality_measurement_detail' measurement.pk %}" class="text-decoration-none">
{{ measurement.indicator.indicator_name|truncatechars:25 }}
</a>
</td>
<td>
<strong>{{ measurement.value|floatformat:1 }}</strong>
<small class="text-muted">{{ measurement.indicator.measurement_unit }}</small>
</td>
<td>
{% if measurement.status == 'VERIFIED' %}
<span class="badge bg-success">Verified</span>
{% elif measurement.status == 'PENDING' %}
<span class="badge bg-warning text-dark">Pending</span>
{% else %}
<span class="badge bg-secondary">{{ measurement.get_status_display }}</span>
{% endif %}
</td>
<td>{{ measurement.measurement_date|date:"M d" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% 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 Recent Measurements</h5>
<p class="text-muted mb-3">No measurements have been recorded recently.</p>
<a href="{% url 'quality:measurement_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Record Measurement
</a>
</div>
{% endif %}
</div>
</div>
</div>
<div class="col-lg-6 mb-4">
<div class="card h-100">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-project-diagram me-2"></i>Active Improvement Projects
</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="refreshProjects()">
<i class="fas fa-sync-alt"></i>
</button>
<a href="{% url 'quality:improvement_project_list' %}" class="btn btn-outline-primary">
<i class="fas fa-list me-1"></i>View All
</a>
</div>
</div>
<div class="card-body p-0">
{% if active_projects %}
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-light">
<tr>
<th>Project</th>
<th>Manager</th>
<th>Methodology</th>
<th>Target Date</th>
</tr>
</thead>
<tbody>
{% for project in active_projects %}
<tr>
<td>
<a href="{% url 'quality:improvement_project_detail' project.pk %}" class="text-decoration-none">
{{ project.project_name|truncatechars:25 }}
</a>
</td>
<td>
{% if project.project_manager %}
<div class="d-flex align-items-center">
<div class="avatar-circle bg-primary text-white me-2">
{{ project.project_manager.first_name.0 }}{{ project.project_manager.last_name.0 }}
</div>
<div>
<div class="fw-semibold">{{ project.project_manager.first_name }} {{ project.project_manager.last_name }}</div>
</div>
</div>
{% else %}
<span class="text-muted">N/A</span>
{% endif %}
</td>
<td>
<span class="badge bg-info">{{ project.get_methodology_display }}</span>
</td>
<td>{{ project.target_completion_date|date:"M d, Y" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-5">
<i class="fas fa-project-diagram fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Active Projects</h5>
<p class="text-muted mb-3">No improvement projects are currently active.</p>
<a href="{% url 'quality:improvement_project_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Start Project
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-bolt me-2"></i>Quick Actions
</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-md-3">
<a href="{% url 'quality:incident_report_create' %}" class="btn btn-outline-danger w-100 h-100 d-flex flex-column align-items-center justify-content-center p-3">
<i class="fas fa-exclamation-triangle fa-2x mb-2"></i>
<span>Report Incident</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'quality:measurement_create' %}" class="btn btn-outline-primary w-100 h-100 d-flex flex-column align-items-center justify-content-center p-3">
<i class="fas fa-chart-line fa-2x mb-2"></i>
<span>Record Measurement</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'quality:risk_assessment_create' %}" class="btn btn-outline-warning w-100 h-100 d-flex flex-column align-items-center justify-content-center p-3">
<i class="fas fa-shield-alt fa-2x mb-2"></i>
<span>Risk Assessment</span>
</a>
</div>
<div class="col-md-3">
<a href="{% url 'quality:improvement_project_create' %}" class="btn btn-outline-success w-100 h-100 d-flex flex-column align-items-center justify-content-center p-3">
<i class="fas fa-project-diagram fa-2x mb-2"></i>
<span>Start Project</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Auto-refresh functions
function refreshIncidents() {
location.reload();
}
function refreshPerformance() {
location.reload();
}
function refreshMeasurements() {
location.reload();
}
function refreshProjects() {
location.reload();
}
// Auto-refresh every 5 minutes
setInterval(function() {
const statsContainer = document.querySelector('[hx-get]');
if (statsContainer) {
htmx.trigger(statsContainer, 'refresh');
}
}, 300000);
</script>
<style>
.avatar-circle {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 0.875rem;
}
.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;
}
.progress {
border-radius: 10px;
}
.progress-bar {
border-radius: 10px;
}
@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;
}
.row.g-3 {
gap: 1rem !important;
}
}
</style>
{% endblock %}