This commit is contained in:
parent
1ea444791b
commit
347b1db9ae
1 changed files with 31 additions and 17 deletions
|
|
@ -835,28 +835,34 @@ function renderClientLastTicketCard() {
|
||||||
}).join('')}</div>`;
|
}).join('')}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
function renderClientUsersCard() {
|
||||||
const wrap = document.getElementById('stats-client-users-wrap');
|
const wrap = document.getElementById('stats-client-users-wrap');
|
||||||
if (!wrap) return;
|
if (!wrap) return;
|
||||||
|
|
||||||
// _clientname — организация (из справочника по clientid)
|
// Собираем: организация → { total, users: { creator → count } }
|
||||||
// clientname — сырое поле API: имя контакта/заявителя когда _clientname задан,
|
|
||||||
// либо имя организации если clientid не задан
|
|
||||||
// Собираем: организация → { total, users: { contactName → count } }
|
|
||||||
const cMap = {};
|
const cMap = {};
|
||||||
allData.forEach((item) => {
|
allData.forEach((item) => {
|
||||||
const t = item.task;
|
const t = item.task;
|
||||||
const org = t._clientname || t.clientname || 'Неизвестно';
|
const org = t._clientname || t.clientname || 'Неизвестно';
|
||||||
// Контакт: clientname когда есть отдельное _clientname (org), иначе lastComment автор
|
const creator = getTaskCreator(t) || '—';
|
||||||
let contact;
|
|
||||||
if (t._clientname && t.clientname && t._clientname !== t.clientname) {
|
|
||||||
contact = t.clientname;
|
|
||||||
} else {
|
|
||||||
contact = item.lastComment?.username || t.updatedby || '—';
|
|
||||||
}
|
|
||||||
if (!cMap[org]) cMap[org] = { total: 0, users: {} };
|
if (!cMap[org]) cMap[org] = { total: 0, users: {} };
|
||||||
cMap[org].total++;
|
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);
|
const entries = Object.entries(cMap).sort((a, b) => b[1].total - a[1].total);
|
||||||
|
|
@ -866,15 +872,23 @@ function renderClientUsersCard() {
|
||||||
wrap.innerHTML = `<div style="display:flex;flex-direction:column;gap:10px;max-height:500px;overflow-y:auto;">${entries.map(([name, v]) => {
|
wrap.innerHTML = `<div style="display:flex;flex-direction:column;gap:10px;max-height:500px;overflow-y:auto;">${entries.map(([name, v]) => {
|
||||||
const pct = v.total / maxTotal * 100;
|
const pct = v.total / maxTotal * 100;
|
||||||
const safeName = escHtml(name).replace(/'/g, ''');
|
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;
|
const uPct = v.total ? cnt / v.total * 100 : 0;
|
||||||
return `<div style="display:flex;align-items:center;gap:6px;margin-top:3px;padding-left:4px;">
|
return `<div style="display:flex;align-items:center;gap:6px;margin-top:3px;padding-left:4px;">
|
||||||
<div style="width:10px;height:10px;border-radius:50%;background:${avatarColor(uname)};flex-shrink:0;"></div>
|
<div style="width:10px;height:10px;border-radius:50%;background:${avatarColor(uname)};flex-shrink:0;"></div>
|
||||||
<span style="font-size:11px;color:var(--text2);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${escHtml(uname)}">${escHtml(uname)}</span>
|
<span style="font-size:11px;color:var(--text2);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${escHtml(uname)}">${escHtml(uname)}</span>
|
||||||
<span style="font-size:11px;font-weight:600;color:var(--text);min-width:20px;text-align:right;">${cnt}</span>
|
<span style="font-size:11px;font-weight:600;color:var(--text);min-width:24px;text-align:right;">${cnt}</span>
|
||||||
<span style="font-size:10px;color:var(--text3);min-width:34px;text-align:right;">${Math.round(uPct)}%</span>
|
<span style="font-size:10px;color:var(--text3);min-width:36px;text-align:right;">${Math.round(uPct)}%</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('') + (unknownCount > 0 ? `<div style="display:flex;align-items:center;gap:6px;margin-top:3px;padding-left:4px;">
|
||||||
|
<div style="width:10px;height:10px;border-radius:50%;background:var(--border2);flex-shrink:0;"></div>
|
||||||
|
<span style="font-size:11px;color:var(--text3);flex:1;">Неизвестен</span>
|
||||||
|
<span style="font-size:11px;font-weight:600;color:var(--text3);min-width:24px;text-align:right;">${unknownCount}</span>
|
||||||
|
<span style="font-size:10px;color:var(--text3);min-width:36px;text-align:right;">${Math.round(unknownCount/v.total*100)}%</span>
|
||||||
|
</div>` : '');
|
||||||
return `<div style="border:1px solid var(--border);border-radius:8px;padding:8px 10px;">
|
return `<div style="border:1px solid var(--border);border-radius:8px;padding:8px 10px;">
|
||||||
<div style="display:flex;align-items:center;gap:8px;cursor:pointer;" onclick="goToClientTasks('${safeName}')">
|
<div style="display:flex;align-items:center;gap:8px;cursor:pointer;" onclick="goToClientTasks('${safeName}')">
|
||||||
<div style="font-size:12px;font-weight:600;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${safeName}">${escHtml(name)}</div>
|
<div style="font-size:12px;font-weight:600;color:var(--text);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${safeName}">${escHtml(name)}</div>
|
||||||
|
|
@ -883,7 +897,7 @@ function renderClientUsersCard() {
|
||||||
<div style="margin-top:5px;height:6px;background:var(--surface2);border-radius:3px;overflow:hidden;">
|
<div style="margin-top:5px;height:6px;background:var(--surface2);border-radius:3px;overflow:hidden;">
|
||||||
<div style="height:100%;width:${Math.max(pct,v.total?2:0)}%;background:var(--accent);border-radius:3px;transition:width .4s;"></div>
|
<div style="height:100%;width:${Math.max(pct,v.total?2:0)}%;background:var(--accent);border-radius:3px;transition:width .4s;"></div>
|
||||||
</div>
|
</div>
|
||||||
${v.total > 0 ? usersList : ''}
|
${usersList}
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('')}</div>`;
|
}).join('')}</div>`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue