共享WiFi营销小程序源码开发:数据模型、uniapp与结算防重
2026/9/15 5:40:15 网站建设 项目流程

简介:共享WIFI营销小程序源码是一套面向线下门店与代理商的全栈营销解决方案,覆盖扫码连WiFi、广告分成、红包激励、社区拼团及自媒体文章发布等核心场景。源码采用PHP后端配合小程序前端,整合了门店WiFi、热点新闻、代理商体系与广告营收模块,能够帮助商家沉淀用户、通过用户点击广告获得提成,实现平台、门店、代理商多方共赢。包体包含2000个文件,压缩包大小25.16MB,以HTML页面、PHP接口、JavaScript脚本、CSS样式为主,同时配有PNG、GIF、SVG图片素材及微信小程序所需的WXML、WXSS文件,结构较为完整,便于二次开发与功能扩展。资源目前已有1180人学习下载,适合具备一定PHP与小程序开发基础、希望快速搭建共享WiFi商业平台的技术人员参考。通过源码可梳理红包营销、拼团分销、自媒体投稿等功能的具体实现逻辑,并直接复用其前后端界面与业务模块,缩短自研周期。

1. 共享WIFI营销小程序源码:本质是一套连WiFi前的营销触点

一个开在商场里的手机维修店,把收银台下面那台路由器刷成共享WiFi系统后,顾客扫码进入小程序,先看到一张门店优惠券或一段广告,点击“连接WiFi”并授权手机号,然后免费上网,商家后台则多了一条会员记录。所谓共享WIFI营销小程序源码,就是把扫码进店、连接网络、手机号授权、上下级归属、佣金结算这一整条链路固化下来的代码集合。它解决的是商家把“公共场所WiFi连接”这个刚需动作,转化为会员沉淀和推广触达的问题。适合做本地生活SaaS的团队、连锁门店运营者,以及正在评估这类源码质量的外包开发。拿到源码先别急着部署,先看数据模型、scene取参和结算接口的幂等实现,这三处基本决定一套源码能不能跑得久。

2. 先看数据模型:设备表、用户表、连接记录怎么定,业务边界就在这

2.1 共享WiFi的完整链路,从设备到分佣一共经过几站

共享WIFI营销小程序与普通工具类小程序最大的不同,是每次用户连接网络都要同时写三块数据:设备信息、用户身份、连接行为。设备信息描述“顾客连的是哪台路由器”;用户身份描述“这个顾客是谁,是谁带来的”;连接行为则决定“这笔佣金该不该发、该发给谁”。很多共享WIFI营销源码号称功能丰富,但核心围绕的其实是下面这条链路:

顾客扫设备上的小程序码 → 小程序解析设备标识 → 微信静默登录获得openid → 用户授权手机号 → 点击“已连接WiFi” → 后端校验连接行为 → 发放用户奖励并更新上级佣金 → 记录流水供后续提现。

如果拿到的源码连这条链路都描述不清楚,说明项目可能只是把通用商城源码改了皮。建议先把数据库表读完,再去看接口,最后才看前端页面。数据模型能直接暴露这家源码作者对业务的理解程度。

2.2 device表:为小程序码scene参数单独留一个短码字段

设备表是最容易做错的地方。很多源码直接把WiFi的SSID或MAC地址塞进小程序码参数里,但微信小程序码的scene参数限制是32个可见字符,一个常见的MAC地址形如A8:6B:AD:12:34:56就占了17位,还要拼上邀请人ID等参数就会超限。更合理的方式是给每台设备单独分配一个短码,类似邀请码机制。

CREATE TABLE `device` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `sn` char(8) NOT NULL COMMENT '设备短码,用于小程序码scene参数', `wifi_name` varchar(64) NOT NULL COMMENT 'WiFi SSID', `wifi_password` varchar(64) NOT NULL COMMENT 'WiFi密码', `merchant_id` int unsigned NOT NULL DEFAULT '0' COMMENT '所属商家', `status` tinyint NOT NULL DEFAULT '1' COMMENT '1启用 0停用', `expire_at` datetime DEFAULT NULL COMMENT '设备到期时间', `created_at` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uniq_sn` (`sn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='共享WIFI设备';

