RPU v2, promo/bank система, админка, оптимизации
— RPU v2: бюджет удачи, потолок (ceiling), комбек после проигрышей, hot/cold анализ, интеграция с promo-фазами — Bank API: mock-банк для карты (депозит/вывод с балансом 1000₽) — Promo-сервис: автогенерация промокодов каждый час, типы (card_to_site, luck_boost, ceiling_boost, free_case, reset_streak) — Promo-фазы: LUCKY/NEUTRAL/UNLUCKY, переключение каждые 1-6ч — Admin: история транзакций (user_history), управление промокодами, управление promo-фазами, API фильтров/коллекций, RPU info — Database: WAL mode, новые поля RPU v2, TransactionLog, карточный баланс, статистики (streaks, ceiling, budget) — Frontend: /deposit, /promo/activate, /withdraw, /card-balance, /online-count, /rpu-info, lifespan вместо startup event — UI: user_history.html, улучшения профиля, кейсов, навигации — Cases: обновление cases.json (1892 строки новых данных) — Achievements: кэш коллекций, оптимизация is_custom проверок — Sounds: дополнительные звуковые эффекты — Upgrade: интеграция с RPU (множители, streaks) — .gitignore: исключены .db, .bak, __pycache__
This commit is contained in:
@@ -8,10 +8,11 @@
|
||||
{% endblock %}
|
||||
{% block top_actions %}
|
||||
<a href="/admin/users" class="at-back">← Назад</a>
|
||||
<a href="/admin/user/{{ target_user.id }}/history" class="a-btn" style="margin-left:0.5rem;font-size:0.82rem;">📜 История</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="a-stats" style="grid-template-columns:repeat(4,1fr)">
|
||||
<div class="a-stats">
|
||||
<div class="a-stat">
|
||||
<div class="as-label">Баланс</div>
|
||||
<div class="as-value">{{ target_user.balance|money }} ₽</div>
|
||||
@@ -49,6 +50,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RPU v2 -->
|
||||
<div class="a-card">
|
||||
<div class="a-card-header">🎲 RPU v2 — подробно</div>
|
||||
<div id="rpuV2Stats" class="a-mb" style="font-size:0.82rem">
|
||||
<div class="a-row a-gap-sm" style="justify-content:space-around;text-align:center;margin-bottom:0.75rem">
|
||||
<div><div class="as-value" id="v2Ceiling" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Потолок / Депнуто</div></div>
|
||||
<div><div class="as-value" id="v2Budget" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Luck Budget</div></div>
|
||||
<div><div class="as-value" id="v2SessionSpent" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Сессия потрачено</div></div>
|
||||
<div><div class="as-value" id="v2HotScore" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Hot Score</div></div>
|
||||
<div><div class="as-value" id="v2PromoPhase" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Промо-фаза</div></div>
|
||||
</div>
|
||||
<div class="a-row a-gap-sm" style="justify-content:space-around;text-align:center">
|
||||
<div><div class="as-value" id="v2Comeback" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Комбек</div></div>
|
||||
<div><div class="as-value" id="v2BreakCount" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Пробитий</div></div>
|
||||
<div><div class="as-value" id="v2LossStreak" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Проигрышей подряд</div></div>
|
||||
<div><div class="as-value" id="v2SessionReset" style="font-size:1.1rem">--</div><div class="as-label" style="font-size:0.65rem">Сброс сессии</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Действия -->
|
||||
<div class="a-card">
|
||||
<div class="a-card-header">🔧 Действия</div>
|
||||
@@ -84,6 +105,27 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="a-table-card-view">
|
||||
{% for item in inventory %}
|
||||
<div class="a-table-card">
|
||||
<div class="tc-row">
|
||||
<span class="tc-label">ID</span>
|
||||
<span class="tc-value">{{ item.id }}</span>
|
||||
</div>
|
||||
<div class="tc-row">
|
||||
<span class="tc-label">Название</span>
|
||||
<span class="tc-value">{{ item.market_hash_name[:40] }}{{'…' if item.market_hash_name|length > 40}}</span>
|
||||
</div>
|
||||
<div class="tc-row">
|
||||
<span class="tc-label">Редкость / Float</span>
|
||||
<span class="tc-value">{{ item.rarity }} / {{ "%.4f"|format(item.float_value) }}</span>
|
||||
</div>
|
||||
<div class="tc-actions">
|
||||
<button class="a-btn a-btn-danger a-btn-sm" onclick="deleteItem({{ item.id }})">🗑️ Удалить</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -251,6 +293,24 @@ async function loadRPU() {
|
||||
document.getElementById('rpuSpent').textContent = Math.round(d.stats.total_spent).toLocaleString() + ' ₽';
|
||||
document.getElementById('rpuOpened').textContent = d.stats.total_opened.toLocaleString();
|
||||
document.getElementById('rpuAutoStatus').textContent = d.auto_adjust ? '✅' : '❌';
|
||||
|
||||
// ── RPU v2 ──
|
||||
if (d.v2) {
|
||||
const v = d.v2;
|
||||
document.getElementById('v2Ceiling').textContent = Math.round(v.ceiling.current_ceiling).toLocaleString('ru') + '₽ / ' + Math.round(v.ceiling.total_deposited).toLocaleString('ru') + '₽';
|
||||
document.getElementById('v2Budget').textContent = v.session.luck_budget + '%';
|
||||
document.getElementById('v2Budget').style.color = v.session.luck_budget < 30 ? '#ef4444' : v.session.luck_budget > 70 ? '#22c55e' : '#f59e0b';
|
||||
document.getElementById('v2SessionSpent').textContent = Math.round(v.session.session_spent).toLocaleString('ru') + '₽';
|
||||
document.getElementById('v2HotScore').textContent = v.hot_cold.hot_score;
|
||||
document.getElementById('v2HotScore').style.color = v.hot_cold.hot_score > 0.5 ? '#22c55e' : v.hot_cold.hot_score < -0.5 ? '#ef4444' : '#f59e0b';
|
||||
const ph = v.promo_phase;
|
||||
document.getElementById('v2PromoPhase').textContent = ph.phase;
|
||||
document.getElementById('v2PromoPhase').style.color = ph.phase === 'LUCKY' ? '#22c55e' : ph.phase === 'UNLUCKY' ? '#ef4444' : '#f59e0b';
|
||||
document.getElementById('v2Comeback').textContent = v.comeback.active ? '✅ x' + v.comeback.multiplier.toFixed(1) + ' (' + v.comeback.openings_left + ')' : '❌';
|
||||
document.getElementById('v2BreakCount').textContent = v.ceiling.break_count + ' (' + v.ceiling.break_session + ' сесс)';
|
||||
document.getElementById('v2LossStreak').textContent = v.comeback.consecutive_loss_count + ' (' + Math.round(v.comeback.consecutive_loss_value).toLocaleString('ru') + '₽)';
|
||||
document.getElementById('v2SessionReset').textContent = v.session.reset_date ? new Date(v.session.reset_date).toLocaleString('ru') : '—';
|
||||
}
|
||||
} catch(_) {}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user