基于Vue和Megalo的微信小程序台球管理系统实战拆解

发布时间:2026/9/15 12:54:29
基于Vue和Megalo的微信小程序台球管理系统实战拆解 简介基于微信小程序的台球管理系统毕业设计项目面向高校计算机专业学生可作毕业设计参考也可用于学习小程序开发。系统围绕台球厅日常运营的会员管理、预约登记、计费结算、库存盘点与报表统计等核心模块展开并提供优惠活动、桌台状态管理等实用功能覆盖前台预约到后台管理的主要流程。压缩包共54个文件以25个页面组件、6个逻辑脚本、5个样式文件为主配有若干图片与说明文档整体约366KB结构清晰便于快速查看。目前已有180人学习/下载。项目提供可直接运行的微信小程序前端工程包含页面展示、状态管理、工具函数与静态资源能帮助读者理解工程项目结构掌握数据交互和跨端框架开发思路并借助说明文档快速定位核心代码适合二次开发及答辩准备。1. 台球管理系统毕业设计为什么值得拆开读一遍微信小程序的毕设项目里管理系统是最容易做成摆设的方向界面抄后台模板逻辑只有增删改查。这套基于微信小程序的台球管理系统不是那个路子。前端跑在微信小程序里用的是 Vue Megalo 编译方案会员登录、桌台预约、分钟级计费、待支付订单汇总是一条完整闭环工程上环境变量、store、请求封装也都是正经 npm 项目的做法不是单页堆代码。适合两类人管理系统类毕业设计的学生照着抄业务设计和目录组织想给台球厅做轻量运营工具的一线开发者从中提炼预约冲突检测这类可复用逻辑。下文按骨架、业务、数据层、发布四步拆每个环节都给出可执行命令和参数说明。2. 从 megalo.config.js 拆解这份 Vue 风格的小程序骨架2.1 目录里每一样东西是干什么的拿到解压目录先别急着执行 yarn install花十分钟把骨架认清楚。src 下面是 pages、App.vue、store、main.js、utils、static标准的 Vue CLI 布局Megalo 把这套 Vue 单文件组件编译成微信小程序能运行的 WXML 和 JS所以开发期写的是 .vue产物是原生小程序代码。根目录的 native 文件夹放原生小程序侧的文件编译时会合并进输出目录微信插件或原生自定义组件的兜底行为通常放这里。路径/文件职责改动频率src/pages每个子目录一个小程序页面开发期最高src/App.vue全局生命周期与公共样式低src/main.js创建 Vue 实例并挂载 store低src/storeVuex 模块user / table / order中src/utils请求封装、计费工具函数中src/static图片、图标等静态资源低native原生小程序文件构建时合并低megalo.config.js页面注册、导航栏、tabBar 配置中这张表已经说明修改节奏页面和 utils 是主力App.vue、main.js、native 这类入口文件尽量少动。.eslintrc.js、.eslintignore是代码规范配置提交前跑一遍 lint 能拦住未使用变量和分号风格问题。有个细节要注意项目同时带着 yarn.lock 和 package-lock.json说明开发过程换过包管理器。我拆这类项目时习惯先看 package.json 的 scripts 确认启动命令然后只保留对应的 lock 文件两个混用会让 CI 和本地装出不同依赖版本排错成本很高。2.2 环境变量拆成两份换来的是部署时的零改动.env.development 和 .env.production 的作用是区分接口地址。开发时小程序连本地后端上线时切线上域名两个文件写好之后代码里不需要任何环境判断。# .env.development —— 本地联调环境 VUE_APP_BASE_URLhttp://127.0.0.1:3000/api VUE_APP_HALL_ID1001 # .env.production —— 线上环境 VUE_APP_BASE_URLhttps://api.yourdomain.com/api VUE_APP_HALL_ID1001VUE_APP_ 前缀是 Vue CLI 的约定只有带这个前缀的变量才会被打进客户端代码工具函数里用process.env.VUE_APP_BASE_URL读取。注意小程序代码最终是公开的任何放进 env 文件的内容都能被扒出来appsecret、数据库密码这类敏感项绝不能出现在这两个文件里。VUE_APP_HALL_ID 在这里是留好的多店字段——同一个后端服务多个台球厅时用门店 ID 隔离数据属于常见的 SaaS 化设计答辩被问如何扩展多店可以直接讲这个字段。提示小程序包下发到用户手机后可以被解包查看env 文件里写密钥等于把密钥公开。2.3 页面注册pages 数组的先后顺序就是启动逻辑Megalo 的小程序页面配置集中在 megalo.config.js编译时映射到小程序 app.json 的 pages 字段。页面注册分两块pages 数组决定有哪些页面和冷启动顺序tabBar 决定底部导航。module.exports { pages: [ pages/index/index, // 冷启动页首页 桌台总览 pages/member/member, // 会员列表与详情 pages/booking/booking, // 预约选台 pages/billing/billing, // 计费与结账 pages/report/report // 营业报表 ], window: { navigationBarTitleText: 台球管理系统, navigationBarBackgroundColor: #1a1a2e, navigationBarTextStyle: white }, tabBar: { color: #999999, selectedColor: #1a1a2e, list: [ { pagePath: pages/index/index, text: 首页 }, { pagePath: pages/member/member, text: 会员 }, { pagePath: pages/booking/booking, text: 预约 } ] } }pages 数组第一个元素就是用户进入小程序看到的第一个页面所以做管理系统时把首页放第一位登录态检查放在首页启动时静默完成比单独搞一个登录中转页体验好。tabBar 配置有两个知识点list 最多五页且 tabBar 页必须出现在 pages 数组里否则编译直接报错selectedColor 要跟导航栏背景色形成对比台球厅场景深色导航栏配浅色文字观感更协调。小程序页面栈深度限制是十层预约、计费这类流程页不要靠长跳转链流程结束用wx.redirectTo或wx.reLaunch清栈这是页面设计里最容易被问到的问题。3. 会员、预约、计费三条业务线的关键实现3.1 会员登录微信 code 换业务 token 的链路小程序没有传统意义上的账号密码会员识别的标准做法是微信登录。wx.login 返回临时 code有效期约五分钟且只能用一次后端拿这个 code 调微信 code2session 接口换到 openid 和 session_key再签发自己的业务 token 返回。业务 token 存进 Vuex 和 storage后续请求都带它。// src/store/modules/user.js import request from ../../utils/request const TOKEN_KEY billiards_token export default { state: { token: wx.getStorageSync(TOKEN_KEY) || }, mutations: { setToken(state, token) { state.token token wx.setStorageSync(TOKEN_KEY, token) // 存本地冷启动直接恢复登录态 } }, actions: { async wxLogin({ commit }) { // code 只能使用一次前端不要缓存它 const { code } await wx.login() const { token } await request({ url: /member/login, method: POST, data: { code } }) commit(setToken, token) } } }最容易踩的坑是把 appid、secret 写进小程序代码。code2session 必须由后端发起token 由后端生成小程序端只负责传 code、收 token。openid 对每个微信用户唯一后端直接用 openid 做会员表的唯一键避免重复建档。如果毕设带了会员等级会员表和 openid、积分、储值余额的关联设计是答辩高频提问点提前把一个 openid 对应一个会员档案订单表单独记 memberId讲清楚比泛泛说实现了会员管理有说服力。3.2 预约台桌时间段冲突检测用两端校验预约模块的数据落点是一张预约单核心字段如下字段类型含义idinteger预约单号主键table_idinteger台球桌编号member_idinteger预约会员start_timedatetime开始时间end_timedatetime预计结束时间statustinyint0 待使用 / 1 使用中 / 2 已完成 / 3 已取消空闲判断的本质是区间相交检测新预约时间段与任意已有未结束预约相交就判定冲突。两个区间相交的充要条件是新开始小于旧结束且新结束大于旧开始写成函数只有几行。// src/utils/book.js // 判断新时间段是否与已有预约冲突 export function hasConflict(bookings, newStart, newEnd) { return bookings.some(item { const s new Date(item.start_time).getTime() const e new Date(item.end_time).getTime() return newStart e newEnd s }) } // 页面提交预约前的本地校验 const conflict hasConflict( table.bookings.filter(b b.status 0 || b.status 1), startTime, endTime ) if (conflict) { wx.showToast({ title: 该时段已被预约, icon: none }) return }前端校验只负责减少无效请求真正的数据一致性要后端兜底创建预约时用事务加行锁或唯一约束防止两个会员在同一毫秒提交同一时间片。毕设里把前端防呆 后端锁这套双保险写进测试章节比单纯贴截图有价值。前端边界条件还要处理 startTime endTime 的非法输入以及跨天预约——台球厅散台基本不跨天但夜场到次日凌晨的单子要能把日期边界算对凌晨两点结束的订单不应和前一天白天的时间片发生误判冲突。3.3 计费结算分钟折算与不要用定时器计时计费规则按桌型单价计算以小时为基准单价、按分钟折算桌型单价元/小时不足一小时普通台30按分钟折算美式台40按分钟折算斯诺克台60按分钟折算// src/utils/billing.js // 按分钟折算费用向上取整到 0.5 元避免分单位误差 export function calcFee(startTime, endTime, ratePerHour) { const elapsedMs new Date(endTime).getTime() - new Date(startTime).getTime() if (elapsedMs 0) return 0 const minutes Math.ceil(elapsedMs / 60000) // 不足一分钟按一分钟计 const fee (minutes / 60) * ratePerHour return Math.ceil(fee * 2) / 2 }这里有个关键设计结束时间取客户点结账的当前时间而不是依赖前端定时器自动计时。小程序切到后台后 setInterval 会被挂起回到前台才恢复用定时器累计时长必然少算钱。常见做法是开台时把 startTime 传给后端结账时前端把当前时间作为 endTime 提交后端按两个时间戳计算需要展示已计时 xx 分钟时才用 setInterval 做每秒刷新且每次刷新只更新界面不做费用累计。状态流转也简单开台创建订单记使用中结账生成待支付金额支付成功回写状态。订单表加一个 pay_status 字段报表统计就是一条 group by。提示依赖前端定时器计时是这类系统最隐蔽的 bug。小程序切后台setInterval 停止回到前台也不会自动补计时。4. Vuex 状态管理与请求层小程序项目最该抄的部分4.1 store 按业务域拆模块src/store 按 user、table、order 三个域拆模块index.js 负责汇总。table 模块存桌台列表与每张桌的实时状态order 模块存当前计费单user 模块管会员信息三者互不直接读写页面里通过 mapState 取数据。// src/store/index.js import Vue from vue import Vuex from vuex import user from ./modules/user import table from ./modules/table import order from ./modules/order Vue.use(Vuex) export default new Vuex.Store({ modules: { user, table, order }, // 严格模式只在开发环境开生产环境避免直接改 state 带来的额外开销 strict: process.env.NODE_ENV development })模块拆分的标准是一个页面关心的数据尽量只来自一个模块。预约页读 table 模块和 booking 模块计费页读 order 模块会员详情读 user 模块跨模块联动一律走 action 分发不要在组件里直接改另一个模块的 state。Vuex 的 mutation 在 DevTools 里可回溯调试时打开 Vue Devtools 看每张桌子的状态变化定位问题比原生小程序里打 setData 日志高效得多。4.2 请求封装token 注入、401 跳转、统一报错全套接口走 utils/request.js 这个封装核心逻辑是把 wx.request 包成 Promise统一处理登录态和错误提示。// src/utils/request.js import store from ../store export default function request(options) { return new Promise((resolve, reject) { wx.request({ url: process.env.VUE_APP_BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: store.state.user.token ? Bearer ${store.state.user.token} : }, success(res) { const body res.data if (body.code 0) { // 业务成功直接抛业务数据页面不用再解一层 resolve(body.data) } else if (body.code 401) { // token 失效清状态并回到首页重新走静默登录 store.commit(user/setToken, ) wx.reLaunch({ url: /pages/index/index }) reject(body) } else { wx.showToast({ title: body.message || 请求失败, icon: none }) reject(body) } }, fail(err) { wx.showToast({ title: 网络异常请重试, icon: none }) reject(err) } }) }) }几点参数说明url 只传相对路径baseURL 由环境变量注入换环境时接口代码一行不动header 里带 Bearer token 是后端常见的鉴权写法401 用 wx.reLaunch 而不是 navigateBack因为 token 失效时返回栈里的旧页面全部作废清栈最省事。业务 code 与 HTTP status 分开判断是值得保留的标准做法后端返回 200 但业务失败的情况比如余额不足不会误进 catch。所有失败请求统一 toast页面里只需要处理成功分支代码量减一半。4.3 Megalo 和原生小程序、uni-app 的差异要心里有数如果你之前写过原生小程序或 uni-app迁到 Megalo 项目前先看这张对照表对比项Megalo原生小程序uni-app页面写法Vue 单文件 .vue.wxml / .js / .wxss 三件套Vue 单文件状态管理Vuex 直接用自己写全局对象或引库Vuex原生 APIwx.* 直接调wx.*uni.* 包装层数据更新Vue 响应式赋值this.setData 指定路径Vue 响应式赋值页面参数this.$root.$mp.queryonLoad(options)onLoad(options)最直观的差异是数据更新原生小程序里写this.setData({ userInfo.nickname: xx })这种带路径的 key嵌套层级一多很容易更新错位置Megalo 里直接this.userInfo res就完成更新不用关心 key 路径这是把原生页面迁到本项目时最省心的一点。页面参数读取上编译型框架通常会把小程序 Page onLoad 的参数挂到this.$root.$mp.query测试发现取不到就退回在 mounted 里读。右上角那颗胶囊按钮三个点和圆圈是微信原生 UI不能关闭也不能改样式只能通过导航栏背景色做视觉配合自定义导航时顶部高度用wx.getSystemInfoSync().statusBarHeight导航栏再补 44px不同机型算出来不一样不能写死 64。5. 上真实机前必须过的三关编译产物、体验版、报表导出5.1 开发工具导入与真机调试编译产物默认输出到 dist 目录微信开发者工具导入时选 dist 而不是项目根目录这是未找到 app.json报错最常见的来源。开发阶段在详情 - 本地设置里勾选不校验合法域名本地联调 http 后端不会失败要做真机预览点工具栏预览生成二维码手机和电脑需在同一局域网调试模式下手机端会出现 vConsole 入口网络请求、storage、报错都能直接看。5.2 上传版本与体验版设置代码稳定后用开发者工具上传按钮提交弹出框会要求填版本号和项目备注。上传完成后只有小程序管理员能在 mp 后台把该版本设为体验版生成体验版二维码给测试同学扫码这个操作开发者工具本身没有入口很多人卡在这里。注意 request 合法域名必须在 mp 后台配置且要求 HTTPS上线后接口全部失败先查合法域名是否配全再查证书是否为有效 HTTPS。5.3 报表导出用 wx.downloadFile 打通 Excel 下载营业报表除了页面展示答辩时现场导出一份 Excel 很出效果。标准链路是后端生成文件返回可访问地址小程序端下载后用 openDocument 打开// 导出当日订单报表 wx.downloadFile({ url: process.env.VUE_APP_BASE_URL /report/export?typedaily, filePath: wx.env.USER_DATA_PATH /daily.xlsx, // 指定落盘路径 success(res) { wx.openDocument({ filePath: res.filePath, fileType: xlsx, showMenu: true // 用户可在右上角菜单保存或转发 }) } })wx.env.USER_DATA_PATH 是小程序本地用户目录指定 filePath 决定文件落盘位置不指定则由系统生成临时路径openDocument 唤起文件查看页showMenu 为 true 用户才能调用右上角菜单保存或转发文件。调用顺序固定为先下载拿本地路径、再 openDocument 打开fileType 要和文件后缀对应这条链路在 iOS 和 Android 表现一致省去自己写文件系统交互。本文还有配套的精品资源点击获取