diff --git a/client/src/components/DashboardActions.vue b/client/src/components/DashboardActions.vue index 48aefa5..ab388cf 100644 --- a/client/src/components/DashboardActions.vue +++ b/client/src/components/DashboardActions.vue @@ -30,6 +30,7 @@ interface RoomDetail { gameStatus?: string; variant?: string; round?: number; + systemMessages?: Array<{ text: string; kind: string; timestamp: number }>; } const props = defineProps<{ rooms: any[]; roomDetails: { [key: string]: RoomDetail } }>(); @@ -46,7 +47,8 @@ function buildCsvByRoom(): string { const headers = [ 'roomId', 'variant', 'round', 'status', 'p1_uuid', 'p1_name', 'p1_pavo', 'p1_elote', 'p1_shame', - 'p2_uuid', 'p2_name', 'p2_pavo', 'p2_elote', 'p2_shame' + 'p2_uuid', 'p2_name', 'p2_pavo', 'p2_elote', 'p2_shame', + 'events_history' ]; const lines: string[] = [headers.join(',')]; @@ -59,6 +61,9 @@ function buildCsvByRoom(): string { 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 kinds = ((det.systemMessages || []) as Array<{ kind: string }>).map(m => (m?.kind || '').toString()).filter(Boolean); + const eventsHistory = kinds.join('|'); + const row = [ room.roomId, variant, @@ -73,7 +78,8 @@ function buildCsvByRoom(): string { p2?.name || '', p2?.pavoTokens ?? 0, p2?.eloteTokens ?? 0, - p2?.shameTokens ?? 0 + p2?.shameTokens ?? 0, + eventsHistory ].map(csvEscape).join(','); lines.push(row); }); @@ -114,6 +120,7 @@ function buildCsvByUuid(): string { return lines.join('\n') + '\n'; } + function triggerDownload(csv: string, suffix: string) { const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); diff --git a/client/src/components/RoomCard.vue b/client/src/components/RoomCard.vue index 47537d4..00de836 100644 --- a/client/src/components/RoomCard.vue +++ b/client/src/components/RoomCard.vue @@ -88,6 +88,16 @@ {{ roomDetails.winner }} + +
@@ -116,6 +126,7 @@ interface RoomDetails { }>; timeRemaining: number; winner?: string; + systemMessages?: Array<{ text: string; kind: string; timestamp: number }>; } defineProps<{ @@ -350,4 +361,11 @@ function formatSeconds(seconds: number): string { color: #4caf50; font-weight: bold; } - \ No newline at end of file + +.system-messages { margin-top: 14px; } +.sys-head { font-weight: 800; font-size: 13px; color:#556; margin-bottom: 6px; } +.sys-list { display:flex; flex-direction:column; gap:6px; max-height: 180px; overflow:auto; padding-right: 4px; } +.sys-item { display:flex; gap:8px; align-items:center; background:#f8f9fa; border:1px solid #eee; border-radius:8px; padding:6px 8px; } +.sys-time { font-family: monospace; font-size: 11px; color:#666; } +.sys-text { font-size: 13px; font-weight:600; color:#333; } + diff --git a/server/src/rooms/GameRoom.ts b/server/src/rooms/GameRoom.ts index df102dd..1dafc8d 100644 --- a/server/src/rooms/GameRoom.ts +++ b/server/src/rooms/GameRoom.ts @@ -6,6 +6,7 @@ import { broadcastDashboardUpdate } from "../adminApi"; export class GameRoom extends Room