init
This commit is contained in:
@@ -0,0 +1,609 @@
|
||||
<template>
|
||||
<div class="score-management">
|
||||
<div class="header">
|
||||
<div class="meeting-info">
|
||||
<h2>{{ meetingTitle }}</h2>
|
||||
<div class="meeting-details">
|
||||
<span><i class="pi pi-calendar"></i> {{ meetingDate }}</span>
|
||||
<span><i class="pi pi-map-marker"></i> {{ meetingLocation }}</span>
|
||||
<span><i class="pi pi-users"></i> 참가자: {{ participants.length }}명</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<Button label="저장" icon="pi pi-save" @click="saveAllScores" />
|
||||
<Button label="내보내기" icon="pi pi-file-excel" class="p-button-success ml-2" @click="exportScores" />
|
||||
<Button label="뒤로" icon="pi pi-arrow-left" class="p-button-secondary ml-2" @click="goBack" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<TabView>
|
||||
<TabPanel header="점수 입력">
|
||||
<div class="filter-section mb-3">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<span class="p-input-icon-left w-full">
|
||||
<i class="pi pi-search" />
|
||||
<InputText v-model="filters.global" placeholder="이름 검색" class="w-full" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<Dropdown v-model="filters.team" :options="teamOptions" optionLabel="name"
|
||||
placeholder="팀 선택" class="w-full" />
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<MultiSelect v-model="selectedGames" :options="gameOptions" optionLabel="name"
|
||||
placeholder="게임 선택" class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DataTable :value="filteredParticipants" :paginator="true" :rows="10"
|
||||
stripedRows responsiveLayout="scroll"
|
||||
v-model:expandedRows="expandedRows">
|
||||
<Column :expander="true" headerStyle="width: 3rem" />
|
||||
<Column field="name" header="이름" sortable style="width: 15%"></Column>
|
||||
<Column field="teamNumber" header="팀" sortable style="width: 8%"></Column>
|
||||
<Column field="handicap" header="핸디캡" sortable style="width: 10%">
|
||||
<template #body="slotProps">
|
||||
<InputNumber v-model="slotProps.data.handicap"
|
||||
:min="0" :max="50"
|
||||
@blur="calculateTotal(slotProps.data)" />
|
||||
</template>
|
||||
</Column>
|
||||
<template v-for="game in gameCount" :key="game">
|
||||
<Column :field="`game${game}`" :header="`G${game}`" sortable style="width: 8%">
|
||||
<template #body="slotProps">
|
||||
<InputNumber v-model="slotProps.data[`game${game}`]"
|
||||
:min="0" :max="300"
|
||||
@blur="calculateTotal(slotProps.data)" />
|
||||
</template>
|
||||
</Column>
|
||||
</template>
|
||||
<Column field="totalPins" header="총점" sortable style="width: 10%"></Column>
|
||||
<Column field="totalWithHandicap" header="핸디포함" sortable style="width: 10%"></Column>
|
||||
<Column field="average" header="에버리지" sortable style="width: 10%"></Column>
|
||||
<template #expansion="slotProps">
|
||||
<div class="score-history p-3">
|
||||
<h4>이전 점수 기록</h4>
|
||||
<DataTable :value="slotProps.data.history" responsiveLayout="scroll">
|
||||
<Column field="date" header="날짜"></Column>
|
||||
<Column field="location" header="장소"></Column>
|
||||
<Column v-for="game in 3" :key="game" :field="`game${game}`" :header="`G${game}`"></Column>
|
||||
<Column field="average" header="에버리지"></Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
</template>
|
||||
</DataTable>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel header="팀별 점수">
|
||||
<div class="team-scores">
|
||||
<div class="grid">
|
||||
<div v-for="team in teamScores" :key="team.teamNumber" class="col-12 md:col-6 lg:col-4">
|
||||
<div class="team-card">
|
||||
<div class="team-header">
|
||||
<h3>팀 {{ team.teamNumber }}</h3>
|
||||
<div class="team-stats">
|
||||
<span>인원: {{ team.members.length }}명</span>
|
||||
<span>평균: {{ team.average.toFixed(1) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<DataTable :value="team.members" responsiveLayout="scroll">
|
||||
<Column field="name" header="이름"></Column>
|
||||
<Column v-for="game in gameCount" :key="game" :field="`game${game}`" :header="`G${game}`"></Column>
|
||||
<Column field="totalWithHandicap" header="총점"></Column>
|
||||
</DataTable>
|
||||
<div class="team-totals">
|
||||
<div class="grid">
|
||||
<div v-for="game in gameCount" :key="game" class="col">
|
||||
<div class="game-total">
|
||||
<span>G{{ game }}: {{ team.gameTotals[game-1] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="game-total total">
|
||||
<span>총점: {{ team.total }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel header="개인 순위">
|
||||
<div class="ranking-filters mb-3">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<Dropdown v-model="rankingType" :options="rankingOptions" optionLabel="name"
|
||||
placeholder="순위 유형" class="w-full" />
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<Dropdown v-model="rankingGame" :options="gameRankingOptions" optionLabel="name"
|
||||
placeholder="게임 선택" class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DataTable :value="individualRankings" :paginator="true" :rows="10"
|
||||
stripedRows responsiveLayout="scroll">
|
||||
<Column field="rank" header="순위" style="width: 8%">
|
||||
<template #body="slotProps">
|
||||
<span class="rank-badge" :class="getRankClass(slotProps.data.rank)">
|
||||
{{ slotProps.data.rank }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="name" header="이름" sortable style="width: 15%"></Column>
|
||||
<Column field="teamNumber" header="팀" sortable style="width: 8%"></Column>
|
||||
<Column field="handicap" header="핸디캡" sortable style="width: 10%"></Column>
|
||||
<Column v-if="rankingGame.code === 'all'"
|
||||
v-for="game in gameCount" :key="game"
|
||||
:field="`game${game}`" :header="`G${game}`" sortable style="width: 8%"></Column>
|
||||
<Column v-if="rankingGame.code !== 'all'"
|
||||
:field="rankingGame.code" :header="rankingGame.name" sortable style="width: 12%"></Column>
|
||||
<Column field="totalPins" header="총점" sortable style="width: 10%"></Column>
|
||||
<Column field="totalWithHandicap" header="핸디포함" sortable style="width: 10%"></Column>
|
||||
<Column field="average" header="에버리지" sortable style="width: 10%"></Column>
|
||||
</DataTable>
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel header="팀 순위">
|
||||
<DataTable :value="teamRankings" :paginator="true" :rows="10"
|
||||
stripedRows responsiveLayout="scroll">
|
||||
<Column field="rank" header="순위" style="width: 8%">
|
||||
<template #body="slotProps">
|
||||
<span class="rank-badge" :class="getRankClass(slotProps.data.rank)">
|
||||
{{ slotProps.data.rank }}
|
||||
</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="teamNumber" header="팀" style="width: 8%"></Column>
|
||||
<Column field="memberCount" header="인원" style="width: 8%"></Column>
|
||||
<Column v-for="game in gameCount" :key="game" :field="`game${game}`" :header="`G${game}`" style="width: 10%"></Column>
|
||||
<Column field="total" header="총점" style="width: 10%"></Column>
|
||||
<Column field="average" header="평균" style="width: 10%"></Column>
|
||||
</DataTable>
|
||||
</TabPanel>
|
||||
</TabView>
|
||||
</div>
|
||||
|
||||
<!-- 내보내기 다이얼로그 -->
|
||||
<Dialog v-model:visible="exportDialog" :style="{width: '450px'}"
|
||||
header="점수 내보내기" :modal="true">
|
||||
<div class="export-options">
|
||||
<div class="field">
|
||||
<label for="exportFormat">파일 형식</label>
|
||||
<Dropdown id="exportFormat" v-model="exportFormat" :options="exportFormatOptions"
|
||||
optionLabel="name" placeholder="형식 선택" class="w-full" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="exportContent">내보낼 내용</label>
|
||||
<MultiSelect id="exportContent" v-model="exportContent" :options="exportContentOptions"
|
||||
optionLabel="name" placeholder="내용 선택" class="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="취소" icon="pi pi-times" class="p-button-text" @click="exportDialog = false" />
|
||||
<Button label="내보내기" icon="pi pi-download" @click="downloadExport" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import scoreService from '@/services/scoreService';
|
||||
import meetingService from '@/services/meetingService';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const toast = useToast();
|
||||
const clubId = ref(localStorage.getItem('clubId') || null);
|
||||
|
||||
// 모임 정보
|
||||
const meetingId = ref(route.query.meetingId || null);
|
||||
const meetingTitle = ref('');
|
||||
const meetingDate = ref('');
|
||||
const meetingLocation = ref('');
|
||||
|
||||
// 점수 관련 상태
|
||||
const participants = ref([]);
|
||||
const expandedRows = ref([]);
|
||||
const gameCount = ref(3);
|
||||
const loading = ref(false);
|
||||
|
||||
// 필터 관련 상태
|
||||
const filters = reactive({
|
||||
global: '',
|
||||
team: null
|
||||
});
|
||||
|
||||
// 팀 옵션
|
||||
const teamOptions = ref([
|
||||
{ name: '전체 팀', code: null }
|
||||
]);
|
||||
|
||||
// 게임 옵션
|
||||
const gameOptions = computed(() => {
|
||||
return Array.from({ length: gameCount.value }, (_, i) => ({
|
||||
name: `게임 ${i + 1}`,
|
||||
code: `game${i + 1}`
|
||||
}));
|
||||
});
|
||||
|
||||
const selectedGames = ref([]);
|
||||
|
||||
// 순위 관련 상태
|
||||
const rankingType = ref({ name: '핸디포함', code: 'handicap' });
|
||||
const rankingOptions = ref([
|
||||
{ name: '스크래치', code: 'scratch' },
|
||||
{ name: '핸디포함', code: 'handicap' }
|
||||
]);
|
||||
|
||||
const rankingGame = ref({ name: '전체', code: 'all' });
|
||||
const gameRankingOptions = computed(() => {
|
||||
const options = [{ name: '전체', code: 'all' }];
|
||||
|
||||
for (let i = 1; i <= gameCount.value; i++) {
|
||||
options.push({ name: `게임 ${i}`, code: `game${i}` });
|
||||
}
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
// 내보내기 관련 상태
|
||||
const exportDialog = ref(false);
|
||||
const exportFormat = ref({ name: 'Excel', code: 'xlsx' });
|
||||
const exportFormatOptions = ref([
|
||||
{ name: 'Excel', code: 'xlsx' },
|
||||
{ name: 'CSV', code: 'csv' },
|
||||
{ name: 'PDF', code: 'pdf' }
|
||||
]);
|
||||
|
||||
const exportContent = ref([]);
|
||||
const exportContentOptions = ref([
|
||||
{ name: '개인 점수', code: 'individual' },
|
||||
{ name: '팀별 점수', code: 'team' },
|
||||
{ name: '개인 순위', code: 'individual_rank' },
|
||||
{ name: '팀 순위', code: 'team_rank' }
|
||||
]);
|
||||
|
||||
// 필터링된 참가자 목록
|
||||
const filteredParticipants = computed(() => {
|
||||
if (!participants.value) return [];
|
||||
|
||||
return participants.value.filter(participant => {
|
||||
// 이름 필터
|
||||
if (filters.global && !participant.name.toLowerCase().includes(filters.global.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 팀 필터
|
||||
if (filters.team && participant.teamNumber !== filters.team.code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
// 팀별 점수
|
||||
const teamScores = computed(() => {
|
||||
const teams = {};
|
||||
|
||||
// 팀별로 참가자 그룹화
|
||||
participants.value.forEach(participant => {
|
||||
const teamNumber = participant.teamNumber;
|
||||
|
||||
if (!teams[teamNumber]) {
|
||||
teams[teamNumber] = {
|
||||
teamNumber,
|
||||
members: [],
|
||||
gameTotals: Array(gameCount.value).fill(0),
|
||||
total: 0,
|
||||
average: 0
|
||||
};
|
||||
}
|
||||
|
||||
teams[teamNumber].members.push(participant);
|
||||
|
||||
// 게임별 팀 총점 계산
|
||||
for (let i = 1; i <= gameCount.value; i++) {
|
||||
const gameScore = participant[`game${i}`];
|
||||
const handicap = participant.handicap || 0;
|
||||
teams[teamNumber].gameTotals[i-1] += (gameScore + handicap);
|
||||
}
|
||||
|
||||
// 팀 총점 계산
|
||||
teams[teamNumber].total += participant.totalWithHandicap || 0;
|
||||
});
|
||||
|
||||
// 팀 평균 계산
|
||||
Object.values(teams).forEach(team => {
|
||||
if (team.members.length > 0) {
|
||||
team.average = team.total / (team.members.length * gameCount.value);
|
||||
}
|
||||
});
|
||||
|
||||
return Object.values(teams).sort((a, b) => a.teamNumber - b.teamNumber);
|
||||
});
|
||||
|
||||
// 개인 순위
|
||||
const individualRankings = computed(() => {
|
||||
if (!participants.value.length) return [];
|
||||
|
||||
const field = rankingType.value.code === 'handicap' ? 'totalWithHandicap' : 'totalPins';
|
||||
const gameField = rankingGame.value.code;
|
||||
|
||||
let sortedParticipants = [...participants.value];
|
||||
|
||||
if (gameField === 'all') {
|
||||
// 전체 게임 기준 정렬
|
||||
sortedParticipants.sort((a, b) => b[field] - a[field]);
|
||||
} else {
|
||||
// 특정 게임 기준 정렬
|
||||
sortedParticipants.sort((a, b) => {
|
||||
const scoreA = (a[gameField] || 0) + (rankingType.value.code === 'handicap' ? (a.handicap || 0) : 0);
|
||||
const scoreB = (b[gameField] || 0) + (rankingType.value.code === 'handicap' ? (b.handicap || 0) : 0);
|
||||
return scoreB - scoreA;
|
||||
});
|
||||
}
|
||||
|
||||
// 순위 부여
|
||||
return sortedParticipants.map((participant, index) => ({
|
||||
...participant,
|
||||
rank: index + 1
|
||||
}));
|
||||
});
|
||||
|
||||
// 팀 순위
|
||||
const teamRankings = computed(() => {
|
||||
if (!teamScores.value.length) return [];
|
||||
|
||||
const rankedTeams = teamScores.value.map(team => ({
|
||||
...team,
|
||||
memberCount: team.members.length,
|
||||
game1: team.gameTotals[0],
|
||||
game2: team.gameTotals[1],
|
||||
game3: team.gameTotals[2]
|
||||
}));
|
||||
|
||||
// 총점 기준 정렬
|
||||
rankedTeams.sort((a, b) => b.total - a.total);
|
||||
|
||||
// 순위 부여
|
||||
return rankedTeams.map((team, index) => ({
|
||||
...team,
|
||||
rank: index + 1
|
||||
}));
|
||||
});
|
||||
|
||||
// 순위 클래스 반환
|
||||
const getRankClass = (rank) => {
|
||||
if (rank === 1) return 'rank-first';
|
||||
if (rank === 2) return 'rank-second';
|
||||
if (rank === 3) return 'rank-third';
|
||||
return '';
|
||||
};
|
||||
|
||||
// 총점 및 에버리지 계산
|
||||
const calculateTotal = (participant) => {
|
||||
let totalPins = 0;
|
||||
let validGames = 0;
|
||||
|
||||
// 총점 계산
|
||||
for (let i = 1; i <= gameCount.value; i++) {
|
||||
const score = participant[`game${i}`];
|
||||
if (score && score > 0) {
|
||||
totalPins += score;
|
||||
validGames++;
|
||||
}
|
||||
}
|
||||
|
||||
participant.totalPins = totalPins;
|
||||
participant.totalWithHandicap = totalPins + (participant.handicap * validGames);
|
||||
participant.average = validGames > 0 ? (totalPins / validGames).toFixed(1) : 0;
|
||||
};
|
||||
|
||||
// 모든 점수 저장
|
||||
const saveAllScores = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await scoreService.saveScores(meetingId.value, participants.value);
|
||||
toast.add({ severity: 'success', summary: '성공', detail: '점수가 성공적으로 저장되었습니다.', life: 3000 });
|
||||
} catch (error) {
|
||||
console.error('점수 저장 중 오류 발생:', error);
|
||||
toast.add({ severity: 'error', summary: '오류', detail: '점수 저장 중 오류가 발생했습니다.', life: 3000 });
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 점수 내보내기 다이얼로그 열기
|
||||
const exportScores = () => {
|
||||
exportContent.value = [exportContentOptions.value[0]];
|
||||
exportDialog.value = true;
|
||||
};
|
||||
|
||||
// 점수 내보내기 다운로드
|
||||
const downloadExport = async () => {
|
||||
try {
|
||||
const format = exportFormat.value.code;
|
||||
const content = exportContent.value.map(item => item.code);
|
||||
|
||||
await scoreService.exportScores(meetingId.value, format, content);
|
||||
exportDialog.value = false;
|
||||
toast.add({ severity: 'success', summary: '성공', detail: '점수가 성공적으로 내보내졌습니다.', life: 3000 });
|
||||
} catch (error) {
|
||||
console.error('점수 내보내기 중 오류 발생:', error);
|
||||
toast.add({ severity: 'error', summary: '오류', detail: '점수 내보내기 중 오류가 발생했습니다.', life: 3000 });
|
||||
}
|
||||
};
|
||||
|
||||
// 뒤로 가기
|
||||
const goBack = () => {
|
||||
router.push('/clubs/meetings');
|
||||
};
|
||||
|
||||
// 컴포넌트 마운트 시 데이터 로드
|
||||
onMounted(async () => {
|
||||
if (!clubId.value) {
|
||||
toast.add({ severity: 'error', summary: '오류', detail: '클럽 ID가 설정되지 않았습니다.', life: 3000 });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!meetingId.value) {
|
||||
toast.add({ severity: 'error', summary: '오류', detail: '모임 ID가 설정되지 않았습니다.', life: 3000 });
|
||||
router.push('/clubs/meetings');
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
// 모임 정보 가져오기
|
||||
const meetingResponse = await meetingService.getMeetingById(meetingId.value);
|
||||
const meeting = meetingResponse.data;
|
||||
|
||||
meetingTitle.value = meeting.title;
|
||||
meetingDate.value = new Date(meeting.date).toLocaleDateString();
|
||||
meetingLocation.value = meeting.location;
|
||||
gameCount.value = meeting.gameCount || 3;
|
||||
|
||||
// 점수 데이터 가져오기
|
||||
const scoresResponse = await scoreService.getMeetingScores(meetingId.value);
|
||||
participants.value = scoresResponse.data;
|
||||
|
||||
// 팀 옵션 설정
|
||||
const teams = new Set(participants.value.map(p => p.teamNumber));
|
||||
teamOptions.value = [
|
||||
{ name: '전체 팀', code: null },
|
||||
...Array.from(teams).map(team => ({ name: `팀 ${team}`, code: team }))
|
||||
];
|
||||
|
||||
// 각 참가자의 총점 및 에버리지 계산
|
||||
participants.value.forEach(participant => {
|
||||
calculateTotal(participant);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('데이터 로드 중 오류 발생:', error);
|
||||
toast.add({ severity: 'error', summary: '오류', detail: '데이터를 로드하는 중 오류가 발생했습니다.', life: 3000 });
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.score-management {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.meeting-info h2 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.meeting-details {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.meeting-details i {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.score-history h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.team-card {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.team-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.team-header h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.team-stats {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.team-totals {
|
||||
margin-top: 1rem;
|
||||
padding-top: 0.5rem;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.game-total {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
padding: 0.5rem;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.game-total.total {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
|
||||
.rank-badge {
|
||||
display: inline-block;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.rank-first {
|
||||
background-color: #ffd700;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.rank-second {
|
||||
background-color: #c0c0c0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.rank-third {
|
||||
background-color: #cd7f32;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.export-options {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user