system message guardados en historial por sala

This commit is contained in:
2025-08-27 18:23:22 -06:00
parent 80af7461a4
commit d7c0b79549
3 changed files with 35 additions and 3 deletions

View File

@@ -30,6 +30,7 @@ interface RoomDetail {
gameStatus?: string; gameStatus?: string;
variant?: string; variant?: string;
round?: number; round?: number;
systemMessages?: Array<{ text: string; kind: string; timestamp: number }>;
} }
const props = defineProps<{ rooms: any[]; roomDetails: { [key: string]: RoomDetail } }>(); const props = defineProps<{ rooms: any[]; roomDetails: { [key: string]: RoomDetail } }>();
@@ -46,7 +47,8 @@ function buildCsvByRoom(): string {
const headers = [ const headers = [
'roomId', 'variant', 'round', 'status', 'roomId', 'variant', 'round', 'status',
'p1_uuid', 'p1_name', 'p1_pavo', 'p1_elote', 'p1_shame', '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(',')]; 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 p1 = players.find(p => p.role === 'P1') || players[0] || ({} as any);
const p2 = players.find(p => p.role === 'P2') || players[1] || ({} 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 = [ const row = [
room.roomId, room.roomId,
variant, variant,
@@ -73,7 +78,8 @@ function buildCsvByRoom(): string {
p2?.name || '', p2?.name || '',
p2?.pavoTokens ?? 0, p2?.pavoTokens ?? 0,
p2?.eloteTokens ?? 0, p2?.eloteTokens ?? 0,
p2?.shameTokens ?? 0 p2?.shameTokens ?? 0,
eventsHistory
].map(csvEscape).join(','); ].map(csvEscape).join(',');
lines.push(row); lines.push(row);
}); });
@@ -114,6 +120,7 @@ function buildCsvByUuid(): string {
return lines.join('\n') + '\n'; return lines.join('\n') + '\n';
} }
function triggerDownload(csv: string, suffix: string) { function triggerDownload(csv: string, suffix: string) {
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);

View File

@@ -88,6 +88,16 @@
<span class="winner-name">{{ roomDetails.winner }}</span> <span class="winner-name">{{ roomDetails.winner }}</span>
</div> </div>
</div> </div>
<div v-if="roomDetails.systemMessages?.length" class="system-messages">
<div class="sys-head">System Messages</div>
<div class="sys-list">
<div v-for="m in roomDetails.systemMessages" :key="m.timestamp + '-' + (m.kind||'')" class="sys-item">
<span class="sys-time">{{ formatTime(m.timestamp) }}</span>
<span class="sys-text">{{ m.text }}</span>
</div>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -116,6 +126,7 @@ interface RoomDetails {
}>; }>;
timeRemaining: number; timeRemaining: number;
winner?: string; winner?: string;
systemMessages?: Array<{ text: string; kind: string; timestamp: number }>;
} }
defineProps<{ defineProps<{
@@ -350,4 +361,11 @@ function formatSeconds(seconds: number): string {
color: #4caf50; color: #4caf50;
font-weight: bold; font-weight: bold;
} }
.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; }
</style> </style>

View File

@@ -6,6 +6,7 @@ import { broadcastDashboardUpdate } from "../adminApi";
export class GameRoom extends Room<GameState> { export class GameRoom extends Room<GameState> {
maxClients = 2; maxClients = 2;
private systemMessages: { text: string; kind: string; timestamp: number }[] = [];
getFilterOptions() { getFilterOptions() {
// If waiting for shuffled players, report as available regardless of current client count // If waiting for shuffled players, report as available regardless of current client count
@@ -45,6 +46,11 @@ export class GameRoom extends Room<GameState> {
if (kind !== 'round_advance') { if (kind !== 'round_advance') {
this.recentSystemMessage = { text, kind, timestamp }; this.recentSystemMessage = { text, kind, timestamp };
} }
// Persist in per-room history (keep last 200)
this.systemMessages.push({ text, kind, timestamp });
if (this.systemMessages.length > 200) {
this.systemMessages.splice(0, this.systemMessages.length - 200);
}
this.broadcast("chat", { this.broadcast("chat", {
id: `${timestamp}-${Math.random().toString(36).slice(2)}`, id: `${timestamp}-${Math.random().toString(36).slice(2)}`,
@@ -937,6 +943,7 @@ export class GameRoom extends Room<GameState> {
variant: this.state.currentVariant, variant: this.state.currentVariant,
round: this.state.currentRound, round: this.state.currentRound,
recentSystemMessage: this.recentSystemMessage, recentSystemMessage: this.recentSystemMessage,
systemMessages: this.systemMessages.slice(-50),
decisions: { decisions: {
p1Action: this.state.p1Action, p1Action: this.state.p1Action,
p2Action: this.state.p2Action, p2Action: this.state.p2Action,