0) {
$stmt = $pdo->prepare("SELECT * FROM vip_customers WHERE id = ? AND is_active = 1");
$stmt->execute([$vip_id]);
$vip_customer = $stmt->fetch();
if (!$vip_customer) {
throw new Exception('选择的VIP客户无效');
}
// 使用VIP客户信息
$customer_name = $vip_customer['customer_name'];
$phone = $vip_customer['phone'];
// #region agent log
$log_data = json_encode(['location' => 'index.php:28', 'message' => 'VIP customer data', 'data' => ['vip_id' => $vip_id, 'has_car_model' => isset($vip_customer['car_model']), 'has_car_number' => isset($vip_customer['car_number'])], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'A']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
// VIP客户信息优先,但允许通过POST覆盖(如果用户想修改)
$car_model = isset($_POST['car_model']) && trim($_POST['car_model']) ? trim($_POST['car_model']) : (isset($vip_customer['car_model']) && $vip_customer['car_model'] ? $vip_customer['car_model'] : '');
$car_number = isset($_POST['car_number']) && trim($_POST['car_number']) ? trim($_POST['car_number']) : (isset($vip_customer['car_number']) && $vip_customer['car_number'] ? $vip_customer['car_number'] : '');
$member_type = 'VIP会员';
} else {
// 新客户录入
$customer_name = trim($_POST['customer_name'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$car_model = trim($_POST['car_model'] ?? '');
$car_number = trim($_POST['car_number'] ?? '');
}
$package_id = (int)($_POST['package_id'] ?? 0);
$custom_services = trim($_POST['custom_services'] ?? '');
$appointment_date = $_POST['appointment_date'] ?? '';
$appointment_time = $_POST['appointment_time'] ?? '';
$duration = (int)($_POST['duration'] ?? 60);
$notes = trim($_POST['notes'] ?? '');
// 验证member_type和source
$allowed_member_types = ['普通客户', 'VIP会员'];
$member_type = isset($_POST['member_type']) && in_array($_POST['member_type'], $allowed_member_types) ? $_POST['member_type'] : '普通客户';
$allowed_sources = ['抖音', '微信', '快手', '朋友介绍', '其他'];
$source = isset($_POST['source']) && in_array($_POST['source'], $allowed_sources) ? $_POST['source'] : '其他';
// 验证必填字段
if (empty($customer_name) || empty($phone) || empty($car_model) ||
empty($car_number) || empty($appointment_date) || empty($appointment_time)) {
throw new Exception('请填写所有必填字段');
}
// 验证VIP客户或新客户的必填字段
if ($customer_type === 'vip') {
if (empty($vip_id)) {
throw new Exception('请选择一个VIP客户');
}
} else {
if (empty($customer_name) || empty($phone)) {
throw new Exception('请填写客户姓名和联系电话');
}
}
// 验证套餐
if ($package_id) {
$stmt = $pdo->prepare("SELECT * FROM packages WHERE id = ? AND is_active = 1");
$stmt->execute([$package_id]);
$package = $stmt->fetch();
if (!$package) {
throw new Exception('选择的套餐无效');
}
$total_price = $package['price'];
} else {
throw new Exception('请选择一个套餐');
}
// 验证日期和时间格式
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $appointment_date)) {
throw new Exception('预约日期格式不正确');
}
if (!preg_match('/^\d{2}:\d{2}$/', $appointment_time)) {
throw new Exception('预约时间格式不正确');
}
// 计算预约时间范围
$start_time = $appointment_date . ' ' . $appointment_time . ':00';
$start_timestamp = strtotime($start_time);
if ($start_timestamp === false) {
throw new Exception('预约时间无效,请检查日期和时间');
}
$end_time = date('Y-m-d H:i:s', $start_timestamp + $duration * 60);
// 验证结束时间是否有效
if ($end_time === false) {
throw new Exception('计算结束时间失败');
}
// 检查时间冲突
// 两个时间段重叠的条件:现有预约的开始时间 < 新预约的结束时间 AND 现有预约的结束时间 > 新预约的开始时间
// #region agent log
$log_data = json_encode(['location' => 'index.php:98', 'message' => 'Checking time conflict', 'data' => ['start_time' => $start_time, 'end_time' => $end_time, 'duration' => $duration], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'F']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
$stmt = $pdo->prepare("SELECT COUNT(*) FROM bookings
WHERE status != '已取消'
AND start_time < ?
AND end_time > ?");
$stmt->execute([$end_time, $start_time]);
$conflict_count = $stmt->fetchColumn();
// #region agent log
$log_data = json_encode(['location' => 'index.php:107', 'message' => 'Time conflict check result', 'data' => ['conflict_count' => $conflict_count], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'F']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
if ($conflict_count > 0) {
throw new Exception('该时间段已被预约,请选择其他时间');
}
// 检查客户是否有历史预约记录,如果有则自动转为普通客户
// #region agent log
$log_data = json_encode(['location' => 'index.php:136', 'message' => 'Checking customer booking history', 'data' => ['phone' => $phone, 'car_number' => $car_number, 'current_member_type' => $member_type], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'I']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
// 检查该手机号和车牌号组合是否有历史预约记录
$stmt = $pdo->prepare("SELECT COUNT(*) FROM bookings
WHERE phone = ? AND car_number = ?");
$stmt->execute([$phone, $car_number]);
$has_booking_history = $stmt->fetchColumn() > 0;
// 如果客户有历史预约记录,自动转为普通客户(除非是VIP客户模式)
if ($has_booking_history && $member_type === 'VIP会员' && $customer_type !== 'vip') {
$member_type = '普通客户';
// #region agent log
$log_data = json_encode(['location' => 'index.php:144', 'message' => 'Auto converted to regular customer', 'data' => ['reason' => 'has_booking_history', 'phone' => $phone, 'car_number' => $car_number], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'I']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
}
// 插入预约记录
// 对于0元订单,自动标记为已付款
$payment_status = ($total_price <= 0) ? '已付款' : '未付款';
$stmt = $pdo->prepare("INSERT INTO bookings
(customer_name, phone, car_model, car_number, package_id, custom_services,
start_time, end_time, duration, total_price, notes, member_type, source, payment_status)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$customer_name, $phone, $car_model, $car_number, $package_id, $custom_services,
$start_time, $end_time, $duration, $total_price, $notes, $member_type, $source, $payment_status]);
$success_message = "预约提交成功!";
} catch (Exception $e) {
$message = $e->getMessage();
}
}
// 获取套餐列表
$stmt = $pdo->query("SELECT * FROM packages WHERE is_active = 1 ORDER BY price");
$packages = $stmt->fetchAll();
// 获取一周内的预约数据用于日历显示
$start_date = date('Y-m-d');
$end_date = date('Y-m-d', strtotime('+7 days'));
$stmt = $pdo->prepare("SELECT DATE(start_time) as date,
COUNT(*) as booking_count,
GROUP_CONCAT(
CONCAT(
TIME_FORMAT(start_time, '%H:%i'), '-',
TIME_FORMAT(end_time, '%H:%i'),
'(', status, ')'
) ORDER BY start_time SEPARATOR '
'
) as bookings
FROM bookings
WHERE DATE(start_time) BETWEEN ? AND ?
AND status NOT IN ('已完成', '已取消')
GROUP BY DATE(start_time)
ORDER BY date");
$stmt->execute([$start_date, $end_date]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 将结果转换为键值对格式(日期 => 预约数量)
$booking_schedule = [];
$booking_details = []; // 存储详细的预约信息
foreach ($results as $row) {
$booking_schedule[$row['date']] = $row['booking_count'];
$booking_details[$row['date']] = $row['bookings'];
}
// 获取具体的时间段预约信息供JavaScript使用
$stmt2 = $pdo->prepare("SELECT DATE(start_time) as date,
TIME_FORMAT(start_time, '%H:%i') as start_time,
TIME_FORMAT(end_time, '%H:%i') as end_time,
status,
customer_name,
car_model,
car_number
FROM bookings
WHERE DATE(start_time) BETWEEN ? AND ?
AND status NOT IN ('已完成', '已取消')
ORDER BY date, start_time");
$stmt2->execute([$start_date, $end_date]);
$all_bookings = $stmt2->fetchAll(PDO::FETCH_ASSOC);
// 按日期组织预约数据,处理跨天预约情况
$bookings_by_date = [];
foreach ($all_bookings as $booking) {
$booking_date = $booking['date']; // 使用不同的变量名避免覆盖外层$start_date
$booking_start_time = $booking['start_time'];
$booking_end_time = $booking['end_time'];
// 将预约添加到开始日期
$bookings_by_date[$booking_date][] = $booking;
// 检查是否是跨天预约(结束时间早于开始时间,表示跨天)
// 注意:这里比较的是时间字符串(HH:MM格式),需要转换为可比较的格式
$start_timestamp = strtotime($booking_start_time);
$end_timestamp = strtotime($booking_end_time);
// #region agent log
$log_data = json_encode(['location' => 'index.php:196', 'message' => 'Checking cross-day booking', 'data' => ['booking_date' => $booking_date, 'start_time' => $booking_start_time, 'end_time' => $booking_end_time, 'start_ts' => $start_timestamp, 'end_ts' => $end_timestamp], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'G']);
file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND);
// #endregion
if ($start_timestamp !== false && $end_timestamp !== false && $end_timestamp < $start_timestamp) {
// 计算第二天的日期
$next_date = date('Y-m-d', strtotime($booking_date . ' +1 day'));
// 创建第二天的预约记录副本
$next_day_booking = $booking;
$next_day_booking['is_cross_day'] = true; // 标记为跨天预约
// 将预约添加到第二天
$bookings_by_date[$next_date][] = $next_day_booking;
}
}
// 获取套餐信息用于JavaScript
$packages_json = json_encode(array_map(function($package) {
$package['services'] = array_filter(array_map('trim', explode(',', $package['services'])));
return $package;
}, $packages));
?>