From f4fe2d2c06c2a3ff6994d6231b183e1255b40b44 Mon Sep 17 00:00:00 2001 From: Degradin <42292046+Degradin@users.noreply.github.com> Date: Tue, 21 Jan 2025 09:43:10 +0300 Subject: [PATCH] MiniApp Update Added scoreboard --- pages.js | 143 ++++++++++++++++++++++++++++++ public/scoreboard.css | 78 +++++++++++++++++ public/scoreboard.html | 191 +++++++++++++++++++++++++++++++++++++++++ public/scoreboard.js | 93 ++++++++++++++++++++ server.bat | 1 + 5 files changed, 506 insertions(+) create mode 100644 pages.js create mode 100644 public/scoreboard.css create mode 100644 public/scoreboard.html create mode 100644 public/scoreboard.js diff --git a/pages.js b/pages.js new file mode 100644 index 0000000..9bf668c --- /dev/null +++ b/pages.js @@ -0,0 +1,143 @@ +require('dotenv').config(); + +const sequelize = require('./db'); // Подключение базы данных + +// Настраиваем глобальные переменные (опционально) +global.path = require('path'); +global.config = require('./config'); // Конфигурация +global.database = sequelize; // База данных +global.utils = require('./utils'); +const { Op } = require('sequelize'); +const express = require('express'); +const { UserModel, CharacterModel, BusinessModel, EnterpriseModel, WarehouseModel } = global.config; +const app = express(); + +app.use(express.static('public')); + +app.get('/scoreboard', (req, res) => { + res.sendFile(global.path.join(__dirname, 'public', 'scoreboard.html')); +}); + +app.get('/users', async (req, res) => { + const { sortBy } = req.query; // Sorting option passed as a query parameter + + const sortOptions = { + money: [sequelize.literal('money'), 'DESC'], + level: [sequelize.literal('level'), 'DESC'] + }; + + const topUser = await UserModel.findAll({ + attributes: ['username', 'money', 'level', 'status'], + order: [sortOptions[sortBy] || sortOptions['money']], // Default sort by money + limit: 15 + }); + + res.json(topUser.map(player => ({ + username: player.username, + money: player.money, + level: player.level, + status: player.status + }))); +}); + + +app.get('/characters', async (req, res) => { + const { sortBy } = req.query; // Use query parameters to specify sorting + + const sortOptions = { + dirtymoney: [sequelize.literal('dirtymoney'), 'DESC'], + level: [sequelize.literal('level'), 'DESC'], + force: [sequelize.literal('force'), 'DESC'], + intelligence: [sequelize.literal('intelligence'), 'DESC'], + resilience: [sequelize.literal('resilience'), 'DESC'], + endurance: [sequelize.literal('endurance'), 'DESC'] + }; + + const topCharacter = await CharacterModel.findAll({ + attributes: ['username', 'dirtymoney', 'level', 'force', 'intelligence', 'resilience', 'endurance'], + order: [sortOptions[sortBy] || sortOptions['dirtymoney']], // Default sort by dirtymoney + limit: 15 + }); + + res.json(topCharacter.map(character => ({ + username: character.username, + dirtymoney: character.dirtymoney, + level: character.level, + force: character.force, + intelligence: character.intelligence, + resilience: character.resilience, + endurance: character.endurance + }))); +}); + + +app.get('/enterprises', async (req, res) => { + const enterprises = await EnterpriseModel.findAll({ + attributes: ['name', 'resourceType', 'level', 'efficiency', 'warehouseCapacity', 'currentResources', 'playerId'] + }); + + const resourceIcons = { + wood: '🌳', + coal: '⛏️', + oil: '🛢️', + metall: '⚒️', + gold: '💰', + diamond: '💎' + }; + + const enterprisesData = await Promise.all(enterprises.map(async enterprise => { + const player = await UserModel.findOne({ + attributes: ['name'], + where: { telegram_id: enterprise.playerId } + }); + + return { + name: enterprise.name, + resourceType: enterprise.resourceType, + level: enterprise.level, + efficiency: enterprise.efficiency, + warehouseCapacity: enterprise.warehouseCapacity, + currentResources: enterprise.currentResources, + owner: player ? player.name : 'Unknown', + icon: resourceIcons[enterprise.resourceType] || '❓' + }; + })); + + res.json(enterprisesData); +}); + +app.get('/businesses', async (req, res) => { + const { sortBy } = req.query; // Sorting option passed as a query parameter + + const sortOptions = { + balance: [sequelize.literal('balance'), 'DESC'], + usersCount: [sequelize.literal('ARRAY_LENGTH(users, 1)'), 'DESC'] + }; + + const businesses = await BusinessModel.findAll({ + attributes: ['name', 'balance', 'users', 'owner'], + order: [sortOptions[sortBy] || sortOptions['balance']], // Default sort by balance + limit: 15 + }); + + const businessesData = await Promise.all(businesses.map(async business => { + const owner = await UserModel.findOne({ + attributes: ['username'], + where: { telegram_id: business.owner } + }); + + return { + name: business.name, + balance: business.balance, + usersCount: business.users.length, + owner: owner ? owner.username : 'Unknown' + }; + })); + + res.json(businessesData); +}); + + +// Запуск сервера +const PORT = process.env.PORT || 3002; +app.listen(PORT, () => console.log(`Сервер запущен на порту ${PORT}`)); diff --git a/public/scoreboard.css b/public/scoreboard.css new file mode 100644 index 0000000..5d5424d --- /dev/null +++ b/public/scoreboard.css @@ -0,0 +1,78 @@ +body { + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f9; +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; +} + +.tabs { + display: flex; + margin-bottom: 20px; +} + +.tab-button { + padding: 10px 20px; + margin-right: 10px; + cursor: pointer; + background-color: #ddd; + border: none; + border-radius: 5px; + transition: background-color 0.3s; +} + +.tab-button.active { + background-color: #0066cc; + color: white; +} + +.tab-button:hover { + background-color: #005bb5; +} + +.tab-content { + display: flex; + flex-direction: column; +} + +.tab-pane { + display: none; +} + +.tab-pane.active { + display: block; +} + +h2 { + font-size: 24px; + margin-bottom: 10px; +} + +.card { + background-color: white; + padding: 15px; + margin-bottom: 15px; + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +.card h3 { + margin: 0; + font-size: 18px; + color: #333; +} + +.card p { + margin: 5px 0; + color: #777; +} + +.card .money { + font-weight: bold; + color: #0066cc; +} diff --git a/public/scoreboard.html b/public/scoreboard.html new file mode 100644 index 0000000..c5f7ad5 --- /dev/null +++ b/public/scoreboard.html @@ -0,0 +1,191 @@ + + + + + + Таблица лидеров + + + + + +
+

