尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

美业微信小程序预约源码:含完整闭环与支付预留

美业微信小程序预约源码:含完整闭环与支付预留 简介这是一套面向美容美发行业商家与微信小程序开发者的在线预约系统源码解决传统门店预约效率低、客户流失率高、服务管理粗放等痛点适用于中小型美业机构快速部署自有预约服务。资源共67个文件涵盖12个JS逻辑层文件、12个WXSS样式文件、11个WXML视图文件、15个JSON配置与数据文件以及PNG图标、LICENSE协议等完整支撑小程序前端渲染、用户交互、服务调度与基础配置压缩包仅1.64MB轻量易集成。已有1337人学习下载说明其在实战落地中具备较高参考价值。开发者可直接运行调试快速掌握预约流程服务选择→技师匹配→时段确认→订单生成、微信支付对接、用户登录态管理及后台数据结构设计目录结构清晰pages下分模块组织login/register/order/proDetail等app.json与project.config.json配置完备便于二次定制品牌视觉与业务规则。1. 这不是“套模板”而是一套能跑通预约闭环的微信小程序源码你拿到的美容美发在线预约微信小程序源码.zip不是那种改个 logo 就叫“可商用”的 Demo 级项目。它真实包含从用户打开小程序 → 查看门店/技师 → 选择服务与时段 → 提交预约 → 支付v3 接口预留→ 后台管理订单的完整链路且所有页面均基于微信原生框架构建无第三方跨端框架封装痕迹。项目结构清晰对应微信官方推荐的app.jsapp.jsonpages/目录规范project.config.json中已预设开发者工具基础配置sitemap.json显式声明了可被微信搜索收录的页面路径——这意味着它不是“写完就扔”的练习代码而是按生产环境标准组织的、可直接部署上线的最小可行系统MVP。适合两类人一是中小型美业门店老板想快速拥有自己的预约入口无需招前端二是刚入行的小程序开发者需要一个结构完整、功能闭环、无冗余依赖的真实项目来拆解学习——尤其适合练手「预约冲突校验」「多角色权限隔离」「微信支付 v3 预留接入点」这三个高频实战难点。2. 源码结构解析与核心模块定位从app.json到pages/order/2.1 项目骨架app.json定义路由与窗口样式是启动逻辑的总开关app.json是整个小程序的“地图”和“门面”。打开该文件你会看到pages数组明确列出了 9 个页面路径按访问顺序排列pages/index/index首页、pages/login/login登录、pages/register/register注册、pages/technician/technician技师列表、pages/proDetail/proDetail服务详情、pages/order/order预约下单、pages/my/my个人中心、pages/reset/reset密码重置、pages/start/start启动页。这种顺序并非随意它直接影响微信小程序的页面栈行为和 tabBar 的默认选中项。特别注意tabBar配置中list仅包含index、order、my三个页面说明该项目采用“首页预约中心我的”三栏导航符合美业用户高频操作路径找服务→下单→查记录。window节点下navigationBarTitleText统一设为“美丽预约”navigationStyle为default表明未自定义导航栏直接复用微信原生标题栏——这是降低兼容性风险的稳妥做法也意味着后续若需修改顶部导航栏高度或添加自定义按钮必须通过wx.setNavigationBarColor或wx.setNavigationBarTitle动态控制而非在app.json中硬编码。提示sitemap.json中rules数组将index、proDetail、technician设为allow说明这三页内容允许被微信搜索抓取。若你上线后发现小程序搜不到第一检查点就是此处是否误删或配错路径。2.2 页面级逻辑以pages/order/order.js为例拆解预约核心流程预约下单页order.js是业务中枢其onLoad生命周期函数执行三步关键初始化// pages/order/order.js Page({ data: { serviceId: , technicianId: , selectedTime: , isSubmitting: false }, onLoad(options) { // 1. 获取上一页传来的服务ID与技师ID this.setData({ serviceId: options.serviceId || , technicianId: options.technicianId || }); // 2. 调用云函数获取该技师当日可预约时段关键避免前端硬编码时间 wx.cloud.callFunction({ name: getAvailableTimes, data: { technicianId: this.data.technicianId } }).then(res { this.setData({ timeSlots: res.result.data || [] }); }).catch(err { console.error(获取时段失败, err); wx.showToast({ title: 时段加载失败, icon: none }); }); // 3. 初始化日期选择器默认为今日 const today new Date(); this.setData({ date: ${today.getFullYear()}-${String(today.getMonth() 1).padStart(2, 0)}-${String(today.getDate()).padStart(2, 0)} }); }, // 用户点击时段后的处理 selectTime(e) { const time e.currentTarget.dataset.time; this.setData({ selectedTime: time }); }, // 提交预约 submitOrder() { if (!this.data.selectedTime) { wx.showToast({ title: 请选择预约时间, icon: none }); return; } this.setData({ isSubmitting: true }); // 构造预约数据并调用云函数提交 const orderData { serviceId: this.data.serviceId, technicianId: this.data.technicianId, date: this.data.date, time: this.data.selectedTime, userId: wx.getStorageSync(userId) // 从本地缓存读取用户ID }; wx.cloud.callFunction({ name: createOrder, data: orderData }).then(res { if (res.result.success) { wx.showToast({ title: 预约成功, icon: success }); setTimeout(() wx.navigateBack(), 1500); } else { wx.showToast({ title: res.result.message || 预约失败, icon: none }); } }).catch(err { wx.showToast({ title: 网络错误请重试, icon: none }); }).finally(() { this.setData({ isSubmitting: false }); }); } });这段代码揭示了三个关键设计点参数传递options.serviceId和options.technicianId来自navigator组件的url属性如navigator url/pages/order/order?serviceId101technicianId205这是小程序页面间传参的标准方式时段动态生成getAvailableTimes云函数负责查询数据库中该技师在指定日期的已预约记录排除冲突时段后返回可用列表避免前端静态写死导致超约状态防重复提交isSubmitting数据绑定到按钮disabled属性配合finally清除状态防止用户连续点击触发多次请求。2.3 用户体系login.js与register.js如何对接微信授权登录页login.js并非传统账号密码模式而是深度集成微信wx.loginwx.getUserProfile替代已废弃的wx.getUserInfo// pages/login/login.js Page({ data: { hasUserInfo: false }, onShow() { // 检查本地是否已有用户信息避免重复授权 const userInfo wx.getStorageSync(userInfo); if (userInfo userInfo.nickName) { this.setData({ hasUserInfo: true }); wx.switchTab({ url: /pages/index/index }); } }, getUserProfile() { // 弹出授权弹窗获取用户昵称头像 wx.getUserProfile({ desc: 用于完善会员资料 }).then(res { const userInfo res.userInfo; // 调用云函数将用户信息存入数据库并返回唯一 openid wx.cloud.callFunction({ name: registerUser, data: { userInfo } }).then(res { wx.setStorageSync(userInfo, userInfo); wx.setStorageSync(userId, res.result.userId); // 存储业务侧用户ID this.setData({ hasUserInfo: true }); wx.switchTab({ url: /pages/index/index }); }); }).catch(err { console.log(用户拒绝授权, err); wx.showToast({ title: 授权失败无法登录, icon: none }); }); } });这里的关键在于registerUser云函数的实现逻辑它接收userInfo对象调用wx.cloud.database().collection(users).add()插入新记录并利用event.userInfo.openid云函数上下文自动注入作为主键关联微信身份。userId字段是业务自增 ID如U20240001与openid分离为后续对接短信、邮箱等多渠道登录预留扩展空间。wx.setStorageSync缓存userInfo和userId使后续页面如order.js能直接读取无需反复调用授权接口。3. 后端能力落地云函数与数据库设计如何支撑预约业务3.1 云函数命名规范与职责划分getAvailableTimes与createOrder的协作逻辑项目中云函数目录结构为cloudfunctions/getAvailableTimes和cloudfunctions/createOrder严格遵循单一职责原则。getAvailableTimes函数的核心逻辑是查询orders集合中指定技师在某日的已预约记录并计算空闲时段// cloudfunctions/getAvailableTimes/index.js const cloud require(wx-server-sdk); cloud.init(); const db cloud.database(); exports.main async (event, context) { const { technicianId, date } event; try { // 查询该技师当日所有已预约订单 const res await db.collection(orders).where({ technicianId: technicianId, date: date, status: db.command.neq(cancelled) // 排除已取消订单 }).field({ time: true }).get(); // 假设营业时间为 9:00-18:00每单耗时 60 分钟则时段为 [09:00, 10:00, ..., 17:00] const allSlots Array.from({ length: 10 }, (_, i) ${String(9 i).padStart(2, 0)}:00 ); // 过滤掉已被占用的时段 const bookedSlots res.data.map(item item.time); const availableSlots allSlots.filter(slot !bookedSlots.includes(slot)); return { success: true, data: availableSlots }; } catch (err) { console.error(查询时段失败, err); return { success: false, message: 服务器繁忙 }; } };此函数的关键点在于时间粒度控制硬编码allSlots生成 9:00–17:00 的整点时段实际项目中应从technicians集合读取该技师的workHours字段如[09:00-12:00, 13:30-18:00]再动态生成此处为简化演示状态过滤status: db.command.neq(cancelled)确保已取消订单不占用时段这是预约系统防超约的核心规则返回结构统一{ success: boolean, data: array }格式前端order.js可直接解构使用。createOrder函数则负责事务性写入先校验时段是否仍可用二次防冲突再插入订单并更新技师当日预约计数// cloudfunctions/createOrder/index.js exports.main async (event, context) { const { serviceId, technicianId, date, time, userId } event; const wxContext cloud.getWXContext(); try { // 1. 再次检查时段是否可用防止并发场景下瞬间被抢 const checkRes await db.collection(orders).where({ technicianId, date, time, status: db.command.neq(cancelled) }).count(); if (checkRes.total 0) { return { success: false, message: 该时段已被预约请重新选择 }; } // 2. 插入新订单 const orderData { _id: db.collection(orders).doc().id, // 自动生成唯一ID serviceId, technicianId, date, time, userId, status: pending, // 初始状态为待确认 createTime: new Date(), openid: wxContext.OPENID // 关联微信身份 }; await db.collection(orders).add({ data: orderData }); // 3. 更新技师统计可选用于后台报表 await db.collection(technicians).doc(technicianId).update({ data: { bookedCount: db.command.inc(1) } }); return { success: true, orderId: orderData._id }; } catch (err) { console.error(创建订单失败, err); return { success: false, message: 系统错误请稍后重试 }; } };注意db.command.inc(1)是原子操作避免并发更新导致计数错误。若你的业务需要更精细的统计如按服务类型分计应在orders集合中增加serviceType字段并在更新时按条件累加。3.2 数据库集合设计services、technicians、orders三表关系项目数据库包含三个核心集合其字段设计直指美业预约痛点集合名关键字段说明services_id,name,duration,price,imageUrl,categoryduration单位为分钟如90表示 1.5 小时category用于首页分类筛选如剪发,染烫technicians_id,name,avatarUrl,level,workHours,bio,bookedCountworkHours为字符串数组[09:00-12:00, 13:30-18:00]bookedCount实时统计当日预约量orders_id,serviceId,technicianId,date,time,userId,status,createTime,openidstatus枚举值pending待确认、confirmed已确认、cancelled已取消、completed已完成这种设计使得pages/technician/technician.js可通过db.collection(technicians).where({ category: 剪发 })快速筛选技师pages/proDetail/proDetail.js能根据serviceId关联查出对应技师列表形成清晰的数据流向。所有集合均启用索引orders集合对(technicianId, date, status)建复合索引大幅提升getAvailableTimes查询效率。4. 个性化定制实操修改启动页、更换主题色与替换 Logo 的具体步骤4.1 修改刚进入的加载页面替换pages/start/start.wxml与start.wxss小程序首次打开时显示的启动页由pages/start/start.wxml控制。默认内容是一个居中image组件加载images/logo.png注意源码中实际为image1.png路径需核对!-- pages/start/start.wxml -- view classcontainer image src/images/image1.png classlogo modeaspectFit/image text classloading-text加载中.../text /view要更换 Logo只需两步将新图片建议尺寸 300×300px格式 PNG放入images/目录命名为logo.png修改start.wxml中src属性为/images/logo.png在start.wxss中调整.logo样式控制大小与位置/* pages/start/start.wxss */ .container { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; background-color: #f8f8f8; } .logo { width: 120rpx; /* 注意单位是 rpx适配不同屏幕 */ height: 120rpx; margin-bottom: 40rpx; } .loading-text { font-size: 28rpx; color: #666; }提示height: 100vh在部分安卓机型上可能失效更稳妥写法是min-height: 100vh并确保父容器page无overflow: hidden干扰。4.2 全局主题色修改通过app.wxss统一控制主色调项目主色调定义在app.wxss的:root伪类中/* app.wxss */ :root { --primary-color: #ff6b6b; /* 主色珊瑚红 */ --secondary-color: #4ecdc4; /* 辅色青绿色 */ --text-color: #333; /* 文字色 */ --border-color: #e0e0e0; /* 边框色 */ }所有页面组件通过color: var(--primary-color)调用该变量。修改主题色只需更改--primary-color的值想用莫兰迪灰改为#8d99ae想用高级黑金改为#222并同步调整--secondary-color为#d4af37修改后需全局搜索var(--primary-color)检查是否有硬编码颜色值如#ff6b6b遗漏确保风格统一。4.3 替换顶部导航栏文字与背景app.json与pages/index/index.js协同控制微信原生导航栏文字由app.json的window.navigationBarTitleText统一设置但首页index需要突出品牌名因此pages/index/index.js在onLoad中动态覆盖// pages/index/index.js Page({ onLoad() { wx.setNavigationBarTitle({ title: XX美发沙龙 }); // 覆盖 app.json 设置 wx.setNavigationBarColor({ frontColor: #ffffff, // 文字颜色白 backgroundColor: #ff6b6b, // 背景颜色主色 animation: { duration: 400, timingFunc: easeIn } }); } });此写法确保首页导航栏为品牌色其他页面如order、my仍沿用app.json的默认设置。若需全站统一直接修改app.json的window节点即可。5. 支付功能对接与调试微信小程序支付 v3 接口的预留接入点5.1 源码中支付模块的现状pages/order/order.js已预留payOrder方法占位当前order.js中submitOrder成功后并未触发支付而是直接跳转成功页。支付逻辑被抽象为独立方法payOrder但未被调用// pages/order/order.js片段 payOrder(orderId) { // TODO: 调用微信支付 v3 接口 console.log(准备支付订单:, orderId); // 此处应调用云函数 getPayParams 获取 prepay_id 等参数 // 然后执行 wx.requestPayment }, // submitOrder 方法末尾注释提示 // ... // wx.showToast({ title: 预约成功, icon: success }); // this.payOrder(res.result.orderId); // ← 解开此行注释并实现 payOrder5.2 接入微信支付 v3 的四步实操指令要启用支付需按顺序执行以下操作需商户资质步骤 1在云函数中实现getPayParams新建云函数cloudfunctions/getPayParams其核心是调用微信支付 v3 下单接口// cloudfunctions/getPayParams/index.js const cloud require(wx-server-sdk); const axios require(axios); // 需在云函数 package.json 中安装 axios cloud.init(); exports.main async (event, context) { const { orderId, totalFee } event; // totalFee 单位为分 const appId your-app-id; // 替换为你的小程序 AppID const mchId your-mch-id; // 替换为你的微信支付商户号 const apiKey your-api-key-v3; // 替换为你的 APIv3 密钥 try { // 1. 构造请求参数 const timestamp Math.floor(Date.now() / 1000); const nonceStr Math.random().toString(36).substr(2, 15); const body 美发预约服务; const outTradeNo ORDER${timestamp}${Math.floor(Math.random() * 1000)}; // 2. 调用微信统一下单接口需 HTTPS const response await axios.post( https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi, { appid: appId, mchid: mchId, description: body, out_trade_no: outTradeNo, notify_url: https://yourdomain.com/api/pay/notify, // 支付结果回调地址 amount: { total: totalFee, currency: CNY }, payer: { openid: context.OPENID } // 用户 openid }, { headers: { Content-Type: application/json, Authorization: WECHATPAY2-SHA256-RSA2048 ${generateAuthHeader()} // 签名头需实现 generateAuthHeader } } ); // 3. 解析返回的 prepay_id 并构造支付参数 const { prepay_id } response.data; const payParams { appId, timeStamp: timestamp.toString(), nonceStr, package: prepay_id${prepay_id}, signType: RSA, paySign: generatePaySign(appId, timestamp, nonceStr, prepay_id${prepay_id}, apiKey) }; return { success: true, payParams }; } catch (err) { console.error(支付参数获取失败, err.response?.data || err); return { success: false, message: 支付初始化失败 }; } }; // 签名生成函数简化版实际需用 node-forge 或 crypto 模块 function generatePaySign(appId, timeStamp, nonceStr, packageStr, apiKey) { // 此处需实现 RSA 签名算法细节略 return fake-signature; }注意generateAuthHeader和generatePaySign需使用微信官方 SDK 或自行实现 RSA 签名密钥需妥善保管严禁硬编码在云函数中。步骤 2在order.js中调用并执行支付解开submitOrder中的注释并补充payOrder实现payOrder(orderId) { wx.cloud.callFunction({ name: getPayParams, data: { orderId, totalFee: 19900 } // 示例199元 19900分 }).then(res { if (res.result.success) { wx.requestPayment({ ...res.result.payParams, success: (payRes) { console.log(支付成功, payRes); wx.showToast({ title: 支付成功, icon: success }); // 更新订单状态为 confirmed wx.cloud.callFunction({ name: updateOrderStatus, data: { orderId, status: confirmed } }); }, fail: (err) { console.log(支付失败, err); wx.showToast({ title: 支付失败, icon: none }); } }); } }); }步骤 3配置支付域名与证书登录 微信支付商户平台 完成在「产品中心」→「开发配置」中将云函数所在域名如xxx.tcb.qcloud.ltd加入「JSAPI 支付」的「支付授权目录」在「账户中心」→「API安全」中下载 APIv3 密钥并上传至云函数环境变量非代码中配置「APIv3密钥」和「证书」确保云函数能调用 v3 接口。步骤 4测试与验证使用微信开发者工具「真机调试」选择已绑定商户号的测试账号触发支付后检查云函数日志是否返回prepay_id若wx.requestPayment报错requestPayment:fail invalid signature检查签名算法与密钥是否匹配支付成功后务必验证updateOrderStatus云函数是否将订单status更新为confirmed否则影响后续服务履约。完成以上四步支付功能即正式接入。源码中所有占位逻辑均已就绪你只需填充密钥与配置无需重构页面结构。本文还有配套的精品资源点击获取
返回列表