html 实现到家预约服务模板
该文章展示了一个完整的到家服务在线预约平台的设计与实现流程。主要包含5个核心功能页面:城市选择、服务人员列表、服务详情、预约时间选择和支付确认。平台采用响应式设计,支持多城市服务展示,提供详细的服务人员信息(包括评分、服务记录、距离等),并集成在线预约和支付功能。技术实现上使用HTML、CSS(Tailwind框架)和JavaScript,通过模块化设计提升用户体验,如自动定位、多条件筛选、灵活预
·
结尾有示例图
到家服务流程设计
选择城市
用户进入应用或网站后,需选择服务所在城市。通常通过定位自动获取当前城市,也可手动切换。城市选择影响后续服务人员及价格的展示。
服务人员列表
根据所选城市,展示可提供服务的人员列表。列表通常包含人员头像、评分、服务次数、距离、价格等信息。支持按评分、距离、价格等条件筛选排序。
服务详情页
点击具体服务人员后,进入详情页。展示更详细的信息,如个人简介、服务项目、用户评价、服务范围等。部分平台会展示服务人员的资质证明或案例照片。
预约时间
用户选择服务日期和时间段。系统会显示服务人员的可预约时段,避免冲突。部分服务需提前预约,如家政、维修等。
支付页面
确认服务信息后,进入支付页面。支持多种支付方式,如微信、支付宝、银行卡等。支付完成后生成订单,部分服务支持预约后支付或到付。
优化建议
- 城市切换流畅性:确保定位准确,手动切换城市时无延迟。
- 服务人员展示:增加标签(如“金牌”、“新人”),帮助用户快速决策。
- 预约时间灵活性:提供非工作时间预约选项,满足特殊需求。
- 支付安全:明确显示支付金额,避免隐藏费用,提供订单取消和退款说明。
通过以上步骤,可提升用户体验并提高订单转化率。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>到家服务平台</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 配置Tailwind -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#FF7D00',
neutral: '#F5F7FA',
dark: '#1D2129',
light: '#86909C'
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
},
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
.transition-custom {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.page-enter {
opacity: 0;
transform: translateY(10px);
}
.page-enter-active {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head>
<body class="font-inter bg-neutral text-dark min-h-screen">
<!-- 页面容器 -->
<div id="app" class="max-w-6xl mx-auto bg-white min-h-screen relative overflow-hidden">
<!-- 导航栏 -->
<header class="sticky top-0 z-50 bg-white/90 backdrop-blur-sm border-b border-gray-100 shadow-sm">
<div class="container mx-auto px-4 py-3 flex justify-between items-center">
<div class="flex items-center space-x-1">
<i class="fa fa-home text-primary text-xl"></i>
<h1 class="text-lg font-bold text-primary">到家服务</h1>
</div>
<div class="flex items-center space-x-4">
<button id="backBtn" class="text-light hover:text-primary transition-custom hidden">
<i class="fa fa-arrow-left"></i>
</button>
<button id="userBtn" class="text-light hover:text-primary transition-custom">
<i class="fa fa-user-circle-o text-xl"></i>
</button>
</div>
</div>
</header>
<!-- 主内容区 -->
<main class="min-h-[calc(100vh-100px)]">
<!-- 1. 城市选择页面 -->
<section id="cityPage" class="page py-6 px-4">
<div class="mb-6">
<h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold mb-2">选择城市</h2>
<p class="text-light">请选择您所在的城市,以便为您提供精准服务</p>
</div>
<!-- 搜索框 -->
<div class="relative mb-6">
<i class="fa fa-search absolute left-3 top-1/2 -translate-y-1/2 text-light"></i>
<input
type="text"
id="citySearch"
placeholder="搜索城市..."
class="w-full pl-10 pr-4 py-3 rounded-lg border border-gray-200 focus:border-primary focus:ring-1 focus:ring-primary outline-none transition-custom"
>
</div>
<!-- 热门城市 -->
<div class="mb-8">
<h3 class="text-sm font-semibold text-light uppercase mb-3">热门城市</h3>
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-3" id="hotCities">
<!-- 城市将通过JS动态生成 -->
</div>
</div>
<!-- 所有城市 -->
<div>
<h3 class="text-sm font-semibold text-light uppercase mb-3">所有城市</h3>
<div id="allCities" class="space-y-4">
<!-- 城市列表将通过JS动态生成 -->
</div>
</div>
</section>
<!-- 2. 服务人员列表页面 -->
<section id="serviceListPage" class="page py-6 px-4 hidden">
<div class="mb-6">
<h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold mb-2">服务人员</h2>
<p class="text-light" id="currentCityText">当前城市:北京市</p>
</div>
<!-- 筛选器 -->
<div class="flex overflow-x-auto pb-2 mb-6 space-x-3 hide-scrollbar">
<button class="whitespace-nowrap px-4 py-2 bg-primary text-white rounded-full text-sm">全部服务</button>
<button class="whitespace-nowrap px-4 py-2 bg-white border border-gray-200 hover:border-primary rounded-full text-sm transition-custom">保洁服务</button>
<button class="whitespace-nowrap px-4 py-2 bg-white border border-gray-200 hover:border-primary rounded-full text-sm transition-custom">家电维修</button>
<button class="whitespace-nowrap px-4 py-2 bg-white border border-gray-200 hover:border-primary rounded-full text-sm transition-custom">管道疏通</button>
<button class="whitespace-nowrap px-4 py-2 bg-white border border-gray-200 hover:border-primary rounded-full text-sm transition-custom">开锁换锁</button>
<button class="whitespace-nowrap px-4 py-2 bg-white border border-gray-200 hover:border-primary rounded-full text-sm transition-custom">搬家服务</button>
</div>
<!-- 服务人员列表 -->
<div id="serviceWorkersList" class="space-y-5">
<!-- 服务人员卡片将通过JS动态生成 -->
</div>
</section>
<!-- 3. 服务人员详情页面 -->
<section id="serviceDetailPage" class="page py-6 px-4 hidden">
<div class="mb-6">
<h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold">服务详情</h2>
</div>
<!-- 服务人员信息 -->
<div class="bg-neutral rounded-xl p-5 mb-6">
<div class="flex items-start space-x-4">
<img id="detailAvatar" src="" alt="服务人员头像" class="w-20 h-20 rounded-full object-cover">
<div class="flex-1">
<div class="flex justify-between items-start">
<div>
<h3 id="detailName" class="text-xl font-bold"></h3>
<p id="detailServiceType" class="text-light"></p>
</div>
<div class="bg-primary/10 text-primary px-3 py-1 rounded-full text-sm font-medium">
<i class="fa fa-star mr-1"></i><span id="detailRating"></span>
</div>
</div>
<div class="flex flex-wrap gap-2 mt-3">
<span class="bg-white px-3 py-1 rounded-full text-sm border border-gray-200">
<i class="fa fa-clock-o mr-1 text-light"></i><span id="detailExperience"></span>
</span>
<span class="bg-white px-3 py-1 rounded-full text-sm border border-gray-200">
<i class="fa fa-map-marker mr-1 text-light"></i><span id="detailDistance"></span>
</span>
<span class="bg-white px-3 py-1 rounded-full text-sm border border-gray-200">
<i class="fa fa-check-circle mr-1 text-light"></i><span id="detailVerified"></span>
</span>
</div>
</div>
</div>
</div>
<!-- 服务介绍 -->
<div class="mb-6">
<h3 class="text-lg font-bold mb-3">服务介绍</h3>
<div class="bg-white rounded-xl p-5 border border-gray-100" id="detailDescription">
<!-- 服务介绍将通过JS动态生成 -->
</div>
</div>
<!-- 服务价格 -->
<div class="mb-6">
<h3 class="text-lg font-bold mb-3">服务价格</h3>
<div class="bg-white rounded-xl p-5 border border-gray-100 space-y-3" id="detailPricing">
<!-- 价格信息将通过JS动态生成 -->
</div>
</div>
<!-- 客户评价 -->
<div class="mb-6">
<h3 class="text-lg font-bold mb-3">客户评价</h3>
<div id="detailReviews" class="space-y-4">
<!-- 评价信息将通过JS动态生成 -->
</div>
</div>
<!-- 底部预约按钮 -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 max-w-6xl mx-auto">
<button id="bookServiceBtn" class="w-full bg-secondary hover:bg-secondary/90 text-white font-medium py-3 rounded-lg transition-custom flex justify-center items-center">
<span>立即预约</span>
<i class="fa fa-arrow-right ml-2"></i>
</button>
</div>
</section>
<!-- 4. 预约时间页面 -->
<section id="bookingTimePage" class="page py-6 px-4 hidden">
<div class="mb-6">
<h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold">选择预约时间</h2>
<p class="text-light">请选择您方便的服务时间</p>
</div>
<!-- 服务人员简要信息 -->
<div class="bg-neutral rounded-xl p-4 mb-6 flex items-center space-x-3">
<img id="bookingAvatar" src="" alt="服务人员头像" class="w-14 h-14 rounded-full object-cover">
<div>
<h3 id="bookingName" class="font-medium"></h3>
<p id="bookingServiceType" class="text-sm text-light"></p>
</div>
</div>
<!-- 日期选择 -->
<div class="mb-6">
<h3 class="text-lg font-bold mb-3">选择日期</h3>
<div class="grid grid-cols-3 sm:grid-cols-5 gap-3" id="dateSelector">
<!-- 日期将通过JS动态生成 -->
</div>
</div>
<!-- 时间段选择 -->
<div class="mb-16">
<h3 class="text-lg font-bold mb-3">选择时间段</h3>
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3" id="timeSlots">
<!-- 时间段将通过JS动态生成 -->
</div>
</div>
<!-- 底部确认按钮 -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 max-w-6xl mx-auto">
<button id="confirmTimeBtn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-3 rounded-lg transition-custom flex justify-center items-center">
<span>确认时间并支付</span>
<i class="fa fa-arrow-right ml-2"></i>
</button>
</div>
</section>
<!-- 5. 支付页面 -->
<section id="paymentPage" class="page py-6 px-4 hidden">
<div class="mb-6">
<h2 class="text-[clamp(1.25rem,3vw,1.75rem)] font-bold">确认支付</h2>
<p class="text-light">请确认订单信息并完成支付</p>
</div>
<!-- 订单信息 -->
<div class="bg-white rounded-xl p-5 mb-6 border border-gray-100">
<h3 class="font-bold mb-4">订单信息</h3>
<div class="flex items-center space-x-3 mb-4">
<img id="paymentAvatar" src="" alt="服务人员头像" class="w-12 h-12 rounded-full object-cover">
<div>
<h4 id="paymentName" class="font-medium"></h4>
<p id="paymentServiceType" class="text-sm text-light"></p>
</div>
</div>
<div class="space-y-3 text-sm">
<div class="flex justify-between">
<span class="text-light">服务城市</span>
<span id="paymentCity"></span>
</div>
<div class="flex justify-between">
<span class="text-light">服务时间</span>
<span id="paymentDateTime"></span>
</div>
<div class="flex justify-between">
<span class="text-light">服务项目</span>
<span id="paymentServiceItem"></span>
</div>
</div>
</div>
<!-- 支付方式 -->
<div class="bg-white rounded-xl p-5 mb-6 border border-gray-100">
<h3 class="font-bold mb-4">选择支付方式</h3>
<div class="space-y-3" id="paymentMethods">
<!-- 支付方式将通过JS动态生成 -->
</div>
</div>
<!-- 价格信息 -->
<div class="bg-white rounded-xl p-5 mb-16 border border-gray-100">
<div class="space-y-3 text-sm mb-4">
<div class="flex justify-between">
<span class="text-light">服务费用</span>
<span id="paymentAmount"></span>
</div>
<div class="flex justify-between">
<span class="text-light">服务费</span>
<span>¥20.00</span>
</div>
<div class="flex justify-between">
<span class="text-light">优惠券</span>
<span class="text-green-500">-¥10.00</span>
</div>
</div>
<div class="pt-4 border-t border-gray-100 flex justify-between font-bold">
<span>总计</span>
<span id="totalPayment" class="text-xl"></span>
</div>
</div>
<!-- 底部支付按钮 -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-100 p-4 max-w-6xl mx-auto">
<button id="completePaymentBtn" class="w-full bg-secondary hover:bg-secondary/90 text-white font-medium py-3 rounded-lg transition-custom flex justify-center items-center">
<span>确认支付</span>
<i class="fa fa-check ml-2"></i>
</button>
</div>
</section>
<!-- 支付成功页面 -->
<section id="successPage" class="page py-6 px-4 hidden flex flex-col items-center justify-center min-h-[calc(100vh-100px)]">
<div class="text-center max-w-md mx-auto">
<div class="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6">
<i class="fa fa-check text-3xl text-green-500"></i>
</div>
<h2 class="text-2xl font-bold mb-2">预约成功!</h2>
<p class="text-light mb-8">您的服务已预约成功,服务人员将按约定时间上门</p>
<div class="bg-white rounded-xl p-5 border border-gray-100 mb-6 text-left">
<div class="flex justify-between mb-3">
<span class="text-light">订单编号</span>
<span id="orderNumber" class="font-medium"></span>
</div>
<div class="flex justify-between mb-3">
<span class="text-light">服务时间</span>
<span id="orderDateTime" class="font-medium"></span>
</div>
<div class="flex justify-between">
<span class="text-light">服务人员</span>
<span id="orderWorkerName" class="font-medium"></span>
</div>
</div>
<button id="backToHomeBtn" class="w-full bg-primary hover:bg-primary/90 text-white font-medium py-3 rounded-lg transition-custom">
返回首页
</button>
</div>
</section>
</main>
<!-- 页脚 -->
<footer class="bg-white border-t border-gray-100 py-4 text-center text-light text-sm">
<p>© 到家服务平台 版权所有</p>
</footer>
</div>
<script>
// 模拟数据 - 城市数据
const cityData = {
hotCities: ["北京", "上海", "广州", "深圳", "杭州", "成都", "武汉", "南京"],
allCities: [
{ letter: "A", cities: ["安庆", "安阳", "鞍山"] },
{ letter: "B", cities: ["北京", "保定", "包头", "滨州", "本溪"] },
{ letter: "C", cities: ["成都", "重庆", "长沙", "长春", "沧州"] },
{ letter: "D", cities: ["大连", "东莞", "德州", "丹东"] },
{ letter: "F", cities: ["福州", "佛山", "抚顺"] },
{ letter: "G", cities: ["广州", "贵阳", "桂林", "赣州"] },
{ letter: "H", cities: ["杭州", "哈尔滨", "合肥", "海口", "邯郸"] },
{ letter: "J", cities: ["济南", "南京", "吉林", "嘉兴", "江门"] },
{ letter: "S", cities: ["上海", "深圳", "沈阳", "石家庄", "苏州"] },
{ letter: "W", cities: ["武汉", "无锡", "温州", "潍坊"] },
{ letter: "X", cities: ["西安", "厦门", "徐州", "邢台"] },
{ letter: "Z", cities: ["郑州", "珠海", "淄博", "中山"] }
]
};
// 模拟数据 - 服务人员数据
const serviceWorkersData = [
{
id: 1,
name: "张师傅",
avatar: "https://picsum.photos/id/1012/200/200",
serviceType: "全能保洁",
rating: 4.9,
reviews: 128,
experience: "5年经验",
distance: "2.3公里",
verified: "已认证",
description: "专业保洁服务,擅长家庭日常保洁、深度清洁、厨房油污清洁、卫生间清洁等。自带全套清洁工具和环保清洁剂,保证清洁效果的同时呵护您的家人健康。",
pricing: [
{ item: "日常保洁(2小时)", price: "¥120.00" },
{ item: "深度保洁(4小时)", price: "¥230.00" },
{ item: "全屋清洁(6小时)", price: "¥320.00" }
],
reviews: [
{ name: "李女士", avatar: "https://picsum.photos/id/1027/100/100", rating: 5, content: "张师傅非常专业,打扫得很干净,特别是厨房油污处理得很彻底,非常满意!" },
{ name: "王先生", avatar: "https://picsum.photos/id/1025/100/100", rating: 4, content: "服务很到位,提前联系确认,清洁工具齐全,值得推荐。" }
],
availableTimes: {
"今天": ["09:00-11:00", "14:00-16:00", "16:00-18:00"],
"明天": ["08:00-10:00", "10:00-12:00", "13:00-15:00", "15:00-17:00"],
"后天": ["09:00-11:00", "11:00-13:00", "14:00-16:00", "16:00-18:00", "19:00-21:00"]
}
},
{
id: 2,
name: "王师傅",
avatar: "https://picsum.photos/id/1025/200/200",
serviceType: "家电维修",
rating: 4.8,
reviews: 96,
experience: "8年经验",
distance: "3.5公里",
verified: "已认证",
description: "专业家电维修师傅,精通冰箱、空调、洗衣机、电视等各类家电维修。快速诊断故障,合理收费,提供三个月质保服务,让您无后顾之忧。",
pricing: [
{ item: "空调清洗", price: "¥80.00" },
{ item: "冰箱维修", price: "¥100.00起" },
{ item: "洗衣机维修", price: "¥90.00起" }
],
reviews: [
{ name: "赵女士", avatar: "https://picsum.photos/id/1062/100/100", rating: 5, content: "王师傅技术很好,很快就修好了我的洗衣机,收费也合理,推荐!" },
{ name: "孙先生", avatar: "https://picsum.photos/id/1074/100/100", rating: 5, content: "服务很专业,提前沟通了故障情况,上门后迅速解决,非常满意。" }
],
availableTimes: {
"今天": ["10:00-12:00", "15:00-17:00"],
"明天": ["09:00-11:00", "13:00-15:00", "17:00-19:00"],
"后天": ["08:00-10:00", "11:00-13:00", "14:00-16:00", "18:00-20:00"]
}
},
{
id: 3,
name: "刘阿姨",
avatar: "https://picsum.photos/id/1062/200/200",
serviceType: "母婴护理",
rating: 4.9,
reviews: 156,
experience: "10年经验",
distance: "1.8公里",
verified: "已认证",
description: "专业母婴护理师,持有高级育婴师证书,擅长新生儿护理、产妇护理、月子餐制作等。有丰富的经验,耐心细致,让您和宝宝得到最贴心的照顾。",
pricing: [
{ item: "日常母婴护理(8小时)", price: "¥350.00" },
{ item: "月子餐制作", price: "¥200.00/天" },
{ item: "新生儿洗澡抚触", price: "¥80.00" }
],
reviews: [
{ name: "陈女士", avatar: "https://picsum.photos/id/1000/100/100", rating: 5, content: "刘阿姨非常专业,对宝宝很有耐心,照顾得无微不至,做的月子餐也很美味。" },
{ name: "林先生", avatar: "https://picsum.photos/id/1012/100/100", rating: 4, content: "服务很好,经验丰富,解答了我们很多育儿问题,非常感谢。" }
],
availableTimes: {
"今天": ["14:00-22:00"],
"明天": ["08:00-16:00", "16:00-24:00"],
"后天": ["08:00-16:00", "16:00-24:00"]
}
},
{
id: 4,
name: "赵师傅",
avatar: "https://picsum.photos/id/1074/200/200",
serviceType: "管道疏通",
rating: 4.7,
reviews: 89,
experience: "6年经验",
distance: "4.2公里",
verified: "已认证",
description: "专业管道疏通服务,精通马桶疏通、下水道疏通、地漏疏通等。采用专业设备,高效解决各类堵塞问题,提供质保服务,不通不收费。",
pricing: [
{ item: "马桶疏通", price: "¥80.00" },
{ item: "下水道疏通", price: "¥100.00" },
{ item: "地漏疏通", price: "¥60.00" }
],
reviews: [
{ name: "郑女士", avatar: "https://picsum.photos/id/1027/100/100", rating: 5, content: "赵师傅技术很好,很快就疏通了我家堵塞的下水道,收费合理,值得推荐。" },
{ name: "吴先生", avatar: "https://picsum.photos/id/1066/100/100", rating: 4, content: "服务及时,态度很好,解决问题很专业,满意。" }
],
availableTimes: {
"今天": ["09:00-11:00", "13:00-15:00", "16:00-18:00", "19:00-21:00"],
"明天": ["08:00-10:00", "11:00-13:00", "14:00-16:00"],
"后天": ["10:00-12:00", "15:00-17:00", "18:00-20:00"]
}
}
];
// 模拟数据 - 支付方式
const paymentMethods = [
{ id: 1, name: "微信支付", icon: "fa-weixin", color: "text-green-500" },
{ id: 2, name: "支付宝", icon: "fa-credit-card", color: "text-blue-500" },
{ id: 3, name: "银行卡支付", icon: "fa-university", color: "text-gray-700" }
];
// 全局状态
const state = {
currentCity: "",
selectedWorker: null,
selectedDate: "",
selectedTimeSlot: "",
selectedPaymentMethod: 1,
selectedServiceItem: "",
selectedServicePrice: ""
};
// DOM 元素
const elements = {
// 页面
cityPage: document.getElementById('cityPage'),
serviceListPage: document.getElementById('serviceListPage'),
serviceDetailPage: document.getElementById('serviceDetailPage'),
bookingTimePage: document.getElementById('bookingTimePage'),
paymentPage: document.getElementById('paymentPage'),
successPage: document.getElementById('successPage'),
// 城市页面
hotCities: document.getElementById('hotCities'),
allCities: document.getElementById('allCities'),
citySearch: document.getElementById('citySearch'),
// 服务列表页面
serviceWorkersList: document.getElementById('serviceWorkersList'),
currentCityText: document.getElementById('currentCityText'),
// 详情页面
detailAvatar: document.getElementById('detailAvatar'),
detailName: document.getElementById('detailName'),
detailServiceType: document.getElementById('detailServiceType'),
detailRating: document.getElementById('detailRating'),
detailExperience: document.getElementById('detailExperience'),
detailDistance: document.getElementById('detailDistance'),
detailVerified: document.getElementById('detailVerified'),
detailDescription: document.getElementById('detailDescription'),
detailPricing: document.getElementById('detailPricing'),
detailReviews: document.getElementById('detailReviews'),
bookServiceBtn: document.getElementById('bookServiceBtn'),
// 预约时间页面
bookingAvatar: document.getElementById('bookingAvatar'),
bookingName: document.getElementById('bookingName'),
bookingServiceType: document.getElementById('bookingServiceType'),
dateSelector: document.getElementById('dateSelector'),
timeSlots: document.getElementById('timeSlots'),
confirmTimeBtn: document.getElementById('confirmTimeBtn'),
// 支付页面
paymentAvatar: document.getElementById('paymentAvatar'),
paymentName: document.getElementById('paymentName'),
paymentServiceType: document.getElementById('paymentServiceType'),
paymentCity: document.getElementById('paymentCity'),
paymentDateTime: document.getElementById('paymentDateTime'),
paymentServiceItem: document.getElementById('paymentServiceItem'),
paymentAmount: document.getElementById('paymentAmount'),
totalPayment: document.getElementById('totalPayment'),
paymentMethods: document.getElementById('paymentMethods'),
completePaymentBtn: document.getElementById('completePaymentBtn'),
// 成功页面
orderNumber: document.getElementById('orderNumber'),
orderDateTime: document.getElementById('orderDateTime'),
orderWorkerName: document.getElementById('orderWorkerName'),
backToHomeBtn: document.getElementById('backToHomeBtn'),
// 导航按钮
backBtn: document.getElementById('backBtn')
};
// 初始化城市页面
function initCityPage() {
// 渲染热门城市
elements.hotCities.innerHTML = cityData.hotCities.map(city => `
<button class="city-btn bg-white border border-gray-200 hover:border-primary hover:text-primary rounded-lg py-3 text-center transition-custom" data-city="${city}">
${city}
</button>
`).join('');
// 渲染所有城市
elements.allCities.innerHTML = cityData.allCities.map(group => `
<div>
<h4 class="text-sm font-semibold text-light mb-2">${group.letter}</h4>
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-2">
${group.cities.map(city => `
<button class="city-btn text-left py-2 px-1 hover:text-primary transition-custom" data-city="${city}">
${city}
</button>
`).join('')}
</div>
</div>
`).join('');
// 添加城市选择事件
document.querySelectorAll('.city-btn').forEach(btn => {
btn.addEventListener('click', () => {
state.currentCity = btn.getAttribute('data-city');
goToServiceListPage();
});
});
// 城市搜索功能
elements.citySearch.addEventListener('input', (e) => {
const searchTerm = e.target.value.toLowerCase();
document.querySelectorAll('.city-btn').forEach(btn => {
const city = btn.getAttribute('data-city').toLowerCase();
if (city.includes(searchTerm)) {
btn.style.display = '';
} else {
btn.style.display = 'none';
}
});
});
}
// 初始化服务列表页面
function initServiceListPage() {
elements.currentCityText.textContent = `当前城市:${state.currentCity}`;
// 渲染服务人员列表
elements.serviceWorkersList.innerHTML = serviceWorkersData.map(worker => `
<div class="service-worker-card bg-white rounded-xl overflow-hidden card-shadow hover:shadow-lg transition-custom cursor-pointer" data-id="${worker.id}">
<div class="p-5 flex">
<img src="${worker.avatar}" alt="${worker.name}" class="w-16 h-16 rounded-full object-cover mr-4">
<div class="flex-1">
<div class="flex justify-between">
<h3 class="font-bold text-lg">${worker.name}</h3>
<div class="flex items-center text-yellow-500">
<i class="fa fa-star text-xs"></i>
<span class="ml-1 text-sm">${worker.rating}</span>
</div>
</div>
<p class="text-light text-sm mb-2">${worker.serviceType}</p>
<div class="flex flex-wrap gap-2">
<span class="bg-neutral px-2 py-1 rounded text-xs">${worker.experience}</span>
<span class="bg-neutral px-2 py-1 rounded text-xs">${worker.distance}</span>
<span class="bg-neutral px-2 py-1 rounded text-xs">${worker.verified}</span>
</div>
<div class="mt-3 flex justify-between items-center">
<div>
<span class="text-secondary font-bold">${worker.pricing[0].price}</span>
<span class="text-light text-sm">起</span>
</div>
<span class="text-xs text-light">${worker.reviews}条评价</span>
</div>
</div>
</div>
</div>
`).join('');
// 添加服务人员点击事件
document.querySelectorAll('.service-worker-card').forEach(card => {
card.addEventListener('click', () => {
const workerId = parseInt(card.getAttribute('data-id'));
state.selectedWorker = serviceWorkersData.find(w => w.id === workerId);
goToServiceDetailPage();
});
});
}
// 初始化服务详情页面
function initServiceDetailPage() {
const worker = state.selectedWorker;
elements.detailAvatar.src = worker.avatar;
elements.detailName.textContent = worker.name;
elements.detailServiceType.textContent = worker.serviceType;
elements.detailRating.textContent = worker.rating;
elements.detailExperience.textContent = worker.experience;
elements.detailDistance.textContent = worker.distance;
elements.detailVerified.textContent = worker.verified;
elements.detailDescription.textContent = worker.description;
// 渲染价格列表
elements.detailPricing.innerHTML = worker.pricing.map((item, index) => `
<div class="flex justify-between items-center p-3 border-b ${index === worker.pricing.length - 1 ? 'border-0' : 'border-gray-100'} hover:bg-neutral rounded-lg cursor-pointer service-item" data-name="${item.item}" data-price="${item.price}">
<span>${item.item}</span>
<span class="text-secondary font-bold">${item.price}</span>
</div>
`).join('');
// 默认选中第一个服务项目
const firstServiceItem = document.querySelector('.service-item');
if (firstServiceItem) {
firstServiceItem.classList.add('bg-primary/5');
state.selectedServiceItem = firstServiceItem.getAttribute('data-name');
state.selectedServicePrice = firstServiceItem.getAttribute('data-price');
}
// 服务项目选择事件
document.querySelectorAll('.service-item').forEach(item => {
item.addEventListener('click', () => {
document.querySelectorAll('.service-item').forEach(i => i.classList.remove('bg-primary/5'));
item.classList.add('bg-primary/5');
state.selectedServiceItem = item.getAttribute('data-name');
state.selectedServicePrice = item.getAttribute('data-price');
});
});
// 渲染评价
elements.detailReviews.innerHTML = worker.reviews.map(review => `
<div class="bg-white rounded-xl p-4 border border-gray-100">
<div class="flex items-center mb-2">
<img src="${review.avatar}" alt="${review.name}" class="w-8 h-8 rounded-full object-cover mr-2">
<span class="font-medium text-sm">${review.name}</span>
<div class="ml-auto flex text-yellow-500 text-xs">
${Array(review.rating).fill(0).map(() => '<i class="fa fa-star"></i>').join('')}
</div>
</div>
<p class="text-sm">${review.content}</p>
</div>
`).join('');
// 预约按钮事件
elements.bookServiceBtn.addEventListener('click', goToBookingTimePage);
}
// 初始化预约时间页面
function initBookingTimePage() {
const worker = state.selectedWorker;
elements.bookingAvatar.src = worker.avatar;
elements.bookingName.textContent = worker.name;
elements.bookingServiceType.textContent = worker.serviceType;
// 生成日期选项
const dates = Object.keys(worker.availableTimes);
elements.dateSelector.innerHTML = dates.map((date, index) => `
<button class="date-btn flex flex-col items-center justify-center p-3 bg-white border border-gray-200 rounded-lg transition-custom ${index === 0 ? 'border-primary bg-primary/5' : ''}" data-date="${date}">
<span class="text-sm text-light">${date}</span>
<span class="text-xs text-light mt-1">${getDateString(index)}</span>
</button>
`).join('');
// 默认选中第一个日期
state.selectedDate = dates[0];
renderTimeSlots(worker.availableTimes[dates[0]]);
// 日期选择事件
document.querySelectorAll('.date-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.date-btn').forEach(b => b.classList.remove('border-primary', 'bg-primary/5'));
btn.classList.add('border-primary', 'bg-primary/5');
state.selectedDate = btn.getAttribute('data-date');
renderTimeSlots(worker.availableTimes[state.selectedDate]);
});
});
// 确认时间按钮事件
elements.confirmTimeBtn.addEventListener('click', () => {
if (!state.selectedTimeSlot) {
alert('请选择服务时间段');
return;
}
goToPaymentPage();
});
}
// 渲染时间段
function renderTimeSlots(times) {
elements.timeSlots.innerHTML = times.map(time => `
<button class="time-slot-btn py-3 px-2 bg-white border border-gray-200 rounded-lg text-center transition-custom hover:border-primary" data-time="${time}">
${time}
</button>
`).join('');
// 时间段选择事件
document.querySelectorAll('.time-slot-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.time-slot-btn').forEach(b => b.classList.remove('border-primary', 'bg-primary/5'));
btn.classList.add('border-primary', 'bg-primary/5');
state.selectedTimeSlot = btn.getAttribute('data-time');
});
});
}
// 获取日期字符串
function getDateString(daysOffset) {
const date = new Date();
date.setDate(date.getDate() + daysOffset);
const month = date.getMonth() + 1;
const day = date.getDate();
const weekdays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const weekday = weekdays[date.getDay()];
return `${month}月${day}日 ${weekday}`;
}
// 初始化支付页面
function initPaymentPage() {
const worker = state.selectedWorker;
elements.paymentAvatar.src = worker.avatar;
elements.paymentName.textContent = worker.name;
elements.paymentServiceType.textContent = worker.serviceType;
elements.paymentCity.textContent = state.currentCity;
elements.paymentDateTime.textContent = `${getDateString(Object.keys(worker.availableTimes).indexOf(state.selectedDate))} ${state.selectedTimeSlot}`;
elements.paymentServiceItem.textContent = state.selectedServiceItem;
elements.paymentAmount.textContent = state.selectedServicePrice;
// 计算总金额
const servicePrice = parseFloat(state.selectedServicePrice.replace('¥', ''));
const total = servicePrice + 20 - 10; // 服务费20元,优惠券10元
elements.totalPayment.textContent = `¥${total.toFixed(2)}`;
// 渲染支付方式
elements.paymentMethods.innerHTML = paymentMethods.map(method => `
<div class="payment-method flex items-center p-3 border ${state.selectedPaymentMethod === method.id ? 'border-primary bg-primary/5' : 'border-gray-200'} rounded-lg cursor-pointer transition-custom" data-id="${method.id}">
<i class="fa ${method.icon} ${method.color} text-xl mr-3"></i>
<span>${method.name}</span>
<i class="fa fa-check-circle ml-auto ${state.selectedPaymentMethod === method.id ? 'text-primary' : 'text-gray-300'}"></i>
</div>
`).join('');
// 支付方式选择事件
document.querySelectorAll('.payment-method').forEach(method => {
method.addEventListener('click', () => {
state.selectedPaymentMethod = parseInt(method.getAttribute('data-id'));
initPaymentPage(); // 重新渲染以更新选中状态
});
});
// 完成支付按钮事件
elements.completePaymentBtn.addEventListener('click', goToSuccessPage);
}
// 初始化成功页面
function initSuccessPage() {
const worker = state.selectedWorker;
// 生成随机订单号
const orderNum = 'OD' + Date.now() + Math.floor(Math.random() * 1000);
elements.orderNumber.textContent = orderNum;
elements.orderDateTime.textContent = `${getDateString(Object.keys(worker.availableTimes).indexOf(state.selectedDate))} ${state.selectedTimeSlot}`;
elements.orderWorkerName.textContent = worker.name;
// 返回首页按钮事件
elements.backToHomeBtn.addEventListener('click', () => {
// 重置状态
Object.keys(state).forEach(key => {
state[key] = key === 'selectedPaymentMethod' ? 1 : '';
});
goToCityPage();
});
}
// 页面导航
function showPage(pageId) {
// 隐藏所有页面
document.querySelectorAll('.page').forEach(page => {
page.classList.add('hidden');
});
// 显示目标页面
const targetPage = document.getElementById(pageId);
targetPage.classList.remove('hidden');
// 添加动画效果
targetPage.classList.add('page-enter');
setTimeout(() => {
targetPage.classList.add('page-enter-active');
}, 10);
setTimeout(() => {
targetPage.classList.remove('page-enter', 'page-enter-active');
}, 300);
// 滚动到顶部
window.scrollTo(0, 0);
}
// 导航到城市页面
function goToCityPage() {
showPage('cityPage');
elements.backBtn.classList.add('hidden');
}
// 导航到服务列表页面
function goToServiceListPage() {
showPage('serviceListPage');
elements.backBtn.classList.remove('hidden');
initServiceListPage();
}
// 导航到服务详情页面
function goToServiceDetailPage() {
showPage('serviceDetailPage');
elements.backBtn.classList.remove('hidden');
initServiceDetailPage();
}
// 导航到预约时间页面
function goToBookingTimePage() {
showPage('bookingTimePage');
elements.backBtn.classList.remove('hidden');
initBookingTimePage();
}
// 导航到支付页面
function goToPaymentPage() {
showPage('paymentPage');
elements.backBtn.classList.remove('hidden');
initPaymentPage();
}
// 导航到成功页面
function goToSuccessPage() {
showPage('successPage');
elements.backBtn.classList.add('hidden');
initSuccessPage();
}
// 返回按钮事件
elements.backBtn.addEventListener('click', () => {
// 判断当前显示的页面,返回上一级
if (!elements.serviceListPage.classList.contains('hidden')) {
goToCityPage();
} else if (!elements.serviceDetailPage.classList.contains('hidden')) {
goToServiceListPage();
} else if (!elements.bookingTimePage.classList.contains('hidden')) {
goToServiceDetailPage();
} else if (!elements.paymentPage.classList.contains('hidden')) {
goToBookingTimePage();
}
});
// 初始化应用
function initApp() {
initCityPage();
goToCityPage();
}
// 启动应用
document.addEventListener('DOMContentLoaded', initApp);
</script>
</body>
</html>







更多推荐


所有评论(0)