clean: remove pycache from tracking
This commit is contained in:
16
SIRH/asgi.py
16
SIRH/asgi.py
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
ASGI config for SIRH project.
|
|
||||||
|
|
||||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SIRH.settings')
|
|
||||||
|
|
||||||
application = get_asgi_application()
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 180 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB |
@@ -1,157 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PRINCICALA</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'icons.css' %}">
|
|
||||||
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700); /* oranges plus sombres */
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.sidebar .nav-link {
|
|
||||||
color: white;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
.sidebar .nav-link:hover {
|
|
||||||
background-color: rgba(255,255,255,0.2);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
max-width: 90px;
|
|
||||||
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
margin-left: 220px;
|
|
||||||
}
|
|
||||||
.stat-card {
|
|
||||||
background: rgb(255, 255, 255);
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0px 2px 5px rgba(113, 11, 11, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
|
|
||||||
<nav class="col-12 col-md-3 col-lg-2 sidebar p-3">
|
|
||||||
<div class="text-center mb-4">
|
|
||||||
<img src="{% static 'CERFIF.jpg' %}" alt="Logo" class="logo mb-5">
|
|
||||||
<h4 class="text-white">CERFIG</h4>
|
|
||||||
</div>
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="/" class="nav-link"><i class="bi bi-speedometer2"></i> Tableau de bord</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class=" bi bi-airplane"></i> Demande de congé </a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-people"></i> Gestion des Employés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-folder"></i> Gestion des Projets</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-airplane"></i> Gestion des Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-graph-up"></i>Rapports et Statistiques</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-gear"></i> Paramètres</a>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Contenu principal -->
|
|
||||||
<main class="col px-4 py-4">
|
|
||||||
<h1 class="mb-4">Bienvenue sur le tableau de bord</h1>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row g-3 mb-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-airplane"></i> Congés en attente</h5>
|
|
||||||
|
|
||||||
<p class="display-6 fw-bold"> {{ nombre_conges_attente }}</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-people"></i> Nombre Employés </h5>
|
|
||||||
<p class="display-6 fw-bold">{{ nombre_employes }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-kanban"></i> Projets en cours</h5>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card p-3">
|
|
||||||
<h3>
|
|
||||||
<i class="bi bi-people"></i> La liste des employés en congé</h3>
|
|
||||||
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Employé</th>
|
|
||||||
<th>Type de congé</th>
|
|
||||||
<th>Date de début</th>
|
|
||||||
<th>Date de fin</th>
|
|
||||||
<th>Statut</th>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
{% for employe in personnes_en_conge %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ employe.nom }} {{ employe.prenom }}</td>
|
|
||||||
<td>{{ employe.type }}</td>
|
|
||||||
<td>{{ employe.date_debut }}</td>
|
|
||||||
<td>{{ employe.date_fin }}</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-success">{{ employe.statut }} </span>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="5" class="text-center">Personne en conge </td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Connexion SI-RH</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<body class="d-flex justify-content-center align-items-center min-vh-100 ">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #b35400, #cc6600);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!-- Formulaire de connexion -->
|
|
||||||
<div class="p-4 shadow-sm rounded bg-white" style="max-width: 400px; margin: auto;">
|
|
||||||
<img src="{% static 'CERFIF.jpg' %}" alt="Logo" class="logo mb-3"
|
|
||||||
style="display: block; margin-left: auto; margin-right: auto; width: 60%; max-width: 500px; height: auto;">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-orange-dark text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-orange-dark text-white
|
|
||||||
{% else %}bg-orange-dark text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
<form method="POST" action="{% url 'login' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="username">Nom d’utilisateur</label>
|
|
||||||
<input type="text" name="username" class="form-control" placeholder="Entrez votre nom d’utilisateur" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 position-relative">
|
|
||||||
<label for="password">Mot de passe</label>
|
|
||||||
<input type="password" name="password" class="form-control" placeholder="Entrez votre mot de passe" required>
|
|
||||||
<i class="bi bi-eye toggle-password" onclick="togglePassword()"
|
|
||||||
style="position:absolute; right:10px; top:38px; cursor:pointer;"></i>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Se connecter</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p class="mt-3 text-center">
|
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#resetPasswordModal">Mot de passe oublié ?</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modale de réinitialisation -->
|
|
||||||
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content p-4">
|
|
||||||
<h5 class="modal-title mb-3" id="resetPasswordModalLabel">Réinitialisation du mot de passe</h5>
|
|
||||||
<form id="resetPasswordForm">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email">Entrez votre email</label>
|
|
||||||
<input type="email" name="email" class="form-control" placeholder="Email" required>
|
|
||||||
</div>
|
|
||||||
<div id="resetMessage" class="mb-3"></div>
|
|
||||||
<button type="submit" class="btn btn-warning w-100">Envoyer le lien</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if show_politique_modal %}
|
|
||||||
<!-- Modal Politique d'utilisation -->
|
|
||||||
<div class="modal fade" id="politiqueModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Politique d'utilisation de SI-RH</h5>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Veuillez lire et accepter notre politique d'utilisation avant d'accéder à votre compte.</p>
|
|
||||||
<h6>Confidentialité des données</h6>
|
|
||||||
<p>Vos informations personnelles et professionnelles sont protégées. Toute divulgation non autorisée est strictement interdite.</p>
|
|
||||||
<h6>Utilisation autorisée</h6>
|
|
||||||
<p>L’application est réservée à un usage professionnel. Toute utilisation à des fins personnelles ou non autorisées est prohibée.</p>
|
|
||||||
<h6>Sécurité des comptes</h6>
|
|
||||||
<p>Ne partagez jamais vos identifiants. Changez votre mot de passe régulièrement et en cas de suspicion d’intrusion.</p>
|
|
||||||
<h6>Responsabilités de l’utilisateur</h6>
|
|
||||||
<p>Vous êtes responsable des actions effectuées via votre compte. Signalez toute anomalie ou problème à l’équipe RH ou à l’administrateur.</p>
|
|
||||||
<h6>Acceptation et conformité</h6>
|
|
||||||
<p>En cliquant sur <strong>“J’accepte”</strong>, vous confirmez avoir lu et accepté cette politique. Le non-respect peut entraîner une suspension ou une révocation de l’accès.</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<form method="POST" action="{% url 'accepter-politique' %}" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-success">J'accepte</button>
|
|
||||||
</form>
|
|
||||||
<form method="POST" action="{% url 'refuser-politique' %}" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var modal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
modal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
||||||
<script>
|
|
||||||
// Afficher / masquer le mot de passe
|
|
||||||
function togglePassword() {
|
|
||||||
const input = document.querySelector('input[name="password"]');
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
|
|
||||||
// AJAX pour réinitialisation
|
|
||||||
$('#resetPasswordForm').on('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const email = $('input[name="email"]').val();
|
|
||||||
const csrfToken = $('[name=csrfmiddlewaretoken]').val();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "{% url 'password_reset' %}",
|
|
||||||
type: 'POST',
|
|
||||||
data: {
|
|
||||||
'email': email,
|
|
||||||
'csrfmiddlewaretoken': csrfToken
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-success">Email envoyé ! Vérifiez votre boîte de réception.</div>');
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-danger">Erreur lors de l’envoi. Vérifiez l’email.</div>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load roles %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PRINCICALA</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- SIDEBAR RESPONSIVE -->
|
|
||||||
<!-- ===================== -->
|
|
||||||
<nav class="sidebar bg-orange-dark text-white d-none d-md-block col-md-3 col-lg-2 p-3"
|
|
||||||
style="background: linear-gradient(90deg, #993d00, #b34700); position: fixed; height: 100vh; overflow-y: auto;">
|
|
||||||
|
|
||||||
<!-- Profil utilisateur -->
|
|
||||||
<div class="text-center mb-4 d-flex flex-column align-items-center" style="margin-top:20px;">
|
|
||||||
<h6 class="fw-bold text-white mb-2">{{ user.first_name }} {{ user.last_name }}</h6>
|
|
||||||
<a href="{% url 'mon_profil' %}">
|
|
||||||
{% if user.photo %}
|
|
||||||
<img src="{{ user.photo.url }}" alt="Profil"
|
|
||||||
class="rounded-circle img-profil mx-auto"
|
|
||||||
style="width: 80px; height: 80px; object-fit: cover;">
|
|
||||||
{% else %}
|
|
||||||
<div class="rounded-circle bg-secondary d-flex justify-content-center align-items-center"
|
|
||||||
style="width: 80px; height: 80px;">
|
|
||||||
<i class="bi bi-person-circle text-white" style="font-size: 2rem;"></i>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Liens du menu -->
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
{% if user|has_role:"Employe" or user|has_role:"Administrateur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Suivi des Activités</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'employe-conge' %}" class="nav-link text-white"><i class="bi bi-airplane"></i> Mes Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mes_formations' %}" class="nav-link text-white"><i class="bi bi-journal-text"></i> Mes certificats</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'salle' %}" class="nav-link text-white"><i class="bi bi-calendar-check"></i> Réserver une salle</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if user|has_role:"RH" or user|has_role:"Directeur" or user|has_role:"Assistante" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'employe-index' %}" class="nav-link text-white"><i class="bi bi-speedometer2"></i> Tableau de bord</a>
|
|
||||||
</li>
|
|
||||||
{% if user|has_role:"Assistante" or user|has_role:"RH" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Suivi des Activités</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if user|has_role:"Directeur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'directeur' %}" class="nav-link text-white"><i class="bi bi-graph-up"></i> Suivi des Projets</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'projet-index' %}" class="nav-link text-white"><i class="bi bi-folder"></i> Gestion des Projets</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'conge' %}" class="nav-link text-white"><i class="bi bi-airplane"></i> Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mes_formations' %}" class="nav-link text-white"><i class="bi bi-journal-text"></i> Mes certificats</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'salle' %}" class="nav-link text-white"><i class="bi bi-calendar-check"></i> Réserver une salle</a>
|
|
||||||
</li>
|
|
||||||
{% if user|has_role:"RH" or user|has_role:"Directeur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'rapport-rh' %}" class="nav-link text-white"><i class="bi bi-graph-up"></i> Rapports et Statistiques</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if user|has_role:"Administrateur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'gestion-utilisateurs' %}" class="nav-link text-white"><i class="bi bi-person-gear"></i> Gestion des Utilisateurs</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'parametres-rh' %}" class="nav-link text-white"><i class="bi bi-gear"></i> Paramètres</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'deconnexion' %}" class="nav-link text-white"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- MENU MOBILE (offcanvas) -->
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- Bouton burger (visible uniquement sur téléphone) -->
|
|
||||||
<nav class="navbar navbar-dark bg-orange-dark d-md-none p-2" style="background: linear-gradient(90deg, #993d00, #b34700);">
|
|
||||||
<button class="btn btn-light" type="button" data-bs-toggle="offcanvas" data-bs-target="#menuMobile">
|
|
||||||
<i class="bi bi-list"></i> Menu
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Menu Offcanvas mobile -->
|
|
||||||
<div class="offcanvas offcanvas-start" tabindex="-1" id="menuMobile" style="background: linear-gradient(90deg, #993d00, #b34700); color: white;">
|
|
||||||
<div class="offcanvas-header">
|
|
||||||
<h5 class="offcanvas-title">{{ user.first_name }} {{ user.last_name }}</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
|
|
||||||
</div>
|
|
||||||
<div class="offcanvas-body">
|
|
||||||
<!-- Tu peux copier ici le même <ul> du menu principal -->
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Activités</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'deconnexion' %}" class="nav-link text-white"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<div class="alert alert-{{ message.tags }} d-flex align-items-center" role="alert">
|
|
||||||
{% if message.tags == 'success' %}
|
|
||||||
<i class="bi bi-check-circle-fill me-2"></i>
|
|
||||||
{% elif message.tags == 'warning' %}
|
|
||||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
|
||||||
{% elif message.tags == 'error' %}
|
|
||||||
<i class="bi bi-x-circle-fill me-2"></i>
|
|
||||||
{% endif %}
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Profil utilisateur</title>
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700); /* oranges plus sombres */
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.card-body p { margin-bottom: 0.5rem; }
|
|
||||||
|
|
||||||
.main {
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<!-- Main -->
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal Message Django -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">
|
|
||||||
{% if messages.0.tags == 'error' %}
|
|
||||||
Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}
|
|
||||||
Succès
|
|
||||||
{% else %}
|
|
||||||
Information
|
|
||||||
{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Icône Notification -->
|
|
||||||
<div class="notification-bell position-fixed top-0 end-0 m-3" data-bs-toggle="modal" data-bs-target="#modalNotifications" style="z-index:1050; cursor:pointer;">
|
|
||||||
<i class="bi bi-bell-fill fs-4"></i>
|
|
||||||
<span class="badge bg-danger">{{ notifications_contrats|length }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Notifications Contrats -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title"><i class="bi bi-bell me-2"></i>Contrats proches de la fin</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications_contrats %}
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for notif in notifications_contrats %}
|
|
||||||
<h5>Votre Contrat <strong>{{ notif.numero }}</strong> signé le <strong>{{ notif.date }}</strong>
|
|
||||||
se termine dans
|
|
||||||
<span class="badge bg-danger rounded-pill">{{ notif.jours_restants }} jours</span>
|
|
||||||
</h5>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted">Aucun contrat proche de la fin.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Profil -->
|
|
||||||
|
|
||||||
<div class="container py-4">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-12 col-md-10 col-lg-8">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
|
|
||||||
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
|
||||||
<h4 class="mb-0 fw-bold">
|
|
||||||
<i class="bi bi-person-circle me-2"></i> Mon Profil
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body p-3">
|
|
||||||
<!-- Infos personnelles -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Nom :</strong> {{ employe.last_name|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Prénom :</strong> {{ employe.first_name|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Matricule :</strong> {{ employe.matricule|default:"Non renseigné" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Département :</strong> {{ employe.departement|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Email :</strong> {{ employe.email|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Téléphone :</strong> {{ employe.telephone|default:"Non renseigné" }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Contrats -->
|
|
||||||
<h5 class="mt-3">Contrats</h5>
|
|
||||||
{% for contrat in contrats %}
|
|
||||||
<div class="mb-3 p-3 border rounded">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Numéro :</strong> {{ contrat.numero_contrat }}</p>
|
|
||||||
<p><strong>Type :</strong> {{ contrat.type_contrat }}</p>
|
|
||||||
<p><strong>Date début :</strong> {{ contrat.date_debut|date:"d/m/Y" }}</p>
|
|
||||||
<p><strong>Date fin :</strong> {{ contrat.date_fin|date:"d/m/Y"|default:"Non précisée" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Salaire mensuel :</strong>
|
|
||||||
{% if contrat.salaire_mensuel %}
|
|
||||||
{{ contrat.salaire_mensuel }} GNF
|
|
||||||
{% else %}
|
|
||||||
Non précisé
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p><strong>Statut :</strong>
|
|
||||||
<span class="badge
|
|
||||||
{% if contrat.statut_auto == 'Actif' %}bg-success
|
|
||||||
{% elif contrat.statut_auto == 'Terminé' %}bg-danger
|
|
||||||
{% elif contrat.statut_auto == 'Suspendu' %}bg-warning text-dark
|
|
||||||
{% else %}bg-secondary{% endif %}">
|
|
||||||
{{ contrat.statut_auto }}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p><strong>Solde congé :</strong> {{ contrat.solde_conge|default:"Non précisé" }} jours</p>
|
|
||||||
<p><strong>Fichier :</strong>
|
|
||||||
{% if contrat.fichier_contrat %}
|
|
||||||
<a href="{{ contrat.fichier_contrat.url }}" target="_blank">
|
|
||||||
<i class="bi bi-file-earmark-pdf me-1"></i> Télécharger
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted">Aucun fichier</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% empty %}
|
|
||||||
<p class="text-danger">Aucun contrat trouvé.</p>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<!-- Projets -->
|
|
||||||
<h5 class="mt-3">Projets</h5>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for a in affectations %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
|
||||||
{{ a.projet.nom_projet }} - {{ a.temps_affectation }}%
|
|
||||||
{% if a.projet.statut %}
|
|
||||||
- <span class="badge bg-info text-dark">{{ a.projet.statut }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<button type="button" class="btn bg-orange-dark btn-sm text-white"
|
|
||||||
data-bs-toggle="modal" data-bs-target="#modalFicheProjet{{ a.projet.id }}">
|
|
||||||
<i class="bi bi-info-circle"></i> Détails
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted text-center">Aucun projet assigné.</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-footer bg-white d-flex justify-content-end">
|
|
||||||
<button type="button" class="btn btn-outline-secondary me-2" onclick="window.history.back()">Fermer</button>
|
|
||||||
<a href="{% url 'profil' %}" class="btn bg-orange-dark text-white">
|
|
||||||
<i class="bi bi-pencil-square me-1"></i> Renseigner les autres informations
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% for a in affectations %}
|
|
||||||
<!-- Modal Détails Projet -->
|
|
||||||
<div class="modal fade" id="modalFicheProjet{{ a.projet.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">
|
|
||||||
<i class="bi bi-info-circle me-2"></i>Détails du projet {{ a.projet.nom_projet }}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<p><strong>Nom :</strong> {{ a.projet.nom_projet }}</p>
|
|
||||||
<p><strong>Numéro convention :</strong> {{ a.projet.numero_convention }}</p>
|
|
||||||
<p><strong>Dates :</strong> {{ a.projet.date_debut|date:"d/m/Y" }} → {{ a.projet.date_fin|date:"d/m/Y" }}</p>
|
|
||||||
<p><strong>Type :</strong> {{ a.projet.get_type_projet_display }}</p>
|
|
||||||
<p><strong>Domaine :</strong> {{ a.projet.get_domaine_recherche_display }}</p>
|
|
||||||
<p><strong>Budget :</strong> {{ a.projet.budget }} GNF</p>
|
|
||||||
<p><strong>Budget RH :</strong> {{ a.projet.budget_RH }} GNF</p>
|
|
||||||
<p><strong>Statut :</strong> <span class="badge bg-info">{{ a.projet.statut }}</span></p>
|
|
||||||
<p><strong>Description :</strong> {{ a.projet.description }}</p>
|
|
||||||
|
|
||||||
<h6 class="mt-4">Employés affectés :</h6>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for aff in a.projet.affectations.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ aff.employe }} <span class="badge bg-orange-dark">{{ aff.temps_affectation }}%</span>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun employé affecté</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h6>Bailleurs :</h6>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for f in a.projet.financements.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ f.bailleur.nom }} <span class="badge bg-success">{{ f.pourcentage }}%</span>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun bailleur enregistré</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h6 class="mt-4">Documents du projet :</h6>
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for doc in a.projet.documents.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
|
||||||
<div>
|
|
||||||
<strong>{{ doc.get_nom_document_display }}</strong><br>
|
|
||||||
pour le projet {{ a.projet.nom_projet }}<br>
|
|
||||||
{% if doc.description %}
|
|
||||||
<small class="text-muted">{{ doc.description }}</small><br>
|
|
||||||
{% endif %}
|
|
||||||
<small class="text-muted">
|
|
||||||
{% if doc.numero %}
|
|
||||||
{{ doc.numero }}
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
<br> <small></small>
|
|
||||||
document ajouter le {{ doc.date_ajout|date:"d/m/Y" }}</small>
|
|
||||||
{% if doc.date_validite %}
|
|
||||||
<br><small class="text-muted"> et Valide jusqu'au {{ doc.date_validite|date:"d/m/Y" }}</small>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun document disponible</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer bg-light">
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle me-1"></i> Fermer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
// Ferme les modales ouvertes avant d'en ouvrir une autre
|
|
||||||
const modals = document.querySelectorAll('.modal');
|
|
||||||
modals.forEach(modal => {
|
|
||||||
modal.addEventListener('show.bs.modal', function () {
|
|
||||||
document.querySelectorAll('.modal.show').forEach(openModal => {
|
|
||||||
if (openModal !== modal) {
|
|
||||||
const instance = bootstrap.Modal.getInstance(openModal);
|
|
||||||
if (instance) instance.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Répare le bug d'écran figé après fermeture
|
|
||||||
document.addEventListener('hidden.bs.modal', function () {
|
|
||||||
if (!document.querySelector('.modal.show')) {
|
|
||||||
document.body.classList.remove('modal-open');
|
|
||||||
document.body.style.removeProperty('padding-right');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const forms = document.querySelectorAll('form[action*="ajouter-document"]');
|
|
||||||
forms.forEach(form => {
|
|
||||||
form.addEventListener('submit', function (e) {
|
|
||||||
const btn = form.querySelector('button[type="submit"]');
|
|
||||||
const modalEl = form.closest('.modal');
|
|
||||||
if (btn) {
|
|
||||||
btn.disabled = true;
|
|
||||||
btn.innerHTML = '<i class="bi bi-hourglass-split"></i> Enregistrement...';
|
|
||||||
}
|
|
||||||
if (modalEl) {
|
|
||||||
const modalInstance = bootstrap.Modal.getInstance(modalEl);
|
|
||||||
if (modalInstance) modalInstance.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const messageModalEl = document.getElementById('messageModal');
|
|
||||||
if (messageModalEl) {
|
|
||||||
const messageModal = new bootstrap.Modal(messageModalEl);
|
|
||||||
messageModal.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Paramètres RH</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<!-- Main -->
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-orange-dark text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-orange-dark text-white
|
|
||||||
{% else %}bg-orange-dark text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2 class="mb-4"><i class="bi bi-gear-fill"></i> Paramètres Administration</h2>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<!-- Colonne Départements -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h5><i class="bi bi-building"></i> Départements</h5>
|
|
||||||
<button class="btn bg-orange-dark btn-sm" data-bs-toggle="modal" data-bs-target="#modalAjouterDepartement">
|
|
||||||
<i class="bi bi-plus-circle"></i> Ajouter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Ajout -->
|
|
||||||
<div class="modal fade" id="modalAjouterDepartement" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="ajouter_departement" value="1">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Ajouter un département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{{ form_departement.as_p }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn bg-orange-dark">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Liste des départements -->
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for d in departements %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ d.nom }}
|
|
||||||
<div>
|
|
||||||
<!-- Bouton détails -->
|
|
||||||
<button class="btn btn-sm btn-outline-info" data-bs-toggle="modal" data-bs-target="#modalDetailDepartement{{ d.id }}">
|
|
||||||
<i class="bi bi-eye"></i> Détails
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Bouton modification -->
|
|
||||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#modalModifierDepartement{{ d.id }}">
|
|
||||||
<i class="bi bi-pencil-square"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
|
|
||||||
<form method="POST" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="supprimer_departement" value="1">
|
|
||||||
<input type="hidden" name="departement_id" value="{{ d.id }}">
|
|
||||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('Voulez-vous vraiment supprimer ce département ?');">
|
|
||||||
<i class="bi bi-trash"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</li><!-- Modal détails -->
|
|
||||||
<div class="modal fade" id="modalDetailDepartement{{ d.id }}" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Détails du département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p><strong>Nom :</strong> {{ d.nom }}</p>
|
|
||||||
<p><strong>Chef :</strong> {% if d.chef %}{{ d.chef.first_name }} {{ d.chef.last_name }}{% else %}Non défini{% endif %}</p>
|
|
||||||
|
|
||||||
<!-- Liste des employés du département -->
|
|
||||||
{% for emp in d.employe_set.all %}
|
|
||||||
<p>- {{ emp.username }}</p>
|
|
||||||
{% empty %}
|
|
||||||
<p>Aucun employé associé</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="modalModifierDepartement{{ d.id }}" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="modifier_departement" value="1">
|
|
||||||
<input type="hidden" name="departement_id" value="{{ d.id }}">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Modifier le département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<!-- Nom du département -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="nom_{{ d.id }}" class="form-label">Nom du département</label>
|
|
||||||
<input type="text" class="form-control" id="nom_{{ d.id }}" name="nom" value="{{ d.nom }}" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sélection du chef -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="chef_{{ d.id }}" class="form-label">Chef du département</label>
|
|
||||||
<select class="form-select" id="chef_{{ d.id }}" name="chef">
|
|
||||||
<option value="">-- Aucun chef --</option>
|
|
||||||
{% for emp in employes %}
|
|
||||||
<option value="{{ emp.id }}" {% if d.chef and emp.id == d.chef.id %}selected{% endif %}>
|
|
||||||
{{ emp.first_name }} {{ emp.last_name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn bg-orange-dark">Modifier</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Colonne Groupes -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h5><i class="bi bi-person-badge-fill"></i> Groupes et rôles</h5>
|
|
||||||
<button class="btn bg-orange-dark btn-sm">Ajouter</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for g in groupes %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ g.name }}
|
|
||||||
<a href="{% url 'admin:auth_group_change' g.id %}" class="btn btn-sm btn-outline-secondary">
|
|
||||||
<i class="bi bi-pencil"></i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Tableau de Bord RH</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
h1 { font-weight: 700; }
|
|
||||||
.card { border-radius: 15px; }
|
|
||||||
.chart-container { position: relative; height: 350px; }
|
|
||||||
table { min-width: 100%; }
|
|
||||||
|
|
||||||
/* Couleurs oranges */
|
|
||||||
.bg-orange-dark { background: linear-gradient(90deg, #b35400, #cc6600); color: white; }
|
|
||||||
.bg-orange { background: #ff9f1c; color: white; }
|
|
||||||
.bg-orange-light { background: #ffc107; color: #212529; }
|
|
||||||
|
|
||||||
/* Badges */
|
|
||||||
.badge-warning { background-color: #ffc107; color: #212529; }
|
|
||||||
.badge-success { background-color: #28a745; color: #fff; }
|
|
||||||
.badge-primary { background-color: #007bff; color: #fff; }
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
body * { visibility: hidden; }
|
|
||||||
.printable-table, .printable-table * { visibility: visible; }
|
|
||||||
.printable-table { position: absolute; top: 0; left: 0; width: 100%; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid py-4">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
<h1 class="mb-5 text-center"><i class="bi bi-bar-chart-line-fill me-2"></i>Tableau de Bord RH</h1>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Filtres -->
|
|
||||||
<form method="GET" class="row g-3 mb-5">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<select name="mois" class="form-select">
|
|
||||||
<option value="">Tous les mois</option>
|
|
||||||
{% for num, nom in mois_liste %}
|
|
||||||
<option value="{{ num }}" {% if mois_selectionne == num %}selected{% endif %}>{{ nom }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<select name="departement" class="form-select">
|
|
||||||
<option value="">Tous les départements</option>
|
|
||||||
{% for d in departements %}
|
|
||||||
<option value="{{ d.id }}" {% if departement_selectionne == d.id %}selected{% endif %}>{{ d.nom }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<button type="submit" class="btn btn-outline-primary w-100"><i class="bi bi-search"></i> Filtrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Cartes statistiques -->
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-people me-2"></i>Total Employés</h6><h3 class="fw-bold">{{ total_employes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-gender-male me-2"></i>Hommes</h6><h3 class="fw-bold">{{ hommes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-gender-female me-2"></i>Femmes</h6><h3 class="fw-bold">{{ femmes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-clock-history me-2"></i>Contrats expirants(2mois)</h6><h3 class="fw-bold">{{ expirants }}</h3></div></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-header fw-bold"><i class="bi bi-airplane me-2"></i>Congés en attente</div><div class="card-body"><h5 class="display-6 fw-bold">{{ conges_attente }}</h5></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-kanban me-2"></i>Projets</h6><h6>(actifs / total)</h6><h3 class="fw-bold">{{ nb_projets_actifs }} / {{ nb_projets }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-header fw-bold"><i class="bi bi-clock-history me-2"></i>Âge moyen</div><div class="card-body"><h5 class="display-6 fw-bold">{{ age_moyen }} ans</h5></div></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Graphiques -->
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-pie-chart-fill me-2"></i> Répartition par Département</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartDepartement"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-pie-chart-fill me-2"></i> Répartition par genre</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartSexe"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-4 mb-6">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-bar-chart-fill me-2"></i> Projets (En cours / Terminés)</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartProjets"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-bar-chart-fill me-2"></i> Projets par domaine de recherche</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartDomaine"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
const couleursOrange = ['#b35400', '#ff9f1c', '#ffc107', '#ffb84d', '#ffcc80'];
|
|
||||||
const departementLabels = {{ departement_labels|safe }};
|
|
||||||
const departementCounts = {{ departement_counts|safe }};
|
|
||||||
const sexeLabels = {{ sexe_labels|safe }};
|
|
||||||
const sexeCounts = {{ sexe_counts|safe }};
|
|
||||||
const projetLabels = {{ projet_labels|safe }};
|
|
||||||
const projetCounts = {{ projet_counts|safe }};
|
|
||||||
const ticketsLabels = ["Traités", "Non traités"];
|
|
||||||
const ticketsCounts = [{{ tickets_traite }}, {{ tickets_non_traite }}];
|
|
||||||
const domaineLabels = {{ domaine_labels|safe }};
|
|
||||||
const domaineCounts = {{ domaine_counts|safe }};
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDepartement"), {
|
|
||||||
type: 'pie',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: departementLabels,
|
|
||||||
datasets: [{ data: departementCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartSexe"), {
|
|
||||||
type: 'doughnut',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: sexeLabels,
|
|
||||||
datasets: [{ data: sexeCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartProjets"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: projetLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: projetCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:16 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, ticks:{ stepSize:1, precision:0 }, title:{ display:true, text:'Nombre de projets' } },
|
|
||||||
x: { title:{ display:true, text:'' } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDomaine"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: domaineLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: domaineCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:14 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, title:{ display:true, text:'Nombre de projets' }, ticks:{ precision:0, stepSize:1 } },
|
|
||||||
x: {
|
|
||||||
ticks:{ autoSkip:false, maxRotation:100, minRotation:30, callback: function(value){ return this.getLabelForValue(value); } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btnVoirRapport').addEventListener('click', function() {
|
|
||||||
const projetId = document.getElementById('projetId').value;
|
|
||||||
if(!projetId) return alert("Veuillez sélectionner un projet.");
|
|
||||||
fetch(`/rapports/projet/${projetId}/`)
|
|
||||||
.then(resp => { if(!resp.ok) throw new Error("Projet non trouvé"); return resp.text(); })
|
|
||||||
.then(html => { document.getElementById('contenuRapportProjet').innerHTML = html; })
|
|
||||||
.catch(err => { document.getElementById('contenuRapportProjet').innerHTML = "<p class='text-danger'>Erreur lors du chargement.</p>"; console.error(err); });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Mot de passe oublié</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body class="container mt-5">
|
|
||||||
<div class="p-4 shadow-sm rounded bg-white" style="max-width: 400px; margin:auto;">
|
|
||||||
<h2 class="mb-4 text-center" style="color:rgba(255, 157, 0, 0.895);">🔑 Réinitialiser le mot de passe</h2>
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-info">{{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email">Adresse e-mail</label>
|
|
||||||
<input type="email" name="email" class="form-control" placeholder="Entrez votre email" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Envoyer le lien</button>
|
|
||||||
</form>
|
|
||||||
<p class="mt-3 text-center">
|
|
||||||
<a href="{% url 'login' %}">Retour à la connexion</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,620 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load roles %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Mes demandes</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
<style>
|
|
||||||
@keyframes pulse {
|
|
||||||
0% { transform: scale(1); }
|
|
||||||
50% { transform: scale(1.2); }
|
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #b35400, #cc6600);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<nav class="col-12 col-md-3 col-lg-2 sidebar p-3">
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main class="col px-4 py-4">
|
|
||||||
|
|
||||||
<!-- Boutons Notifications -->
|
|
||||||
{% if notifications %}
|
|
||||||
<div class="d-flex justify-content-end mb-3">
|
|
||||||
<button type="button" class="btn position-relative" data-bs-toggle="modal" data-bs-target="#modalNotifications">
|
|
||||||
<i class="bi bi-bell-fill"></i> Notifications
|
|
||||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
|
||||||
{{ notifications|length }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Bouton Notifications -->
|
|
||||||
{% if notifications_employe %}
|
|
||||||
<div class="d-flex justify-content-end mb-3">
|
|
||||||
<button type="button" class="btn position-relative" data-bs-toggle="modal" data-bs-target="#modalNotifications">
|
|
||||||
<i class="bi bi-bell-fill"></i> Notifications
|
|
||||||
<span id="badgeNotifications" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
|
||||||
{{ notifications_employe|length }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Modal Notifications -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-labelledby="modalNotificationsLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalNotificationsLabel">Mes Notifications</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications_employe %}
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for notif in notifications_employe %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ notif.message|default:"Nouvelle notification" }}
|
|
||||||
<small class="text-muted">{{ notif.date_created|date:"d/m/Y H:i" }}</small>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted">Aucune notification pour le moment.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
var modal = document.getElementById('modalNotifications');
|
|
||||||
|
|
||||||
modal.addEventListener('show.bs.modal', function () {
|
|
||||||
fetch("{% url 'notifications-lues' %}", {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'X-CSRFToken': '{{ csrf_token }}',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({})
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => {
|
|
||||||
if(data.status === "ok"){
|
|
||||||
document.getElementById('badgeNotifications').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<h1 class="mb-4">La liste des demandes de congés</h1>
|
|
||||||
<!-- Cartes Statistiques -->
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-list-check me-2"></i> Total Demandes</h6>
|
|
||||||
<p class="card-text fs-4">{{ total }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-check-circle me-2"></i> Validés</h6>
|
|
||||||
<p class="card-text fs-4">{{ valides }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-x-circle me-2"></i> Refusés</h6>
|
|
||||||
<p class="card-text fs-4">{{ refuses }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-dark ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-hourglass-split me-2"></i> En attente</h6>
|
|
||||||
<p class="card-text fs-4">{{ attentes }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-danger text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-success text-white
|
|
||||||
{% else %}bg-info text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Bouton Nouvelle Demande -->
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
||||||
<h2><i class="bi bi-people"></i> Liste</h2>
|
|
||||||
<button type="button" class="btn btn-primary mb-3" data-bs-toggle="modal" data-bs-target="#modalDemandeConge">
|
|
||||||
<i class="bi bi-calendar-plus"></i> Nouvelle demande de congé
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Nouvelle Demande -->
|
|
||||||
<div class="modal fade" id="modalDemandeConge" tabindex="-1" aria-labelledby="modalDemandeCongeLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title" id="modalDemandeCongeLabel">
|
|
||||||
<i class="bi bi-calendar-plus me-2"></i> Nouvelle demande de congé
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<fieldset class="border p-3 rounded">
|
|
||||||
<legend class="fw-bold">Informations du congé
|
|
||||||
Il vous reste {{ employe.solde_conge }} jours de congé Annuel
|
|
||||||
</legend>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.type.label_tag }} {{ form.type }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.date_debut.label_tag }} {{ form.date_debut }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.date_fin.label_tag }} {{ form.date_fin }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.nombre_jours.label_tag }} {{ form.nombre_jours }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-send"></i> Envoyer
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle"></i> Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tableau des demandes -->
|
|
||||||
<table class="table table-striped mt-2">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Employe</th>
|
|
||||||
<th>Date demande</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Date début</th>
|
|
||||||
<th>Date fin</th>
|
|
||||||
<th>Nombre jours</th>
|
|
||||||
<th>Jours restant</th>
|
|
||||||
<th>Statut</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for conge in conges %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ conge.employe.first_name }} {{ conge.employe.last_name }}</td>
|
|
||||||
|
|
||||||
<td>{{ conge.date_demande|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.type }}</td>
|
|
||||||
<td>{{ conge.date_debut|date:"d/m/Y"}}</td>
|
|
||||||
<td>{{ conge.date_fin|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.nombre_jours }}</td>
|
|
||||||
|
|
||||||
<td>{{ conge.employe.solde_conge }} </td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
{% if conge.statut == "Refusé" %}
|
|
||||||
<span class="badge bg-danger">Refusé</span>
|
|
||||||
{% elif conge.statut == "Validé directeur" %}
|
|
||||||
<span class="badge bg-success">Valide </span>
|
|
||||||
{% elif conge.statut == "Validé chef" %}
|
|
||||||
<span class="badge bg-warning">Approuvé </span>
|
|
||||||
{% elif conge.statut == "Refusé par chef" %}
|
|
||||||
<span class="badge bg-danger">Refusé </span>
|
|
||||||
{% elif conge.statut == "En attente" %}
|
|
||||||
<span class="badge bg-warning">En attente </span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-sm btn-info"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#detailsCongeModal{{ conge.id }}">
|
|
||||||
<i class="bi bi-eye"></i> Voir
|
|
||||||
</button>
|
|
||||||
{% if conge.statut == "En attente" and conge.employe == request.user %}
|
|
||||||
<!-- Bouton modifier -->
|
|
||||||
<button class="btn btn-sm btn-primary"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#modifierCongeModal{{ conge.id }}">
|
|
||||||
Modifier
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Bouton supprimer -->
|
|
||||||
<button class="btn btn-sm btn-danger"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#supprimerCongeModal{{ conge.id }}">
|
|
||||||
Supprimer
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<div class="modal fade" id="modifierCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="conge_id" value="{{ conge.id }}">
|
|
||||||
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Modifier la demande de congé</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Type de congé</label>
|
|
||||||
<select name="type" class="form-select">
|
|
||||||
<option value="Conge Annuel" {% if conge.type == "Conge Annuel" %}selected{% endif %}>Conge Annuel</option>
|
|
||||||
<option value="Maladie" {% if conge.type == "Maladie" %}selected{% endif %}>Maladie</option>
|
|
||||||
<option value="Vacances" {% if conge.type == "Vacances" %}selected{% endif %}>Vacances</option>
|
|
||||||
<option value="Maternité" {% if conge.type == "Maternité" %}selected{% endif %}>Maternité</option>
|
|
||||||
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Nombre de jours</label>
|
|
||||||
<input type="number" name="nombre_jours" class="form-control" value="{{ conge.nombre_jours }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date début</label>
|
|
||||||
<input type="date" name="date_debut" class="form-control" value="{{ conge.date_debut|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date fin</label>
|
|
||||||
<input type="date" name="date_fin" class="form-control" value="{{ conge.date_fin|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<div class="modal fade" id="detailsCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Détails de la demande</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><strong>Employé :</strong> {{ conge.employe.first_name }} {{ conge.employe.last_name }}</li>
|
|
||||||
<li class="list-group-item"><strong>Type de congé :</strong> {{ conge.type }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date début :</strong> {{ conge.date_debut|date:"d/m/Y" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date fin :</strong> {{ conge.date_fin|date:"d/m/Y" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Nombre de jours :</strong> {{ conge.nombre_jours }}</li>
|
|
||||||
<li class="list-group-item"><strong>Solde restant :</strong> {{ conge.employe.solde_conge }}</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>Statut :</strong>
|
|
||||||
{% if conge.statut == "En attente" %}
|
|
||||||
<span class="badge bg-warning text-dark">{{ conge.statut }}</span>
|
|
||||||
{% elif conge.statut == "Validé directeur" %}
|
|
||||||
<span class="badge bg-success">Validé</span>
|
|
||||||
{% elif conge.statut == "Refusé" %}
|
|
||||||
<span class="badge bg-danger">Refusé</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-secondary">{{ conge.statut }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item"><strong>Motif :</strong> {{ conge.motif_refus|default:"—" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date de la demande :</strong> {{ conge.date_demande|date:"d/m/Y H:i" }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<!-- Modal supprimer -->
|
|
||||||
<div class="modal fade" id="supprimerCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="delete_id" value="{{ conge.id }}">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Supprimer la demande</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Voulez-vous vraiment supprimer la demande de congé du
|
|
||||||
<strong>{{ conge.date_debut|date:"d/m/Y" }}</strong> au
|
|
||||||
<strong>{{ conge.date_fin|date:"d/m/Y" }}</strong> ?</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-danger">Supprimer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="10" class="text-center text-muted">Aucune demande trouvée.</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
<nav>
|
|
||||||
<ul class="pagination">
|
|
||||||
{% for page_num in conges.paginator.page_range %}
|
|
||||||
<li class="page-item {% if conges.number == page_num %}active{% endif %}">
|
|
||||||
<a class="page-link" href="?page={{ page_num }}&search={{ search }}">{{ page_num }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<!-- Modal Notifications Chef -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title"><i class="bi bi-bell-fill me-2"></i> Demandes de congé en attente</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications %}
|
|
||||||
<table class="table table-bordered table-hover">
|
|
||||||
<thead class="table-light">
|
|
||||||
<tr>
|
|
||||||
<th>Employé</th>
|
|
||||||
<th>Période</th>
|
|
||||||
<th>Jours</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for conge in notifications %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ conge.employe.first_name }} {{ conge.employe.last_name }}</td>
|
|
||||||
<td>{{ conge.date_debut|date:"d/m/Y" }} - {{ conge.date_fin|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.nombre_jours }}</td>
|
|
||||||
<td>{{ conge.type }}</td>
|
|
||||||
<td class="d-flex gap-1">
|
|
||||||
|
|
||||||
<!-- Valider -->
|
|
||||||
<form method="POST" action="{% url 'valider-par-chef' conge.id %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-success btn-sm" title="Valider">
|
|
||||||
<i class="bi bi-check-circle"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Refuser -->
|
|
||||||
<button class="btn btn-danger btn-sm btn-refuser"
|
|
||||||
data-id="{{ conge.id }}"
|
|
||||||
data-nom="{{ conge.employe.first_name }} {{ conge.employe.last_name }}"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#modalRefuserGlobal">
|
|
||||||
<i class="bi bi-x-circle"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-info">Aucune demande en attente.</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Modal Refuser -->
|
|
||||||
<div class="modal fade" id="modalRefuserGlobal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="POST" id="formRefuser">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Refuser la demande</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="texteConge"></p>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Motif du refus</label>
|
|
||||||
{{ form.motif_refus }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const modal = new bootstrap.Modal(document.getElementById('modalRefuserGlobal'));
|
|
||||||
const texteConge = document.getElementById('texteConge');
|
|
||||||
const formRefuser = document.getElementById('formRefuser');
|
|
||||||
|
|
||||||
document.querySelectorAll('.btn-refuser').forEach(button => {
|
|
||||||
button.addEventListener('click', function() {
|
|
||||||
const congeId = this.getAttribute('data-id');
|
|
||||||
const nomEmploye = this.getAttribute('data-nom');
|
|
||||||
|
|
||||||
texteConge.innerHTML = `Refuser le congé de <strong>${nomEmploye}</strong> ?`;
|
|
||||||
formRefuser.action = `/refuser-par-chef/${congeId}/`; // URL dynamique vers Django
|
|
||||||
formRefuser.reset();
|
|
||||||
modal.show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
navigator.serviceWorker.register('{% static "sw.js" %}').then(function(reg) {
|
|
||||||
console.log('Service worker registered.', reg);
|
|
||||||
}).catch(function(err) {
|
|
||||||
console.warn('Service worker registration failed:', err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -38,13 +38,7 @@ urlpatterns = [
|
|||||||
name='deconnexion'
|
name='deconnexion'
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
<<<<<<< HEAD
|
|
||||||
'gestion-employe/',
|
'gestion-employe/',
|
||||||
=======
|
|
||||||
>>>>>>> 4934b42 (Implementation de sso)
|
|
||||||
=======
|
|
||||||
'',
|
|
||||||
>>>>>>> 55e5a28 (Ajout du contexte processor)
|
|
||||||
include("gestion_employe.urls")
|
include("gestion_employe.urls")
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
|
|||||||
16
SIRH/wsgi.py
16
SIRH/wsgi.py
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
WSGI config for SIRH project.
|
|
||||||
|
|
||||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SIRH.settings')
|
|
||||||
|
|
||||||
application = get_wsgi_application()
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class GestionCongeConfig(AppConfig):
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'gestion_conge'
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from .models import Conge
|
|
||||||
|
|
||||||
class CongeForm(forms.ModelForm):
|
|
||||||
"""Formulaire de demande de congé."""
|
|
||||||
class Meta:
|
|
||||||
model = Conge
|
|
||||||
fields =['type', 'date_debut', 'date_fin']
|
|
||||||
widgets = {
|
|
||||||
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
}
|
|
||||||
|
|
||||||
labels = {
|
|
||||||
'nombre_jours':'Nombre de jours',
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
const bouton_enregistrer_detail = document.getElementById("bouton-enregistrer-detail-conge");
|
|
||||||
|
|
||||||
if(bouton_enregistrer_detail){
|
|
||||||
bouton_enregistrer_detail.addEventListener("click", () => {
|
|
||||||
const form = document.getElementById("form-detail-conge");
|
|
||||||
const csrftoken = new FormData(form).get("csrfmiddlewaretoken");
|
|
||||||
const actionUrl = form.action;
|
|
||||||
const id_conge = document.getElementById("id_conge").value;
|
|
||||||
const validation_hierarchique_input = document.querySelector('input[name="validation_hierarchique"]:checked');
|
|
||||||
const validation_hierarchique = validation_hierarchique_input ? validation_hierarchique_input.value : null;
|
|
||||||
const validation_direction_input = document.querySelector('input[name="validation_direction"]:checked');
|
|
||||||
const validation_direction = validation_direction_input ? validation_direction_input.value : null;
|
|
||||||
const motif_refus = document.getElementById("motif_refus").value;
|
|
||||||
|
|
||||||
fetch(actionUrl, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-CSRFToken": csrftoken
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
id_conge,
|
|
||||||
validation_hierarchique,
|
|
||||||
validation_direction,
|
|
||||||
motif_refus
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
alert(data.message);
|
|
||||||
navigation.reload();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(document.getElementById("validation_hierarchique_refuse")){
|
|
||||||
document.getElementById("validation_hierarchique_refuse").addEventListener('click', function(){
|
|
||||||
if(this.checked){
|
|
||||||
alert("coucou");
|
|
||||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
|
||||||
}else{
|
|
||||||
document.getElementById("motif_refus_container").className="d-none";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(document.getElementById("validation_hierarchique_refuse")){
|
|
||||||
document.getElementById("validation_hierarchique_refuse").addEventListener('click', function(){
|
|
||||||
if(this.checked){
|
|
||||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
|
||||||
}else{
|
|
||||||
document.getElementById("motif_refus_container").className="d-none";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(document.getElementById("validation_hierarchique_valide")){
|
|
||||||
document.getElementById("validation_hierarchique_valide").addEventListener('click', function(){
|
|
||||||
if(this.checked){
|
|
||||||
document.getElementById("motif_refus_container").className="d-none";
|
|
||||||
}else{
|
|
||||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if(document.getElementById("validation_direction_valide")){
|
|
||||||
document.getElementById("validation_direction_valide").addEventListener('click', function(){
|
|
||||||
if(this.checked){
|
|
||||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
|
||||||
}else{
|
|
||||||
document.getElementById("motif_refus_container").className="d-none";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<div class="modal fade" id="modalDemandeConge" tabindex="-1" aria-labelledby="modalDemandeCongeLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title" id="modalDemandeCongeLabel">
|
|
||||||
<i class="bi bi-calendar-plus me-2"></i> Nouvelle demande de congé
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" action="{% url 'gestion_conges:demande-conge' %}" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formulaire_demande_conge.as_p }}
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-send"></i> Soumettre
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle"></i> Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
<div class="modal fade" id="detailsCongeModal" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Détails de la demande de congés</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" id="form-detail-conge" action="{% url 'gestion_conges:validation-des-conges' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" id="id_conge" value="">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="motif_refus">Employé :</label>
|
|
||||||
<input type="text" class="form-control" id="employe" value="" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="type_conge">Type de congé :</label>
|
|
||||||
<select class="form-select" id="type_conge" readonly>
|
|
||||||
{% comment %} <option value="maladie">Maladie</option> {% endcomment %}
|
|
||||||
<option value="Conge Annuel">Conge Annuel</option>
|
|
||||||
{% comment %} <option value="conge_maternite">Conge Maternité</option> {% endcomment %}
|
|
||||||
{% comment %} <option value="conge_mariage">Conge Mariage</option>
|
|
||||||
<option value="conge_naissance">Conge Naissance</option>
|
|
||||||
<option value="conge_deces_proche">Conge de décès d'un proche</option>
|
|
||||||
<option value="conge_mariage_proche">Conge de mariage d'un proche</option>
|
|
||||||
<option value="autre">Autre</option> {% endcomment %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="date_debut">Date début :</label>
|
|
||||||
<input type="date" class="form-control" id="date_debut" value="" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="date_fin">Date fin :</label>
|
|
||||||
<input type="date" class="form-control" id="date_fin" value="" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="nombre_jours">Nombre de jours :</label>
|
|
||||||
<input type="number" class="form-control" id="nombre_jours" value="" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="solde_restant">Solde restant :</label>
|
|
||||||
<input type="number" class="form-control" id="solde_restant" value="" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label for="date_demande">Date de la demande :</label>
|
|
||||||
<input type="text" class="form-control" id="date_demande" value="" readonly>
|
|
||||||
</div>
|
|
||||||
{% if employe_est_il_chef or est_chef_projet %}
|
|
||||||
<hr>
|
|
||||||
<h5 class="text-center">Validation par le supérieur hiérarchique</h5>
|
|
||||||
<div class="d-flex align-items-center justify-content-center mb-2">
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" type="radio" name="validation_hierarchique" id="validation_hierarchique_valide" value="valide">
|
|
||||||
<label class="form-check-label" for="validation_hierarchique_valide">Valide</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" type="radio" name="validation_hierarchique" id="validation_hierarchique_refuse" value="refuse" {% if conge.validation_hierarchique == False %}checked{% endif %}>
|
|
||||||
<label class="form-check-label" for="validation_hierarchique_refuse">Refusé</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if membre_de_la_direction %}
|
|
||||||
<hr>
|
|
||||||
<h5 class="text-center">Validation par le directeur</h5>
|
|
||||||
<div class="d-flex align-items-center justify-content-center mb-2">
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" type="radio" name="validation_direction" id="validation_direction_valide" value="valide" {% if conge.validation_direction == True %}checked{% endif %}>
|
|
||||||
<label class="form-check-label" for="validation_direction_valide">Valide</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<input class="form-check-input" type="radio" name="validation_direction" id="validation_direction_refuse" value="refuse" {% if conge.validation_direction == False %}checked{% endif %}>
|
|
||||||
<label class="form-check-label" for="validation_direction_refuse">Refusé</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<hr>
|
|
||||||
<div class="d-none form-group mt-3" id="motif_refus_container">
|
|
||||||
<label for="motif_refus">Motif de refus (si applicable) :</label>
|
|
||||||
<textarea class="form-control" id="motif_refus" rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
{% if employe_est_il_chef or membre_de_la_direction or est_chef_projet %}
|
|
||||||
<button type="button" class="btn btn-success" id="bouton-enregistrer-detail-conge">Enregistrer</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{% for conge in conges %}
|
|
||||||
<div class="modal fade" id="modifierCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="conge_id" value="{{ conge.id }}">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Modifier la demande de congé</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Type de congé</label>
|
|
||||||
<select name="type" class="form-select">
|
|
||||||
<option value="Conge Annuel" {% if conge.type == "Conge Annuel" %}selected{% endif %}>Conge Annuel</option>
|
|
||||||
<option value="Maladie" {% if conge.type == "Maladie" %}selected{% endif %}>Maladie</option>
|
|
||||||
<option value="Conge maternité" {% if conge.type == "Conge maternité" %}selected{% endif %}>Conge Maternité</option>
|
|
||||||
<option value="Conge de Mariage" {% if conge.type == "Conge de Mariage" %}selected{% endif %}>Conge Mariage</option>
|
|
||||||
<option value="conge de naissance" {% if conge.type == "conge de naissance" %}selected{% endif %}>Conge de Naissance</option>
|
|
||||||
<option value="conge de deces dun proche" {% if conge.type == "conge de deces dun proche" %}selected{% endif %}>Conge de décès d'un proche</option>
|
|
||||||
<option value="conge de mariage dun proche" {% if conge.type == "conge de mariage dun proche" %}selected{% endif %}>Conge de mariage d'un proche</option>
|
|
||||||
<option value="conge pour evenements familiaux" {% if conge.type == "conge pour evenements familiaux" %}selected{% endif %}>Conge pour événements familiaux</option>
|
|
||||||
<option value="Autre" {% if conge.type == "Autre" %}selected{% endif %}>Autre</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Nombre de jours</label>
|
|
||||||
<input type="number" name="nombre_jours" class="form-control" value="{{ conge.nombre_jours }}">
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date début</label>
|
|
||||||
<input type="date" name="date_debut" class="form-control" value="{{ conge.date_debut|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date fin</label>
|
|
||||||
<input type="date" name="date_fin" class="form-control" value="{{ conge.date_fin|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn bg-orange-dark">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<div class="modal fade" id="modalRefuserGlobal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="POST" id="formRefuser">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Refuser la demande</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="texteConge"></p>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Motif du refus</label>
|
|
||||||
{{ form.motif_refus }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
app_name = "gestion_conges"
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path(
|
|
||||||
'',
|
|
||||||
views.index,
|
|
||||||
name='conge'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'demande_conge/',
|
|
||||||
views.demander_conge,
|
|
||||||
name='demande-conge'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'liste-des-conges/',
|
|
||||||
views.liste_demande_conges,
|
|
||||||
name='liste-des-conges'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'validation-des-conges/',
|
|
||||||
views.validation_de_conge,
|
|
||||||
name='validation-des-conges'
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import Departement, Employe
|
|
||||||
|
|
||||||
@admin.register(Departement)
|
|
||||||
class DepartementAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ("nom", )
|
|
||||||
|
|
||||||
@admin.register(Employe)
|
|
||||||
class EmployeAdmin(admin.ModelAdmin):
|
|
||||||
list_display = (
|
|
||||||
"user",
|
|
||||||
"matricule",
|
|
||||||
"fonction",
|
|
||||||
)
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from .models import Contrat, Departement, Employe,Affectation,Formation
|
|
||||||
|
|
||||||
class EmployeForm(forms.ModelForm):
|
|
||||||
"""Formulaire pour modifier les informations de profil d'un employé"""
|
|
||||||
class Meta:
|
|
||||||
model = Employe
|
|
||||||
fields = (
|
|
||||||
'adresse',
|
|
||||||
'telephone',
|
|
||||||
'CV',
|
|
||||||
'diplome',
|
|
||||||
'rib',
|
|
||||||
'photo',
|
|
||||||
'casier_judiciaire'
|
|
||||||
)
|
|
||||||
|
|
||||||
class AffectationForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Affectation
|
|
||||||
fields = (
|
|
||||||
'projet',
|
|
||||||
'date_affectation',
|
|
||||||
'date_fin_daffectation',
|
|
||||||
'role',
|
|
||||||
'pourcentage_temps_affectation'
|
|
||||||
)
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'projet': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
'date_affectation': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
|
||||||
'date_fin_daffectation': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
|
||||||
'role': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
'pourcentage_temps_affectation': forms.NumberInput(attrs={'class': 'form-control'}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContratForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Contrat
|
|
||||||
fields = [
|
|
||||||
"numero_contrat",
|
|
||||||
"type_contrat",
|
|
||||||
"date_debut",
|
|
||||||
"date_fin",
|
|
||||||
"salaire_mensuel",
|
|
||||||
"statut",
|
|
||||||
"fichier_contrat"
|
|
||||||
]
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'numero_contrat': forms.TextInput(attrs={'class': 'form-control'}),
|
|
||||||
'type_contrat': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
'date_debut': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
|
||||||
'date_fin': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
|
||||||
'salaire_mensuel': forms.TextInput(attrs={'class': 'form-control'}),
|
|
||||||
'statut': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
'fichier_contrat': forms.FileInput(attrs={'class': 'form-control'}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class DepartementForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Departement
|
|
||||||
fields = ['nom']
|
|
||||||
|
|
||||||
class FormationForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Formation
|
|
||||||
fields = [
|
|
||||||
'titre',
|
|
||||||
'organisme',
|
|
||||||
'date_obtention',
|
|
||||||
'date_fin',
|
|
||||||
'description',
|
|
||||||
'certificat'
|
|
||||||
]
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'titre': forms.TextInput(attrs={"class": "form-control"}),
|
|
||||||
'organisme': forms.TextInput(attrs={"class": "form-control"}),
|
|
||||||
'date_obtention': forms.DateInput(attrs={"class": "form-control", "type": "date"}),
|
|
||||||
'date_fin': forms.DateInput(attrs={"class": "form-control", "type": "date"}),
|
|
||||||
'description': forms.Textarea(attrs={"class": "form-control"}),
|
|
||||||
'certificat': forms.FileInput(attrs={"class": "form-control"}),
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
{% extends "BASE.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% block 'titre_page' %} Gestion des employés - Mon profil {% endblock %}
|
|
||||||
{% block 'contenu' %}
|
|
||||||
<div class="card shadow-sm border-0 w-100" style="max-width: 850px;">
|
|
||||||
<div class="card-header bg-orange-dark">
|
|
||||||
<h5 class="mb-0 fw-bold">
|
|
||||||
<i class="bi bi-pencil-square me-2"></i> Modifier mon profil
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<form method="POST" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="accordion" id="accordionProfil">
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="headingInfo">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseInfo" aria-expanded="false" aria-controls="collapseInfo">
|
|
||||||
<i class="bi bi-person-lines-fill me-2"></i> Informations personnelles
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseInfo" class="accordion-collapse collapse" aria-labelledby="headingInfo" data-bs-parent="#accordionProfil">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Photo de profil :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Prénom :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Nom :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Email :</label>
|
|
||||||
<input type="email" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Téléphone :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Adresse :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="headingDocs">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDocs" aria-expanded="false" aria-controls="collapseDocs">
|
|
||||||
<i class="bi bi-file-earmark-text me-2"></i> Documents
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseDocs" class="accordion-collapse collapse" aria-labelledby="headingDocs" data-bs-parent="#accordionProfil">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>CV :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Diplome :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>RIB :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Casier judiciaire :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex justify-content-end mt-4 gap-2 flex-wrap">
|
|
||||||
<a href="{% url 'gestion_employe:mon-profil' %}" class="btn btn-outline-secondary">
|
|
||||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
|
||||||
</a>
|
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'modal' %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'js' %}
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAffectation" tabindex="-1" aria-labelledby="modalAffectationLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog ">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title" id="modalAffectationLabel" >
|
|
||||||
Affectation de projet (<span id="affectation-nom-employe"></span>)
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal">
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form action="{% url 'gestion_employe:affecter_employe_projet' %}" method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="affecter_employe_id" id="affecter_employe_id">
|
|
||||||
{{ affectation_form.as_p }}
|
|
||||||
<div class="modal-footer bg-light">
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-check-circle"></i> affecter
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAjouterFormation" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Ajouter un certificat</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" action="{% url 'gestion_employe:ajouter_formation' %}" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formation_form.as_p }}
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-success">Enregistrer</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
<div class="modal fade" id="modalContrat" tabindex="-1" aria-labelledby="modalContratLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog ">
|
|
||||||
<div class="modal-content bg-white">
|
|
||||||
<div class="modal-header ">
|
|
||||||
<h5 class="modal-title" id="modalContratLabel">
|
|
||||||
<i class="bi bi-file-earmark-text me-2"></i>
|
|
||||||
Contrat de <span id="contrat-employe"></span>
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form action="{% url 'gestion_employe:creation-contrat' %}" method="POST" id="contrat_form" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="employe_id" value="" id="employeIdInput">
|
|
||||||
{{ contrat_form.as_p }}
|
|
||||||
<div class="modal-footer bg-light">
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% comment %} <fieldset class="border p-3 mb-4">
|
|
||||||
<legend class="fw-bold mb-3 text-muted">Informations du contrat</legend>
|
|
||||||
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Numero de contrat :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Type contrat :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>date de début :</label>
|
|
||||||
<input type="date" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>date de fin :</label>
|
|
||||||
<input type="date" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Salaire mensuel :</label>
|
|
||||||
<input type="text" class="form-control">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Fichier du contrat :</label>
|
|
||||||
<input type="file" class="form-control">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset> {% endcomment %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<div class="modal fade" id="modalDocuments" tabindex="-1" aria-labelledby="modalDocumentsLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog ">
|
|
||||||
<div class="modal-content border-0 shadow-lg">
|
|
||||||
<div class="modal-header ">
|
|
||||||
<h5 class="modal-title" id="modalDocumentsLabel">
|
|
||||||
<i class="bi bi-folder2-open me-2"></i> Documents RH de <span id="document-employe"></span>
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col">
|
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>Diplôme :</strong>
|
|
||||||
<a id="document-diplome" target="_blank"></a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>CV :</strong>
|
|
||||||
<a id="document-cv" target="_blank"></a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>RIB :</strong>
|
|
||||||
<a id="document-rib" target="_blank"></a>
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>Casier judiciaire :</strong>
|
|
||||||
<a id="document-casier-judiciaire" target="_blank"></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer bg-light">
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle"></i> Fermer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<div class="modal fade" id="modalListeDesContratExpirants" tabindex="-1">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Contrats expirants dans un maximum de 60 jours</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id='listeContratExpirant'></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<div class="modal fade" id="modalModifierProfil" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title"><i class="bi bi-person-lines-fill me-2"></i> Modifier le mot de passe</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="POST" action="{% url 'gestion_employe:modifier-mot-passe' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Votre mot de passe actuel :</label>
|
|
||||||
<input class="form-control" type="password" name="ancien-mdp">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Votre nouveau mot de passe :</label>
|
|
||||||
<input class="form-control" type="password" name="nouveau-mdp">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Confirmez votre nouveau mot de passe :</label>
|
|
||||||
<input class="form-control" type="password" name="confirmation-mdp">
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
||||||
Fermer
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
"""Tags personnalisés pour les templates d'authentification.
|
|
||||||
|
|
||||||
Ce fichier contient des tags personnalisés pour les templates du projet lié à
|
|
||||||
la gestion de l'accès des utilisateurs aux différentes pages.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django import template
|
|
||||||
from django.utils import timezone
|
|
||||||
from gestion_employe.models import Affectation
|
|
||||||
|
|
||||||
register = template.Library()
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def has_group(user, group_name):
|
|
||||||
"""Vérifiez si un utilisateur appartient à un groupe spécifique."""
|
|
||||||
return user.groups.filter(name=group_name).exists()
|
|
||||||
|
|
||||||
@register.filter
|
|
||||||
def is_chef_projet(user):
|
|
||||||
try:
|
|
||||||
affectation = Affectation.objects.get(employe__user__username = user, date_fin_daffectation__gte = timezone.now().date())
|
|
||||||
except Affectation.DoesNotExist:
|
|
||||||
return False
|
|
||||||
return affectation.role == "chef_projet"
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -211,10 +211,6 @@ def modifier_employer(request):
|
|||||||
except Employe.DoesNotExist:
|
except Employe.DoesNotExist:
|
||||||
return JsonResponse({"message": "Employé non trouvé."})
|
return JsonResponse({"message": "Employé non trouvé."})
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
<<<<<<< HEAD
|
|
||||||
data = request.POST
|
|
||||||
=======
|
|
||||||
>>>>>>> 8c6e59e (Correction enregistrement profil)
|
|
||||||
user = User.objects.get(username=request.user)
|
user = User.objects.get(username=request.user)
|
||||||
user.last_name = request.POST['nom']
|
user.last_name = request.POST['nom']
|
||||||
user.first_name = request.POST['prenom']
|
user.first_name = request.POST['prenom']
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
from .models import DomaineDeRecherche
|
|
||||||
|
|
||||||
@admin.register(DomaineDeRecherche)
|
|
||||||
class DomaineDeRecherche(admin.ModelAdmin):
|
|
||||||
list_display = ('nom',)
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from gestion_projet.models import Projet
|
|
||||||
from .models import (
|
|
||||||
ActiviteProjet,
|
|
||||||
Bailleur,
|
|
||||||
DocumentProjet,
|
|
||||||
FinancementProjet,
|
|
||||||
LivrablesLivres,
|
|
||||||
DomaineDeRecherche
|
|
||||||
)
|
|
||||||
|
|
||||||
class ProjetForm(forms.ModelForm):
|
|
||||||
"""Formulaire de création et de modification d'un projet, avec validation des dates et personnalisation des champs."""
|
|
||||||
class Meta:
|
|
||||||
model = Projet
|
|
||||||
fields = (
|
|
||||||
'id_projet',
|
|
||||||
'nom_projet',
|
|
||||||
'date_debut',
|
|
||||||
'date_fin',
|
|
||||||
'numero_convention',
|
|
||||||
'domaine_recherche',
|
|
||||||
'type_projet',
|
|
||||||
'budget',
|
|
||||||
'budget_RH',
|
|
||||||
'description'
|
|
||||||
)
|
|
||||||
# domaine_recherche = forms.ModelMultipleChoiceField(
|
|
||||||
# queryset=DomaineDeRecherche.objects.all(),
|
|
||||||
# to_field_name="nom",
|
|
||||||
# required=False
|
|
||||||
# )
|
|
||||||
widgets = {
|
|
||||||
'id_projet': forms.TextInput(attrs={'class': "form-control"}),
|
|
||||||
'nom_projet': forms.TextInput(attrs={'class': "form-control"}),
|
|
||||||
'numero_convention': forms.TextInput(attrs={'class': "form-control"}),
|
|
||||||
'domaine_recherche': forms.SelectMultiple(attrs={'class': "form-control"}),
|
|
||||||
'type_projet': forms.Select(attrs={'class': "form-select"}),
|
|
||||||
'budget': forms.NumberInput(attrs={'class': "form-control"}),
|
|
||||||
'budget_RH': forms.NumberInput(attrs={'class': "form-control"}),
|
|
||||||
'description': forms.Textarea(attrs={'class': "form-control"}),
|
|
||||||
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': "form-control"}),
|
|
||||||
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': "form-control"}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class BailleurForm(forms.ModelForm):
|
|
||||||
"""
|
|
||||||
Formulaire de création et de modification d'un bailleur,
|
|
||||||
avec validation des champs et personnalisation des labels.
|
|
||||||
"""
|
|
||||||
class Meta:
|
|
||||||
model = Bailleur
|
|
||||||
fields = ('nom_organisme', 'contact', 'email', 'pays')
|
|
||||||
widgets = {
|
|
||||||
'nom_organisme':forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
'contact':forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
'email':forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
'pays':forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class DocumentProjetForm(forms.ModelForm):
|
|
||||||
"""
|
|
||||||
Formulaire pour ajouter ou modifier un document associé à un projet,
|
|
||||||
avec validation des champs et personnalisation des labels.
|
|
||||||
"""
|
|
||||||
class Meta:
|
|
||||||
model = DocumentProjet
|
|
||||||
fields = [
|
|
||||||
'nom_document',
|
|
||||||
'numero',
|
|
||||||
'date_validite',
|
|
||||||
'fichier',
|
|
||||||
'description'
|
|
||||||
]
|
|
||||||
widgets = {
|
|
||||||
'nom_document': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
|
|
||||||
'numero': forms.TextInput(attrs={'class': 'form-control'}),
|
|
||||||
'date_validite': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
|
||||||
'fichier': forms.ClearableFileInput(attrs={'class': 'form-control'}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class ActiviteProjetForm(forms.ModelForm):
|
|
||||||
"""Formulaire pour créer ou modifier une activité de projet, avec validation des champs et personnalisation des widgets."""
|
|
||||||
class Meta:
|
|
||||||
model = ActiviteProjet
|
|
||||||
fields = (
|
|
||||||
'titre',
|
|
||||||
'date_debut',
|
|
||||||
'date_fin',
|
|
||||||
'besoin_ressource_materielle',
|
|
||||||
'budget_prevu',
|
|
||||||
'description',
|
|
||||||
)
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'titre':forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'placeholder':'Titre de l’activité'
|
|
||||||
}),
|
|
||||||
'description':forms.Textarea(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'rows':3,
|
|
||||||
'placeholder':'Description de l’activité'
|
|
||||||
}),
|
|
||||||
'date_debut':forms.DateInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'type':'date'
|
|
||||||
}),
|
|
||||||
'date_fin':forms.DateInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'type':'date'
|
|
||||||
}),
|
|
||||||
'besoin_ressource_materielle': forms.Textarea(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'rows':3,
|
|
||||||
'placeholder':'Besoin de ressources matérielles'
|
|
||||||
}),
|
|
||||||
'budget_prevu': forms.NumberInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'placeholder':'Budget prévu'
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class FinancementProjetFrom(forms.ModelForm):
|
|
||||||
"""Formulaire pour créer ou modifier le financement relatif à un projet."""
|
|
||||||
class Meta:
|
|
||||||
model = FinancementProjet
|
|
||||||
fields = (
|
|
||||||
'projet',
|
|
||||||
'bailleur',
|
|
||||||
'pourcentage',
|
|
||||||
)
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'projet':forms.Select(attrs={
|
|
||||||
'class':'form-select',
|
|
||||||
}),
|
|
||||||
'bailleur':forms.Select(attrs={
|
|
||||||
'class':'form-select',
|
|
||||||
}),
|
|
||||||
'pourcentage':forms.NumberInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
class LivrablesLivresForm(forms.ModelForm):
|
|
||||||
"""Formulaire pour créer ou modifier un livrable livré dans le cadre d'une activité de projet."""
|
|
||||||
class Meta:
|
|
||||||
model = LivrablesLivres
|
|
||||||
fields = (
|
|
||||||
'activite',
|
|
||||||
'nom',
|
|
||||||
'fichier',
|
|
||||||
)
|
|
||||||
|
|
||||||
widgets = {
|
|
||||||
'activite': forms.Select(attrs={
|
|
||||||
'class':'form-select',
|
|
||||||
}),
|
|
||||||
'nom': forms.TextInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
'placeholder':'Nom du livrable'
|
|
||||||
}),
|
|
||||||
'fichier': forms.ClearableFileInput(attrs={
|
|
||||||
'class':'form-control',
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
@@ -1,309 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
from datetime import date
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
class Bailleur(models.Model):
|
|
||||||
"""Modèle représentant un bailleur de fonds pour les projets de recherche."""
|
|
||||||
nom_organisme = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
contact = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
email = models.EmailField(
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
pays = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.nom_organisme
|
|
||||||
|
|
||||||
class DomaineDeRecherche(models.Model):
|
|
||||||
"""Modèle représentant les domaines de recherche"""
|
|
||||||
|
|
||||||
DOMAINE_RECHERCHE = [
|
|
||||||
('sciences_sociales', 'Sciences sociales'),
|
|
||||||
('naturelles', 'Naturelles'),
|
|
||||||
('humaines', 'Humaines'),
|
|
||||||
('veterinaires', 'Vétérinaires')
|
|
||||||
]
|
|
||||||
|
|
||||||
nom = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
verbose_name="Domaine de recherche",
|
|
||||||
choices=DOMAINE_RECHERCHE,
|
|
||||||
primary_key=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name = 'Domaine de recherche'
|
|
||||||
verbose_name_plural = 'Domaines de recherche'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.nom
|
|
||||||
|
|
||||||
class Projet(models.Model):
|
|
||||||
"""Modèle représentant un projet de recherche avec ses caractéristiques et son bailleur associé."""
|
|
||||||
TYPE_PROJET = [
|
|
||||||
('laboratoire', 'Laboratoire'),
|
|
||||||
('épidémiologie', 'Épidémiologie'),
|
|
||||||
('sciences sociales', 'Sciences sociales'),
|
|
||||||
('cliniques', 'Cliniques'),
|
|
||||||
('autre', 'Autre'),
|
|
||||||
]
|
|
||||||
id_projet = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
unique=True,
|
|
||||||
primary_key=True,
|
|
||||||
verbose_name="ID du projet"
|
|
||||||
)
|
|
||||||
nom_projet = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
verbose_name="Nom du projet"
|
|
||||||
)
|
|
||||||
date_debut = models.DateField(
|
|
||||||
verbose_name="Date de début"
|
|
||||||
)
|
|
||||||
date_fin = models.DateField(
|
|
||||||
verbose_name="Date de fin"
|
|
||||||
)
|
|
||||||
numero_convention = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
verbose_name="Numéro de convention"
|
|
||||||
)
|
|
||||||
description = models.TextField(
|
|
||||||
verbose_name="Description"
|
|
||||||
)
|
|
||||||
type_projet = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
choices=TYPE_PROJET,
|
|
||||||
default='épidémiologie',
|
|
||||||
verbose_name="Type de projet"
|
|
||||||
)
|
|
||||||
domaine_recherche = models.ManyToManyField(DomaineDeRecherche)
|
|
||||||
budget=models.DecimalField(
|
|
||||||
max_digits=12,
|
|
||||||
decimal_places=2,
|
|
||||||
verbose_name="Budget"
|
|
||||||
)
|
|
||||||
budget_RH = models.DecimalField(
|
|
||||||
max_digits=12,
|
|
||||||
decimal_places=2,
|
|
||||||
verbose_name="Budget RH"
|
|
||||||
)
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
bailleur = models.ForeignKey(
|
|
||||||
Bailleur,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
verbose_name="Bailleur de fonds"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def statut(self):
|
|
||||||
if self.date_fin < date.today():
|
|
||||||
return "Terminé"
|
|
||||||
return "En cours"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def avancement(self):
|
|
||||||
aujourd_hui = date.today()
|
|
||||||
if (self.date_debut and self.date_fin) and (self.date_debut < self.date_fin):
|
|
||||||
duree_projet = (self.date_fin - self.date_debut).days
|
|
||||||
temps_ecoule = (aujourd_hui - self.date_debut).days
|
|
||||||
if duree_projet > 0:
|
|
||||||
return round((temps_ecoule / duree_projet) * 100, 2)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.nom_projet}"
|
|
||||||
|
|
||||||
class FinancementProjet(models.Model):
|
|
||||||
"""
|
|
||||||
Modèle représentant le financement d'un projet par un bailleur,
|
|
||||||
avec le pourcentage de contribution.
|
|
||||||
"""
|
|
||||||
projet = models.ForeignKey(
|
|
||||||
Projet,
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
bailleur = models.ForeignKey(
|
|
||||||
Bailleur,
|
|
||||||
on_delete=models.CASCADE
|
|
||||||
)
|
|
||||||
pourcentage = models.DecimalField(
|
|
||||||
max_digits = 5,
|
|
||||||
decimal_places=2
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
unique_together = ('projet', 'bailleur')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.bailleur.nom} - {self.projet.nom_projet} ({self.pourcentage}%)"
|
|
||||||
|
|
||||||
class DocumentProjet(models.Model):
|
|
||||||
"""Modèle représentant un document associé à un projet, avec des métadonnées et un fichier attaché."""
|
|
||||||
NOM_DOCUMENT_CHOICES = [
|
|
||||||
('protocole', 'Protocole d’étude'),
|
|
||||||
('ethique', "Approbation du comité d'éthique"),
|
|
||||||
('autorisation', 'Autorisation (DNLP)'),
|
|
||||||
('rapport_technique', 'Rapport technique'),
|
|
||||||
('rapport_financier', 'Rapport financier'),
|
|
||||||
('rapport_avancement', "Rapport d'avancement"),
|
|
||||||
('convention', 'Convention'),
|
|
||||||
('rapport_final', 'Rapport final'),
|
|
||||||
('autre', 'Autre'),
|
|
||||||
]
|
|
||||||
|
|
||||||
projet = models.ForeignKey(
|
|
||||||
Projet,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='documents',
|
|
||||||
verbose_name="Projet"
|
|
||||||
)
|
|
||||||
date_ajout = models.DateTimeField(
|
|
||||||
auto_now_add=True,
|
|
||||||
verbose_name="Date d'ajout"
|
|
||||||
)
|
|
||||||
nom_document = models.CharField(
|
|
||||||
max_length = 100,
|
|
||||||
choices = NOM_DOCUMENT_CHOICES,
|
|
||||||
verbose_name="Type de document"
|
|
||||||
)
|
|
||||||
description = models.TextField(
|
|
||||||
blank = True,
|
|
||||||
verbose_name = "Description"
|
|
||||||
)
|
|
||||||
numero = models.CharField(
|
|
||||||
max_length = 100,
|
|
||||||
blank = True,
|
|
||||||
null = True,
|
|
||||||
verbose_name = "Numéro du document"
|
|
||||||
)
|
|
||||||
date_validite = models.DateField(
|
|
||||||
blank = True,
|
|
||||||
null = True,
|
|
||||||
verbose_name = "Date de validité"
|
|
||||||
)
|
|
||||||
fichier = models.FileField(
|
|
||||||
upload_to = 'documents_projets/',
|
|
||||||
verbose_name = "Fichier à télécharger"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.nom_document} ({self.projet})"
|
|
||||||
|
|
||||||
class ActiviteProjet(models.Model):
|
|
||||||
"""Modèle représentant le planning d'un projet, avec des activités associées et un statut."""
|
|
||||||
projet = models.ForeignKey(
|
|
||||||
Projet,
|
|
||||||
on_delete = models.CASCADE,
|
|
||||||
verbose_name = "Projet"
|
|
||||||
)
|
|
||||||
titre = models.CharField(
|
|
||||||
max_length = 200,
|
|
||||||
verbose_name = "Titre de l'activité"
|
|
||||||
)
|
|
||||||
description = models.TextField(
|
|
||||||
blank = True,
|
|
||||||
null = True,
|
|
||||||
verbose_name = "Description de l'activité"
|
|
||||||
)
|
|
||||||
date_debut = models.DateField(verbose_name="Date de début")
|
|
||||||
date_fin = models.DateField(verbose_name="Date de fin")
|
|
||||||
annuler = models.BooleanField(
|
|
||||||
default = False,
|
|
||||||
verbose_name = "Annuler l'activité"
|
|
||||||
)
|
|
||||||
motif_annulation = models.TextField(
|
|
||||||
blank = True,
|
|
||||||
null = True,
|
|
||||||
verbose_name = "Motif d'annulation"
|
|
||||||
)
|
|
||||||
|
|
||||||
motif_changement_budget = models.TextField(
|
|
||||||
blank = True,
|
|
||||||
null = True,
|
|
||||||
verbose_name = "Motif de changement de budget"
|
|
||||||
)
|
|
||||||
budget_prevu = models.DecimalField(
|
|
||||||
max_digits = 15,
|
|
||||||
decimal_places = 2,
|
|
||||||
default = 0,
|
|
||||||
verbose_name = "Budget prévu"
|
|
||||||
)
|
|
||||||
budget_depense = models.DecimalField(
|
|
||||||
max_digits = 15,
|
|
||||||
decimal_places = 2,
|
|
||||||
default = 0,
|
|
||||||
verbose_name = "Budget dépensé"
|
|
||||||
)
|
|
||||||
besoin_ressource_materielle = models.TextField(
|
|
||||||
verbose_name="Besoin de ressources matérielles"
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def statut(self):
|
|
||||||
today = timezone.now().date()
|
|
||||||
if not self.annuler:
|
|
||||||
if self.date_fin < today:
|
|
||||||
return 'Terminé'
|
|
||||||
elif self.date_debut > today:
|
|
||||||
return 'À venir'
|
|
||||||
else:
|
|
||||||
return 'En cours'
|
|
||||||
else:
|
|
||||||
return 'Annulé'
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"{self.titre} ({self.projet.nom_projet})"
|
|
||||||
|
|
||||||
# class LivrableAttendu(models.Model):
|
|
||||||
# """
|
|
||||||
# Modèle représentant un livrable attendu pour une activité de projet,
|
|
||||||
# avec des critères de validation.
|
|
||||||
# """
|
|
||||||
# activite = models.ForeignKey(
|
|
||||||
# ActiviteProjet,
|
|
||||||
# on_delete = models.CASCADE,
|
|
||||||
# related_name = "livrables_attendus"
|
|
||||||
# )
|
|
||||||
# nom = models.CharField(max_length=255)
|
|
||||||
|
|
||||||
# def __str__(self):
|
|
||||||
# return f"{self.nom} (Activité: {self.activite.titre})"
|
|
||||||
|
|
||||||
class LivrablesLivres(models.Model):
|
|
||||||
"""Modèle représentant un livrable livré pour une activité de projet."""
|
|
||||||
activite = models.ForeignKey(
|
|
||||||
ActiviteProjet,
|
|
||||||
on_delete = models.CASCADE
|
|
||||||
)
|
|
||||||
# nom = models.ForeignKey(
|
|
||||||
# LivrableAttendu,
|
|
||||||
# on_delete = models.CASCADE
|
|
||||||
# )
|
|
||||||
nom = models.CharField(
|
|
||||||
max_length=255,
|
|
||||||
verbose_name="Nom du livrable"
|
|
||||||
)
|
|
||||||
|
|
||||||
fichier = models.FileField(
|
|
||||||
upload_to = 'fichier_livrables/',
|
|
||||||
blank = True,
|
|
||||||
null = True
|
|
||||||
)
|
|
||||||
def __str__(self):
|
|
||||||
return self.nom
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const boutonEnregistrerProjet = $("btnEnregistrerProjet");
|
|
||||||
|
|
||||||
boutonEnregistrerProjet.addEventListener("click", function() {
|
|
||||||
const formulaire = $("formCreationProjet");
|
|
||||||
const formData = new FormData(formulaire);
|
|
||||||
fetch(formulaire.action, {
|
|
||||||
method: "POST",
|
|
||||||
body: formData,
|
|
||||||
headers: {
|
|
||||||
"X-CSRFToken": formData.get("csrfmiddlewaretoken")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) {
|
|
||||||
window.location.reload();
|
|
||||||
alert("Projet enregistré avec succès !");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
const btn_enregistrer_financement = document.getElementById('btn_enregistrer_financement');
|
|
||||||
|
|
||||||
btn_enregistrer_financement.addEventListener('click', function() {
|
|
||||||
const form = document.getElementById('form_financement');
|
|
||||||
const formData = new FormData(form);
|
|
||||||
fetch(form.action, {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData,
|
|
||||||
headers: {
|
|
||||||
'X-CSRFToken': formData.get('csrfmiddlewaretoken')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.success) {
|
|
||||||
alert(data.message);
|
|
||||||
window.location.reload();
|
|
||||||
}else {
|
|
||||||
alert(data.message);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
const $ = (element) => document.getElementById(element)
|
|
||||||
const url_liste_projet = $("tableau-liste-projet").dataset.url;
|
|
||||||
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
|
|
||||||
fitColumns: true,
|
|
||||||
responsiveLayout : true,
|
|
||||||
columns: [
|
|
||||||
{title: "Projet", field: "nom_projet"},
|
|
||||||
{title: "Source de financement", field: "source_financement"},
|
|
||||||
{title: "Budget Total", field: "budget"},
|
|
||||||
{title: "Budget RH", field: "budget_RH"},
|
|
||||||
{title: "Avancement", field: "avancement", formatter: "progress"},
|
|
||||||
{title: "Statut", field: "statut"},
|
|
||||||
],
|
|
||||||
ajaxURL: url_liste_projet
|
|
||||||
})
|
|
||||||
|
|
||||||
const employes_affectes_projet = new Tabulator("#employes_affectes_projet", {
|
|
||||||
columns: [
|
|
||||||
{title: "Employé", field: "employe"},
|
|
||||||
{title: "Pourcentage d'affectation", field: "pourcentage_affectation"},
|
|
||||||
],
|
|
||||||
placeholder: "Aucun employé affecté pour ce projet",
|
|
||||||
})
|
|
||||||
|
|
||||||
const bailleurs_projet = new Tabulator("#bailleurs_projet", {
|
|
||||||
columns: [
|
|
||||||
{title: "Bailleur", field: "bailleur"},
|
|
||||||
{title: "Pourcentage de financement", field: "pourcentage_financement"},
|
|
||||||
],
|
|
||||||
placeholder: "Aucun bailleur attribué pour ce projet",
|
|
||||||
})
|
|
||||||
|
|
||||||
tableau_liste_projet.on("rowClick", function (row, rowData) {
|
|
||||||
const data = rowData.getData();
|
|
||||||
const modal = new bootstrap.Modal($("modalDetailProjet"));
|
|
||||||
|
|
||||||
$("detail_id_projet").value = data.id_projet;
|
|
||||||
$("detail_nom_projet").value = data.nom_projet;
|
|
||||||
$("detail_date_debut").value = data.date_debut;
|
|
||||||
$("detail_date_fin").value = data.date_fin;
|
|
||||||
$("detail_numero_convention").value = data.numero_convention;
|
|
||||||
$("detail_type_projet").value = data.type_projet;
|
|
||||||
Array.from($("detail_domaine_recherche").options).forEach(option => {
|
|
||||||
if (data.domaine_recherche.includes(option.value)) {
|
|
||||||
option.selected = true;
|
|
||||||
} else {
|
|
||||||
option.selected = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$("detail_budget").value = data.budget;
|
|
||||||
$("detail_budget_rh").value = data.budget_RH;
|
|
||||||
$("detail_description").value = data.description;
|
|
||||||
$("detail_statut").value = data.statut;
|
|
||||||
|
|
||||||
employes_affectes_projet.setData(`projet/liste-employes-par-projet/${$("detail_id_projet").value}`);
|
|
||||||
bailleurs_projet.setData(`projet/bailleurs/${data.id_projet}/`);
|
|
||||||
|
|
||||||
modal.show();
|
|
||||||
})
|
|
||||||
|
|
||||||
// $('detail-projet-form').addEventListener('submit', (e) => {
|
|
||||||
// e.preventDefault();
|
|
||||||
// new FormData($("detail-projet-form"));
|
|
||||||
// })
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const urlListeDocument = document.getElementById('listeDocuments').dataset.urllistedocument;
|
|
||||||
|
|
||||||
const table_liste_documents = new Tabulator(document.getElementById('listeDocuments'), {
|
|
||||||
layout: "fitColumns",
|
|
||||||
placeholder: "Aucun document trouvé",
|
|
||||||
columns: [
|
|
||||||
{ title: "Nom du Document", field: "nom_document" },
|
|
||||||
{ title: "Numéro", field: "numero" },
|
|
||||||
{ title: "Date de Validité", field: "date_validite", formatter: "datetime", formatterParams: {
|
|
||||||
inputFormat: "yyyy-MM-dd",
|
|
||||||
outputFormat: "dd/MM/yyyy"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ title: "Lien vers le Document", field: "lien_document", formatter:"link", formatterParams:{
|
|
||||||
target:"_blank",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
ajaxURL: urlListeDocument,
|
|
||||||
});
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
const $ = (element) => document.getElementById(element)
|
|
||||||
|
|
||||||
const url_liste_activite = $("tableau-liste-activite").dataset.urllisteactivite
|
|
||||||
const tableau_liste_activite = new Tabulator("#tableau-liste-activite", {
|
|
||||||
columns: [
|
|
||||||
{title: "Activité", field: "titre"},
|
|
||||||
{title: "Date début", field: "date_debut"},
|
|
||||||
{title: "Date fin", field: "date_fin"},
|
|
||||||
{title: "Budget prévu", field: "budget_prevu"},
|
|
||||||
{title: "Budget dépensé", field: "budget_depense"},
|
|
||||||
{title: "Motif de changement de budget", field: "motif_changement_budget"},
|
|
||||||
{title: "Statut", field: "statut"},
|
|
||||||
],
|
|
||||||
ajaxURL: url_liste_activite,
|
|
||||||
})
|
|
||||||
tableau_liste_activite.on("rowClick", function (row, rowData) {
|
|
||||||
const data = rowData.getData();
|
|
||||||
$("idDetailActivite").value = data.id;
|
|
||||||
$("titreDetailActivite").value = data.titre;
|
|
||||||
$("descriptionDetailActivite").value = data.description;
|
|
||||||
$("date_debutDetailActivite").value = data.date_debut;
|
|
||||||
$("date_finDetailActivite").value = data.date_fin;
|
|
||||||
$("statutDetailActivite").value = data.statut;
|
|
||||||
$("budget_prevuDetailActivite").value = data.budget_prevu;
|
|
||||||
$("besoin_ressources_materiellesDetailActivite").value = data.besoin_ressource_materielle;
|
|
||||||
const modal = new bootstrap.Modal($("modalDetailActivite"));
|
|
||||||
modal.show();
|
|
||||||
|
|
||||||
fetch(`liste-des-livrables/${data.id}/`)
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(livrables => {
|
|
||||||
tableau_liste_livrable.setData(livrables);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const tableau_liste_livrable = new Tabulator("#listeLivrables", {
|
|
||||||
columns: [
|
|
||||||
{title: "Livrable", field: "titre"},
|
|
||||||
{title: "Lien du livrable", field: "lien", formatter: "link", formatterParams: {blank: true}},
|
|
||||||
],
|
|
||||||
placeholder: "Aucun livrable trouvé",
|
|
||||||
})
|
|
||||||
|
|
||||||
$("btnMiseAJourDepense").addEventListener("click", function() {
|
|
||||||
const modal = new bootstrap.Modal($("modalDepenseActivite"));
|
|
||||||
bootstrap.Modal.getOrCreateInstance($("modalDetailActivite")).hide();
|
|
||||||
const idActivite = $("idDetailActivite").value;
|
|
||||||
const budgetPrevu = $("budget_prevuDetailActivite").value;
|
|
||||||
|
|
||||||
$("id_activite_depense").value = idActivite;
|
|
||||||
$("budget_prevu").value = budgetPrevu;
|
|
||||||
modal.show();
|
|
||||||
})
|
|
||||||
|
|
||||||
$("btnAnnulerActivite").addEventListener("click", function(event) {
|
|
||||||
new bootstrap.Modal($("modalAnnulerActivite")).show();
|
|
||||||
$("id_activite_annulation").value = $("idDetailActivite").value;
|
|
||||||
bootstrap.Modal.getOrCreateInstance($("modalDetailActivite")).hide();
|
|
||||||
})
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{% extends "BASE.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% block 'titre_page' %} Gestion des projets {% endblock %}
|
|
||||||
{% block 'contenu' %}
|
|
||||||
<button class="btn btn-primary mb-3">
|
|
||||||
<i class="bi bi-caret-left-fill"></i> Retour
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="row d-flex justify-content-center">
|
|
||||||
<div class="col-8 card bordered rounded py-4 px-2 ">
|
|
||||||
<h5>Ajout du financement au projet (Nom du projet ici)</h5>
|
|
||||||
<hr>
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:creation-projet' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formulaire_creation_projet.as_p }}
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<button type="submit" class="btn btn-danger">Annuler</button>
|
|
||||||
<a href="{% url 'gestion_projet:ajouter_financement' %}" class="btn btn-primary ms-2">Enregistrer et ajouter un financement</a>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'modal' %}
|
|
||||||
{% include "gestion_projet/parts/modalAjoutProjet.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'js' %}
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/index.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{% extends "BASE.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% block 'titre_page' %} Gestion des projets {% endblock %}
|
|
||||||
{% block 'contenu' %}
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% comment %} <h3>Enregistrement d'un nouveau projet</h3> {% endcomment %}
|
|
||||||
<div class="row d-flex justify-content-center">
|
|
||||||
<div class="col-8 card bordered rounded py-4 px-2 ">
|
|
||||||
<h5>Enregistrement d'un nouveau projet</h5>
|
|
||||||
<hr>
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:creation-projet' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formulaire_creation_projet.as_p }}
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<button type="submit" class="btn btn-danger">Annuler</button>
|
|
||||||
<button class="btn btn-primary ms-2">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'modal' %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'js' %}
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
{% extends "BASE.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% load tags_personnaliser %}
|
|
||||||
{% block 'titre_page' %} Gestion des projets {% endblock %}
|
|
||||||
{% block 'contenu' %}
|
|
||||||
<h3>Gestion des projets</h3>
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
|
||||||
<span class="fs-5">Projets en cours</span>
|
|
||||||
<h3>{{projet_en_cours}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4 mx-2">
|
|
||||||
<span class="fs-5">Budget Total (GNF)</span>
|
|
||||||
<h3>{{budget_total}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
|
||||||
<span class="fs-5">Personnel sous projet</span>
|
|
||||||
<h3>{{nombre_personnel}}</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col d-flex justify-content-between align-items-center mb-3">
|
|
||||||
<h5 class="mb-4" >La liste des projets </h5>
|
|
||||||
{% if user|has_group:"ressource_humaine" %}
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalProjet">
|
|
||||||
<i class="bi bi-plus-circle"></i> Ajouter un projet
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#modalBailleur">
|
|
||||||
<i class="bi bi-person"></i> Ajouter un bailleur
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div id="tableau-liste-projet" data-url="{% url 'gestion_projet:liste-projet' %}"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'modal' %}
|
|
||||||
{% include "gestion_projet/parts/modalAjoutProjet.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalFinancement.html" %}
|
|
||||||
{% include "gestion_projet/parts/creation_bailleur.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalDetailProjet.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'js' %}
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/index.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/creation_projet.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/enregistrement_bailleur.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/enregistrement_financement.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<div class="modal fade" id="modalBailleur" tabindex="-1" aria-labelledby="modalBailleurLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalBailleurLabel">Ajouter un Bailleur</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-4">
|
|
||||||
<form id="formBailleur" method="POST" action="{% url 'gestion_projet:creation-bailleur' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form_ajout_bailleur.as_p }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" id="btnEnregistrerBailleur" class="btn btn-success"><i class="bi bi-save me-1"></i> Enregistrer</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<div class="modal fade" id="modalListeDocument" tabindex="-1" aria-labelledby="modalListeDocumentLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title fw-bold" id="modalListeDocumentLabel">Liste des Documents</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-4">
|
|
||||||
<div id="listeDocuments" data-urllistedocument="{% url 'gestion_projet:liste-documents-projet' %}"></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAjoutActivite" tabindex="-1" aria-labelledby="modalAjoutActiviteLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalAjoutActiviteLabel">Ajouter une Activité</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:ajouter-activite' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-body">
|
|
||||||
{{ form_ajout_activite.as_p }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Ajouter</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAjoutDocument" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Ajouter un Document</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:ajouter-document' %}" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-body">
|
|
||||||
{{ form_ajout_document.as_p }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Ajouter</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAjouterLivrable" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Ajouter un livrable - (Nom du livrable)</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" action="{% url 'gestion_projet:ajouter-livrable' %}" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form_ajout_livrable.as_p }}
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-success">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<!-- Modale Projet -->
|
|
||||||
<div class="modal fade" id="modalProjet" tabindex="-1" aria-labelledby="modalProjetLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title" id="modalProjetLabel">Ajouter un projet</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-3">
|
|
||||||
<form method="POST" id="formCreationProjet" action="{% url 'gestion_projet:creation-projet' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formulaire_creation_projet.as_p }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" id="btnEnregistrerProjet" class="btn btn-success">Enregistrer</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<div class="modal fade" id="modalAnnulerActivite" tabindex="-1" aria-labelledby="modalAnnulerActiviteLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title fw-bold" id="modalAnnulerActiviteLabel">Annuler l'activité</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-4">
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:annuler-activite' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="id_activite" id="id_activite_annulation">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="motif_annulation" class="form-label">Motif d'annulation</label>
|
|
||||||
<textarea class="form-control" name="motif_annulation" id="motif_annulation" rows="4" required></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-danger">
|
|
||||||
<i class="bi bi-x-circle"></i> Confirmer l'annulation
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<div class="modal fade" id="modalDetailActivite" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Détails de l'activité</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="">
|
|
||||||
<input type="hidden" id="idDetailActivite">
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Titre :</label>
|
|
||||||
<input type="text" class="form-control" id="titreDetailActivite">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Description :</label>
|
|
||||||
<textarea class="form-control" id="descriptionDetailActivite"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Date de début :</label>
|
|
||||||
<input type="date" class="form-control" id="date_debutDetailActivite">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Date de fin :</label>
|
|
||||||
<input type="date" class="form-control" id="date_finDetailActivite">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Statut:</label>
|
|
||||||
<input type="text" class="form-control" id="statutDetailActivite">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Budget prévu :</label>
|
|
||||||
<input type="number" class="form-control" id="budget_prevuDetailActivite">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Besoin de ressources matérielles:</label>
|
|
||||||
<textarea class="form-control" id="besoin_ressources_materiellesDetailActivite"></textarea>
|
|
||||||
</div>
|
|
||||||
<p><strong>Liste des livrables :</strong></p>
|
|
||||||
<div id="listeLivrables"></div>
|
|
||||||
<button class="btn btn-danger d-block mx-auto" id="btnAnnulerActivite">
|
|
||||||
Annuler cette activité
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-success" id="btnMiseAJourDepense">
|
|
||||||
<i class="bi bi-plus-circle"></i> Mise à jour du budget
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjouterLivrable">
|
|
||||||
<i class="bi bi-plus-circle"></i> Ajouter un livrable
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
{% load tags_personnaliser %}
|
|
||||||
<div class="modal fade" id="modalDetailProjet{{ activite.id }}" tabindex="-1">
|
|
||||||
<div class="modal-dialog ">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header ">
|
|
||||||
<h5 class="modal-title">Détails du projet </h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="row g-3">
|
|
||||||
<div class="col" id="detail-projet-container">
|
|
||||||
<form method='post' action="{% url 'gestion_projet:mises-a-jour-projet' %}" id="detail-projet-form">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Id projet:</label>
|
|
||||||
<input type="text" class="form-control" id="detail_id_projet" name='id_projet' readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label> Nom projet :</label>
|
|
||||||
<input type="text" class="form-control" id="detail_nom_projet" name='nom_projet'>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Numero de convention:</label>
|
|
||||||
<input type="text" class="form-control" id="detail_numero_convention" name="numero_convention">
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Date de début :</label>
|
|
||||||
<input type="date" class="form-control" id="detail_date_debut" name='date_debut'>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Date de fin :</label>
|
|
||||||
<input type="date" class="form-control" id="detail_date_fin" name='date_fin'>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label> Type de projet </label>
|
|
||||||
<select class="form-select" id="detail_type_projet" name='type_projet'>
|
|
||||||
<option value="laboratoire">Laboratoire</option>
|
|
||||||
<option value="épidémiologie">Épidémiologie</option>
|
|
||||||
<option value="sciences sociales">Sciences sociales</option>
|
|
||||||
<option value="cliniques">Cliniques</option>
|
|
||||||
<option value="autre">Autre</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label> Domaine de recherche </label>
|
|
||||||
<select class="form-select" multiple id="detail_domaine_recherche" name="domaine_recherche">
|
|
||||||
<option value="sciences_sociales">Sciences sociales</option>
|
|
||||||
<option value="naturelles">Naturelles</option>
|
|
||||||
<option value="humaines">Humaines</option>
|
|
||||||
<option value="veterinaires">Vétérinaires</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Budget :</label>
|
|
||||||
<input type="number" class="form-control" id="detail_budget" name='budget'>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Budget RH:</label>
|
|
||||||
<input type="number" class="form-control" id="detail_budget_rh" name='budget_RH'>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label>Description :</label>
|
|
||||||
<textarea class="form-control" id="detail_description" name='description'></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="form-check-group mb-2">
|
|
||||||
<label class="form-check-label">Statut :</label>
|
|
||||||
<input type="text" class="form-control" id="detail_statut" readonly>
|
|
||||||
</div>
|
|
||||||
<button type='submit' class="btn btn-warning">
|
|
||||||
<i class="bi bi-pencil"></i> Modifier Projet
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<hr class="my-4">
|
|
||||||
<div class="accordion" id="accordionDetailProjet">
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="employesAffectes">
|
|
||||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
|
||||||
Employés Affectés
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="employesAffectes" data-bs-parent="#accordionDetailProjet">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div id="employes_affectes_projet"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="accordion-item">
|
|
||||||
<h2 class="accordion-header" id="bailleursProjet">
|
|
||||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
|
||||||
Liste des bailleurs
|
|
||||||
</button>
|
|
||||||
</h2>
|
|
||||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="bailleursProjet" data-bs-parent="#accordionDetailProjet">
|
|
||||||
<div class="accordion-body">
|
|
||||||
<div id="bailleurs_projet"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
{% if user|has_group:"ressource_humaine" %}
|
|
||||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modal_ajout_financement">
|
|
||||||
<i class="bi bi-plus-circle"></i> Ajouter un financement
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle"></i> Fermer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<div class="modal fade" id="modal_ajout_financement" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Ajout de financement</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="POST" id="form_financement" action="{% url 'gestion_projet:ajouter_financement' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ form_ajout_financement.as_p }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" id="btn_enregistrer_financement" class="btn btn-success">Enregistrer</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<div class="modal fade" id="modalDepenseActivite" tabindex="-1" aria-labelledby="modalDepenseActiviteLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalDepenseActiviteLabel">
|
|
||||||
<i class="bi bi-cash-stack me-2"></i> Mise à jour des dépenses
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="POST" action="{% url 'gestion_projet:mettre-a-jour-depense' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="id_activite" id="id_activite_depense">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label">Budget prévu (GNF)</label>
|
|
||||||
<input type="number" class="form-control" name="budget_prevu" id="budget_prevu" value="" disabled>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="budget_depense" class="form-label">Montant dépensé (GNF)</label>
|
|
||||||
<input type="number" name="budget_depense" id="budget_depense" class="form-control" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label">Motif de différence</label>
|
|
||||||
<textarea class="form-control" name="motif" rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-save"></i> Enregistrer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
{% extends "BASE.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% block 'titre_page' %} Gestion des projets {% endblock %}
|
|
||||||
{% block 'contenu' %}
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
|
|
||||||
{{ message }}
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
<h5 class="mb-4 fw-bold text-uppercase text-orange-dark">
|
|
||||||
<i class="bi bi-kanban-fill me-2"></i> Suivi des Activités ({{ nom_projet }} )
|
|
||||||
</h5>
|
|
||||||
<div class="row d-flex justify-content-center mb-4">
|
|
||||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
|
||||||
<span class="fs-5">Budget Total (GNF)</span>
|
|
||||||
<h3>{{ budget_total }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col text-white bg-info d-flex flex-column justify-content-center align-items-center border rounded mx-3 p-4">
|
|
||||||
<span class="fs-5">Budget RH (GNF)</span>
|
|
||||||
<h3>{{ budget_RH }}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col text-white bg-warning d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
|
||||||
<span class="fs-5">Budget Dépensé (GNF)</span>
|
|
||||||
<h3>{{budget_depense}}</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="mt-4 d-flex justify-content-between mb-3">
|
|
||||||
<h5><i class="bi bi-people"></i> La liste des Activités</h5>
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjoutActivite">
|
|
||||||
<i class="bi bi-plus-circle me-2"></i> Ajouter une Activité
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalAjoutDocument">
|
|
||||||
<i class="bi bi-plus-circle me-2"></i> Ajouter un document
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#modalListeDocument">
|
|
||||||
Documents du projet
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-responsive">
|
|
||||||
<div id="tableau-liste-activite" data-urllisteactivite="{% url 'gestion_projet:liste-activites-projet' %}"></div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'modal' %}
|
|
||||||
{% include "gestion_projet/parts/modalAjoutActivite.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalDetailActivite.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalAjoutDocument.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalMiseAJourDepense.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalAjoutLivrable.html" %}
|
|
||||||
{% include "gestion_projet/parts/liste_document_projet.html" %}
|
|
||||||
{% include "gestion_projet/parts/modalAnnulerActivite.html" %}
|
|
||||||
{% endblock %}
|
|
||||||
{% block 'js' %}
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/suivi-activites.js' %}"></script>
|
|
||||||
<script type="text/javascript" src="{% static 'gestion_projet/js/liste_documents_projet.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class GestionSalleConfig(AppConfig):
|
|
||||||
name = 'gestion_salle'
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from .models import Reservation
|
|
||||||
|
|
||||||
class ReservationForm(forms.ModelForm):
|
|
||||||
class Meta:
|
|
||||||
model = Reservation
|
|
||||||
fields = ['salle', 'date_debut', 'date_fin', 'heure_debut', 'heure_fin', 'motif_reservation', 'besoin_zoom', 'besoin_ordi']
|
|
||||||
widgets = {
|
|
||||||
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'heure_debut': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
|
|
||||||
'heure_fin': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
|
|
||||||
'motif_reservation': forms.Textarea(attrs={'rows': 3, 'cols': 40, 'style':'resize:none;', 'class': 'form-control'}),
|
|
||||||
'salle': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
}
|
|
||||||
besoin_zoom = forms.BooleanField(
|
|
||||||
required=False,
|
|
||||||
label="Besoin d'un lien Zoom ?",
|
|
||||||
widget=forms.CheckboxInput(attrs={'class': 'form-check-input', 'id': 'id_besoin_zoom'})
|
|
||||||
)
|
|
||||||
besoin_ordi = forms.BooleanField(
|
|
||||||
required=False,
|
|
||||||
label="Besoin d'ordinateur ?",
|
|
||||||
widget=forms.CheckboxInput(attrs={'class': 'form-check-input', 'id': 'id_besoin_ordi'})
|
|
||||||
)
|
|
||||||
|
|
||||||
class RefusReservationForm(forms.Form):
|
|
||||||
motif_refus = forms.CharField(
|
|
||||||
label= "Motif du refus",
|
|
||||||
widget=forms.Textarea(attrs={'rows': 3, 'cols': 40, 'style': 'resize:none;'}),
|
|
||||||
required=True
|
|
||||||
)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<div class="modal fade" id="refusModal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header ">
|
|
||||||
<h5 class="modal-title">Motif du refus</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="POST" id="refusForm" action="{% url 'gestion_salle:refuser-reservation' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type='' class="form-control" id="id_reservation_refus" name='id_reservation' value="">
|
|
||||||
<textarea class="form-control" name="motif_refus" rows="3" required></textarea>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<!-- Modal Ajouter/Modifier lien Zoom -->
|
|
||||||
<div class="modal fade" id="modalZoom" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header ">
|
|
||||||
<h5 class="modal-title">Ajouter/Modifier le lien Zoom</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" id="formZoom" action="{% url 'gestion_salle:ajouter-lien_zoom' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type='hidden' class="form-control" id="id_reservation_zoom" name='id_reservation'>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="lienZoom" class="form-label">Lien Zoom</label>
|
|
||||||
<input type="url" class="form-control" name="lien_zoom" id="lienZoom"
|
|
||||||
value="" required>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-success">Enregistrer</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<!-- Modal de création d'une nouvelle reservation -->
|
|
||||||
<div class="modal fade" id="modalReservation" tabindex="-1" aria-labelledby="modalReservationLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h1 class="modal-title fs-5" id="modalReservationLabel">
|
|
||||||
Nouvelle reservation
|
|
||||||
</h1>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="POST" action="{% url 'gestion_salle:reservation-salle' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
{{ formulaire_reservation.as_p }}
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!-- Modal d'affichage des détails d'une reservation -->
|
|
||||||
<div class="modal fade" id="modalReservationAttente" tabindex="-1" aria-labelledby="modalReservationAttenteLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h1 class="modal-title fs-5" id="modalReservationAttenteLabel">
|
|
||||||
Liste des reservation en attente de validation
|
|
||||||
</h1>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div id="tableau-reservation-attente" data-reservationattentes = "{% url 'gestion_salle:liste-reservation-attente' %}"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
from django.urls import path
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
app_name = "gestion_salle"
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path(
|
|
||||||
'revervation/',
|
|
||||||
views.index,
|
|
||||||
name='reservation-salle'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'revervation/details/<int:reservation_id>',
|
|
||||||
views.detail_reservation,
|
|
||||||
name='detail-reservation'
|
|
||||||
),
|
|
||||||
|
|
||||||
path(
|
|
||||||
'reservation/annuler',
|
|
||||||
views.annuler_reservation,
|
|
||||||
name='annuler-reservation'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'reservation/valider',
|
|
||||||
views.valider_reservation,
|
|
||||||
name='valider-reservation'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'reservation/refuser',
|
|
||||||
views.refuser_reservation,
|
|
||||||
name='refuser-reservation'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'reservation/ajout-de-lien-zoom',
|
|
||||||
views.ajouter_lien_zoom,
|
|
||||||
name='ajouter-lien_zoom'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'liste-reservation',
|
|
||||||
views.liste_reservation,
|
|
||||||
name='liste-reservation'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'liste-reservation-attente',
|
|
||||||
views.liste_reservation_attente,
|
|
||||||
name="liste-reservation-attente"
|
|
||||||
)
|
|
||||||
]
|
|
||||||
22
manage.py
22
manage.py
@@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""Django's command-line utility for administrative tasks."""
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Run administrative tasks."""
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SIRH.settings')
|
|
||||||
try:
|
|
||||||
from django.core.management import execute_from_command_line
|
|
||||||
except ImportError as exc:
|
|
||||||
raise ImportError(
|
|
||||||
"Couldn't import Django. Are you sure it's installed and "
|
|
||||||
"available on your PYTHONPATH environment variable? Did you "
|
|
||||||
"forget to activate a virtual environment?"
|
|
||||||
) from exc
|
|
||||||
execute_from_command_line(sys.argv)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
6
static/css/bootstrap.min.css
vendored
6
static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,278 +0,0 @@
|
|||||||
/* === Print === */
|
|
||||||
@media print {
|
|
||||||
nav, .btn, .sidebar, .form-select, .form-control {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-size: 12pt;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
main {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Body & Container === */
|
|
||||||
body {
|
|
||||||
background-color: #e4dccc;
|
|
||||||
background-attachment: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-container {
|
|
||||||
background-color: #ffffff;
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.05);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 30px auto;
|
|
||||||
max-width: 1200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: fixed;
|
|
||||||
width: 220px;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
margin-left: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* === Sidebar === */
|
|
||||||
.sidebar {
|
|
||||||
background: linear-gradient(180deg, #b35400, #993d00); /* dégradé orange foncé */
|
|
||||||
color: white;
|
|
||||||
min-height: 100vh; /* prend toute la hauteur */
|
|
||||||
top: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link {
|
|
||||||
color: white;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 5px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .dropdown-menu {
|
|
||||||
display: none;
|
|
||||||
position: relative;
|
|
||||||
left: 10px;
|
|
||||||
top: -5px;
|
|
||||||
border: none;
|
|
||||||
padding-left: 1rem;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .dropdown:hover .dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Navbar / Logo / Profil === */
|
|
||||||
.logo {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-profil {
|
|
||||||
width: 80px !important;
|
|
||||||
height: 80px !important;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Cards === */
|
|
||||||
.card {
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
font-weight: bold !important;
|
|
||||||
color: black !important;
|
|
||||||
font-size: 1rem;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body h5 {
|
|
||||||
color: black !important;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 2.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Stat cards === */
|
|
||||||
.stat-card {
|
|
||||||
background: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 5px rgba(113, 11, 11, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Employé / Projet details === */
|
|
||||||
.employe-detail {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail .card-title {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail p {
|
|
||||||
margin-bottom: 0.4rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail a.btn {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-card, .projet-card {
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
||||||
padding: 2.5rem;
|
|
||||||
max-width: 1400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Forms === */
|
|
||||||
.form-wrapper {
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: auto;
|
|
||||||
background-color: rgba(255, 255, 255, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
form label {
|
|
||||||
font-weight: 600;
|
|
||||||
margin-top: 1rem;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input, form select, form textarea {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5rem;
|
|
||||||
margin-top: 0.3rem;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Formation badges === */
|
|
||||||
.formation-badge {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-actions {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-badge:hover .formation-actions {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-actions button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #fff;
|
|
||||||
margin-left: 5px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Context menu === */
|
|
||||||
#contextMenu {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Transitions / Animations === */
|
|
||||||
.fade-out {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-content {
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.login-box {
|
|
||||||
background: linear-gradient(to right, #f5f7fa, #c3cfe2);
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Responsive === */
|
|
||||||
@media (max-width: 576px) {
|
|
||||||
.modal-dialog {
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-profil {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
static/css/tabulator_bootstrap5.min.css
vendored
2
static/css/tabulator_bootstrap5.min.css
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB |
@@ -1,13 +0,0 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
// Vérifie si le formulaire contient des erreurs
|
|
||||||
var formErrors = {{ complet_form.non_field_errors|length|default:0 }};
|
|
||||||
if (formErrors > 0) {
|
|
||||||
// Ouvre la modale
|
|
||||||
var modal = new bootstrap.Modal(document.getElementById('modalModifierProfil'));
|
|
||||||
modal.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
navigator.serviceWorker.register('{% static "sw.js" %}').then(function(reg) {
|
|
||||||
console.log('Service worker registered.', reg);
|
|
||||||
}).catch(function(err) {
|
|
||||||
console.warn('Service worker registration failed:', err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const couleursOrange = ['#b35400', '#ff9f1c', '#ffc107', '#ffb84d', '#ffcc80'];
|
|
||||||
const departementLabels = {{ departement_labels|safe }};
|
|
||||||
const departementCounts = {{ departement_counts|safe }};
|
|
||||||
const sexeLabels = {{ sexe_labels|safe }};
|
|
||||||
const sexeCounts = {{ sexe_counts|safe }};
|
|
||||||
const projetLabels = {{ projet_labels|safe }};
|
|
||||||
const projetCounts = {{ projet_counts|safe }};
|
|
||||||
const ticketsLabels = ["Traités", "Non traités"];
|
|
||||||
const ticketsCounts = [{{ tickets_traite }}, {{ tickets_non_traite }}];
|
|
||||||
const domaineLabels = {{ domaine_labels|safe }};
|
|
||||||
const domaineCounts = {{ domaine_counts|safe }};
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDepartement"), {
|
|
||||||
type: 'pie',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: departementLabels,
|
|
||||||
datasets: [{ data: departementCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartSexe"), {
|
|
||||||
type: 'doughnut',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: sexeLabels,
|
|
||||||
datasets: [{ data: sexeCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartProjets"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: projetLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: projetCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:16 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, ticks:{ stepSize:1, precision:0 }, title:{ display:true, text:'Nombre de projets' } },
|
|
||||||
x: { title:{ display:true, text:'' } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDomaine"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: domaineLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: domaineCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:14 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, title:{ display:true, text:'Nombre de projets' }, ticks:{ precision:0, stepSize:1 } },
|
|
||||||
x: {
|
|
||||||
ticks:{ autoSkip:false, maxRotation:100, minRotation:30, callback: function(value){ return this.getLabelForValue(value); } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btnVoirRapport').addEventListener('click', function() {
|
|
||||||
const projetId = document.getElementById('projetId').value;
|
|
||||||
if(!projetId) return alert("Veuillez sélectionner un projet.");
|
|
||||||
fetch(`/rapports/projet/${projetId}/`)
|
|
||||||
.then(resp => { if(!resp.ok) throw new Error("Projet non trouvé"); return resp.text(); })
|
|
||||||
.then(html => { document.getElementById('contenuRapportProjet').innerHTML = html; })
|
|
||||||
.catch(err => { document.getElementById('contenuRapportProjet').innerHTML = "<p class='text-danger'>Erreur lors du chargement.</p>"; console.error(err); });
|
|
||||||
});
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
navigator.serviceWorker.register('{% static "sw.js" %}').then(function(reg) {
|
|
||||||
console.log('Service worker registered.', reg);
|
|
||||||
}).catch(function(err) {
|
|
||||||
console.warn('Service worker registration failed:', err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var modal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
modal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
||||||
<script>
|
|
||||||
// Afficher / masquer le mot de passe
|
|
||||||
function togglePassword() {
|
|
||||||
const input = document.querySelector('input[name="password"]');
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
|
|
||||||
// AJAX pour réinitialisation
|
|
||||||
$('#resetPasswordForm').on('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const email = $('input[name="email"]').val();
|
|
||||||
const csrfToken = $('[name=csrfmiddlewaretoken]').val();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "{% url 'password_reset' %}",
|
|
||||||
type: 'POST',
|
|
||||||
data: {
|
|
||||||
'email': email,
|
|
||||||
'csrfmiddlewaretoken': csrfToken
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-success">Email envoyé ! Vérifiez votre boîte de réception.</div>');
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-danger">Erreur lors de l’envoi. Vérifiez l’email.</div>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@@ -1,279 +0,0 @@
|
|||||||
select.admin-autocomplete {
|
|
||||||
width: 20em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container {
|
|
||||||
min-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single,
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple {
|
|
||||||
min-height: 30px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--focus .select2-selection,
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open .select2-selection {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
min-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--single,
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--single {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--focus .select2-selection.select2-selection--multiple,
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open .select2-selection.select2-selection--multiple {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single {
|
|
||||||
background-color: var(--body-bg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__rendered {
|
|
||||||
color: var(--body-fg);
|
|
||||||
line-height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__clear {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__placeholder {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow {
|
|
||||||
height: 26px;
|
|
||||||
position: absolute;
|
|
||||||
top: 1px;
|
|
||||||
right: 1px;
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--single .select2-selection__arrow b {
|
|
||||||
border-color: #888 transparent transparent transparent;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 5px 4px 0 4px;
|
|
||||||
height: 0;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -4px;
|
|
||||||
margin-top: -2px;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
|
||||||
left: 1px;
|
|
||||||
right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single {
|
|
||||||
background-color: var(--darkened-bg);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
|
||||||
border-color: transparent transparent #888 transparent;
|
|
||||||
border-width: 0 4px 5px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple {
|
|
||||||
background-color: var(--body-bg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: text;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered {
|
|
||||||
box-sizing: border-box;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 10px 5px 5px;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__rendered li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__placeholder {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
margin-top: 5px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__clear {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 5px;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice {
|
|
||||||
background-color: var(--darkened-bg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: default;
|
|
||||||
float: left;
|
|
||||||
margin-right: 5px;
|
|
||||||
margin-top: 5px;
|
|
||||||
padding: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-selection--multiple .select2-selection__choice__remove:hover {
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
|
||||||
margin-left: 5px;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--focus .select2-selection--multiple {
|
|
||||||
border: solid var(--body-quiet-color) 1px;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--disabled .select2-selection--multiple {
|
|
||||||
background-color: var(--darkened-bg);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--disabled .select2-selection__choice__remove {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--above .select2-selection--multiple {
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--single, .select2-container--admin-autocomplete.select2-container--open.select2-container--below .select2-selection--multiple {
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-search--dropdown {
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-search--dropdown .select2-search__field {
|
|
||||||
background: var(--body-bg);
|
|
||||||
color: var(--body-fg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-search--inline .select2-search__field {
|
|
||||||
background: transparent;
|
|
||||||
color: var(--body-fg);
|
|
||||||
border: none;
|
|
||||||
outline: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
-webkit-appearance: textfield;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results > .select2-results__options {
|
|
||||||
max-height: 200px;
|
|
||||||
overflow-y: auto;
|
|
||||||
color: var(--body-fg);
|
|
||||||
background: var(--body-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option[role=group] {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option[aria-disabled=true] {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option[aria-selected=true] {
|
|
||||||
background-color: var(--selected-bg);
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option {
|
|
||||||
padding-left: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__group {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option {
|
|
||||||
margin-left: -1em;
|
|
||||||
padding-left: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
|
||||||
margin-left: -2em;
|
|
||||||
padding-left: 3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
|
||||||
margin-left: -3em;
|
|
||||||
padding-left: 4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
|
||||||
margin-left: -4em;
|
|
||||||
padding-left: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
|
||||||
margin-left: -5em;
|
|
||||||
padding-left: 6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__option--highlighted[aria-selected] {
|
|
||||||
background-color: var(--primary);
|
|
||||||
color: var(--primary-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.select2-container--admin-autocomplete .select2-results__group {
|
|
||||||
cursor: default;
|
|
||||||
display: block;
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.errors .select2-selection {
|
|
||||||
border: 1px solid var(--error-fg);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,343 +0,0 @@
|
|||||||
/* CHANGELISTS */
|
|
||||||
|
|
||||||
#changelist {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .changelist-form-container {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .hiddenfields { display:none; }
|
|
||||||
|
|
||||||
.change-list .filtered table {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .filtered {
|
|
||||||
min-height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .filtered .results, .change-list .filtered .paginator,
|
|
||||||
.filtered #toolbar, .filtered div.xfull {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .filtered table tbody th {
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-form .results {
|
|
||||||
overflow-x: auto;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .toplinks {
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .paginator {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
background: var(--body-bg);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CHANGELIST TABLES */
|
|
||||||
|
|
||||||
#changelist table thead th {
|
|
||||||
padding: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist table thead th.action-checkbox-column {
|
|
||||||
width: 1.5em;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist table tbody td.action-checkbox {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist table tfoot {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TOOLBAR */
|
|
||||||
|
|
||||||
#toolbar {
|
|
||||||
padding: 8px 10px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border-top: 1px solid var(--hairline-color);
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbar form input {
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
padding: 5px;
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbar #searchbar {
|
|
||||||
height: 1.1875rem;
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
padding: 2px 5px;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: top;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbar #searchbar:focus {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbar form input[type="submit"] {
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
padding: 4px 8px;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
background: var(--body-bg);
|
|
||||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#toolbar form input[type="submit"]:focus,
|
|
||||||
#toolbar form input[type="submit"]:hover {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-search img {
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-search .help {
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FILTER COLUMN */
|
|
||||||
|
|
||||||
#changelist-filter {
|
|
||||||
flex: 0 0 240px;
|
|
||||||
order: 1;
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
border-left: none;
|
|
||||||
margin: 0 0 0 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (forced-colors: active) {
|
|
||||||
#changelist-filter {
|
|
||||||
border: 1px solid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter h2 {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
padding: 5px 15px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter h3,
|
|
||||||
#changelist-filter details summary {
|
|
||||||
font-weight: 400;
|
|
||||||
padding: 0 15px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter details summary > * {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter details > summary {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter details > summary::-webkit-details-marker {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter details > summary::before {
|
|
||||||
content: '→';
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--link-hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter details[open] > summary::before {
|
|
||||||
content: '↓';
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter ul {
|
|
||||||
margin: 5px 0;
|
|
||||||
padding: 0 15px 15px;
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter ul:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter li {
|
|
||||||
list-style-type: none;
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter a {
|
|
||||||
display: block;
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter li.selected {
|
|
||||||
border-left: 5px solid var(--hairline-color);
|
|
||||||
padding-left: 10px;
|
|
||||||
margin-left: -15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter li.selected a {
|
|
||||||
color: var(--link-selected-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter a:focus, #changelist-filter a:hover,
|
|
||||||
#changelist-filter li.selected a:focus,
|
|
||||||
#changelist-filter li.selected a:hover {
|
|
||||||
color: var(--link-hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist-filter #changelist-filter-extra-actions {
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DATE DRILLDOWN */
|
|
||||||
|
|
||||||
.change-list .toplinks {
|
|
||||||
display: flex;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 3px 17px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .toplinks a {
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .toplinks .date-back {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-list .toplinks .date-back:focus,
|
|
||||||
.change-list .toplinks .date-back:hover {
|
|
||||||
color: var(--link-hover-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ACTIONS */
|
|
||||||
|
|
||||||
.filtered .actions {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist table input {
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Once the :has() pseudo-class is supported by all browsers, the tr.selected
|
|
||||||
selector and the JS adding the class can be removed. */
|
|
||||||
#changelist tbody tr.selected {
|
|
||||||
background-color: var(--selected-row);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist tbody tr:has(.action-select:checked) {
|
|
||||||
background-color: var(--selected-row);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (forced-colors: active) {
|
|
||||||
#changelist tbody tr.selected {
|
|
||||||
background-color: SelectedItem;
|
|
||||||
}
|
|
||||||
#changelist tbody tr:has(.action-select:checked) {
|
|
||||||
background-color: SelectedItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions {
|
|
||||||
padding: 10px;
|
|
||||||
background: var(--body-bg);
|
|
||||||
border-top: none;
|
|
||||||
border-bottom: none;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions span.all,
|
|
||||||
#changelist .actions span.action-counter,
|
|
||||||
#changelist .actions span.clear,
|
|
||||||
#changelist .actions span.question {
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
margin: 0 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions select {
|
|
||||||
vertical-align: top;
|
|
||||||
height: 1.5rem;
|
|
||||||
color: var(--body-fg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
padding: 0 0 0 4px;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions select:focus {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions label {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions .button {
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--body-bg);
|
|
||||||
box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 1.5rem;
|
|
||||||
line-height: 1;
|
|
||||||
padding: 4px 8px;
|
|
||||||
margin: 0;
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#changelist .actions .button:focus, #changelist .actions .button:hover {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--primary: #264b5d;
|
|
||||||
--primary-fg: #f7f7f7;
|
|
||||||
|
|
||||||
--body-fg: #eeeeee;
|
|
||||||
--body-bg: #121212;
|
|
||||||
--body-quiet-color: #d0d0d0;
|
|
||||||
--body-medium-color: #e0e0e0;
|
|
||||||
--body-loud-color: #ffffff;
|
|
||||||
|
|
||||||
--breadcrumbs-link-fg: #e0e0e0;
|
|
||||||
--breadcrumbs-bg: var(--primary);
|
|
||||||
|
|
||||||
--link-fg: #81d4fa;
|
|
||||||
--link-hover-color: #4ac1f7;
|
|
||||||
--link-selected-fg: #6f94c6;
|
|
||||||
|
|
||||||
--hairline-color: #272727;
|
|
||||||
--border-color: #353535;
|
|
||||||
|
|
||||||
--error-fg: #e35f5f;
|
|
||||||
--message-success-bg: #006b1b;
|
|
||||||
--message-warning-bg: #583305;
|
|
||||||
--message-error-bg: #570808;
|
|
||||||
|
|
||||||
--darkened-bg: #212121;
|
|
||||||
--selected-bg: #1b1b1b;
|
|
||||||
--selected-row: #00363a;
|
|
||||||
|
|
||||||
--close-button-bg: #333333;
|
|
||||||
--close-button-hover-bg: #666666;
|
|
||||||
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--primary: #264b5d;
|
|
||||||
--primary-fg: #f7f7f7;
|
|
||||||
|
|
||||||
--body-fg: #eeeeee;
|
|
||||||
--body-bg: #121212;
|
|
||||||
--body-quiet-color: #d0d0d0;
|
|
||||||
--body-medium-color: #e0e0e0;
|
|
||||||
--body-loud-color: #ffffff;
|
|
||||||
|
|
||||||
--breadcrumbs-link-fg: #e0e0e0;
|
|
||||||
--breadcrumbs-bg: var(--primary);
|
|
||||||
|
|
||||||
--link-fg: #81d4fa;
|
|
||||||
--link-hover-color: #4ac1f7;
|
|
||||||
--link-selected-fg: #6f94c6;
|
|
||||||
|
|
||||||
--hairline-color: #272727;
|
|
||||||
--border-color: #353535;
|
|
||||||
|
|
||||||
--error-fg: #e35f5f;
|
|
||||||
--message-success-bg: #006b1b;
|
|
||||||
--message-warning-bg: #583305;
|
|
||||||
--message-error-bg: #570808;
|
|
||||||
|
|
||||||
--darkened-bg: #212121;
|
|
||||||
--selected-bg: #1b1b1b;
|
|
||||||
--selected-row: #00363a;
|
|
||||||
|
|
||||||
--close-button-bg: #333333;
|
|
||||||
--close-button-hover-bg: #666666;
|
|
||||||
|
|
||||||
color-scheme: dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* THEME SWITCH */
|
|
||||||
.theme-toggle {
|
|
||||||
cursor: pointer;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin-inline-start: 5px;
|
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-toggle svg {
|
|
||||||
vertical-align: middle;
|
|
||||||
height: 1.5rem;
|
|
||||||
width: 1.5rem;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fully hide screen reader text so we only show the one matching the current
|
|
||||||
theme.
|
|
||||||
*/
|
|
||||||
.theme-toggle .visually-hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="auto"] .theme-toggle .theme-label-when-auto {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="dark"] .theme-toggle .theme-label-when-dark {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="light"] .theme-toggle .theme-label-when-light {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ICONS */
|
|
||||||
.theme-toggle svg.theme-icon-when-auto,
|
|
||||||
.theme-toggle svg.theme-icon-when-dark,
|
|
||||||
.theme-toggle svg.theme-icon-when-light {
|
|
||||||
fill: var(--header-link-color);
|
|
||||||
color: var(--header-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="light"] .theme-toggle svg.theme-icon-when-light {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/* DASHBOARD */
|
|
||||||
.dashboard td, .dashboard th {
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard .module table th {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard .module table td {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard .module table td a {
|
|
||||||
display: block;
|
|
||||||
padding-right: .6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RECENT ACTIONS MODULE */
|
|
||||||
|
|
||||||
.module ul.actionlist {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.actionlist li {
|
|
||||||
list-style-type: none;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
@@ -1,498 +0,0 @@
|
|||||||
@import url('widgets.css');
|
|
||||||
|
|
||||||
/* FORM ROWS */
|
|
||||||
|
|
||||||
.form-row {
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row img, .form-row input {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row label input[type="checkbox"] {
|
|
||||||
margin-top: 0;
|
|
||||||
vertical-align: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .form-row p {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-multiline {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-multiline > div {
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FORM LABELS */
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-weight: normal;
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.required label, label.required {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RADIO BUTTONS */
|
|
||||||
|
|
||||||
form div.radiolist div {
|
|
||||||
padding-right: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form div.radiolist.inline div {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
form div.radiolist label {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
form div.radiolist input[type="radio"] {
|
|
||||||
margin: -2px 4px 0 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form ul.inline {
|
|
||||||
margin-left: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form ul.inline li {
|
|
||||||
float: left;
|
|
||||||
padding-right: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIELDSETS */
|
|
||||||
|
|
||||||
fieldset .fieldset-heading,
|
|
||||||
fieldset .inline-heading,
|
|
||||||
:not(.inline-related) .collapse summary {
|
|
||||||
border: 1px solid var(--header-bg);
|
|
||||||
margin: 0;
|
|
||||||
padding: 8px;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
background: var(--header-bg);
|
|
||||||
color: var(--header-link-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ALIGNED FIELDSETS */
|
|
||||||
|
|
||||||
.aligned label {
|
|
||||||
display: block;
|
|
||||||
padding: 4px 10px 0 0;
|
|
||||||
min-width: 160px;
|
|
||||||
width: 160px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned label:not(.vCheckboxLabel):after {
|
|
||||||
content: '';
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned label + p, .aligned .checkbox-row + div.help, .aligned label + div.readonly {
|
|
||||||
padding: 6px 0;
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned ul label {
|
|
||||||
display: inline;
|
|
||||||
float: none;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned .form-row input {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField {
|
|
||||||
width: 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned ul {
|
|
||||||
margin-left: 160px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned div.radiolist {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned p.help,
|
|
||||||
form .aligned div.help {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-left: 160px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned p.date div.help.timezonewarning,
|
|
||||||
form .aligned p.datetime div.help.timezonewarning,
|
|
||||||
form .aligned p.time div.help.timezonewarning {
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned p.help:last-child,
|
|
||||||
form .aligned div.help:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned input + p.help,
|
|
||||||
form .aligned textarea + p.help,
|
|
||||||
form .aligned select + p.help,
|
|
||||||
form .aligned input + div.help,
|
|
||||||
form .aligned textarea + div.help,
|
|
||||||
form .aligned select + div.help {
|
|
||||||
margin-left: 160px;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned select option:checked {
|
|
||||||
background-color: var(--selected-row);
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned ul li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .aligned table p {
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned .vCheckboxLabel {
|
|
||||||
padding: 1px 0 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aligned .vCheckboxLabel + p.help,
|
|
||||||
.aligned .vCheckboxLabel + div.help {
|
|
||||||
margin-top: -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField {
|
|
||||||
width: 610px;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset .fieldBox {
|
|
||||||
margin-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* WIDE FIELDSETS */
|
|
||||||
|
|
||||||
.wide label {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .wide p.help,
|
|
||||||
form .wide ul.errorlist,
|
|
||||||
form .wide div.help {
|
|
||||||
padding-left: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
form div.help ul {
|
|
||||||
padding-left: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField {
|
|
||||||
width: 450px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* COLLAPSIBLE FIELDSETS */
|
|
||||||
|
|
||||||
.collapse summary .fieldset-heading,
|
|
||||||
.collapse summary .inline-heading {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
color: currentColor;
|
|
||||||
display: inline;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MONOSPACE TEXTAREAS */
|
|
||||||
|
|
||||||
fieldset.monospace textarea {
|
|
||||||
font-family: var(--font-family-monospace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* SUBMIT ROW */
|
|
||||||
|
|
||||||
.submit-row {
|
|
||||||
padding: 12px 14px 12px;
|
|
||||||
margin: 0 0 20px;
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
border: 1px solid var(--hairline-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.popup .submit-row {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row input {
|
|
||||||
height: 2.1875rem;
|
|
||||||
line-height: 0.9375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row input, .submit-row a {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row input.default {
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row a.deletelink {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row a.deletelink {
|
|
||||||
display: block;
|
|
||||||
background: var(--delete-button-bg);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 0.625rem 0.9375rem;
|
|
||||||
height: 0.9375rem;
|
|
||||||
line-height: 0.9375rem;
|
|
||||||
color: var(--button-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row a.closelink {
|
|
||||||
display: inline-block;
|
|
||||||
background: var(--close-button-bg);
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 10px 15px;
|
|
||||||
height: 0.9375rem;
|
|
||||||
line-height: 0.9375rem;
|
|
||||||
color: var(--button-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row a.deletelink:focus,
|
|
||||||
.submit-row a.deletelink:hover,
|
|
||||||
.submit-row a.deletelink:active {
|
|
||||||
background: var(--delete-button-hover-bg);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submit-row a.closelink:focus,
|
|
||||||
.submit-row a.closelink:hover,
|
|
||||||
.submit-row a.closelink:active {
|
|
||||||
background: var(--close-button-hover-bg);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CUSTOM FORM FIELDS */
|
|
||||||
|
|
||||||
.vSelectMultipleField {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vCheckboxField {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vDateField, .vTimeField {
|
|
||||||
margin-right: 2px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vDateField {
|
|
||||||
min-width: 6.85em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vTimeField {
|
|
||||||
min-width: 4.7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vURLField {
|
|
||||||
width: 30em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vLargeTextField, .vXMLLargeTextField {
|
|
||||||
width: 48em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flatpages-flatpage #id_content {
|
|
||||||
height: 40.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.module table .vPositiveSmallIntegerField {
|
|
||||||
width: 2.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vIntegerField {
|
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vBigIntegerField {
|
|
||||||
width: 10em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vForeignKeyRawIdAdminField {
|
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vTextField, .vUUIDField {
|
|
||||||
width: 20em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* INLINES */
|
|
||||||
|
|
||||||
.inline-group {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 0 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group thead th {
|
|
||||||
padding: 8px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .aligned label {
|
|
||||||
width: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related h4,
|
|
||||||
.inline-related:not(.tabular) .collapse summary {
|
|
||||||
margin: 0;
|
|
||||||
color: var(--body-medium-color);
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
border: 1px solid var(--hairline-color);
|
|
||||||
border-left-color: var(--darkened-bg);
|
|
||||||
border-right-color: var(--darkened-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related h3 span.delete {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related h3 span.delete label {
|
|
||||||
margin-left: 2px;
|
|
||||||
font-size: 0.6875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related fieldset {
|
|
||||||
margin: 0;
|
|
||||||
background: var(--body-bg);
|
|
||||||
border: none;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular fieldset.module {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-related.tabular fieldset.module table {
|
|
||||||
width: 100%;
|
|
||||||
overflow-x: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last-related fieldset {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular tr.has_original td {
|
|
||||||
padding-top: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular tr td.original {
|
|
||||||
padding: 2px 0 0 0;
|
|
||||||
width: 0;
|
|
||||||
_position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular th.original {
|
|
||||||
width: 0px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular td.original p {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
height: 1.1em;
|
|
||||||
padding: 2px 9px;
|
|
||||||
overflow: hidden;
|
|
||||||
font-size: 0.5625rem;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
_width: 700px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group div.add-row,
|
|
||||||
.inline-group .tabular tr.add-row td {
|
|
||||||
color: var(--body-quiet-color);
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group .tabular tr.add-row td {
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-bottom: 1px solid var(--hairline-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-group div.add-row a,
|
|
||||||
.inline-group .tabular tr.add-row td a {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-form {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RELATED FIELD ADD ONE / LOOKUP */
|
|
||||||
|
|
||||||
.related-lookup {
|
|
||||||
margin-left: 5px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.related-lookup {
|
|
||||||
width: 1rem;
|
|
||||||
height: 1rem;
|
|
||||||
background-image: url(../img/search.svg);
|
|
||||||
}
|
|
||||||
|
|
||||||
form .related-widget-wrapper ul {
|
|
||||||
display: inline-block;
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearable-file-input input {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/* LOGIN FORM */
|
|
||||||
|
|
||||||
.login {
|
|
||||||
background: var(--darkened-bg);
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login #header {
|
|
||||||
height: auto;
|
|
||||||
padding: 15px 16px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login #header h1 {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login #header h1 a {
|
|
||||||
color: var(--header-link-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.login #content {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login #container {
|
|
||||||
background: var(--body-bg);
|
|
||||||
border: 1px solid var(--hairline-color);
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 28em;
|
|
||||||
min-width: 300px;
|
|
||||||
margin: 100px auto;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .form-row {
|
|
||||||
padding: 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .form-row label {
|
|
||||||
display: block;
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .form-row #id_username, .login .form-row #id_password {
|
|
||||||
padding: 8px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .submit-row {
|
|
||||||
padding: 1em 0 0 0;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login .password-reset-link {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
.sticky {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
max-height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-nav-sidebar {
|
|
||||||
z-index: 20;
|
|
||||||
left: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex: 0 0 23px;
|
|
||||||
width: 23px;
|
|
||||||
border: 0;
|
|
||||||
border-right: 1px solid var(--hairline-color);
|
|
||||||
background-color: var(--body-bg);
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
color: var(--link-fg);
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[dir="rtl"] .toggle-nav-sidebar {
|
|
||||||
border-left: 1px solid var(--hairline-color);
|
|
||||||
border-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-nav-sidebar:hover,
|
|
||||||
.toggle-nav-sidebar:focus {
|
|
||||||
background-color: var(--darkened-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar {
|
|
||||||
z-index: 15;
|
|
||||||
flex: 0 0 275px;
|
|
||||||
left: -276px;
|
|
||||||
margin-left: -276px;
|
|
||||||
border-top: 1px solid transparent;
|
|
||||||
border-right: 1px solid var(--hairline-color);
|
|
||||||
background-color: var(--body-bg);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[dir="rtl"] #nav-sidebar {
|
|
||||||
border-left: 1px solid var(--hairline-color);
|
|
||||||
border-right: 0;
|
|
||||||
left: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
right: -276px;
|
|
||||||
margin-right: -276px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-nav-sidebar::before {
|
|
||||||
content: '\00BB';
|
|
||||||
}
|
|
||||||
|
|
||||||
.main.shifted .toggle-nav-sidebar::before {
|
|
||||||
content: '\00AB';
|
|
||||||
}
|
|
||||||
|
|
||||||
.main > #nav-sidebar {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main.shifted > #nav-sidebar {
|
|
||||||
margin-left: 0;
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
[dir="rtl"] .main.shifted > #nav-sidebar {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar .module th {
|
|
||||||
width: 100%;
|
|
||||||
overflow-wrap: anywhere;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar .module th,
|
|
||||||
#nav-sidebar .module caption {
|
|
||||||
padding-left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar .module td {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
[dir="rtl"] #nav-sidebar .module th,
|
|
||||||
[dir="rtl"] #nav-sidebar .module caption {
|
|
||||||
padding-left: 8px;
|
|
||||||
padding-right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar .current-app .section:link,
|
|
||||||
#nav-sidebar .current-app .section:visited {
|
|
||||||
color: var(--header-color);
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar .current-model {
|
|
||||||
background: var(--selected-row);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (forced-colors: active) {
|
|
||||||
#nav-sidebar .current-model {
|
|
||||||
background-color: SelectedItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.main > #nav-sidebar + .content {
|
|
||||||
max-width: calc(100% - 23px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.main.shifted > #nav-sidebar + .content {
|
|
||||||
max-width: calc(100% - 299px);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
#nav-sidebar, #toggle-nav-sidebar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main > #nav-sidebar + .content,
|
|
||||||
.main.shifted > #nav-sidebar + .content {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-filter {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 2px 5px;
|
|
||||||
margin: 5px 0;
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
background-color: var(--darkened-bg);
|
|
||||||
color: var(--body-fg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-filter:focus {
|
|
||||||
border-color: var(--body-quiet-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-filter.no-results {
|
|
||||||
background: var(--message-error-bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-sidebar table {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user