236 lines
7.9 KiB
HTML
236 lines
7.9 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||
<title>МракоЗвон — управление номерами</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||
background: #0f0f0f;
|
||
color: #fff;
|
||
padding: 16px;
|
||
margin: 0;
|
||
}
|
||
.container {
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
.card {
|
||
background: #1e1e1e;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 16px;
|
||
}
|
||
.header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
h3 {
|
||
font-size: 20px;
|
||
}
|
||
.total {
|
||
background: #2d7a2d;
|
||
padding: 6px 14px;
|
||
border-radius: 20px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
.number-card {
|
||
background: #2a2a2a;
|
||
border-radius: 12px;
|
||
padding: 14px 16px;
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
.phone {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
font-family: monospace;
|
||
}
|
||
.meta {
|
||
font-size: 11px;
|
||
color: #888;
|
||
margin-top: 4px;
|
||
}
|
||
.delete-btn {
|
||
background: #dc2626;
|
||
border: none;
|
||
color: white;
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
font-weight: 500;
|
||
flex-shrink: 0;
|
||
}
|
||
.bonus-btn {
|
||
background: #2d7a2d;
|
||
border: none;
|
||
color: white;
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
font-weight: 500;
|
||
flex-shrink: 0;
|
||
margin-right: 8px;
|
||
}
|
||
.delete-btn:active {
|
||
background: #b91c1c;
|
||
}
|
||
.bonus-btn:active {
|
||
background: #1e5e1e;
|
||
}
|
||
.loading {
|
||
text-align: center;
|
||
padding: 60px 20px;
|
||
color: #aaa;
|
||
}
|
||
.empty {
|
||
text-align: center;
|
||
padding: 40px;
|
||
color: #666;
|
||
}
|
||
</style>
|
||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="card">
|
||
<div class="header">
|
||
<h3>🌑 МракоЗвон</h3>
|
||
<div class="total" id="totalCount">Загрузка...</div>
|
||
</div>
|
||
<div id="list"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const tg = window.Telegram.WebApp;
|
||
tg.expand();
|
||
|
||
async function loadNumbers() {
|
||
const listDiv = document.getElementById('list');
|
||
const totalSpan = document.getElementById('totalCount');
|
||
listDiv.innerHTML = '<div class="loading">⏳ Загрузка...</div>';
|
||
|
||
try {
|
||
const response = await fetch('/get_numbers');
|
||
const data = await response.json();
|
||
|
||
if (!data.numbers || data.numbers.length === 0) {
|
||
listDiv.innerHTML = '<div class="empty">📭 Нет номеров</div>';
|
||
totalSpan.innerText = 'Всего: 0';
|
||
return;
|
||
}
|
||
|
||
totalSpan.innerText = `Всего: ${data.numbers.length}`;
|
||
listDiv.innerHTML = '';
|
||
|
||
data.numbers.forEach(num => {
|
||
const card = document.createElement('div');
|
||
card.className = 'number-card';
|
||
const created = new Date(num.created_at).toLocaleString('ru');
|
||
const used = num.used_at ? new Date(num.used_at).toLocaleString('ru') : '—';
|
||
const hasBonus = num.has_bonus_card ? '✅ Есть' : '❌ Нет';
|
||
|
||
const bonusButton = num.has_bonus_card ?
|
||
`<button class="bonus-btn" data-id="${num.id}">🃏 Карта</button>` : '';
|
||
|
||
card.innerHTML = `
|
||
<div style="flex:1">
|
||
<div class="phone">📱 ${num.phone}</div>
|
||
<div class="meta">🃏 Бонусная карта: ${hasBonus}</div>
|
||
<div class="meta">➕ Добавлен: ${created}</div>
|
||
<div class="meta">🔄 Использован: ${num.usage_count} раз, последний: ${used}</div>
|
||
</div>
|
||
<div>
|
||
${bonusButton}
|
||
<button class="delete-btn" data-id="${num.id}">🗑 Удалить</button>
|
||
</div>
|
||
`;
|
||
listDiv.appendChild(card);
|
||
});
|
||
|
||
// Вешаем обработчики на кнопки удаления
|
||
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||
btn.addEventListener('click', async (e) => {
|
||
const id = btn.getAttribute('data-id');
|
||
if (confirm('Удалить номер?')) {
|
||
await fetch('/delete_number', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({id: parseInt(id)})
|
||
});
|
||
loadNumbers();
|
||
}
|
||
});
|
||
});
|
||
|
||
// Вешаем обработчики на кнопки бонусных карт
|
||
document.querySelectorAll('.bonus-btn').forEach(btn => {
|
||
btn.addEventListener('click', async (e) => {
|
||
const id = btn.getAttribute('data-id');
|
||
await showBonusCard(id);
|
||
});
|
||
});
|
||
} catch (e) {
|
||
console.error(e);
|
||
listDiv.innerHTML = '<div class="empty">⚠️ Ошибка загрузки</div>';
|
||
}
|
||
}
|
||
|
||
async function showBonusCard(id) {
|
||
try {
|
||
const response = await fetch(`/get_bonus_card/${id}`);
|
||
const data = await response.json();
|
||
|
||
if (data.bonus_card) {
|
||
const modal = document.createElement('div');
|
||
modal.style.position = 'fixed';
|
||
modal.style.top = '0';
|
||
modal.style.left = '0';
|
||
modal.style.width = '100%';
|
||
modal.style.height = '100%';
|
||
modal.style.background = 'rgba(0,0,0,0.95)';
|
||
modal.style.display = 'flex';
|
||
modal.style.justifyContent = 'center';
|
||
modal.style.alignItems = 'center';
|
||
modal.style.zIndex = '1000';
|
||
modal.style.cursor = 'pointer';
|
||
|
||
const img = document.createElement('img');
|
||
img.src = data.bonus_card;
|
||
img.style.maxWidth = '85%';
|
||
img.style.maxHeight = '85%';
|
||
img.style.borderRadius = '12px';
|
||
img.style.boxShadow = '0 4px 20px rgba(0,0,0,0.5)';
|
||
|
||
modal.onclick = () => modal.remove();
|
||
modal.appendChild(img);
|
||
document.body.appendChild(modal);
|
||
} else {
|
||
alert('Бонусная карта отсутствует для этого номера');
|
||
}
|
||
} catch (e) {
|
||
alert('Ошибка загрузки бонусной карты');
|
||
}
|
||
}
|
||
|
||
loadNumbers();
|
||
</script>
|
||
</body>
|
||
</html> |