From f2d3b5fc9629afe5147e6d526b2cdc9fa092f03b Mon Sep 17 00:00:00 2001 From: dv Date: Wed, 15 Apr 2026 13:52:55 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B8=2011?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/statistics.js | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/public/js/statistics.js b/public/js/statistics.js index 151eb79..16ac309 100644 --- a/public/js/statistics.js +++ b/public/js/statistics.js @@ -839,6 +839,17 @@ function renderClientUsersCard() { const wrap = document.getElementById('stats-client-users-wrap'); if (!wrap) return; + const UNKNOWN_USER_KEY = '__unknown__'; + const normalizeUserName = (value) => String(value || '') + .replace(/\u00A0/g, ' ') + .replace(/\s+/g, ' ') + .trim() + .toLowerCase(); + const displayUserName = (value) => String(value || '') + .replace(/\u00A0/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + // createdby — строка с именем создателя, приходит прямо из API // Базовый список клиентов берём из _allClients (все usergroup из dictionaries), // чтобы показывать клиентов с нулём заявок тоже. @@ -848,18 +859,30 @@ function renderClientUsersCard() { // Сначала заполняем всех известных клиентов с нулями, включая всех пользователей группы (window._allClients || []).forEach((c) => { const users = {}; - (clientUsers[String(c.client_id)] || []).forEach((u) => { users[u] = 0; }); - cMap[c.name] = { total: 0, users }; + const userLabels = {}; + (clientUsers[String(c.client_id)] || []).forEach((u) => { + const display = displayUserName(u); + const key = normalizeUserName(display); + if (!key) return; + users[key] = 0; + if (!userLabels[key]) userLabels[key] = display; + }); + cMap[c.name] = { total: 0, users, userLabels }; }); // Затем считаем реальные заявки allData.forEach((item) => { const t = item.task; const org = t._clientname || t.clientname || 'Неизвестно'; - const creator = t.createdby || '—'; - if (!cMap[org]) cMap[org] = { total: 0, users: {} }; + const creatorDisplay = displayUserName(t.createdby); + const isUnknownCreator = !creatorDisplay || creatorDisplay === '\u2014' || creatorDisplay === '-'; + const creatorKey = isUnknownCreator ? UNKNOWN_USER_KEY : normalizeUserName(creatorDisplay); + if (!cMap[org]) cMap[org] = { total: 0, users: {}, userLabels: {} }; cMap[org].total++; - cMap[org].users[creator] = (cMap[org].users[creator] || 0) + 1; + cMap[org].users[creatorKey] = (cMap[org].users[creatorKey] || 0) + 1; + if (!isUnknownCreator && !cMap[org].userLabels[creatorKey]) { + cMap[org].userLabels[creatorKey] = creatorDisplay; + } }); const entries = Object.entries(cMap).sort((a, b) => b[1].total - a[1].total); @@ -870,9 +893,10 @@ function renderClientUsersCard() { const pct = v.total / maxTotal * 100; const safeName = escHtml(name).replace(/'/g, '''); const sortedUsers = Object.entries(v.users).sort((a, b) => b[1] - a[1]); - const knownUsers = sortedUsers.filter(([u]) => u !== '—'); - const unknownCount = v.users['—'] || 0; - const usersList = knownUsers.map(([uname, cnt]) => { + const knownUsers = sortedUsers.filter(([key]) => key !== UNKNOWN_USER_KEY); + const unknownCount = v.users[UNKNOWN_USER_KEY] || 0; + const usersList = knownUsers.map(([key, cnt]) => { + const uname = v.userLabels?.[key] || key; const uPct = v.total ? cnt / v.total * 100 : 0; return `