c64651d6c7
refactor(预约统计): 修改查询逻辑只计算有效预约
868 lines
39 KiB
PHP
868 lines
39 KiB
PHP
<?php
|
|
// bookings.php - 预约列表页面
|
|
require_once 'db_connect.php';
|
|
|
|
// 处理状态更新
|
|
if (isset($_POST['action']) && isset($_POST['booking_id'])) {
|
|
$booking_id = $_POST['booking_id'];
|
|
$action = $_POST['action'];
|
|
|
|
try {
|
|
if (in_array($action, ['已确认', '已完成', '已取消'])) {
|
|
// 更新预约状态
|
|
$stmt = $pdo->prepare("UPDATE bookings SET status = ? WHERE id = ?");
|
|
$stmt->execute([$action, $booking_id]);
|
|
$success_message = '预约状态更新成功!';
|
|
} elseif (in_array($action, ['已付款', '未付款'])) {
|
|
// 更新付款状态
|
|
$stmt = $pdo->prepare("UPDATE bookings SET payment_status = ? WHERE id = ?");
|
|
$stmt->execute([$action, $booking_id]);
|
|
$success_message = '付款状态更新成功!';
|
|
} elseif ($action == 'update_time' && isset($_POST['new_start_time']) && isset($_POST['new_end_time'])) {
|
|
// 更新预约时间
|
|
$new_start_time = $_POST['new_start_time'];
|
|
$new_end_time = $_POST['new_end_time'];
|
|
$stmt = $pdo->prepare("UPDATE bookings SET start_time = ?, end_time = ? WHERE id = ?");
|
|
$stmt->execute([$new_start_time, $new_end_time, $booking_id]);
|
|
$success_message = '预约时间更新成功!';
|
|
} elseif ($action == 'update_notes' && isset($_POST['notes_content'])) {
|
|
// 更新客服备注
|
|
$notes_content = $_POST['notes_content'];
|
|
$stmt = $pdo->prepare("UPDATE bookings SET custom_services = ? WHERE id = ?");
|
|
$stmt->execute([$notes_content, $booking_id]);
|
|
echo 'success';
|
|
exit();
|
|
}
|
|
} catch (Exception $e) {
|
|
$error_message = '更新失败:' . $e->getMessage();
|
|
}
|
|
}
|
|
|
|
// 获取所有预约,支持状态筛选和搜索功能
|
|
try {
|
|
// 构建查询,支持筛选和搜索
|
|
$query = "SELECT b.*, p.package_name, p.package_reminder FROM bookings b LEFT JOIN packages p ON b.package_id = p.id WHERE 1=1 ";
|
|
$params = [];
|
|
|
|
// 状态筛选
|
|
if (isset($_GET['status']) && !empty($_GET['status'])) {
|
|
$query .= " AND b.status = ?";
|
|
$params[] = $_GET['status'];
|
|
} else if (!isset($_GET['search']) || empty($_GET['search'])) {
|
|
// 默认为只显示未完成订单,但如果有搜索条件则显示所有订单
|
|
$query .= " AND b.status NOT IN ('已完成', '已取消')";
|
|
}
|
|
|
|
// 搜索功能
|
|
if (isset($_GET['search']) && !empty($_GET['search'])) {
|
|
$searchTerm = '%' . $_GET['search'] . '%';
|
|
$query .= " AND (b.phone LIKE ? OR b.car_number LIKE ?)";
|
|
$params[] = $searchTerm;
|
|
$params[] = $searchTerm;
|
|
}
|
|
|
|
$query .= " ORDER BY b.start_time DESC";
|
|
|
|
$stmt = $pdo->prepare($query);
|
|
$stmt->execute($params);
|
|
$bookings = $stmt->fetchAll();
|
|
} catch (Exception $e) {
|
|
$error_message = '获取预约列表失败:' . $e->getMessage();
|
|
$bookings = [];
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="format-detection" content="telephone=no">
|
|
<meta name="description" content="洗车预约管理列表,查看和管理所有预约记录">
|
|
<meta name="keywords" content="预约管理,洗车预约,预约列表">
|
|
<title>张老师撸车(私家车库)工作室</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
<script src="mobile-nav.js" defer></script>
|
|
|
|
<!-- Favicon for mobile devices -->
|
|
<link rel="apple-touch-icon" sizes="180x180" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚗</text></svg>">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<header class="header">
|
|
<button class="mobile-menu-toggle" onclick="toggleMobileMenu()" aria-label="菜单">
|
|
<span></span>
|
|
<span></span>
|
|
<span></span>
|
|
</button>
|
|
<h1>🚗 张老师撸车工作室 - 预约管理</h1>
|
|
<nav class="nav">
|
|
<a href="index.php" class="nav-link">预约洗车</a>
|
|
<a href="bookings.php" class="nav-link active">预约管理</a>
|
|
<a href="pending_bookings.php" class="nav-link">待处理预约</a>
|
|
<a href="packages.php" class="nav-link">套餐管理</a>
|
|
<a href="vip.php" class="nav-link">VIP管理</a>
|
|
<a href="announcement.php" class="nav-link">今日待办</a>
|
|
</nav>
|
|
</header>
|
|
|
|
<!-- 移动端导航菜单 -->
|
|
<div class="mobile-nav-overlay" onclick="closeMobileMenu()"></div>
|
|
<nav class="mobile-nav">
|
|
<a href="index.php" class="nav-link">预约洗车</a>
|
|
<a href="bookings.php" class="nav-link active">预约管理</a>
|
|
<a href="pending_bookings.php" class="nav-link">待处理预约</a>
|
|
<a href="packages.php" class="nav-link">套餐管理</a>
|
|
<a href="vip.php" class="nav-link">VIP管理</a>
|
|
<a href="announcement.php" class="nav-link">今日待办</a>
|
|
</nav>
|
|
|
|
<?php if (isset($success_message)): ?>
|
|
<div class="success-message"><?php echo $success_message; ?></div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (isset($error_message)): ?>
|
|
<div class="error-message">
|
|
<?php echo $error_message; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card">
|
|
<h2>所有预约 (共 <?php echo count($bookings); ?> 条)</h2>
|
|
|
|
<!-- 筛选和搜索区域 -->
|
|
<div class="filter-search-area">
|
|
<form method="GET" class="filter-form">
|
|
<div class="filter-group">
|
|
<label for="status_filter">状态筛选:</label>
|
|
<select id="status_filter" name="status" class="filter-select">
|
|
<option value="">显示所有订单</option>
|
|
<option value="待确认" <?php echo isset($_GET['status']) && $_GET['status'] == '待确认' ? 'selected' : ''; ?>>待确认</option>
|
|
<option value="已确认" <?php echo isset($_GET['status']) && $_GET['status'] == '已确认' ? 'selected' : ''; ?>>已确认</option>
|
|
<option value="已完成" <?php echo isset($_GET['status']) && $_GET['status'] == '已完成' ? 'selected' : ''; ?>>已完成</option>
|
|
<option value="已取消" <?php echo isset($_GET['status']) && $_GET['status'] == '已取消' ? 'selected' : ''; ?>>已取消</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="search-group">
|
|
<label for="search_term">搜索:</label>
|
|
<input type="text" id="search_term" name="search" placeholder="手机号或车牌号"
|
|
value="<?php echo isset($_GET['search']) ? htmlspecialchars($_GET['search']) : ''; ?>">
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-sm btn-primary filter-submit">应用筛选</button>
|
|
<a href="bookings.php" class="btn btn-sm btn-secondary">重置筛选</a>
|
|
</form>
|
|
</div>
|
|
|
|
<?php if (empty($bookings)): ?>
|
|
<div class="empty-message">暂无预约记录</div>
|
|
<?php else: ?>
|
|
<?php foreach ($bookings as $booking): ?>
|
|
<div class="package-card">
|
|
<div class="package-header">
|
|
<h3><?php echo htmlspecialchars($booking['customer_name']); ?> 的预约</h3>
|
|
<div class="package-status">
|
|
<span class="status-badge <?php
|
|
echo $booking['status'] === '待确认' ? 'pending' :
|
|
($booking['status'] === '已确认' ? 'active' :
|
|
($booking['status'] === '已完成' ? 'active' : 'inactive'));
|
|
?>">
|
|
<?php echo $booking['status']; ?>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="package-details">
|
|
<div class="detail-item">
|
|
<span class="detail-label">联系方式:</span>
|
|
<span class="detail-value"><?php echo htmlspecialchars($booking['phone']); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">车型:</span>
|
|
<span class="detail-value"><?php echo htmlspecialchars($booking['car_model']); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">车牌号:</span>
|
|
<span class="detail-value"><?php echo htmlspecialchars($booking['car_number']); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">服务套餐:</span>
|
|
<span class="detail-value"><?php echo htmlspecialchars($booking['package_name'] ?? '未选择套餐'); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">预约日期:</span>
|
|
<span class="detail-value"><?php echo date('Y-m-d', strtotime($booking['start_time'])); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">预约时间:</span>
|
|
<span class="detail-value"><?php echo date('H:i', strtotime($booking['start_time'])); ?> - <?php echo date('H:i', strtotime($booking['end_time'])); ?></span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">付款状态:</span>
|
|
<span class="detail-value">
|
|
<span class="payment-status <?php echo $booking['payment_status'] === '已付款' ? 'paid' : 'unpaid'; ?>">
|
|
<?php echo $booking['payment_status'] === '已付款' ? '💰 已付款' : '💳 未付款'; ?>
|
|
</span>
|
|
</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">会员类型:</span>
|
|
<span class="detail-value">
|
|
<?php if ($booking['member_type'] === 'VIP会员'): ?>
|
|
<span style="color: #ffd700; font-weight: bold;">👑 VIP会员</span>
|
|
<?php else: ?>
|
|
<span style="color: #666;">普通客户</span>
|
|
<?php endif; ?>
|
|
</span>
|
|
</div>
|
|
<div class="detail-item">
|
|
<span class="detail-label">客户来源:</span>
|
|
<span class="detail-value">
|
|
<?php
|
|
$source_icons = [
|
|
'抖音' => '🎵',
|
|
'微信' => '💬',
|
|
'快手' => '⚡',
|
|
'朋友介绍' => '🤝',
|
|
'其他' => '📋'
|
|
];
|
|
$icon = $source_icons[$booking['source']] ?? '📋';
|
|
echo $icon . ' ' . $booking['source'];
|
|
?>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($booking['notes']): ?>
|
|
<div class="package-description">
|
|
<span class="detail-label">客户备注:</span>
|
|
<span><?php echo htmlspecialchars($booking['notes']); ?></span>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($booking['custom_services']): ?>
|
|
<div class="package-description">
|
|
<span class="detail-label">客服备注:</span>
|
|
<span><?php echo htmlspecialchars($booking['custom_services']); ?></span>
|
|
<button type="button" class="btn btn-sm btn-secondary" onclick="openEditNotesModal(<?php echo $booking['id']; ?>, '<?php echo htmlspecialchars($booking['custom_services']); ?>')" style="margin-left: 10px;">修改</button>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="package-description">
|
|
<span class="detail-label">客服备注:</span>
|
|
<span style="color: #999;">无</span>
|
|
<button type="button" class="btn btn-sm btn-secondary" onclick="openEditNotesModal(<?php echo $booking['id']; ?>, '<?php echo htmlspecialchars($booking['custom_services']); ?>')" style="margin-left: 10px;">添加</button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="package-meta">
|
|
<span>预约时间:<?php echo $booking['created_at']; ?></span>
|
|
</div>
|
|
|
|
<div class="package-actions">
|
|
<?php if ($booking['status'] !== '已完成' && $booking['status'] !== '已取消'): ?>
|
|
<!-- 状态更新按钮 - 使用AJAX -->
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-success" onclick="updateStatus(<?php echo $booking['id']; ?>, '已确认')">确认</button>
|
|
<button type="button" class="btn btn-sm btn-primary" onclick="updateStatus(<?php echo $booking['id']; ?>, '已完成')">完成</button>
|
|
<button type="button" class="btn btn-sm btn-danger" onclick="updateStatus(<?php echo $booking['id']; ?>, '已取消')">取消</button>
|
|
</div>
|
|
<br>
|
|
<!-- 付款状态操作 - 使用AJAX -->
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-info" onclick="updateStatus(<?php echo $booking['id']; ?>, '已付款')">标记为已付款</button>
|
|
<button type="button" class="btn btn-sm btn-warning" onclick="updateStatus(<?php echo $booking['id']; ?>, '未付款')">标记为未付款</button>
|
|
</div>
|
|
<br>
|
|
<!-- 修改预约时间按钮 -->
|
|
<button type="button" class="btn btn-sm btn-secondary" onclick="openEditModal(<?php echo $booking['id']; ?>, '<?php echo date('Y-m-d\TH:i', strtotime($booking['start_time'])); ?>', '<?php echo date('Y-m-d\TH:i', strtotime($booking['end_time'])); ?>')">修改预约时间</button>
|
|
<br>
|
|
<?php endif; ?>
|
|
<!-- 转换为VIP客户按钮 -->
|
|
<?php
|
|
// 检查该客户是否已经是VIP
|
|
$stmt_check_vip = $pdo->prepare("SELECT id FROM vip_customers WHERE phone = ? AND car_number = ? AND is_active = 1");
|
|
$stmt_check_vip->execute([$booking['phone'], $booking['car_number']]);
|
|
$is_vip = $stmt_check_vip->fetch() !== false;
|
|
?>
|
|
<?php if (!$is_vip && $booking['member_type'] === '普通客户'): ?>
|
|
<form method="POST" action="vip.php" style="display: inline; margin-top: 10px;">
|
|
<input type="hidden" name="action" value="convert_from_booking">
|
|
<input type="hidden" name="booking_id" value="<?php echo $booking['id']; ?>">
|
|
<button type="submit" class="btn btn-sm" style="background-color: #ffd700; color: #333; font-weight: bold;"
|
|
onclick="return confirm('确定要将该客户转换为VIP客户吗?\n\n客户:<?php echo htmlspecialchars($booking['customer_name']); ?>\n手机号:<?php echo htmlspecialchars($booking['phone']); ?>\n车牌号:<?php echo htmlspecialchars($booking['car_number']); ?>')">
|
|
👑 转换为VIP客户
|
|
</button>
|
|
</form>
|
|
<br>
|
|
<?php endif; ?>
|
|
<!-- 复制预约信息按钮 -->
|
|
<?php
|
|
// 计算服务时长(分钟)
|
|
$start = strtotime($booking['start_time']);
|
|
$end = strtotime($booking['end_time']);
|
|
$duration = round(($end - $start) / 60);
|
|
// 获取车友备注(如果不存在则为空字符串)
|
|
$notes = $booking['notes'] ?? '';
|
|
?>
|
|
<button type="button" class="btn btn-sm btn-copy"
|
|
data-id="<?php echo $booking['id']; ?>"
|
|
data-customer-name="<?php echo htmlspecialchars($booking['customer_name']); ?>"
|
|
data-phone="<?php echo htmlspecialchars($booking['phone']); ?>"
|
|
data-car-model="<?php echo htmlspecialchars($booking['car_model']); ?>"
|
|
data-car-number="<?php echo htmlspecialchars($booking['car_number']); ?>"
|
|
data-package-name="<?php echo htmlspecialchars($booking['package_name'] ?? '未选择套餐'); ?>"
|
|
data-date="<?php echo date('Y-m-d', strtotime($booking['start_time'])); ?>"
|
|
data-time="<?php echo date('H:i', strtotime($booking['start_time'])) . ' - ' . date('H:i', strtotime($booking['end_time'])); ?>"
|
|
data-duration="<?php echo $duration; ?>"
|
|
data-notes="<?php echo htmlspecialchars($notes); ?>"
|
|
data-package-reminder="<?php echo htmlspecialchars($booking['package_reminder'] ?? ''); ?>"
|
|
onclick="copyMessage(this)">复制预约信息</button>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div style="text-align: center; margin-top: 2rem;">
|
|
<a href="index.php" class="btn">返回预约页面</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 编辑客服备注模态框 -->
|
|
<div id="editNotesModal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0,0,0,0.4);">
|
|
<div style="background-color: #fefefe; margin: 15% auto; padding: 20px; border-radius: 8px; width: 90%; max-width: 500px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
|
|
<div class="modal-header">
|
|
<h3>编辑客服备注</h3>
|
|
<span class="close-modal" onclick="closeEditNotesModal()">×</span>
|
|
</div>
|
|
<form id="editNotesForm">
|
|
<input type="hidden" id="editNotesBookingId" name="booking_id">
|
|
<div class="form-group">
|
|
<label for="editNotesContent">客服备注内容:</label>
|
|
<textarea id="editNotesContent" name="notes_content" rows="5" placeholder="请输入客服备注内容..." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box;"></textarea>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button type="button" class="btn btn-sm" onclick="closeEditNotesModal()">取消</button>
|
|
<button type="submit" class="btn btn-sm btn-primary">保存</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 修改预约时间模态框 -->
|
|
<div id="editTimeModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h3>修改预约时间</h3>
|
|
<span class="close-modal" onclick="closeEditModal()">×</span>
|
|
</div>
|
|
<div class="modal-body">
|
|
<form id="editTimeForm" method="POST">
|
|
<input type="hidden" name="booking_id" id="editBookingId" value="">
|
|
<input type="hidden" name="action" value="update_time">
|
|
|
|
<div class="form-group">
|
|
<label for="new_start_time">新的开始时间:</label>
|
|
<input type="datetime-local" id="new_start_time" name="new_start_time" required>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="new_end_time">新的结束时间:</label>
|
|
<input type="datetime-local" id="new_end_time" name="new_end_time" required>
|
|
</div>
|
|
|
|
<div class="modal-actions">
|
|
<button type="submit" class="btn btn-primary">确认修改</button>
|
|
<button type="button" class="btn btn-secondary" onclick="closeEditModal()">取消</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
/* 筛选和搜索区域样式 */
|
|
.filter-search-area {
|
|
background-color: #f8f9fa;
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.filter-form {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 12px;
|
|
align-items: end;
|
|
}
|
|
|
|
.filter-group,
|
|
.search-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.filter-group label,
|
|
.search-group label {
|
|
font-weight: 500;
|
|
color: #495057;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.filter-select,
|
|
#search_term {
|
|
padding: 8px 12px;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 4px;
|
|
font-size: 0.9rem;
|
|
min-width: 150px;
|
|
}
|
|
|
|
#search_term {
|
|
width: 200px;
|
|
}
|
|
|
|
.filter-submit {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* 响应式调整 */
|
|
@media (max-width: 768px) {
|
|
/* 筛选表单响应式 */
|
|
.filter-form {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.filter-group,
|
|
.search-group {
|
|
width: 100%;
|
|
}
|
|
|
|
#search_term {
|
|
width: 100%;
|
|
}
|
|
|
|
.filter-form button,
|
|
.filter-form a {
|
|
width: 100%;
|
|
margin-top: 8px;
|
|
}
|
|
}
|
|
|
|
/* 付款状态样式 */
|
|
.payment-status {
|
|
padding: 3px 8px;
|
|
border-radius: 12px;
|
|
font-weight: bold;
|
|
font-size: 0.9em;
|
|
}
|
|
.payment-status.paid {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
}
|
|
.payment-status.unpaid {
|
|
background-color: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
/* 模态框样式 */
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
z-index: 1000;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(0,0,0,0.4);
|
|
overflow: auto;
|
|
}
|
|
.modal-content {
|
|
background-color: #fff;
|
|
margin: 15% auto;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
width: 90%;
|
|
max-width: 500px;
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
|
}
|
|
.modal-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
}
|
|
.modal-header h3 {
|
|
margin: 0;
|
|
}
|
|
.close-modal {
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
color: #666;
|
|
}
|
|
.close-modal:hover {
|
|
color: #000;
|
|
}
|
|
.modal-body {
|
|
margin-bottom: 15px;
|
|
}
|
|
.modal-actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 10px;
|
|
margin-top: 20px;
|
|
}
|
|
.form-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
font-weight: bold;
|
|
}
|
|
.form-group input {
|
|
width: 100%;
|
|
padding: 8px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
// 确保jQuery库已加载
|
|
if (typeof jQuery === 'undefined') {
|
|
// 如果jQuery未加载,动态加载它
|
|
var script = document.createElement('script');
|
|
script.src = 'https://code.jquery.com/jquery-3.6.0.min.js';
|
|
script.onload = function() {
|
|
console.log('jQuery已成功加载');
|
|
};
|
|
script.onerror = function() {
|
|
console.log('jQuery加载失败,将使用原生JavaScript实现');
|
|
};
|
|
document.head.appendChild(script);
|
|
}
|
|
|
|
// 修改预约时间相关函数
|
|
function openEditModal(bookingId, startTime, endTime) {
|
|
document.getElementById('editBookingId').value = bookingId;
|
|
document.getElementById('new_start_time').value = startTime;
|
|
document.getElementById('new_end_time').value = endTime;
|
|
document.getElementById('editTimeModal').style.display = 'block';
|
|
}
|
|
|
|
function closeEditModal() {
|
|
document.getElementById('editTimeModal').style.display = 'none';
|
|
}
|
|
|
|
// 编辑客服备注相关函数
|
|
function openEditNotesModal(bookingId, notesContent) {
|
|
document.getElementById('editNotesBookingId').value = bookingId;
|
|
document.getElementById('editNotesContent').value = notesContent;
|
|
document.getElementById('editNotesModal').style.display = 'block';
|
|
}
|
|
|
|
function closeEditNotesModal() {
|
|
document.getElementById('editNotesModal').style.display = 'none';
|
|
}
|
|
|
|
// 点击模态框外部关闭模态框
|
|
window.onclick = function(event) {
|
|
const modal = document.getElementById('editTimeModal');
|
|
const notesModal = document.getElementById('editNotesModal');
|
|
if (event.target == modal) {
|
|
closeEditModal();
|
|
} else if (event.target == notesModal) {
|
|
closeEditNotesModal();
|
|
}
|
|
}
|
|
|
|
// 编辑客服备注表单提交处理 - 使用AJAX
|
|
document.getElementById('editNotesForm').addEventListener('submit', function(event) {
|
|
event.preventDefault();
|
|
|
|
const bookingId = document.getElementById('editNotesBookingId').value;
|
|
const notesContent = document.getElementById('editNotesContent').value;
|
|
|
|
// 创建AJAX请求
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open('POST', 'bookings.php', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
xhr.onload = function() {
|
|
if (xhr.status === 200) {
|
|
// 刷新页面以显示更新后的备注
|
|
window.location.reload();
|
|
} else {
|
|
alert('保存失败,请重试');
|
|
}
|
|
};
|
|
xhr.onerror = function() {
|
|
alert('网络错误,请重试');
|
|
};
|
|
|
|
// 发送请求
|
|
xhr.send('action=update_notes&booking_id=' + bookingId + '¬es_content=' + encodeURIComponent(notesContent));
|
|
});
|
|
|
|
// 修改预约时间表单提交处理 - 使用AJAX
|
|
document.getElementById('editTimeForm').addEventListener('submit', function(event) {
|
|
event.preventDefault();
|
|
|
|
const bookingId = document.getElementById('editBookingId').value;
|
|
const startTime = new Date(document.getElementById('new_start_time').value);
|
|
const endTime = new Date(document.getElementById('new_end_time').value);
|
|
const now = new Date();
|
|
|
|
if (startTime < now) {
|
|
alert('开始时间不能早于当前时间');
|
|
return;
|
|
}
|
|
|
|
if (endTime <= startTime) {
|
|
alert('结束时间必须晚于开始时间');
|
|
return;
|
|
}
|
|
|
|
if (typeof jQuery !== 'undefined') {
|
|
$.ajax({
|
|
url: 'update_booking.php',
|
|
type: 'POST',
|
|
data: {
|
|
booking_id: bookingId,
|
|
action: 'update_time',
|
|
new_start_time: document.getElementById('new_start_time').value,
|
|
new_end_time: document.getElementById('new_end_time').value
|
|
},
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
if (response.status === 'success') {
|
|
alert(response.message);
|
|
closeEditModal();
|
|
location.reload(); // 刷新页面以显示最新状态
|
|
} else {
|
|
alert(response.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
alert('操作失败,请重试');
|
|
}
|
|
});
|
|
} else {
|
|
// 纯JavaScript的Ajax实现作为备用
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open('POST', 'update_booking.php', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState === 4) {
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
alert(response.message);
|
|
if (response.status === 'success') {
|
|
closeEditModal();
|
|
location.reload();
|
|
}
|
|
} catch (e) {
|
|
alert('操作失败,请重试');
|
|
}
|
|
}
|
|
};
|
|
|
|
const params = new URLSearchParams();
|
|
params.append('booking_id', bookingId);
|
|
params.append('action', 'update_time');
|
|
params.append('new_start_time', document.getElementById('new_start_time').value);
|
|
params.append('new_end_time', document.getElementById('new_end_time').value);
|
|
xhr.send(params.toString());
|
|
}
|
|
});
|
|
|
|
// 处理状态更新的AJAX函数
|
|
function updateStatus(bookingId, action) {
|
|
let confirmMsg;
|
|
|
|
if (action === '已付款' || action === '未付款') {
|
|
confirmMsg = `确定要将预约的付款状态更改为「${action}」吗?`;
|
|
} else {
|
|
confirmMsg = `确定要将预约的状态更改为「${action}」吗?`;
|
|
}
|
|
|
|
if (confirm(confirmMsg)) {
|
|
if (typeof jQuery !== 'undefined') {
|
|
$.ajax({
|
|
url: 'update_booking.php',
|
|
type: 'POST',
|
|
data: {
|
|
booking_id: bookingId,
|
|
action: action
|
|
},
|
|
dataType: 'json',
|
|
success: function(response) {
|
|
if (response.status === 'success') {
|
|
alert(response.message);
|
|
location.reload(); // 刷新页面以显示最新状态
|
|
} else {
|
|
alert(response.message);
|
|
}
|
|
},
|
|
error: function() {
|
|
alert('操作失败,请重试');
|
|
}
|
|
});
|
|
} else {
|
|
// 纯JavaScript的Ajax实现作为备用
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open('POST', 'update_booking.php', true);
|
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
|
xhr.onreadystatechange = function() {
|
|
if (xhr.readyState === 4) {
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
alert(response.message);
|
|
if (response.status === 'success') {
|
|
location.reload();
|
|
}
|
|
} catch (e) {
|
|
alert('操作失败,请重试');
|
|
}
|
|
}
|
|
};
|
|
|
|
const params = new URLSearchParams();
|
|
params.append('booking_id', bookingId);
|
|
params.append('action', action);
|
|
xhr.send(params.toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
</script>
|
|
|
|
<!-- 单独的JavaScript块用于复制功能 -->
|
|
<!-- 复制预约信息功能 -->
|
|
<script>
|
|
function copyMessage(button) {
|
|
try {
|
|
// 从按钮的data属性获取预约信息
|
|
var id = button.dataset.id;
|
|
var customer_name = button.dataset.customerName;
|
|
var phone = button.dataset.phone;
|
|
var car_model = button.dataset.carModel;
|
|
var car_number = button.dataset.carNumber;
|
|
var package_name = button.dataset.packageName;
|
|
var date = button.dataset.date;
|
|
var time = button.dataset.time;
|
|
var duration = button.dataset.duration;
|
|
var notes = button.dataset.notes;
|
|
var package_reminder = button.dataset.packageReminder;
|
|
|
|
var msg = "【张老师撸车工作室】预约确认\n\n";
|
|
msg += "客户姓名:" + customer_name + "\n";
|
|
msg += "联系方式:" + phone + "\n";
|
|
msg += "车型:" + car_model + "\n";
|
|
msg += "车牌号:" + car_number + "\n";
|
|
msg += "预约日期:" + date + "\n";
|
|
msg += "套餐:" + package_name + "\n";
|
|
msg += "预约时间:" + time + "\n";
|
|
msg += "预计服务时长:" + duration + "分钟\n";
|
|
msg += "车友备注:" + notes + "\n";
|
|
msg += "" + (package_reminder || "") + "\n\n";
|
|
|
|
|
|
// 复制到剪贴板
|
|
var ta = document.createElement('textarea');
|
|
ta.value = msg;
|
|
ta.style.position = 'fixed';
|
|
ta.style.left = '-9999px';
|
|
document.body.appendChild(ta);
|
|
ta.select();
|
|
|
|
try {
|
|
document.execCommand('copy');
|
|
alert('预约信息已复制到剪贴板!');
|
|
} catch (err) {
|
|
alert('复制失败,请手动复制!');
|
|
}
|
|
|
|
document.body.removeChild(ta);
|
|
} catch (e) {
|
|
alert('复制过程中发生错误,请稍后重试!');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script type="text/javascript">
|
|
|
|
// 移动端优化脚本
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// 为按钮添加触摸反馈
|
|
const buttons = document.querySelectorAll('.btn');
|
|
buttons.forEach(btn => {
|
|
btn.addEventListener('touchstart', function() {
|
|
this.style.transform = 'translateY(1px)';
|
|
});
|
|
btn.addEventListener('touchend', function() {
|
|
this.style.transform = 'translateY(-2px)';
|
|
});
|
|
});
|
|
|
|
// 优化表单按钮
|
|
const formButtons = document.querySelectorAll('form button');
|
|
formButtons.forEach(btn => {
|
|
btn.addEventListener('touchstart', function() {
|
|
this.style.transform = 'scale(0.98)';
|
|
});
|
|
btn.addEventListener('touchend', function() {
|
|
this.style.transform = 'scale(1)';
|
|
});
|
|
});
|
|
|
|
// 预约项目点击优化
|
|
const bookingItems = document.querySelectorAll('.booking-item');
|
|
bookingItems.forEach(item => {
|
|
item.addEventListener('touchstart', function() {
|
|
this.style.backgroundColor = '#f0f0f0';
|
|
});
|
|
item.addEventListener('touchend', function() {
|
|
setTimeout(() => {
|
|
this.style.backgroundColor = '';
|
|
}, 150);
|
|
});
|
|
});
|
|
|
|
// 检测设备类型并添加类名
|
|
const isMobile = /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
if (isMobile) {
|
|
document.body.classList.add('mobile-device');
|
|
}
|
|
|
|
// 防止双击缩放(针对iOS Safari)
|
|
let lastTouchEnd = 0;
|
|
document.addEventListener('touchend', function(event) {
|
|
const now = (new Date()).getTime();
|
|
if (now - lastTouchEnd <= 300) {
|
|
event.preventDefault();
|
|
}
|
|
lastTouchEnd = now;
|
|
}, false);
|
|
|
|
// 长按删除确认(可选功能)
|
|
const statusButtons = document.querySelectorAll('form button[value="已取消"]');
|
|
statusButtons.forEach(btn => {
|
|
btn.addEventListener('contextmenu', function(e) {
|
|
e.preventDefault();
|
|
if (confirm('确定要取消这个预约吗?')) {
|
|
this.closest('form').submit();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|