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

发布时间:2026/9/10 17:28:52

美业微信小程序预约源码:含完整闭环与支付预留 简介这是一套面向美容美发行业商家与微信小程序开发者的在线预约系统源码解决传统门店预约效率低、客户流失率高、服务管理粗放等痛点适用于中小型美业机构快速部署自有预约服务。资源共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否则影响后续服务履约。完成以上四步支付功能即正式接入。源码中所有占位逻辑均已就绪你只需填充密钥与配置无需重构页面结构。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/9/10 18:13:58

中文书目自动分类系统:BiLSTM+Attention实现92%准确率

1. 项目背景与核心价值中文书目自动分类系统是当前图书馆数字化建设中的关键技术痛点。传统人工分类方式存在效率低下、标准不统一等问题,而基于规则的系统又难以应对海量图书数据的分类需求。这个毕设项目正是瞄准了这一实际应用场景,采用机器学习技术实…

2026/9/10 18:13:58

python-dateutil报错排查:从环境错乱到依赖冲突的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 18:13:58

Docker容器技术栈:从核心组件到Kubernetes集成

1. 容器技术栈的组成与演进容器技术发展到今天已经形成了一个复杂的工具链生态。当我们运行docker run命令时,背后实际上有多个组件在协同工作。这些组件各自承担着不同的职责,却又紧密配合,共同构成了现代容器运行时的基础架构。在早期的Doc…

2026/9/10 18:08:58

多AI编程Agent难管理?T3 Code统一控制台让并行开发可控可回放

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码