2025-08-12 13:33:25 +03:00

570 lines
26 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Lab Workflow - 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 Workflow Management</h4>
<h6>Monitor and manage laboratory workflow processes</h6>
</div>
<div class="page-btn">
<a href="#" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#workflowConfigModal">
<i class="fa fa-cog"></i> Configure Workflow
</a>
</div>
</div>
</div>
</div>
<!-- Workflow Overview 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-inbox"></i>
</span>
<div class="dash-count">
<h3>{{ workflow_stats.pending_orders|default:0 }}</h3>
</div>
</div>
<div class="dash-widget-info">
<h6 class="text-muted">Pending Orders</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-flask"></i>
</span>
<div class="dash-count">
<h3>{{ workflow_stats.in_process|default:0 }}</h3>
</div>
</div>
<div class="dash-widget-info">
<h6 class="text-muted">In Process</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-check-circle"></i>
</span>
<div class="dash-count">
<h3>{{ workflow_stats.ready_for_review|default:0 }}</h3>
</div>
</div>
<div class="dash-widget-info">
<h6 class="text-muted">Ready for Review</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-file-text"></i>
</span>
<div class="dash-count">
<h3>{{ workflow_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>
<!-- Workflow Stages -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Workflow Stages</h5>
</div>
<div class="card-body">
<div class="workflow-container">
<div class="row">
<!-- Order Received -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-primary text-white">
<i class="fa fa-inbox"></i>
<h6>Order Received</h6>
<span class="badge bg-light text-dark">{{ stage_counts.order_received|default:0 }}</span>
</div>
<div class="stage-content">
{% for item in order_received_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-{{ item.priority_color }}">{{ item.priority }}</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Specimen Collection -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-warning text-white">
<i class="fa fa-vial"></i>
<h6>Collection</h6>
<span class="badge bg-light text-dark">{{ stage_counts.collection|default:0 }}</span>
</div>
<div class="stage-content" data-stage="collection">
{% for item in collection_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-{{ item.priority_color }}">{{ item.priority }}</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Processing -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-info text-white">
<i class="fa fa-cogs"></i>
<h6>Processing</h6>
<span class="badge bg-light text-dark">{{ stage_counts.processing|default:0 }}</span>
</div>
<div class="stage-content" data-stage="processing">
{% for item in processing_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-{{ item.priority_color }}">{{ item.priority }}</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
<div class="progress mt-1" style="height: 4px;">
<div class="progress-bar" style="width: {{ item.progress }}%"></div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Quality Control -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-secondary text-white">
<i class="fa fa-shield-alt"></i>
<h6>Quality Control</h6>
<span class="badge bg-light text-dark">{{ stage_counts.qc|default:0 }}</span>
</div>
<div class="stage-content" data-stage="qc">
{% for item in qc_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-{{ item.priority_color }}">{{ item.priority }}</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Review -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-dark text-white">
<i class="fa fa-eye"></i>
<h6>Review</h6>
<span class="badge bg-light text-dark">{{ stage_counts.review|default:0 }}</span>
</div>
<div class="stage-content" data-stage="review">
{% for item in review_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-{{ item.priority_color }}">{{ item.priority }}</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Completed -->
<div class="col-md-2">
<div class="workflow-stage">
<div class="stage-header bg-success text-white">
<i class="fa fa-check"></i>
<h6>Completed</h6>
<span class="badge bg-light text-dark">{{ stage_counts.completed|default:0 }}</span>
</div>
<div class="stage-content" data-stage="completed">
{% for item in completed_items %}
<div class="workflow-item" draggable="true" data-id="{{ item.id }}">
<div class="item-header">
<strong>{{ item.order_id }}</strong>
<span class="badge bg-success">Done</span>
</div>
<div class="item-details">
<small>{{ item.patient_name }}</small><br>
<small>{{ item.test_type }}</small>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Workflow Analytics -->
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Workflow Performance</h5>
</div>
<div class="card-body">
<canvas id="workflowChart" height="200"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Turnaround Time</h5>
</div>
<div class="card-body">
<canvas id="turnaroundChart" height="200"></canvas>
</div>
</div>
</div>
</div>
<!-- Recent Activity -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Recent Workflow Activity</h5>
</div>
<div class="card-body">
<div class="activity-timeline">
{% for activity in recent_activities %}
<div class="activity-item">
<div class="activity-icon bg-{{ activity.type_color }}">
<i class="fa fa-{{ activity.icon }}"></i>
</div>
<div class="activity-content">
<h6>{{ activity.title }}</h6>
<p>{{ activity.description }}</p>
<small class="text-muted">{{ activity.timestamp|timesince }} ago by {{ activity.user }}</small>
</div>
</div>
{% empty %}
<div class="text-center text-muted">
<i class="fa fa-clock fa-2x mb-3"></i>
<p>No recent activity</p>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Workflow Configuration Modal -->
<div class="modal fade" id="workflowConfigModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Workflow Configuration</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-12">
<h6>Stage Configuration</h6>
<div class="table-responsive">
<table class="table table-sm">
<thead>
<tr>
<th>Stage</th>
<th>Auto-Advance</th>
<th>SLA (Hours)</th>
<th>Required Role</th>
</tr>
</thead>
<tbody>
<tr>
<td>Order Received</td>
<td><input type="checkbox" name="auto_advance_order" class="form-check-input"></td>
<td><input type="number" name="sla_order" class="form-control form-control-sm" value="1"></td>
<td>
<select name="role_order" class="form-select form-select-sm">
<option>Lab Clerk</option>
<option>Lab Technician</option>
</select>
</td>
</tr>
<tr>
<td>Collection</td>
<td><input type="checkbox" name="auto_advance_collection" class="form-check-input"></td>
<td><input type="number" name="sla_collection" class="form-control form-control-sm" value="2"></td>
<td>
<select name="role_collection" class="form-select form-select-sm">
<option>Phlebotomist</option>
<option>Nurse</option>
</select>
</td>
</tr>
<tr>
<td>Processing</td>
<td><input type="checkbox" name="auto_advance_processing" class="form-check-input"></td>
<td><input type="number" name="sla_processing" class="form-control form-control-sm" value="4"></td>
<td>
<select name="role_processing" class="form-select form-select-sm">
<option>Lab Technician</option>
<option>Medical Technologist</option>
</select>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-12 mt-3">
<h6>Notification Settings</h6>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="notify_sla_breach" id="notifySLA">
<label class="form-check-label" for="notifySLA">
Notify on SLA breach
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="notify_stage_change" id="notifyStage">
<label class="form-check-label" for="notifyStage">
Notify on stage changes
</label>
</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">Save Configuration</button>
</div>
</form>
</div>
</div>
</div>
<style>
.workflow-container {
min-height: 500px;
}
.workflow-stage {
border: 1px solid #dee2e6;
border-radius: 8px;
margin-bottom: 20px;
height: 400px;
}
.stage-header {
padding: 10px;
border-radius: 8px 8px 0 0;
text-align: center;
position: relative;
}
.stage-content {
padding: 10px;
height: 340px;
overflow-y: auto;
}
.workflow-item {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 8px;
margin-bottom: 8px;
cursor: move;
transition: all 0.3s ease;
}
.workflow-item:hover {
background: #e9ecef;
transform: translateY(-2px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.workflow-item.dragging {
opacity: 0.5;
}
.stage-content.drag-over {
background: #e3f2fd;
border: 2px dashed #2196f3;
}
.activity-timeline {
max-height: 400px;
overflow-y: auto;
}
.activity-item {
display: flex;
margin-bottom: 20px;
}
.activity-icon {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
color: white;
}
.activity-content {
flex: 1;
}
</style>
<script>
// Drag and Drop functionality
document.addEventListener('DOMContentLoaded', function() {
const workflowItems = document.querySelectorAll('.workflow-item');
const stageContents = document.querySelectorAll('.stage-content');
workflowItems.forEach(item => {
item.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text/plain', this.dataset.id);
this.classList.add('dragging');
});
item.addEventListener('dragend', function() {
this.classList.remove('dragging');
});
});
stageContents.forEach(stage => {
stage.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('drag-over');
});
stage.addEventListener('dragleave', function() {
this.classList.remove('drag-over');
});
stage.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('drag-over');
const itemId = e.dataTransfer.getData('text/plain');
const newStage = this.dataset.stage;
// Here you would make an AJAX call to update the item's stage
console.log(`Moving item ${itemId} to stage ${newStage}`);
});
});
});
// Charts
const workflowCtx = document.getElementById('workflowChart').getContext('2d');
new Chart(workflowCtx, {
type: 'doughnut',
data: {
labels: ['Pending', 'In Process', 'Review', 'Completed'],
datasets: [{
data: [{{ stage_counts.pending|default:0 }}, {{ stage_counts.processing|default:0 }}, {{ stage_counts.review|default:0 }}, {{ stage_counts.completed|default:0 }}],
backgroundColor: ['#ffc107', '#17a2b8', '#6c757d', '#28a745']
}]
},
options: {
responsive: true,
maintainAspectRatio: false
}
});
const turnaroundCtx = document.getElementById('turnaroundChart').getContext('2d');
new Chart(turnaroundCtx, {
type: 'line',
data: {
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
datasets: [{
label: 'Average TAT (hours)',
data: [4.2, 3.8, 4.1, 3.9, 4.3, 5.1, 4.8],
borderColor: '#007bff',
tension: 0.1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
{% endblock %}