1076 lines
49 KiB
HTML
1076 lines
49 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static %}
|
|
|
|
{% block title %}Radiology Workflow - Radiology{% 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>Radiology Workflow Management</h4>
|
|
<h6>Monitor and manage the complete radiology workflow from order to report</h6>
|
|
</div>
|
|
<div class="page-btn">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-primary" onclick="refreshWorkflow()">
|
|
<i class="fa fa-sync"></i> Refresh
|
|
</button>
|
|
<button type="button" class="btn btn-info" onclick="optimizeWorkflow()">
|
|
<i class="fa fa-cogs"></i> Optimize
|
|
</button>
|
|
<button type="button" class="btn btn-success" onclick="generateWorkflowReport()">
|
|
<i class="fa fa-chart-bar"></i> Analytics
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Workflow Overview -->
|
|
<div class="row">
|
|
<div class="col-xl-2 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-file-medical"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ workflow_stats.ordered|default:28 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Ordered</h6>
|
|
<small class="text-primary">
|
|
<i class="fa fa-clock"></i> Avg: 15 min
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-2 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-calendar-check"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ workflow_stats.scheduled|default:24 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Scheduled</h6>
|
|
<small class="text-info">
|
|
<i class="fa fa-clock"></i> Avg: 45 min
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-2 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-camera"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ workflow_stats.imaging|default:12 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Imaging</h6>
|
|
<small class="text-warning">
|
|
<i class="fa fa-clock"></i> Avg: 25 min
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-2 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-secondary border-secondary">
|
|
<i class="fa fa-search"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ workflow_stats.reading|default:18 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Reading</h6>
|
|
<small class="text-secondary">
|
|
<i class="fa fa-clock"></i> Avg: 35 min
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-2 col-sm-6 col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="dash-widget-header">
|
|
<span class="dash-widget-icon text-dark border-dark">
|
|
<i class="fa fa-file-alt"></i>
|
|
</span>
|
|
<div class="dash-count">
|
|
<h3>{{ workflow_stats.reporting|default:8 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Reporting</h6>
|
|
<small class="text-dark">
|
|
<i class="fa fa-clock"></i> Avg: 20 min
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-2 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>{{ workflow_stats.completed|default:156 }}</h3>
|
|
</div>
|
|
</div>
|
|
<div class="dash-widget-info">
|
|
<h6 class="text-muted">Completed</h6>
|
|
<small class="text-success">
|
|
<i class="fa fa-arrow-up"></i> +12% today
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Workflow Pipeline -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Workflow Pipeline</h5>
|
|
<div class="card-tools">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-sm btn-outline-primary active" data-view="kanban" onclick="switchView('kanban')">
|
|
<i class="fa fa-columns"></i> Kanban
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-primary" data-view="timeline" onclick="switchView('timeline')">
|
|
<i class="fa fa-chart-line"></i> Timeline
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-primary" data-view="table" onclick="switchView('table')">
|
|
<i class="fa fa-table"></i> Table
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="card-body">
|
|
<!-- Kanban View -->
|
|
<div id="kanbanView" class="workflow-view">
|
|
<div class="kanban-board">
|
|
<div class="row">
|
|
<div class="col-md-2">
|
|
<div class="kanban-column ordered">
|
|
<div class="column-header">
|
|
<h6>Ordered</h6>
|
|
<span class="badge bg-primary">{{ workflow_stats.ordered|default:28 }}</span>
|
|
</div>
|
|
<div class="column-content" id="orderedColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-001">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-001</strong>
|
|
<span class="badge bg-danger">STAT</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>John Smith</strong></p>
|
|
<p>CT Chest</p>
|
|
<small class="text-muted">Ordered: 14:30</small>
|
|
</div>
|
|
</div>
|
|
<div class="workflow-item" draggable="true" data-id="RAD-002">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-002</strong>
|
|
<span class="badge bg-warning">Urgent</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>Mary Wilson</strong></p>
|
|
<p>X-Ray Knee</p>
|
|
<small class="text-muted">Ordered: 14:15</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="kanban-column scheduled">
|
|
<div class="column-header">
|
|
<h6>Scheduled</h6>
|
|
<span class="badge bg-info">{{ workflow_stats.scheduled|default:24 }}</span>
|
|
</div>
|
|
<div class="column-content" id="scheduledColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-003">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-003</strong>
|
|
<span class="badge bg-success">Routine</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>Robert Davis</strong></p>
|
|
<p>MRI Brain</p>
|
|
<small class="text-muted">Scheduled: 15:30</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="kanban-column imaging">
|
|
<div class="column-header">
|
|
<h6>Imaging</h6>
|
|
<span class="badge bg-warning">{{ workflow_stats.imaging|default:12 }}</span>
|
|
</div>
|
|
<div class="column-content" id="imagingColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-004">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-004</strong>
|
|
<span class="badge bg-warning">Urgent</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>Lisa Anderson</strong></p>
|
|
<p>Ultrasound Abdomen</p>
|
|
<small class="text-muted">Started: 15:00</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="kanban-column reading">
|
|
<div class="column-header">
|
|
<h6>Reading</h6>
|
|
<span class="badge bg-secondary">{{ workflow_stats.reading|default:18 }}</span>
|
|
</div>
|
|
<div class="column-content" id="readingColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-005">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-005</strong>
|
|
<span class="badge bg-success">Routine</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>Michael Brown</strong></p>
|
|
<p>CT Abdomen</p>
|
|
<small class="text-muted">Reading: Dr. Smith</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="kanban-column reporting">
|
|
<div class="column-header">
|
|
<h6>Reporting</h6>
|
|
<span class="badge bg-dark">{{ workflow_stats.reporting|default:8 }}</span>
|
|
</div>
|
|
<div class="column-content" id="reportingColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-006">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-006</strong>
|
|
<span class="badge bg-success">Routine</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>Sarah Johnson</strong></p>
|
|
<p>X-Ray Chest</p>
|
|
<small class="text-muted">Reporting: Dr. Wilson</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="kanban-column completed">
|
|
<div class="column-header">
|
|
<h6>Completed</h6>
|
|
<span class="badge bg-success">{{ workflow_stats.completed|default:156 }}</span>
|
|
</div>
|
|
<div class="column-content" id="completedColumn">
|
|
<div class="workflow-item" draggable="true" data-id="RAD-007">
|
|
<div class="item-header">
|
|
<strong>RAD-2024-007</strong>
|
|
<span class="badge bg-success">Routine</span>
|
|
</div>
|
|
<div class="item-content">
|
|
<p><strong>David Wilson</strong></p>
|
|
<p>CT Head</p>
|
|
<small class="text-muted">Completed: 14:45</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timeline View -->
|
|
<div id="timelineView" class="workflow-view" style="display: none;">
|
|
<div class="timeline-container">
|
|
<div class="timeline-header">
|
|
<div class="row">
|
|
<div class="col-md-2"><strong>Time</strong></div>
|
|
<div class="col-md-2"><strong>Patient</strong></div>
|
|
<div class="col-md-2"><strong>Study</strong></div>
|
|
<div class="col-md-2"><strong>Status</strong></div>
|
|
<div class="col-md-2"><strong>Assigned To</strong></div>
|
|
<div class="col-md-2"><strong>Duration</strong></div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-content">
|
|
<div class="timeline-item">
|
|
<div class="row">
|
|
<div class="col-md-2">14:30</div>
|
|
<div class="col-md-2">John Smith</div>
|
|
<div class="col-md-2">CT Chest</div>
|
|
<div class="col-md-2"><span class="badge bg-primary">Ordered</span></div>
|
|
<div class="col-md-2">-</div>
|
|
<div class="col-md-2">-</div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="row">
|
|
<div class="col-md-2">15:00</div>
|
|
<div class="col-md-2">Lisa Anderson</div>
|
|
<div class="col-md-2">Ultrasound</div>
|
|
<div class="col-md-2"><span class="badge bg-warning">Imaging</span></div>
|
|
<div class="col-md-2">Tech Johnson</div>
|
|
<div class="col-md-2">25 min</div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-item">
|
|
<div class="row">
|
|
<div class="col-md-2">15:15</div>
|
|
<div class="col-md-2">Michael Brown</div>
|
|
<div class="col-md-2">CT Abdomen</div>
|
|
<div class="col-md-2"><span class="badge bg-secondary">Reading</span></div>
|
|
<div class="col-md-2">Dr. Smith</div>
|
|
<div class="col-md-2">35 min</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Table View -->
|
|
<div id="tableView" class="workflow-view" style="display: none;">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Order ID</th>
|
|
<th>Patient</th>
|
|
<th>Study Type</th>
|
|
<th>Priority</th>
|
|
<th>Status</th>
|
|
<th>Assigned To</th>
|
|
<th>Duration</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>RAD-2024-001</strong></td>
|
|
<td>John Smith</td>
|
|
<td>CT Chest</td>
|
|
<td><span class="badge bg-danger">STAT</span></td>
|
|
<td><span class="badge bg-primary">Ordered</span></td>
|
|
<td>-</td>
|
|
<td>15 min</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="viewWorkflowItem('RAD-2024-001')">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>RAD-2024-004</strong></td>
|
|
<td>Lisa Anderson</td>
|
|
<td>Ultrasound Abdomen</td>
|
|
<td><span class="badge bg-warning">Urgent</span></td>
|
|
<td><span class="badge bg-warning">Imaging</span></td>
|
|
<td>Tech Johnson</td>
|
|
<td>25 min</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="viewWorkflowItem('RAD-2024-004')">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>RAD-2024-005</strong></td>
|
|
<td>Michael Brown</td>
|
|
<td>CT Abdomen</td>
|
|
<td><span class="badge bg-success">Routine</span></td>
|
|
<td><span class="badge bg-secondary">Reading</span></td>
|
|
<td>Dr. Smith</td>
|
|
<td>35 min</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="viewWorkflowItem('RAD-2024-005')">
|
|
<i class="fa fa-eye"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Performance Metrics -->
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Workflow Performance</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="workflowChart" height="300"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Bottleneck Analysis</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="bottleneck-item mb-3">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h6>Reading Queue</h6>
|
|
<small class="text-muted">18 studies waiting</small>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge bg-danger">High</span><br>
|
|
<small class="text-muted">Avg: 45 min</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bottleneck-item mb-3">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h6>CT Scanner 2</h6>
|
|
<small class="text-muted">Equipment utilization</small>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge bg-warning">Medium</span><br>
|
|
<small class="text-muted">95% busy</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bottleneck-item">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h6>Reporting</h6>
|
|
<small class="text-muted">8 reports pending</small>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge bg-success">Low</span><br>
|
|
<small class="text-muted">Avg: 20 min</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Staff Workload -->
|
|
<div class="card mt-3">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Staff Workload</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="staff-item mb-2">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Dr. Smith (Radiologist)</span>
|
|
<span class="badge bg-warning">8 studies</span>
|
|
</div>
|
|
<div class="progress mt-1" style="height: 6px;">
|
|
<div class="progress-bar bg-warning" style="width: 80%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="staff-item mb-2">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Dr. Wilson (Radiologist)</span>
|
|
<span class="badge bg-info">5 studies</span>
|
|
</div>
|
|
<div class="progress mt-1" style="height: 6px;">
|
|
<div class="progress-bar bg-info" style="width: 50%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="staff-item mb-2">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Tech Johnson (CT)</span>
|
|
<span class="badge bg-success">3 studies</span>
|
|
</div>
|
|
<div class="progress mt-1" style="height: 6px;">
|
|
<div class="progress-bar bg-success" style="width: 30%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="staff-item">
|
|
<div class="d-flex justify-content-between">
|
|
<span>Tech Davis (MRI)</span>
|
|
<span class="badge bg-primary">2 studies</span>
|
|
</div>
|
|
<div class="progress mt-1" style="height: 6px;">
|
|
<div class="progress-bar bg-primary" style="width: 20%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Equipment Status -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Equipment Status & Utilization</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="equipment-card">
|
|
<div class="equipment-header">
|
|
<h6>CT Scanner 1</h6>
|
|
<span class="badge bg-success">Online</span>
|
|
</div>
|
|
<div class="equipment-stats">
|
|
<div class="stat-item">
|
|
<span class="stat-label">Utilization:</span>
|
|
<span class="stat-value">85%</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Queue:</span>
|
|
<span class="stat-value">4 studies</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Next Available:</span>
|
|
<span class="stat-value">16:30</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="equipment-card">
|
|
<div class="equipment-header">
|
|
<h6>CT Scanner 2</h6>
|
|
<span class="badge bg-warning">Busy</span>
|
|
</div>
|
|
<div class="equipment-stats">
|
|
<div class="stat-item">
|
|
<span class="stat-label">Utilization:</span>
|
|
<span class="stat-value">95%</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Queue:</span>
|
|
<span class="stat-value">7 studies</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Next Available:</span>
|
|
<span class="stat-value">17:15</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="equipment-card">
|
|
<div class="equipment-header">
|
|
<h6>MRI Scanner</h6>
|
|
<span class="badge bg-success">Online</span>
|
|
</div>
|
|
<div class="equipment-stats">
|
|
<div class="stat-item">
|
|
<span class="stat-label">Utilization:</span>
|
|
<span class="stat-value">70%</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Queue:</span>
|
|
<span class="stat-value">2 studies</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Next Available:</span>
|
|
<span class="stat-value">16:00</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="equipment-card">
|
|
<div class="equipment-header">
|
|
<h6>X-Ray Room 1</h6>
|
|
<span class="badge bg-success">Online</span>
|
|
</div>
|
|
<div class="equipment-stats">
|
|
<div class="stat-item">
|
|
<span class="stat-label">Utilization:</span>
|
|
<span class="stat-value">60%</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Queue:</span>
|
|
<span class="stat-value">1 study</span>
|
|
</div>
|
|
<div class="stat-item">
|
|
<span class="stat-label">Next Available:</span>
|
|
<span class="stat-value">15:45</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Alerts and Notifications -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title">Workflow Alerts</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="alert alert-warning" role="alert">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<i class="fa fa-exclamation-triangle"></i>
|
|
<strong>High Priority Queue:</strong> 3 STAT orders waiting for more than 30 minutes
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-warning" onclick="handleAlert('stat_queue')">
|
|
<i class="fa fa-cog"></i> Manage
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="alert alert-info" role="alert">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<i class="fa fa-info-circle"></i>
|
|
<strong>Equipment Maintenance:</strong> CT Scanner 2 scheduled for maintenance at 18:00
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-info" onclick="handleAlert('maintenance')">
|
|
<i class="fa fa-calendar"></i> Reschedule
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="alert alert-success" role="alert">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<i class="fa fa-check-circle"></i>
|
|
<strong>Performance Goal:</strong> Average turnaround time improved by 15% this week
|
|
</div>
|
|
<button class="btn btn-sm btn-outline-success" onclick="handleAlert('performance')">
|
|
<i class="fa fa-chart-bar"></i> View Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
let currentView = 'kanban';
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeWorkflowChart();
|
|
setupDragAndDrop();
|
|
|
|
// Auto-refresh every 30 seconds
|
|
setInterval(refreshWorkflow, 30000);
|
|
});
|
|
|
|
function initializeWorkflowChart() {
|
|
const ctx = document.getElementById('workflowChart').getContext('2d');
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['8:00', '10:00', '12:00', '14:00', '16:00', '18:00'],
|
|
datasets: [{
|
|
label: 'Studies Completed',
|
|
data: [12, 28, 45, 67, 89, 112],
|
|
borderColor: '#28a745',
|
|
backgroundColor: 'rgba(40, 167, 69, 0.1)',
|
|
tension: 0.4
|
|
}, {
|
|
label: 'Average Turnaround (min)',
|
|
data: [95, 88, 82, 78, 75, 72],
|
|
borderColor: '#007bff',
|
|
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
|
tension: 0.4,
|
|
yAxisID: 'y1'
|
|
}, {
|
|
label: 'Queue Length',
|
|
data: [15, 22, 18, 25, 20, 16],
|
|
borderColor: '#ffc107',
|
|
backgroundColor: 'rgba(255, 193, 7, 0.1)',
|
|
tension: 0.4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
type: 'linear',
|
|
display: true,
|
|
position: 'left',
|
|
},
|
|
y1: {
|
|
type: 'linear',
|
|
display: true,
|
|
position: 'right',
|
|
grid: {
|
|
drawOnChartArea: false,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function setupDragAndDrop() {
|
|
const workflowItems = document.querySelectorAll('.workflow-item');
|
|
const columns = document.querySelectorAll('.column-content');
|
|
|
|
workflowItems.forEach(item => {
|
|
item.addEventListener('dragstart', handleDragStart);
|
|
item.addEventListener('dragend', handleDragEnd);
|
|
});
|
|
|
|
columns.forEach(column => {
|
|
column.addEventListener('dragover', handleDragOver);
|
|
column.addEventListener('drop', handleDrop);
|
|
});
|
|
}
|
|
|
|
function handleDragStart(e) {
|
|
e.dataTransfer.setData('text/plain', e.target.dataset.id);
|
|
e.target.style.opacity = '0.5';
|
|
}
|
|
|
|
function handleDragEnd(e) {
|
|
e.target.style.opacity = '1';
|
|
}
|
|
|
|
function handleDragOver(e) {
|
|
e.preventDefault();
|
|
}
|
|
|
|
function handleDrop(e) {
|
|
e.preventDefault();
|
|
const itemId = e.dataTransfer.getData('text/plain');
|
|
const item = document.querySelector(`[data-id="${itemId}"]`);
|
|
const targetColumn = e.target.closest('.column-content');
|
|
|
|
if (targetColumn && item) {
|
|
targetColumn.appendChild(item);
|
|
updateWorkflowStatus(itemId, getColumnStatus(targetColumn.id));
|
|
}
|
|
}
|
|
|
|
function getColumnStatus(columnId) {
|
|
const statusMap = {
|
|
'orderedColumn': 'ordered',
|
|
'scheduledColumn': 'scheduled',
|
|
'imagingColumn': 'imaging',
|
|
'readingColumn': 'reading',
|
|
'reportingColumn': 'reporting',
|
|
'completedColumn': 'completed'
|
|
};
|
|
return statusMap[columnId] || 'unknown';
|
|
}
|
|
|
|
function updateWorkflowStatus(itemId, newStatus) {
|
|
console.log(`Updated ${itemId} status to: ${newStatus}`);
|
|
// In real implementation, this would update the database
|
|
}
|
|
|
|
function switchView(view) {
|
|
// Hide all views
|
|
document.querySelectorAll('.workflow-view').forEach(el => {
|
|
el.style.display = 'none';
|
|
});
|
|
|
|
// Show selected view
|
|
document.getElementById(view + 'View').style.display = 'block';
|
|
|
|
// Update active button
|
|
document.querySelectorAll('[data-view]').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
document.querySelector(`[data-view="${view}"]`).classList.add('active');
|
|
|
|
currentView = view;
|
|
console.log(`Switched to ${view} view`);
|
|
}
|
|
|
|
function viewWorkflowItem(itemId) {
|
|
console.log(`Viewing workflow item: ${itemId}`);
|
|
alert(`Detailed workflow information for ${itemId} would be displayed here.`);
|
|
}
|
|
|
|
function refreshWorkflow() {
|
|
console.log('Refreshing workflow data...');
|
|
|
|
// Simulate data refresh
|
|
const stats = document.querySelectorAll('.dash-count h3');
|
|
stats.forEach(stat => {
|
|
const currentValue = parseInt(stat.textContent);
|
|
const change = Math.floor(Math.random() * 5) - 2; // Random change -2 to +2
|
|
stat.textContent = Math.max(0, currentValue + change);
|
|
});
|
|
|
|
console.log('Workflow data refreshed');
|
|
}
|
|
|
|
function optimizeWorkflow() {
|
|
console.log('Optimizing workflow...');
|
|
|
|
const optimizations = [
|
|
'Redistributed reading queue to balance radiologist workload',
|
|
'Rescheduled non-urgent studies to optimize equipment utilization',
|
|
'Prioritized STAT orders in imaging queue',
|
|
'Allocated additional staff to bottleneck areas'
|
|
];
|
|
|
|
const optimization = optimizations[Math.floor(Math.random() * optimizations.length)];
|
|
alert(`Workflow optimization applied: ${optimization}`);
|
|
}
|
|
|
|
function generateWorkflowReport() {
|
|
const reportType = prompt('Generate workflow report:\n1. Performance Summary\n2. Bottleneck Analysis\n3. Staff Productivity\n4. Equipment Utilization\n\nEnter number:');
|
|
|
|
if (reportType && ['1', '2', '3', '4'].includes(reportType)) {
|
|
const reportTypes = {
|
|
'1': 'Performance Summary',
|
|
'2': 'Bottleneck Analysis',
|
|
'3': 'Staff Productivity',
|
|
'4': 'Equipment Utilization'
|
|
};
|
|
|
|
console.log(`Generating report: ${reportTypes[reportType]}`);
|
|
alert(`${reportTypes[reportType]} report is being generated. You will receive an email when ready.`);
|
|
}
|
|
}
|
|
|
|
function handleAlert(alertType) {
|
|
const actions = {
|
|
'stat_queue': 'STAT queue management interface would open here.',
|
|
'maintenance': 'Equipment maintenance scheduling would open here.',
|
|
'performance': 'Detailed performance analytics would be displayed here.'
|
|
};
|
|
|
|
console.log(`Handling alert: ${alertType}`);
|
|
alert(actions[alertType] || 'Alert management interface would open here.');
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.dash-widget-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.dash-widget-icon {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.2rem;
|
|
margin-right: 1rem;
|
|
border: 2px solid;
|
|
}
|
|
|
|
.dash-count h3 {
|
|
margin: 0;
|
|
font-size: 1.8rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.kanban-board {
|
|
min-height: 500px;
|
|
}
|
|
|
|
.kanban-column {
|
|
background-color: #f8f9fa;
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
min-height: 450px;
|
|
}
|
|
|
|
.column-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 2px solid #dee2e6;
|
|
}
|
|
|
|
.column-header h6 {
|
|
margin: 0;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.column-content {
|
|
min-height: 350px;
|
|
}
|
|
|
|
.workflow-item {
|
|
background-color: white;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 6px;
|
|
padding: 0.75rem;
|
|
margin-bottom: 0.75rem;
|
|
cursor: move;
|
|
transition: all 0.2s;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
|
|
.workflow-item:hover {
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.item-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.item-content p {
|
|
margin-bottom: 0.25rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.timeline-container {
|
|
background-color: #f8f9fa;
|
|
border-radius: 6px;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.timeline-header {
|
|
background-color: #e9ecef;
|
|
padding: 0.75rem;
|
|
border-radius: 4px;
|
|
margin-bottom: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.timeline-item {
|
|
background-color: white;
|
|
padding: 0.75rem;
|
|
margin-bottom: 0.5rem;
|
|
border-radius: 4px;
|
|
border-left: 4px solid #007bff;
|
|
}
|
|
|
|
.bottleneck-item {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 6px;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.staff-item {
|
|
padding: 0.5rem 0;
|
|
}
|
|
|
|
.equipment-card {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
padding: 1rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.equipment-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 1rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
|
|
.equipment-header h6 {
|
|
margin: 0;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.equipment-stats {
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.stat-item {
|
|
display: flex;
|
|
justify-content: between;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.stat-label {
|
|
color: #6c757d;
|
|
}
|
|
|
|
.stat-value {
|
|
font-weight: 600;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.dash-widget-header {
|
|
flex-direction: column;
|
|
text-align: center;
|
|
}
|
|
|
|
.dash-widget-icon {
|
|
margin-right: 0;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.kanban-column {
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.timeline-header .row,
|
|
.timeline-item .row {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.equipment-card {
|
|
margin-bottom: 2rem;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|