휴일 진료 설정

This commit is contained in:
pjs
2025-12-22 23:20:02 +09:00
parent 957652682f
commit bec0b3338b
4 changed files with 1077 additions and 2640 deletions

View File

@@ -0,0 +1,470 @@
* {
box-sizing: border-box;
}
body {
font-family: 'Noto Sans KR', sans-serif;
margin: 0;
background: #fafafa;
color: #222;
height: 100vh;
display: flex;
flex-direction: column;
}
/* Main container */
.reservation-container {
display: flex;
max-width: 1280px !important;
margin: 0 auto;
gap: 20px;
height: 100%;
flex: 1;
padding: 20px 0;
margin-top: 65px;
}
.box {
background: #fff;
border-radius: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
padding: 24px 16px;
flex: 1 1 0;
min-width: 260px;
display: flex;
flex-direction: column;
height: fit-content;
min-height: 600px;
}
.step-title {
color: #b23c3c;
font-weight: 700;
font-size: 1.1em;
margin-bottom: 12px;
letter-spacing: 0.02em;
transition: color 0.3s ease;
}
.step-title.completed {
color: #008000 !important;
}
/* Service section */
.service-list {
flex: 1;
margin-bottom: 24px;
}
.service-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 1.1em;
margin-bottom: 10px;
}
.service-item .del {
cursor: pointer;
color: #b23c3c;
margin-left: 8px;
font-size: 1.2em;
transition: color 0.3s ease, opacity 0.3s ease;
}
.service-item .del:hover {
color: #ff0000;
}
.service-item .del.disabled {
color: #ccc;
cursor: not-allowed;
opacity: 0.5;
}
.service-item .del.disabled:hover {
color: #ccc;
}
.service-item .price {
font-weight: bold;
color: #b23c3c;
}
/* Service count indicator */
.service-count-info {
font-size: 0.85em;
color: #888;
margin-bottom: 8px;
text-align: center;
padding: 4px 8px;
background: #f8f9fa;
border-radius: 4px;
}
.service-count-info.single {
color: #ff8c00;
background: #fff3e0;
border: 1px solid #ffcc80;
}
.total {
border-top: 1px solid #eee;
margin-top: auto;
padding-top: 16px;
display: flex;
justify-content: space-between;
font-size: 1.1em;
font-weight: bold;
}
.total .price {
color: #b23c3c;
}
.total small {
font-weight: normal;
color: #888;
font-size: 0.9em;
margin-right: 8px;
}
/* Calendar section */
.calendar-box {
margin-bottom: 20px;
}
.calendar-header {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.calendar-header button {
background: none;
border: none;
font-size: 1.2em;
cursor: pointer;
color: #b23c3c;
padding: 0 6px;
}
.calendar-table {
width: 100%;
border-collapse: collapse;
text-align: center;
margin-bottom: 8px;
}
.calendar-table th,
.calendar-table td {
width: 2em;
height: 2em;
padding: 2px;
font-size: 1em;
border-radius: 50%;
cursor: pointer;
transition: background 0.15s;
}
.calendar-table th {
color: #b23c3c;
font-weight: 500;
background: none;
}
.calendar-table td.selected {
background: #b23c3c;
color: #fff;
}
.calendar-table td.today {
border: 1.5px solid #b23c3c;
}
.calendar-table td:not(.selected):hover {
background: #f5eaea;
}
.calendar-table td.disabled {
color: #ccc;
pointer-events: none;
background: none;
}
/* Time slots */
.time-slots {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
}
.time-btn {
flex: 1 0 30%;
min-width: 80px;
padding: 8px 0;
border: 1px solid #b23c3c;
border-radius: 20px;
background: #fff;
color: #b23c3c;
font-size: 1em;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.time-btn.selected,
.time-btn:active {
background: #b23c3c;
color: #fff;
}
.time-btn:disabled {
color: #ccc;
border-color: #eee;
background: #f5f5f5;
cursor: not-allowed;
}
.person-count {
margin-top: 12px;
font-size: 0.98em;
color: #888;
}
/* Form section */
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 4px;
font-weight: 500;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 8px 10px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 1em;
resize: none;
transition: border-color 0.3s ease;
}
.form-group textarea {
min-height: 60px;
}
.checkbox-group {
display: flex;
align-items: center;
margin-bottom: 18px;
font-size: 0.98em;
}
.checkbox-group input[type="checkbox"] {
margin-right: 8px;
accent-color: #b23c3c;
}
.submit-btn {
width: 100%;
padding: 14px 0;
background: #ddd;
color: #888;
border: none;
border-radius: 8px;
font-size: 1.1em;
font-weight: bold;
cursor: not-allowed;
transition: all 0.3s ease;
}
.submit-btn.step-progress {
background: linear-gradient(45deg, #ddd, #bbb);
color: #666;
font-size: 0.95em;
}
.submit-btn.ready {
background: #b23c3c;
color: #fff;
cursor: pointer;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.02); }
100% { transform: scale(1); }
}
/* Phone message styles (common.js PhoneValidator용) */
.phone-message {
font-size: 12px;
margin-top: 5px;
padding: 4px 8px;
border-radius: 4px;
font-weight: 500;
transition: all 0.3s ease;
}
.phone-message.error {
color: #ff0000;
background-color: #ffebee;
border: 1px solid #ffcdd2;
}
.phone-message.warning {
color: #ff8c00;
background-color: #fff3e0;
border: 1px solid #ffcc80;
}
.phone-message.success {
color: #008000;
background-color: #f1f8e9;
border: 1px solid #c8e6c9;
}
.phone-message.info {
color: #2196f3;
background-color: #e3f2fd;
border: 1px solid #90caf9;
}
/* Birth date message styles */
.birth-date-message {
font-size: 12px;
margin-top: 5px;
padding: 4px 8px;
border-radius: 4px;
font-weight: 500;
transition: all 0.3s ease;
}
.birth-date-message.error {
color: #ff0000;
background-color: #ffebee;
border: 1px solid #ffcdd2;
}
.birth-date-message.warning {
color: #ff8c00;
background-color: #fff3e0;
border: 1px solid #ffcc80;
}
.birth-date-message.success {
color: #008000;
background-color: #f1f8e9;
border: 1px solid #c8e6c9;
}
.birth-date-message.info {
color: #2196f3;
background-color: #e3f2fd;
border: 1px solid #90caf9;
}
/* Disabled calendar cell - 강화된 스타일 */
.calendar-table td.disabled {
color: #ccc;
cursor: not-allowed;
pointer-events: none;
background: none !important;
}
.calendar-table td.disabled:hover {
background: none !important;
cursor: not-allowed !important;
}
/* Responsive Design */
@media (max-width: 1199.98px) {
.reservation-container {
max-width: 960px !important;
gap: 16px;
padding: 20px 15px;
}
.box {
padding: 20px 14px;
}
}
@media (max-width: 991.98px) {
.reservation-container {
max-width: 720px !important;
flex-direction: column;
gap: 24px;
height: auto;
padding: 20px 15px;
}
.box {
min-height: unset;
min-width: unset;
}
}
@media (max-width: 767.98px) {
.reservation-container {
max-width: 540px !important;
padding: 15px;
gap: 20px;
}
.box {
padding: 16px 12px;
}
.calendar-table th,
.calendar-table td {
width: 1.8em;
height: 1.8em;
}
.time-btn {
min-width: 70px;
font-size: 0.95em;
}
}
@media (max-width: 575.98px) {
.reservation-container {
max-width: 100% !important;
padding: 10px;
gap: 16px;
}
.box {
padding: 16px 8px;
}
.calendar-table th,
.calendar-table td {
width: 1.5em;
height: 1.5em;
font-size: 0.9em;
}
.time-btn {
min-width: 60px;
font-size: 0.9em;
padding: 6px 0;
}
.step-title {
font-size: 1em;
}
.service-item {
font-size: 1em;
}
}

