랭킹표시 수정

This commit is contained in:
2025-05-17 07:53:05 +09:00
parent a2b5ce88a6
commit b03f8d2d35
13 changed files with 1284 additions and 203 deletions
@@ -7,6 +7,11 @@
<div v-for="member in members" :key="member.participantId" class="member-row">
<div class="member-info-block">
<div class="member-header-row">
<span v-if="member && (member.participantId || member.id) && (memberRanksRef[member.participantId] || memberRanksRef[member.id])"
class="medal-icon-container">
<i class="pi pi-trophy medal-icon" :class="'medal-' + (memberRanksRef[member.participantId] || memberRanksRef[member.id])"></i>
<span class="medal-rank" :class="'medal-rank-' + (memberRanksRef[member.participantId] || memberRanksRef[member.id])">{{ memberRanksRef[member.participantId] || memberRanksRef[member.id] }}</span>
</span>
<span class="member-name">{{ member.name }}</span>
<Tag v-if="member.isGuest" value="G" severity="warning" class="ml-2" />
</div>
@@ -31,6 +36,14 @@
<template v-for="n in gameCount" :key="n">
<div class="score-input-hc-wrap">
<div class="score-input-status-wrap">
<!-- 상태 아이콘을 입력 필드 앞으로 이동 -->
<span class="score-status-icon-container">
<i v-if="scoreStates[member.participantId + '-' + n] === 'saving'" class="pi pi-spin pi-spinner score-status-icon" />
<i v-else-if="scoreStates[member.participantId + '-' + n] === 'saved'" class="pi pi-check score-status-icon" />
<i v-else-if="scoreStates[member.participantId + '-' + n] === 'error'" class="pi pi-times score-status-icon" />
</span>
<!-- 점수 입력 필드 -->
<InputText
v-if="canInputScore"
v-model.number="scoresProxy[member.participantId + '-' + n]"
@@ -43,29 +56,29 @@
@keydown.enter="onScoreEnter(member, n, teamNumber)"
/>
<span v-else>{{ member.scores?.[n - 1] ?? '-' }}</span>
<!-- 핸디캡 포함 점수 표시 -->
<span :class="scoreColorClass(scoreStates[member.participantId + '-' + n], scoresProxy[member.participantId + '-' + n], member.handicap)"
class="score-hc-value score-status-text"
:key="scoreStates[member.participantId + '-' + n] + '-' + scoresProxy[member.participantId + '-' + n]">
{{ (scoresProxy[member.participantId + '-' + n] !== undefined && scoresProxy[member.participantId + '-' + n] !== '') ?
Number(scoresProxy[member.participantId + '-' + n]) + (Number(member.handicap) || 0) : ''
}}
<i v-if="scoreStates[member.participantId + '-' + n] === 'saving'" class="pi pi-spin pi-spinner score-status-icon" />
<i v-else-if="scoreStates[member.participantId + '-' + n] === 'saved'" class="pi pi-check score-status-icon" />
<i v-else-if="scoreStates[member.participantId + '-' + n] === 'error'" class="pi pi-times score-status-icon" />
</span>
</div>
</div>
</template>
<div class="member-score-summary">
<span>총점: {{ getMemberTotalScore(member) }}</span>
<span class="member-score-avg">/ 에버리지: {{ getMemberAverageScore(member) }}</span>
<span class="member-score-avg">/ 평균: {{ getMemberAverageScore(member) }}</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { toRefs } from 'vue'
import { computed, onMounted, watch, ref } from 'vue';
import { calculateIndividualRankings, getRankColorClass } from '@/utils/rankingUtils';
const props = defineProps({
title: String,
members: Array,
@@ -80,6 +93,127 @@ const props = defineProps({
onScoreEnter: Function,
getMemberTotalScore: Function,
getMemberAverageScore: Function,
scoreColorClass: Function
scoreColorClass: Function,
memberRanks: Object
})
// 디버깅을 위한 코드
// 순위 데이터를 저장할 로컬 변수
const localRanks = ref({});
// 점수 변경 감지를 위한 참조 변수
const lastScores = ref({});
// 순위 계산 함수 - 순위 계산 유틸리티 사용
const updateLocalRanks = () => {
if (!props.members || props.members.length === 0) return;
// 순위 계산 유틸리티 함수 호출
const newRanks = calculateIndividualRankings(
props.members,
props.scoresProxy || {},
props.gameCount || 3
);
// 순위 맵 갱신
localRanks.value = newRanks;
// 현재 점수 저장
lastScores.value = {};
props.members.forEach(member => {
if (member && member.participantId) {
lastScores.value[member.participantId] = props.getMemberTotalScore ? props.getMemberTotalScore(member) : 0;
}
});
};
// 프록스와 로컬 데이터를 통합한 계산된 순위 객체
const memberRanksRef = computed(() => {
// 무조건 props.memberRanks 사용 - 최종 순위 테이블과 동일한 순위 표시를 위해
return props.memberRanks || {};
});
onMounted(() => {
if (props.members && props.members.length > 0) {
// props가 undefined인 경우 기본값 설정
if (!props.memberRanks) {
updateLocalRanks();
}
// 초기 점수 저장
props.members.forEach(member => {
if (member && member.participantId) {
lastScores.value[member.participantId] = props.getMemberTotalScore ? props.getMemberTotalScore(member) : 0;
}
});
}
})
// props.memberRanks 변경 감지
watch(() => props.memberRanks, (newVal) => {
}, { deep: true })
// 점수 변경 감지
watch(() => props.scoresProxy, () => {
// 점수가 변경되었는지 확인
let scoresChanged = false;
props.members.forEach(member => {
if (member && member.participantId) {
const currentScore = props.getMemberTotalScore ? props.getMemberTotalScore(member) : 0;
const previousScore = lastScores.value[member.participantId] || 0;
if (currentScore !== previousScore) {
scoresChanged = true;
}
}
});
// 점수가 변경되었으면 순위 재계산
if (scoresChanged) {
updateLocalRanks();
}
}, { deep: true })
</script>
<style scoped>
.medal-icon-container {
position: relative;
display: inline-block;
margin-right: 8px;
}
.medal-icon {
font-size: 1.8rem;
color: #eee;
}
/* 메달 색상 */
.medal-1 {
color: gold;
}
.medal-2 {
color: silver;
}
.medal-3 {
color: #cd7f32; /* 동메달 색상 */
}
.medal-rank {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -80%);
font-size: 1rem;
font-weight: bold;
color: black;
/* 글자 테두리 효과 */
text-shadow:
-1px -1px 0 rgba(255, 255, 255, 0.7),
1px -1px 0 rgba(255, 255, 255, 0.7),
-1px 1px 0 rgba(255, 255, 255, 0.7),
1px 1px 0 rgba(255, 255, 255, 0.7);
}
</style>