false, 'message' => '알 수 없는 요청입니다.']; // 월별 예약 가능일 조회 if ($action === 'get_month_availability') { $year = (int) ($_POST['year'] ?? 0); $month = (int) ($_POST['month'] ?? 0); if ($year && $month) { $start_date = date('Y-m-d', mktime(0, 0, 0, $month, 1, $year)); $end_date = date('Y-m-t', strtotime($start_date)); $max_advance_days = consultant_get_config('max_advance_days', 30); $max_date = date('Y-m-d', strtotime("+" . $max_advance_days . " days")); $sql = "SELECT specific_date, SUM(CASE WHEN is_available = 1 AND max_persons > (SELECT COUNT(*) FROM consultant_reservations r WHERE r.reservation_date = s.specific_date AND r.reservation_time = s.start_time AND r.status != 'cancelled') THEN 1 ELSE 0 END) as available_slots, MAX(CASE WHEN temp_1 = 'holiday' THEN 1 ELSE 0 END) as is_holiday FROM consultant_schedule s WHERE specific_date BETWEEN '{$start_date}' AND '{$end_date}' GROUP BY specific_date"; $result = sql_query($sql); $availability = []; while ($row = sql_fetch_array($result)) { $is_bookable = true; $reason = ''; if ($row['is_holiday']) { $is_bookable = false; $reason = 'holiday'; } elseif ($row['specific_date'] < date('Y-m-d')) { $is_bookable = false; $reason = 'past_date'; } elseif ($row['specific_date'] > $max_date) { $is_bookable = false; $reason = 'too_far'; } elseif ($row['available_slots'] == 0) { $is_bookable = false; $reason = 'full'; } $availability[date('j', strtotime($row['specific_date']))] = [ 'available' => $is_bookable, 'reason' => $reason ]; } $response = ['success' => true, 'data' => $availability]; } } // 특정일의 예약 가능 시간 조회 if ($action === 'get_time_slots') { $date = preg_replace('/[^0-9\-]/', '', $_POST['date'] ?? ''); if ($date) { $min_advance_hours = consultant_get_config('min_advance_hours', 24); $min_datetime = date('Y-m-d H:i:s', strtotime("+" . $min_advance_hours . " hours")); $sql = "SELECT s.start_time, s.max_persons, (SELECT COUNT(*) FROM consultant_reservations r WHERE r.reservation_date = s.specific_date AND r.reservation_time = s.start_time AND r.status != 'cancelled') as reserved_count FROM consultant_schedule s WHERE s.specific_date = '{$date}' AND s.is_available = 1 ORDER BY s.start_time"; $result = sql_query($sql); $slots = []; while ($row = sql_fetch_array($result)) { $slot_datetime = $date . ' ' . $row['start_time']; $is_too_soon = ($slot_datetime < $min_datetime); $available_count = $row['max_persons'] - $row['reserved_count']; $is_full = ($available_count <= 0); $slots[] = [ 'time' => substr($row['start_time'], 0, 5), 'available' => !$is_too_soon && !$is_full, 'reason' => $is_too_soon ? 'too_soon' : ($is_full ? 'full' : ''), 'reserved_count' => (int)$row['reserved_count'], 'max_persons' => (int)$row['max_persons'] ]; } $response = ['success' => true, 'data' => $slots]; } } echo json_encode($response); exit; } // 💡 [수정] 아래는 팝업의 HTML/CSS/JS 부분입니다. if (!defined('_GNUBOARD_')) exit; include_once(G5_ADMIN_PATH . '/consultant_manage/_common_con.php'); // 💡 [수정] 컴포넌트용 공통 파일 포함 $consultant_installed = is_consultant_installed(); if($consultant_installed) { // 💡 [추가] 시스템이 설치된 경우에만 팝업을 렌더링합니다. // 현재 날짜 정보 $current_year = date('Y'); $current_month_num = date('n'); // 💡 [개선] 설정 값을 DB에서 직접 가져와 일관성을 유지합니다. $consultation_fee = consultant_get_config('consultation_fee', 50000); $account_info = consultant_get_config('account_info', ''); $max_advance_days = consultant_get_config('max_advance_days', 30); // 💡 [수정] 스킨 URL 및 AJAX 엔드포인트 설정 $ajax_url = G5_ADMIN_URL . '/consultant_manage/components/reservation_popup.php'; $form_action_url = G5_ADMIN_URL . '/consultant_manage/components/reservation_submit.php'; // 💡 [추가] 리소스 목록 조회 $resources = []; $res_result = sql_query("SELECT id, name FROM consultant_resources WHERE is_active = 1 ORDER BY group_id, name"); while ($row = sql_fetch_array($res_result)) { $resources[] = $row; } ?>