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:
@@ -0,0 +1,122 @@
|
||||
{% extends "admin/base.html" %}
|
||||
{% block title %}История {{ target_user.username }} — Админ-панель{% endblock %}
|
||||
{% block nav_users %}active{% endblock %}
|
||||
{% block page_title %}
|
||||
📜 История {{ target_user.username }}
|
||||
<span class="at-sub">ID {{ target_user.id }}</span>
|
||||
{% endblock %}
|
||||
{% block top_actions %}
|
||||
<a href="/admin/user/{{ target_user.id }}" class="at-back">← Профиль</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_styles %}
|
||||
<style>
|
||||
.rarity-Covert, .rarity-Rare\ Special\ Item, .rarity-Extraordinary { color: #eb4b4b; }
|
||||
.rarity-Classified { color: #d32ce6; }
|
||||
.rarity-Restricted { color: #8847ff; }
|
||||
.rarity-Mil-Spec, .rarity-Mil-Spec\ Grade { color: #4b69ff; }
|
||||
.rarity-Industrial\ Grade { color: #5e98d9; }
|
||||
.rarity-Consumer\ Grade { color: #b0b0b0; }
|
||||
.mono { font-family: monospace; font-size: 0.72rem; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="a-stats" style="margin-bottom:1rem">
|
||||
<div class="a-stat"><div class="as-label">Потолок</div><div class="as-value">{{ "%.0f"|format(ceiling) }} ₽</div></div>
|
||||
<div class="a-stat"><div class="as-label">Текущая ценность</div><div class="as-value">{{ "%.0f"|format(total_value) }} ₽</div></div>
|
||||
<div class="a-stat"><div class="as-label">Luck budget</div><div class="as-value">{{ "%.1f"|format(rpu.luck_budget) }}%</div></div>
|
||||
<div class="a-stat"><div class="as-label">Hot score</div><div class="as-value">{{ "%.0f"|format(rpu.hot_score or 0) }}</div></div>
|
||||
<div class="a-stat"><div class="as-label">Ceiling mult</div><div class="as-value">{{ "%.2f"|format(rpu.ceiling_multiplier) }}</div></div>
|
||||
<div class="a-stat"><div class="as-label">Комбек</div><div class="as-value">{{ rpu.comeback_active }}</div></div>
|
||||
</div>
|
||||
|
||||
<div class="a-flex a-mb" style="gap:0.5rem">
|
||||
<button class="a-btn a-btn-primary tab-btn active" onclick="switchTab('openings')">📦 Открытия ({{ openings|length }})</button>
|
||||
<button class="a-btn tab-btn" onclick="switchTab('upgrades')">⬆️ Апгрейды ({{ upgrades|length }})</button>
|
||||
<button class="a-btn tab-btn" onclick="switchTab('transactions')">💳 Транзакции ({{ transactions|length }})</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-openings" class="tab-content" style="display:block">
|
||||
<div class="a-table-wrap">
|
||||
<table class="a-table">
|
||||
<thead><tr><th>ID</th><th>Дата</th><th>Кейс</th><th>Предмет</th><th>Редкость</th><th>Float</th></tr></thead>
|
||||
<tbody>
|
||||
{% for o in openings %}
|
||||
<tr>
|
||||
<td class="mono">{{ o.id }}</td>
|
||||
<td>{{ o.opened_at.strftime('%d.%m %H:%M') }}</td>
|
||||
<td>{{ o.case_name }}</td>
|
||||
<td>{{ o.item_name }}</td>
|
||||
<td><span class="rarity-{{ o.rarity|replace(' ', '\\ ') }}">{{ o.rarity }}</span></td>
|
||||
<td>{{ "%.4f"|format(o.float_value) if o.float_value else '—' }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="a-empty" style="padding:2rem">Нет открытий</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-upgrades" class="tab-content" style="display:none">
|
||||
<div class="a-table-wrap">
|
||||
<table class="a-table">
|
||||
<thead><tr><th>ID</th><th>Дата</th><th>Вход</th><th>Цель</th><th>Результат</th><th>Базовый шанс</th><th>RPU шанс</th></tr></thead>
|
||||
<tbody>
|
||||
{% for u in upgrades %}
|
||||
<tr>
|
||||
<td class="mono">{{ u.id }}</td>
|
||||
<td>{{ u.created_at.strftime('%d.%m %H:%M') }}</td>
|
||||
<td>{{ u.input_item_name }}</td>
|
||||
<td>{{ u.target_item_name }}</td>
|
||||
<td style="color:{% if u.success %}#22c55e{% else %}#ef4444{% endif %}">{% if u.success %}✅ Успех{% else %}❌ Провал{% endif %}</td>
|
||||
<td>{{ "%.1f"|format(u.probability * 100 if u.probability else 0) }}%</td>
|
||||
<td>{{ "%.1f"|format(u.rpu_adjusted_probability * 100 if u.rpu_adjusted_probability else 0) }}%</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="7" class="a-empty" style="padding:2rem">Нет апгрейдов</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-transactions" class="tab-content" style="display:none">
|
||||
<div class="a-table-wrap">
|
||||
<table class="a-table">
|
||||
<thead><tr><th>ID</th><th>Дата</th><th>Тип</th><th>Сумма</th><th>Комиссия</th><th>Детали</th></tr></thead>
|
||||
<tbody>
|
||||
{% for t in transactions %}
|
||||
<tr>
|
||||
<td class="mono">{{ t.id }}</td>
|
||||
<td>{{ t.created_at.strftime('%d.%m %H:%M') }}</td>
|
||||
<td>
|
||||
{% if t.tx_type == 'card_to_site' %}<span class="a-badge a-badge-success">Депозит</span>
|
||||
{% elif t.tx_type == 'site_to_card' %}<span class="a-badge a-badge-banned">Вывод</span>
|
||||
{% elif t.tx_type == 'promo_bonus' %}<span class="a-badge" style="background:rgba(234,179,8,0.12);color:#eab308">Промо</span>
|
||||
{% else %}<span class="a-badge a-badge-user">{{ t.tx_type }}</span>{% endif %}
|
||||
</td>
|
||||
<td>{{ "%.0f"|format(t.amount) }} ₽</td>
|
||||
<td>{% if t.fee %}{{ "%.0f"|format(t.fee) }} ₽{% else %}—{% endif %}</td>
|
||||
<td style="max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{ t.details or '' }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="6" class="a-empty" style="padding:2rem">Нет транзакций</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function switchTab(name) {
|
||||
document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
|
||||
document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active'));
|
||||
document.getElementById('tab-' + name).style.display = 'block';
|
||||
document.querySelector('.tab-btn[onclick="switchTab(\'' + name + '\')"]').classList.add('active');
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user