funcion de descargar json eliminada

This commit is contained in:
2025-08-29 12:46:33 -06:00
parent 21adaf4caa
commit f8fe1bdf57

View File

@@ -13,9 +13,6 @@
<span class="collapse-icon" :class="{ rotated: filtersCollapsed }"></span> <span class="collapse-icon" :class="{ rotated: filtersCollapsed }"></span>
<span class="collapse-text">{{ filtersCollapsed ? 'Mostrar filtros' : 'Ocultar filtros' }}</span> <span class="collapse-text">{{ filtersCollapsed ? 'Mostrar filtros' : 'Ocultar filtros' }}</span>
</button> </button>
<button class="btn" @click="downloadJSON" :disabled="loading" title="Descargar datos actuales como JSON">
📊 <span class="label">JSON</span>
</button>
</div> </div>
</div> </div>
<div class="header-markers filters-indicators"> <div class="header-markers filters-indicators">
@@ -87,29 +84,6 @@
}" }"
/> />
<!-- Raw payload viewer for players-actions-stream -->
<div class="raw-viewer glass light" v-if="rawActionsPayload">
<div class="raw-header">
<div class="raw-title">Datos del stream (players-actions-stream)</div>
<div class="raw-actions">
<button class="btn" @click="showRaw = !showRaw">{{ showRaw ? 'Ocultar' : 'Mostrar' }}</button>
<button class="btn" @click="copyRaw" title="Copiar JSON">Copiar</button>
</div>
</div>
<pre v-show="showRaw" class="raw-pre">{{ prettyRaw }}</pre>
</div>
<!-- Datos filtrados (vista actual) -->
<div class="raw-viewer glass light">
<div class="raw-header">
<div class="raw-title">Datos filtrados (vista actual)</div>
<div class="raw-actions">
<button class="btn" @click="showFiltered = !showFiltered">{{ showFiltered ? 'Ocultar' : 'Mostrar' }}</button>
<button class="btn" @click="copyFiltered" title="Copiar JSON">Copiar</button>
</div>
</div>
<pre v-show="showFiltered" class="raw-pre">{{ prettyFiltered }}</pre>
</div>
<AppCredits position="bottom-right" /> <AppCredits position="bottom-right" />
</div> </div>
</template> </template>
@@ -426,7 +400,6 @@ watch(filterState, () => {
}, { deep: true }); }, { deep: true });
const availableRooms = ref<{ roomId: string; name: string; playerCount?: number }[]>([]); const availableRooms = ref<{ roomId: string; name: string; playerCount?: number }[]>([]);
const selectedRoomIds = ref<string[]>([]);
const playerLoading = ref(false); const playerLoading = ref(false);
const playerEventCounts = ref<Record<string, number>>((Object.fromEntries(EVENTS.map(k => [k, 0])) as Record<string, number>)); const playerEventCounts = ref<Record<string, number>>((Object.fromEntries(EVENTS.map(k => [k, 0])) as Record<string, number>));
const playersActionsByUuid = ref<Record<string, Record<string, number>>>({}); const playersActionsByUuid = ref<Record<string, Record<string, number>>>({});
@@ -447,64 +420,6 @@ const playerBarGradient = computed(() => '#8b5cf6');
const apiBase = (import.meta as any).env?.VITE_API_URL || `${window.location.protocol}//${window.location.host}/api`; const apiBase = (import.meta as any).env?.VITE_API_URL || `${window.location.protocol}//${window.location.host}/api`;
const esActions = ref<EventSource|null>(null); const esActions = ref<EventSource|null>(null);
const rawActionsPayload = ref<any>(null); const rawActionsPayload = ref<any>(null);
const showRaw = ref(false);
const prettyRaw = computed(() => {
try {
return JSON.stringify(rawActionsPayload.value, null, 2);
} catch {
return String(rawActionsPayload.value || '');
}
});
function copyRaw() {
try {
navigator.clipboard.writeText(prettyRaw.value);
} catch {}
}
// Filtered snapshot (what the UI is showing after filters)
const showFiltered = ref(false);
const filteredSnapshot = computed(() => {
try {
return {
metadata: {
timestamp: new Date().toISOString(),
dataSource: filterState.value.timeMode === 'active' ? 'active-rooms' : 'aggregated',
filters: {
room: filterState.value.rooms,
round: filterState.value.rounds,
game: filterState.value.games,
selectedPlayers: filterState.value.playerUuids,
selectedRooms: selectedRoomIds.value,
timeMode: filterState.value.timeMode,
from: filterState.value.rangeFrom,
to: filterState.value.rangeTo,
liveEnd: filterState.value.liveEnd
}
},
chartTotals: {
offers: offersTotal.value,
responses: responsesTotal.value,
force: forceTotal.value,
shame: shameTotal.value,
report: reportTotal.value,
averageScore: averageScoreTotal.value,
totalPlayers: totalPlayersCount.value
},
globalEventCounts: eventFilters.globalEventCounts.value,
playerEventCounts: playerEventCounts.value,
combinedCounts: {
global: combinedGlobalCounts.value,
players: combinedPlayerCounts.value
}
};
} catch (e) {
return { error: String(e) };
}
});
const prettyFiltered = computed(() => JSON.stringify(filteredSnapshot.value, null, 2));
function copyFiltered() {
try { navigator.clipboard.writeText(prettyFiltered.value); } catch {}
}
// Indicator labels // Indicator labels
const periodLabel = computed(() => { const periodLabel = computed(() => {
@@ -654,96 +569,6 @@ onUnmounted(() => {
// const allPlayersActions = ref<{ uuid: string; name: string; total: number }[]>([]); // const allPlayersActions = ref<{ uuid: string; name: string; total: number }[]>([]);
function downloadJSON() {
// Create a comprehensive snapshot of current interface data
const currentData = {
metadata: {
timestamp: new Date().toISOString(),
dataSource: filterState.value.timeMode === 'active' ? 'active-rooms' : 'aggregated',
filters: {
room: filterState.value.rooms,
round: filterState.value.rounds,
game: filterState.value.games,
hasActiveFilters: activeFilters.value.hasFilters,
selectedPlayers: filterState.value.playerUuids,
selectedRooms: selectedRoomIds.value,
timeMode: filterState.value.timeMode,
rangeFrom: filterState.value.rangeFrom,
rangeTo: filterState.value.rangeTo,
liveEnd: filterState.value.liveEnd
}
},
// Current chart totals being displayed
chartTotals: {
offers: offersTotal.value,
responses: responsesTotal.value,
force: forceTotal.value,
shame: shameTotal.value,
report: reportTotal.value,
averageScore: averageScoreTotal.value,
totalPlayers: totalPlayersCount.value
},
// Global event counts (filtered)
globalEventCounts: eventFilters.globalEventCounts.value,
// Selected player event counts (if applicable)
selectedPlayersEventCounts: filterState.value.playerUuids.length ? playerEventCounts.value : null,
// Additional metrics being displayed
additionalMetrics: additionalMetrics.value,
// Selected player metrics (if applicable)
selectedPlayersMetrics: filterState.value.playerUuids.length ? selectedPlayerMetrics.value : null,
// Combined counts used in charts
combinedGlobalCounts: combinedGlobalCounts.value,
combinedPlayerCounts: filterState.value.playerUuids.length ? combinedPlayerCounts.value : null,
// Players data
players: allPlayersWithScores.value,
availableRooms: availableRooms.value,
// Current filtered data if available
currentSourceEvents: eventFilters.currentSourceEvents.value,
// Per-player action counts
playersActionsByUuid: playersActionsByUuid.value,
// All players with scores data
allPlayersWithScores: allPlayersWithScores.value.map(player => ({
uuid: player.uuid,
name: player.name,
total: player.total,
shameTokens: player.shameTokens,
counts: player.counts,
roomScoreHistory: player.roomScoreHistory
}))
};
// Convert to formatted JSON string
const jsonString = JSON.stringify(currentData, null, 2);
// Create and download file
const blob = new Blob([jsonString], { type: 'application/json;charset=utf-8;' });
const link = document.createElement('a');
const url = URL.createObjectURL(blob);
link.setAttribute('href', url);
// Generate filename with current filters and timestamp
const timestamp = new Date().toISOString().slice(0, 19).replace(/[T:]/g, '-');
const dataSourceLabel = filterState.value.timeMode === 'range' ? 'agregados' : 'activos';
const filterLabel = activeFilters.value.hasFilters ? '_filtrado' : '';
const filename = `leaderboard_${dataSourceLabel}${filterLabel}_${timestamp}.json`;
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
</script> </script>
@@ -939,12 +764,6 @@ function downloadJSON() {
.marker-chip { display: inline-flex; align-items: center; gap: 6px; padding: 2px 4px; border-radius: 999px; border: none; background: transparent; color: #334155; font-size: 12px; font-weight: 700; } .marker-chip { display: inline-flex; align-items: center; gap: 6px; padding: 2px 4px; border-radius: 999px; border: none; background: transparent; color: #334155; font-size: 12px; font-weight: 700; }
.marker-chip.clickable { cursor: pointer; } .marker-chip.clickable { cursor: pointer; }
/* Raw payload styles */
.raw-viewer { margin-top: 14px; padding: 12px; border-radius: 14px; }
.raw-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.raw-title { font-weight: 800; color: #334155; font-size: 14px; }
.raw-actions { display: flex; gap: 8px; }
.raw-pre { max-height: 420px; overflow: auto; background: #0b1020; color: #e5e7eb; padding: 12px; border-radius: 10px; font-size: 12px; line-height: 1.4; border: 1px solid #1f2937; }
/* Time indicator key */ /* Time indicator key */
.key.time { background: linear-gradient(90deg, #f59e0b, #d97706); box-shadow: 0 0 8px rgba(245,158,11,0.35); } .key.time { background: linear-gradient(90deg, #f59e0b, #d97706); box-shadow: 0 0 8px rgba(245,158,11,0.35); }