568 lines
22 KiB
HTML
568 lines
22 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Комнаты - Капитал & Рынок{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="screen active">
|
||
<!-- Шапка -->
|
||
<div class="header">
|
||
<a href="{{ url_for('index') }}" class="back-button">←</a>
|
||
<div class="logo-container">
|
||
<span class="logo-text" style="color: white; font-weight: bold; font-size: 1.2rem;">
|
||
💰 Комнаты
|
||
</span>
|
||
</div>
|
||
<div style="margin-left: auto;">
|
||
<span style="font-size: 0.9rem;">
|
||
{% if current_user.is_authenticated %}
|
||
{{ current_user.username }}
|
||
{% endif %}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Основной контент -->
|
||
<div class="container">
|
||
<!-- Поиск и создание комнаты -->
|
||
<div class="search-bar">
|
||
<input type="text" id="room-search" placeholder="Поиск комнат по названию..."
|
||
onkeyup="searchRooms()">
|
||
<button onclick="searchRooms()">🔍</button>
|
||
</div>
|
||
|
||
<button class="button" onclick="createRoom()" style="margin-bottom: 20px;">
|
||
+ Создать новую комнату
|
||
</button>
|
||
|
||
<!-- Доступные комнаты -->
|
||
<div class="card">
|
||
<h3>📢 Доступные комнаты</h3>
|
||
<div style="margin: 10px 0; color: var(--light-text); font-size: 0.9rem;">
|
||
{% if rooms %}
|
||
Найдено {{ rooms|length }} комнат
|
||
{% else %}
|
||
Нет доступных комнат
|
||
{% endif %}
|
||
</div>
|
||
|
||
<ul class="room-list" id="room-list">
|
||
{% if rooms %}
|
||
{% for room in rooms %}
|
||
<li class="room-item" onclick="joinRoom('{{ room.code }}')">
|
||
<div class="room-info">
|
||
<div class="room-avatar"
|
||
style="background-color: {% if room.status == 'waiting' %}#4caf50{% elif room.status == 'playing' %}#ff9800{% else %}#9e9e9e{% endif %};">
|
||
{{ room.player_count }}
|
||
</div>
|
||
<div style="flex: 1;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||
<strong>{{ room.name }}</strong>
|
||
<span style="font-size: 0.8rem; color: var(--light-text);">
|
||
Месяц {{ room.current_month }}/{{ room.total_months }}
|
||
</span>
|
||
</div>
|
||
<div class="room-meta">
|
||
Создатель: {{ room.creator.username if room.creator else 'Система' }} •
|
||
Игроков: {{ room.player_count }}/{{ config.MAX_PLAYERS_PER_ROOM }}
|
||
</div>
|
||
{% if room.settings %}
|
||
<div style="margin-top: 3px;">
|
||
{% set settings = room.settings|from_json %}
|
||
{% if settings.allow_loans %}
|
||
<span style="background-color: #e3f2fd; color: #1976d2; padding: 2px 6px; border-radius: 10px; font-size: 0.75rem; margin-right: 5px;">Кредиты</span>
|
||
{% endif %}
|
||
{% if settings.allow_black_market %}
|
||
<span style="background-color: #f3e5f5; color: #7b1fa2; padding: 2px 6px; border-radius: 10px; font-size: 0.75rem;">Чёрный рынок</span>
|
||
{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
<div class="room-status {{ room.status }}">
|
||
{% if room.status == 'waiting' %}
|
||
Ожидание
|
||
{% elif room.status == 'playing' %}
|
||
Игра идет
|
||
{% elif room.status == 'full' %}
|
||
Заполнена
|
||
{% else %}
|
||
{{ room.status }}
|
||
{% endif %}
|
||
</div>
|
||
</li>
|
||
{% endfor %}
|
||
{% else %}
|
||
<li style="text-align: center; padding: 20px; color: var(--light-text);">
|
||
<div style="font-size: 3rem; margin-bottom: 10px;">🏢</div>
|
||
<p>Пока нет доступных комнат</p>
|
||
<p style="font-size: 0.9rem;">Создайте первую комнату!</p>
|
||
</li>
|
||
{% endif %}
|
||
</ul>
|
||
</div>
|
||
|
||
<!-- Ваши комнаты -->
|
||
<div class="card">
|
||
<h3>⭐ Ваши комнаты</h3>
|
||
{% if user_rooms %}
|
||
<ul class="room-list" id="my-room-list">
|
||
{% for room in user_rooms %}
|
||
<li class="room-item" onclick="joinRoom('{{ room.code }}')">
|
||
<div class="room-info">
|
||
<div class="room-avatar" style="background-color: var(--primary-color);">
|
||
{{ room.player_count }}
|
||
</div>
|
||
<div style="flex: 1;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||
<strong>{{ room.name }}</strong>
|
||
{% if room.creator_id == current_user.id %}
|
||
<span style="background-color: #fff3e0; color: #ef6c00; padding: 2px 8px; border-radius: 10px; font-size: 0.75rem;">Админ</span>
|
||
{% endif %}
|
||
</div>
|
||
<div class="room-meta">
|
||
Месяц {{ room.current_month }}/{{ room.total_months }} •
|
||
Игроков: {{ room.player_count }}/{{ config.MAX_PLAYERS_PER_ROOM }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="room-status {{ room.status }}">
|
||
{% if room.status == 'waiting' %}
|
||
Ожидание
|
||
{% elif room.status == 'playing' %}
|
||
В игре
|
||
{% else %}
|
||
{{ room.status }}
|
||
{% endif %}
|
||
</div>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<div style="text-align: center; padding: 20px; color: var(--light-text);">
|
||
<div style="font-size: 3rem; margin-bottom: 10px;">👤</div>
|
||
<p>Вы пока не участвуете в комнатах</p>
|
||
<p style="font-size: 0.9rem;">Присоединитесь к существующей или создайте свою</p>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<!-- Быстрые действия -->
|
||
<div class="card">
|
||
<h3>⚡ Быстрые действия</h3>
|
||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-top: 15px;">
|
||
<button class="button secondary" onclick="createQuickRoom('Быстрая игра')">
|
||
Быстрая игра
|
||
</button>
|
||
<button class="button secondary" onclick="createQuickRoom('Для новичков')">
|
||
Для новичков
|
||
</button>
|
||
<button class="button secondary" onclick="createQuickRoom('Турнир')">
|
||
Турнир
|
||
</button>
|
||
<button class="button secondary" onclick="createQuickRoom('С друзьями')">
|
||
С друзьями
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Статистика -->
|
||
{% if current_user.is_authenticated %}
|
||
<div class="card">
|
||
<h3>📊 Ваша статистика</h3>
|
||
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-top: 15px;">
|
||
<div style="text-align: center; padding: 15px; background-color: #f5f5f5; border-radius: var(--border-radius);">
|
||
<div style="font-size: 2rem; font-weight: bold; color: var(--primary-color);">{{
|
||
current_user.total_games }}
|
||
</div>
|
||
<div style="font-size: 0.9rem; color: var(--light-text);">Всего игр</div>
|
||
</div>
|
||
<div style="text-align: center; padding: 15px; background-color: #f5f5f5; border-radius: var(--border-radius);">
|
||
<div style="font-size: 2rem; font-weight: bold; color: var(--primary-color);">{{
|
||
current_user.games_won }}
|
||
</div>
|
||
<div style="font-size: 0.9rem; color: var(--light-text);">Побед</div>
|
||
</div>
|
||
<div style="text-align: center; padding: 15px; background-color: #f5f5f5; border-radius: var(--border-radius);">
|
||
<div style="font-size: 2rem; font-weight: bold; color: var(--primary-color);">
|
||
{% if current_user.total_games > 0 %}
|
||
{{ "%.1f"|format(current_user.games_won / current_user.total_games * 100) }}%
|
||
{% else %}
|
||
0%
|
||
{% endif %}
|
||
</div>
|
||
<div style="font-size: 0.9rem; color: var(--light-text);">Процент побед</div>
|
||
</div>
|
||
<div style="text-align: center; padding: 15px; background-color: #f5f5f5; border-radius: var(--border-radius);">
|
||
<div style="font-size: 2rem; font-weight: bold; color: var(--primary-color);">
|
||
{{ current_user.total_earnings|format_currency }}
|
||
</div>
|
||
<div style="font-size: 0.9rem; color: var(--light-text);">Заработано</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Модальное окно создания комнаты -->
|
||
<div id="create-room-modal" class="modal-backdrop">
|
||
<div class="modal">
|
||
<h3>Создание комнаты</h3>
|
||
|
||
<form id="create-room-form" onsubmit="return submitRoomForm(event)">
|
||
<div class="input-group">
|
||
<label for="room-name">Название комнаты *</label>
|
||
<input type="text" id="room-name" name="name"
|
||
placeholder="Например: Быки и медведи" required>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label for="total-months">Длительность игры</label>
|
||
<select id="total-months" name="total_months">
|
||
<option value="6">6 месяцев (быстрая игра)</option>
|
||
<option value="12" selected>12 месяцев (стандартная)</option>
|
||
<option value="18">18 месяцев (продвинутая)</option>
|
||
<option value="24">24 месяца (экспертная)</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label for="start-capital">Стартовый капитал</label>
|
||
<input type="number" id="start-capital" name="start_capital"
|
||
value="100000" min="50000" max="1000000" step="10000">
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label style="display: flex; align-items: center; gap: 10px;">
|
||
<input type="checkbox" id="allow-loans" name="allow_loans" checked>
|
||
<span>Разрешить кредиты</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label style="display: flex; align-items: center; gap: 10px;">
|
||
<input type="checkbox" id="allow-black-market" name="allow_black_market">
|
||
<span>Разрешить чёрный рынок</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="input-group">
|
||
<label style="display: flex; align-items: center; gap: 10px;">
|
||
<input type="checkbox" id="private-room" name="private_room">
|
||
<span>Приватная комната (по приглашению)</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="flex gap-2 mt-4">
|
||
<button type="submit" class="button success">Создать комнату</button>
|
||
<button type="button" onclick="hideCreateRoomModal()" class="button secondary">Отмена</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
// Глобальные переменные
|
||
let allRooms = [];
|
||
|
||
// Инициализация при загрузке
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
console.log('Rooms page loaded');
|
||
|
||
// Сохраняем все комнаты для поиска
|
||
const roomItems = document.querySelectorAll('.room-item');
|
||
allRooms = Array.from(roomItems).map(item => ({
|
||
name: item.querySelector('strong')?.textContent.toLowerCase() || '',
|
||
element: item
|
||
}));
|
||
|
||
// Подключение к комнате через WebSocket
|
||
if (typeof socket !== 'undefined') {
|
||
console.log('Socket connected, joining global room');
|
||
socket.emit('join_global_room');
|
||
}
|
||
});
|
||
|
||
// Поиск комнат
|
||
function searchRooms() {
|
||
const searchTerm = document.getElementById('room-search').value.toLowerCase();
|
||
const roomList = document.getElementById('room-list');
|
||
|
||
if (!roomList) return;
|
||
|
||
const rooms = roomList.querySelectorAll('.room-item');
|
||
rooms.forEach(room => {
|
||
const roomName = room.querySelector('strong')?.textContent.toLowerCase() || '';
|
||
if (roomName.includes(searchTerm) || searchTerm === '') {
|
||
room.style.display = 'flex';
|
||
} else {
|
||
room.style.display = 'none';
|
||
}
|
||
});
|
||
}
|
||
|
||
// Создание комнаты
|
||
function createRoom() {
|
||
console.log('Opening create room modal');
|
||
const modal = document.getElementById('create-room-modal');
|
||
if (modal) {
|
||
modal.classList.add('active');
|
||
document.getElementById('room-name').focus();
|
||
}
|
||
}
|
||
|
||
// Быстрое создание комнаты
|
||
function createQuickRoom(name) {
|
||
console.log('Creating quick room:', name);
|
||
|
||
// Создаем форму данных
|
||
const formData = new FormData();
|
||
formData.append('name', name);
|
||
formData.append('total_months', '12');
|
||
formData.append('start_capital', '100000');
|
||
formData.append('allow_loans', 'on');
|
||
formData.append('allow_black_market', 'off');
|
||
formData.append('private_room', 'off');
|
||
|
||
// Отправляем запрос
|
||
createRoomRequest(formData);
|
||
}
|
||
|
||
// Отправка формы создания комнаты
|
||
function submitRoomForm(event) {
|
||
console.log('Submitting room form');
|
||
event.preventDefault();
|
||
|
||
const form = document.getElementById('create-room-form');
|
||
const formData = new FormData(form);
|
||
|
||
createRoomRequest(formData);
|
||
return false;
|
||
}
|
||
|
||
// Функция для отправки запроса на создание комнаты
|
||
function createRoomRequest(formData) {
|
||
console.log('Sending create room request');
|
||
|
||
fetch('/room/create', {
|
||
method: 'POST',
|
||
body: formData,
|
||
headers: {
|
||
'Accept': 'application/json',
|
||
}
|
||
})
|
||
.then(response => {
|
||
console.log('Response status:', response.status);
|
||
console.log('Response headers:', response.headers.get('content-type'));
|
||
|
||
// Проверяем тип ответа
|
||
const contentType = response.headers.get('content-type');
|
||
if (contentType && contentType.includes('application/json')) {
|
||
return response.json();
|
||
} else {
|
||
return response.text().then(text => {
|
||
console.error('Expected JSON, got:', text.substring(0, 200));
|
||
throw new Error('Server returned HTML instead of JSON');
|
||
});
|
||
}
|
||
})
|
||
.then(data => {
|
||
console.log('Create room response:', data);
|
||
|
||
if (data.error) {
|
||
alert('Ошибка: ' + data.error);
|
||
} else if (data.redirect) {
|
||
// Редирект в лобби комнаты
|
||
window.location.href = data.redirect;
|
||
} else if (data.success) {
|
||
// Редирект по коду комнаты
|
||
window.location.href = `/room/${data.room_code}`;
|
||
} else {
|
||
alert('Неизвестный ответ от сервера');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error creating room:', error);
|
||
alert('Ошибка при создании комнаты. Проверьте консоль для деталей.');
|
||
});
|
||
}
|
||
|
||
// Скрыть модальное окно
|
||
function hideCreateRoomModal() {
|
||
const modal = document.getElementById('create-room-modal');
|
||
if (modal) {
|
||
modal.classList.remove('active');
|
||
}
|
||
}
|
||
|
||
// Присоединение к комнате
|
||
function joinRoom(roomCode) {
|
||
console.log('Joining room:', roomCode);
|
||
window.location.href = `/room/${roomCode}`;
|
||
}
|
||
|
||
// Обновление статуса онлайн
|
||
function updateOnlineStatus() {
|
||
if (typeof socket !== 'undefined' && socket.connected) {
|
||
socket.emit('user_online', {
|
||
timestamp: new Date().toISOString()
|
||
});
|
||
}
|
||
}
|
||
|
||
// Периодическое обновление статуса
|
||
setInterval(updateOnlineStatus, 30000);
|
||
updateOnlineStatus();
|
||
|
||
// Обработка клавиши Escape для закрытия модального окна
|
||
document.addEventListener('keydown', function(event) {
|
||
if (event.key === 'Escape') {
|
||
hideCreateRoomModal();
|
||
}
|
||
});
|
||
|
||
// Закрытие модального окна при клике на фон
|
||
document.addEventListener('click', function(event) {
|
||
const modal = document.getElementById('create-room-modal');
|
||
if (modal && modal.classList.contains('active') && event.target === modal) {
|
||
hideCreateRoomModal();
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<style>
|
||
/* Дополнительные стили для rooms.html */
|
||
.room-item {
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border-radius: var(--border-radius);
|
||
margin: 5px 0;
|
||
padding: 12px;
|
||
border: 1px solid transparent;
|
||
}
|
||
|
||
.room-item:hover {
|
||
background-color: #f5f5f5;
|
||
border-color: var(--primary-color);
|
||
transform: translateX(5px);
|
||
}
|
||
|
||
.room-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-weight: bold;
|
||
font-size: 1.1rem;
|
||
margin-right: 12px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.room-status {
|
||
padding: 5px 10px;
|
||
border-radius: 15px;
|
||
font-size: 0.8rem;
|
||
font-weight: bold;
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.room-status.waiting {
|
||
background-color: #e3f2fd;
|
||
color: #1976d2;
|
||
}
|
||
|
||
.room-status.playing {
|
||
background-color: #fff3e0;
|
||
color: #ef6c00;
|
||
}
|
||
|
||
.room-status.full {
|
||
background-color: #ffebee;
|
||
color: #d32f2f;
|
||
}
|
||
|
||
.search-bar {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.search-bar input {
|
||
flex: 1;
|
||
padding: 12px;
|
||
border: 1px solid #ddd;
|
||
border-radius: var(--border-radius);
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.search-bar button {
|
||
padding: 0 20px;
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
border: none;
|
||
border-radius: var(--border-radius);
|
||
cursor: pointer;
|
||
font-size: 1.1rem;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
.search-bar button:hover {
|
||
background-color: #0077b3;
|
||
}
|
||
|
||
.modal-backdrop {
|
||
display: none;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-backdrop.active {
|
||
display: flex;
|
||
}
|
||
|
||
.modal {
|
||
background-color: white;
|
||
border-radius: var(--border-radius);
|
||
padding: 20px;
|
||
max-width: 500px;
|
||
width: 90%;
|
||
max-height: 90vh;
|
||
overflow-y: auto;
|
||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.room-item {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.room-status {
|
||
align-self: flex-end;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.search-bar {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.search-bar button {
|
||
width: 100%;
|
||
padding: 12px;
|
||
}
|
||
}
|
||
</style>
|
||
{% endblock %} |