hospital-management/templates/hr/schedule_detail.html
2025-08-12 13:33:25 +03:00

564 lines
26 KiB
HTML

{% extends "base.html" %}
{% load static %}
{% block title %}{{ schedule.name }} | Schedule Details{% endblock %}
{% block css %}
<!-- DataTables CSS -->
<link href="{% static 'plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
<link href="{% static 'plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
<!-- Fullcalendar CSS -->
<link href="{% static 'plugins/fullcalendar/main.min.css' %}" rel="stylesheet" />
<style>
.schedule-header {
background: linear-gradient(to right, #2d62ed, #3a7bd5);
color: white;
padding: 20px;
border-radius: 5px;
margin-bottom: 20px;
}
.schedule-stats {
background: #f8f9fa;
border-radius: 5px;
padding: 15px;
}
.stat-card {
transition: all 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.employee-card {
transition: all 0.3s ease;
}
.employee-card:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.tab-content {
padding: 20px;
border: 1px solid #dee2e6;
border-top: none;
border-radius: 0 0 5px 5px;
}
.fc-event {
cursor: pointer;
}
.fc-event-title {
font-weight: bold;
}
.calendar-container {
height: 600px;
}
.assignment-time {
font-size: 0.85rem;
color: #6c757d;
}
.shift-type {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 5px;
}
.shift-morning {
background-color: #28a745;
}
.shift-afternoon {
background-color: #fd7e14;
}
.shift-night {
background-color: #6f42c1;
}
.shift-full {
background-color: #007bff;
}
</style>
{% endblock %}
{% block content %}
<!-- begin breadcrumb -->
<ol class="breadcrumb float-xl-end">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Home</a></li>
<li class="breadcrumb-item"><a href="{% url 'hr:dashboard' %}">HR</a></li>
<li class="breadcrumb-item"><a href="{% url 'hr:schedule_list' %}">Schedules</a></li>
<li class="breadcrumb-item active">{{ schedule.name }}</li>
</ol>
<!-- end breadcrumb -->
<!-- begin page-header -->
<h1 class="page-header">Schedule Details</h1>
<!-- end page-header -->
<!-- Schedule Header -->
<div class="schedule-header">
<div class="d-flex justify-content-between align-items-center">
<div>
<h2 class="mb-1">{{ schedule.name }}</h2>
<p class="mb-0">{{ schedule.start_date|date:"M d, Y" }} - {{ schedule.end_date|date:"M d, Y" }}</p>
</div>
<div>
{% if schedule.status == 'DRAFT' %}
<span class="badge bg-warning fs-6">Draft</span>
{% elif schedule.status == 'PUBLISHED' %}
<span class="badge bg-success fs-6">Published</span>
{% else %}
<span class="badge bg-secondary fs-6">Archived</span>
{% endif %}
</div>
</div>
</div>
<!-- Action Buttons -->
<div class="d-flex justify-content-end mb-4">
{% if schedule.status == 'DRAFT' %}
<a href="{% url 'hr:publish_schedule' schedule.id %}" class="btn btn-success me-2">
<i class="fas fa-check"></i> Publish Schedule
</a>
{% endif %}
<a href="{% url 'hr:schedule_update' schedule.id %}" class="btn btn-primary me-2">
<i class="fas fa-edit"></i> Edit Schedule
</a>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="exportDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<i class="fas fa-download"></i> Export
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="exportDropdown">
<li><a class="dropdown-item" href="#" id="export-pdf"><i class="fas fa-file-pdf"></i> PDF</a></li>
<li><a class="dropdown-item" href="#" id="export-excel"><i class="fas fa-file-excel"></i> Excel</a></li>
<li><a class="dropdown-item" href="#" id="export-csv"><i class="fas fa-file-csv"></i> CSV</a></li>
</ul>
</div>
</div>
<!-- begin row -->
<div class="row">
<!-- begin col-4 -->
<div class="col-xl-4">
<!-- Schedule Info Card -->
<div class="card mb-4">
<div class="card-header d-flex align-items-center">
<h5 class="card-title mb-0">Schedule Information</h5>
</div>
<div class="card-body">
<table class="table table-borderless">
<tbody>
<tr>
<th width="35%">Department:</th>
<td>
{% if schedule.department %}
<a href="{% url 'hr:department_detail' schedule.department.id %}">
{{ schedule.department.name }}
</a>
{% else %}
<span class="text-muted">All Departments</span>
{% endif %}
</td>
</tr>
<tr>
<th>Period:</th>
<td>{{ schedule.start_date|date:"M d, Y" }} - {{ schedule.end_date|date:"M d, Y" }}</td>
</tr>
<tr>
<th>Duration:</th>
<td>{{ schedule.duration }} days</td>
</tr>
<tr>
<th>Status:</th>
<td>
{% if schedule.status == 'DRAFT' %}
<span class="badge bg-warning">Draft</span>
{% elif schedule.status == 'PUBLISHED' %}
<span class="badge bg-success">Published</span>
{% else %}
<span class="badge bg-secondary">Archived</span>
{% endif %}
</td>
</tr>
<tr>
<th>Created By:</th>
<td>{{ schedule.created_by.get_full_name }}</td>
</tr>
<tr>
<th>Created At:</th>
<td>{{ schedule.created_at|date:"M d, Y H:i" }}</td>
</tr>
{% if schedule.published_at %}
<tr>
<th>Published At:</th>
<td>{{ schedule.published_at|date:"M d, Y H:i" }}</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
<!-- Schedule Statistics Card -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">Schedule Statistics</h5>
</div>
<div class="card-body">
<div class="row g-3">
<div class="col-6">
<div class="stat-card bg-primary bg-opacity-10 p-3 rounded text-center">
<h3 class="mb-1">{{ schedule.assignments.count }}</h3>
<p class="mb-0">Total Assignments</p>
</div>
</div>
<div class="col-6">
<div class="stat-card bg-success bg-opacity-10 p-3 rounded text-center">
<h3 class="mb-1">{{ employee_count }}</h3>
<p class="mb-0">Employees</p>
</div>
</div>
<div class="col-6">
<div class="stat-card bg-info bg-opacity-10 p-3 rounded text-center">
<h3 class="mb-1">{{ total_hours }}</h3>
<p class="mb-0">Total Hours</p>
</div>
</div>
<div class="col-6">
<div class="stat-card bg-warning bg-opacity-10 p-3 rounded text-center">
<h3 class="mb-1">{{ avg_hours_per_employee|floatformat:1 }}</h3>
<p class="mb-0">Avg Hours/Employee</p>
</div>
</div>
</div>
<!-- Shift Distribution Chart -->
<div class="mt-4">
<h6 class="mb-3">Shift Distribution</h6>
<canvas id="shiftDistributionChart" height="200"></canvas>
</div>
</div>
</div>
<!-- Notes Card -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">Notes</h5>
</div>
<div class="card-body">
{% if schedule.notes %}
<p>{{ schedule.notes|linebreaks }}</p>
{% else %}
<p class="text-muted">No notes available for this schedule.</p>
{% endif %}
</div>
</div>
</div>
<!-- end col-4 -->
<!-- begin col-8 -->
<div class="col-xl-8">
<!-- Schedule Description -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">Description</h5>
</div>
<div class="card-body">
{% if schedule.description %}
<p>{{ schedule.description }}</p>
{% else %}
<p class="text-muted">No description available.</p>
{% endif %}
</div>
</div>
<!-- Schedule Tabs -->
<div class="card mb-4">
<div class="card-header p-0">
<ul class="nav nav-tabs" id="scheduleTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="calendar-tab" data-bs-toggle="tab" data-bs-target="#calendar" type="button" role="tab" aria-controls="calendar" aria-selected="true">
<i class="fas fa-calendar-alt me-1"></i> Calendar View
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="assignments-tab" data-bs-toggle="tab" data-bs-target="#assignments" type="button" role="tab" aria-controls="assignments" aria-selected="false">
<i class="fas fa-tasks me-1"></i> Assignments
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="employees-tab" data-bs-toggle="tab" data-bs-target="#employees" type="button" role="tab" aria-controls="employees" aria-selected="false">
<i class="fas fa-users me-1"></i> Employees
</button>
</li>
</ul>
</div>
<div class="card-body p-0">
<div class="tab-content" id="scheduleTabsContent">
<!-- Calendar Tab -->
<div class="tab-pane fade show active" id="calendar" role="tabpanel" aria-labelledby="calendar-tab">
<div class="calendar-container">
<div id="schedule-calendar"></div>
</div>
</div>
<!-- Assignments Tab -->
<div class="tab-pane fade" id="assignments" role="tabpanel" aria-labelledby="assignments-tab">
<div class="table-responsive">
<table id="assignments-table" class="table table-striped table-bordered align-middle">
<thead>
<tr>
<th>Employee</th>
<th>Date</th>
<th>Shift</th>
<th>Hours</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for assignment in schedule.assignments.all %}
<tr>
<td>
<div class="d-flex align-items-center">
<div class="avatar avatar-sm me-2">
<img src="{% static 'img/user/default-avatar.jpg' %}" alt="{{ assignment.employee.get_full_name }}" class="rounded-circle">
</div>
<div>
<a href="{% url 'hr:employee_detail' assignment.employee.id %}">
{{ assignment.employee.get_full_name }}
</a>
<small class="d-block text-muted">{{ assignment.employee.job_title }}</small>
</div>
</div>
</td>
<td>{{ assignment.date|date:"M d, Y" }}</td>
<td>
<div>
<span class="shift-type
{% if assignment.shift_type == 'MORNING' %}shift-morning
{% elif assignment.shift_type == 'AFTERNOON' %}shift-afternoon
{% elif assignment.shift_type == 'NIGHT' %}shift-night
{% else %}shift-full{% endif %}"></span>
{{ assignment.get_shift_type_display }}
</div>
<div class="assignment-time">
{{ assignment.start_time|time:"H:i" }} - {{ assignment.end_time|time:"H:i" }}
</div>
</td>
<td>{{ assignment.hours }} hrs</td>
<td>
<div class="btn-group">
<a href="{% url 'hr:schedule_assignment_update' assignment.id %}" class="btn btn-sm btn-primary">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-sm btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal{{ assignment.id }}">
<i class="fas fa-trash"></i>
</button>
</div>
<!-- Delete Modal -->
<div class="modal fade" id="deleteModal{{ assignment.id }}" tabindex="-1" aria-labelledby="deleteModalLabel{{ assignment.id }}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel{{ assignment.id }}">Confirm Deletion</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete this assignment for {{ assignment.employee.get_full_name }} on {{ assignment.date|date:"M d, Y" }}?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<a href="{% url 'hr:schedule_assignment_delete' assignment.id %}" class="btn btn-danger">Delete</a>
</div>
</div>
</div>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="text-center">No assignments found for this schedule.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="mt-3">
<a href="{% url 'hr:schedule_assignment_create' %}?schedule={{ schedule.id }}" class="btn btn-primary">
<i class="fas fa-plus"></i> Add Assignment
</a>
</div>
</div>
<!-- Employees Tab -->
<div class="tab-pane fade" id="employees" role="tabpanel" aria-labelledby="employees-tab">
<div class="row g-3">
{% for employee in employees %}
<div class="col-md-6">
<div class="card employee-card h-100">
<div class="card-body">
<div class="d-flex align-items-center mb-3">
<div class="avatar avatar-md me-3">
<img src="{% static 'img/user/default-avatar.jpg' %}" alt="{{ employee.get_full_name }}" class="rounded-circle">
</div>
<div>
<h5 class="card-title mb-0">{{ employee.get_full_name }}</h5>
<p class="card-text text-muted">{{ employee.job_title }}</p>
</div>
</div>
<div class="mb-3">
<strong>Department:</strong>
{% if employee.department %}
<a href="{% url 'hr:department_detail' employee.department.id %}">
{{ employee.department.name }}
</a>
{% else %}
<span class="text-muted">Not assigned</span>
{% endif %}
</div>
<div class="mb-3">
<strong>Assignments:</strong> {{ employee.assignments_count }}
<span class="text-muted">({{ employee.total_hours }} hours)</span>
</div>
<a href="{% url 'hr:employee_detail' employee.id %}" class="btn btn-sm btn-outline-primary">
<i class="fas fa-user"></i> View Profile
</a>
</div>
</div>
</div>
{% empty %}
<div class="col-12">
<div class="alert alert-info">
No employees assigned to this schedule.
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- end col-8 -->
</div>
<!-- end row -->
{% endblock %}
{% block js %}
<!-- DataTables JS -->
<script src="{% static 'plugins/datatables.net/js/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
<script src="{% static 'plugins/datatables.net-responsive/js/dataTables.responsive.min.js' %}"></script>
<script src="{% static 'plugins/datatables.net-responsive-bs5/js/responsive.bootstrap5.min.js' %}"></script>
<!-- Fullcalendar JS -->
<script src="{% static 'plugins/fullcalendar/main.min.js' %}"></script>
<!-- Chart.js -->
<script src="{% static 'plugins/chart.js/dist/Chart.min.js' %}"></script>
<script>
$(document).ready(function() {
// Initialize DataTable
$('#assignments-table').DataTable({
responsive: true,
lengthMenu: [10, 25, 50, 100],
pageLength: 10
});
// Initialize Calendar
var calendarEl = document.getElementById('schedule-calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
initialDate: '{{ schedule.start_date|date:"Y-m-d" }}',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
events: [
{% for assignment in schedule.assignments.all %}
{
title: '{{ assignment.employee.get_full_name }}',
start: '{{ assignment.date|date:"Y-m-d" }}T{{ assignment.start_time|time:"H:i:s" }}',
end: '{{ assignment.date|date:"Y-m-d" }}T{{ assignment.end_time|time:"H:i:s" }}',
backgroundColor: '{% if assignment.shift_type == "MORNING" %}#28a745{% elif assignment.shift_type == "AFTERNOON" %}#fd7e14{% elif assignment.shift_type == "NIGHT" %}#6f42c1{% else %}#007bff{% endif %}',
borderColor: '{% if assignment.shift_type == "MORNING" %}#28a745{% elif assignment.shift_type == "AFTERNOON" %}#fd7e14{% elif assignment.shift_type == "NIGHT" %}#6f42c1{% else %}#007bff{% endif %}',
extendedProps: {
employee: '{{ assignment.employee.get_full_name }}',
shift: '{{ assignment.get_shift_type_display }}',
hours: '{{ assignment.hours }}'
}
}{% if not forloop.last %},{% endif %}
{% endfor %}
],
eventDidMount: function(info) {
$(info.el).tooltip({
title: info.event.title + ' - ' + info.event.extendedProps.shift + ' (' + info.event.extendedProps.hours + ' hrs)',
placement: 'top',
trigger: 'hover',
container: 'body'
});
}
});
calendar.render();
// Shift Distribution Chart
var ctx = document.getElementById('shiftDistributionChart').getContext('2d');
var shiftDistributionChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ['Morning', 'Afternoon', 'Night', 'Full Day'],
datasets: [{
data: [
{{ morning_shifts }},
{{ afternoon_shifts }},
{{ night_shifts }},
{{ full_day_shifts }}
],
backgroundColor: [
'#28a745',
'#fd7e14',
'#6f42c1',
'#007bff'
],
borderColor: [
'#28a745',
'#fd7e14',
'#6f42c1',
'#007bff'
],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
position: 'bottom',
labels: {
boxWidth: 12
}
}
}
});
// Export functionality
$('#export-pdf').click(function(e) {
e.preventDefault();
window.location.href = '{% url "hr:export_schedule" schedule.id %}?format=pdf';
});
$('#export-excel').click(function(e) {
e.preventDefault();
window.location.href = '{% url "hr:export_schedule" schedule.id %}?format=excel';
});
$('#export-csv').click(function(e) {
e.preventDefault();
window.location.href = '{% url "hr:export_schedule" schedule.id %}?format=csv';
});
});
</script>
{% endblock %}