416 lines
22 KiB
HTML
416 lines
22 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Batch Processing - 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>Laboratory Batch Processing</h4>
|
|
<h6>Manage and process laboratory test batches efficiently</h6>
|
|
</div>
|
|
<div class="page-btn">
|
|
<a href="#" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createBatchModal">
|
|
<i class="fa fa-plus"></i> Create New Batch
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Batch 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-flask"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ batch_stats.active_batches|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Active Batches</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-clock"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ batch_stats.pending_samples|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Pending Samples</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-check-circle"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ batch_stats.completed_today|default:0 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Completed 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-percentage"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ batch_stats.efficiency_rate|default:0 }}%</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Processing Efficiency</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Batch Filters -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Batch 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">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All Status</option>
|
|
<option value="pending">Pending</option>
|
|
<option value="in_progress">In Progress</option>
|
|
<option value="completed">Completed</option>
|
|
<option value="cancelled">Cancelled</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Priority</label>
|
|
<select name="priority" class="form-select">
|
|
<option value="">All Priorities</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="high">High</option>
|
|
<option value="normal">Normal</option>
|
|
<option value="low">Low</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Date From</label>
|
|
<input type="date" name="date_from" class="form-control">
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label">Date To</label>
|
|
<input type="date" name="date_to" class="form-control">
|
|
</div>
|
|
<div class="col-12">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fa fa-search"></i> Filter
|
|
</button>
|
|
<a href="{% url 'laboratory:batch_processing' %}" class="btn btn-secondary">
|
|
<i class="fa fa-refresh"></i> Reset
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Active Batches -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Laboratory Batches</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Batch ID</th>
|
|
<th>Test Type</th>
|
|
<th>Sample Count</th>
|
|
<th>Priority</th>
|
|
<th>Status</th>
|
|
<th>Created By</th>
|
|
<th>Created Date</th>
|
|
<th>Progress</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for batch in batches %}
|
|
<tr>
|
|
<td>
|
|
<a href="#" class="text-primary">{{ batch.batch_id }}</a>
|
|
</td>
|
|
<td>{{ batch.test_type|title }}</td>
|
|
<td>
|
|
<span class="badge bg-info">{{ batch.sample_count }} samples</span>
|
|
</td>
|
|
<td>
|
|
{% if batch.priority == 'urgent' %}
|
|
<span class="badge bg-danger">Urgent</span>
|
|
{% elif batch.priority == 'high' %}
|
|
<span class="badge bg-warning">High</span>
|
|
{% elif batch.priority == 'normal' %}
|
|
<span class="badge bg-primary">Normal</span>
|
|
{% else %}
|
|
<span class="badge bg-secondary">Low</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if batch.status == 'pending' %}
|
|
<span class="badge bg-warning">Pending</span>
|
|
{% elif batch.status == 'in_progress' %}
|
|
<span class="badge bg-info">In Progress</span>
|
|
{% elif batch.status == 'completed' %}
|
|
<span class="badge bg-success">Completed</span>
|
|
{% else %}
|
|
<span class="badge bg-danger">Cancelled</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>{{ batch.created_by.get_full_name|default:batch.created_by.username }}</td>
|
|
<td>{{ batch.created_at|date:"M d, Y H:i" }}</td>
|
|
<td>
|
|
<div class="progress" style="height: 20px;">
|
|
<div class="progress-bar" role="progressbar"
|
|
style="width: {{ batch.progress_percentage }}%"
|
|
aria-valuenow="{{ batch.progress_percentage }}"
|
|
aria-valuemin="0" aria-valuemax="100">
|
|
{{ batch.progress_percentage }}%
|
|
</div>
|
|
</div>
|
|
</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 batch.status == 'pending' %}
|
|
<a href="#" class="btn btn-sm btn-outline-success" title="Start Processing">
|
|
<i class="fa fa-play"></i>
|
|
</a>
|
|
{% endif %}
|
|
{% if batch.status == 'in_progress' %}
|
|
<a href="#" class="btn btn-sm btn-outline-warning" title="Pause">
|
|
<i class="fa fa-pause"></i>
|
|
</a>
|
|
{% endif %}
|
|
<a href="#" class="btn btn-sm btn-outline-info" title="Edit">
|
|
<i class="fa fa-edit"></i>
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="9" class="text-center">No batches found</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Batch Processing Queue -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Processing Queue</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
{% for queue_item in processing_queue %}
|
|
<div class="col-md-6 col-lg-4">
|
|
<div class="card border-left-primary">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<h6 class="card-title">{{ queue_item.batch_id }}</h6>
|
|
<p class="card-text">{{ queue_item.test_type|title }}</p>
|
|
<small class="text-muted">{{ queue_item.sample_count }} samples</small>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge bg-{{ queue_item.priority_color }}">
|
|
{{ queue_item.priority|title }}
|
|
</span>
|
|
<br>
|
|
<small class="text-muted">ETA: {{ queue_item.estimated_completion }}</small>
|
|
</div>
|
|
</div>
|
|
<div class="mt-3">
|
|
<div class="progress" style="height: 5px;">
|
|
<div class="progress-bar bg-{{ queue_item.priority_color }}"
|
|
style="width: {{ queue_item.progress }}%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="col-12">
|
|
<div class="text-center text-muted">
|
|
<i class="fa fa-inbox fa-3x mb-3"></i>
|
|
<p>No items in processing queue</p>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Create Batch Modal -->
|
|
<div class="modal fade" id="createBatchModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Create New Batch</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">Batch Name</label>
|
|
<input type="text" name="batch_name" class="form-control" required>
|
|
</div>
|
|
</div>
|
|
<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">Priority</label>
|
|
<select name="priority" class="form-select" required>
|
|
<option value="normal">Normal</option>
|
|
<option value="high">High</option>
|
|
<option value="urgent">Urgent</option>
|
|
<option value="low">Low</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-3">
|
|
<label class="form-label">Expected Completion</label>
|
|
<input type="datetime-local" name="expected_completion" class="form-control">
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Sample Selection</label>
|
|
<div class="border rounded p-3" style="max-height: 200px; overflow-y: auto;">
|
|
{% for sample in available_samples %}
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox"
|
|
name="selected_samples" value="{{ sample.id }}"
|
|
id="sample_{{ sample.id }}">
|
|
<label class="form-check-label" for="sample_{{ sample.id }}">
|
|
{{ sample.specimen_id }} - {{ sample.patient_name }} ({{ sample.test_type }})
|
|
</label>
|
|
</div>
|
|
{% empty %}
|
|
<p class="text-muted">No available samples</p>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12">
|
|
<div class="mb-3">
|
|
<label class="form-label">Notes</label>
|
|
<textarea name="notes" 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">Create Batch</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Auto-refresh processing queue every 30 seconds
|
|
setInterval(function() {
|
|
location.reload();
|
|
}, 30000);
|
|
|
|
// Sample selection counter
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const checkboxes = document.querySelectorAll('input[name="selected_samples"]');
|
|
const updateCounter = () => {
|
|
const selected = document.querySelectorAll('input[name="selected_samples"]:checked').length;
|
|
console.log(`Selected samples: ${selected}`);
|
|
};
|
|
|
|
checkboxes.forEach(checkbox => {
|
|
checkbox.addEventListener('change', updateCounter);
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|