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

461 lines
21 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}Radiology Equipment{% endblock %}
{% block content %}
<div class="d-flex align-items-center mb-3">
<div>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'radiology:dashboard' %}">Radiology</a></li>
<li class="breadcrumb-item active">Equipment</li>
</ol>
<h1 class="page-header mb-0">Radiology Equipment</h1>
</div>
<div class="ms-auto">
<a href="{% url 'radiology:equipment_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add Equipment
</a>
</div>
</div>
<!-- Equipment Status Overview -->
<div class="row mb-4">
<div class="col-xl-3 col-md-6">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-1">{{ operational_count|default:0 }}</h4>
<p class="mb-0">Operational</p>
</div>
<div class="flex-shrink-0">
<i class="fas fa-check-circle fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-warning text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-1">{{ maintenance_count|default:0 }}</h4>
<p class="mb-0">Maintenance</p>
</div>
<div class="flex-shrink-0">
<i class="fas fa-tools fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-danger text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-1">{{ offline_count|default:0 }}</h4>
<p class="mb-0">Offline</p>
</div>
<div class="flex-shrink-0">
<i class="fas fa-exclamation-triangle fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-info text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h4 class="mb-1">{{ total_equipment|default:0 }}</h4>
<p class="mb-0">Total Equipment</p>
</div>
<div class="flex-shrink-0">
<i class="fas fa-x-ray fa-2x opacity-75"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h4 class="card-title">
<i class="fas fa-x-ray me-2"></i>
Equipment Management
</h4>
<div class="card-toolbar">
<button type="button" class="btn btn-sm btn-outline-secondary me-2" data-bs-toggle="modal" data-bs-target="#filterModal">
<i class="fas fa-filter me-1"></i>Filters
</button>
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-primary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-download me-1"></i>Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="?export=csv"><i class="fas fa-file-csv me-2"></i>CSV</a></li>
<li><a class="dropdown-item" href="?export=excel"><i class="fas fa-file-excel me-2"></i>Excel</a></li>
</ul>
</div>
</div>
</div>
<div class="card-body">
<!-- Search and Quick Filters -->
<div class="row mb-3">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text"><i class="fas fa-search"></i></span>
<input type="text" class="form-control" id="searchInput" placeholder="Search equipment...">
</div>
</div>
<div class="col-md-8">
<div class="btn-group" role="group">
<input type="radio" class="btn-check" name="statusFilter" id="all" value="" checked>
<label class="btn btn-outline-secondary btn-sm" for="all">All</label>
<input type="radio" class="btn-check" name="statusFilter" id="operational" value="operational">
<label class="btn btn-outline-success btn-sm" for="operational">Operational</label>
<input type="radio" class="btn-check" name="statusFilter" id="maintenance" value="maintenance">
<label class="btn btn-outline-warning btn-sm" for="maintenance">Maintenance</label>
<input type="radio" class="btn-check" name="statusFilter" id="offline" value="offline">
<label class="btn btn-outline-danger btn-sm" for="offline">Offline</label>
</div>
</div>
</div>
<!-- Equipment Grid -->
<div class="row" id="equipmentGrid">
{% for equipment in object_list %}
<div class="col-xl-4 col-lg-6 mb-4 equipment-card" data-status="{{ equipment.status }}" data-modality="{{ equipment.modality }}">
<div class="card h-100">
<div class="card-header">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<h6 class="card-title mb-0">{{ equipment.name }}</h6>
<small class="text-muted">{{ equipment.get_modality_display }}</small>
</div>
<div class="flex-shrink-0">
<span class="badge bg-{% if equipment.status == 'operational' %}success{% elif equipment.status == 'maintenance' %}warning{% elif equipment.status == 'offline' %}danger{% else %}secondary{% endif %}">
{{ equipment.get_status_display }}
</span>
</div>
</div>
</div>
<div class="card-body">
<div class="row text-center mb-3">
<div class="col-4">
<div class="text-muted small">Location</div>
<div class="fw-bold">{{ equipment.location|default:"N/A" }}</div>
</div>
<div class="col-4">
<div class="text-muted small">Studies Today</div>
<div class="fw-bold">{{ equipment.studies_today|default:0 }}</div>
</div>
<div class="col-4">
<div class="text-muted small">Utilization</div>
<div class="fw-bold">{{ equipment.utilization_rate|default:0 }}%</div>
</div>
</div>
<!-- Equipment Details -->
<div class="mb-3">
<div class="row">
<div class="col-6">
<small class="text-muted">Manufacturer:</small><br>
<strong>{{ equipment.manufacturer|default:"N/A" }}</strong>
</div>
<div class="col-6">
<small class="text-muted">Model:</small><br>
<strong>{{ equipment.model|default:"N/A" }}</strong>
</div>
</div>
</div>
<!-- Status Indicators -->
<div class="mb-3">
<div class="row">
<div class="col-6">
<small class="text-muted">Last Service:</small><br>
<span class="{% if equipment.days_since_service > 90 %}text-warning{% else %}text-success{% endif %}">
{{ equipment.last_service_date|date:"M d, Y"|default:"Never" }}
</span>
</div>
<div class="col-6">
<small class="text-muted">Next Service:</small><br>
<span class="{% if equipment.service_overdue %}text-danger{% elif equipment.service_due_soon %}text-warning{% else %}text-success{% endif %}">
{{ equipment.next_service_date|date:"M d, Y"|default:"Not scheduled" }}
</span>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="d-flex gap-2">
<a href="{% url 'radiology:equipment_detail' equipment.pk %}" class="btn btn-outline-primary btn-sm flex-fill">
<i class="fas fa-eye me-1"></i>View
</a>
<a href="{% url 'radiology:equipment_update' equipment.pk %}" class="btn btn-outline-secondary btn-sm flex-fill">
<i class="fas fa-edit me-1"></i>Edit
</a>
{% if equipment.status == 'operational' %}
<button type="button" class="btn btn-outline-warning btn-sm" onclick="scheduleService({{ equipment.pk }})">
<i class="fas fa-tools me-1"></i>Service
</button>
{% endif %}
</div>
</div>
<div class="card-footer">
<div class="d-flex align-items-center justify-content-between">
<small class="text-muted">
<i class="fas fa-calendar me-1"></i>Installed: {{ equipment.installation_date|date:"M Y"|default:"Unknown" }}
</small>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-info dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" onclick="viewSchedule({{ equipment.pk }})"><i class="fas fa-calendar me-2"></i>View Schedule</a></li>
<li><a class="dropdown-item" href="#" onclick="viewMaintenance({{ equipment.pk }})"><i class="fas fa-wrench me-2"></i>Maintenance Log</a></li>
<li><a class="dropdown-item" href="#" onclick="generateReport({{ equipment.pk }})"><i class="fas fa-chart-bar me-2"></i>Usage Report</a></li>
<li><hr class="dropdown-divider"></li>
{% if equipment.status == 'operational' %}
<li><a class="dropdown-item text-warning" href="#" onclick="takeOffline({{ equipment.pk }})"><i class="fas fa-pause me-2"></i>Take Offline</a></li>
{% elif equipment.status == 'offline' %}
<li><a class="dropdown-item text-success" href="#" onclick="bringOnline({{ equipment.pk }})"><i class="fas fa-play me-2"></i>Bring Online</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
{% empty %}
<div class="col-12">
<div class="text-center py-5">
<i class="fas fa-x-ray fa-3x text-muted mb-3"></i>
<h5 class="text-muted">No Equipment Found</h5>
<p class="text-muted">Add your first piece of radiology equipment to get started.</p>
<a href="{% url 'radiology:equipment_create' %}" class="btn btn-primary">
<i class="fas fa-plus me-2"></i>Add First Equipment
</a>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
{% if is_paginated %}
<nav aria-label="Equipment pagination">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1">&laquo; First</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% endif %}
<li class="page-item active">
<span class="page-link">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
</span>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}">Last &raquo;</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
<!-- Filter Modal -->
<div class="modal fade" id="filterModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Equipment Filters</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="filterForm">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Modality</label>
<select class="form-select" name="modality">
<option value="">All modalities</option>
<option value="xray">X-Ray</option>
<option value="ct">CT Scanner</option>
<option value="mri">MRI</option>
<option value="ultrasound">Ultrasound</option>
<option value="mammography">Mammography</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Location</label>
<select class="form-select" name="location">
<option value="">All locations</option>
{% for location in locations %}
<option value="{{ location }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Manufacturer</label>
<select class="form-select" name="manufacturer">
<option value="">All manufacturers</option>
{% for manufacturer in manufacturers %}
<option value="{{ manufacturer }}">{{ manufacturer }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Service Status</label>
<select class="form-select" name="service_status">
<option value="">All service statuses</option>
<option value="current">Service Current</option>
<option value="due_soon">Service Due Soon</option>
<option value="overdue">Service Overdue</option>
</select>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="applyFilters()">Apply Filters</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Search functionality
const searchInput = document.getElementById('searchInput');
const equipmentCards = document.querySelectorAll('.equipment-card');
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
equipmentCards.forEach(card => {
const text = card.textContent.toLowerCase();
card.style.display = text.includes(searchTerm) ? '' : 'none';
});
});
// Status filter functionality
const statusFilters = document.querySelectorAll('input[name="statusFilter"]');
statusFilters.forEach(filter => {
filter.addEventListener('change', function() {
const status = this.value;
equipmentCards.forEach(card => {
if (!status || card.dataset.status === status) {
card.style.display = '';
} else {
card.style.display = 'none';
}
});
});
});
// Auto-refresh equipment status
setInterval(function() {
updateEquipmentStatus();
}, 60000); // Refresh every minute
});
function scheduleService(equipmentId) {
if (confirm('Schedule maintenance for this equipment?')) {
window.location.href = `/radiology/equipment/${equipmentId}/schedule-service/`;
}
}
function viewSchedule(equipmentId) {
window.open(`/radiology/equipment/${equipmentId}/schedule/`, '_blank');
}
function viewMaintenance(equipmentId) {
window.open(`/radiology/equipment/${equipmentId}/maintenance/`, '_blank');
}
function generateReport(equipmentId) {
window.open(`/radiology/equipment/${equipmentId}/report/`, '_blank');
}
function takeOffline(equipmentId) {
if (confirm('Take this equipment offline? This will prevent new studies from being scheduled.')) {
updateEquipmentStatus(equipmentId, 'offline');
}
}
function bringOnline(equipmentId) {
if (confirm('Bring this equipment online? It will be available for scheduling.')) {
updateEquipmentStatus(equipmentId, 'operational');
}
}
function updateEquipmentStatus(equipmentId = null, status = null) {
if (equipmentId && status) {
fetch(`/radiology/equipment/${equipmentId}/status/`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({status: status})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
}
});
} else {
// Refresh all equipment status
fetch('/radiology/equipment/status-update/')
.then(response => response.json())
.then(data => {
if (data.updates) {
location.reload();
}
});
}
}
function applyFilters() {
const form = document.getElementById('filterForm');
const formData = new FormData(form);
const params = new URLSearchParams(formData);
window.location.href = '?' + params.toString();
}
</script>
{% endblock %}