diff --git a/client/src/components/DashboardActions.vue b/client/src/components/DashboardActions.vue index ab388cf..2a6bbf7 100644 --- a/client/src/components/DashboardActions.vue +++ b/client/src/components/DashboardActions.vue @@ -87,35 +87,66 @@ function buildCsvByRoom(): string { return lines.join('\n') + '\n'; } -function buildCsvByUuid(): string { +async function buildCsvByUuid(): Promise { const headers = [ 'roomId', 'variant', 'round', 'status', - 'uuid', 'name', 'role', 'pavo', 'elote', 'shame' + 'uuid', 'name', 'role', 'pavo', 'elote', 'shame', 'events_made' ]; const lines: string[] = [headers.join(',')]; - gameRooms.value.forEach(room => { + const apiBase = (import.meta as any).env?.VITE_API_URL || `${window.location.protocol}//${window.location.host}/api`; + const historyCache = new Map(); + + for (const room of gameRooms.value) { const det = (props.roomDetails[room.roomId] || {}) as any; const status = det.gameStatus || room?.metadata?.gameStatus || 'waiting'; const variant = det.variant || room?.metadata?.currentVariant || 'G1'; const round = det.round || room?.metadata?.currentRound || 1; const players = (det.players || []) as PlayerRow[]; - players.forEach(p => { + + for (const p of players) { + const uuid = (p?.uuid || '').toString(); + let history = uuid ? historyCache.get(uuid) : []; + if (uuid && !history) { + try { + const resp = await fetch(`${apiBase}/players/${uuid}/history`); + const data = await resp.json(); + history = Array.isArray(data?.history) ? data.history : []; + } catch { + history = []; + } + historyCache.set(uuid, history); + } + + // Build events_made generically: + // - If kind starts with p1_ or p2_, include only when event.role matches P1/P2 + // - Otherwise include by default (system/agnostic events) + const events = (history || []).filter((h: any) => { + const kind = (h?.kind || '').toString(); + if (!kind) return false; + const evRole = kind.startsWith('p1_') ? 'P1' : (kind.startsWith('p2_') ? 'P2' : null); + if (!evRole) return true; // role-agnostic + const r = ((h?.role || '') as string).toUpperCase(); + return r === evRole; + }).map((h: any) => h.kind); + + const eventsHistory = events.join('|'); const row = [ room.roomId, variant, round, status, - p?.uuid || '', + uuid, p?.name || '', p?.role || '', p?.pavoTokens ?? 0, p?.eloteTokens ?? 0, - p?.shameTokens ?? 0 + p?.shameTokens ?? 0, + eventsHistory ].map(csvEscape).join(','); lines.push(row); - }); - }); + } + } return lines.join('\n') + '\n'; } @@ -137,7 +168,7 @@ function triggerDownload(csv: string, suffix: string) { } function downloadCsvByRoom() { triggerDownload(buildCsvByRoom(), 'by-room'); } -function downloadCsvByUuid() { triggerDownload(buildCsvByUuid(), 'by-uuid'); } +async function downloadCsvByUuid() { const csv = await buildCsvByUuid(); triggerDownload(csv, 'by-uuid'); } diff --git a/client/src/views/games/PlayerStats.vue b/client/src/views/games/PlayerStats.vue index de827c2..151b9c4 100644 --- a/client/src/views/games/PlayerStats.vue +++ b/client/src/views/games/PlayerStats.vue @@ -37,7 +37,12 @@
Historial del sistema — {{ player.name }}
- +
+ + +
Cargando…
Sin historial
@@ -51,11 +56,11 @@ Mensaje Sala
-
+
{{ fmtTime(m.timestamp) }} {{ (m.role || '') || '—' }} 🦃 {{ m.pavoTokens ?? 0 }} · 🌽 {{ m.eloteTokens ?? 0 }} · 😶 {{ m.shameTokens }} - {{ m.kind }} + {{ friendlyKind(m.kind) }} {{ m.text }} {{ (m.roomId || '').slice(0,8) }}
@@ -92,6 +97,19 @@ const primary = computed(() => props.player.color || '#667eea'); const showHistory = ref(false); const loadingHistory = ref(false); const historyItems = ref([]); +const onlyEventsMade = ref(false); +const filteredHistory = computed(() => { + if (!onlyEventsMade.value) return historyItems.value || []; + const list = Array.isArray(historyItems.value) ? historyItems.value : []; + return list.filter((h: any) => { + const kind = (h?.kind || '').toString(); + if (!kind) return false; + const prefix = kind.slice(0,3).toLowerCase(); + if (prefix === 'p1_') return ((h?.role || '').toUpperCase() === 'P1'); + if (prefix === 'p2_') return ((h?.role || '').toUpperCase() === 'P2'); + return true; // system/agnostic events + }); +}); const room = computed(() => colyseusService.gameRoom.value as any); function toggleHistory() { @@ -155,6 +173,24 @@ onMounted(() => { onBeforeUnmount(() => { window.removeEventListener('keydown', onKeydown); }); + +function friendlyKind(kind: string): string { + const k = (kind || '').toString(); + const map: Record = { + p1_propose: 'Ofrecer', + p1_no_offer: 'No Ofrecer', + p2_snatch: 'Robar', + p2_accept: 'Aceptar Oferta', + p2_force: 'Forzar Oferta', + p2_no_force: 'No Forzar Oferta', + p2_reject: 'Rechazar Oferta', + p1_shame: 'Asignar Vergüenza', + p1_no_shame: 'No Asignar Vergüenza', + p1_report: 'Denunciar', + p1_no_report: 'No Denunciar', + }; + return map[k] || k; +}