<template>
<div class="container">
<div class="main-wrapper" :class="{ 'sidebar-active': isSidebarOpen }">
<Common
v-model:active-menu-item="activeMenuItem"
v-model:isSidebarOpen="isSidebarOpen"
@menu-selected="selectMenuItem"
/>
<div class="content-area">
<h1 class="page-title">내 번호 당첨 확인</h1>
<div class="lotto-check-section">
<div class="section-description">
<span class="bullet-point"></span> 번호를 입력하시면 최근 1년 이내 당첨된 모든 결과를 알려드립니다.
</div>
<div class="lotto-input-container">
<div class="lotto-number-inputs">
<input
type="text"
maxlength="2"
class="lotto-number-box"
v-for="n in 6"
:key="n"
v-model="myNumbers[n - 1]"
@input="handleNumberInput(n - 1, $event)"
@keydown="handleKeyDown(n - 1, $event)"
:ref="(el) => el && (numberInputs[n - 1] = el as HTMLInputElement)"
/>
</div>
<button class="check-result-btn" @click="checkLottoNumbers" :disabled="!allNumbersEntered">결과확인</button>
</div>
<div v-if="lottoResults.length > 0" class="lotto-results-table-container">
<h3>당첨 결과</h3>
<table class="lotto-results-table">
<thead>
<tr>
<th>회차</th>
<th>당첨일</th>
<th>당첨번호</th>
<th>보너스</th>
<th>내 번호와 일치</th>
</tr>
</thead>
<tbody>
<tr v-for="result in lottoResults" :key="result.round">
<td>{{ result.round }}</td>
<td>{{ result.date }}</td>
<td>
<span
v-for="(num, index) in result.lottoNumbers"
:key="index"
:class="{ 'matched-number': result.matchedNumbers.includes(num) }"
>
{{ num }}
</span>
</td>
<td>{{ result.bonus }}</td>
<td>{{ result.matchCount }}개</td>
</tr>
</tbody>
</table>
</div>
<div v-else-if="searchAttempted && lottoResults.length === 0" class="no-results-message">
입력하신 번호와 일치하는 당첨 기록이 없습니다.
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Common from "@/components/common/common.vue";
import { ref, onMounted, watch, computed } from "vue";
import axios from "axios";
const activeMenuItem = ref('');
const isSidebarOpen = ref(true);
const myNumbers = ref<string[]>(['', '', '', '', '', '']); // 사용자 입력 번호
const lottoResults = ref<any[]>([]); // 당첨 결과 저장
const searchAttempted = ref(false); // 검색 시도 여부
const numberInputs = ref<HTMLInputElement[]>([]); // input 요소에 접근하기 위한 ref
// 모든 번호가 입력되었는지 확인하는 computed 속성
const allNumbersEntered = computed(() => {
return myNumbers.value.every(num => num.length > 0);
});
// 메뉴 아이템 클릭 시 호출될 함수
const selectMenuItem = (menuText: string) => {
activeMenuItem.value = menuText;
};
// 번호 입력 시 다음 칸으로 자동 이동
const handleNumberInput = (index: number, event: Event) => {
const inputElement = event.target as HTMLInputElement;
let value = inputElement.value.replace(/[^0-9]/g, ''); // 숫자만 입력 받기
if (value.length > 2) {
value = value.slice(0, 2);
}
myNumbers.value[index] = value;
if (value.length === 2 && index < 5) {
const nextInput = numberInputs.value[index + 1];
if (nextInput) {
nextInput.focus();
}
}
if (index === 5 && value.length === 2) {
inputElement.blur(); // 마지막 칸 입력 후 포커스 해제
}
};
// Backspace 키 입력 시 이전 칸으로 이동 및 내용 삭제
const handleKeyDown = (index: number, event: KeyboardEvent) => {
if (event.key === 'Backspace' && myNumbers.value[index] === '' && index > 0) {
const prevInput = numberInputs.value[index - 1];
if (prevInput) {
prevInput.focus();
}
}
};
// 로또 번호 확인 함수
const checkLottoNumbers = () => {
searchAttempted.value = true; // 검색시도 여부
lottoResults.value = []; // 이전 결과 초기화
// 입력된 번호를 숫자로 변환하고 유효성 검사 (1부터 45까지, 중복 없음)
const numbers = myNumbers.value.map(Number);
const uniqueNumbers = new Set(numbers);
if (numbers.some(isNaN) || numbers.some(num => num < 1 || num > 45) || uniqueNumbers.size !== 6) {
alert("로또 번호는 1부터 45까지의 숫자 6개를 중복 없이 입력해야 합니다.");
return;
}
const requestData = {
num1: numbers[0],
num2: numbers[1],
num3: numbers[2],
num4: numbers[3],
num5: numbers[4],
num6: numbers[5]
};
/* v-model 에서 myNumbers[n - 1] 입력값 myNumbers 배열로 들어감. numbers는 my~의 값 */
axios.post('/check/check.do', requestData)
.then(response => {
const res = response.data;
if (res && res.result === 1 && Array.isArray(res.data)) {
lottoResults.value = res.data.map((item: any) => {
const lottoNumbers = [item.num1, item.num2, item.num3, item.num4, item.num5, item.num6];
const myNumbersSet = new Set(numbers);
const matchedNumbers = lottoNumbers.filter(num => myNumbersSet.has(num));
return {
round: item.round,
date: item.date,
lottoNumbers: lottoNumbers.sort((a, b) => a - b),
bonus: item.bonus,
matchedNumbers,
matchCount: matchedNumbers.length
};
});
} else if (res && res.result === 0) {
alert("입력하신 번호가 유효하지 않습니다. 다시 확인해주세요.");
} else {
alert("번호 확인 중 알 수 없는 오류가 발생했습니다.");
}
})
.catch(error => {
console.error("서버 통신 오류:", error);
alert("서버와의 통신 중 오류가 발생했습니다.");
});
};
watch(activeMenuItem, (newValue) => {
localStorage.setItem('activeMenuItem', newValue);
});
onMounted(() => {
const savedActiveMenuItem = localStorage.getItem('activeMenuItem');
if (savedActiveMenuItem) {
activeMenuItem.value = savedActiveMenuItem;
} else {
activeMenuItem.value = '내 번호 당첨확인';
}
});
</script>
<style scoped>
.content-area {
flex-grow: 1;
padding: 20px;
max-width: 900px;
margin: 0 auto;
}
.page-title {
font-size: 24px;
color: #555;
margin: 30px 0;
}
.lotto-check-section {
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
padding: 20px 30px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
.section-description {
font-size: 15px;
color: #333;
margin-bottom: 25px;
display: flex;
align-items: center;
}
.bullet-point {
display: inline-block;
width: 6px;
height: 6px;
background-color: #333;
border-radius: 50%;
margin-right: 8px;
}
.lotto-input-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
padding: 20px 0;
}
.lotto-number-inputs {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.lotto-number-box {
width: 50px;
height: 60px;
font-size: 32px;
text-align: center;
border: 1px solid #ccc;
border-radius: 5px;
outline: none;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);
transition: border-color 0.2s ease, box-shadow 0.2s ease;
-moz-appearance: textfield;
}
.lotto-number-box::-webkit-outer-spin-button,
.lotto-number-box::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.lotto-number-box:focus {
border-color: #003e80;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.check-result-btn {
background-color: #0d4785;
color: white;
padding: 12px 20px;
border: none;
font-size: 18px;
cursor: pointer;
transition: background-color 0.3s ease;
min-width: 150px;
}
.check-result-btn:hover {
background-color: #002247;
}
.lotto-results-table-container {
margin-top: 40px;
width: 100%;
}
.lotto-results-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.lotto-results-table th,
.lotto-results-table td {
border: 1px solid #eee;
padding: 12px 15px;
text-align: center;
}
.lotto-results-table th {
background-color: #f8f8f8;
font-weight: bold;
color: #555;
}
.lotto-results-table tbody tr:nth-child(even) {
background-color: #f9f9f9;
}
.lotto-results-table tbody tr:hover {
background-color: #f0f0f0;
}
.matched-number {
font-weight: bold;
color: #d9534f; /* 빨간색 계열로 강조 */
margin: 0 2px;
}
/* 당첨번호 각각에 패딩을 줘서 간격 주기 */
.lotto-results-table td:nth-child(3) span {
display: inline-block;
padding: 0 3px;
}
.no-results-message {
text-align: center;
margin-top: 30px;
font-size: 16px;
color: #777;
padding: 15px;
border: 1px dashed #ddd;
border-radius: 5px;
background-color: #fcfcfc;
}
</style>