false, 'message' => '알 수 없는 요청입니다.']; // 월별 예약 가능일 조회 if ($action === 'get_expert_visit_month_availability') { $year = (int) ($_POST['year'] ?? 0); $month = (int) ($_POST['month'] ?? 0); $expert_id = $_POST['expert_id'] ?? ''; // 전문가 ID 추가 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 = get_order_config('expert_visit_max_advance_days', 30); $max_date = date('Y-m-d', strtotime("+" . $max_advance_days . " days")); // 날짜별로 루프를 돌며 가용성을 체크합니다. // 쿼리 하나로 처리하기 복잡하므로, 기간 내의 모든 스케줄을 가져와서 PHP에서 병합합니다. // 1. 기간 내의 모든 '지정일' 스케줄 가져오기 $specific_schedules = []; $sql_specific = "SELECT * FROM expert_visit_schedules WHERE specific_date BETWEEN '{$start_date}' AND '{$end_date}' AND (expert_id = '{$expert_id}' OR expert_id IS NULL) ORDER BY expert_id DESC"; // 전문가 설정 우선 $res_specific = sql_query($sql_specific); while ($row = sql_fetch_array($res_specific)) { $date = $row['specific_date']; if (!isset($specific_schedules[$date])) { // 이미 전문가 설정이 있으면 공통 설정은 무시 $specific_schedules[$date] = $row; } } // 2. '요일별' 스케줄 가져오기 $weekly_schedules = []; $sql_weekly = "SELECT * FROM expert_visit_schedules WHERE day_of_week IS NOT NULL AND (expert_id = '{$expert_id}' OR expert_id IS NULL) ORDER BY expert_id DESC"; // 전문가 설정 우선 $res_weekly = sql_query($sql_weekly); while ($row = sql_fetch_array($res_weekly)) { $dow = $row['day_of_week']; if (!isset($weekly_schedules[$dow])) { $weekly_schedules[$dow] = $row; } } $availability = []; $current = strtotime($start_date); $end = strtotime($end_date); while ($current <= $end) { $date_str = date('Y-m-d', $current); $day_num = date('j', $current); $dow = date('N', $current); // 1(월) ~ 7(일) // 우선순위: 지정일 > 요일별 $schedule = $specific_schedules[$date_str] ?? ($weekly_schedules[$dow] ?? null); $is_bookable = false; $reason = ''; if (!$schedule) { $reason = 'no_schedule'; // 스케줄 없음 } elseif ($schedule['is_available'] == 0) { $reason = 'holiday'; // 휴무 } elseif ($date_str < date('Y-m-d')) { $reason = 'past_date'; // 지난 날짜 } elseif ($date_str > $max_date) { $reason = 'too_far'; // 예약 가능 기간 초과 } else { // 예약 꽉 찼는지 확인 // 해당 날짜, 해당 전문가(또는 전체)의 예약 건수 확인 // 시간대별로 체크해야 정확하지만, 여기서는 '하루 전체 마감' 여부를 대략적으로 판단하거나 // 일단 '가능'으로 표시하고 시간 선택에서 막을 수 있습니다. // 정확도를 위해 해당 날짜의 총 슬롯 수와 예약 수를 비교합니다. $start_time = strtotime($date_str . ' ' . $schedule['start_time']); $end_time = strtotime($date_str . ' ' . $schedule['end_time']); $slot_duration = $schedule['time_slot'] * 60; $total_slots = 0; for ($t = $start_time; $t < $end_time; $t += $slot_duration) { $total_slots++; } $max_capacity = $total_slots * $schedule['max_persons']; // 예약된 건수 조회 $sql_reserved = "SELECT COUNT(*) as cnt FROM expert_visit_reservations WHERE visit_date = '{$date_str}' AND status != 'cancelled'"; if ($expert_id) { $sql_reserved .= " AND expert_id = '{$expert_id}'"; } $row_reserved = sql_fetch($sql_reserved); if ($row_reserved['cnt'] >= $max_capacity) { $reason = 'full'; } else { $is_bookable = true; } } $availability[$day_num] = [ 'available' => $is_bookable, 'reason' => $reason ]; $current = strtotime('+1 day', $current); } $response = ['success' => true, 'data' => $availability]; } } // 특정일의 예약 가능 시간 조회 if ($action === 'get_expert_visit_time_slots') { $date = preg_replace('/[^0-9\-]/', '', $_POST['date'] ?? ''); $expert_id = $_POST['expert_id'] ?? ''; if ($date) { $min_advance_hours = get_order_config('expert_visit_min_advance_hours', 24); $min_datetime = date('Y-m-d H:i:s', strtotime("+" . $min_advance_hours . " hours")); $dow = date('N', strtotime($date)); // 1. 해당 날짜의 스케줄 조회 (우선순위 적용) $schedule = sql_fetch("SELECT * FROM expert_visit_schedules WHERE (specific_date = '{$date}' OR (specific_date IS NULL AND day_of_week = '{$dow}')) AND (expert_id = '{$expert_id}' OR expert_id IS NULL) ORDER BY specific_date DESC, expert_id DESC LIMIT 1"); $slots = []; if ($schedule && $schedule['is_available']) { $start_time = strtotime($date . ' ' . $schedule['start_time']); $end_time = strtotime($date . ' ' . $schedule['end_time']); $slot_duration = $schedule['time_slot'] * 60; $max_persons = $schedule['max_persons']; for ($t = $start_time; $t < $end_time; $t += $slot_duration) { $current_slot_time = date('H:i', $t); $slot_datetime = $date . ' ' . $current_slot_time; // 예약 건수 조회 $sql_reserved = "SELECT COUNT(*) as cnt FROM expert_visit_reservations WHERE visit_date = '{$date}' AND visit_time = '{$current_slot_time}:00' AND status != 'cancelled'"; if ($expert_id) { $sql_reserved .= " AND expert_id = '{$expert_id}'"; } $reserved_count = (int)sql_fetch($sql_reserved)['cnt']; $is_too_soon = ($slot_datetime < $min_datetime); $is_full = ($reserved_count >= $max_persons); $slots[] = [ 'time' => $current_slot_time, 'available' => !$is_too_soon && !$is_full, 'reason' => $is_too_soon ? 'too_soon' : ($is_full ? 'full' : ''), 'reserved_count' => $reserved_count, 'max_persons' => $max_persons ]; } } $response = ['success' => true, 'data' => $slots]; } } echo json_encode($response); exit; } if (!defined('_GNUBOARD_')) exit; include_once(G5_ADMIN_PATH . '/order_manage/_common_con.php'); include_once(G5_ADMIN_PATH . '/order_manage/lib/notification_helper.php'); $current_year = date('Y'); $current_month_num = date('n'); $visit_fee = get_order_config('expert_visit_fee', 50000); $account_info = get_order_config('expert_visit_account_info', ''); $max_advance_days = get_order_config('expert_visit_max_advance_days', 30); $ajax_url = G5_ADMIN_URL . '/order_manage/components/expert_visit_popup.php'; $form_action_url = G5_ADMIN_URL . '/order_manage/components/expert_visit_submit.php'; $css_url = G5_ADMIN_URL . '/order_manage/components/expert_visit_popup.css'; $wr_id = isset($_GET['wr_id']) ? (int)$_GET['wr_id'] : 0; // 💡 [추가] 로그인 회원 정보 가져오기 $customer_name = ''; $customer_phone = ''; $customer_email = ''; if (isset($member) && $member['mb_id']) { $customer_name = $member['mb_name']; $customer_phone = $member['mb_hp']; $customer_email = $member['mb_email']; } ?>

전문가 방문 예약

1 날짜 선택
2 시간 선택
3 정보 입력

📅 방문 날짜를 선택해주세요

최대 일 후까지 예약 가능합니다.

예약 가능
휴일
예약 마감
불가
선택