更新待预约页面:添加套餐选择、日历和空闲时间段显示功能

This commit is contained in:
2025-12-06 01:02:00 +08:00
parent a9b50046c1
commit 3944051b25
+412 -41
View File
@@ -14,6 +14,8 @@ if (isset($_POST['action']) && $_POST['action'] == 'convert_to_booking' && isset
$selected_time = $_POST['selected_time'];
$selected_package = $_POST['selected_package'];
$custom_notes = $_POST['custom_notes'];
$total_price = $_POST['total_price'];
$duration = $_POST['duration'];
try {
// 获取WPS表单提交数据
@@ -36,7 +38,7 @@ if (isset($_POST['action']) && $_POST['action'] == 'convert_to_booking' && isset
// 计算开始和结束时间
$start_time = $selected_date . ' ' . $selected_time;
$end_time = date('Y-m-d H:i:s', strtotime($start_time) + $package['base_duration'] * 60);
$end_time = date('Y-m-d H:i:s', strtotime($start_time) + $duration * 60);
// 将数据插入到正式预约表
$stmt = $pdo->prepare("INSERT INTO bookings (
@@ -58,8 +60,8 @@ if (isset($_POST['action']) && $_POST['action'] == 'convert_to_booking' && isset
$custom_notes,
$start_time,
$end_time,
$package['base_duration'],
$package['price'],
$duration,
$total_price,
$submission['remarks'],
'已确认', // 默认设置为已确认
'普通客户', // 默认普通客户,可根据需要调整
@@ -73,12 +75,11 @@ if (isset($_POST['action']) && $_POST['action'] == 'convert_to_booking' && isset
$stmt->execute([$submission_id]);
// 生成预约成功信息
$booking_success_msg = "预约成功!\n\n客户:{$submission['name']}\n手机号:{$submission['mobile']}\n车牌号:{$submission['license_plate']}\n车型:{$submission['car_type']}\n\n预约时间:{$start_time}\n服务项目:{$package['package_name']}\n服务时长:{$package['base_duration']}分钟\n总价:{$package['price']}\n\n感谢您的预约!";
$booking_success_msg = "预约成功!\n\n客户:{$submission['name']}\n手机号:{$submission['mobile']}\n车牌号:{$submission['license_plate']}\n车型:{$submission['car_type']}\n\n预约时间:{$start_time}\n服务项目:{$package['package_name']}\n服务时长:{$duration}分钟\n总价:{$total_price}\n\n感谢您的预约!";
$success_message = "预约转换成功!预约ID{$booking_id}";
// 存储预约成功信息到会话,以便在页面上显示
session_start();
$_SESSION['booking_success_msg'] = $booking_success_msg;
} catch (Exception $e) {
@@ -105,6 +106,76 @@ try {
$error_message = '获取套餐信息失败:' . $e->getMessage();
$packages = [];
}
// 获取当前日期及未来7天的日期
$current_date = date('Y-m-d');
$available_dates = [];
for ($i = 0; $i < 7; $i++) {
$available_dates[] = date('Y-m-d', strtotime($current_date . " +$i days"));
}
// 获取所有预约数据,用于显示空闲时间段
$booking_schedule = [];
$bookings_by_date = [];
try {
// 获取所有未来的预约
$stmt = $pdo->prepare("SELECT * FROM bookings WHERE end_time > NOW() ORDER BY start_time ASC");
$stmt->execute();
$all_bookings = $stmt->fetchAll();
// 处理预约数据
foreach ($all_bookings as $booking) {
$start_date = date('Y-m-d', strtotime($booking['start_time']));
$end_date = date('Y-m-d', strtotime($booking['end_time']));
$start_time = date('H:i', strtotime($booking['start_time']));
$end_time = date('H:i', strtotime($booking['end_time']));
// 处理跨天预约
$is_cross_day = $start_date != $end_date;
// 添加到预约日程
if (!isset($booking_schedule[$start_date])) {
$booking_schedule[$start_date] = [];
}
if (!isset($bookings_by_date[$start_date])) {
$bookings_by_date[$start_date] = [];
}
// 主预约记录
$bookings_by_date[$start_date][] = [
'booking_id' => $booking['id'],
'customer_name' => $booking['customer_name'],
'car_model' => $booking['car_model'],
'car_number' => $booking['car_number'],
'status' => $booking['status'],
'start_time' => $start_time,
'end_time' => $end_time,
'is_cross_day' => $is_cross_day
];
// 如果是跨天预约,添加第二天的记录
if ($is_cross_day) {
if (!isset($bookings_by_date[$end_date])) {
$bookings_by_date[$end_date] = [];
}
$bookings_by_date[$end_date][] = [
'booking_id' => $booking['id'],
'customer_name' => $booking['customer_name'],
'car_model' => $booking['car_model'],
'car_number' => $booking['car_number'],
'status' => $booking['status'],
'start_time' => $start_time,
'end_time' => $end_time,
'is_cross_day' => $is_cross_day
];
}
}
} catch (Exception $e) {
$error_message = '获取预约数据失败:' . $e->getMessage();
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
@@ -247,6 +318,131 @@ try {
background: #ffc107;
color: #212529;
}
/* 日历和时间选择样式 */
.calendar-container {
margin-bottom: 20px;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 10px;
}
.calendar-day {
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.calendar-day:hover {
background: #e9ecef;
}
.calendar-day.selected {
background: #007bff;
color: white;
}
.time-slots-container {
margin-bottom: 20px;
}
.time-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 10px;
}
.time-slot {
padding: 10px;
border-radius: 4px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.time-slot.available {
background: #d4edda;
color: #155724;
}
.time-slot.booked {
background: #f8d7da;
color: #721c24;
cursor: not-allowed;
}
.time-slot.past {
background: #e9ecef;
color: #6c757d;
cursor: not-allowed;
}
.time-slot.selected {
background: #007bff;
color: white;
}
.time-slot:hover.available {
background: #c3e6cb;
}
/* 套餐信息样式 */
.package-info {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 15px;
margin-bottom: 15px;
display: none;
}
.package-details {
margin-bottom: 10px;
}
.package-meta {
display: flex;
gap: 20px;
margin: 10px 0;
}
.booking-detail-item {
background: #fff;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 10px;
margin-bottom: 10px;
}
.booking-time {
font-weight: bold;
margin-bottom: 5px;
}
.status-已确认 {
color: #28a745;
}
.status-待服务 {
color: #ffc107;
}
.status-已完成 {
color: #6c757d;
}
</style>
</head>
<body>
@@ -356,45 +552,76 @@ try {
<input type="hidden" name="action" value="convert_to_booking">
<input type="hidden" name="submission_id" value="<?php echo $submission['id']; ?>">
<div class="form-row">
<div class="form-group">
<label for="selected_date_<?php echo $submission['id']; ?>">选择日期:</label>
<input type="date" id="selected_date_<?php echo $submission['id']; ?>" name="selected_date"
value="<?php echo date('Y-m-d'); ?>" required>
<div class="form-group">
<label for="selected_package_<?php echo $submission['id']; ?>">选择套餐:</label>
<select id="selected_package_<?php echo $submission['id']; ?>" name="selected_package" required onchange="updatePackageInfo(<?php echo $submission['id']; ?>)">
<option value="">请选择套餐</option>
<?php foreach ($packages as $package): ?>
<option value="<?php echo $package['id']; ?>"
data-duration="<?php echo $package['base_duration']; ?>"
data-price="<?php echo $package['price']; ?>"
data-services='<?php echo htmlspecialchars($package['services']); ?>'>
<?php echo htmlspecialchars($package['package_name']); ?> - ¥<?php echo number_format($package['price'], 2); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="package-info" id="packageInfo_<?php echo $submission['id']; ?>">
<div class="package-details">
<h4 id="packageName_<?php echo $submission['id']; ?>"></h4>
<div class="package-meta">
<span id="packageDuration_<?php echo $submission['id']; ?>"></span>
<span id="packagePrice_<?php echo $submission['id']; ?>"></span>
</div>
<div class="form-group" style="margin-top: 15px;">
<label for="total_price_<?php echo $submission['id']; ?>">最终价格 (¥)</label>
<input type="number" id="total_price_<?php echo $submission['id']; ?>" name="total_price" min="0" step="0.01" value="0" placeholder="输入最终价格" required>
<input type="hidden" id="package_price_<?php echo $submission['id']; ?>" value="0">
</div>
<div id="packageServices_<?php echo $submission['id']; ?>"></div>
</div>
<div class="form-group">
<label for="selected_time_<?php echo $submission['id']; ?>">选择时间:</label>
<select id="selected_time_<?php echo $submission['id']; ?>" name="selected_time" required>
<?php
// 生成可选时间(9:00-18:00,每30分钟一个时间段)
$start_hour = 9;
$end_hour = 18;
for ($hour = $start_hour; $hour < $end_hour; $hour++) {
for ($minute = 0; $minute < 60; $minute += 30) {
$time = sprintf('%02d:%02d', $hour, $minute);
echo "<option value='$time'>$time</option>";
}
}
?>
</select>
</div>
<div class="calendar-container">
<div class="calendar-header">
<h5>选择预约日期</h5>
</div>
<div class="form-group">
<label for="selected_package_<?php echo $submission['id']; ?>">选择套餐:</label>
<select id="selected_package_<?php echo $submission['id']; ?>" name="selected_package" required>
<?php foreach ($packages as $package): ?>
<option value="<?php echo $package['id']; ?>">
<?php echo htmlspecialchars($package['package_name']); ?> - <?php echo $package['price']; ?>元 (<?php echo $package['base_duration']; ?>分钟)
</option>
<?php endforeach; ?>
</select>
<div class="calendar-grid" id="calendarGrid_<?php echo $submission['id']; ?>">
<?php foreach ($available_dates as $date): ?>
<div class="calendar-day"
data-date="<?php echo $date; ?>"
onclick="selectDate(<?php echo $submission['id']; ?>, '<?php echo $date; ?>')">
<div><?php echo date('m月d日', strtotime($date)); ?></div>
<div><?php echo date('D', strtotime($date)); ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="form-group">
<label for="custom_notes_<?php echo $submission['id']; ?>">自定义备注:</label>
<textarea id="custom_notes_<?php echo $submission['id']; ?>" name="custom_notes" rows="3"></textarea>
<input type="hidden" id="selected_date_<?php echo $submission['id']; ?>" name="selected_date" value="<?php echo date('Y-m-d'); ?>">
<input type="hidden" id="selected_time_<?php echo $submission['id']; ?>" name="selected_time" value="" required>
</div>
<div class="time-slots-container">
<h5>选择预约时间</h5>
<div class="time-grid" id="timeGrid_<?php echo $submission['id']; ?>">
<!-- 时间格子将通过JavaScript生成 -->
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="duration_<?php echo $submission['id']; ?>">服务时长(分钟)</label>
<input type="number" id="duration_<?php echo $submission['id']; ?>" name="duration" min="30" step="30" value="60" required>
</div>
</div>
<div class="form-group">
<label for="custom_notes_<?php echo $submission['id']; ?>">自定义服务需求:</label>
<textarea id="custom_notes_<?php echo $submission['id']; ?>" name="custom_notes" rows="3"
placeholder="如有特殊需求,请在此说明..."></textarea>
</div>
<button type="submit" class="btn btn-primary">确认预约</button>
@@ -421,10 +648,154 @@ try {
alert('预约信息已复制到剪贴板!');
}
// 设置最小日期为今天
document.querySelectorAll('input[type="date"]').forEach(input => {
input.min = new Date().toISOString().split('T')[0];
// 工作时间设置
const workingHours = {
start: 0, // 00:00
end: 24, // 24:00
slotDuration: 30 // 30分钟一个时段
};
// 预约数据
const bookingsByDate_<?php echo $submission['id']; ?> = <?php echo json_encode($bookings_by_date); ?>;
// 页面加载时初始化第一个预约的日期和时间
document.addEventListener('DOMContentLoaded', function() {
<?php foreach ($pending_submissions as $submission): ?>
// 初始化日期
selectDate(<?php echo $submission['id']; ?>, '<?php echo date('Y-m-d'); ?>');
<?php endforeach; ?>
});
// 选择日期
function selectDate(submissionId, date) {
const calendarGrid = document.getElementById('calendarGrid_' + submissionId);
const timeGrid = document.getElementById('timeGrid_' + submissionId);
const selectedDateInput = document.getElementById('selected_date_' + submissionId);
// 更新日期输入
selectedDateInput.value = date;
// 更新日历选中状态
calendarGrid.querySelectorAll('.calendar-day').forEach(day => {
day.classList.remove('selected');
});
document.querySelector(`[data-date="${date}"]`).classList.add('selected');
// 生成时间段
generateTimeSlots(submissionId, date);
}
// 生成时间段
function generateTimeSlots(submissionId, date) {
const timeGrid = document.getElementById('timeGrid_' + submissionId);
const selectedTimeInput = document.getElementById('selected_time_' + submissionId);
timeGrid.innerHTML = '';
// 获取当天已有预约
const dayBookings = bookingsByDate_<?php echo $submission['id']; ?>[date] || [];
// 生成时间段
for (let hour = workingHours.start; hour < workingHours.end; hour++) {
for (let minute = 0; minute < 60; minute += workingHours.slotDuration) {
const timeString = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
const slotTime = new Date(`${date} ${timeString}:00`);
const now = new Date();
const isPast = slotTime <= now;
const isBooked = checkTimeSlotBooked(date, timeString, submissionId);
const slotDiv = document.createElement('div');
slotDiv.className = `time-slot ${isPast ? 'past' : ''} ${isBooked ? 'booked' : 'available'}`;
slotDiv.textContent = timeString;
slotDiv.onclick = () => selectTimeSlot(submissionId, timeString);
timeGrid.appendChild(slotDiv);
}
}
selectedTimeInput.value = '';
}
// 检查时间段是否已被预约
function checkTimeSlotBooked(date, time, submissionId) {
const bookings = bookingsByDate_<?php echo $submission['id']; ?>[date] || [];
for (let booking of bookings) {
const bookingStart = booking.start_time;
const bookingEnd = booking.end_time;
// 处理跨天预约的情况
if (booking.is_cross_day) {
// 如果是跨天预约的第二天记录,所有时间都应该是已被预约的(从00:00到结束时间)
if (time < bookingEnd) {
return true; // 该时间段已被预约
}
} else {
// 正常预约检查
if (time >= bookingStart && time < bookingEnd) {
return true; // 该时间段已被预约
}
}
}
return false; // 该时间段可用
}
// 选择时间
function selectTimeSlot(submissionId, time) {
const selectedTimeInput = document.getElementById('selected_time_' + submissionId);
// 更新时间输入
selectedTimeInput.value = time;
// 更新时间段选中状态
const timeGrid = document.getElementById('timeGrid_' + submissionId);
timeGrid.querySelectorAll('.time-slot').forEach(slot => {
slot.classList.remove('selected');
});
const slotElement = timeGrid.querySelector(`[onclick="selectTimeSlot(${submissionId}, '${time}')"]`);
if (slotElement) {
slotElement.classList.add('selected');
}
}
// 更新套餐信息
function updatePackageInfo(submissionId) {
const packageSelect = document.getElementById('selected_package_' + submissionId);
const selectedOption = packageSelect.options[packageSelect.selectedIndex];
const packageInfoDiv = document.getElementById('packageInfo_' + submissionId);
const durationInput = document.getElementById('duration_' + submissionId);
const totalPriceInput = document.getElementById('total_price_' + submissionId);
if (selectedOption && selectedOption.value) {
const packageId = parseInt(selectedOption.value);
const duration = parseInt(selectedOption.getAttribute('data-duration'));
const price = parseFloat(selectedOption.getAttribute('data-price'));
const services = JSON.parse(selectedOption.getAttribute('data-services'));
// 更新套餐信息显示
document.getElementById('packageName_' + submissionId).textContent = selectedOption.textContent;
document.getElementById('packageDuration_' + submissionId).textContent = `基础时长: ${duration}分钟`;
document.getElementById('packagePrice_' + submissionId).textContent = `套餐价格: ¥${price.toFixed(2)}`;
// 更新服务项目显示
const servicesContainer = document.getElementById('packageServices_' + submissionId);
if (services && services.length > 0) {
servicesContainer.innerHTML = '<strong>包含服务:</strong><br>' +
services.map(service => `• ${service}`).join('<br>');
} else {
servicesContainer.innerHTML = '';
}
// 更新时长和价格
durationInput.value = duration;
totalPriceInput.value = price.toFixed(2);
packageInfoDiv.style.display = 'block';
} else {
packageInfoDiv.style.display = 'none';
}
}
</script>
</body>
</html>