reset UUID y shame persistente

This commit is contained in:
2025-08-16 00:56:16 -06:00
parent b18397deb4
commit 730c7bda9e
5 changed files with 291 additions and 6 deletions

View File

@@ -0,0 +1,112 @@
<template>
<div class="actions-container">
<div class="section-header">
<h2>📥 Export / Tools</h2>
</div>
<div class="buttons">
<button class="btn btn-export" @click="downloadCsv">Descargar resultados (CSV)</button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface PlayerRow {
sessionId: string;
uuid?: string;
name: string;
role: 'P1' | 'P2' | '';
pavoTokens?: number;
eloteTokens?: number;
shameTokens?: number;
color?: string;
}
interface RoomDetail {
roomId: string;
players?: PlayerRow[];
gameStatus?: string;
variant?: string;
round?: number;
}
const props = defineProps<{ rooms: any[]; roomDetails: { [key: string]: RoomDetail } }>();
const gameRooms = computed(() => props.rooms.filter(r => r.name === 'game'));
function csvEscape(v: any): string {
const s = String(v ?? '').replace(/\r?\n/g, ' ');
if (/[",]/.test(s)) return '"' + s.replace(/"/g, '""') + '"';
return s;
}
function buildCsv(): string {
const headers = [
'roomId', 'variant', 'round', 'status',
'p1_name', 'p1_pavo', 'p1_elote',
'p2_name', 'p2_pavo', 'p2_elote'
];
const lines: string[] = [headers.join(',')];
gameRooms.value.forEach(room => {
const det = props.roomDetails[room.roomId] || {};
const status = (det as any).gameStatus || room?.metadata?.gameStatus || 'waiting';
const variant = (det as any).variant || room?.metadata?.currentVariant || 'G1';
const round = (det as any).round || room?.metadata?.currentRound || 1;
const players = (det.players || []) as PlayerRow[];
const p1 = players.find(p => p.role === 'P1') || players[0] || ({} as any);
const p2 = players.find(p => p.role === 'P2') || players[1] || ({} as any);
const row = [
room.roomId,
variant,
round,
status,
p1?.name || '',
p1?.pavoTokens ?? 0,
p1?.eloteTokens ?? 0,
p2?.name || '',
p2?.pavoTokens ?? 0,
p2?.eloteTokens ?? 0
].map(csvEscape).join(',');
lines.push(row);
});
return lines.join('\n') + '\n';
}
function downloadCsv() {
const csv = buildCsv();
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const now = new Date();
const pad = (n: number) => String(n).padStart(2, '0');
const fname = `snatch-results-${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}-${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}.csv`;
const a = document.createElement('a');
a.href = url;
a.download = fname;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
</script>
<style scoped>
.actions-container {
margin-bottom: 24px;
background: rgba(255,255,255,0.1);
border-radius: 12px;
padding: 16px;
}
.section-header {
display:flex; align-items:center; justify-content:space-between; margin-bottom:10px;
}
.section-header h2 { margin:0; font-size: 1.3rem; }
.buttons { display:flex; gap: 10px; flex-wrap: wrap; }
.btn { padding: 10px 14px; border:none; border-radius: 10px; font-weight:700; cursor:pointer; }
.btn-export { background: linear-gradient(135deg, #10b981 0%, #059669 100%); color:white; }
.btn-export:hover { filter: brightness(1.05); }
</style>