From 905bbc5934500f84a7971cc681b52fdebe5b3f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E5=B1=95=E9=B9=8F?= Date: Fri, 12 Dec 2025 02:38:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=B9=B6=E6=94=B9=E8=BF=9B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在多个文件中添加调试日志记录功能 - 将数据库连接统一迁移到db_connect.php - 改进预约时间冲突检测逻辑 - 优化VIP客户数据处理 - 增强套餐查询的健壮性 - 更新预约状态处理流程 --- get_bookings.php | 145 +++++++++++++------------ index.php | 8 +- process_booking.php | 254 +++++++++++++++++++++++++------------------- update_booking.php | 11 +- vip.php | 14 ++- 5 files changed, 240 insertions(+), 192 deletions(-) diff --git a/get_bookings.php b/get_bookings.php index d168ca4..9a79d18 100644 --- a/get_bookings.php +++ b/get_bookings.php @@ -1,12 +1,9 @@ 0, 'completed' => 0, 'bookings' => [] - ]); + ], JSON_UNESCAPED_UNICODE); exit; } -// 创建数据库连接 -$conn = new mysqli($servername, $username, $password, $dbname); +try { + // 准备SQL查询 - 查询用户的预约记录(使用新的数据库结构) + $sql = "SELECT b.*, p.package_name + FROM bookings b + LEFT JOIN packages p ON b.package_id = p.id + WHERE b.phone = ? + ORDER BY b.start_time DESC, b.id DESC"; -// 检查连接 -if ($conn->connect_error) { + $stmt = $pdo->prepare($sql); + $stmt->execute([$phone]); + $results = $stmt->fetchAll(); + + $bookings = []; + $pending = 0; + $completed = 0; + + // 处理查询结果 + foreach ($results as $row) { + // 格式化日期和时间 + $booking_date = $row['start_time'] ? date('Y-m-d', strtotime($row['start_time'])) : ''; + $time_slot = ''; + if ($row['start_time'] && $row['end_time']) { + $start_time = date('H:i', strtotime($row['start_time'])); + $end_time = date('H:i', strtotime($row['end_time'])); + $time_slot = $start_time . '-' . $end_time; + } + + $booking = [ + 'id' => $row['id'], + 'booking_date' => $booking_date, + 'phone' => $row['phone'], + 'car_number' => $row['car_number'] ?? '', + 'car_model' => $row['car_model'] ?? '', + 'time_slot' => $time_slot, + 'status' => $row['status'] ?? '未知', + 'package_name' => $row['package_name'] ?? '', + 'notes' => $row['notes'] ?? '' + ]; + + // 统计不同状态的预约数量 + if ($booking['status'] === '待确认' || $booking['status'] === '已确认' || $booking['status'] === '进行中') { + $pending++; + } elseif ($booking['status'] === '已完成') { + $completed++; + } + + $bookings[] = $booking; + } + + // 计算总预约数 + $total = count($bookings); + + // 构建响应数据 + $response = [ + 'success' => true, + 'total' => $total, + 'pending' => $pending, + 'completed' => $completed, + 'bookings' => $bookings + ]; + + // 返回JSON数据 + echo json_encode($response, JSON_UNESCAPED_UNICODE); + +} catch (Exception $e) { echo json_encode([ 'success' => false, - 'message' => '数据库连接失败', + 'message' => '查询失败:' . $e->getMessage(), 'total' => 0, 'pending' => 0, 'completed' => 0, 'bookings' => [] - ]); - exit; + ], JSON_UNESCAPED_UNICODE); } - -// 准备SQL查询 - 查询用户的预约记录 -// 假设预约表名为bookings,套餐表名为packages -$sql = "SELECT b.*, p.package_name - FROM bookings b - LEFT JOIN packages p ON b.package_id = p.id - WHERE b.phone = ? - ORDER BY b.booking_date DESC, b.id DESC"; - -$stmt = $conn->prepare($sql); -$stmt->bind_param("s", $phone); -$stmt->execute(); -$result = $stmt->get_result(); - -$bookings = []; -$pending = 0; -$completed = 0; - -// 处理查询结果 -while ($row = $result->fetch_assoc()) { - $booking = [ - 'id' => $row['id'], - 'booking_date' => $row['booking_date'], - 'phone' => $row['phone'], - 'car_number' => $row['car_number'] ?? '', - 'car_model' => $row['car_model'] ?? '', - 'time_slot' => $row['time_slot'] ?? '', - 'status' => $row['status'] ?? '未知', - 'package_name' => $row['package_name'] ?? '', - 'notes' => $row['notes'] ?? '' - ]; - - // 统计不同状态的预约数量 - if ($booking['status'] === '待服务') { - $pending++; - } elseif ($booking['status'] === '已完成') { - $completed++; - } - - $bookings[] = $booking; -} - -// 计算总预约数 -$total = count($bookings); - -// 构建响应数据 -$response = [ - 'success' => true, - 'total' => $total, - 'pending' => $pending, - 'completed' => $completed, - 'bookings' => $bookings -]; - -// 返回JSON数据 -echo json_encode($response); - -// 关闭数据库连接 -$stmt->close(); -$conn->close(); +?> diff --git a/index.php b/index.php index 1ef8494..f4c4db1 100644 --- a/index.php +++ b/index.php @@ -25,8 +25,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 使用VIP客户信息 $customer_name = $vip_customer['customer_name']; $phone = $vip_customer['phone']; - $car_model = $vip_customer['car_model'] ?: $car_model; // 允许覆盖 - $car_number = $vip_customer['car_number'] ?: $car_number; // 允许覆盖 + // #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 + $car_model = isset($vip_customer['car_model']) && $vip_customer['car_model'] ? $vip_customer['car_model'] : ''; // 允许覆盖 + $car_number = isset($vip_customer['car_number']) && $vip_customer['car_number'] ? $vip_customer['car_number'] : ''; // 允许覆盖 $member_type = 'VIP会员'; } else { // 新客户录入 diff --git a/process_booking.php b/process_booking.php index f167d7e..7e428b0 100644 --- a/process_booking.php +++ b/process_booking.php @@ -1,111 +1,145 @@ 'process_booking.php:3', 'message' => 'Database connection check', 'data' => ['has_pdo' => isset($pdo), 'using_db_connect' => true], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'D']); +file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND); +// #endregion // 检查表单提交 if ($_SERVER['REQUEST_METHOD'] === 'POST') { - // 获取表单数据 - $customer_name = $_POST['customer_name'] ?? ''; - $phone = $_POST['phone'] ?? ''; - $car_model = $_POST['car_model'] ?? ''; - $car_number = $_POST['car_number'] ?? ''; - $booking_date = $_POST['booking_date'] ?? ''; - $time_slot = $_POST['time_slot'] ?? ''; - $package_id = $_POST['package_id'] ?? ''; - $notes = $_POST['notes'] ?? ''; - $source = $_POST['source'] ?? ''; // 来源标识,用于确定返回页面 - - // 验证必填字段 - $errors = []; - - if (empty($customer_name)) { - $errors[] = '请输入客户姓名'; - } - - if (empty($phone)) { - $errors[] = '请输入手机号码'; - } elseif (!preg_match('/^1[3-9]\d{9}$/', $phone)) { - $errors[] = '请输入正确的手机号码'; - } - - if (empty($car_number)) { - $errors[] = '请输入车牌号'; - } - - if (empty($booking_date)) { - $errors[] = '请选择预约日期'; - } - - if (empty($time_slot)) { - $errors[] = '请选择预约时间'; - } - - if (empty($package_id)) { - $errors[] = '请选择洗车套餐'; - } - - // 验证日期是否为过去 - $current_date = date('Y-m-d'); - if ($booking_date < $current_date) { - $errors[] = '不能选择过去的日期'; - } - - // 如果有错误,返回错误信息 - if (!empty($errors)) { - $error_message = implode('\n', $errors); - echo ""; - exit; - } - - // 创建数据库连接 - $conn = new mysqli($servername, $username, $password, $dbname); - - // 检查连接 - if ($conn->connect_error) { - echo ""; - exit; - } - - // 检查是否已经存在相同的预约(同一天、同一时间段、同一车牌号) - $check_sql = "SELECT * FROM bookings - WHERE booking_date = ? AND time_slot = ? AND car_number = ? AND status != '已取消'"; - $check_stmt = $conn->prepare($check_sql); - $check_stmt->bind_param("sss", $booking_date, $time_slot, $car_number); - $check_stmt->execute(); - $check_result = $check_stmt->get_result(); - - if ($check_result->num_rows > 0) { - echo ""; - $check_stmt->close(); - $conn->close(); - exit; - } - $check_stmt->close(); - - // 插入预约记录 - $status = '待服务'; // 默认为待服务状态 - $create_time = date('Y-m-d H:i:s'); - - $insert_sql = "INSERT INTO bookings - (customer_name, phone, car_model, car_number, booking_date, time_slot, package_id, notes, status, create_time) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - - $stmt = $conn->prepare($insert_sql); - $stmt->bind_param("ssssssssss", $customer_name, $phone, $car_model, $car_number, $booking_date, $time_slot, $package_id, $notes, $status, $create_time); - - if ($stmt->execute()) { + try { + // 获取表单数据 + $customer_name = $_POST['customer_name'] ?? ''; + $phone = $_POST['phone'] ?? ''; + $car_model = $_POST['car_model'] ?? ''; + $car_number = $_POST['car_number'] ?? ''; + $booking_date = $_POST['booking_date'] ?? ''; + $time_slot = $_POST['time_slot'] ?? ''; + $package_id = $_POST['package_id'] ?? ''; + $notes = $_POST['notes'] ?? ''; + $source = $_POST['source'] ?? '其他'; // 来源标识,用于确定返回页面 + $duration = isset($_POST['duration']) ? (int)$_POST['duration'] : 60; // 默认60分钟 + $total_price = isset($_POST['total_price']) ? (float)$_POST['total_price'] : 0; + + // 验证必填字段 + if (empty($customer_name)) { + throw new Exception('请输入客户姓名'); + } + + if (empty($phone)) { + throw new Exception('请输入手机号码'); + } elseif (!preg_match('/^1[3-9]\d{9}$/', $phone)) { + throw new Exception('请输入正确的手机号码'); + } + + if (empty($car_number)) { + throw new Exception('请输入车牌号'); + } + + if (empty($booking_date)) { + throw new Exception('请选择预约日期'); + } + + if (empty($time_slot)) { + throw new Exception('请选择预约时间'); + } + + if (empty($package_id)) { + throw new Exception('请选择洗车套餐'); + } + + // 验证日期是否为过去 + $current_date = date('Y-m-d'); + if ($booking_date < $current_date) { + throw new Exception('不能选择过去的日期'); + } + + // 解析时间段,转换为start_time和end_time + // time_slot格式可能是 "09:00-10:00" 或 "09:00" + $start_time_str = ''; + $end_time_str = ''; + + if (strpos($time_slot, '-') !== false) { + // 格式:09:00-10:00 + list($start_time_str, $end_time_str) = explode('-', $time_slot); + $start_time = $booking_date . ' ' . trim($start_time_str) . ':00'; + $end_time = $booking_date . ' ' . trim($end_time_str) . ':00'; + } else { + // 格式:09:00,使用默认时长 + $start_time = $booking_date . ' ' . trim($time_slot) . ':00'; + $end_time = date('Y-m-d H:i:s', strtotime($start_time) + $duration * 60); + } + + // #region agent log + $log_data = json_encode(['location' => 'process_booking.php:70', 'message' => 'Time conversion', 'data' => ['booking_date' => $booking_date, 'time_slot' => $time_slot, 'start_time' => $start_time, 'end_time' => $end_time, 'duration' => $duration], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'E']); + file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND); + // #endregion + + // 获取套餐信息以获取价格和默认时长 + $stmt = $pdo->prepare("SELECT * FROM packages WHERE id = ? AND is_active = 1"); + $stmt->execute([$package_id]); + $package = $stmt->fetch(); + + if (!$package) { + throw new Exception('选择的套餐无效'); + } + + // 如果未提供价格,使用套餐价格 + if ($total_price <= 0) { + $total_price = $package['price']; + } + + // 如果未提供时长,使用套餐默认时长 + if ($duration <= 0) { + $duration = $package['base_duration']; + // 重新计算结束时间 + $end_time = date('Y-m-d H:i:s', strtotime($start_time) + $duration * 60); + } + + // 检查时间冲突 + $stmt = $pdo->prepare("SELECT COUNT(*) FROM bookings + WHERE status != '已取消' + AND ( + (start_time <= ? AND end_time > ?) + OR (start_time < ? AND end_time >= ?) + OR (start_time >= ? AND end_time <= ?) + )"); + $stmt->execute([$start_time, $start_time, $end_time, $end_time, $start_time, $end_time]); + + if ($stmt->fetchColumn() > 0) { + throw new Exception('该时间段已被预约,请选择其他时间'); + } + + // 对于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, status) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + + $member_type = '普通客户'; // 默认普通客户,VIP客户应该通过index.php添加 + + $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, + '待确认' // status + ]); + // 预约成功 $success_message = '预约添加成功!'; @@ -116,19 +150,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { alert('$success_message'); window.location.href = '$redirect_url'; "; - } else { - // 预约失败 + + } catch (Exception $e) { + $error_message = $e->getMessage(); echo ""; } - - // 关闭数据库连接 - $stmt->close(); - $conn->close(); } else { // 不是POST请求,重定向到首页 header('Location: index.php'); exit; } +?> diff --git a/update_booking.php b/update_booking.php index 038f7b4..d964a09 100644 --- a/update_booking.php +++ b/update_booking.php @@ -62,7 +62,16 @@ try { } // 计算新的持续时间(分钟) - $duration = $start_dt->diff($end_dt)->i + ($start_dt->diff($end_dt)->h * 60); + // #region agent log + $log_data = json_encode(['location' => 'update_booking.php:65', 'message' => 'Calculating duration', 'data' => ['start_time' => $new_start_time, 'end_time' => $new_end_time], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'C']); + file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND); + // #endregion + $interval = $start_dt->diff($end_dt); + $duration = ($interval->days * 24 * 60) + ($interval->h * 60) + $interval->i; + // #region agent log + $log_data = json_encode(['location' => 'update_booking.php:67', 'message' => 'Duration calculated', 'data' => ['duration' => $duration, 'days' => $interval->days, 'hours' => $interval->h, 'minutes' => $interval->i], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'C']); + file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND); + // #endregion // 更新预约时间和持续时间 $stmt = $pdo->prepare("UPDATE bookings SET start_time = ?, end_time = ?, duration = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?"); diff --git a/vip.php b/vip.php index 076d1fd..22adb4b 100644 --- a/vip.php +++ b/vip.php @@ -414,13 +414,19 @@ try { query("SELECT id, package_name, price FROM packages ORDER BY price ASC"); - if ($package_result && $package_result->num_rows > 0) { - while ($package = $package_result->fetch_assoc()) { + // #region agent log + $log_data = json_encode(['location' => 'vip.php:417', 'message' => 'Loading packages', 'data' => ['using_pdo' => isset($pdo), 'using_conn' => isset($conn)], 'timestamp' => time() * 1000, 'sessionId' => 'debug-session', 'runId' => 'run1', 'hypothesisId' => 'B']); + file_put_contents('.cursor/debug.log', $log_data . "\n", FILE_APPEND); + // #endregion + try { + $stmt = $pdo->query("SELECT id, package_name, price FROM packages WHERE is_active = 1 ORDER BY price ASC"); + $packages = $stmt->fetchAll(); + foreach ($packages as $package) { echo ""; } + } catch (Exception $e) { + echo ""; } - $package_result->free_result(); ?>