View File

@@ -0,0 +1,598 @@
// 휴일(완전 휴무) 설정
const disabledSpecificDates = [
'2025-12-25', // 크리스마스
'2026-01-01' // 신정
];
// 단축 진료일 (15:30까지, 점심시간 없음)
const shortWorkingDates = [
'2025-12-24', // 크리스마스 이브
'2025-12-31' // 연말
];
// 점심시간 (14:00 ~ 15:00)
const lunchTimeStart = 1400; // 14:00
const lunchTimeEnd = 1500; // 15:00
// 날짜가 휴무일인지 확인
function isDateDisabled(date) {
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
return disabledSpecificDates.includes(dateStr);
}
// 단축 근무일인지 확인
function isShortWorkingDate(date) {
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
return shortWorkingDates.includes(dateStr);
}
// 점심시간인지 확인 (월화수목금만 해당)
function isLunchTime(timeStr) {
const timeNum = parseInt(timeStr.replace(':', '')); // "14:30" -> 1430
return timeNum >= lunchTimeStart && timeNum < lunchTimeEnd;
}
// 생년월일 검증 클래스
class BirthDateValidator {
constructor(inputId, options = {}) {
this.inputElement = document.getElementById(inputId);
this.messageElement = null;
this.options = {
showMessage: true,
realTimeValidation: true,
minAge: 0,
maxAge: 150,
format: 'YYYYMMDD',
allowFuture: false,
onValidationChange: null,
...options
};
if (this.inputElement && this.options.showMessage) {
this.createMessageElement();
}
if (this.inputElement && this.options.realTimeValidation) {
this.bindEvents();
}
}
createMessageElement() {
this.messageElement = document.createElement('div');
this.messageElement.className = 'birth-date-message';
this.messageElement.style.display = 'none';
this.inputElement.parentNode.insertBefore(this.messageElement, this.inputElement.nextSibling);
}
bindEvents() {
this.inputElement.addEventListener('input', () => {
this.inputElement.value = this.inputElement.value.replace(/[^0-9]/g, '');
this.validateAndShowMessage();
});
this.inputElement.addEventListener('blur', () => {
this.validateAndShowMessage();
});
this.inputElement.addEventListener('keydown', (e) => {
if ([8, 9, 46, 37, 38, 39, 40].includes(e.keyCode)) return;
if ((e.keyCode < 48 || e.keyCode > 57) && (e.keyCode < 96 || e.keyCode > 105)) {
e.preventDefault();
}
});
}
validateBirthDate(dateStr) {
if (!dateStr) return { valid: false, message: '생년월일을 입력해주세요.' };
let cleanDate = dateStr.replace(/[^0-9]/g, '');
if (cleanDate.length !== 8) {
return { valid: false, message: '생년월일은 8자리 숫자로 입력해주세요. (예: 19900115)' };
}
const year = parseInt(cleanDate.slice(0, 4));
const month = parseInt(cleanDate.slice(4, 6));
const day = parseInt(cleanDate.slice(6, 8));
const currentYear = new Date().getFullYear();
const minYear = currentYear - this.options.maxAge;
const maxYear = currentYear - this.options.minAge;
if (year < minYear || year > maxYear) {
return { valid: false, message: `출생연도는 ${minYear}년부터 ${maxYear}년 사이여야 합니다.` };
}
if (month < 1 || month > 12) return { valid: false, message: '월은 01부터 12까지 입력 가능합니다.' };
if (day < 1 || day > 31) return { valid: false, message: '일은 01부터 31까지 입력 가능합니다.' };
const date = new Date(year, month - 1, day);
const isValidDate = date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day;
if (!isValidDate) return { valid: false, message: '존재하지 않는 날짜입니다.' };
if (!this.options.allowFuture && date > new Date()) return { valid: false, message: '미래 날짜는 입력할 수 없습니다.' };
return { valid: true, message: '올바른 생년월일입니다.' };
}
validateAndShowMessage() {
const result = this.validateBirthDate(this.inputElement.value);
if (this.messageElement) {
this.messageElement.textContent = result.message;
this.messageElement.className = `birth-date-message ${result.valid ? 'success' : 'error'}`;
this.messageElement.style.display = 'block';
}
if (typeof this.options.onValidationChange === 'function') {
this.options.onValidationChange(result, this.inputElement.value);
}
return result.valid;
}
isValid() {
return this.validateBirthDate(this.inputElement.value).valid;
}
}
// 전역 변수
let birthDateValidator;
let selectedTreatments = [];
let selectedDate = null;
let selectedTime = null;
let selectedYear, selectedMonth;
// DOM 요소
const calendarTitle = document.getElementById('calendar-title');
const calendarTable = document.getElementById('calendar-table');
const timeSlots = document.getElementById('time-slots');
const personCount = document.getElementById('person-count');
const form = document.getElementById('reserve-form');
const agree = document.getElementById('agree');
const submitBtn = document.getElementById('submit-btn');
const step02Title = document.getElementById('step02-title');
const step03Title = document.getElementById('step03-title');
// 진료시간 설정 (점심시간 제외)
const times_mon_wed_fri = [
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
"15:00","15:30","16:00","16:30","17:00","17:30","18:00","18:30"
];
const times_tue_thu = [
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
"15:00","15:30","16:00","16:30","17:00","17:30","18:00","18:30","19:00","19:30"
];
const times_sat_short = [
"10:00","10:30","11:00","11:30","12:00","12:30","13:00","13:30",
"14:00","14:30","15:00","15:30"
];
// 시술 관리 함수들
function removeService(el) {
const serviceItems = document.querySelectorAll('.service-item');
if (serviceItems.length <= 1) {
alert('최소 1개의 시술은 선택되어 있어야 합니다.');
return false;
}
const serviceName = el.closest('.service-item').querySelector('span:first-child').textContent;
if (!confirm(`'${serviceName}' 시술을 삭제하시겠습니까?`)) return false;
el.closest('.service-item').remove();
updateTotalPrice();
updateServiceCount();
return true;
}
function updateTotalPrice() {
const serviceItems = document.querySelectorAll('.service-item');
let totalPrice = 0;
serviceItems.forEach(item => {
const priceText = item.querySelector('.price').textContent;
totalPrice += parseInt(priceText.replace(/[^0-9]/g, '')) || 0;
});
document.getElementById('total-price').textContent = totalPrice.toLocaleString() + '원';
}
function updateServiceCount() {
const serviceItems = document.querySelectorAll('.service-item');
const count = serviceItems.length;
const info = document.getElementById('service-count-info');
info.textContent = `선택된 시술: ${count}${count === 1 ? ' (최소 필수)' : ''}`;
info.className = count === 1 ? 'service-count-info single' : 'service-count-info';
serviceItems.forEach(item => {
const delBtn = item.querySelector('.del');
if (count <= 1) {
delBtn.className = 'del disabled';
delBtn.title = '최소 1개의 시술은 필요합니다';
} else {
delBtn.className = 'del';
delBtn.title = '삭제';
}
});
}
// 캘린더 렌더링 (일요일 + 공휴일만 휴무)
function renderCalendar(year, month) {
selectedYear = year;
selectedMonth = month;
calendarTitle.textContent = `${year}.${String(month + 1).padStart(2, '0')}`;
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const todayDate = new Date();
todayDate.setHours(0, 0, 0, 0);
let html = '<thead><tr>';
['일','월','화','수','목','금','토'].forEach(d => html += `<th>${d}</th>`);
html += '</tr></thead><tbody><tr>';
for(let i = 0; i < firstDay.getDay(); i++) html += '<td class="disabled"></td>';
for(let d = 1; d <= lastDay.getDate(); d++) {
const dateObj = new Date(year, month, d);
let classes = [];
const isPastDate = dateObj < todayDate;
const isSunday = dateObj.getDay() === 0;
const isHoliday = isDateDisabled(dateObj);
if(dateObj.toDateString() === new Date().toDateString()) classes.push('today');
if(selectedDate && dateObj.toDateString() === selectedDate.toDateString()) classes.push('selected');
if(isPastDate || isSunday || isHoliday) classes.push('disabled');
const clickHandler = (isPastDate || isSunday || isHoliday) ?
'' : `onclick="selectDate(${year},${month},${d})"`;
html += `<td class="${classes.join(' ')}" ${clickHandler}>${d}</td>`;
if((firstDay.getDay() + d) % 7 === 0 && d !== lastDay.getDate()) html += '</tr><tr>';
}
for (let i = lastDay.getDay(); i < 6; i++) {
html += '<td class="disabled"></td>';
}
html += '</tr></tbody>';
calendarTable.innerHTML = html;
checkForm();
}
function selectDate(y, m, d) {
const tempDate = new Date(y, m, d);
const todayDate = new Date();
todayDate.setHours(0, 0, 0, 0);
if (tempDate < todayDate) {
alert('과거 날짜는 선택할 수 없습니다.');
return;
}
if (tempDate.getDay() === 0) {
alert('일요일은 휴무일입니다.');
return;
}
if (isDateDisabled(tempDate)) {
alert('해당 날짜는 휴무일입니다.');
return;
}
selectedDate = tempDate;
renderCalendar(y, m);
renderTimeSlots();
checkForm();
}
// 월 이동
document.getElementById('prev-month').onclick = function() {
selectedMonth === 0 ? (selectedYear--, selectedMonth = 11) : selectedMonth--;
renderCalendar(selectedYear, selectedMonth);
};
document.getElementById('next-month').onclick = function() {
selectedMonth === 11 ? (selectedYear++, selectedMonth = 0) : selectedMonth++;
renderCalendar(selectedYear, selectedMonth);
};
// 시간 슬롯 렌더링 (점심시간 제외 + 특수일 처리)
function renderTimeSlots() {
if (!selectedDate) {
timeSlots.innerHTML = '';
return;
}
const dayOfWeek = selectedDate.getDay();
if (dayOfWeek === 0 || isDateDisabled(selectedDate)) {
timeSlots.innerHTML = '';
return;
}
let slotArr;
if (isShortWorkingDate(selectedDate)) {
slotArr = times_sat_short; // 12/24, 12/31: 토요일과 동일
} else if ([1, 3, 5].includes(dayOfWeek)) { // 월수금
slotArr = times_mon_wed_fri;
} else if ([2, 4].includes(dayOfWeek)) { // 화목
slotArr = times_tue_thu;
} else if (dayOfWeek === 6) { // 토
slotArr = times_sat_short;
} else {
timeSlots.innerHTML = '';
return;
}
const now = new Date();
const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const isToday = selectedDate.toDateString() === todayDate.toDateString();
let html = '';
slotArr.forEach(t => {
let isDisabled = false;
if (isToday) {
const currentTime = now.getHours() * 100 + now.getMinutes();
const [hour, minute] = t.split(':').map(Number);
if (hour * 100 + minute <= currentTime) isDisabled = true;
}
const selectedClass = selectedTime === t && !isDisabled ? ' selected' : '';
const disabledAttr = isDisabled ? 'disabled' : '';
html += `<button type="button" class="time-btn${selectedClass}${isDisabled ? ' disabled' : ''}"
${isDisabled ? '' : `onclick="selectTimeAndCall('${t}', this)"`} ${disabledAttr}>${t}</button>`;
});
timeSlots.innerHTML = html;
}
function selectTimeAndCall(t, el) {
const now = new Date();
const todayDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const isToday = selectedDate.toDateString() === todayDate.toDateString();
if (isToday) {
const currentTime = now.getHours() * 100 + now.getMinutes();
const [hour, minute] = t.split(':').map(Number);
if (hour * 100 + minute <= currentTime) {
alert('지난 시간은 선택할 수 없습니다.');
return;
}
}
selectedTime = t;
renderTimeSlots();
if (el) {
document.querySelectorAll('.time-btn').forEach(btn => btn.classList.remove('active'));
el.classList.add('active');
}
onClickTime(getSelectedDateStr(), t);
checkForm();
}
function getSelectedDateStr() {
if (!selectedDate) return '';
return selectedDate.getFullYear() +
String(selectedDate.getMonth() + 1).padStart(2, '0') +
String(selectedDate.getDate()).padStart(2, '0');
}
// 폼 검증
function checkForm() {
const name = document.getElementById('customer-name').value.trim();
const phone = document.getElementById('customer-phone').value.trim();
const birthDate = document.getElementById('birthDate').value.trim();
const phoneValid = phone.match(/^01[0-9]{8,9}$/) ||
(typeof PhoneValidator !== 'undefined' && PhoneValidator.isValid?.('customer-phone'));
const birthDateValid = birthDate.match(/^\d{8}$/) ||
(birthDateValidator?.isValid?.());
const conditions = {
date: !!selectedDate,
time: !!selectedTime,
name: !!name,
phone: !!phoneValid,
birthDate: !!birthDateValid,
agree: agree.checked
};
const valid = Object.values(conditions).every(Boolean);
submitBtn.disabled = !valid;
updateStepStatus(conditions);
updateButtonText(conditions);
submitBtn.className = valid ? 'submit-btn ready' :
selectedDate ? 'submit-btn step-progress' : 'submit-btn';
}
function updateStepStatus(conditions) {
step02Title.textContent = (conditions.date && conditions.time) ? 'STEP 02. 예약 시간 선택 ✓' : 'STEP 02. 예약 시간 선택';
step02Title.className = (conditions.date && conditions.time) ? 'step-title completed' : 'step-title';
step03Title.textContent = (conditions.name && conditions.phone && conditions.birthDate && conditions.agree) ?
'STEP 03. 고객정보 ✓' : 'STEP 03. 고객정보';
step03Title.className = (conditions.name && conditions.phone && conditions.birthDate && conditions.agree) ?
'step-title completed' : 'step-title';
}
function updateButtonText(conditions) {
if (!conditions.date) return submitBtn.textContent = '📅 예약 날짜를 선택해주세요';
if (!conditions.time) return submitBtn.textContent = '⏰ 예약 시간을 선택해주세요';
if (!conditions.name) return submitBtn.textContent = '👤 고객명을 입력해주세요';
if (!conditions.birthDate) return submitBtn.textContent = '📅 생년월일을 올바르게 입력해주세요';
if (!conditions.phone) return submitBtn.textContent = '📱 연락처를 올바르게 입력해주세요';
if (!conditions.agree) return submitBtn.textContent = '✅ 개인정보 동의를 체크해주세요';
submitBtn.textContent = '🎉 시술 예약하기';
}
// 초기화
const today = new Date();
selectedYear = today.getFullYear();
selectedMonth = today.getMonth();
form.addEventListener('input', (e) => {
if (e.target.id !== 'customer-phone' && e.target.id !== 'birthDate') setTimeout(checkForm, 10);
});
agree.addEventListener('change', checkForm);
form.onsubmit = function(e) {
e.preventDefault();
if (!selectedDate || !selectedTime) {
alert('예약 날짜와 시간을 선택해 주세요.');
return;
}
if (!birthDateValidator?.isValid()) {
alert('올바른 생년월일을 입력해 주세요.');
return;
}
fn_reservation();
};
// AJAX 함수들 (기존 그대로)
function fn_reservation() {
let formData = new FormData();
if (selectedDate) {
formData.append('SELECTED_DATE', `${selectedDate.getFullYear()}-${String(selectedDate.getMonth() + 1).padStart(2, '0')}-${String(selectedDate.getDate()).padStart(2, '0')}`);
}
if (selectedTime) formData.append('TIME', selectedTime);
formData.append('CATEGORY_DIV_CD', typeof category_div_cd !== 'undefined' ? category_div_cd : '');
formData.append('CATEGORY_NO', typeof category_no !== 'undefined' ? category_no : '');
formData.append('POST_NO', typeof post_no !== 'undefined' ? post_no : '');
formData.append('NAME', document.getElementById('customer-name').value);
formData.append('BIRTH_DATE', document.getElementById('birthDate').value);
formData.append('PHONE_NUMBER', document.getElementById('customer-phone').value);
formData.append('ETC', document.getElementById('customer-req').value);
formData.append('TREATMENT_INFOS', JSON.stringify(selectedTreatments));
$.ajax({
url: encodeURI('/webservice/insertReservation.do'),
data: formData,
dataType: 'json',
processData: false,
contentType: false,
type: 'POST',
async: true,
success: function(data) {
if (data.msgCode == '0') {
alert('예약이 완료되었습니다.');
location.href = "/webevent/selectListWebEventIntro.do";
} else {
modalEvent.danger("조회 오류", data.msgDesc);
}
},
error: function() {
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
},
beforeSend: function() { $(".loading-image-layer").show(); },
complete: function() { $(".loading-image-layer").hide(); }
});
}
function fn_SelectReservation(category_div_cd, category_no, post_no, procedure_id) {
let formData = new FormData();
formData.append('CATEGORY_DIV_CD', category_div_cd);
formData.append('CATEGORY_NO', category_no);
formData.append('POST_NO', post_no);
formData.append('PROCEDURE_ID', procedure_id);
$.ajax({
url: encodeURI('/webservice/selectReservation.do'),
data: formData,
dataType: 'json',
processData: false,
contentType: false,
type: 'POST',
async: true,
success: function(data) {
if (data.msgCode == '0') {
const serviceList = document.getElementById('service-list');
serviceList.innerHTML = '';
let totalprice = 0;
selectedTreatments = [];
if (data.reservation?.length > 0) {
data.reservation.forEach(item => {
let price = item.DISCOUNT_PRICE ?? item.PRICE ?? 0;
totalprice += Number(price);
selectedTreatments.push({
MU_TREATMENT_ID: item.MU_TREATMENT_ID,
TREATMENT_NAME: item.TREATMENT_NAME,
TREATMENT_PROCEDURE_NAME: item.TREATMENT_PROCEDURE_NAME,
MU_TREATMENT_PROCEDURE_ID: item.MU_TREATMENT_PROCEDURE_ID
});
const div = document.createElement('div');
div.className = 'service-item';
div.innerHTML = `
<span>${item.TREATMENT_PROCEDURE_NAME}</span>
<span>
${item.DISCOUNT_PRICE != null ? `<span style="text-decoration:line-through; color:#bbb; font-size:0.95em; margin-right:6px;">${(item.PRICE || 0).toLocaleString()}원</span>` : ''}
<span class="price">${Number(price).toLocaleString()}원</span>
<span class="del" title="삭제" onclick="removeService(this)">×</span>
</span>
`;
serviceList.appendChild(div);
});
}
document.getElementById('total-price').textContent = totalprice.toLocaleString() + '원';
updateServiceCount();
} else {
modalEvent.danger("조회 오류", data.msgDesc);
}
},
error: function() {
modalEvent.danger("조회 오류", "조회 중 오류가 발생하였습니다. 잠시후 다시시도하십시오.");
},
beforeSend: function() { $(".loading-image-layer").show(); },
complete: function() { $(".loading-image-layer").hide(); }
});
}
function onClickTime(selectedDateStr, time) {
let formData = new FormData();
formData.append('SELECTED_DATE', selectedDateStr);
formData.append('TIME', time);
$.ajax({
url: encodeURI('/webservice/selectReservationCnt.do'),
data: formData,
dataType: 'json',
processData: false,
contentType: false,
type: 'POST',
async: true,
success: function(data) {
personCount.textContent = data.msgCode == '0' && data.rows?.RES_CNT !== undefined ?
data.rows.RES_CNT : '-';
},
error: function() {
personCount.textContent = '-';
}
});
}
// 문서 준비 완료
$(document).ready(function() {
// Validator 초기화
try {
birthDateValidator = new BirthDateValidator('birthDate', {
showMessage: true,
realTimeValidation: true,
onValidationChange: () => setTimeout(checkForm, 10)
});
} catch (e) {
console.error('BirthDateValidator init error:', e);
}
// 초기 캘린더 및 시술 로드
const today = new Date();
let initDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
while (initDate.getDay() === 0 || isDateDisabled(initDate)) {
initDate.setDate(initDate.getDate() + 1);
}
renderCalendar(today.getFullYear(), today.getMonth());
fn_SelectReservation(category_div_cd, category_no, post_no, procedure_id);
setTimeout(checkForm, 500);
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff