last update
This commit is contained in:
429
assets/js/dsi.js
429
assets/js/dsi.js
@@ -8,6 +8,13 @@
|
||||
* - le JOURNAL D'ACTIVITÉ : recherche filtrée et paginée, statistiques de tête,
|
||||
* purge des entrées anciennes.
|
||||
*
|
||||
* Le premier bloc est rendu par `comptes-acces.js`, partagé avec l'onglet
|
||||
* Administration : ce fichier ne lui apporte que ce qui est propre à la DSI —
|
||||
* les rôles privilégiés et leur champ « Nom du titulaire », les badges de mot de
|
||||
* passe (V7.12), l'alerte du jeton d'installation et le bouton qui filtre le
|
||||
* journal sur un compte. Le second bloc, le journal, n'existe QUE sur cet écran
|
||||
* et vit donc entièrement ici.
|
||||
*
|
||||
* RÈGLE CENTRALE DE L'ÉCRAN : un jeton n'existe en clair que dans la réponse qui
|
||||
* vient de le produire. Il est donc affiché dans un panneau dédié, qui reste
|
||||
* ouvert tant que la DSI ne l'a pas refermé, et n'est jamais rechargé depuis le
|
||||
@@ -17,11 +24,13 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
const PTA = window.PTA;
|
||||
// core.js absent : la page reste lisible, simplement non interactive.
|
||||
if (!PTA) return;
|
||||
// core.js ou comptes-acces.js absent : la page reste lisible, simplement non
|
||||
// interactive.
|
||||
if (!PTA?.shared?.ecranComptesAcces) return;
|
||||
|
||||
const { readJsonResponse, apiErrorMessage, escapeHtml } = PTA.utils;
|
||||
const { apiJson, postJson, showMessageIn, formatDateTime, escapeHtml } = PTA.utils;
|
||||
const el = (id) => document.getElementById(id);
|
||||
const message = (id, texte, type = 'info') => showMessageIn(id, texte, type);
|
||||
|
||||
/** Page courante du journal, seul état conservé par le module. */
|
||||
let pageJournal = 1;
|
||||
@@ -41,352 +50,89 @@
|
||||
SYSTEME: 'Système',
|
||||
};
|
||||
|
||||
/** Message dans un des bandeaux de la page. */
|
||||
function message(id, texte, type = 'info') {
|
||||
const boite = el(id);
|
||||
if (!boite) return;
|
||||
boite.className = `message message-${type}`;
|
||||
boite.textContent = texte;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appel d'API mutualisé : lit le JSON et transforme toute réponse non-OK en
|
||||
* exception. Toutes les actions de la page passent par ici.
|
||||
*/
|
||||
async function api(url, options = {}) {
|
||||
const reponse = await fetch(url, options);
|
||||
const donnees = await readJsonResponse(reponse);
|
||||
if (!reponse.ok) throw new Error(apiErrorMessage(donnees, 'Opération impossible.'));
|
||||
return donnees;
|
||||
}
|
||||
|
||||
/** Raccourci des appels mutants : POST JSON avec le jeton CSRF du corps. */
|
||||
function poster(url, charge) {
|
||||
return api(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ csrf_token: window.PTA_CONFIG.csrfToken, ...charge }),
|
||||
});
|
||||
}
|
||||
|
||||
/** « 2026-08-20 09:41:07.482 » → « 20/08/2026 09:41 ». */
|
||||
function formatDateHeure(valeur) {
|
||||
if (!valeur) return '—';
|
||||
const [date, heure = ''] = String(valeur).split(' ');
|
||||
const [annee, mois, jour] = date.split('-');
|
||||
return `${jour}/${mois}/${annee} ${heure.slice(0, 5)}`;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ jetons
|
||||
|
||||
/**
|
||||
* Affiche les jetons produits par la dernière action.
|
||||
*
|
||||
* @param {Array<{libelle: string, role: string, jeton: string}>} jetons
|
||||
*/
|
||||
function afficherJetons(jetons) {
|
||||
const panneau = el('dsi-token-panel');
|
||||
const liste = el('dsi-token-list');
|
||||
if (!panneau || !liste || !jetons.length) return;
|
||||
|
||||
liste.innerHTML = jetons.map((entree) => `
|
||||
<div class="dsi-token-row">
|
||||
<div class="dsi-token-identity">
|
||||
<strong>${escapeHtml(entree.libelle)}</strong>
|
||||
<small>${escapeHtml(LIBELLES_ROLE[entree.role] || entree.role)}</small>
|
||||
</div>
|
||||
<code class="dsi-token-value">${escapeHtml(entree.jeton)}</code>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
panneau.hidden = false;
|
||||
message('dsi-token-message', `${jetons.length} jeton(s) à transmettre. Ils ne seront plus affichés après fermeture. Les comptes Service Enfance et DSI choisiront en plus un mot de passe à leur première connexion.`, 'warning');
|
||||
panneau.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
|
||||
/**
|
||||
* Copie les jetons affichés dans le presse-papiers.
|
||||
*
|
||||
* L'API Clipboard n'existe QUE dans un contexte sécurisé : sur une
|
||||
* installation en http:// sur le réseau de la collectivité, elle est
|
||||
* absente. D'où le repli par zone de texte masquée, puis, en dernier
|
||||
* ressort, l'invitation à sélectionner à la main.
|
||||
*/
|
||||
async function copierJetons() {
|
||||
const lignes = Array.from(document.querySelectorAll('#dsi-token-list .dsi-token-row')).map((ligne) => {
|
||||
const identite = ligne.querySelector('strong')?.textContent || '';
|
||||
const jeton = ligne.querySelector('.dsi-token-value')?.textContent || '';
|
||||
return `${identite}\t${jeton}`;
|
||||
});
|
||||
if (!lignes.length) return;
|
||||
|
||||
const texte = lignes.join('\n');
|
||||
try {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(texte);
|
||||
} else {
|
||||
const zone = document.createElement('textarea');
|
||||
zone.value = texte;
|
||||
zone.setAttribute('readonly', 'readonly');
|
||||
zone.className = 'dsi-clipboard-relay';
|
||||
document.body.appendChild(zone);
|
||||
zone.select();
|
||||
document.execCommand('copy');
|
||||
zone.remove();
|
||||
}
|
||||
message('dsi-token-message', `${lignes.length} jeton(s) copié(s) dans le presse-papiers.`, 'success');
|
||||
} catch (erreur) {
|
||||
message('dsi-token-message', 'Copie impossible sur ce navigateur : sélectionnez les jetons à la main.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/** Referme le panneau des jetons ; leur contenu est perdu pour de bon. */
|
||||
function fermerJetons() {
|
||||
const panneau = el('dsi-token-panel');
|
||||
if (!panneau) return;
|
||||
panneau.hidden = true;
|
||||
el('dsi-token-list').innerHTML = '';
|
||||
message('dsi-token-message', '');
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- comptes
|
||||
|
||||
/** Une ligne du tableau des comptes. */
|
||||
function ligneCompte(compte) {
|
||||
const identite = [
|
||||
`<strong>${escapeHtml(compte.identite_libelle)}</strong>`,
|
||||
compte.matricule ? `<br><small>Matricule ${escapeHtml(compte.matricule)}</small>` : '',
|
||||
compte.commentaire ? `<br><small>${escapeHtml(compte.commentaire)}</small>` : '',
|
||||
].join('');
|
||||
|
||||
/**
|
||||
* Badges d'état propres à la DSI, ajoutés à « Actif / Désactivé ».
|
||||
*
|
||||
* Second facteur (V7.12) : seuls les comptes Service Enfance et DSI en
|
||||
* portent un. « À définir » n'est pas une anomalie — c'est l'état normal
|
||||
* d'un compte neuf ou fraîchement réinitialisé.
|
||||
*/
|
||||
function etatsCompte(compte) {
|
||||
const etats = [];
|
||||
if (!compte.actif) etats.push('<span class="dsi-state dsi-state-off">Désactivé</span>');
|
||||
else if (!compte.identite_active) etats.push('<span class="dsi-state dsi-state-off">Identité inactive</span>');
|
||||
else etats.push('<span class="dsi-state dsi-state-on">Actif</span>');
|
||||
if (compte.jeton_installation) etats.push('<span class="dsi-state dsi-state-alert">Jeton d’installation</span>');
|
||||
// Second facteur (V7.12) : seuls les comptes Service Enfance et DSI en
|
||||
// portent un. « À définir » n'est pas une anomalie — c'est l'état normal
|
||||
// d'un compte neuf ou fraîchement réinitialisé.
|
||||
if (compte.mot_de_passe_requis) {
|
||||
etats.push(compte.mot_de_passe_defini
|
||||
? '<span class="dsi-state dsi-state-on">Mot de passe défini</span>'
|
||||
: '<span class="dsi-state dsi-state-wait">Mot de passe à définir</span>');
|
||||
}
|
||||
|
||||
const connexions = compte.nombre_connexions > 0
|
||||
? `<br><small>${compte.nombre_connexions} connexion(s)</small>`
|
||||
: '';
|
||||
|
||||
return `
|
||||
<tr data-compte-id="${Number(compte.id_compte)}">
|
||||
<td>${identite}</td>
|
||||
<td>${escapeHtml(LIBELLES_ROLE[compte.role] || compte.role)}</td>
|
||||
<td><code>${escapeHtml(compte.jeton_prefixe)}…</code></td>
|
||||
<td>${formatDateHeure(compte.date_derniere_connexion)}${connexions}</td>
|
||||
<td>${etats.join(' ')}</td>
|
||||
<td class="dsi-actions-cell">
|
||||
<button type="button" class="button button-secondary dsi-regenerate">Régénérer</button>
|
||||
<button type="button" class="button button-secondary dsi-toggle">${compte.actif ? 'Désactiver' : 'Réactiver'}</button>
|
||||
${compte.mot_de_passe_requis && compte.mot_de_passe_defini
|
||||
? '<button type="button" class="button button-secondary dsi-reset-password">Effacer le mot de passe</button>'
|
||||
: ''}
|
||||
<button type="button" class="button button-danger dsi-delete">Supprimer</button>
|
||||
<button type="button" class="button button-secondary dsi-see-journal">Journal</button>
|
||||
</td>
|
||||
</tr>`;
|
||||
return etats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplit les listes déroulantes de création à partir des identités SANS
|
||||
* compte : proposer un agent qui en a déjà un ne mènerait qu'à un refus du
|
||||
* serveur (un seul compte par identité).
|
||||
* Boutons propres à la DSI en fin de ligne : effacement du mot de passe (la
|
||||
* DSI peut l'effacer, jamais en poser un) et accès au journal du compte.
|
||||
*/
|
||||
function remplirIdentites(manquants) {
|
||||
const agents = manquants.filter((identite) => identite.role === 'AGENT');
|
||||
const lieux = manquants.filter((identite) => identite.role === 'RESPONSABLE_STRUCTURE');
|
||||
|
||||
const selectAgent = el('dsi-account-agent');
|
||||
const selectLieu = el('dsi-account-structure');
|
||||
if (selectAgent) {
|
||||
selectAgent.innerHTML = '<option value="">Choisir un agent sans compte</option>'
|
||||
+ agents.map((agent) => `<option value="${Number(agent.id_agent)}">${escapeHtml(agent.libelle)}</option>`).join('');
|
||||
}
|
||||
if (selectLieu) {
|
||||
selectLieu.innerHTML = '<option value="">Choisir un lieu sans compte</option>'
|
||||
+ lieux.map((lieu) => `<option value="${Number(lieu.id_structure)}">${escapeHtml(lieu.libelle)}</option>`).join('');
|
||||
}
|
||||
|
||||
const compteur = el('dsi-missing-count');
|
||||
if (compteur) {
|
||||
compteur.textContent = String(manquants.length);
|
||||
compteur.hidden = manquants.length === 0;
|
||||
}
|
||||
const bouton = el('dsi-generate-missing');
|
||||
if (bouton) bouton.disabled = manquants.length === 0;
|
||||
function actionsCompte(compte) {
|
||||
return [
|
||||
compte.mot_de_passe_requis && compte.mot_de_passe_defini
|
||||
? '<button type="button" class="button button-secondary compte-reset-password">Effacer le mot de passe</button>'
|
||||
: '',
|
||||
'<button type="button" class="button button-secondary compte-journal">Journal</button>',
|
||||
].join('');
|
||||
}
|
||||
|
||||
/** Recharge la liste des comptes selon les filtres courants. */
|
||||
async function chargerComptes() {
|
||||
const parametres = new URLSearchParams();
|
||||
const role = el('dsi-filter-role')?.value || '';
|
||||
const etat = el('dsi-filter-state')?.value || '';
|
||||
const recherche = el('dsi-filter-search')?.value.trim() || '';
|
||||
if (role) parametres.set('role', role);
|
||||
if (etat !== '') parametres.set('actif', etat);
|
||||
if (recherche) parametres.set('q', recherche);
|
||||
/**
|
||||
* Traite les deux boutons que la fabrique ne connaît pas.
|
||||
* @returns {boolean} Vrai s'il faut recharger la liste des comptes derrière.
|
||||
*/
|
||||
async function actionCompte(evenement, { bouton, compteId, titulaire }) {
|
||||
if (bouton.classList.contains('compte-reset-password')) {
|
||||
if (!window.confirm(`Effacer le mot de passe de ${titulaire} ? Son jeton reste valable, et il en choisira un nouveau à sa prochaine connexion.`)) return false;
|
||||
const donnees = await postJson('api/dsi_compte_mot_de_passe.php', { compte_id: compteId });
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
return true;
|
||||
}
|
||||
|
||||
message('dsi-accounts-message', 'Chargement des comptes…');
|
||||
try {
|
||||
const donnees = await api(`api/dsi_comptes.php?${parametres.toString()}`);
|
||||
const comptes = donnees.comptes || [];
|
||||
el('dsi-accounts-body').innerHTML = comptes.length
|
||||
? comptes.map(ligneCompte).join('')
|
||||
: '<tr><td colspan="6">Aucun compte ne correspond à ces filtres.</td></tr>';
|
||||
remplirIdentites(donnees.manquants || []);
|
||||
if (bouton.classList.contains('compte-journal')) {
|
||||
// Filtre le journal sur ce compte, sans quitter la page ni toucher
|
||||
// à la liste des comptes.
|
||||
el('dsi-journal-search').value = '';
|
||||
pageJournal = 1;
|
||||
await chargerJournal({ id_compte: compteId });
|
||||
el('dsi-journal-body')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const ecranComptes = PTA.shared.ecranComptesAcces({
|
||||
prefixe: 'dsi',
|
||||
endpoints: {
|
||||
liste: 'api/dsi_comptes.php',
|
||||
creer: 'api/dsi_compte_creer.php',
|
||||
jeton: 'api/dsi_compte_jeton.php',
|
||||
statut: 'api/dsi_compte_statut.php',
|
||||
manquants: 'api/dsi_comptes_manquants.php',
|
||||
},
|
||||
// Seul l'espace DSI crée des comptes sans identité en base : eux seuls
|
||||
// ont besoin du champ libre « Nom du titulaire », et de ces deux aides.
|
||||
avecLibelle: true,
|
||||
aides: {
|
||||
SERVICE_ENFANCE: 'Compte d’administration métier : accès à tous les lieux, à tous les agents et à la validation des plannings. Il n’est rattaché à aucun agent en base — indiquez simplement le nom de son titulaire. Son titulaire choisira un mot de passe à sa première connexion, en plus du jeton.',
|
||||
DSI: 'Compte d’administration technique : comptes d’accès et journal uniquement, aucun accès aux plannings. Prévoyez-en au moins deux, pour ne pas dépendre d’un seul jeton. Son titulaire choisira un mot de passe à sa première connexion, en plus du jeton.',
|
||||
},
|
||||
rappelJetons: ' Les comptes Service Enfance et DSI choisiront en plus un mot de passe à leur première connexion.',
|
||||
etatsSupplementaires: etatsCompte,
|
||||
actionsSupplementaires: actionsCompte,
|
||||
actionPersonnalisee: actionCompte,
|
||||
// Le jeton d'installation est publié en clair dans la migration SQL :
|
||||
// l'alerte reste affichée tant qu'il n'a pas été régénéré.
|
||||
apresChargement: (donnees) => {
|
||||
const alerte = el('dsi-installation-warning');
|
||||
if (alerte) alerte.hidden = !donnees.jeton_installation_actif;
|
||||
|
||||
message('dsi-accounts-message', `${comptes.length} compte(s) affiché(s).`, 'success');
|
||||
} catch (erreur) {
|
||||
message('dsi-accounts-message', erreur.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ce qu'il faut renseigner change entièrement selon le type de compte :
|
||||
* l'écran l'explique plutôt que de laisser deviner pourquoi un champ
|
||||
* apparaît ou disparaît.
|
||||
*/
|
||||
const AIDES_ROLE = {
|
||||
SERVICE_ENFANCE: 'Compte d’administration métier : accès à tous les lieux, à tous les agents et à la validation des plannings. Il n’est rattaché à aucun agent en base — indiquez simplement le nom de son titulaire. Son titulaire choisira un mot de passe à sa première connexion, en plus du jeton.',
|
||||
DSI: 'Compte d’administration technique : comptes d’accès et journal uniquement, aucun accès aux plannings. Prévoyez-en au moins deux, pour ne pas dépendre d’un seul jeton. Son titulaire choisira un mot de passe à sa première connexion, en plus du jeton.',
|
||||
AGENT: 'Compte en lecture seule sur son propre planning. Seuls les agents actifs qui n’ont pas encore de compte sont proposés.',
|
||||
RESPONSABLE_STRUCTURE: 'Compte d’édition des brouillons d’un seul lieu. Seuls les lieux actifs qui n’ont pas encore de compte sont proposés.',
|
||||
};
|
||||
|
||||
/** Affiche les seuls champs d'identité utiles au type de compte choisi. */
|
||||
function ajusterFormulaireCompte() {
|
||||
const role = el('dsi-account-role')?.value || '';
|
||||
const champAgent = el('dsi-account-agent-field');
|
||||
const champLieu = el('dsi-account-structure-field');
|
||||
const champLibelle = el('dsi-account-label-field');
|
||||
if (!champAgent || !champLieu || !champLibelle) return;
|
||||
|
||||
champAgent.hidden = role !== 'AGENT';
|
||||
champLieu.hidden = role !== 'RESPONSABLE_STRUCTURE';
|
||||
// Service Enfance et DSI ne pointent vers aucune identité en base : leur
|
||||
// seul identifiant lisible est le libellé saisi ici.
|
||||
champLibelle.hidden = role === 'AGENT' || role === 'RESPONSABLE_STRUCTURE';
|
||||
|
||||
el('dsi-account-agent').required = role === 'AGENT';
|
||||
el('dsi-account-structure').required = role === 'RESPONSABLE_STRUCTURE';
|
||||
el('dsi-account-label').required = !champLibelle.hidden;
|
||||
|
||||
const aide = el('dsi-account-hint');
|
||||
if (aide) aide.textContent = AIDES_ROLE[role] || '';
|
||||
}
|
||||
|
||||
/** Crée un compte, puis affiche son jeton — unique occasion de le lire. */
|
||||
async function creerCompte(evenement) {
|
||||
evenement.preventDefault();
|
||||
const role = el('dsi-account-role').value;
|
||||
|
||||
try {
|
||||
const donnees = await poster('api/dsi_compte_creer.php', {
|
||||
role,
|
||||
agent_id: role === 'AGENT' ? Number(el('dsi-account-agent').value) : null,
|
||||
structure_id: role === 'RESPONSABLE_STRUCTURE' ? Number(el('dsi-account-structure').value) : null,
|
||||
libelle: el('dsi-account-label').value,
|
||||
commentaire: el('dsi-account-comment').value,
|
||||
});
|
||||
message('dsi-account-message', donnees.message, 'success');
|
||||
el('dsi-account-label').value = '';
|
||||
el('dsi-account-comment').value = '';
|
||||
afficherJetons([{
|
||||
libelle: donnees.compte?.identite_libelle || '',
|
||||
role: donnees.compte?.role || role,
|
||||
jeton: donnees.jeton,
|
||||
}]);
|
||||
await chargerComptes();
|
||||
} catch (erreur) {
|
||||
message('dsi-account-message', erreur.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/** Régénération, activation, suppression : délégation sur le tableau. */
|
||||
async function agirSurCompte(evenement) {
|
||||
const ligne = evenement.target.closest('tr[data-compte-id]');
|
||||
if (!ligne) return;
|
||||
const compteId = Number(ligne.dataset.compteId);
|
||||
const titulaire = ligne.querySelector('strong')?.textContent || 'ce compte';
|
||||
|
||||
try {
|
||||
if (evenement.target.closest('.dsi-regenerate')) {
|
||||
if (!window.confirm(`Régénérer le jeton de ${titulaire} ? L’ancien cessera immédiatement de fonctionner.`)) return;
|
||||
const donnees = await poster('api/dsi_compte_jeton.php', { compte_id: compteId });
|
||||
afficherJetons([{
|
||||
libelle: donnees.compte?.identite_libelle || titulaire,
|
||||
role: donnees.compte?.role || '',
|
||||
jeton: donnees.jeton,
|
||||
}]);
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
await chargerComptes();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evenement.target.closest('.dsi-reset-password')) {
|
||||
if (!window.confirm(`Effacer le mot de passe de ${titulaire} ? Son jeton reste valable, et il en choisira un nouveau à sa prochaine connexion.`)) return;
|
||||
const donnees = await poster('api/dsi_compte_mot_de_passe.php', { compte_id: compteId });
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
await chargerComptes();
|
||||
return;
|
||||
}
|
||||
|
||||
const bascule = evenement.target.closest('.dsi-toggle');
|
||||
if (bascule) {
|
||||
const action = bascule.textContent.trim() === 'Désactiver' ? 'DESACTIVER' : 'ACTIVER';
|
||||
const donnees = await poster('api/dsi_compte_statut.php', { compte_id: compteId, action });
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
await chargerComptes();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evenement.target.closest('.dsi-delete')) {
|
||||
if (!window.confirm(`Supprimer définitivement le compte de ${titulaire} ? Ses traces dans le journal seront conservées.`)) return;
|
||||
const donnees = await poster('api/dsi_compte_statut.php', { compte_id: compteId, action: 'SUPPRIMER' });
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
await chargerComptes();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evenement.target.closest('.dsi-see-journal')) {
|
||||
// Filtre le journal sur ce compte, sans quitter la page.
|
||||
el('dsi-journal-search').value = '';
|
||||
pageJournal = 1;
|
||||
await chargerJournal({ id_compte: compteId });
|
||||
el('dsi-journal-body')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
} catch (erreur) {
|
||||
message('dsi-accounts-message', erreur.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/** Équipe d'un coup toutes les identités actives sans compte. */
|
||||
async function genererManquants() {
|
||||
const attendus = Number(el('dsi-missing-count')?.textContent || 0);
|
||||
if (!attendus) return;
|
||||
if (!window.confirm(`Générer ${attendus} jeton(s) ? Ils ne seront affichés qu’une seule fois, tout de suite après.`)) return;
|
||||
|
||||
try {
|
||||
const donnees = await poster('api/dsi_comptes_manquants.php', {});
|
||||
message('dsi-accounts-message', donnees.message, 'success');
|
||||
afficherJetons(donnees.jetons || []);
|
||||
await chargerComptes();
|
||||
} catch (erreur) {
|
||||
message('dsi-accounts-message', erreur.message, 'error');
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// ----------------------------------------------------------------- journal
|
||||
|
||||
@@ -406,7 +152,7 @@
|
||||
|
||||
return `
|
||||
<tr class="dsi-journal-row${classeResultat}">
|
||||
<td>${formatDateHeure(entree.date_evenement)}</td>
|
||||
<td>${formatDateTime(entree.date_evenement)}</td>
|
||||
<td>${escapeHtml(LIBELLES_CATEGORIE[entree.categorie] || entree.categorie)}</td>
|
||||
<td>${escapeHtml(entree.acteur || 'Anonyme')}<br><small>${escapeHtml(LIBELLES_ROLE[entree.role] || entree.role || '—')}</small></td>
|
||||
<td><code>${escapeHtml(entree.action)}</code></td>
|
||||
@@ -454,7 +200,7 @@
|
||||
|
||||
message('dsi-journal-message', 'Chargement du journal…');
|
||||
try {
|
||||
const donnees = await api(`api/dsi_journal.php?${parametres.toString()}`);
|
||||
const donnees = await apiJson(`api/dsi_journal.php?${parametres.toString()}`);
|
||||
const entrees = donnees.entrees || [];
|
||||
el('dsi-journal-body').innerHTML = entrees.length
|
||||
? entrees.map(ligneJournal).join('')
|
||||
@@ -480,7 +226,7 @@
|
||||
if (!window.confirm(`Supprimer définitivement les entrées de plus de ${jours} jours ?`)) return;
|
||||
|
||||
try {
|
||||
const donnees = await poster('api/dsi_journal_purge.php', { jours });
|
||||
const donnees = await postJson('api/dsi_journal_purge.php', { jours });
|
||||
message('dsi-journal-message', donnees.message, 'success');
|
||||
pageJournal = 1;
|
||||
await chargerJournal();
|
||||
@@ -492,16 +238,9 @@
|
||||
function init() {
|
||||
const params = window.PTA_PAGE_CONFIG?.params || {};
|
||||
|
||||
el('dsi-account-role')?.addEventListener('change', ajusterFormulaireCompte);
|
||||
el('dsi-account-form')?.addEventListener('submit', creerCompte);
|
||||
el('dsi-accounts-body')?.addEventListener('click', agirSurCompte);
|
||||
el('dsi-accounts-refresh')?.addEventListener('click', chargerComptes);
|
||||
el('dsi-filter-role')?.addEventListener('change', chargerComptes);
|
||||
el('dsi-filter-state')?.addEventListener('change', chargerComptes);
|
||||
el('dsi-filter-search')?.addEventListener('change', chargerComptes);
|
||||
el('dsi-generate-missing')?.addEventListener('click', genererManquants);
|
||||
el('dsi-token-copy')?.addEventListener('click', copierJetons);
|
||||
el('dsi-token-close')?.addEventListener('click', fermerJetons);
|
||||
// Comptes, jetons et formulaire de création : branchés et chargés par la
|
||||
// fabrique partagée.
|
||||
ecranComptes.attacher();
|
||||
|
||||
['dsi-journal-category', 'dsi-journal-result', 'dsi-journal-role', 'dsi-journal-from', 'dsi-journal-to', 'dsi-journal-search']
|
||||
.forEach((identifiant) => el(identifiant)?.addEventListener('change', () => {
|
||||
@@ -519,11 +258,9 @@
|
||||
});
|
||||
el('dsi-purge-form')?.addEventListener('submit', purgerJournal);
|
||||
|
||||
ajusterFormulaireCompte();
|
||||
chargerComptes();
|
||||
// Lien profond « journal de ce compte » venu d'une autre page.
|
||||
chargerJournal(params.compteId ? { id_compte: params.compteId } : {});
|
||||
}
|
||||
|
||||
PTA.modules.dsi = { init, chargerComptes, chargerJournal };
|
||||
PTA.modules.dsi = { init, chargerComptes: ecranComptes.chargerComptes, chargerJournal };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user