feat: 初始化洗车预约系统基础框架
添加系统核心文件包括数据库配置、连接、SQL脚本、前端页面和样式 实现预约提交、管理功能及移动端优化 包含完整的README文档说明系统功能和使用方法
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
# 洗车预约系统
|
||||
|
||||
一个简单实用的PHP洗车预约管理系统,支持在线预约和预约管理功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 客户功能
|
||||
- 📝 在线提交洗车预约
|
||||
- 📱 填写客户信息(姓名、电话、车型、车牌号)
|
||||
- 🛁 选择服务类型(普通洗车、精洗、打蜡、内饰清洁)
|
||||
- 📅 选择预约日期和时间
|
||||
- 💬 添加备注信息
|
||||
- ✅ 防重复预约检查
|
||||
|
||||
### 管理功能
|
||||
- 📋 查看所有预约记录
|
||||
- 🔄 更新预约状态(待确认→已确认→已完成)
|
||||
- ❌ 取消预约功能
|
||||
- 📊 预约统计显示
|
||||
- 🎯 状态颜色标识
|
||||
|
||||
## 技术栈
|
||||
- **后端**: PHP 7.4+
|
||||
- **数据库**: MySQL 5.7+
|
||||
- **前端**: HTML5 + CSS3 + JavaScript
|
||||
- **响应式设计**: 移动端自适应
|
||||
- **数据库操作**: PDO
|
||||
|
||||
## 移动端优化特性
|
||||
- 📱 **响应式设计**: 完美适配手机、平板、桌面设备
|
||||
- 👆 **触摸优化**: 针对移动设备优化的触摸交互
|
||||
- 🔍 **防缩放**: 防止意外的双击缩放
|
||||
- ⌨️ **输入优化**: 针对移动端键盘类型的自动适配
|
||||
- 🎨 **界面适配**: 小屏幕下的布局优化
|
||||
- 🚫 **触摸反馈**: 按钮点击的视觉反馈效果
|
||||
- 📋 **表单体验**: 移动端友好的表单交互
|
||||
|
||||
## 文件结构
|
||||
```
|
||||
carwash_order/
|
||||
├── index.php # 预约首页
|
||||
├── bookings.php # 预约管理页面
|
||||
├── config.php # 数据库配置
|
||||
├── db_connect.php # 数据库连接
|
||||
├── carwash_db.sql # 数据库结构
|
||||
├── style.css # 样式文件
|
||||
└── README.md # 说明文档
|
||||
```
|
||||
|
||||
## 安装说明
|
||||
|
||||
### 1. 环境要求
|
||||
- PHP 7.4 或更高版本
|
||||
- MySQL 5.7 或更高版本
|
||||
- Web服务器 (Apache/Nginx)
|
||||
|
||||
### 2. 数据库配置
|
||||
1. 创建MySQL数据库
|
||||
2. 导入数据库结构:
|
||||
```bash
|
||||
mysql -u root -p < carwash_db.sql
|
||||
```
|
||||
|
||||
### 3. 修改配置文件
|
||||
编辑 `config.php` 文件,修改数据库连接信息:
|
||||
```php
|
||||
$host = 'localhost'; // 数据库主机
|
||||
$username = 'root'; // 数据库用户名
|
||||
$password = ''; // 数据库密码
|
||||
$database = 'carwash_booking'; // 数据库名
|
||||
```
|
||||
|
||||
### 4. 运行系统
|
||||
1. 将所有文件放在Web服务器根目录
|
||||
2. 访问 `index.php` 开始使用系统
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 客户预约流程
|
||||
1. 访问首页,填写完整的预约信息
|
||||
2. 选择服务类型和预约时间
|
||||
3. 提交表单后系统会检查时间冲突
|
||||
4. 成功提交后会显示确认信息
|
||||
|
||||
### 管理员操作
|
||||
1. 访问 `bookings.php` 查看所有预约
|
||||
2. 可以更新预约状态:
|
||||
- **已确认**: 联系客户确认预约
|
||||
- **已完成**: 洗车服务已完成
|
||||
- **已取消**: 取消该预约
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### bookings 表
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | INT | 主键,自增 |
|
||||
| customer_name | VARCHAR(100) | 客户姓名 |
|
||||
| phone | VARCHAR(20) | 联系电话 |
|
||||
| car_model | VARCHAR(50) | 车型 |
|
||||
| car_number | VARCHAR(20) | 车牌号 |
|
||||
| service_type | ENUM | 服务类型 |
|
||||
| appointment_date | DATE | 预约日期 |
|
||||
| appointment_time | TIME | 预约时间 |
|
||||
| notes | TEXT | 备注信息 |
|
||||
| status | ENUM | 预约状态 |
|
||||
| created_at | TIMESTAMP | 创建时间 |
|
||||
|
||||
## 服务类型和价格
|
||||
- **普通洗车**: ¥30
|
||||
- **精洗**: ¥80
|
||||
- **打蜡**: ¥120
|
||||
- **内饰清洁**: ¥60
|
||||
|
||||
## 状态说明
|
||||
- **待确认**: 新提交的预约,等待管理员确认
|
||||
- **已确认**: 管理员已确认,可以提供服务
|
||||
- **已完成**: 服务已完成
|
||||
- **已取消**: 预约已取消
|
||||
|
||||
## 扩展功能建议
|
||||
如需添加更多功能,可以考虑:
|
||||
- 用户注册登录系统
|
||||
- 在线支付功能
|
||||
- 短信/邮件通知
|
||||
- 预约提醒功能
|
||||
- 服务评价系统
|
||||
- 数据统计报表
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 数据库连接失败
|
||||
1. 检查 `config.php` 中的数据库配置
|
||||
2. 确认MySQL服务正在运行
|
||||
3. 检查数据库用户权限
|
||||
|
||||
### 页面显示异常
|
||||
1. 确认PHP版本兼容
|
||||
2. 检查Web服务器配置
|
||||
3. 查看PHP错误日志
|
||||
|
||||
## 许可证
|
||||
本项目基于MIT许可证开源。
|
||||
|
||||
## 联系信息
|
||||
如有问题或建议,请联系开发团队。
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
// bookings.php - 预约列表页面
|
||||
require_once 'db_connect.php';
|
||||
|
||||
// 处理状态更新
|
||||
if (isset($_POST['action']) && isset($_POST['booking_id'])) {
|
||||
$booking_id = $_POST['booking_id'];
|
||||
$new_status = $_POST['action'];
|
||||
|
||||
if (in_array($new_status, ['已确认', '已完成', '已取消'])) {
|
||||
try {
|
||||
$stmt = $pdo->prepare("UPDATE bookings SET status = ? WHERE id = ?");
|
||||
$stmt->execute([$new_status, $booking_id]);
|
||||
$success_message = '状态更新成功!';
|
||||
} catch (Exception $e) {
|
||||
$error_message = '状态更新失败:' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有预约
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT * FROM bookings ORDER BY appointment_date DESC, appointment_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">
|
||||
|
||||
<!-- 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>
|
||||
<h1>📋 预约列表</h1>
|
||||
<p>管理所有洗车预约</p>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="index.php">预约洗车</a>
|
||||
<a href="bookings.php">查看预约</a>
|
||||
</nav>
|
||||
|
||||
<?php if (isset($success_message)): ?>
|
||||
<div class="success-message"><?php echo $success_message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($error_message)): ?>
|
||||
<div style="background: #f8d7da; color: #721c24; padding: 1rem; border-radius: 4px; margin-bottom: 1rem; border: 1px solid #f5c6cb;">
|
||||
<?php echo $error_message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="bookings-list">
|
||||
<h2>所有预约 (共 <?php echo count($bookings); ?> 条)</h2>
|
||||
|
||||
<?php if (empty($bookings)): ?>
|
||||
<p style="text-align: center; color: #666; padding: 2rem;">暂无预约记录</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($bookings as $booking): ?>
|
||||
<div class="booking-item">
|
||||
<div class="booking-header">
|
||||
<h3><?php echo htmlspecialchars($booking['customer_name']); ?> 的预约</h3>
|
||||
<span class="status <?php
|
||||
echo $booking['status'] === '待确认' ? 'pending' :
|
||||
($booking['status'] === '已确认' ? 'confirmed' :
|
||||
($booking['status'] === '已完成' ? 'completed' : 'cancelled'));
|
||||
?>">
|
||||
<?php echo $booking['status']; ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem;">
|
||||
<div>
|
||||
<strong>联系方式:</strong><?php echo htmlspecialchars($booking['phone']); ?>
|
||||
</div>
|
||||
<div>
|
||||
<strong>车型:</strong><?php echo htmlspecialchars($booking['car_model']); ?>
|
||||
</div>
|
||||
<div>
|
||||
<strong>车牌号:</strong><?php echo htmlspecialchars($booking['car_number']); ?>
|
||||
</div>
|
||||
<div>
|
||||
<strong>服务类型:</strong><?php echo htmlspecialchars($booking['service_type']); ?>
|
||||
</div>
|
||||
<div>
|
||||
<strong>预约日期:</strong><?php echo $booking['appointment_date']; ?>
|
||||
</div>
|
||||
<div>
|
||||
<strong>预约时间:</strong><?php echo $booking['appointment_time']; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($booking['notes']): ?>
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<strong>备注:</strong><?php echo htmlspecialchars($booking['notes']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="font-size: 0.9rem; color: #666;">
|
||||
预约时间:<?php echo $booking['created_at']; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($booking['status'] !== '已完成' && $booking['status'] !== '已取消'): ?>
|
||||
<div style="margin-top: 1rem;">
|
||||
<form method="POST" style="display: inline;">
|
||||
<input type="hidden" name="booking_id" value="<?php echo $booking['id']; ?>">
|
||||
<button type="submit" name="action" value="已确认" class="btn" style="margin-right: 0.5rem;">确认</button>
|
||||
<button type="submit" name="action" value="已完成" class="btn" style="margin-right: 0.5rem;">完成</button>
|
||||
<button type="submit" name="action" value="已取消" class="btn" style="background: #dc3545;">取消</button>
|
||||
</form>
|
||||
</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>
|
||||
|
||||
<script>
|
||||
// 移动端优化脚本
|
||||
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>
|
||||
@@ -0,0 +1,22 @@
|
||||
-- carwash_db.sql - 数据库创建脚本
|
||||
CREATE DATABASE IF NOT EXISTS carwash_booking;
|
||||
USE carwash_booking;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bookings (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
customer_name VARCHAR(100) NOT NULL,
|
||||
phone VARCHAR(20) NOT NULL,
|
||||
car_model VARCHAR(50) NOT NULL,
|
||||
car_number VARCHAR(20) NOT NULL,
|
||||
service_type ENUM('普通洗车', '精洗', '打蜡', '内饰清洁') NOT NULL,
|
||||
appointment_date DATE NOT NULL,
|
||||
appointment_time TIME NOT NULL,
|
||||
notes TEXT,
|
||||
status ENUM('待确认', '已确认', '已完成', '已取消') DEFAULT '待确认',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 插入一些示例数据
|
||||
INSERT INTO bookings (customer_name, phone, car_model, car_number, service_type, appointment_date, appointment_time, notes) VALUES
|
||||
('张三', '13800138001', '大众朗逸', '京A12345', '普通洗车', '2024-01-15', '09:00:00', ''),
|
||||
('李四', '13800138002', '丰田凯美瑞', '京B67890', '精洗', '2024-01-15', '10:30:00', '需要特别清洗内饰');
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
// config.php - 数据库配置文件
|
||||
$host = 'localhost';
|
||||
$username = 'root';
|
||||
$password = '';
|
||||
$database = 'carwash_booking';
|
||||
?>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
// db_connect.php - 数据库连接文件
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$database;charset=utf8", $username, $password);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
} catch(PDOException $e) {
|
||||
die("数据库连接失败: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
// index.php - 预约首页
|
||||
require_once 'db_connect.php';
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// 处理表单提交
|
||||
if ($_POST) {
|
||||
try {
|
||||
$customer_name = $_POST['customer_name'] ?? '';
|
||||
$phone = $_POST['phone'] ?? '';
|
||||
$car_model = $_POST['car_model'] ?? '';
|
||||
$car_number = $_POST['car_number'] ?? '';
|
||||
$service_type = $_POST['service_type'] ?? '';
|
||||
$appointment_date = $_POST['appointment_date'] ?? '';
|
||||
$appointment_time = $_POST['appointment_time'] ?? '';
|
||||
$notes = $_POST['notes'] ?? '';
|
||||
|
||||
// 验证必填字段
|
||||
if (empty($customer_name) || empty($phone) || empty($car_model) ||
|
||||
empty($car_number) || empty($service_type) || empty($appointment_date) || empty($appointment_time)) {
|
||||
$message = '请填写所有必填字段!';
|
||||
$message_type = 'error';
|
||||
} else {
|
||||
// 检查时间是否已经被预约
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM bookings WHERE appointment_date = ? AND appointment_time = ? AND status != '已取消'");
|
||||
$stmt->execute([$appointment_date, $appointment_time]);
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
$message = '该时间段已被预约,请选择其他时间!';
|
||||
$message_type = 'error';
|
||||
} else {
|
||||
// 插入新预约
|
||||
$stmt = $pdo->prepare("INSERT INTO bookings (customer_name, phone, car_model, car_number, service_type, appointment_date, appointment_time, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$customer_name, $phone, $car_model, $car_number, $service_type, $appointment_date, $appointment_time, $notes]);
|
||||
|
||||
$message = '预约成功!我们会尽快联系您确认。';
|
||||
$message_type = 'success';
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$message = '预约失败:' . $e->getMessage();
|
||||
$message_type = 'error';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!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">
|
||||
|
||||
<!-- 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>
|
||||
<h1>🚗 洗车预约系统</h1>
|
||||
<p>快速预约,专业洗车服务</p>
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<a href="index.php">预约洗车</a>
|
||||
<a href="bookings.php">查看预约</a>
|
||||
</nav>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="<?php echo $message_type === 'success' ? 'success-message' : ''; ?>" style="<?php echo $message_type === 'error' ? 'background: #f8d7da; color: #721c24; padding: 1rem; border-radius: 4px; margin-bottom: 1rem; border: 1px solid #f5c6cb;' : ''; ?>">
|
||||
<?php echo $message; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="booking-form">
|
||||
<h2>预约信息</h2>
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label for="customer_name">姓名 *</label>
|
||||
<input type="text" id="customer_name" name="customer_name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">联系电话 *</label>
|
||||
<input type="tel" id="phone" name="phone" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="car_model">车型 *</label>
|
||||
<input type="text" id="car_model" name="car_model" placeholder="如:大众朗逸" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="car_number">车牌号 *</label>
|
||||
<input type="text" id="car_number" name="car_number" placeholder="如:京A12345" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="service_type">服务类型 *</label>
|
||||
<select id="service_type" name="service_type" required>
|
||||
<option value="">请选择服务类型</option>
|
||||
<option value="普通洗车">普通洗车 (¥30)</option>
|
||||
<option value="精洗">精洗 (¥80)</option>
|
||||
<option value="打蜡">打蜡 (¥120)</option>
|
||||
<option value="内饰清洁">内饰清洁 (¥60)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="appointment_date">预约日期 *</label>
|
||||
<input type="date" id="appointment_date" name="appointment_date" min="<?php echo date('Y-m-d'); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="appointment_time">预约时间 *</label>
|
||||
<input type="time" id="appointment_time" name="appointment_time" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="notes">备注</label>
|
||||
<textarea id="notes" name="notes" rows="3" placeholder="特殊要求或备注信息"></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">提交预约</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; margin-top: 2rem; color: #666;">
|
||||
<p>营业时间:8:00 - 18:00 | 咨询电话:400-123-4567</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 移动端优化脚本
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 自动聚焦到第一个输入框
|
||||
const firstInput = document.querySelector('input[type="text"]');
|
||||
if (firstInput && !/Mobi|Android/i.test(navigator.userAgent)) {
|
||||
firstInput.focus();
|
||||
}
|
||||
|
||||
// 为按钮添加触摸反馈
|
||||
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 inputs = document.querySelectorAll('input, select, textarea');
|
||||
inputs.forEach(input => {
|
||||
// 添加焦点样式
|
||||
input.addEventListener('focus', function() {
|
||||
this.parentElement.style.transform = 'scale(1.02)';
|
||||
this.parentElement.style.transition = 'transform 0.2s';
|
||||
});
|
||||
|
||||
input.addEventListener('blur', function() {
|
||||
this.parentElement.style.transform = 'scale(1)';
|
||||
});
|
||||
|
||||
// iOS Safari的输入类型优化
|
||||
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
||||
if (input.type === 'tel') {
|
||||
input.setAttribute('pattern', '[0-9]*');
|
||||
}
|
||||
if (input.type === 'number') {
|
||||
input.setAttribute('inputmode', 'numeric');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 检测设备类型并添加类名
|
||||
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 form = document.querySelector('form');
|
||||
if (form) {
|
||||
form.addEventListener('submit', function(e) {
|
||||
const requiredFields = this.querySelectorAll('[required]');
|
||||
let hasEmpty = false;
|
||||
|
||||
requiredFields.forEach(field => {
|
||||
if (!field.value.trim()) {
|
||||
hasEmpty = true;
|
||||
field.style.borderColor = '#dc3545';
|
||||
field.addEventListener('input', function() {
|
||||
this.style.borderColor = '';
|
||||
}, { once: true });
|
||||
}
|
||||
});
|
||||
|
||||
if (hasEmpty) {
|
||||
e.preventDefault();
|
||||
alert('请填写所有必填字段!');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,374 @@
|
||||
/* style.css - 样式文件 */
|
||||
body {
|
||||
font-family: 'Microsoft YaHei', Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 2rem 0;
|
||||
margin-bottom: 2rem;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
.booking-form {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus,
|
||||
.form-group textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.bookings-list {
|
||||
background: white;
|
||||
padding: 2rem;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.booking-item {
|
||||
border: 1px solid #ddd;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 4px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.booking-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.status {
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status.pending {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status.confirmed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status.completed {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
}
|
||||
|
||||
.status.cancelled {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1rem;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
nav {
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: inline-block;
|
||||
margin: 0 1rem;
|
||||
padding: 0.5rem 1rem;
|
||||
text-decoration: none;
|
||||
color: #667eea;
|
||||
border: 2px solid #667eea;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 移动端响应式设计 */
|
||||
|
||||
/* 平板设备优化 */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 1.5rem 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.booking-form,
|
||||
.bookings-list {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.booking-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.status {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin: 0.5rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 手机设备优化 */
|
||||
@media (max-width: 480px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 1rem 0;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.booking-form,
|
||||
.bookings-list {
|
||||
padding: 1rem;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
padding: 1rem;
|
||||
font-size: 16px; /* 防止iOS缩放 */
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 1rem 2rem;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.booking-item {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.booking-item div {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* 预约信息网格改为单列布局 */
|
||||
.booking-item > div[style*="grid"] {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
nav a {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 小屏幕手机优化 */
|
||||
@media (max-width: 360px) {
|
||||
.container {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 0.75rem 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.booking-form,
|
||||
.bookings-list {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
padding: 0.875rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.875rem 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 触摸设备优化 */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.btn {
|
||||
min-height: 44px; /* Apple人机界面指南建议的最小触摸目标 */
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select,
|
||||
.form-group textarea {
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
nav a {
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* 横屏手机优化 */
|
||||
@media (max-height: 500px) and (orientation: landscape) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 0.75rem 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.booking-form,
|
||||
.bookings-list {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 打印样式 */
|
||||
@media print {
|
||||
body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
header {
|
||||
background: none;
|
||||
color: black;
|
||||
border-bottom: 2px solid #333;
|
||||
}
|
||||
|
||||
.btn,
|
||||
nav {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.booking-form,
|
||||
.bookings-list {
|
||||
box-shadow: none;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user