fix(phonebook,ucp): v2.6.4 affichage des postes multi-groupes dans chaque onglet de groupe
This commit is contained in:
1 parent
8cb8f1cdf7
commit
f918c929f5
3 files changed
+69
-32
No files matched your search
+52
-27
@@ -48,14 +48,22 @@ class PhonebookManager
|
||||
CREATE INDEX IF NOT EXISTS idx_phonebook_group ON phonebook_contacts(group_name);
|
||||
");
|
||||
|
||||
// 1. Récupère la cartographie des groupes d'extensions
|
||||
$egRows = $db->query("SELECT id, name, members FROM extension_groups")->fetchAll();
|
||||
$extToGroup = [];
|
||||
// 1. Récupère la cartographie complète des groupes d'extensions (un poste peut appartenir à plusieurs groupes)
|
||||
$egRows = $db->query("SELECT id, name, members FROM extension_groups ORDER BY name COLLATE NOCASE ASC")->fetchAll();
|
||||
$extToGroups = [];
|
||||
foreach ($egRows as $eg) {
|
||||
$grpName = trim((string)($eg['name'] ?? ''));
|
||||
if ($grpName === '') {
|
||||
continue;
|
||||
}
|
||||
$members = json_decode((string)$eg['members'], true) ?: [];
|
||||
foreach ($members as $extNum) {
|
||||
if (!isset($extToGroup[(string)$extNum])) {
|
||||
$extToGroup[(string)$extNum] = trim((string)$eg['name']);
|
||||
$k = (string)$extNum;
|
||||
if (!isset($extToGroups[$k])) {
|
||||
$extToGroups[$k] = [];
|
||||
}
|
||||
if (!in_array($grpName, $extToGroups[$k], true)) {
|
||||
$extToGroups[$k][] = $grpName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +88,7 @@ class PhonebookManager
|
||||
$extNum = trim((string)$ext['extension']);
|
||||
$extName = trim((string)$ext['name']);
|
||||
$email = trim((string)($ext['voicemail_email'] ?? ''));
|
||||
$group = $extToGroup[$extNum] ?? 'Général';
|
||||
$group = !empty($extToGroups[$extNum]) ? implode(', ', $extToGroups[$extNum]) : 'Général';
|
||||
$activeExtIds[] = $extId;
|
||||
|
||||
$findStmt->execute([':ext_id' => $extId, ':num' => $extNum]);
|
||||
@@ -122,33 +130,48 @@ class PhonebookManager
|
||||
{
|
||||
self::syncExtensions($db);
|
||||
|
||||
$params = [];
|
||||
$sql = "SELECT * FROM phonebook_contacts";
|
||||
$stmt = $db->query("SELECT * FROM phonebook_contacts ORDER BY display_name COLLATE NOCASE ASC");
|
||||
$contacts = $stmt ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
|
||||
|
||||
if ($group !== null && trim($group) !== '' && strtolower(trim($group)) !== 'all' && strtolower(trim($group)) !== 'tous') {
|
||||
$cleanGroup = trim($group);
|
||||
$sql .= " WHERE LOWER(group_name) = LOWER(:grp) OR LOWER(group_name) LIKE LOWER(:grp_like) OR LOWER(group_name) IN ('tous', 'all')";
|
||||
$params[':grp'] = $cleanGroup;
|
||||
$params[':grp_like'] = "%{$cleanGroup}%";
|
||||
}
|
||||
$cleanGroup = ($group !== null) ? trim($group) : '';
|
||||
$filterByGroup = ($cleanGroup !== '' && !in_array(mb_strtolower($cleanGroup), ['all', 'tous'], true));
|
||||
$targetLower = mb_strtolower($cleanGroup);
|
||||
|
||||
$sql .= " ORDER BY display_name COLLATE NOCASE ASC";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$contacts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Vérification de la présence réelle du fichier sur le disque
|
||||
foreach ($contacts as &$c) {
|
||||
$result = [];
|
||||
foreach ($contacts as $c) {
|
||||
if (!empty($c['photo_url'])) {
|
||||
$filename = basename((string)$c['photo_url']);
|
||||
if (!file_exists(self::AVATARS_DIR . '/' . $filename)) {
|
||||
$c['photo_url'] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($c);
|
||||
|
||||
return $contacts;
|
||||
$rawGroups = preg_split('/\s*,\s*/', trim((string)($c['group_name'] ?? ''))) ?: [];
|
||||
$groupsList = array_values(array_unique(array_filter($rawGroups, fn($g) => $g !== '')));
|
||||
if (empty($groupsList)) {
|
||||
$groupsList = ['Général'];
|
||||
}
|
||||
$c['groups'] = $groupsList;
|
||||
$c['group_name'] = implode(', ', $groupsList);
|
||||
|
||||
if ($filterByGroup) {
|
||||
$matched = false;
|
||||
foreach ($groupsList as $g) {
|
||||
$gLower = mb_strtolower($g);
|
||||
if ($gLower === $targetLower || in_array($gLower, ['tous', 'all'], true)) {
|
||||
$matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$matched) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $c;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,9 +186,11 @@ class PhonebookManager
|
||||
if ($g !== '') $groups[$g] = true;
|
||||
}
|
||||
$pbRows = $db->query("SELECT DISTINCT group_name FROM phonebook_contacts WHERE group_name != ''")->fetchAll(PDO::FETCH_COLUMN);
|
||||
foreach ($pbRows as $g) {
|
||||
$g = trim((string)$g);
|
||||
if ($g !== '') $groups[$g] = true;
|
||||
foreach ($pbRows as $raw) {
|
||||
foreach (preg_split('/\s*,\s*/', trim((string)$raw)) ?: [] as $g) {
|
||||
$g = trim((string)$g);
|
||||
if ($g !== '') $groups[$g] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Ajoute Issy-Les-Moulineaux si pas encore présent
|
||||
|
||||
+15
-4
@@ -756,14 +756,26 @@ async function loadPhonebook() {
|
||||
}
|
||||
}
|
||||
|
||||
function getContactGroups(contact) {
|
||||
if (Array.isArray(contact?.groups) && contact.groups.length > 0) {
|
||||
return contact.groups.map(g => String(g || '').trim()).filter(Boolean);
|
||||
}
|
||||
const split = String(contact?.group_name || '')
|
||||
.split(',')
|
||||
.map(g => g.trim())
|
||||
.filter(Boolean);
|
||||
return split.length > 0 ? Array.from(new Set(split)) : ['Général'];
|
||||
}
|
||||
|
||||
function renderPhonebookGroupTabs(allContacts) {
|
||||
const tabsEl = document.getElementById('ucp-pb-group-tabs');
|
||||
if (!tabsEl) return;
|
||||
|
||||
const counts = {};
|
||||
for (const c of allContacts) {
|
||||
const grp = String(c.group_name || '').trim() || 'Général';
|
||||
counts[grp] = (counts[grp] || 0) + 1;
|
||||
for (const grp of getContactGroups(c)) {
|
||||
counts[grp] = (counts[grp] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
const groups = Object.keys(counts).sort((a, b) => {
|
||||
@@ -821,8 +833,7 @@ function renderPhonebookGrid() {
|
||||
const activeGroup = ucpState.selectedPbGroup || '__all__';
|
||||
const q = (document.getElementById('ucp-pb-search')?.value || '').trim().toLowerCase();
|
||||
const list = allContacts.filter(c => {
|
||||
const grp = String(c.group_name || '').trim() || 'Général';
|
||||
if (activeGroup !== '__all__' && grp !== activeGroup) return false;
|
||||
if (activeGroup !== '__all__' && !getContactGroups(c).includes(activeGroup)) return false;
|
||||
if (!q) return true;
|
||||
return [c.display_name, c.internal_number, c.mobile_number, c.other_number, c.email, c.group_name]
|
||||
.some(v => String(v || '').toLowerCase().includes(q));
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"version": "2.6.3",
|
||||
"version": "2.6.4",
|
||||
"codename": "Pulsar UCP",
|
||||
"release_date": "2026-11-12",
|
||||
"min_php_version": "8.2",
|
||||
"changelog": [
|
||||
"Correctif v2.6.4 : prise en charge multi-groupes dans l'annuaire UCP & Admin (un poste appartenant à plusieurs groupes apparaît bien dans chacun des onglets correspondants)",
|
||||
"UI v2.6.3 : onglets dynamiques par groupe (Tous, Général, Paris, New-York...) avec compteurs dans l'Annuaire UCP",
|
||||
"Correctif v2.6.2 : sélection stricte de <host> GroundWire (NAT si renseigné, sinon VIP HA si cluster actif, sinon IP locale + port d'écoute local)",
|
||||
"UI v2.6.1 : suppression de l'icône smartphone sur les éléments GroundWire et refonte des boutons d'action du tableau Postes (Redémarrer / Modifier / Supprimer)",
|
||||
|
||||
Reference in new issue
Block a user