简介:这是一份面向微信小程序开发者与美业商家的美容美发营销版小程序源码,覆盖品牌展示、服务预约、营销活动等常见业务模块,能够帮助读者快速搭建一套可运行的小程序项目,并作为二次开发或课程实战的参考。压缩包共1359个文件,主要包含html页面文件、png图片素材、js交互逻辑、wxss/wxml小程序样式与结构文件、json配置文件以及php后端接口脚本,各类文件分工明确,整体大小9.27MB,便于下载与部署。已有629人学习/下载。源码目录组织较清晰,前端页面与后端接口相互配套,读者可以结合预览中的样式表与脚本文件快速定位功能点,节省从零开发的时间,适合具备基础小程序知识、希望提升项目落地能力的开发者。
1. 微信小程序美容美发营销版源码:从首页装修到预约成交的完整链路
做美容美发这类到店生意,最缺的不是流量,而是把流量转成预约和复购的营销工具。这套微信小程序营销版源码,前端基于微信小程序原生框架开发,内含style.css、bootstrap.min.css、custom.css、font-awesome.min.css、sweetalert2.css等样式文件,覆盖了首页轮播、服务展示、技师介绍、优惠券领取、会员卡开卡、在线预约、订单管理、分销裂变等美容美发门店最常用的营销模块。它不是那种只能看不能用的Demo,而是把「展示、转化、留存、裂变」四个环节串起来的完整业务闭环。对小程序开发者来说,它是研究电商营销组件如何在原生小程序里落地的现成素材;对美发店或美容院的运营者来说,它是可以直接改品牌信息就上线的营销工具。接下来我会从模块设计、前端工程、核心链路和性能优化四个维度逐层拆解这套源码,并给出每个关键环节的可执行代码和参数说明,方便你直接复用到自己的项目里。
2. 营销版小程序的模块划分与关键数据模型
理解这套美容美发营销版源码,不能只看页面长相,要先看它的模块边界。一套营销版小程序和一个普通展示型小程序最大的区别在于:它多了「用户身份体系、优惠券账户、会员等级、预约单状态机」这些带业务状态的数据结构。这套源码里,tabBar 分为首页、项目、预约、我的四个入口,每个入口背后对应一组独立的数据集合,下面逐个拆解。
2.1 模块清单:从页面到功能的映射关系
整体功能模块可以划分为六个核心域:首页内容域、服务商品域、预约交易域、营销活动域、会员资产域、分销裂变域。每个域在小程序目录里都有对应的页面文件夹和逻辑层文件。
| 模块域 | 对应页面 | 核心数据字段 | 主要交互动作 |
|---|---|---|---|
| 首页内容域 | pages/index | banner列表、公告、门店信息 | 轮播点击、拨打电话 |
| 服务商品域 | pages/service | service_id、price、duration | 卡片浏览、加入购物车 |
| 预约交易域 | pages/booking | staff_id、time_slot、status | 选择技师、选时段、提交预约 |
| 营销活动域 | pages/marketing | coupon_id、threshold、discount | 优惠券领取、拼团/秒杀入口 |
| 会员资产域 | pages/member | level、points、balance | 开卡、签到、积分兑换 |
| 分销裂变域 | pages/share | inviter_id、commission | 生成海报、绑定上下级 |
这六个域不是分散的瓦片,而是有数据流向的闭环。用户从首页 banner 进入项目详情,通过营销活动领取优惠券,然后进入预约页选择到店时间,预约完成后获得会员积分,积分又反过来驱动下一次消费折扣和分享裂变。如果你手头这个 zip 解压后只有前端源码,没有配套的云函数或后端接口,常见做法是自己在微信云开发里按字段设计 collection 即可,比如appointment集合的文档结构就是预约交易域的核心。
{ "_id": "appointment_20250115_001", "openid": "oXk8J5abc123", "shop_id": "store_001", "service_id": "svc_cut_hair", "staff_id": "staff_008", "date": "2025-01-18", "time_slot": "14:00-14:45", "status": "pending", "coupon_id": "coupon_2025_newyear", "discount_amount": 20, "pay_amount": 80, "create_time": 1705305600000 }这段 JSON 是预约单的最小可用结构。status字段在源码的预约列表页里控制按钮的渲染,比如pending(待确认)、confirmed(已确认)、completed(已完成)、cancelled(已取消)四个状态对应不同的操作按钮和颜色标签。time_slot用字符串"14:00-14:45"而不是时间戳,是为了在页面渲染时段选择器时直接做字符串比对,省去格式转换。coupon_id和discount_amount必须同时存在,保证订单快照里有优惠来源和优惠金额,这是营销版小程序对账的关键。
2.2 为什么美容美发行业需要「服务+营销」双轨模型
普通电商小程序的模型是「商品-SKU-库存」,而美容美发小程序的核心模型是「服务-技师-时段」。服务本身不可存储,卖的是技师的时段产能;营销工具也必须围绕时段来设计,比如「非高峰时段7折券」「新客首次体验价」「老客带新客赠一次护理」,这些营销动作都落在「人-服务-时间」这三个维度的交叉点上。
这套源码里两个核心自定义组件值得单独看:coupon-card和staff-picker。coupon-card接收coupon对象,渲染出优惠券面的样式,同时处理「立即领取」和「已领取」两种状态切换;staff-picker接收staffList数组,渲染技师头像列表,选中后高亮并在底部弹出该技师的可用时段。组件化的好处在于,营销活动和预约流程都可以复用这两个组件,不会因为页面不同而出现多份拷贝的业务逻辑。
// components/coupon-card/index.js Component({ properties: { coupon: { type: Object, value: {}, observer: function(newVal) { this.setData({ statusText: newVal.received ? '已领取' : '立即领取', expired: newVal.end_time < Date.now() }); } } }, methods: { onClaimTap() { if (this.data.expired) return; this.triggerEvent('claim', { coupon_id: this.data.coupon.coupon_id }); } } });这段代码的逻辑要点在observer里:当父页面异步请求优惠券列表返回后,coupon属性被赋新值,组件内部立即更新状态文案和是否过期标记,不需要父页面额外调用组件方法。triggerEvent是微信自定义组件向父页面通信的标准方式,这里把coupon_id传给父页面,由父页面调用wx.request或者云函数claimCoupon完成领取操作,组件不负责网络请求,保持单一职责。这样做的好处是:首页、营销活动页、会员中心三个场景都可以引这个组件,领取逻辑只写一次。
2.3 营销活动数据模型:优惠券的生成与核销边界
优惠券模块是营销版小程序的核心资产。源码里优惠券的模型包含threshold(满减门槛)、discount_type(满减/折扣)、valid_days(领取后有效期)、range_type(全场/指定项目)四个关键字段。这些字段直接决定页面上的判断逻辑和接口入参校验。
function validateCoupon(coupon, cartAmount, serviceIds) { if (coupon.range_type === 'specific' && !coupon.service_ids.some(id => serviceIds.includes(id))) { return { valid: false, reason: '当前项目不可使用该优惠券' }; } if (coupon.discount_type === 'full_reduction' && cartAmount < coupon.threshold) { return { valid: false, reason: `还差${coupon.threshold - cartAmount}元可用此券` }; } return { valid: true, amount: coupon.discount_type === 'discount' ? cartAmount * coupon.rate : coupon.value }; }这里range_type是specific时要额外校验service_ids,否则用户拿着一张「仅限染发项目」的券去结剪发的单,核销时后台会报错。discount_type是discount时用的是折扣率,比如0.8代表八折,前端算完金额还要再Math.round()一次,避免出现小数分为。源码在utils/coupon.js里还封装了calcBestCoupon函数,从用户持有的多张券里自动选出最优券,逻辑是遍历所有可用券调用validateCoupon,比较实付金额取最小值,这是营销型小程序和普通展示型小程序拉开差距的地方。
3. 前端工程结构解析:样式组织、组件通信与页面路由配置
这节进入源码本身,把目录结构、样式组织方式和页面路由配置讲清楚。很多开发者拿到这套源码后第一反应是把style.css和bootstrap.min.css直接删掉——在小程序里确实不能直接用 bootstrap 的类名做布局,但源码这么放是有原因的,值得先理解再动手。
3.1 文件清单的作用与取舍:哪些直接用、哪些要改造
zip 里出现的style.css、bootstrap.min.css、custom.css、custom.min.css、font-awesome.min.css、select2-bootstrap.min.css、sweetalert2.css这些文件,其实是很多模板作者从 Web 端管理后台或 H5 模板迁移到小程序时残留的产物。它们不会全部被打进小程序包体,但有三个文件可以起到参考作用:
| 文件 | 在小程序中的真实用途 | 处理建议 |
|---|---|---|
custom.css | 定义了主题色变量、按钮圆角、卡片阴影 | 提取变量到app.wxss的page选择器 |
bootstrap.min.css | 栅格系统的类名可以对应到小程序 flex 布局 | 只借鉴思路,不要引入文件 |
sweetalert2.css | 弹窗样式参考 | 替换为wx.showModal或自定义弹窗组件 |
最值得留意的其实是custom.css里的主题色变量部分,美容美发门店通常有固定的品牌色(比如深紫、玫瑰金、墨绿),把这几个颜色提取到app.wxss里做成 CSS 变量,后续所有页面的按钮、标签、价格文字都能统一跟随品牌色切换。其他三个 bootstrap 风格文件直接删掉,不会影响功能,小程序有自己的一套样式体系,留着反而让开发者工具不停提示未使用的样式规则。
3.2 页面目录结构与 app.json 的路由注册逻辑
打开解压后的根目录,标准的原生小程序工程结构是pages、components、utils、images四个目录加app.js、app.json、app.wxss三个全局文件。pages下每个业务域一个文件夹,比如pages/index/index是首页,pages/booking/index是预约页。app.json里 pages 数组第一项就是启动页,源码的启动页是pages/index/index,tabBar 配置了四个入口。
{ "pages": ["pages/index/index", "pages/service/index", "pages/booking/index", "pages/member/index", "pages/order/list"], "window": { "navigationBarBackgroundColor": "#2F1B33", "navigationBarTitleText": "品牌名", "navigationBarTextStyle": "white", "backgroundColor": "#f7f4f2" }, "tabBar": { "color": "#999999", "selectedColor": "#2F1B33", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/service/index", "text": "项目" }, { "pagePath": "pages/booking/index", "text": "预约" }, { "pagePath": "pages/member/index", "text": "我的" } ] } }这里的navigationBarBackgroundColor和tabBar.selectedColor需要设置为同一个品牌色,保持视觉入口和内容页的一致性。backgroundColor是窗口下拉露出部分的颜色,通常比导航栏颜色浅一个层级,让页面滚动时体验柔和。在app.json修改 pages 数组顺序即可修改程序启动时的第一屏,很多运营想把「营销活动页」设为启动页,直接把它移到数组第一位就行,注意 tabBar 页面必须在 pages 数组里且只能有四个。
3.3 自定义组件如何拆:营销卡片、技师选择器与服务列表
组件拆分的粒度决定了这个小程序后续能不能持续加功能。这套源码的components目录下,service-card、staff-picker、coupon-card、empty-placeholder四个组件是最核心的复用单元。service-card的properties接收service对象和index序号,页面引用时通过wx:for循环渲染。
// components/service-card/index.js Component({ properties: { service: { type: Object, value: {} }, index: { type: Number, value: 0 } }, methods: { onTap() { const serviceId = this.data.service.service_id; wx.navigateTo({ url: `/pages/service/detail?id=${serviceId}` }); wx.reportAnalytics('service_click', { service_id: serviceId, position: this.data.index }); } } });wx.reportAnalytics是微信小程序的数据上报接口,这里用它来记录用户点击了哪个服务、在列表第几位,后续在微信公众平台「统计-事件分析」里能看到「服务点击次数」和「曝光-点击转化率」。wx.navigateTo跳转详情页时通过 URL 参数传递service_id,详情页在onLoad生命周期里通过options.id拿到参数并请求详情接口。这里没有用组件自身跳转后还要getCurrentPages()回传数据,链路清晰:列表页只管列表渲染和埋点,详情页独立请求数据,解耦度最好。
3.4 首页动线设计:banner、金刚区、营销浮窗的模块编排
首页的动线编排直接决定转化率。这套源码首页从上到下的模块顺序是:banner轮播图、金刚区四宫格(预约、优惠券、会员卡、签到)、限时秒杀横条、今日推荐服务列表、底部营销浮窗。这个顺序本身就值得抄:轮播图负责品牌传递和活动曝光,金刚区负责功能分流,秒杀横条制造紧迫感,服务列表承接交易,底部浮窗提供兜底转化。
<view class="page-wrapper"> <swiper indicator-dots autoplay circular interval="3500" duration="500"> <block wx:for="{{banners}}" wx:key="banner_id"> <swiper-item> <image src="{{item.image_url}}" mode="aspectFill">// utils/auth.js function login() { return new Promise((resolve, reject) => { wx.login({ success: async (res) => { if (res.code) { try { const { data } = await wx.request({ url: `${BASE_URL}/api/auth/login`, method: 'POST', data: { code: res.code, scene: 'miniapp' } }); wx.setStorageSync('token', data.token); wx.setStorageSync('userInfo', data.userInfo); resolve(data); } catch (e) { reject(e); } } else { reject(new Error('wx.login failed: ' + res.errMsg)); } }, fail: reject }); }); }wx.login的success回调里拿到的code有效期只有 5 分钟,而且只能用一次,所以后端拿到 code 后要立即调code2Session接口换取openid和session_key,再签发自定义 token 返回。前端把 token 写入Storage,后续请求在wx.request的 header 里加Authorization: Bearer ${token}。判断登录态过期的方式是请求返回 401 状态码时重新调login()刷新 token,常见做法是在utils/request.js里包一层 Promise 拦截器,这样所有业务页面的请求都不用关心 token 过期的事,全部由统一层处理。
4.2 营销活动页的优惠券发放流程:数量校验与防重复领取
优惠券发放最怕两件事:超发和重复领取。超发靠后端库存字段原子扣减解决,在前端能做的校验是「未登录用户先去登录」「已领取的用户按钮置灰」。这节的代码覆盖了前端处理和状态反馈的完整流程。
// pages/marketing/index.js async function onClaimCoupon(e) { const { couponId } = e.detail; const token = wx.getStorageSync('token'); if (!token) { wx.navigateTo({ url: '/pages/login/index' }); return; } try { const res = await request({ url: `/api/coupon/claim`, method: 'POST', data: { coupon_id: couponId }, loading: true }); if (res.code === 0) { const couponList = this.data.couponList.map(item => { if (item.coupon_id === couponId) { item.received = true; item.stock = item.stock - 1; } return item; }); this.setData({ couponList }); wx.showToast({ title: `领取成功,已到账${res.data.expire_text}`, icon: 'none' }); } } catch (err) { if (err.code === 'COUPON_RECEIVED') { wx.showToast({ title: '您已领过这张券了', icon: 'none' }); } else if (err.code === 'COUPON_SOLDOUT') { wx.showToast({ title: '手慢了,券被抢完了', icon: 'none' }); } } }这段代码的关键是e.detail里拿到的couponId,也就是第 2 章自定义组件coupon-card通过triggerEvent传上来的数据。领取成功后不是重新请求列表,而是就地更新本地couponList里对应项的received和stock字段,这样界面响应几乎无延迟。loading: true是request封装里的全局加载态开关,请求期间底部弹出 loading 动画,防止用户连续点击重复提交。领券接口的后端语义是幂等的——同一个coupon_id重复提交返回COUPON_RECEIVED,前端识别错误码给出对应提示,而不是笼统的「领取失败」。
4.3 预约流程的状态机:选技师、选时段到提交预约
预约是这个源码里业务复杂度最高的模块。用户要依次选择:服务项目、技师、日期、时段、备注、优惠券,最后提交。每一步之间都有联动关系:选了某个技师后,可预约时段会变化;选了时段后,可用的优惠券范围也会变化。
// pages/booking/index.js Page({ data: { staffId: '', date: '', timeSlot: '', serviceId: '', availableSlots: [], remark: '' }, async onStaffChange(e) { const staffId = e.currentTarget.dataset.id; this.setData({ staffId, timeSlot: '', availableSlots: [] }); const res = await request({ url: '/api/staff/slots', data: { staff_id: staffId, date: this.data.date } }); this.setData({ availableSlots: res.data.slots }); }, submitAppointment() { const { staffId, date, timeSlot, serviceId, remark } = this.data; if (!staffId || !date || !timeSlot || !serviceId) { wx.showToast({ title: '请选择完整的预约信息', icon: 'none' }); return; } request({ url: '/api/appointment/create', method: 'POST', data: { staff_id: staffId, date, time_slot: timeSlot, service_id: serviceId, remark }, loading: true }).then(() => { wx.redirectTo({ url: '/pages/order/success?source=booking' }); }); } });onStaffChange里先清空之前选的timeSlot和availableSlots,再请求新技师的可用时段,这个顺序很重要。如果不先清空,用户先选技师 A 再切技师 B,页面上会残留技师 A 的时段数据,用户拿技师 B 选了技师 A 的时段提交,后端校验报错,体验很差。提交前的字段校验在submitAppointment里集中处理,少选了哪项直接 toast 提示,不在四个字段都齐全前发起请求。成功后的wx.redirectTo跳转成功页而不是navigateTo,这样用户点返回不会回到填好的表单页,避免重复提交同一预约。
4.4 预约冲突检测与门店营业时间参数配置
预约模块最大的坑是冲突检测。美容美发店的多个服务可能由同一个技师完成,如果预约接口不做时段占用校验,一个技师同一时段会被约两单。前端可以提前做到的是:从接口返回的availableSlots已经过滤掉被占用的时段,但前端仍需处理一个边界——用户停留在页面时间过长,看到的时段可能已经被别人抢走。
// utils/slot.js const BUSINESS_HOURS = { start: 10, end: 20 }; const SLOT_DURATION = 45; function generateSlots(date, bookedSlots) { const slots = []; for (let h = BUSINESS_HOURS.start; h < BUSINESS_HOURS.end; h++) { for (let m = 0; m < 60; m += SLOT_DURATION) { const label = `${pad(h)}:${pad(m)}`; if (m + SLOT_DURATION > 60) continue; slots.push({ label, disabled: bookedSlots.includes(label) }); } } return slots; }generateSlots接收日期和已被占用的时段列表,返回完整的时段数组并标记disabled。BUSINESS_HOURS是门店营业时间,SLOT_DURATION是每个服务的基础时长,这两个参数在源码里是硬编码配置,真实项目应该改成从后端配置读取,因为有些门店中午不休息,有些店晚上要到 21 点。提交预约时后端必须再校验一次时段是否仍可预约,前端防不住「两人同时提交同一时段」的并发场景,这属于后端事务边界,前端能做的就是在提交失败返回SLOT_TAKEN错误码时,重新拉取availableSlots并提示用户选择新时段。
5. 性能优化、真机调试与运营埋点:上线前必须处理的关卡
功能跑通只是第一步,营销版小程序上线前有三个关卡必须逐一处理:白屏性能、按钮防抖、运营埋点。这一章的实操性很强,每项都可以直接照做。
5.1 包体瘦身与首页渲染性能优化:图片懒加载和分包策略
拿到这套源码后第一件事是看「详情-基本信息」里的代码包大小。微信小程序主包限制 2MB,超过就必须做分包。美容美发小程序的图片资源通常很多:技师头像、服务项目图、banner 活动图,这类图片全部走 CDN 是基本要求,本地images目录里最好只保留 tabBar 图标和应用图标。
<image src="{{item.image_url}}" lazy-load="{{true}}" mode="aspectFill" binderror="onImgError" />lazy-load属性是微信小程序的图片懒加载开关,它会等图片进入视口前 3 倍屏高时才真正开始加载网络图,首页长列表的渲染性能会明显提升。binderror处理图片加载失败的情况——如果 CDN 图片被误删,onImgError里把src替换成本地默认占位图,避免页面出现破图裂图。对于预约列表和历史订单这类低频访问页面,放到分包subpackages里,用户点击时按需加载,首包体积能再降一截。
5.2 页面滚动与 canvas 生成的注意事项:长列表和分享海报
营销版小程序不免要做分享海报,用 canvas 绘制海报时有个高频踩坑点:wx.createCanvasContext绘制图片先要在onLoad里调用wx.getImageInfo拿到图片本地路径,不能在 canvas 里直接用网络 URL。而且生成海报是异步过程,用户快速点击「保存图片」会拿到空白图,常见做法是加一个 loading 状态锁。
async function generatePoster() { if (this.data.posterGenerating) return; this.setData({ posterGenerating: true }); wx.showLoading({ title: '生成中...' }); const { path } = await getImageInfo(this.data.qrcodeUrl); const ctx = wx.createCanvasContext('posterCanvas', this); // 绘制背景、品牌名、二维码 ctx.draw(false, () => { wx.canvasToTempFilePath({ canvasId: 'posterCanvas', success: (res) => { this.setData({ posterPath: res.tempFilePath, posterGenerating: false }); wx.hideLoading(); }, fail: () => { this.setData({ posterGenerating: false }); wx.hideLoading(); } }); }); }getImageInfo返回的path是图片的本地临时缓存路径,只有这张图片被绘制之后,canvasToTempFilePath生成的tempFilePath才能被wx.saveImageToPhotosAlbum保存。posterGenerating这个状态锁防止用户在生成过程中连续点击,避免 canvas 绘制冲突和重复提示。二维码图片的来源是后端接口返回的小程序码,小程序码的scene参数里带上inviter_id,这样新用户扫码进来就能自动绑定上下级关系,分享裂变才能形成闭环。
5.3 真机调试与常见报错对照表
开发工具里一切正常,一上真机就出问题是小程序开发的常态。下面这张表整理了这套美容美发营销版源码最常见的四类真机问题、原因和解决手段。
| 问题现象 | 触发场景 | 原因 | 解决方案 |
|---|---|---|---|
| 图片加载不出来 | 苹果手机 | 图片链路为 http 未加白名单 | 在公众平台「开发-开发设置-服务器域名」里配置 downloadFile 合法域名 |
| 页面白屏 | 冷启动 | 分包异步代码执行时序问题 | wx.nextTick里做页面初始化,或把核心数据请求前移 |
| canvas 生成海报空白 | 安卓机型 | 绘制异步时序,canvas 宽高未设置 | 给 canvas 加canvas-id且style="width:300px;height:400px",绘制前wx.nextTick |
| 预约提交重复 | 弱网双击 | 按钮未做提交锁 | 提交函数开头if (this.data.submitting) return; this.setData({ submitting: true }) |
需要额外提醒的是第三项 canvas 真机空白,在开发者工具里几乎不会复现,一定要在「真机调试」模式下测。而且 canvas 绘制用的字体在小程序端只支持系统默认字体,不要在绘制时尝试ctx.font = 'bold 16px sans-serif'加自定义字体,iOS 和 Android 渲染结果差异非常大,营销文案最好直接用<view>叠加在 canvas 上而不是画进 canvas 里。
5.4 运营级埋点清单:从页面浏览到预约成功全链路
营销版小程序上线后必然要关注转化漏斗,埋点数据是运营决策的基础。这套源码有一个utils/tracker.js文件,封装了统一的埋点上报函数,核心代码如下:
// utils/tracker.js function track(eventName, params = {}) { const sessionId = wx.getStorageSync('session_id') || genSessionId(); const userInfo = wx.getStorageSync('userInfo') || {}; wx.reportAnalytics(eventName, { ...params, session_id: sessionId, openid: userInfo.openid || '', ts: Date.now() }); }运营关注的核心事件包括:banner_click(banner 点击)、service_view(服务详情浏览)、coupon_claim_success(优惠券领取成功)、booking_submit_success(预约提交成功)、member_open_card(开卡成功)、share_success(分享成功)。这六个事件串起来就是一个完整的营销漏斗:曝光 → 浏览 → 领券 → 预约 → 开卡 → 分享。banner_click事件的position参数要精确到第几张轮播图,service_view要带上服务项目 ID 和所属分类,这样后续才能看出美发和美容两个业务线哪个转化率更高、哪个位置触达用户最有效。
6. 从优惠券到复购:会员成长值与分享裂变的落地技巧
最后一章收在两个具体技巧上:会员等级如何驱动复购,分享裂变参数怎么埋才有效。这两个点直接决定美容美发小程序上线三个月后的用户活跃度和客单价。
6.1 会员积分规则的参数化配置
源码的会员体系实现了「消费得积分、积分抵现金、等级差异权」三层结构。但如果你只是让程序员硬编码一套积分规则,运营改规则就得发版,非常不灵活。推荐把规则抽成配置,存到云数据库或远程配置中心,前端实时拉取。
{ "points_per_yuan": 1, "points_deduct_rate": 0.1, "level_rules": [ { "level": "普通会员", "threshold": 0, "discount": 1, "birthday": false }, { "level": "银卡会员", "threshold": 500, "discount": 0.95, "birthday": true }, { "level": "金卡会员", "threshold": 1500, "discount": 0.9, "birthday": true } ] }points_per_yuan表示每消费 1 元获得 1 积分,points_deduct_rate表示积分抵扣比例上限为 10%,level_rules里配置每个等级对应的累计消费门槛、折扣区间和生日特权。前端在支付成功回调里解析配置,把积分变动和等级升级结果展示在「支付成功」页面上,配合「再消费 200 元升级金卡,享九折优惠」的引导文案,复购动力直接拉满。这套参数化配置的好处是运营调门槛只改后端数据,不用动前端代码。
6.2 分享裂变的参数回路:scene 携带 inviter_id 的完整做法
最后一个技巧是分享裂变的参数回路。小程序分享裂变需要一个关键机制:新用户从分享链接点进来时,如何知道他是谁带来的。微信小程序的onShareAppMessage里设置path参数可以携带自定义参数,但path长度有限制,参数过多容易溢出,业界通用做法是把参数塞进小程序码的scene字段里,scene最多支持 32 个可见字符。
onShareAppMessage() { const inviterId = wx.getStorageSync('userInfo').user_id; const scene = `inviter_id=${inviterId}`; return { title: '我在XX美发领了一张新客专享券,陪你一起变美', path: `/pages/index/index?scene=${encodeURIComponent(scene)}`, imageUrl: this.data.shareImage }; }新用户从分享卡片进入后,在onLoad的options.scene里拿到inviter_id,调用绑定接口建立上下级关系。分享文案的标题是转化的关键变量,「新客专享券」「陪你一起变美」比「欢迎光临本店」的点开率高很多。imageUrl用分享海报而不是默认截图,海报上有品牌名、优惠力度和二维码,信息密度完全不一样。这个回路跑通之后,配合第 5 节的埋点数据,你能清楚看到哪个渠道的分享带来了多少新客和多少预约单,再把预算花在转化率最高的渠道上,获客成本会显著下降。
本文还有配套的精品资源,点击获取