简介:这是一套开箱即用的家政预约类微信小程序模板源码,面向家政服务企业、个体创业者及小程序初学者,解决线上服务预约系统快速搭建难题。资源共106个文件,涵盖21个JS逻辑层代码、18个WXML页面结构、19个WXSS样式文件、22个JSON配置及24个PNG图标素材,完整呈现前端交互、服务列表展示、时间预约、在线支付与评价反馈等核心功能模块,压缩包仅1.18MB,轻量易部署。已有307人学习下载,适合无编程基础者通过配置快速上线,也便于开发者基于现有结构扩展地图定位、预约提醒或多服务分类等功能。源码结构清晰,含homepage.js、index.js、add.js等典型页面逻辑,配合预览中的wxb.js工具库与多张界面截图,可直观理解业务流程与UI组织方式,是学习小程序工程化开发与生活服务类应用落地的实用参考。
1. 家政预约微信小程序模板源码:不是“拿来就能上线”的套壳工程,而是能跑通「用户下单→服务派单→订单闭环」的最小可行业务骨架
你花20分钟下载、解压、用开发者工具打开这个家政预约的微信小程序模板源码下载.zip,会发现它不像某些“UI炫酷但点不动”的Demo——首页真能选保洁/搬家/维修服务,点击立即预约后,表单能提交、手机号能校验、订单号能生成、甚至模拟了师傅接单状态变更。这不是一个纯静态页面集合,而是一套基于微信原生框架(WXML/WXSS/JS)构建、已预置基础云函数调用逻辑、数据库字段结构清晰、且明确标注了「需替换为真实环境」位置的业务型模板。它解决的不是“怎么写一个按钮”,而是“如何让家政服务从微信里真正流转起来”:用户侧有服务分类+时间选择+地址联动,后台侧预留了订单状态机(待接单/已接单/服务中/已完成/已取消)、服务人员池管理入口、以及关键的微信登录+手机号授权链路占位。适合两类人:刚接手家政类小程序外包需求的前端工程师,想快速验证业务流程是否合理;或是创业团队技术负责人,需要评估自建小程序的开发成本边界——它不承诺“零代码上线”,但能让你在3小时内跑通从首页到订单详情页的全链路,省掉至少80%的基建踩坑时间。
2. 源码结构拆解与核心模块定位:看清这6个文件夹,你就掌握了家政小程序的“脏器分布”
2.1 项目根目录:miniprogram是唯一主战场,project.config.json决定能否打开
解压后你会看到典型的微信小程序目录结构,但重点只在miniprogram/这个文件夹——它才是运行时实际加载的源码主体。project.config.json文件必须存在且配置正确,否则开发者工具会报错“未找到 project.config.json”。该文件中appid字段默认为"wx1234567890abcdef"(占位符),首次打开前必须替换成你自己的小程序 AppID,否则所有网络请求、登录、支付都会失败。注意:这个 AppID 必须已在微信公众平台注册并完成认证(个体工商户可认证),否则云开发环境无法绑定。
{ "description": "家政预约小程序模板", "setting": { "urlCheck": true, "es6": true, "enhance": true, "postcss": true, "preloadBackgroundComponents": true, "enableAppxNg": false, "minified": true, "newFeature": true }, "compileType": "miniprogram", "libVersion": "2.28.4", "appid": "wx1234567890abcdef", // ← 此处必须修改! "projectname": "jiazheng-appointment-template" }提示:
libVersion字段值2.28.4表示该模板基于微信基础库 2.28.4 版本开发。若你的开发者工具基础库版本低于此(如 2.25.x),部分新 API(如wx.getPhoneNumber的needLogin参数)可能不可用,需升级工具或降级适配。
2.2 页面层:pages/下的5个核心页面,每个都带业务语义命名
pages/目录下不是一堆indexlistdetail这种泛化命名,而是直接体现家政场景:
index/:首页,含服务分类轮播图 + 快捷入口(保洁/家电清洗/搬家)+ 热门服务卡片order/:订单列表页,区分「待服务」「已完成」「已取消」Tab,每条订单显示服务类型、时间、状态标签book/:预约下单页,关键组件包括:picker时间选择器(限制未来7天)、map地址选择器(调用微信地图API)、form表单(含姓名、电话、服务需求描述)my/:个人中心页,集成微信头像昵称、订单统计、常用地址管理、客服入口detail/:订单详情页,展示订单号、服务时间、地址、服务内容、师傅信息(模拟数据)、状态操作按钮(仅用户可见“取消订单”,师傅端需另行开发)
每个页面的.js文件中,onLoad()函数内均有注释标明“此处应调用云函数获取数据”,例如book.js中:
// book.js Page({ data: { serviceType: 'cleaning', selectedTime: '', address: '' }, onLoad() { // 【关键占位】此处应调用云函数 getServicesList 获取服务类型列表 // 当前为模拟数据,上线前需替换为真实云函数调用 this.setData({ services: [ { id: 'cleaning', name: '家庭保洁', price: '80元/小时' }, { id: 'appliance', name: '家电清洗', price: '120元/台' } ] }) } })2.3 云函数层:cloudfunctions/中的3个函数,是业务逻辑的“心脏”
模板已预置云函数目录结构,无需手动创建,但需在开发者工具中右键“上传部署”:
| 云函数名 | 功能说明 | 关键参数 | 注意事项 |
|---|---|---|---|
createOrder | 创建订单,生成订单号、校验手机号格式、写入云数据库orders集合 | serviceType,time,address,phone,userId | 依赖wx.cloud.database(),需提前在云开发控制台创建orders集合并设置权限(建议设为“仅管理员可读写”) |
getOrderList | 查询用户订单列表,按userId过滤,支持分页 | userId,status,page,limit | 返回字段包含statusText(中文状态映射),避免前端硬编码状态文案 |
updateOrderStatus | 更新订单状态(如师傅接单),需校验操作权限 | orderId,newStatus,operatorId,operatorType('user'/'staff') | 当前未实现权限校验逻辑,上线前必须补全,否则任意用户可篡改他人订单状态 |
注意:云函数部署后,其名称会自动同步到小程序端
wx.cloud.callFunction()调用中。若修改函数名,必须同步更新pages/order/order.js中的name: 'getOrderList'字段。
2.4 数据库设计:cloudDB预置2个集合,字段命名直指业务本质
云开发数据库中,模板已规划好两个核心集合:
orders集合(订单主表):_id: ObjectId(自动生成)orderNo: String(格式JD202405200001,年月日+4位序号)userId: String(微信 openid)serviceType: String('cleaning', 'moving', 'repair')time: Date(服务时间)address: Object(含province,city,district,detail)status: Number(0=待接单, 1=已接单, 2=服务中, 3=已完成, 4=已取消)createdAt: Date(创建时间)
staff集合(服务人员池,仅作示意):_id: ObjectIdname: Stringphone: Stringskills: Array(['保洁', '家电清洗'])available: Boolean(是否可接单)
提示:
orders集合的status字段使用数字而非字符串,是为了便于数据库索引优化和状态机流转判断。前端展示时通过statusMap = {0:'待接单',1:'已接单'...}映射,避免在数据库中存冗余中文。
2.5 登录与授权:app.js中的onLaunch是整个流程的“第一道闸门”
小程序启动时,app.js的onLaunch函数执行初始化逻辑,这里埋了两个关键钩子:
// app.js App({ onLaunch() { // 1. 检查登录态(检查本地缓存的 openid) const openid = wx.getStorageSync('openid') if (!openid) { // 2. 未登录则跳转到 login 页面(非强制,可改为静默登录) wx.navigateTo({ url: '/pages/login/login' }) return } // 3. 已登录,初始化全局数据 this.globalData.openid = openid }, globalData: { openid: '', userInfo: null } })而真正的微信登录与手机号获取,被拆解到两个独立页面:
pages/login/login.js:调用wx.login()获取 code,再通过云函数login换取 openid(模板中该云函数已存在,但需部署)pages/book/book.js:在提交订单前,调用wx.getPhoneNumber()获取加密手机号(注意:此 API 需用户主动触发 button 点击,且 button 必须设置open-type="getPhoneNumber"),模板中book.wxml已写好该 button,但bindgetphonenumber事件处理器为空,需自行实现解密逻辑。
提示:
wx.getPhoneNumber返回的encryptedData和iv,必须由后端(云函数)调用微信接口auth.getPhoneNumber解密。小程序端无法直接解密——这是微信的安全设计,也是新手最容易翻车的点:试图在前端 JS 里用 AES 解密,结果永远失败。
2.6 样式与组件:components/中的address-picker是复用性最高的自定义组件
模板将地址选择逻辑封装为独立组件components/address-picker/,其优势在于:
- 封装了
wx.chooseLocation()调用、坐标逆解析(wx.getAddress())、地址格式化(省市区+详细地址)全流程 - 对外只暴露
bind:select事件,父页面只需监听即可获取结构化地址对象 - 支持
disabled属性控制是否可编辑,适配订单详情页只读场景
在book.wxml中引用方式简洁:
<address-picker bind:select="onAddressSelect" disabled="{{false}}" />而address-picker.js的onSelect方法内部,已处理了微信地图 API 的错误兜底(如用户拒绝位置授权时,自动 fallback 到手动输入框)。这种封装极大降低了页面耦合度——后续开发“上门维修”页面时,直接复用该组件即可,无需重复写地图逻辑。
3. 微信登录与手机号获取:从wx.login()到wx.getPhoneNumber()的完整链路实操
3.1wx.login():获取临时登录凭证 code,不是 openid!
很多新手误以为wx.login()返回的就是 openid,这是典型认知偏差。wx.login()实际返回的是一个一次性的code,它必须发送给后端(云函数),由后端调用微信服务器接口https://api.weixin.qq.com/sns/jscode2session,用appid+appsecret+code换取openid和session_key。模板中cloudfunctions/login/index.js已实现该逻辑:
// cloudfunctions/login/index.js const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { const { code } = event try { const res = await cloud.http.request({ method: 'GET', url: `https://api.weixin.qq.com/sns/jscode2session?appid=${process.env.APPID}&secret=${process.env.APPSECRET}&js_code=${code}&grant_type=authorization_code` }) const { openid, session_key } = res.data // 将 openid 存入数据库或返回给小程序端 return { openid, session_key } } catch (err) { console.error('login error:', err) return { error: 'login failed' } } }关键点:
process.env.APPID和process.env.APPSECRET需在云开发控制台的「环境变量」中配置,绝不能硬编码在代码里。APPSECRET 是敏感密钥,泄露即导致小程序账号被盗用。
3.2wx.getPhoneNumber():必须用<button open-type="getPhoneNumber">触发
微信严格规定:获取手机号必须由用户主动点击按钮触发,且该按钮必须设置open-type="getPhoneNumber"。模板中book.wxml的写法是合规的:
<button class="phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber" > 授权获取手机号 </button>当用户点击后,onGetPhoneNumber事件处理器被触发,event.detail中包含encryptedData和iv:
// book.js onGetPhoneNumber(e) { if (e.detail.errMsg === 'getPhoneNumber:ok') { const { encryptedData, iv } = e.detail // 将 encryptedData 和 iv 发送给云函数 decryptPhone wx.cloud.callFunction({ name: 'decryptPhone', data: { encryptedData, iv } }).then(res => { console.log('手机号解密成功:', res.result.phoneNumber) this.setData({ phone: res.result.phoneNumber }) }) } }3.3 云函数decryptPhone:用cloud.openapi安全解密
微信官方推荐使用cloud.openapi模块调用auth.getPhoneNumber接口,它比手动 HTTP 请求更安全(自动携带 access_token):
// cloudfunctions/decryptPhone/index.js const cloud = require('wx-server-sdk') cloud.init() exports.main = async (event, context) => { const { encryptedData, iv } = event try { const result = await cloud.openapi.auth.getPhoneNumber({ phoneNumber: encryptedData, iv: iv }) return { phoneNumber: result.phoneNumber } } catch (err) { console.error('decrypt failed:', err) return { error: 'decrypt failed' } } }注意:
cloud.openapi.auth.getPhoneNumber是云开发提供的封装方法,底层仍是调用微信服务器接口。它要求云函数运行环境为Node.js 16或更高版本,且需在云开发控制台开通「开放能力」权限。
3.4 前端手机号校验:别只信wx.getPhoneNumber,还得自己验格式
即使微信返回了手机号,前端仍需做二次校验,因为:
- 用户可能在授权弹窗中点了“取消”,此时
e.detail.errMsg为'getPhoneNumber:fail user deny',但新手常忽略此分支,导致phone字段为空提交 - 微信返回的
phoneNumber是标准 11 位数字字符串(如"13812345678"),但用户手动输入时可能带空格或-,需统一清理
模板中book.js的提交逻辑做了双保险:
submitOrder() { const { phone, address, time } = this.data // 1. 前端格式校验 if (!/^1[3-9]\d{9}$/.test(phone)) { wx.showToast({ title: '手机号格式错误', icon: 'none' }) return } // 2. 必填项校验 if (!address.province || !time) { wx.showToast({ title: '请完善地址和时间', icon: 'none' }) return } // 3. 调用云函数创建订单 wx.cloud.callFunction({ name: 'createOrder', data: { phone, address, time } }) }3.5 状态持久化:wx.setStorageSync('openid')是登录态的“后悔药”
小程序没有 Cookie 概念,登录态必须手动维护。模板采用最简方案:wx.setStorageSync('openid', openid)将 openid 存入本地缓存。app.js的onLaunch会优先读取该缓存,避免每次启动都重新登录。
但要注意:wx.setStorageSync有 10MB 本地存储上限,且不同小程序间数据隔离。对于家政类应用,openid 是核心标识,必须确保其写入成功。因此模板在login.js中增加了写入校验:
// pages/login/login.js wx.cloud.callFunction({ name: 'login', data: { code } }).then(res => { const { openid } = res.result if (openid) { wx.setStorageSync('openid', openid) // 写入后立即读取验证 const cached = wx.getStorageSync('openid') if (cached === openid) { wx.switchTab({ url: '/pages/index/index' }) } else { wx.showToast({ title: '登录态保存失败', icon: 'none' }) } } })提示:
wx.setStorageSync是同步 API,但写入失败不会抛异常,只会静默失败。因此必须用wx.getStorageSync反向验证,这是生产环境必备的“血泪经验”。
3.6 避坑:微信登录与手机号获取的5个高频翻车点
现象1:wx.login()返回的 code 过期,导致jscode2session接口返回invalid code
原因:code 有效期仅为 5 分钟,且只能使用一次。若用户从登录页跳转到其他页面再回来,code 已失效。
解决:在onLoad中立即调用wx.login(),获取 code 后立刻传给云函数,不要缓存 code。模板中login.js的onLoad即执行登录,规避此问题。
现象2:wx.getPhoneNumber()点击无反应,控制台报open-type="getPhoneNumber" is not supported
原因:开发者工具版本过低(< 1.05.2205100),或小程序基础库版本低于 2.21.0。
解决:升级开发者工具至最新版,并在project.config.json中将libVersion设为2.28.4或更高。
现象3:云函数decryptPhone报错access denied
原因:未在云开发控制台开通「开放能力」,或云函数环境未启用Node.js 16。
解决:进入云开发控制台 → 「设置」→ 「开放能力」→ 开启「手机号」权限;云函数详情页 → 「运行环境」→ 选择Node.js 16。
现象4:用户授权手机号后,e.detail.errMsg为getPhoneNumber:fail,但无具体错误信息
原因:用户在系统设置中关闭了小程序的“获取手机号”权限,或微信版本过低(< 8.0.30)。
解决:增加引导提示:“如无法获取手机号,请前往微信【我】→【设置】→【隐私】→【授权管理】中开启权限”,并在bindgetphonenumber中捕获e.detail.errMsg并友好提示。
现象5:wx.chooseLocation()在真机上白屏,或返回坐标但逆解析失败
原因:未在微信公众平台开通「地图组件」权限,或wx.getAddress()接口未在app.json的permission中声明。
解决:登录微信公众平台 →「开发管理」→「开发设置」→「接口设置」→ 开通「获取地理位置」和「获取用户地址」;app.json中添加:
"permission": { "scope.userLocation": { "desc": "用于获取您的位置信息,以便为您推荐附近服务" }, "scope.address": { "desc": "用于获取您的详细地址,以便安排师傅上门" } }4. 订单状态机与派单逻辑:从“用户下单”到“师傅接单”的状态流转设计
4.1 状态定义:5个数字状态码,覆盖家政服务全生命周期
模板采用整型状态码而非字符串,既节省数据库空间,又便于状态机流转判断。orders集合中的status字段定义如下:
| 状态码 | 中文含义 | 前端展示样式 | 可触发操作 | 备注 |
|---|---|---|---|---|
| 0 | 待接单 | 黄色标签 | 无(等待师傅抢单) | 用户提交后初始状态 |
| 1 | 已接单 | 蓝色标签 | 用户可“取消订单”,师傅可“开始服务” | 师傅点击“接单”按钮后更新 |
| 2 | 服务中 | 橙色标签 | 用户可“联系师傅”,师傅可“完成服务” | 师傅点击“开始服务”后更新 |
| 3 | 已完成 | 绿色标签 | 用户可“评价”,师傅无操作 | 师傅点击“完成服务”后更新 |
| 4 | 已取消 | 灰色标签 | 无 | 用户或师傅主动取消 |
前端通过statusMap对象映射展示文案,避免硬编码:
// utils/status.js const statusMap = { 0: { text: '待接单', color: '#FFA500' }, 1: { text: '已接单', color: '#1890FF' }, 2: { text: '服务中', color: '#FAAD14' }, 3: { text: '已完成', color: '#52C418' }, 4: { text: '已取消', color: '#BFBFBF' } } module.exports = { statusMap }4.2 状态更新:updateOrderStatus云函数的原子性保障
订单状态变更必须保证原子性,防止并发冲突(如两个师傅同时点击“接单”)。模板中updateOrderStatus函数使用db.collection('orders').doc(orderId).update()的field更新方式,并加入条件判断:
// cloudfunctions/updateOrderStatus/index.js exports.main = async (event, context) => { const { orderId, newStatus, operatorId, operatorType } = event const db = cloud.database() try { // 1. 先查询原订单,校验当前状态是否允许变更 const order = await db.collection('orders').doc(orderId).get() if (!order.data) throw new Error('订单不存在') const oldStatus = order.data.status // 2. 状态流转规则校验(仅允许合法流转) const validTransitions = { 0: [1], // 待接单 → 已接单 1: [2, 4], // 已接单 → 服务中 / 已取消 2: [3, 4], // 服务中 → 已完成 / 已取消 3: [], // 已完成不可变 4: [] // 已取消不可变 } if (!validTransitions[oldStatus].includes(newStatus)) { throw new Error(`状态 ${oldStatus} 不可流转至 ${newStatus}`) } // 3. 执行更新(带条件,防止并发覆盖) await db.collection('orders').doc(orderId).update({ data: { status: newStatus, updatedAt: db.serverDate(), ...(operatorType === 'staff' ? { staffId: operatorId } : {}), ...(newStatus === 1 ? { acceptTime: db.serverDate() } : {}) } }) return { success: true } } catch (err) { console.error('update status failed:', err) return { error: err.message } } }关键点:
db.serverDate()确保时间戳由服务器生成,避免客户端时间篡改;...(operatorType === 'staff' ? { staffId: operatorId } : {})仅在师傅操作时记录staffId,为后续派单分析留痕。
4.3 师傅端逻辑:如何让“接单”按钮只对匹配师傅可见?
模板当前仅实现用户端,但为扩展师傅端预留了接口。核心思路是:师傅端首页需实时拉取“待接单”订单,并按技能匹配过滤。
假设staff集合中师傅skills: ['保洁', '家电清洗'],则查询待接单订单时,需匹配serviceType:
// 师傅端伪代码(需另建 staff-pages/) const db = cloud.database() const res = await db.collection('orders').where({ status: 0, // 待接单 serviceType: _.in(['cleaning', 'appliance']) // 匹配师傅技能 }).orderBy('createdAt', 'desc').get()提示:
_.in是云数据库的数组包含查询操作符,比==更精准。若师傅技能为['保洁'],则serviceType: 'cleaning'的订单会被匹配,而'moving'不会。
4.4 订单号生成:JD202405200001格式背后的防重逻辑
订单号JD202405200001由三部分组成:前缀JD+ 日期20240520+ 序号0001。模板中createOrder函数通过数据库事务保证序号唯一:
// cloudfunctions/createOrder/index.js exports.main = async (event, context) => { const { serviceType, time, address, phone, userId } = event const db = cloud.database() const _ = db.command try { // 1. 查询今日最大序号 const today = new Date().toISOString().slice(0, 10).replace(/-/g, '') // '20240520' const maxOrder = await db.collection('orders').where({ orderNo: _.regex({ regexp: `^JD${today}\\d{4}$` }) }).orderBy('orderNo', 'desc').limit(1).get() let seq = 1 if (maxOrder.data.length > 0) { const lastSeq = parseInt(maxOrder.data[0].orderNo.slice(-4)) seq = lastSeq + 1 } // 2. 生成订单号 const orderNo = `JD${today}${seq.toString().padStart(4, '0')}` // 3. 写入数据库 await db.collection('orders').add({ data: { orderNo, userId, serviceType, time, address, phone, status: 0, createdAt: db.serverDate() } }) return { orderNo } } catch (err) { console.error('create order failed:', err) return { error: 'create failed' } } }注意:此逻辑在高并发下仍有极小概率重复(如两请求同时查到
seq=1),生产环境应改用云数据库的autoIncrement字段或分布式 ID 生成器。模板作为入门级方案,已足够应对中小家政公司日均百单量级。
4.5 状态通知:如何让师傅实时收到新订单?
微信小程序不支持服务端主动推送,必须依赖客户端轮询或订阅消息。模板采用轻量级轮询方案:
- 师傅端页面
onShow时启动定时器,每30秒调用getOrderList查询status: 0的订单 - 为减少无效请求,可增加
lastCheckedTime缓存,只查询createdAt > lastCheckedTime的新订单
// staff-pages/index/index.js Page({ data: { newOrders: [] }, onLoad() { this.checkNewOrders() }, checkNewOrders() { const lastTime = wx.getStorageSync('lastCheckedTime') || 0 wx.cloud.callFunction({ name: 'getOrderList', data: { status: 0, since: lastTime } }).then(res => { if (res.result.data.length > 0) { this.setData({ newOrders: res.result.data }) wx.showTabBarBadge({ index: 0, text: res.result.data.length.toString() }) } wx.setStorageSync('lastCheckedTime', Date.now()) // 继续轮询 setTimeout(() => this.checkNewOrders(), 30000) }) } })提示:
wx.showTabBarBadge在 TabBar 上显示红点徽章,是提升师傅响应速度的有效手段。但需在app.json的tabBar配置中为对应页面开启badge权限。
4.6 避坑:订单状态流转的3个玄学陷阱
现象1:用户取消订单后,状态变为4,但师傅端仍显示“已接单”
原因:状态更新未广播,师傅端缓存的订单数据未刷新。
解决:用户取消后,在updateOrderStatus云函数中触发一个云函数事件(如sendNotification),通知相关师傅;或师傅端页面onShow时强制重新拉取订单列表。
现象2:两个师傅同时点击“接单”,订单状态变为1,但staffId只记录了后一个师傅
原因:updateOrderStatus未加锁,第二个请求覆盖了第一个请求的staffId。
解决:在更新时加入where条件,确保只更新status == 0的订单:
await db.collection('orders').doc(orderId).update({ data: { status: 1, staffId: operatorId }, where: { status: 0 } // ← 关键!只有原状态为0才更新 })现象3:订单状态从1变为2后,用户端订单详情页未刷新状态
原因:页面未监听onShow事件,或onShow中未调用getOrderDetail重新拉取数据。
解决:在detail.js的onShow中添加:
onShow() { const orderId = this.data.orderId wx.cloud.callFunction({ name: 'getOrderDetail', data: { orderId } }) .then(res => this.setData({ order: res.result })) }5. 本地调试与真机联调:绕过“开发者工具假数据”,直连真实微信环境
5.1 开发者工具调试:用“条件编译”区分测试与生产环境
模板中所有云函数调用均通过wx.cloud.callFunction(),但env参数需动态切换。app.js中定义全局环境变量:
// app.js App({ globalData: { env: 'release', // 'test' or 'release' cloudEnv: 'jiazheng-test' // 测试环境云开发环境ID } })在utils/request.js中封装请求方法,自动注入env:
// utils/request.js const app = getApp() function callCloud(name, data) { return wx.cloud.callFunction({ name, data, env: app.globalData.env === 'test' ? app.globalData.cloudEnv : true // true 表示使用默认环境 }) } module.exports = { callCloud }提示:
env: true表示使用小程序默认云开发环境,无需显式指定。测试时设为具体环境ID,上线前改为true即可。
5.2 真机调试:wx.openSetting()是排查权限问题的终极武器
真机上常因权限缺失导致功能异常(如地图白屏、手机号获取失败)。模板在pages/book/book.js的onLoad中加入一键授权入口:
// book.js onLoad() { // 检查必要权限 wx.getSetting({ success: (res) => { if (!res.authSetting['scope.userLocation']) { this.setData({ needLocationAuth: true }) } if (!res.authSetting['scope.address']) { this.setData({ needAddressAuth: true }) } } }) }, openSetting() { wx.openSetting({ success: (res) => { console.log('openSetting success', res) // 权限开启后,重新执行业务逻辑 this.checkPermissions() } }) }book.wxml中对应按钮:
<view wx:if="{{needLocationAuth || needAddressAuth}}" class="auth-tip"> <text>请授权位置和地址权限</text> <button bindtap="openSetting" class="auth-btn">去设置</button> </view>关键点:
wx.openSetting()会跳转到系统设置页,用户开启权限后返回小程序,此时onShow会再次触发,可重新检查权限状态。
5.3 日志追踪:console.log在真机上不可见,必须用wx.reportAnalytics
开发者工具的console.log在真机上不输出,调试时需依赖微信提供的wx.reportAnalytics上报关键节点:
// book.js submitOrder() { wx.reportAnalytics('order_submit_start', { serviceType: this.data.serviceType }) // ... 提交逻辑 wx.reportAnalytics('order_submit_success', { orderNo: res.result.orderNo }) }然后在微信公众平台 →「数据分析」→「自定义事件」中查看上报数据,可精准定位哪一步失败。
5.4 网络抓包:用charles抓取微信小程序真实请求(非模拟)
虽然模板基于云开发,但若后续接入第三方 API(如支付、短信),需抓包分析。charles是主流方案,但需注意:
- 微信小程序默认不信任
charles证书,需在 iOS 设置中安装并信任证书,Android 需在系统证书管理中导入
本文还有配套的精品资源,点击获取