这里sn字段不要用自增ID代替,因为自增ID可被遍历,别人拿到设备A的ID就能猜测设备B的标识。固定的8位短码建议用大小写字母加数字的随机串,生成时注意排除容易混淆的字符如0/O1/Iwifi_password在实际场景里通常不会明文暴露给用户,小程序端通过接口获取后在页面里动态显示或复制,所以这个字段的读取接口一定要加设备状态的判断,停用设备不能继续返回密码。

2.3 connect_log表:一次连接记录同时承载结算和防刷

连接记录表是这套源码里最核心的表,它既要记录业务事实,又要承担防重复结算的重任。设计的时候一定要有联合唯一索引,最常用的是“用户+设备+日期”三重唯一,含义是同一用户同一台设备一天最多结算一次。

CREATE TABLE `connect_log` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `user_id` int unsigned NOT NULL COMMENT '用户ID', `device_id` int unsigned NOT NULL COMMENT '设备ID', `ip` varchar(45) DEFAULT NULL COMMENT '点击时出口IP', `network_type` varchar(16) DEFAULT NULL COMMENT 'wifi或4g', `status` tinyint NOT NULL DEFAULT '0' COMMENT '0待确认 1已结算', `reward_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '奖励金额', `created_at` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uniq_user_device_day` (`user_id`,`device_id`,`created_at`), KEY `idx_device_created` (`device_id`,`created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户连接设备记录';

需要注意created_at参与唯一索引会有精度问题,如果程序里写入的时间精确到秒,倒也无妨;但如果你打算用ON DUPLICATE KEY UPDATE做幂等,就得保证同一事务里写入的created_at严格一致。更稳妥的方案是在表里加一个connect_date字段,只存2025-06-01这样的日期字符串,唯一索引改为(user_id, device_id, connect_date)。这样做还有一个好处:按天统计佣金时直接走这个字段,查询性能优于对created_atDATE()函数处理。

3. uniapp微信小程序扫码进页面:scene参数、静默登录与手机号授权的正确写法

3.1 小程序码scene参数的解析,decodeURIComponent这一步不能省

共享WiFi设备上贴的小程序码,一般是后端通过微信getwxacodeunlimit接口生成的,生成时把设备短码和上级用户ID拼进scene参数。用户扫码后进入小程序的onLoad,拿到的options.scene是一段经过URL编码的字符串,必须先做decodeURIComponent再解析。

// pages/index/index.vue onLoad(options) { // 二维码进入时,参数都在 options.scene 里,且是编码后的 const scene = decodeURIComponent(options.scene || '') // 约定的scene格式:d=设备短码&u=上级用户id const params = this.parseScene(scene) this.deviceSn = params.d this.puid = params.u if (!this.deviceSn) { uni.showToast({ title: '请扫描设备上的二维码进入', icon: 'none' }) return } this.fetchWifiInfo() }, methods: { parseScene(scene) { const result = {} if (!scene) return result scene.split('&').forEach(item => { const pair = item.split('=') if (pair.length === 2) result[pair[0]] = pair[1] }) return result } }

这段代码里值得注意的有两点。第一是options.scene只有在“扫小程序码”进入时才存在,普通分享卡片进入时是另一个字段,调试时不要混淆。第二是解析逻辑尽量自己写,不要依赖qs这类库,因为微信的scene参数只传少量自定义数据,自己解析反而更容易排查问题。puid参数就是上下级归属关系的入口,用户首次扫码时把这个ID存进用户表,后续这个用户产生的连接奖励就会同步给上级。

3.2 微信小程序静默登录:wx.login拿到code后,换取openid必须放后端

获取openid的流程有固定的安全要求,code2Session接口的调用凭据是小程序的appidsecret,这两个信息一旦暴露在小程序前端代码里,任何人都能伪造请求获取用户openid。所以正确做法是小程序端调用wx.login获取临时code,然后传给自己的后端,由后端请求微信接口。

uni.login({ provider: 'weixin', success: async (loginRes) => { // loginRes.code 有效期5分钟,且只能使用一次 const { data } = await uni.request({ url: 'https://api.example.com/wifi/login', method: 'POST', data: { code: loginRes.code } }) // 后端返回自定义token,后续接口都带这个token uni.setStorageSync('token', data.token) } })

后端收到这个code后,调用微信jscode2session接口,用appidsecretjs_code三个参数换取openidsession_keysession_key千万不要返回给前端,它只留在服务端用于解密敏感数据。换取成功后,用自己的逻辑生成业务token返回给小程序。很多共享WiFi营销源码在这一步偷懒,直接在PHP里写了微信secret并允许前端传入code换取,甚至为了调试方便把secret写死在uniapp的代码里,这类源码基本可以直接弃用。

3.3 手机号授权:按钮必须用户主动点击,无法静默获取

共享WiFi营销的核心诉求是获取用户手机号,但微信对手机号获取的限制很严格,无法通过wx.login静默拿到。必须在小程序页面放一个button组件,设置open-type="getPhoneNumber",由用户主动点击触发。

<button open-type="getPhoneNumber" @getphonenumber="onPhoneNumber" class="connect-btn"> 一键连接WiFi </button>
async onPhoneNumber(e) { // e.detail.code 是动态令牌,只能用一次 if (!e.detail.code) { uni.showToast({ title: '需要授权手机号才能连接', icon: 'none' }) return } const { data } = await uni.request({ url: 'https://api.example.com/wifi/phone', method: 'POST', data: { code: e.detail.code, // 前端拿到的动态令牌 deviceSn: this.deviceSn, // 设备短码 puid: this.puid // 上级用户ID }, header: { token: uni.getStorageSync('token') } }) // 后端此时才有真实手机号,前端拿不到 }

这里有个常见的坑:有些开发者在e.detail里直接取encryptedDataiv去解密手机号,这是旧版的做法。新版本接口在用户同意后直接返回code字段,后端需要拿这个code去调用微信getuserphonenumber接口换取真实手机号。调用这个接口需要先获取access_tokenaccess_token有效期7200秒,后端要做缓存,不能每个请求都去微信重新换取,否则高频场景下很容易触发频率限制。另外这个接口要求小程序已完成微信认证,未认证的小程序无法使用手机号快速验证组件,这是上线前必须确认的硬性条件。

4. 共享WiFi营销后端结算:PHP佣金发放、唯一索引防重与防薅参数设计

4.1 结算接口的调用时序,点和线之间要加一道确认

用户点击“已连接WiFi”按钮后,前端会向后端提交一个连接确认请求,这个请求来到后端时,需要依次做以下校验:token是否有效,设备是否存在且启用,用户是否已绑定手机号,今日该用户对该设备是否已结算过,设备今日结算次数是否已达上限。全部通过后,才进入金额计算和佣金发放。

// 连接确认与结算入口 public function connectConfirm($userId, $deviceSn, $ip) { // 1. 设备校验 $device = $this->findDeviceBySn($deviceSn); if (!$device || $device['status'] != 1) { return $this->fail('设备不存在或已停用'); } // 2. 手机号绑定校验 $user = $this->findUserById($userId); if (empty($user['phone'])) { return $this->fail('请先授权手机号'); } // 3. 当日重复结算校验 $today = date('Y-m-d'); $exists = $this->query( "SELECT id FROM connect_log WHERE user_id = ? AND device_id = ? AND connect_date = ?", [$userId, $device['id'], $today] ); if ($exists) { return $this->fail('今日已连接过该设备'); } // 4. 进入事务结算 $this->beginTransaction(); try { $this->insertConnectLog($userId, $device['id'], $ip, $today); $this->updateUserBalance($userId, $device['reward_amount']); $this->updateParentReward($user['parent_id'], $device['parent_reward']); $this->commit(); return $this->success('连接成功'); } catch (Exception $e) { $this->rollback(); return $this->fail('系统繁忙,请稍后重试'); } }

这段代码里的updateParentReward是给上级用户发放推广奖励,发放逻辑放在同一个事务里,保证“用户到账”和“上级到账”要么同时成功,要么同时失败。共享WiFi营销源码最常见的错误是把用户奖励和上级奖励拆成两个接口调用,用户到账了上级没到账,投诉率极高。注意第三步的当日重复校验用的是select先查再插,在高并发下会有竞态问题,所以connect_log表里的(user_id, device_id, connect_date)唯一索引是兜底防线,两个请求同时进来时,数据库会拒绝后插入的那个。

4.2 防薅参数怎么设:把单设备日奖励次数卡在合理区间

参数推荐值说明
单用户单设备日结算上限1次超过即提示“今日已连接”
单设备日结算总上限50次防止一台设备被批量刷量
单用户日结算总上限30次防止同一用户扫多台设备薅佣金
手机号绑定校验强制未绑定手机号不进入结算
结算冷静期60秒点击按钮到确认成功之间至少间隔60秒

这里单独说下结算冷静期。用户扫码进入小程序、连接WiFi、再点击确认,正常操作至少需要几十秒。如果日志显示某用户从进入页面到点击确认只用了不到1秒,大概率是脚本模拟请求。后端可以把页面进入时间记录在token对应的缓存里,确认接口校验当前时间与进入时间的差值,小于60秒直接拒绝。这样虽然不能完全杜绝刷量,但能把批量脚本的成本抬高。

4.3 探活有没有必要做:三条真实边界告诉你怎么选

很多共享WiFi营销源码声称能做“真实连接验证”,实际是做不到完全精确的。第一条路是拿用户设备MAC地址去路由器后台查在线状态,但小程序根本拿不到用户的MAC地址,这条路直接堵死。第二条路是判断用户当前网络类型是否为WiFi,小程序端可以获取networkType,但用户开着自己的4G网络点确认也能通过,这个校验形同虚设。第三条路是比对出口IP,要求门店宽带拥有固定公网IP,且用户点击确认时小程序主动请求一个探活接口,后端比对两次请求的出口IP是否一致,这个方案成本高、误杀率高,家庭宽带用户经常因为IP频繁变化被错误拒绝。

所以行业里的通用做法是:不做强探活,改用“手机号绑定+单设备日上限+冷静期”三道软约束。这套组合拳不能拦截所有恶意用户,但能把损失控制在可接受范围内。真正要防的不是个人用户,而是用脚本批量刷量的黑产,对这批人,软约束加数据监控比技术探活更有效。

5. 上线前最后一步:备案备注、并发验证和三类常见返工

5.1 小程序备案备注信息怎么填,决定审核是否顺利

2023年9月之后微信小程序新提交版本必须完成备案,共享WiFi类小程序属于“生活服务-商业服务”,备案备注信息要写清实际业务。常见的填法是“提供商业场所顾客扫码连接WiFi的网络接入服务,及商户会员营销信息展示”,不要写“广告分发”“流量变现”这类容易触发审核风险的表述。如果源码里包含用户之间的推广奖励功能,备案时不要提及分销、返利等字眼,微信对这类描述极其敏感。

5.2 并发结算的验证方法,必须用真实环境压一遍

结算接口上线前最值得做的测试是并发去重,模拟两个相同请求同时打到接口,观察数据库只生成一条记录。用bash直接发两个并发请求即可验证:

curl -X POST 'https://api.example.com/wifi/connect' \ -H 'token: test-user-token-001' \ -d 'deviceSn=A8F3K2LQ' & curl -X POST 'https://api.example.com/wifi/connect' \ -H 'token: test-user-token-001' \ -d 'deviceSn=A8F3K2LQ' & wait

然后去数据库执行SELECT * FROM connect_log WHERE user_id=1 AND device_id=1 ORDER BY id DESC;,如果出现两条记录,说明唯一索引没生效或者插入时connect_date不一致。测试通过后可以顺手验证一下另一个场景:同一用户连接两台不同设备,这应该生成两条记录,且都算有效连接。如果这条测试失败,说明connect_date唯一索引的粒度不对。

5.3 经常被忽略的三处返工点

导航栏适配是第一个返工点。共享WiFi小程序页面通常要做自定义导航栏,uniapp里用uni.getSystemInfoSync()获取状态栏高度,再通过uni.getMenuButtonBoundingClientRect()拿到胶囊按钮的位置,两者相加才是自定义导航栏的实际高度,不同机型的偏差很大,不要写死数值。第二个返工点是动态设置页面标题,扫码进入不同门店时页面标题应显示对应商家名,用uni.setNavigationBarTitle({ title: 商家名 })即可,但要注意这个接口必须在页面onShow之后调用才稳定。第三个返工点是首页加载速度,小程序冷启动时同时请求登录、设备信息、WiFi密码三个接口,高峰期经常出现登录还没完成其他接口就报401的情况,建议登录接口成功后统一回调再并行请求其余数据。

验证完并发和边界条件后,把压测脚本里15分钟以上的连续请求结果拉到connect_log里看一眼是否有脏数据,再做一次余额与流水对账,这套源码就可以交给运营去铺设备了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询