mejoras de codigo 2
This commit is contained in:
@@ -43,7 +43,7 @@
|
||||
class="bar-fill global shimmer"
|
||||
:style="{
|
||||
width: globalBarWidth(eventType) + '%',
|
||||
background: eventStyles[eventType]?.gradient || 'linear-gradient(90deg, #94a3b8, #64748b)'
|
||||
background: EVENT_STYLES[eventType]?.gradient || 'linear-gradient(90deg, #94a3b8, #64748b)'
|
||||
}"
|
||||
></div>
|
||||
<div
|
||||
@@ -61,7 +61,7 @@
|
||||
borderColor: getEventBorderColor(eventType)
|
||||
}"
|
||||
>
|
||||
<span class="event-icon">{{ eventStyles[eventType]?.icon || '📊' }}</span>
|
||||
<span class="event-icon">{{ EVENT_STYLES[eventType]?.icon || '📊' }}</span>
|
||||
<span class="chip-label">{{ friendlyEventName(eventType) }}</span>
|
||||
<span class="chip-count global">{{ globalValueLabel(eventType) }}</span>
|
||||
<span v-if="selectedPlayerUuid" class="chip-count player">{{ playerValueLabel(eventType) }}</span>
|
||||
@@ -94,7 +94,7 @@
|
||||
class="ratio-segment"
|
||||
:style="{
|
||||
width: group.percentages[actionIndex] + '%',
|
||||
background: eventStyles[action]?.gradient || 'linear-gradient(90deg, #94a3b8, #64748b)'
|
||||
background: EVENT_STYLES[action]?.gradient || 'linear-gradient(90deg, #94a3b8, #64748b)'
|
||||
}"
|
||||
>
|
||||
<div
|
||||
@@ -105,7 +105,7 @@
|
||||
borderColor: getEventBorderColor(action)
|
||||
}"
|
||||
>
|
||||
<span class="ratio-icon">{{ eventStyles[action]?.icon || '📊' }}</span>
|
||||
<span class="ratio-icon">{{ EVENT_STYLES[action]?.icon || '📊' }}</span>
|
||||
<span class="ratio-label">{{ group.labels[actionIndex] }}</span>
|
||||
<span class="ratio-count">{{ group.values[actionIndex] }} ({{ Math.round(group.percentages[actionIndex]) }}%)</span>
|
||||
</div>
|
||||
@@ -123,12 +123,14 @@
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
interface Props {
|
||||
eventTypes: string[];
|
||||
eventStyles: Record<string, { icon: string; color: string; gradient: string }>;
|
||||
globalEventCounts: Record<string, number>;
|
||||
playerEventCounts: Record<string, number>;
|
||||
filteredData?: {
|
||||
events: any[];
|
||||
players: any[];
|
||||
metrics: Record<string, number>;
|
||||
aggregatedCounts: Record<string, number>;
|
||||
sourceData: string;
|
||||
};
|
||||
selectedPlayerUuid?: string;
|
||||
playerBarGradient: string;
|
||||
viewMode: 'count' | 'percent' | 'ratio';
|
||||
loading?: boolean;
|
||||
filtersCollapsed?: boolean;
|
||||
@@ -140,15 +142,6 @@ interface Props {
|
||||
selectedPlayer?: string;
|
||||
selectedRoom?: string;
|
||||
};
|
||||
groupTotals?: {
|
||||
offers: number;
|
||||
responses: number;
|
||||
force: number;
|
||||
shame: number;
|
||||
report: number;
|
||||
averageScore: number;
|
||||
totalPlayers: number;
|
||||
};
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -156,51 +149,174 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
loading: false
|
||||
});
|
||||
|
||||
// Event types and styles
|
||||
const EVENTS = [
|
||||
'p1_propose', 'p1_no_offer',
|
||||
'p2_snatch', 'p2_accept', 'p2_force', 'p2_no_force', 'p2_reject',
|
||||
'p1_shame', 'p1_no_shame', 'p1_report', 'p1_no_report'
|
||||
];
|
||||
|
||||
const METRICS = [
|
||||
'players_seated', 'score_p1', 'score_p2', 'players_with_shame', 'players_without_shame'
|
||||
];
|
||||
|
||||
const ALL_CHART_TYPES = [...EVENTS, ...METRICS];
|
||||
|
||||
const EVENT_STYLES: Record<string, { icon: string; color: string; gradient: string }> = {
|
||||
'p1_propose': { icon: '✨', color: '#667eea', gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
|
||||
'p1_no_offer': { icon: '❌', color: '#6b7280', gradient: 'linear-gradient(135deg, #94a3b8 0%, #64748b 100%)' },
|
||||
'p2_accept': { icon: '✓', color: '#10b981', gradient: 'linear-gradient(135deg, #10b981 0%, #059669 100%)' },
|
||||
'p2_reject': { icon: '✕', color: '#f59e0b', gradient: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)' },
|
||||
'p2_snatch': { icon: '👹', color: '#ef4444', gradient: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)' },
|
||||
'p2_force': { icon: '⚡', color: '#667eea', gradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' },
|
||||
'p2_no_force': { icon: '🚫', color: '#6b7280', gradient: 'linear-gradient(135deg, #94a3b8 0%, #64748b 100%)' },
|
||||
'p1_shame': { icon: '😶', color: '#fbbf24', gradient: 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%)' },
|
||||
'p1_no_shame': { icon: '🙂', color: '#6b7280', gradient: 'linear-gradient(135deg, #94a3b8 0%, #64748b 100%)' },
|
||||
'p1_report': { icon: '⚖️', color: '#8b5cf6', gradient: 'linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%)' },
|
||||
'p1_no_report': { icon: '🤝', color: '#6b7280', gradient: 'linear-gradient(135deg, #94a3b8 0%, #64748b 100%)' },
|
||||
'players_seated': { icon: '👥', color: '#06b6d4', gradient: 'linear-gradient(135deg, #06b6d4 0%, #0891b2 100%)' },
|
||||
'score_p1': { icon: '🦃', color: '#16a34a', gradient: 'linear-gradient(135deg, #16a34a 0%, #15803d 100%)' },
|
||||
'score_p2': { icon: '🌽', color: '#d97706', gradient: 'linear-gradient(135deg, #d97706 0%, #b45309 100%)' },
|
||||
'players_with_shame': { icon: '😶', color: '#dc2626', gradient: 'linear-gradient(135deg, #dc2626 0%, #b91c1c 100%)' },
|
||||
'players_without_shame': { icon: '👥', color: '#06b6d4', gradient: 'linear-gradient(135deg, #06b6d4 0%, #0891b2 100%)' }
|
||||
};
|
||||
|
||||
const highlighted = ref('');
|
||||
|
||||
// Main data computations
|
||||
const eventTypes = computed(() => ALL_CHART_TYPES);
|
||||
|
||||
const globalEventCounts = computed(() => {
|
||||
if (!props.filteredData) return {};
|
||||
return {
|
||||
...props.filteredData.aggregatedCounts,
|
||||
...props.filteredData.metrics
|
||||
};
|
||||
});
|
||||
|
||||
const playerEventCounts = computed(() => {
|
||||
if (!props.selectedPlayerUuid || !props.filteredData) return {};
|
||||
|
||||
// Calculate player-specific counts from filtered events
|
||||
const playerCounts: Record<string, number> = {};
|
||||
EVENTS.forEach(eventType => {
|
||||
playerCounts[eventType] = props.filteredData!.events.filter(
|
||||
(e: any) => e.kind === eventType && e.playerUuid === props.selectedPlayerUuid
|
||||
).length;
|
||||
});
|
||||
|
||||
// Calculate player-specific metrics
|
||||
const selectedPlayer = props.filteredData.players.find((p: any) => p.uuid === props.selectedPlayerUuid);
|
||||
if (selectedPlayer) {
|
||||
let totalP1Scores = 0;
|
||||
let totalP2Scores = 0;
|
||||
let p1Count = 0;
|
||||
let p2Count = 0;
|
||||
let playersWithShame = selectedPlayer.shameTokens > 0 ? 1 : 0;
|
||||
|
||||
if (selectedPlayer.roomScoreHistory) {
|
||||
selectedPlayer.roomScoreHistory.forEach((roomScore: any) => {
|
||||
roomScore.scores.forEach((score: any) => {
|
||||
if (score.role === 'P1') {
|
||||
totalP1Scores += score.score;
|
||||
p1Count++;
|
||||
} else if (score.role === 'P2') {
|
||||
totalP2Scores += score.score;
|
||||
p2Count++;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
playerCounts.players_seated = 1;
|
||||
playerCounts.score_p1 = p1Count > 0 ? Math.round((totalP1Scores / p1Count) * 10) / 10 : 0;
|
||||
playerCounts.score_p2 = p2Count > 0 ? Math.round((totalP2Scores / p2Count) * 10) / 10 : 0;
|
||||
playerCounts.players_with_shame = playersWithShame;
|
||||
playerCounts.players_without_shame = 1 - playersWithShame;
|
||||
}
|
||||
|
||||
return playerCounts;
|
||||
});
|
||||
|
||||
const playerBarGradient = computed(() => '#8b5cf6');
|
||||
|
||||
// Group totals computation
|
||||
const groupTotals = computed(() => {
|
||||
const counts = globalEventCounts.value;
|
||||
return {
|
||||
offers: (counts.p1_propose || 0) + (counts.p1_no_offer || 0),
|
||||
responses: (counts.p2_accept || 0) + (counts.p2_reject || 0) + (counts.p2_snatch || 0),
|
||||
force: (counts.p2_force || 0) + (counts.p2_no_force || 0),
|
||||
shame: (counts.p1_shame || 0) + (counts.p1_no_shame || 0),
|
||||
report: (counts.p1_report || 0) + (counts.p1_no_report || 0),
|
||||
averageScore: calculateAverageScore(),
|
||||
totalPlayers: counts.players_seated || 0
|
||||
};
|
||||
});
|
||||
|
||||
function calculateAverageScore(): number {
|
||||
if (!props.filteredData?.players.length) return 0;
|
||||
|
||||
let totalScores = 0;
|
||||
let totalScoreCount = 0;
|
||||
|
||||
props.filteredData.players.forEach((player: any) => {
|
||||
if (player.roomScoreHistory) {
|
||||
player.roomScoreHistory.forEach((roomScore: any) => {
|
||||
roomScore.scores.forEach((score: any) => {
|
||||
totalScores += score.score;
|
||||
totalScoreCount++;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return totalScoreCount > 0 ? Math.round((totalScores / totalScoreCount) * 10) / 10 : 0;
|
||||
}
|
||||
|
||||
// Define ratio groups for superposed view
|
||||
const ratioGroups = computed(() => [
|
||||
{
|
||||
name: 'Ofertas',
|
||||
actions: ['p1_propose', 'p1_no_offer'],
|
||||
labels: ['Ofrecer', 'No Ofrecer'],
|
||||
total: props.groupTotals?.offers || 0
|
||||
total: groupTotals.value.offers
|
||||
},
|
||||
{
|
||||
name: 'Respuestas',
|
||||
actions: ['p2_accept', 'p2_reject', 'p2_snatch'],
|
||||
labels: ['Aceptar', 'Rechazar', 'Robar'],
|
||||
total: props.groupTotals?.responses || 0
|
||||
total: groupTotals.value.responses
|
||||
},
|
||||
{
|
||||
name: 'Forzar',
|
||||
actions: ['p2_force', 'p2_no_force'],
|
||||
labels: ['Forzar', 'No Forzar'],
|
||||
total: props.groupTotals?.force || 0
|
||||
total: groupTotals.value.force
|
||||
},
|
||||
{
|
||||
name: 'Avergonzar',
|
||||
actions: ['p1_shame', 'p1_no_shame'],
|
||||
labels: ['Asignar', 'No Asignar'],
|
||||
total: props.groupTotals?.shame || 0
|
||||
total: groupTotals.value.shame
|
||||
},
|
||||
{
|
||||
name: 'Denunciar',
|
||||
actions: ['p1_report', 'p1_no_report'],
|
||||
labels: ['Denunciar', 'No Denunciar'],
|
||||
total: props.groupTotals?.report || 0
|
||||
total: groupTotals.value.report
|
||||
},
|
||||
{
|
||||
name: 'Puntaje Promedio',
|
||||
actions: ['score_p1', 'score_p2'],
|
||||
labels: ['P1', 'P2'],
|
||||
total: props.groupTotals?.averageScore ? props.groupTotals.averageScore.toFixed(1) : '0.0'
|
||||
total: groupTotals.value.averageScore.toFixed(1)
|
||||
},
|
||||
{
|
||||
name: 'Total Jugadores',
|
||||
actions: ['players_with_shame', 'players_without_shame'],
|
||||
labels: ['Con vergüenza', 'Sin vergüenza'],
|
||||
total: props.groupTotals?.totalPlayers || 0,
|
||||
total: groupTotals.value.totalPlayers,
|
||||
isCustomRatio: true // Special handling needed
|
||||
}
|
||||
]);
|
||||
@@ -209,8 +325,8 @@ const ratioGroups = computed(() => [
|
||||
const ratioData = computed(() => {
|
||||
return ratioGroups.value.map(group => {
|
||||
const counts = props.selectedPlayerUuid
|
||||
? props.playerEventCounts
|
||||
: props.globalEventCounts;
|
||||
? playerEventCounts.value
|
||||
: globalEventCounts.value;
|
||||
|
||||
let values = group.actions.map(action => counts[action] || 0);
|
||||
|
||||
@@ -234,55 +350,55 @@ const ratioData = computed(() => {
|
||||
|
||||
// Global calculations
|
||||
const globalMax = computed(() => {
|
||||
const vals = props.eventTypes.map(k => props.globalEventCounts[k] || 0);
|
||||
const vals = eventTypes.value.map(k => globalEventCounts.value[k] || 0);
|
||||
const m = Math.max(0, ...vals);
|
||||
return m || 1;
|
||||
});
|
||||
|
||||
const globalTotal = computed(() =>
|
||||
props.eventTypes.reduce((acc, k) => acc + (props.globalEventCounts[k] || 0), 0) || 1
|
||||
eventTypes.value.reduce((acc, k) => acc + (globalEventCounts.value[k] || 0), 0) || 1
|
||||
);
|
||||
|
||||
function globalBarWidth(eventType: string) {
|
||||
const v = props.globalEventCounts[eventType] || 0;
|
||||
const v = globalEventCounts.value[eventType] || 0;
|
||||
return Math.round((v / (props.viewMode === 'percent' ? globalTotal.value : globalMax.value)) * 100);
|
||||
}
|
||||
|
||||
function globalValueLabel(eventType: string) {
|
||||
const v = props.globalEventCounts[eventType] || 0;
|
||||
const v = globalEventCounts.value[eventType] || 0;
|
||||
return props.viewMode === 'percent' ? `${Math.round((v / globalTotal.value) * 100)}%` : String(v);
|
||||
}
|
||||
|
||||
// Player calculations
|
||||
const playerMax = computed(() => {
|
||||
const vals = props.eventTypes.map(k => props.playerEventCounts[k] || 0);
|
||||
const vals = eventTypes.value.map(k => playerEventCounts.value[k] || 0);
|
||||
const m = Math.max(0, ...vals);
|
||||
return m || 1;
|
||||
});
|
||||
|
||||
const playerTotal = computed(() =>
|
||||
props.eventTypes.reduce((acc, k) => acc + (props.playerEventCounts[k] || 0), 0) || 1
|
||||
eventTypes.value.reduce((acc, k) => acc + (playerEventCounts.value[k] || 0), 0) || 1
|
||||
);
|
||||
|
||||
function playerBarWidth(eventType: string) {
|
||||
const v = props.playerEventCounts[eventType] || 0;
|
||||
const v = playerEventCounts.value[eventType] || 0;
|
||||
return Math.round((v / (props.viewMode === 'percent' ? playerTotal.value : playerMax.value)) * 100);
|
||||
}
|
||||
|
||||
function playerValueLabel(eventType: string) {
|
||||
const v = props.playerEventCounts[eventType] || 0;
|
||||
const v = playerEventCounts.value[eventType] || 0;
|
||||
return props.viewMode === 'percent' ? `${Math.round((v / playerTotal.value) * 100)}%` : String(v);
|
||||
}
|
||||
|
||||
// Styling helpers
|
||||
function getEventChipBg(eventType: string): string {
|
||||
const style = props.eventStyles[eventType];
|
||||
const style = EVENT_STYLES[eventType];
|
||||
if (!style) return 'rgba(255,255,255,0.82)';
|
||||
return `linear-gradient(135deg, ${style.color}15 0%, rgba(255,255,255,0.9) 100%)`;
|
||||
}
|
||||
|
||||
function getEventBorderColor(eventType: string): string {
|
||||
const style = props.eventStyles[eventType];
|
||||
const style = EVENT_STYLES[eventType];
|
||||
if (!style) return 'rgba(229,231,235,0.9)';
|
||||
return `${style.color}40`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user