feat: per-user click stats with aggregation

This commit is contained in:
Dauren777 2026-07-13 03:35:21 +00:00
parent c7ce89c83f
commit 387cb97d22

View File

@ -23,22 +23,41 @@ body{font:17px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,s
<section class="hero"><div class="container"> <section class="hero"><div class="container">
<h1>Сбор статистики нажатий</h1> <h1>Сбор статистики нажатий</h1>
<p>Нажимайте на кнопки — счётчик будет сохраняться в браузере.</p> <p>Нажимайте на кнопки — счётчик будет сохраняться в браузере.</p>
<div style="margin-top:12px;">
<label for="userInput" style="margin-right:8px;">Пользователь:</label>
<input id="userInput" type="text" placeholder="Введите имя" style="padding:4px 8px; border:1px solid var(--gray-500); border-radius:4px;">
<button id="setUserBtn" class="btn" style="padding:4px 12px; font-size:14px;">Установить</button>
</div>
</div></section> </div></section>
<section class="section"><div class="container"> <section class="section"><div class="container">
<h2>Кнопки</h2> <h2>Кнопки</h2>
<div id="buttons"></div> <div id="buttons"></div>
<div id="aggregation" style="margin-top:24px;"></div>
</div></section> </div></section>
<script> <script>
// Список кнопок, которые нужно отслеживать // Список кнопок, которые нужно отслеживать
const buttonLabels = ['Кнопка A', 'Кнопка B', 'Кнопка C']; const buttonLabels = ['Кнопка A', 'Кнопка B', 'Кнопка C'];
// Хранилище счётчиков в localStorage // Ключ в localStorage для всех статистик
const storageKey = 'clickStats'; const storageKey = 'clickStats';
let stats = JSON.parse(localStorage.getItem(storageKey)) || {}; // Текущий пользователь (по умолчанию «guest»)
// Инициализируем нули, если кнопки новые let currentUser = localStorage.getItem('currentUser') || 'guest';
buttonLabels.forEach(label => { if(!(label in stats)) stats[label]=0; }); // Объект {user: {label: count}}
// Сохраняем при загрузке (на случай новых кнопок) let allStats = JSON.parse(localStorage.getItem(storageKey)) || {};
localStorage.setItem(storageKey, JSON.stringify(stats)); // Инициализируем запись для текущего пользователя, если её нет
if (!allStats[currentUser]) {
allStats[currentUser] = {};
buttonLabels.forEach(label => allStats[currentUser][label] = 0);
}
// Убедимся, что у всех пользователей присутствуют новые кнопки
Object.values(allStats).forEach(userStats => {
buttonLabels.forEach(label => {
if (!(label in userStats)) userStats[label] = 0;
});
});
localStorage.setItem(storageKey, JSON.stringify(allStats));
const container = document.getElementById('buttons'); const container = document.getElementById('buttons');
function renderButtons() {
container.innerHTML = '';
buttonLabels.forEach((label, i) => { buttonLabels.forEach((label, i) => {
const btn = document.createElement('button'); const btn = document.createElement('button');
btn.className = 'btn'; btn.className = 'btn';
@ -46,15 +65,46 @@ buttonLabels.forEach((label,i)=>{
const cnt = document.createElement('span'); const cnt = document.createElement('span');
cnt.className = 'counter'; cnt.className = 'counter';
cnt.id = 'cnt-' + i; cnt.id = 'cnt-' + i;
cnt.textContent = stats[label]; cnt.textContent = allStats[currentUser][label];
btn.addEventListener('click', () => { btn.addEventListener('click', () => {
stats[label]++; allStats[currentUser][label]++;
cnt.textContent = stats[label]; cnt.textContent = allStats[currentUser][label];
localStorage.setItem(storageKey, JSON.stringify(stats)); localStorage.setItem(storageKey, JSON.stringify(allStats));
renderAggregation();
}); });
container.appendChild(btn); container.appendChild(btn);
container.appendChild(cnt); container.appendChild(cnt);
}); });
}
function renderAggregation() {
const aggDiv = document.getElementById('aggregation');
const totals = {};
buttonLabels.forEach(label => totals[label] = 0);
Object.values(allStats).forEach(userStats => {
buttonLabels.forEach(label => {
totals[label] += userStats[label] || 0;
});
});
aggDiv.innerHTML = '<h3>Общая статистика</h3>' +
buttonLabels.map(label => `<div>${label}: <span class="counter">${totals[label]}</span></div>`).join('');
}
// UI для установки пользователя
document.getElementById('setUserBtn').addEventListener('click', () => {
const input = document.getElementById('userInput').value.trim();
if (input) {
currentUser = input;
localStorage.setItem('currentUser', currentUser);
if (!allStats[currentUser]) {
allStats[currentUser] = {};
buttonLabels.forEach(label => allStats[currentUser][label] = 0);
}
renderButtons();
renderAggregation();
}
});
// Initial render
renderButtons();
renderAggregation();
</script> </script>
</body> </body>
</html> </html>