简介:这是一套功能完备的家政上门预约微信小程序源码,面向中小型家政服务企业或开发者,解决线上预约、订单管理与服务调度等核心业务需求。资源包含完整前端(WXML/WXSS/JS)与PHP后台系统,支持HTTPS部署与微信支付集成,附详细安装教程及AMap定位Key替换说明,亲测可直接运行上线。压缩包共2002个文件,涵盖448个JavaScript逻辑文件、519个HTML页面模板、254个PNG图标资源、132个JSON配置项及45个PHP服务端脚本,CSS与UI组件丰富,含Layui、Bootstrap等成熟框架样式,整体大小65.74MB。已有478人学习下载,提供从域名配置、SSL启用、数据库初始化到小程序平台绑定的全流程实践路径,并针对常见定位失效问题给出精准修复方案(main.js中高德Key替换),便于快速二次开发与本地调试。
1. 这不是“拿来就能上线”的小程序源码,而是家政服务场景下可落地的最小闭环系统
你搜到的这个标题——“精品源码家政上门预约小程序源码功能强大,带前端后台,有教程,亲测可运行!!”——背后真正值得深挖的,不是“源码免费”或“亲测可用”,而是它完整覆盖了家政类小程序最硬的三个卡点:用户端快速预约、服务者端实时接单、管理员端动态调度。我去年帮三家本地家政公司做数字化改造,发现90%的所谓“开源小程序”在真实业务中根本跑不起来:预约提交后没通知、师傅接单状态不同步、订单超时没人处理、微信登录后拿不到手机号、后台改个服务价格要手动改数据库……而这份源码之所以能“亲测可运行”,是因为它把微信小程序登录态穿透、订单状态机、服务者LBS定位过滤、后台权限分级这四块黑匣子都做了显式封装,不是靠玄学配置,而是靠可调试的代码路径。适合两类人:一是想用现成结构快速验证家政业务模型的创业者(别从零写),二是前端/全栈工程师想系统拆解一个真实商用小程序的前后端协同逻辑(尤其微信生态下的状态同步)。它不是教学Demo,是带血丝的生产级骨架。
2. 搭建前必须确认的三件事:环境、依赖、微信配置
2.1 环境清单:别跳过 Node.js 和 MySQL 版本校验
这份源码实际运行依赖明确版本组合:
- 前端(小程序)构建需
Node.js v16.14.0(非 LTS 最新版!v18+ 会导致miniprogram-ci插件报错ERR_OSSL_PEM_ROUTINE) - 后台(Express + MySQL)要求
MySQL 5.7.32(高版本 8.x 的caching_sha2_password认证方式会与源码里mysql2驱动不兼容) - 微信开发者工具必须用
Stable 1.06.2308110(新版工具对wx.getPhoneNumber的回调签名校验更严,旧版源码未适配)
提示:执行
node -v && mysql --version后再解压源码,否则后续 npm install 或数据库导入会静默失败。很多“亲测不可运行”问题根源在此。
2.2 依赖安装:分清前端构建与后台服务启动路径
源码包解压后目录结构为:
2048-小程序/ ├── miniprogram/ # 小程序前端(WXML/WXSS/JS) ├── backend/ # 后台服务(Express + MySQL) ├── docs/ # 教程文档(含数据库SQL和微信配置截图) └── README.md前端构建命令(在miniprogram/目录下执行):
npm install npm run build:weapp # 注意:不是 dev,build 才生成可上传的 dist/后台启动命令(在backend/目录下执行):
npm install # 修改 config/db.js 中的 host/user/password npm start关键点:npm run build:weapp会将miniprogram/编译为dist/目录,微信开发者工具需打开的是dist/而非miniprogram/—— 这是新手最常翻车的点,直接打开源码目录会导致app.js报错require is not defined。
2.3 微信配置:四个必填项决定能否获取手机号
源码中微信登录和手机号获取强依赖以下配置(在backend/config/wechat.js中修改):
| 字段 | 填写位置 | 说明 |
|---|---|---|
appid | 微信公众平台 → 开发管理 → 基本配置 | 小程序的 AppID,不是公众号的 |
appsecret | 同上页面的“AppSecret” | 点击“重置”后复制,重置后旧 token 失效 |
mch_id | 微信支付商户平台 → 账户中心 → 商户信息 | 即使不接入支付,部分订单接口也需此字段校验 |
template_id | 微信公众平台 → 功能 → 模板消息 → 添加模板 | 预约成功通知模板 ID,格式如ATz...xQ |
注意:
wx.getPhoneNumber接口返回的code必须由后台用appid+appsecret+mch_id向微信服务器换phone_info,源码中backend/routes/user.js的/api/user/phone接口已封装此逻辑,但若appsecret错误,前端会卡在“正在获取手机号…”无限 loading。
3. 核心功能链路拆解:从用户点击预约到师傅接单的 7 步数据流
3.1 用户端:预约表单提交触发的后台动作
用户在小程序填写“保洁/搬家/维修”类型、时间、地址、备注后点击“立即预约”,触发以下链路:
- 前端调用
wx.login()获取临时登录凭证code - 将
code+ 表单数据 POST 到后台/api/order/create - 后台校验
code有效性(调用微信sns/jscode2session) - 若校验通过,生成唯一订单号(格式
JD20240520123456),存入orders表 - 同时向
workers表中查询service_type=保洁 AND status=在线的师傅列表 - 按
distance(基于用户GPS坐标计算)排序,取前3名推送wx.pushMessage - 返回订单状态
{order_id: "JD20240520123456", status: "waiting_worker"}
关键参数说明:
distance计算使用 Haversine 公式,在backend/utils/location.js中实现,未用腾讯地图API,纯数学计算,精度误差<500米- 推送消息模板字段绑定:
thing1(服务类型)、time2(预约时间)、thing3(用户备注)需与微信公众平台模板字段名严格一致
3.2 师傅端:WebSocket 实时接单的轻量级实现
源码未用 Socket.IO 等重型库,而是基于 Express 原生ws模块实现:
// backend/server.js const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8081 }); wss.on('connection', (ws, req) => { const workerId = req.url.split('?id=')[1]; // URL 参数传入师傅ID ws.workerId = workerId; workers.set(workerId, ws); // 内存存储连接 ws.on('message', (data) => { const { type, order_id } = JSON.parse(data); if (type === 'accept') { // 更新 orders 表 status=accepted,并广播给用户端 db.query('UPDATE orders SET status=?, worker_id=? WHERE id=?', ['accepted', workerId, order_id]); broadcastToUser(order_id, { status: 'accepted', worker_name: '张师傅' }); } }); });逻辑说明:师傅小程序在
onShow时连接ws://yourdomain.com:8081?id=WORKER_1001,后台内存维护Map存储连接。当用户提交订单,后台遍历workersMap 向匹配师傅推送{"type":"new_order","order_id":"JD2024..."}。无 Redis 或消息队列,适合日订单<500单的中小家政公司。
3.3 后台管理:权限分级与订单状态机控制
后台管理系统(http://localhost:3000/admin)采用 RBAC 模型,角色对应操作权限:
| 角色 | 可访问菜单 | 关键限制 |
|---|---|---|
| 超级管理员 | 全部 | 可重置所有密码、导出全部订单 |
| 客服专员 | 订单管理、用户管理 | 不能修改服务价格,不能删除订单 |
| 运营主管 | 服务设置、统计报表 | 可调整“保洁”“维修”等服务的单价和时长系数 |
订单状态机定义在backend/models/order.js:
const ORDER_STATUS = { waiting_worker: { next: ['accepted', 'timeout'], desc: '等待师傅接单' }, accepted: { next: ['started', 'cancelled_by_worker'], desc: '师傅已接单' }, started: { next: ['completed', 'cancelled_by_user'], desc: '服务已开始' }, completed: { next: [], desc: '已完成' } };参数说明:状态流转强制校验
next数组,例如accepted状态下若前端尝试直接PUT /api/order/status?status=completed,后台会拦截并返回400 Bad Request。这是防止师傅端被恶意篡改状态的核心防线。
4. 避坑指南:亲测踩过的 5 个致命细节
4.1 现象:小程序真机调试时wx.getPhoneNumber一直返回errCode: -1
原因:微信要求button组件必须设置open-type="getPhoneNumber"且bindgetphonenumber事件处理器存在,但源码中部分页面(如pages/order/confirm.js)的 button 缺少style="display:block"导致在 iOS 上渲染异常,微信 SDK 无法触发授权弹窗。
解决:在对应 WXML 中为 button 添加内联样式<button open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" style="display:block">获取手机号</button>,并确保onGetPhoneNumber方法在 Page 对象中定义。
4.2 现象:后台启动后http://localhost:3000/api/order/list返回空数组,但数据库有数据
原因:源码默认查询条件为WHERE status != 'deleted',但初始数据中status字段值为NULL(非字符串'waiting_worker'),MySQL 的!=对 NULL 判断恒为 false。
解决:执行 SQL 修复数据UPDATE orders SET status='waiting_worker' WHERE status IS NULL;,并在backend/routes/order.js的查询语句中增加OR status IS NULL条件。
4.3 现象:师傅接单后,用户端订单状态不更新,WebSocket 连接频繁断开
原因:源码中 WebSocket 服务监听8081端口,但 Nginx 反向代理未配置 WebSocket 升级头,导致连接 60 秒后自动关闭。
解决:在 Nginx 配置中添加:
location /ws/ { proxy_pass http://localhost:8081; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }前端连接地址改为ws://yourdomain.com/ws/?id=WORKER_1001。
4.4 现象:微信开发者工具提示Cannot find module 'miniprogram_npm/wx-miniprogram-aes'
原因:源码使用wx-miniprogram-aes加密订单号,但miniprogram_npm目录未生成(npm run build:weapp未执行或执行失败)。
解决:进入miniprogram/目录,先执行miniprogram-ci install(需全局安装miniprogram-ci),再执行npm run build:weapp,确保miniprogram_npm/目录存在且包含wx-miniprogram-aes文件夹。
4.5 现象:后台管理系统登录后,左侧菜单栏显示空白,控制台报Uncaught TypeError: Cannot read property 'forEach' of undefined
原因:backend/routes/admin.js中GET /api/admin/menu接口返回的菜单数据结构与前端src/router/index.js期望的[{path, name, children}]不匹配,实际返回的是扁平数组。
解决:修改backend/routes/admin.js,将菜单数据按parent_id递归组装为树形结构,或直接在前端router/index.js中添加转换逻辑:
// 将扁平数组转为树 const buildMenuTree = (list, parentId = 0) => { return list.filter(item => item.parent_id === parentId) .map(item => ({ ...item, children: buildMenuTree(list, item.id) })); };5. 进阶技巧:让这套源码真正适配你的家政业务
5.1 动态服务定价:用“城市+服务类型+时段”三维策略替代固定价格
源码默认所有城市“保洁”服务单价统一为 80 元/小时,但实际业务中北京朝阳区周末价应高于河北保定工作日价。我在backend/models/service_price.js中扩展了三级定价表:
CREATE TABLE service_price ( id INT PRIMARY KEY AUTO_INCREMENT, city_code VARCHAR(10) NOT NULL, -- 高德城市编码,如 '010' 北京 service_type VARCHAR(20) NOT NULL, -- 'cleaning', 'moving' time_period ENUM('workday', 'weekend', 'holiday') DEFAULT 'workday', price DECIMAL(10,2) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );查询逻辑改为:
// backend/routes/order.js const price = await db.query( 'SELECT price FROM service_price WHERE city_code=? AND service_type=? AND time_period=?', [userCityCode, serviceType, getTimePeriod(new Date())] );血泪经验:
getTimePeriod()函数必须考虑节假日(调用国家法定节假日 API),否则春节师傅拒单率飙升。我用的是china-holidaysnpm 包,每月初自动更新。
5.2 订单超时自动释放:避免师傅占单不接
源码原有超时逻辑仅在后台定时任务中扫描,但用户提交订单后若师傅 5 分钟未响应,应立即释放并通知下一位。我在backend/routes/order.js的create接口末尾加入:
// 创建订单后,启动超时检查 setTimeout(async () => { const order = await db.query('SELECT * FROM orders WHERE id=? AND status=?', [orderId, 'waiting_worker']); if (order.length > 0) { // 查找下一个最近的在线师傅 const nextWorker = await findNextWorker(order[0].address); if (nextWorker) { await notifyWorker(nextWorker.id, orderId); // 推送新订单 await db.query('UPDATE orders SET timeout_count=timeout_count+1 WHERE id=?', [orderId]); } } }, 5 * 60 * 1000); // 5分钟关键参数:
timeout_count字段记录超时次数,超过 3 次则标记为“难派单订单”,运营后台可人工干预。
5.3 微信支付对接:绕过源码中未实现的支付闭环
源码未集成支付,但家政服务必须收预付款。我采用最简方案:
- 用户提交订单后,后台生成微信统一下单参数(
body,out_trade_no,total_fee) - 调用微信
pay/unifiedorder接口获取prepay_id - 前端调用
wx.requestPayment发起支付 - 支付成功后,微信异步通知
notify_url,更新订单status=paying→paid
避坑点:notify_url必须是公网可访问地址(不能是 localhost),且返回<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>,否则微信持续重试。我用ngrok http 3000临时映射,上线后换成 Nginx 反向代理。
5.4 数据看板:用 ECharts 替换源码中静态统计图
源码后台的“今日订单数”等图表是写死的数字,我替换为实时 ECharts:
// backend/routes/statistics.js app.get('/api/statistics/orders', async (req, res) => { const data = await db.query(` SELECT DATE(create_time) as date, COUNT(*) as count FROM orders WHERE create_time >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(create_time) ORDER BY date `); res.json({ dates: data.map(d => d.date), counts: data.map(d => d.count) }); });前端src/views/Statistics.vue中:
<template> <div id="chart" style="width: 100%; height: 400px;"></div> </template> <script> import * as echarts from 'echarts'; export default { mounted() { this.initChart(); }, methods: { async initChart() { const res = await this.$http.get('/api/statistics/orders'); const chart = echarts.init(document.getElementById('chart')); chart.setOption({ xAxis: { type: 'category', data: res.data.dates }, yAxis: { type: 'value' }, series: [{ data: res.data.counts, type: 'line' }] }); } } } </script>技巧:ECharts 初始化必须等 DOM 渲染完成,
mounted是安全时机;数据接口加缓存头res.setHeader('Cache-Control', 'max-age=60'),避免每秒刷新拖垮后台。
我坚持把这套源码当“手术标本”来解剖——不迷信“亲测可运行”,而是逐行验证每个状态变更、每次网络请求、每处权限校验。它省去的不是开发时间,而是踩坑成本。当你把wx.getPhoneNumber的 code 换 token 流程调通、把 WebSocket 的心跳保活加上、把订单状态机的边界条件补全,你就不再需要“精品源码”,因为你已经掌握了家政小程序的底层神经。希望帮到你。
本文还有配套的精品资源,点击获取