From 347b1db9ae2b5ba33ddbea8dd4be2bfff7860083 Mon Sep 17 00:00:00 2001 From: dv Date: Wed, 15 Apr 2026 10:33:11 +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=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/js/statistics.js | 48 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/public/js/statistics.js b/public/js/statistics.js index 3abdca3..da7891a 100644 --- a/public/js/statistics.js +++ b/public/js/statistics.js @@ -835,28 +835,34 @@ function renderClientLastTicketCard() { }).join('')}`; } +function getTaskCreator(task) { + // Ищем создателя по lifetime: самая ранняя запись с usertype=20 (внешний/клиент). + // lifetime.data отсортирован по убыванию (новые первые), поэтому ищем с конца. + const entries = task.lifetime?.data || []; + // Сначала ищем внешнего пользователя (клиента) + for (let i = entries.length - 1; i >= 0; i--) { + if (entries[i].usertype === 20 && entries[i].username) return entries[i].username; + } + // Fallback: последняя запись (самая ранняя) с любым username + for (let i = entries.length - 1; i >= 0; i--) { + if (entries[i].username) return entries[i].username; + } + return null; +} + function renderClientUsersCard() { const wrap = document.getElementById('stats-client-users-wrap'); if (!wrap) return; - // _clientname — организация (из справочника по clientid) - // clientname — сырое поле API: имя контакта/заявителя когда _clientname задан, - // либо имя организации если clientid не задан - // Собираем: организация → { total, users: { contactName → count } } + // Собираем: организация → { total, users: { creator → count } } const cMap = {}; allData.forEach((item) => { const t = item.task; const org = t._clientname || t.clientname || 'Неизвестно'; - // Контакт: clientname когда есть отдельное _clientname (org), иначе lastComment автор - let contact; - if (t._clientname && t.clientname && t._clientname !== t.clientname) { - contact = t.clientname; - } else { - contact = item.lastComment?.username || t.updatedby || '—'; - } + const creator = getTaskCreator(t) || '—'; if (!cMap[org]) cMap[org] = { total: 0, users: {} }; cMap[org].total++; - cMap[org].users[contact] = (cMap[org].users[contact] || 0) + 1; + cMap[org].users[creator] = (cMap[org].users[creator] || 0) + 1; }); const entries = Object.entries(cMap).sort((a, b) => b[1].total - a[1].total); @@ -866,15 +872,23 @@ function renderClientUsersCard() { wrap.innerHTML = `
${entries.map(([name, v]) => { const pct = v.total / maxTotal * 100; const safeName = escHtml(name).replace(/'/g, '''); - const usersList = Object.entries(v.users).sort((a, b) => b[1] - a[1]).map(([uname, cnt]) => { + 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 uPct = v.total ? cnt / v.total * 100 : 0; return `
${escHtml(uname)} - ${cnt} - ${Math.round(uPct)}% + ${cnt} + ${Math.round(uPct)}%
`; - }).join(''); + }).join('') + (unknownCount > 0 ? `
+
+ Неизвестен + ${unknownCount} + ${Math.round(unknownCount/v.total*100)}% +
` : ''); return `
${escHtml(name)}
@@ -883,7 +897,7 @@ function renderClientUsersCard() {
- ${v.total > 0 ? usersList : ''} + ${usersList}
`; }).join('')}
`; }