diff --git a/client/src/components/DashboardActions.vue b/client/src/components/DashboardActions.vue
index 4bf37b8..48aefa5 100644
--- a/client/src/components/DashboardActions.vue
+++ b/client/src/components/DashboardActions.vue
@@ -4,7 +4,8 @@
📥 Export / Tools
-
+
+
@@ -41,19 +42,19 @@ function csvEscape(v: any): string {
return s;
}
-function buildCsv(): string {
+function buildCsvByRoom(): string {
const headers = [
'roomId', 'variant', 'round', 'status',
- 'p1_name', 'p1_pavo', 'p1_elote',
- 'p2_name', 'p2_pavo', 'p2_elote'
+ 'p1_uuid', 'p1_name', 'p1_pavo', 'p1_elote', 'p1_shame',
+ 'p2_uuid', 'p2_name', 'p2_pavo', 'p2_elote', 'p2_shame'
];
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 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[];
const p1 = players.find(p => p.role === 'P1') || players[0] || ({} as any);
const p2 = players.find(p => p.role === 'P2') || players[1] || ({} as any);
@@ -63,12 +64,16 @@ function buildCsv(): string {
variant,
round,
status,
+ p1?.uuid || '',
p1?.name || '',
p1?.pavoTokens ?? 0,
p1?.eloteTokens ?? 0,
+ p1?.shameTokens ?? 0,
+ p2?.uuid || '',
p2?.name || '',
p2?.pavoTokens ?? 0,
- p2?.eloteTokens ?? 0
+ p2?.eloteTokens ?? 0,
+ p2?.shameTokens ?? 0
].map(csvEscape).join(',');
lines.push(row);
});
@@ -76,13 +81,45 @@ function buildCsv(): string {
return lines.join('\n') + '\n';
}
-function downloadCsv() {
- const csv = buildCsv();
+function buildCsvByUuid(): string {
+ const headers = [
+ 'roomId', 'variant', 'round', 'status',
+ 'uuid', 'name', 'role', 'pavo', 'elote', 'shame'
+ ];
+ const lines: string[] = [headers.join(',')];
+
+ gameRooms.value.forEach(room => {
+ 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 => {
+ const row = [
+ room.roomId,
+ variant,
+ round,
+ status,
+ p?.uuid || '',
+ p?.name || '',
+ p?.role || '',
+ p?.pavoTokens ?? 0,
+ p?.eloteTokens ?? 0,
+ p?.shameTokens ?? 0
+ ].map(csvEscape).join(',');
+ lines.push(row);
+ });
+ });
+
+ 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);
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 fname = `snatch-results-${suffix}-${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;
@@ -91,6 +128,9 @@ function downloadCsv() {
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
+
+function downloadCsvByRoom() { triggerDownload(buildCsvByRoom(), 'by-room'); }
+function downloadCsvByUuid() { triggerDownload(buildCsvByUuid(), 'by-uuid'); }
-
diff --git a/client/src/views/Dashboard.vue b/client/src/views/Dashboard.vue
index 69fb18e..a01ba17 100644
--- a/client/src/views/Dashboard.vue
+++ b/client/src/views/Dashboard.vue
@@ -137,6 +137,7 @@
+