699 lines
38 KiB
HTML
699 lines
38 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Performance Reviews | HR Management{% 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" />
|
|
<!-- DateRangePicker CSS -->
|
|
<link href="{% static 'plugins/bootstrap-daterangepicker/daterangepicker.css' %}" rel="stylesheet" />
|
|
<style>
|
|
.filter-card {
|
|
background-color: #f8f9fa;
|
|
border-radius: 5px;
|
|
padding: 15px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.status-badge {
|
|
width: 10px;
|
|
height: 10px;
|
|
display: inline-block;
|
|
border-radius: 50%;
|
|
margin-right: 5px;
|
|
}
|
|
.status-draft {
|
|
background-color: #6c757d;
|
|
}
|
|
.status-in-progress {
|
|
background-color: #ffc107;
|
|
}
|
|
.status-completed {
|
|
background-color: #28a745;
|
|
}
|
|
.status-overdue {
|
|
background-color: #dc3545;
|
|
}
|
|
.review-card {
|
|
transition: all 0.3s ease;
|
|
}
|
|
.review-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
|
}
|
|
.summary-card {
|
|
border-left: 4px solid #2d62ed;
|
|
}
|
|
.view-toggle .btn {
|
|
min-width: 100px;
|
|
}
|
|
.score-badge {
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-weight: bold;
|
|
color: white;
|
|
}
|
|
.score-excellent {
|
|
background-color: #28a745;
|
|
}
|
|
.score-good {
|
|
background-color: #17a2b8;
|
|
}
|
|
.score-average {
|
|
background-color: #ffc107;
|
|
}
|
|
.score-needs-improvement {
|
|
background-color: #fd7e14;
|
|
}
|
|
.score-poor {
|
|
background-color: #dc3545;
|
|
}
|
|
.progress-thin {
|
|
height: 5px;
|
|
}
|
|
</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 active">Performance Reviews</li>
|
|
</ol>
|
|
<!-- end breadcrumb -->
|
|
|
|
<!-- begin page-header -->
|
|
<h1 class="page-header">Performance Reviews <small>manage employee performance evaluations</small></h1>
|
|
<!-- end page-header -->
|
|
|
|
<!-- begin row -->
|
|
<div class="row">
|
|
<!-- begin col-12 -->
|
|
<div class="col-xl-12">
|
|
<!-- Summary Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card summary-card h-100">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<h5 class="card-title">Total Reviews</h5>
|
|
<h2 class="mb-0">{{ total_reviews|default:"0" }}</h2>
|
|
</div>
|
|
<div class="text-primary">
|
|
<i class="fas fa-clipboard-list fa-3x"></i>
|
|
</div>
|
|
</div>
|
|
<p class="card-text text-muted">Current period</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card summary-card h-100" style="border-left-color: #28a745;">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<h5 class="card-title">Completed</h5>
|
|
<h2 class="mb-0">{{ completed_reviews|default:"0" }}</h2>
|
|
</div>
|
|
<div class="text-success">
|
|
<i class="fas fa-check-circle fa-3x"></i>
|
|
</div>
|
|
</div>
|
|
<p class="card-text text-muted">Reviews completed</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card summary-card h-100" style="border-left-color: #ffc107;">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<h5 class="card-title">In Progress</h5>
|
|
<h2 class="mb-0">{{ in_progress_reviews|default:"0" }}</h2>
|
|
</div>
|
|
<div class="text-warning">
|
|
<i class="fas fa-hourglass-half fa-3x"></i>
|
|
</div>
|
|
</div>
|
|
<p class="card-text text-muted">Reviews in progress</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card summary-card h-100" style="border-left-color: #dc3545;">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between">
|
|
<div>
|
|
<h5 class="card-title">Overdue</h5>
|
|
<h2 class="mb-0">{{ overdue_reviews|default:"0" }}</h2>
|
|
</div>
|
|
<div class="text-danger">
|
|
<i class="fas fa-exclamation-circle fa-3x"></i>
|
|
</div>
|
|
</div>
|
|
<p class="card-text text-muted">Reviews overdue</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- begin panel -->
|
|
<div class="panel panel-inverse">
|
|
<!-- begin panel-heading -->
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Performance Reviews</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-success" data-toggle="panel-reload"><i class="fa fa-redo"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-warning" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<!-- end panel-heading -->
|
|
|
|
<!-- begin panel-body -->
|
|
<div class="panel-body">
|
|
<!-- Filters -->
|
|
<div class="filter-card">
|
|
<form method="get" id="filterForm">
|
|
<div class="row g-3">
|
|
<div class="col-md-3">
|
|
<label for="employee" class="form-label">Employee</label>
|
|
<select class="form-select" id="employee" name="employee">
|
|
<option value="">All Employees</option>
|
|
{% for employee in employees %}
|
|
<option value="{{ employee.id }}" {% if selected_employee == employee.id %}selected{% endif %}>
|
|
{{ employee.get_full_name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="department" class="form-label">Department</label>
|
|
<select class="form-select" id="department" name="department">
|
|
<option value="">All Departments</option>
|
|
{% for dept in departments %}
|
|
<option value="{{ dept.id }}" {% if selected_department == dept.id %}selected{% endif %}>
|
|
{{ dept.name }}
|
|
</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="status" class="form-label">Status</label>
|
|
<select class="form-select" id="status" name="status">
|
|
<option value="">All Statuses</option>
|
|
<option value="DRAFT" {% if selected_status == 'DRAFT' %}selected{% endif %}>Draft</option>
|
|
<option value="IN_PROGRESS" {% if selected_status == 'IN_PROGRESS' %}selected{% endif %}>In Progress</option>
|
|
<option value="COMPLETED" {% if selected_status == 'COMPLETED' %}selected{% endif %}>Completed</option>
|
|
<option value="OVERDUE" {% if selected_status == 'OVERDUE' %}selected{% endif %}>Overdue</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="date_range" class="form-label">Review Period</label>
|
|
<input type="text" class="form-control" id="date_range" name="date_range" value="{{ date_range }}">
|
|
</div>
|
|
<div class="col-md-12">
|
|
<div class="d-flex">
|
|
<button type="submit" class="btn btn-primary me-2">
|
|
<i class="fas fa-filter"></i> Apply Filters
|
|
</button>
|
|
<a href="{% url 'hr:performance_review_list' %}" class="btn btn-secondary me-2">
|
|
<i class="fas fa-times"></i> Clear Filters
|
|
</a>
|
|
<div class="dropdown ms-auto">
|
|
<button class="btn btn-outline-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>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between mb-3">
|
|
<div>
|
|
<a href="{% url 'hr:performance_review_create' %}" class="btn btn-primary">
|
|
<i class="fas fa-plus"></i> Create Review
|
|
</a>
|
|
<div class="btn-group ms-2 view-toggle" role="group">
|
|
<button type="button" class="btn btn-outline-secondary active" id="table-view-btn">
|
|
<i class="fas fa-table"></i> Table
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary" id="card-view-btn">
|
|
<i class="fas fa-th-large"></i> Cards
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<form method="get" class="d-flex">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" placeholder="Search reviews..." name="search" value="{{ search }}">
|
|
<button class="btn btn-outline-secondary" type="submit">
|
|
<i class="fas fa-search"></i>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Table View -->
|
|
<div id="table-view">
|
|
<table id="reviews-table" class="table table-striped table-bordered align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>Employee</th>
|
|
<th>Review Period</th>
|
|
<th>Reviewer</th>
|
|
<th>Status</th>
|
|
<th>Score</th>
|
|
<th>Due Date</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for review in performance_reviews %}
|
|
<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="{{ review.employee.get_full_name }}" class="rounded-circle">
|
|
</div>
|
|
<div>
|
|
<a href="{% url 'hr:employee_detail' review.employee.id %}">
|
|
{{ review.employee.get_full_name }}
|
|
</a>
|
|
<small class="d-block text-muted">{{ review.employee.job_title }}</small>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>{{ review.period_start|date:"M d, Y" }} - {{ review.period_end|date:"M d, Y" }}</td>
|
|
<td>
|
|
{% if review.reviewer %}
|
|
{{ review.reviewer.get_full_name }}
|
|
{% else %}
|
|
Not assigned
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if review.status == 'DRAFT' %}
|
|
<span class="status-badge status-draft"></span> Draft
|
|
{% elif review.status == 'IN_PROGRESS' %}
|
|
<span class="status-badge status-in-progress"></span> In Progress
|
|
{% elif review.status == 'COMPLETED' %}
|
|
<span class="status-badge status-completed"></span> Completed
|
|
{% elif review.status == 'OVERDUE' %}
|
|
<span class="status-badge status-overdue"></span> Overdue
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if review.overall_score %}
|
|
<div class="d-flex align-items-center">
|
|
<div class="score-badge
|
|
{% if review.overall_score >= 4.5 %}score-excellent
|
|
{% elif review.overall_score >= 3.5 %}score-good
|
|
{% elif review.overall_score >= 2.5 %}score-average
|
|
{% elif review.overall_score >= 1.5 %}score-needs-improvement
|
|
{% else %}score-poor{% endif %}">
|
|
{{ review.overall_score }}
|
|
</div>
|
|
<div class="ms-2">
|
|
{% if review.overall_score >= 4.5 %}
|
|
Excellent
|
|
{% elif review.overall_score >= 3.5 %}
|
|
Good
|
|
{% elif review.overall_score >= 2.5 %}
|
|
Average
|
|
{% elif review.overall_score >= 1.5 %}
|
|
Needs Improvement
|
|
{% else %}
|
|
Poor
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<span class="text-muted">Not rated</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{{ review.due_date|date:"M d, Y" }}
|
|
{% if review.status == 'OVERDUE' %}
|
|
<span class="badge bg-danger ms-1">Overdue</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<div class="btn-group">
|
|
<a href="{% url 'hr:performance_review_detail' review.id %}" class="btn btn-sm btn-info">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<a href="{% url 'hr:performance_review_update' review.id %}" class="btn btn-sm btn-primary">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
{% if review.status != 'COMPLETED' %}
|
|
<a href="{% url 'hr:performance_review_delete' review.id %}" class="btn btn-sm btn-danger">
|
|
<i class="fas fa-trash"></i>
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="7" class="text-center">No performance reviews found.</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- Pagination -->
|
|
{% if is_paginated %}
|
|
<nav aria-label="Page navigation">
|
|
<ul class="pagination justify-content-center">
|
|
{% if page_obj.has_previous %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page=1{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="First">
|
|
<span aria-hidden="true">««</span>
|
|
</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Previous">
|
|
<span aria-hidden="true">«</span>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for num in page_obj.paginator.page_range %}
|
|
{% if page_obj.number == num %}
|
|
<li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
|
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
<li class="page-item"><a class="page-link" href="?page={{ num }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}">{{ num }}</a></li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if page_obj.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Next">
|
|
<span aria-hidden="true">»</span>
|
|
</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Last">
|
|
<span aria-hidden="true">»»</span>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Card View -->
|
|
<div id="card-view" class="row g-3" style="display: none;">
|
|
{% for review in performance_reviews %}
|
|
<div class="col-md-6 col-lg-4">
|
|
<div class="card review-card h-100">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0">{{ review.employee.get_full_name }}</h5>
|
|
{% if review.status == 'DRAFT' %}
|
|
<span class="badge bg-secondary">Draft</span>
|
|
{% elif review.status == 'IN_PROGRESS' %}
|
|
<span class="badge bg-warning">In Progress</span>
|
|
{% elif review.status == 'COMPLETED' %}
|
|
<span class="badge bg-success">Completed</span>
|
|
{% elif review.status == 'OVERDUE' %}
|
|
<span class="badge bg-danger">Overdue</span>
|
|
{% endif %}
|
|
</div>
|
|
<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="{{ review.employee.get_full_name }}" class="rounded-circle">
|
|
</div>
|
|
<div>
|
|
<p class="card-text mb-0">{{ review.employee.job_title }}</p>
|
|
<small class="text-muted">
|
|
{% if review.employee.department %}
|
|
{{ review.employee.department.name }}
|
|
{% else %}
|
|
No Department
|
|
{% endif %}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<strong>Review Period:</strong><br>
|
|
{{ review.period_start|date:"M d, Y" }} - {{ review.period_end|date:"M d, Y" }}
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<strong>Due Date:</strong><br>
|
|
{{ review.due_date|date:"M d, Y" }}
|
|
{% if review.status == 'OVERDUE' %}
|
|
<span class="badge bg-danger ms-1">Overdue</span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<strong>Reviewer:</strong><br>
|
|
{% if review.reviewer %}
|
|
{{ review.reviewer.get_full_name }}
|
|
{% else %}
|
|
Not assigned
|
|
{% endif %}
|
|
</div>
|
|
|
|
{% if review.overall_score %}
|
|
<div class="mb-3">
|
|
<strong>Overall Score:</strong>
|
|
<div class="d-flex align-items-center mt-2">
|
|
<div class="score-badge
|
|
{% if review.overall_score >= 4.5 %}score-excellent
|
|
{% elif review.overall_score >= 3.5 %}score-good
|
|
{% elif review.overall_score >= 2.5 %}score-average
|
|
{% elif review.overall_score >= 1.5 %}score-needs-improvement
|
|
{% else %}score-poor{% endif %}">
|
|
{{ review.overall_score }}
|
|
</div>
|
|
<div class="ms-2">
|
|
{% if review.overall_score >= 4.5 %}
|
|
Excellent
|
|
{% elif review.overall_score >= 3.5 %}
|
|
Good
|
|
{% elif review.overall_score >= 2.5 %}
|
|
Average
|
|
{% elif review.overall_score >= 1.5 %}
|
|
Needs Improvement
|
|
{% else %}
|
|
Poor
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if review.status == 'IN_PROGRESS' %}
|
|
<div class="mb-3">
|
|
<strong>Completion Progress:</strong>
|
|
<div class="progress progress-thin mt-2">
|
|
<div class="progress-bar" role="progressbar" style="width: {{ review.completion_percentage|default:0 }}%;" aria-valuenow="{{ review.completion_percentage|default:0 }}" aria-valuemin="0" aria-valuemax="100">{{ review.completion_percentage|default:0 }}%</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div class="card-footer">
|
|
<div class="btn-group w-100">
|
|
<a href="{% url 'hr:performance_review_detail' review.id %}" class="btn btn-sm btn-info">
|
|
<i class="fas fa-eye"></i> View
|
|
</a>
|
|
<a href="{% url 'hr:performance_review_update' review.id %}" class="btn btn-sm btn-primary">
|
|
<i class="fas fa-edit"></i> Edit
|
|
</a>
|
|
{% if review.status != 'COMPLETED' %}
|
|
<a href="{% url 'hr:performance_review_delete' review.id %}" class="btn btn-sm btn-danger">
|
|
<i class="fas fa-trash"></i> Delete
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="col-12">
|
|
<div class="alert alert-info">
|
|
No performance reviews found.
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
|
|
<!-- Pagination for Card View -->
|
|
{% if is_paginated %}
|
|
<div class="col-12 mt-3">
|
|
<nav aria-label="Page navigation">
|
|
<ul class="pagination justify-content-center">
|
|
{% if page_obj.has_previous %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page=1{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="First">
|
|
<span aria-hidden="true">««</span>
|
|
</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Previous">
|
|
<span aria-hidden="true">«</span>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for num in page_obj.paginator.page_range %}
|
|
{% if page_obj.number == num %}
|
|
<li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
|
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
<li class="page-item"><a class="page-link" href="?page={{ num }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}">{{ num }}</a></li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if page_obj.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Next">
|
|
<span aria-hidden="true">»</span>
|
|
</a>
|
|
</li>
|
|
<li class="page-item">
|
|
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}{% if search %}&search={{ search }}{% endif %}{% if selected_employee %}&employee={{ selected_employee }}{% endif %}{% if selected_department %}&department={{ selected_department }}{% endif %}{% if selected_status %}&status={{ selected_status }}{% endif %}{% if date_range %}&date_range={{ date_range }}{% endif %}" aria-label="Last">
|
|
<span aria-hidden="true">»»</span>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- end panel-body -->
|
|
</div>
|
|
<!-- end panel -->
|
|
</div>
|
|
<!-- end col-12 -->
|
|
</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>
|
|
<!-- DateRangePicker JS -->
|
|
<script src="{% static 'plugins/moment/min/moment.min.js' %}"></script>
|
|
<script src="{% static 'plugins/bootstrap-daterangepicker/daterangepicker.js' %}"></script>
|
|
<!-- Select2 JS -->
|
|
<script src="{% static 'plugins/select2/dist/js/select2.min.js' %}"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize DataTable
|
|
var table = $('#reviews-table').DataTable({
|
|
dom: "<'row'<'col-md-6'l><'col-md-6'f>><'row'<'col-md-12't>><'row'<'col-md-5'i><'col-md-7'p>>",
|
|
lengthMenu: [10, 25, 50, 100],
|
|
responsive: true,
|
|
paging: false, // We're using Django's pagination
|
|
searching: false, // We're using our own search
|
|
info: false // We're using Django's pagination info
|
|
});
|
|
|
|
// Initialize DateRangePicker
|
|
$('#date_range').daterangepicker({
|
|
opens: 'left',
|
|
autoUpdateInput: false,
|
|
locale: {
|
|
cancelLabel: 'Clear',
|
|
format: 'YYYY-MM-DD'
|
|
}
|
|
});
|
|
|
|
$('#date_range').on('apply.daterangepicker', function(ev, picker) {
|
|
$(this).val(picker.startDate.format('YYYY-MM-DD') + ' - ' + picker.endDate.format('YYYY-MM-DD'));
|
|
});
|
|
|
|
$('#date_range').on('cancel.daterangepicker', function(ev, picker) {
|
|
$(this).val('');
|
|
});
|
|
|
|
// Initialize Select2
|
|
$('#employee, #department, #status').select2({
|
|
placeholder: "Select an option",
|
|
allowClear: true
|
|
});
|
|
|
|
// View toggle functionality
|
|
$('#table-view-btn').click(function() {
|
|
$(this).addClass('active');
|
|
$('#card-view-btn').removeClass('active');
|
|
$('#table-view').show();
|
|
$('#card-view').hide();
|
|
localStorage.setItem('review-view', 'table');
|
|
});
|
|
|
|
$('#card-view-btn').click(function() {
|
|
$(this).addClass('active');
|
|
$('#table-view-btn').removeClass('active');
|
|
$('#table-view').hide();
|
|
$('#card-view').show();
|
|
localStorage.setItem('review-view', 'card');
|
|
});
|
|
|
|
// Load saved view preference
|
|
var savedView = localStorage.getItem('review-view');
|
|
if (savedView === 'card') {
|
|
$('#card-view-btn').click();
|
|
}
|
|
|
|
// Export functionality
|
|
$('#export-pdf').click(function(e) {
|
|
e.preventDefault();
|
|
var url = '{% url "hr:export_performance_reviews" %}?format=pdf';
|
|
var filterParams = $('#filterForm').serialize();
|
|
if (filterParams) {
|
|
url += '&' + filterParams;
|
|
}
|
|
window.location.href = url;
|
|
});
|
|
|
|
$('#export-excel').click(function(e) {
|
|
e.preventDefault();
|
|
var url = '{% url "hr:export_performance_reviews" %}?format=excel';
|
|
var filterParams = $('#filterForm').serialize();
|
|
if (filterParams) {
|
|
url += '&' + filterParams;
|
|
}
|
|
window.location.href = url;
|
|
});
|
|
|
|
$('#export-csv').click(function(e) {
|
|
e.preventDefault();
|
|
var url = '{% url "hr:export_performance_reviews" %}?format=csv';
|
|
var filterParams = $('#filterForm').serialize();
|
|
if (filterParams) {
|
|
url += '&' + filterParams;
|
|
}
|
|
window.location.href = url;
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|