loadTournament();
function loadTournament() {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if(xhr.readyState !== XMLHttpRequest.DONE) {
return;
}
loading.hide();
if(xhr.status < 200 || xhr.status >= 300) {
alert('알 수 없는 오류가 발생하였습니다.');
return;
}
const responseObject = JSON.parse(xhr.responseText);
const title = responseObject['tournamentTitle']; // 불러온 토너먼트 제목
let products = responseObject['products']; // 불러온 토너먼트 요소들
// 선택 부분
const playContainer = document.querySelector('.play-container');
products.sort(() => Math.random() - 0.5); // 요소를 랜덤으로 섞기
console.log(products);
tournamentTitle.innerText = title; // 제목 설정
xhr.open('GET', `/tournament/loadTournament?index=${tournamentIndex}`);
xhr.send();
loading.show();
컨트롤러 부분을 구현 후, 해당 토너먼트의 데이터를 가져온다. 그리고 랜덤으로 섞는다.
"가장 좋아하는 동물을 선택하시오"

불러온 해당 토너먼트의 요소 값들
products.sort(() => Math.random() - 0.5); // 요소를 랜덤으로 섞기
console.log(products);
tournamentTitle.innerText = title; // 제목 설정
// 맨 처음에는 데이터들을 화면에 나타내기
playContainer.insertAdjacentHTML('beforeend',
`<div class="product-box">
<div class="product-select">
<input class="productIndex1" value="0" type="hidden">
<img class="product-img" src="/tournament/productThumbnail?index=${products[0].index}" alt="">
</div>
<span class="product-name">${products[0].name}</span>
</div>
<div class="product-box">
<div class="product-select">
<input class="productIndex2" value="1" type="hidden">
<img class="product-img" src="/tournament/productThumbnail?index=${products[1].index}" alt="">
</div>
<span class="product-name">${products[1].name}</span>
</div>`);

불러온 요소들을 랜덤으로 섞은 후, 맨 처음 인덱스 0, 1번을 화면에 나타나게 한다.
<section class="select-container">
<div class="select">선택1</div>
<div class="select">선택2</div>
</section>
// 선택하는
let productSelect = document.querySelectorAll('.select');
let i = 2; // 인덱스
let count = 1; // 8일 경우 16강 완료, 12일 경우 8강 완료,
let round4 = []; // 4강에서 탈락한 요소의 인덱스
let runnerUp; // 준우승 인덱스
let champion; // 우승 인덱스
productSelect는 이미 HTML에서 만든 버튼이다. 무엇을 누르냐에 따라 선택된 요소가 바뀐다. (왼쪽이나 오른쪽이냐..)
productSelect.forEach(e => {
e.onclick = function round16() {
try {
// 왼쪽 선택시 오른쪽 데이터를 공백으로 처리, 오른쪽 역시 마찬가지
if (e.innerText === '선택1') {
let productIndex1 = document.querySelector('.productIndex1').value;
let productIndex2 = document.querySelector('.productIndex2').value;
if (count > 14) {
runnerUp = products[productIndex2].index;
champion = products[productIndex1].index;
} else if (count > 12) {
round4.push(products[productIndex2].index);
}
products[productIndex2] = ''; // 비선택된 값은 공백처리
} else if (e.innerText === '선택2') {
let productIndex1 = document.querySelector('.productIndex1').value;
let productIndex2 = document.querySelector('.productIndex2').value;
if (count > 14) {
runnerUp = products[productIndex1].index;
champion = products[productIndex2].index;
} else if (count > 12) {
round4.push(products[productIndex1].index);
}
products[productIndex1] = ''; // 비선택된 값은 공백처리
}
if (count === 8) { // 8강 시작
i = 0; // 인덱스 초기화
products = products.filter(
(e) => e !== ""
).sort(() => Math.random() - 0.5);
// 공백처리된 값 제거 후 랜덤으로
tournamentRound.innerText = '8강';
}
if (count === 12) { // 4강 시작
i = 0;
products = products.filter(
(e) => e !== ""
).sort(() => Math.random() - 0.5);
// 공백처리된 값 제거 후 랜덤으로
tournamentRound.innerText = '4강';
}
if (count === 14) { // 결승 시작
i = 0;
products = products.filter(
(e) => e !== ""
).sort(() => Math.random() - 0.5);
// 공백처리된 값 제거 후 랜덤으로
tournamentRound.innerText = '결승';
}
if (count === 15) { // 끝
playContainer.innerHTML = '';
sendResult(round4, runnerUp, champion); // 끝났으면 저장된 4강팀과 결승팀들 인덱스값을 보내는 함수 실행
}
playContainer.innerHTML = '';
playContainer.insertAdjacentHTML('beforeend',
`<div class="product-box">
<div class="product-select">
<input class="productIndex1" value="${i}" type="hidden">
<img class="product-img" src="/tournament/productThumbnail?index=${products[i].index}" alt="">
</div>
<span class="product-name">${products[i].name}</span>
</div>
<div class="product-box">
<div class="product-select">
<input class="productIndex2" value="${i+1}" type="hidden">
<img class="product-img" src="/tournament/productThumbnail?index=${products[i+1].index}" alt="">
</div>
<span class="product-name">${products[i+1].name}</span>
</div>`);
i+=2;
count++;
} catch (e) {
console.log('토너먼트 완료');
}
}
});
전체 로직이다. 나는 우선 토너먼트 요소들이 들어있는 products 배열에서 요소를 하나씩 지우는 방식으로 구현했다. 각 라운드가 진행되는 도중에, 인덱스 값이 변경되지 않도록, 비선택된 요소를 공백으로 바꾸고, 라운드 종료 시 공백이 되어버린 요소를 지우는 방식이다. 4강이 끝나고 결승이 시작되었을 시, 4강에서 탈락한 요소의 식별값인 데이터의 인덱스를 저장하고, 결승이 끝나면 준우승, 우승 데이터의 인덱스값을 저장하여, PATCH를 실행하는 함수에 전달한다.
function sendResult (round4, runnerUp, champion) {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append('round4One', round4[0]);
formData.append('round4Two', round4[1]);
formData.append('runnerUp', runnerUp);
formData.append('champion', champion);
formData.append('tournamentIndex', tournamentIndex);
xhr.onreadystatechange = function() {
if(xhr.readyState !== XMLHttpRequest.DONE) {
return;
}
if(xhr.status < 200 || xhr.status >= 300) {
alert('알 수 없는 오류가 발생하였습니다.');
return;
}
const responseObject = JSON.parse(xhr.responseText);
if (responseObject['result'] === 'failure') {
alert('토너먼트 완료 실패');
} else if (responseObject['result'] === 'success') {
location.href = `/tournament/ranking?index=${tournamentIndex}`;
}
}
xhr.open('PATCH', '/tournament/loadTournament');
xhr.send(formData);
}
각 토너먼트 요소의 db를 수정하는 컨트롤러에 해당 파라미터를 전달하였고, 그 인덱스 값을 이용하여 해당 요소의 db의 point 데이터를 변경하여, 점수를 매긴다. 우승은 10점, 준우승은 5점, 4강 탈락팀은 2점

서비스와 컨트롤러로 기능 구현 후, 토너먼트를 진행 해보았다. 맨 왼쪽의 요소들의 point 값이 변경된 걸 볼 수 있다.
'프로젝트(이상형월드컵)' 카테고리의 다른 글
| 이상형 월드컵 및 굿즈 판매 사이트 시연 영상 (0) | 2024.11.21 |
|---|---|
| 3. 페이징 (+ 검색 페이징) (0) | 2024.08.18 |
| 2. URL 파라미터 값 가져오기 (0) | 2024.06.21 |