357 lines
17 KiB
HTML
357 lines
17 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Quality Control - Laboratory{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="content">
|
|
<div class="container-fluid">
|
|
<!-- Page Header -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="page-header">
|
|
<div class="page-title">
|
|
<h4>Quality Control Management</h4>
|
|
<h6>Monitor and manage laboratory quality control procedures</h6>
|
|
</div>
|
|
<div class="page-btn">
|
|
<a href="#" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addQCModal">
|
|
<i class="fa fa-plus"></i> Add QC Test
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QC Summary Cards -->
|
|
<div class="row">
|
|
<div class="col-xl-3 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-primary border-primary">
|
|
<i class="fa fa-check-circle"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ qc_stats.passed_today|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">QC Tests Passed Today</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-warning border-warning">
|
|
<i class="fa fa-exclamation-triangle"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ qc_stats.failed_today|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">QC Tests Failed Today</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-info border-info">
|
|
<i class="fa fa-clock"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ qc_stats.pending_today|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Pending QC Tests</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-3 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-success border-success">
|
|
<i class="fa fa-percentage"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ qc_stats.success_rate|default:0 }}%</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Success Rate This Month</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QC Filters -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Quality Control Filters</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="get" class="row g-3">
|
|
<div class="col-md-3">
|
|
<label class="form-label">Test Type</label>
|
|
<select name="test_type" class="form-select">
|
|
<option value="">All Test Types</option>
|
|
<option value="chemistry">Chemistry</option>
|
|
<option value="hematology">Hematology</option>
|
|
<option value="microbiology">Microbiology</option>
|
|
<option value="immunology">Immunology</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label">Control Level</label>
|
|
<select name="control_level" class="form-select">
|
|
<option value="">All Levels</option>
|
|
<option value="level_1">Level 1 (Low)</option>
|
|
<option value="level_2">Level 2 (Normal)</option>
|
|
<option value="level_3">Level 3 (High)</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All Status</option>
|
|
<option value="passed">Passed</option>
|
|
<option value="failed">Failed</option>
|
|
<option value="pending">Pending</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Date Range</label>
|
|
<input type="date" name="date_from" class="form-control" placeholder="From Date">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label"> </label>
|
|
<input type="date" name="date_to" class="form-control" placeholder="To Date">
|
|
</div>
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-search"></i> Filter
|
|
</button>
|
|
<a href="{% url 'laboratory:quality_control' %}" class="btn btn-secondary">
|
|
<i class="fa fa-refresh"></i> Reset
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QC Tests Table -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Quality Control Tests</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>QC ID</th>
|
|
<th>Test Type</th>
|
|
<th>Control Material</th>
|
|
<th>Level</th>
|
|
<th>Target Value</th>
|
|
<th>Observed Value</th>
|
|
<th>Status</th>
|
|
<th>Performed By</th>
|
|
<th>Date/Time</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for qc in quality_controls %}
|
|
<tr>
|
|
<td>{{ qc.qc_id }}</td>
|
|
<td>{{ qc.test_type|title }}</td>
|
|
<td>{{ qc.control_material }}</td>
|
|
<td>
|
|
<span class="badge bg-info">{{ qc.control_level|title }}</span>
|
|
</td>
|
|
<td>{{ qc.target_value }} {{ qc.unit }}</td>
|
|
<td>{{ qc.observed_value }} {{ qc.unit }}</td>
|
|
<td>
|
|
{% if qc.status == 'passed' %}
|
|
<span class="badge bg-success">Passed</span>
|
|
{% elif qc.status == 'failed' %}
|
|
<span class="badge bg-danger">Failed</span>
|
|
{% else %}
|
|
<span class="badge bg-warning">Pending</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ qc.performed_by.get_full_name|default:qc.performed_by.username }}</td>
|
|
<td>{{ qc.performed_at|date:"M d, Y H:i" }}</td>
|
|
<td>
|
|
<div class="btn-group">
|
|
<a href="#" class="btn btn-sm btn-outline-primary" title="View Details">
|
|
<i class="fa fa-eye"></i>
|
|
</a>
|
|
{% if qc.status == 'pending' %}
|
|
<a href="#" class="btn btn-sm btn-outline-success" title="Mark as Passed">
|
|
<i class="fa fa-check"></i>
|
|
</a>
|
|
<a href="#" class="btn btn-sm btn-outline-danger" title="Mark as Failed">
|
|
<i class="fa fa-times"></i>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="10" class="text-center">No quality control tests found</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QC Trends Chart -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">QC Trends</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="qcTrendsChart" height="100"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add QC Test Modal -->
|
|
<div class="modal fade" id="addQCModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Add Quality Control Test</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Test Type</label>
|
|
<select name="test_type" class="form-select" required>
|
|
<option value="">Select Test Type</option>
|
|
<option value="chemistry">Chemistry</option>
|
|
<option value="hematology">Hematology</option>
|
|
<option value="microbiology">Microbiology</option>
|
|
<option value="immunology">Immunology</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Control Material</label>
|
|
<input type="text" name="control_material" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Control Level</label>
|
|
<select name="control_level" class="form-select" required>
|
|
<option value="">Select Level</option>
|
|
<option value="level_1">Level 1 (Low)</option>
|
|
<option value="level_2">Level 2 (Normal)</option>
|
|
<option value="level_3">Level 3 (High)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Control Lot</label>
|
|
<input type="text" name="control_lot" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Target Value</label>
|
|
<input type="number" step="0.01" name="target_value" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Observed Value</label>
|
|
<input type="number" step="0.01" name="observed_value" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="mb-3">
|
|
<label class="form-label">Unit</label>
|
|
<input type="text" name="unit" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Comments</label>
|
|
<textarea name="comments" class="form-control" rows="3"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Add QC Test</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// QC Trends Chart
|
|
const ctx = document.getElementById('qcTrendsChart').getContext('2d');
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
|
|
datasets: [{
|
|
label: 'Pass Rate %',
|
|
data: [95, 97, 94, 96, 98, 95],
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
max: 100
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|