尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

多场馆预约小程序系统搭建全攻略:基于FastAdmin的部署与二次开发

多场馆预约小程序系统搭建全攻略:基于FastAdmin的部署与二次开发 简介这是一套面向场馆运营方与中小型SaaS服务商的多场馆预约系统完整源码基于FastAdminThinkPHPUniapp技术栈构建专为解决体育场馆、共享办公、自助酒店等实体场所的场地预约、在线支付、核销管理等数字化运营痛点。资源包含后台管理系统、微信小程序前端及全套搭建教程支持私有化独立部署满足对数据安全与业务自主性的高要求。压缩包共2000个文件含1682个JS逻辑脚本、171个HTML页面模板、70个Vue组件、65个Markdown说明文档及1个SQL数据库初始化文件整体大小20.66MB结构清晰、模块解耦便于二次开发与场景适配。目前已有87人学习下载提供无加密全源码、可运行的前后端工程、关键配置说明及安装引导页如install.html、config.html等开发者可快速验证登录流程、支付对接与核销闭环是深入理解预约类SaaS系统架构与实战落地的优质参考样本。 做场地预约类的小程序市面上成套源码不少但真正能落地、能跑通支付和核销闭环的其实不多。最近我在一家运动场馆运营方这边完整部署了一套基于 FastAdmin 的多场馆预约系统含小程序端、管理后台和全套搭建流程前后花了大概两天时间把环境、支付、核销全部调通。这篇就把整个拆解过程、核心设计、部署细节和踩过的坑一次性写出来给正在选型或准备自己搞一套场馆预约系统的朋友做个参考。这套东西解决的核心问题其实很典型多场馆怎么统一管理、场地怎么按时间段排期、用户怎么完成预约和支付、线下怎么核销、以及商家后台怎么处理订单和退款。如果你正要做一个羽毛球馆、篮球馆、共享会议室、甚至自习室的预约小程序这套源码的思路完全可以直接借鉴。1. 项目整体设计与技术选型拆解1.1 核心需求解析先把这个项目的业务模型讲清楚。它叫“多场馆预约系统”核心关键词在“多场馆”三个字。很多初做预约系统的开发者容易把思路做成“单场馆场地”也就是一个门店下面挂几个场地时分复用。但这套源码做的是两级维度多场馆多个物理门店和多场地每个场馆下多个可预约单元。举个例子一个连锁羽毛球品牌有 3 家门店每家门店有 6 片场地每片场地按小时切分成多个场次。用户在小程序里先选门店再选日期和场地系统自动把不可约的时段置灰用户选一个或多个连续时段提交订单并支付到店后由前台出示核销码或者让用户在小程序里自助核销。这样一套流程走下来才叫完整的预约闭环。除了预约主流程后台还需要处理这些基础数据会员管理、场次模板、节假日特殊安排、押金规则、优惠券、平台抽成结算、操作员权限以及提现退款。这套源码在 FastAdmin 框架上做了一层业务封装恰好覆盖了其中大部分对于中小型场馆运营方来说完全够用。1.2 为什么选 FastAdmin 做底层FastAdmin 是目前国内中小项目里出镜率相当高的 PHP 后台框架基于 ThinkPHP 5 Bootstrap RequireJS。有人可能会说它“不够现代”但在实际的场馆管理业务里选它做底层的理由其实很实在。第一后台权限管理是现成的。场馆运营涉及的角色不少超级管理员看全局场馆经理只管自己场馆的数据前台员工只管核销和订单操作。FastAdmin 自带完整的 RBAC 权限体系直接分配角色和规则即可不需要自己从零开发权限模型。第二后台 CRUD 生成效率极高。FastAdmin 的命令行可以一键生成控制器、模型、视图和 JS 文件场馆、场地、场次这些基础资料的表单页面基本都是生成后微调的两天之内把后台业务页面搭完完全不是夸张。对比用 Vue 全家桶从零写一套后台FastAdmin 在“能快速出活”这件事上优势确实明显。第三插件机制成熟。FastAdmin 有一套在线插件市场支付插件、短信插件、小程序登录插件都有现成方案。这套预约系统的支付和登录就是依靠 FastAdmin 的插件生态串起来的省去了很多底层对接工作。1.3 技术栈与模块划分整个项目分两大端FastAdmin 后台管理端 微信小程序用户端。后台端核心模块场馆管理场馆列表、地址、营业时间、轮播图场地管理场地名称、类型、容纳人数、排序、状态场次模板按星期设置可预约时段可配置多套模板按日期生效订单管理全部订单、待支付、已支付待核销、已完成、已取消、售后核销管理核销码、核销记录、核销员对应关系会员管理OpenID、手机号、余额、积分、消费记录财务管理交易流水、提现申请、平台与场馆结算小程序端核心模块微信一键登录场馆列表与场地详情日期 场次选择器订单确认与微信支付订单列表与订单详情核销码展示个人中心和会员信息后台 API 与小程序之间通过application/api模块下的 JSON 接口通信接口统一走 HTTPS返回码和数据格式做了封装小程序端通过wx.request统一访问。2. 核心数据表设计与预约状态机2.1 数据表关系梳理这套系统的数据表大概有十几张核心的几张关系如下场馆表venue一个场馆有多条场地记录场地表site一个场地属于一个场馆场地场次表site_schedule一个场地在某个日期下存在多个可预约时段订单表order一个订单关联一个场地 一个场次组合核销记录表consume_record一个订单最多对应一条核销成功记录这种设计最关键的关联点在于场次表实际上就是库存表。每个可预约时段在某一天就是一条库存记录预约成功后该时段的status从可约变为锁定再配合数据库唯一索引保证同一时刻不会两个人同时抢到同一个时段。2.2 场次库存的并发控制这是整个预约系统最容易出bug的地方。如果直接在代码里先查status 1再更新status 2高并发下绝对会超卖。原因很简单两个请求同时读到可约状态然后先后执行更新就会产生一单变两单的问题。这套系统在数据层做了一个很好的兜底在site_schedule表上对site_id schedule_date start_time三个字段建立了联合唯一索引并且在更新库存时用了一条带条件的 SQLUPDATE site_schedule SET status 2, order_id {$orderId} WHERE id {$scheduleId} AND status 1然后通过affected_rows判断是否更新成功。如果影响行数为 0说明这个时段已经被别人抢了代码直接返回“该时段已被预约”这条记录不会被再次更新。数据层的唯一约束 条件更新双重保障了并发安全。2.3 预约、支付、核销三条状态流转这套系统的状态机拆成三段来看理解起来会清晰很多。预约链路用户选择场馆、场地、日期、时段创建订单状态为待支付同时锁定场次此时场次状态变为锁定中不再对外展示如果 15 分钟内未支付系统自动释放场次并取消订单支付链路小程序端调起微信支付支付成功微信服务器异步通知后台后台验签并更新订单状态为待核销同时生成唯一核销码核销链路用户到店出示核销码商家在后台输入核销码或者扫描二维码系统校验核销码状态从待核销变为已核销记录核销员、核销时间、核销门店订单生命周期结束这三条链路在设计上相互独立又彼此关联。比如支付回调是异步的不能依赖支付结果同步去改订单状态必须等回调完成后才把订单推到“待核销”阶段。曾经遇到过微信支付回调延迟的情况用户那边已经支付成功后台订单还挂着“待支付”后来加了一个主动查询订单状态的兜底接口才解决。3. 本地环境搭建与 FastAdmin 部署全流程3.1 环境准备我用的这套组合部署这套源码我用的本地环境组合是 PHP 7.4 MySQL 5.7 NginxFastAdmin 官方推荐是 PHP 7.x 加 MySQL 5.6 以上实测 7.4 兼容性很好换成 PHP 8.0 时部分旧插件会报语法兼容问题所以建议先按 7.4 来。Windows 上我直接用了 phpstudy 集成环境macOS 上可以用 MAMP 或者自己 brew 装一套。关键是 PHP 需要安装这些扩展fileinfo、redis、bcmath、openssl、pdo_mysql、curl。特别是fileinfoFastAdmin 上传附件时依赖它没开的话后台附件管理会一直报错。bcmath扩展很容易被忽略但在支付金额计算时非常重要。微信支付金额单位是分和元互相转换时如果用浮点数直接乘除会产生精度问题用bcmath的bcmul和bcdiv就能干净地处理。我在项目里所有涉及金额的地方都改成了字符串运算避免浮点误差。3.2 FastAdmin 安装与目录结构FastAdmin 的安装方式有两种一种是从官网下载完整包另一种是下载源码后通过命令行安装。这套预约系统源码自带完整后台代码安装起来更简单流程基本是将源码解压到站点根目录如www/reservation访问http://你的域名/install.php按向导填写数据库信息和管理员账号安装完成后删除install.php后台访问入口是http://你的域名/admin.php用默认管理员账号密码登录后台在“常规管理 → 系统配置”里修改站点信息。部署路径这里有个小细节源码里的 API 文件、后台文件、小程序代码目录结构是分开的小程序端需要单独用微信开发者工具打开而后台源码才是 PHP 工程根目录。建议给后台单独绑定一个域名比如admin.xxx.com前端业务接口用api.xxx.com这样在小程序后台配置合法域名时更方便也不容易和 web 端混在一起。3.3 安装过程中最容易被卡住的几个问题第一次装 FastAdmin 相关源码大概率会遇到下面几个问题第一install.php自动检测显示某目录不可写。FastAdmin 安装时要求runtime、public/uploads、application/database.php等目录具备写入权限。Windows 下 phpstudy 一般是Everyone用户权限不足在目录上右键 → 属性 → 安全 → 编辑 → 添加Everyone完全控制即可。Linux 服务器上直接chmod -R 777 runtime public/uploads是懒人做法安全要求高的环境可以细化到www:www用户组。第二后台执行php think命令时提示“请在网站根目录运行”。FastAdmin 的命令行操作需要先cd到站点根目录再执行php think不要在子目录里执行。另外 Windows 下用 phpstudy 时php命令可能没进系统环境变量用 phpstudy 自带 PHP 的完整路径执行或者先设置环境变量。第三登录后台后报Class app\common\library\database not found一类错误。这通常是因为 PHP 版本不对某些类文件用了 PHP 7.4 不支持的新语法。把 PHP 版本切回 7.4 基本能解决。问题排查的经验先放到后面统一讲这里先把整个部署过程跑通。3.4 数据库导入与初始配置源码包里一般会附带一份 SQL 文件比如reservation.sql。导入时要注意 utf8mb4 编码和表前缀。FastAdmin 默认表前缀是fa_如果源码里的数据表用的是别的前缀比如v2_需要同步修改application/database.php里的prefix配置项否则后台会一直出现“数据表不存在”的报错。导入完成后进入后台第一件事是检查系统配置里几个关键项站点域名填当前后台访问域名API 地址填小程序端接口的域名前缀比如https://api.xxx.com/index.php/api小程序 AppID/AppSecret在微信公众平台申请好小程序后填入微信支付商户号、API 密钥支付配置必须填完整如果后台代码是独立域名部署API 地址还需要注意跨域问题。FastAdmin 在application/api模块里已经封装好跨域请求头一般在公共控制器里直接处理了不需要额外配置。4. 小程序端从登录到支付核销的实现细节4.1 小程序项目结构与页面路由规划小程序端如果是原生微信小程序页面结构一般是这样的pages/ ├── index/ 首页 → 场馆列表 ├── venue/ 场馆详情 → 场地列表、场次时间轴 ├── booking/ 预约确认页 → 选择场次、提交订单 ├── order/ 订单列表 ├── order-detail/ 订单详情 → 核销码展示 ├── mine/ 个人中心这套系统的小程序端另外用到了自定义导航栏因为要在首页嵌入普通导航栏展示搜索框需要注意在app.json里配置navigationStyle: custom后页面顶部要手动适配状态栏高度。获取状态栏高度的方法很简单const systemInfo wx.getSystemInfoSync() const statusBarHeight systemInfo.statusBarHeight设置自定义导航栏时顶部胶囊按钮的位置一般用wx.getMenuButtonBoundingClientRect()获取用来计算导航栏高度避免页面元素被胶囊按钮遮挡。4.2 微信登录与 Token 鉴权流程小程序的登录流程现在主流方案是wx.login获取 code然后后端调微信接口换 openid再返回自定义 token。这套源码的做法是用户进入小程序wx.login获取 code调后端接口登录/微信传 code 和用户信息后端用 code 换 openid查询会员表首次登录则自动创建会员返回 user_id 和 token小程序将 token 存入wx.setStorageSync后续所有请求在 header 中携带token字段。这里有一个很繁琐但必须处理的事token 过期后接口会返回 401小程序端需要统一拦截并重新走登录逻辑。我在app.js里封装了一个request公共方法在success回调里判断 HTTP 状态码如果是 401 就跳转到登录页重新wx.login避免用户操作到一半才发现 token 失效。4.3 场地选择器与预约场次的交互设计场地预约的交互是这个项目里最核心的部分。我在做的时候参考了主流的在线订场 App把页面横切成上下两块上面是场地切换栏一片场地一个 tab下面是当日场次时间轴。时间轴中每个场次格子有两种颜色可约和不可约。用户点击某个场地下的某个时段如果时段可约就跳到确认页不可约就弹一个轻提示说明原因。场次数据从接口一次性拉回来按场地分组返回{ code: 1, data: { site_id: 12, date: 2024-06-15, schedule_list: [ {id: 101, start_time: 09:00, end_time: 10:00, status: 1, price: 60.00}, {id: 102, start_time: 10:00, end_time: 11:00, status: 0, price: 60.00} ] } }status 1表示可约status 0表示不可约。不可约的包括已经被别人约走和系统后台手动锁定的时段。前端在渲染时对status 0的格子增加一个半透明遮罩和“已满”标签。单选框组件本来也可以用于场地切换但这个场景下一屏显示多个场地时用滑动 tab 切换更直观我最终用了scroll-view横向滚动实现。4.4 微信支付的完整对接细节微信支付是这套源码里比较完整的部分值得单独拆开讲。整体流程是小程序端拿订单号调后端创建支付参数接口后端用商户号和 API 密钥生成微信支付预支付单返回小程序端timeStamp、nonceStr、package、signType、paySign五个参数小程序端调用wx.requestPayment拉起收银台用户输入密码微信客户端弹出支付结果后台收到微信异步回调更新订单状态。生成支付参数的核心代码逻辑在application/api/controller/Pay.php里关键点是签名算法。微信支付签名用的是 MD5把所有参与签名的参数按照字典序拼接最后加上key$signStr appIdxxxnonceStrxxxpackageprepay_idxxxsignTypeMD5timeStampxxxkey商户API密钥; $sign strtoupper(md5($signStr));这里最容易踩的坑是参数名不统一。前端传package时是prepay_idxxx这样完整的一段而某些封装库返回时少了prepay_id前缀导致微信提示package 参数格式错误。我在联调阶段调试了很久才定位到是这个原因后来统一在服务端拼接好完整参数前端只做透传问题就不再出现。支付回调处理同样要留意回调通知地址必须是 HTTPS 且公网可访问回调返回给微信的响应必须是正确的 XML 格式xmlreturn_code![CDATA[SUCCESS]]/return_codereturn_msg![CDATA[OK]]/return_msg/xml如果返回格式不对微信会持续通知每次间隔一段时间重试直到商户返回成功。另外支付回调还需要做幂等处理同一个订单的多次回调第二次起必须直接返回成功避免重复更新订单状态导致流水错误。4.5 核销功能实现与安全校验核销是预约系统区别于普通商城的关键环节。这套源码的核销有三种方式后台手动核销、扫码核销、小程序端游客核销我实际部署时重点调试的是后台扫码核销这一种。订单支付成功后会生成一个核销码这个核销码不能直接用订单编号因为太容易被伪造。源码里的做法是用订单号 随机数做了一次可逆加密生成一个 6 位数字码并存到consume_code字段中。为了安全核销码的有效期设置成订单支付后的 90 天内超过有效期系统自动拒绝核销。核销接口的逻辑是这样的输入核销码校验是否存在且有效校验订单当前状态是否为待核销校验核销员是否有该场馆的核销权限开启事务更新订单状态为已核销写入核销记录提交事务返回核销成功信息。整个过程相当于把线上预约和线下到场打通了。没有这套核销机制用户付了钱不到场场馆管理方根本不知道这个场地到底有没有人来这单到底算不算完成。核销数据也为后续做场馆运营分析提供了原始依据。5. 常见问题与排查技巧实录5.1 后台插件安装与 FastAdmin 版本兼容问题在部署这套预约系统时遇到过几次后台插件安装缓慢甚至安装失败的情况。FastAdmin 插件安装时报错请从官网渠道下载插件压缩包 (code:2)这个问题通常是因为服务器访问 FastAdmin 官方插件市场超时。解决办法是在后台“插件管理”里先把插件离线包下载下来再通过“导入”方式安装手动上传压缩包速度稳定可控。另外个别老插件在 PHP 8.0 环境下会出现兼容性错误比如类方法签名不一致、each()函数被移除等。最稳妥的方式是全部依赖 PHP 7.4 运行不要轻易升级。如果确实需要高版本 PHP先在测试环境把插件逐个过一遍再切正式线。5.2 小程序多场馆模式下地图组件与定位的兼容问题多场馆系统里场馆详情页一般要展示地图和定位信息。前期调研时也考虑过用腾讯地图或者高德地图组件但最终选择了微信自带的map组件搭配腾讯位置服务 API 实现场馆坐标展示。为什么不用其他地图组件因为微信小程序的map组件是原生组件性能和稳定性有保障支持markers标记、include-points自适应视野等能力完全够用。实际开发中地图组件在自定义导航栏页面偶发出现层级穿透的问题位置偏差明显。解决方案是给地图容器设置固定宽高并在外层加position: relative; z-index: 1保证层级正常。另外如果场馆数量少且分布固定也可以直接把坐标静态写在后台配置里省去地图 API 的调用成本。5.3 订单状态与支付回调的异步一致性运营中发现过一个典型问题用户在小程序端点击支付微信收银台显示支付成功但小程序订单列表仍显示“待支付”。排查后发现是开发阶段使用的回调地址是内网穿透临时地址微信回调请求没有正常到达导致后台根本没有收到支付成功通知。解决思路是在支付轮询上加了兜底逻辑支付页面打开期间每 3 秒主动调一次后端接口查询订单状态最长轮询 2 分钟。后端在处理查询时如果发现订单是待支付状态会主动向微信支付服务端发起“订单查询”请求确认是否已经支付成功如果成功则直接更新订单状态。这相当于支付回调之外的第二道保障联调阶段和正式运行阶段都很有用。5.4 并发预约场景下事务和锁的使用建议高并发场景下条件更新和事务配合才能保证数据一致。在更新场次状态时SQL 条件中带上status 1如果影响行数为 0 说明被别人抢先了此时就要回滚事务直接提示用户“该时段刚刚被预约了”。这里有个细节值得注意MySQL 默认隔离级别是REPEATABLE READ在高并发下事务 A 更新了某行数据且未提交事务 B 执行相同的更新 SQL 会被阻塞直到事务 A 提交或回滚。如果业务代码在更新后还执行了其他耗时操作事务就迟迟不提交后面的请求全部排队页面表现为“卡死”。解决方式是把事务范围缩小只在“更新场次状态 创建订单”这两个操作之间开启事务其他耗时操作放在事务外部。5.5 FastAdmin 后台自定义按钮和 Ajax 操作扩展FastAdmin 后台自带的表格操作按钮基本满足常规需求但在预约管理列表里需要加一些例如“锁定场地”“优先级调价”之类的自定义操作。FastAdmin 的自定义按钮扩展方式是在 table 初始化operate列中配置buttons并绑定事件{field: operate, title: __(操作), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate, buttons: [ { name: lock, title: 锁定, classname: btn btn-xs btn-warning btn-ajax, icon: fa fa-lock, url: reservation/site/lock, confirm: 确认锁定该场地吗, success: function (data, ret) { Layer.msg(ret.msg); table.bootstrapTable(refresh); } } ]}在控制器中写好lock方法使用$this-success或$this-error返回结果前端btn-ajax类会自动处理请求很是方便。这里是 FastAdmin 后台扩展的重点做二次开发时几乎每天都会用到。6. 二次开发方向与个人经验总结这套源码部署完之后我和场馆运营方一起梳理了接下来的迭代方向。几个比较明确的需求点在这里也分享出来给你参考。第一分时计价。目前的源码是按固定单价计费的但实际运营中通常工作日和周末价格不同热门时段比如晚上 7 点到 9 点会溢价淡季时段可以打折。计划把价格字段从场次表里拆出来独立成一份价格规则表按星期、时段、场地类型分别配置计算订单金额时走统一的价格引擎。第二会员卡和次卡。场馆类业务非常适合卖次卡用户先买 10 次卡每次预约扣一次次数不用每次下单都走支付。这个功能需要新增次卡表、用户次卡表、次卡核销扣减记录并在下单流程里增加“余额支付/次卡抵扣/微信支付”三种支付方式的兼容逻辑。第三平台与场馆分账。如果是做多商户平台而不是自营场馆每笔订单需要按一定比例分账给平台方和场馆方。可以利用支付成功回调里拿到的金额计算分成比例生成财务结算单并按周或按月生成结算报表这样平台方的财务才能对账。第四短信通知。目前预约成功和取消都是通过小程序订阅消息通知用户但很多用户不常打开小程序导致预约成功被忽略。接入短信服务商在关键节点发短信提醒虽然增加了成本但对提升到场率效果明显。我实际做下来最大的体会是这类预约系统的核心难点不在于页面多漂亮而在于数据一致性和支付链路这两个地方。建表时就把唯一约束设计好支付回调做幂等场次更新用条件更新和事务保护这三个点做到位系统就能稳定跑起来。另外就是任何改动都要先在测试环境验证尤其是支付、核销这种和钱相关的流程线上直接操作的风险太大。最后再分享一个小技巧FastAdmin 后台生成的 API 文档模块可以把小程序端的接口文档一并管理起来。每次修改接口后让运营方在后台就能看到最新的参数说明沟通成本能降不少。这套预约系统后续如果要做成 SaaS 产品向外出租这个模块可以直接变成客户自服务的一部分也算是一种扩展思路。本文还有配套的精品资源点击获取
返回列表