This repository has been archived on 2026-06-20. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
carwash_order/bookings.php
T
wsh5485 0ffb4f610b feat(预约管理): 添加付款状态功能并增强预约更新逻辑
添加付款状态字段到预约表,实现状态更新API和前端交互
新增update_booking.php处理预约状态、付款状态和时间更新
改进bookings.php前端界面,添加付款状态显示和AJAX操作
添加测试页面test_update_booking.php验证功能
2025-11-19 12:48:04 +08:00

548 lines
24 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 = '预约时间更新成功!';
}
} catch (Exception $e) {
$error_message = '更新失败:' . $e->getMessage();
}
}
// 获取所有预约(过滤掉已完成和已取消的订单)
try {
// 确保查询包含payment_status字段
$stmt = $pdo->query("SELECT b.*, p.package_name FROM bookings b LEFT JOIN packages p ON b.package_id = p.id WHERE b.status NOT IN ('已完成', '已取消') ORDER BY b.start_time DESC");
$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>
<!-- 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">
<h1>📋 预约列表</h1>
<nav class="nav">
<a href="index.php" class="nav-link">预约洗车</a>
<a href="bookings.php" class="nav-link active">预约管理</a>
<a href="packages.php" class="nav-link">套餐管理</a>
</nav>
</header>
<?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>
<?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; ?>
<div class="package-meta">
<span>预约时间:<?php echo $booking['created_at']; ?></span>
</div>
<?php if ($booking['status'] !== '已完成' && $booking['status'] !== '已取消'): ?>
<div class="package-actions">
<!-- 状态更新按钮 - 使用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>
</div>
<?php endif; ?>
</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="editTimeModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>修改预约时间</h3>
<span class="close-modal" onclick="closeEditModal()">&times;</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>
/* 付款状态样式 */
.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';
}
// 点击模态框外部关闭模态框
window.onclick = function(event) {
const modal = document.getElementById('editTimeModal');
if (event.target == modal) {
closeEditModal();
}
}
// 表单提交处理 - 使用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());
}
}
}
// 移动端优化脚本
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>