Таблица Лидеров

+ + +
+ + + + +
+ + +
+
+ + + + + + + diff --git a/public/scoreboard.js b/public/scoreboard.js new file mode 100644 index 0000000..86d40ff --- /dev/null +++ b/public/scoreboard.js @@ -0,0 +1,93 @@ +document.addEventListener('DOMContentLoaded', () => { + const tabs = document.querySelectorAll('.tab-button'); + const tabPanes = document.querySelectorAll('.tab-pane'); + + // Handle tab navigation + tabs.forEach(tab => { + tab.addEventListener('click', () => { + tabs.forEach(t => t.classList.remove('active')); + tabPanes.forEach(pane => pane.classList.remove('active')); + + tab.classList.add('active'); + document.getElementById(tab.dataset.tab).classList.add('active'); + }); + }); + + // Fetch and display top users by balance + async function fetchTopUsers() { + const sortBy = document.getElementById('sort-users').value; + const response = await fetch(`/top-users?sortBy=${sortBy}`); + const data = await response.json(); + + const topUsersContainer = document.getElementById('top-users'); + topUsersContainer.innerHTML = data.map(player => ` +
+

${player.name} ${player.status === 'bronze' ? '[🔺]' : player.status === 'silver' ? '[🔹]' : '[🔸]'}

+

Баланс: ${player.money} ₽

+

Уровень: ${player.level}

+
+ `).join(''); + } + + // Fetch and display top characters by balance + async function fetchTopCharacters() { + const sortBy = document.getElementById('sort-characters').value; + const response = await fetch(`/top-characters?sortBy=${sortBy}`); + const data = await response.json(); + + const topCharactersContainer = document.getElementById('top-characters'); + topCharactersContainer.innerHTML = data.map(character => ` +
+

${character.name}

+

Грязные деньги: ${character.dirtymoney} ₽

+

Уровень: ${character.level}

+

Сила: ${character.force}

+

Интеллект: ${character.intelligence}

+

Устойчивость: ${character.resilience}

+

Выносливость: ${character.endurance}

+
+ `).join(''); + } + + // Fetch and display enterprises + async function fetchEnterprises() { + const response = await fetch('/enterprises'); + const data = await response.json(); + + const enterprisesContainer = document.getElementById('enterprises-list'); + enterprisesContainer.innerHTML = data.map(enterprise => ` +
+

${enterprise.name} ${enterprise.icon}

+

Тип ресурса: ${enterprise.resourceType}

+

Уровень: ${enterprise.level}

+

Производительность: ${enterprise.efficiency} ед./час

+

Емкость склада: ${enterprise.warehouseCapacity} ед.

+

Текущие ресурсы: ${enterprise.currentResources} ед.

+

Владелец: ${enterprise.owner}

+
+ `).join(''); + } + + // Fetch and display businesses + async function fetchBusinesses() { + const sortBy = document.getElementById('sort-businesses').value; + const response = await fetch(`/businesses?sortBy=${sortBy}`); + const data = await response.json(); + + const businessesContainer = document.getElementById('businesses-list'); + businessesContainer.innerHTML = data.map(business => ` +
+

${business.name}

+

Владелец: ${business.owner}

+

Баланс: ${business.balance} ₽

+

Пользователи: ${business.usersCount}

+
+ `).join(''); + } + + // Initial fetches + fetchTopUsers(); + fetchTopCharacters(); + fetchEnterprises(); + fetchBusinesses(); +}); diff --git a/server.bat b/server.bat index c090ad7..bce3d3b 100644 --- a/server.bat +++ b/server.bat @@ -1,2 +1,3 @@ nodemon --ignore json/ .\server.js +nodemon --ignore json/ .\pages.js pause \ No newline at end of file