mejoras UI,
This commit is contained in:
@@ -70,6 +70,7 @@
|
||||
<div
|
||||
v-for="group in ratioData"
|
||||
:key="group.name"
|
||||
v-show="group.total > 0"
|
||||
class="ratio-group"
|
||||
:class="{ highlight: highlighted === group.name }"
|
||||
@mouseenter="highlighted = group.name"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<div class="leaderboard light">
|
||||
<div class="header glass light">
|
||||
<div class="header-left">
|
||||
<button class="btn-back" @click="goHome" title="Volver al inicio">
|
||||
← Inicio
|
||||
</button>
|
||||
<h1>📈 Leaderboard</h1>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn-collapse" @click="filtersCollapsed = !filtersCollapsed" :title="filtersCollapsed ? 'Mostrar filtros' : 'Ocultar filtros'">
|
||||
<span class="collapse-icon" :class="{ rotated: filtersCollapsed }">▼</span>
|
||||
@@ -123,6 +128,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import EventChart from '../components/EventChart.vue';
|
||||
import EventFilters from '../components/EventFilters.vue';
|
||||
import DataSourceSelector from '../components/DataSourceSelector.vue';
|
||||
@@ -131,6 +137,7 @@ import { useEventFilters } from '../composables/useEventFilters';
|
||||
interface RoomInfo { roomId: string; metadata?: any; }
|
||||
interface RoomState { players?: any[]; systemMessages?: { kind: string }[] }
|
||||
|
||||
const router = useRouter();
|
||||
const loading = ref(false);
|
||||
const eventFilters = useEventFilters();
|
||||
const filtersCollapsed = ref(false);
|
||||
@@ -193,6 +200,26 @@ const selectedPlayerMetrics = ref<Record<string, number>>({
|
||||
// Store room score history from players
|
||||
const allPlayersWithScores = ref<any[]>([]);
|
||||
|
||||
// Function to check if a score passes the current filters
|
||||
function scorePassesFilters(score: any, roomId: string) {
|
||||
// Room filter
|
||||
if (eventFilters.roomFilter.value !== 'all' && roomId !== eventFilters.roomFilter.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Round filter
|
||||
if (eventFilters.roundFilter.value !== 'all' && score.round !== eventFilters.roundFilter.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Game variant filter
|
||||
if (eventFilters.gameFilter.value !== 'all' && score.variant !== eventFilters.gameFilter.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Function to compute additional metrics from players' score history
|
||||
function computeMetricsFromScores() {
|
||||
if (!allPlayersWithScores.value.length) return;
|
||||
@@ -213,6 +240,11 @@ function computeMetricsFromScores() {
|
||||
if (player.roomScoreHistory) {
|
||||
player.roomScoreHistory.forEach((roomScore: any) => {
|
||||
roomScore.scores.forEach((score: any) => {
|
||||
// Apply filters to scores
|
||||
if (!scorePassesFilters(score, roomScore.roomId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (score.role === 'P1') {
|
||||
totalP1Scores += score.score;
|
||||
p1Count++;
|
||||
@@ -259,6 +291,11 @@ function computeSelectedPlayerMetrics(uuid: string) {
|
||||
|
||||
playerData.roomScoreHistory.forEach((roomScore: any) => {
|
||||
roomScore.scores.forEach((score: any) => {
|
||||
// Apply filters to scores
|
||||
if (!scorePassesFilters(score, roomScore.roomId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (score.role === 'P1') {
|
||||
totalP1Scores += score.score;
|
||||
p1Count++;
|
||||
@@ -328,11 +365,16 @@ const averageScoreTotal = computed(() => {
|
||||
let totalScores = 0;
|
||||
let totalScoreCount = 0;
|
||||
|
||||
// Sum all individual scores from all players regardless of role
|
||||
// Sum all individual scores from all players regardless of role, applying filters
|
||||
allPlayersWithScores.value.forEach((player: any) => {
|
||||
if (player.roomScoreHistory) {
|
||||
player.roomScoreHistory.forEach((roomScore: any) => {
|
||||
roomScore.scores.forEach((score: any) => {
|
||||
// Apply filters to scores
|
||||
if (!scorePassesFilters(score, roomScore.roomId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
totalScores += score.score;
|
||||
totalScoreCount++;
|
||||
});
|
||||
@@ -360,6 +402,8 @@ const activeFilters = computed(() => ({
|
||||
// Watch for changes in filters and data source
|
||||
watch([eventFilters.dataSource, eventFilters.roundFilter, eventFilters.gameFilter, eventFilters.roomFilter], () => {
|
||||
eventFilters.applyFilters(EVENTS);
|
||||
// Recalculate metrics when filters change
|
||||
computeMetricsFromScores();
|
||||
});
|
||||
|
||||
// selectedUuid watch will be added after selectedUuid is declared
|
||||
@@ -480,6 +524,10 @@ function clearRoom() {
|
||||
eventFilters.applyFilters(EVENTS);
|
||||
}
|
||||
|
||||
function goHome() {
|
||||
router.push('/');
|
||||
}
|
||||
|
||||
function prevPage() { page.value = Math.max(1, page.value - 1); }
|
||||
function nextPage() { page.value = Math.min(pageCount.value, page.value + 1); }
|
||||
function prevRoomPage() { roomPage.value = Math.max(1, roomPage.value - 1); }
|
||||
@@ -875,6 +923,9 @@ function downloadCSV() {
|
||||
|
||||
.header { display:flex; align-items:center; justify-content:space-between; padding: 12px 14px; margin-bottom: 14px; }
|
||||
.header h1 { margin: 0; }
|
||||
.header-left { display:flex; align-items:center; gap: 16px; }
|
||||
.btn-back { background:#667eea; color:#fff; border:none; border-radius:8px; padding:8px 14px; font-weight:600; cursor:pointer; transition: all 0.3s ease; font-size: 14px; }
|
||||
.btn-back:hover { background:#5b6bda; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); }
|
||||
.actions { display:flex; gap: 8px; }
|
||||
.actions .btn { background:#667eea; color:#fff; border:none; border-radius:10px; padding:8px 12px; font-weight:800; cursor:pointer; }
|
||||
.actions .btn.toggle { background:#eef2ff; color:#3949ab; border:1px solid #c7d2fe; }
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
<button @click="goToDashboard" class="btn-dashboard">
|
||||
🎛️ Dashboard Admin
|
||||
</button>
|
||||
<button @click="goToLeaderboard" class="btn-leaderboard">
|
||||
📈 Leaderboard
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- QR Mode Toggle -->
|
||||
@@ -230,6 +233,10 @@ function goToDashboard() {
|
||||
router.push('/dashboard');
|
||||
}
|
||||
|
||||
function goToLeaderboard() {
|
||||
router.push('/leaderboard');
|
||||
}
|
||||
|
||||
// Context menu functions
|
||||
function showContextMenu(event: MouseEvent, uuidInfo: UuidInfo) {
|
||||
contextMenu.value = {
|
||||
@@ -796,7 +803,8 @@ async function copyToClipboard() {
|
||||
}
|
||||
|
||||
.btn-random,
|
||||
.btn-dashboard {
|
||||
.btn-dashboard,
|
||||
.btn-leaderboard {
|
||||
padding: 12px 30px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
@@ -826,6 +834,16 @@ async function copyToClipboard() {
|
||||
box-shadow: 0 5px 15px rgba(79, 172, 254, 0.4);
|
||||
}
|
||||
|
||||
.btn-leaderboard {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-leaderboard:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* Context Menu */
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
@@ -1038,7 +1056,8 @@ async function copyToClipboard() {
|
||||
}
|
||||
|
||||
.btn-random,
|
||||
.btn-dashboard {
|
||||
.btn-dashboard,
|
||||
.btn-leaderboard {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user