
简介千寻百念修复版喝酒小程序源码是一款面向聚会与喝酒场景的微信小程序项目适合需要快速搭建互动娱乐工具的个人开发者也可部署用于线下聚会运营。压缩包共447个文件体积仅1.38MB其中以218个PNG图片、48个JS逻辑文件、40个JSON配置、34个MP3音效、34个WXSS样式及32个WXML页面为主覆盖界面素材、交互逻辑、页面结构、音频资源等完整维度。目前已有53人学习下载适合作为轻量级小程序参考。源码经过修复优化内置转盘、弹幕、评论、灯光、游戏、设置、视频等模块目录按功能拆分便于按模块阅读与二次开发既可作为学习小程序工程结构、逻辑拆分和基础交互的实战样例也可作为完整产品快速部署。对于想研究小程序工程结构或快速上线聚会娱乐工具的开发者这份源码提供了实用的基础平台和可扩展思路。1. 喝酒小程序源码的“千寻百念修复版”先跑起来再改代码才不亏喝酒小程序的“喝酒”落到产品上通常是三种形态酒水商城、酒桌游戏划拳、骰子、行酒令、以及拼酒活动的营销页。“千寻百念修复版”在你手里的意义更多是“修复”两个字下载源码时最常遇到的登录失效、云环境没绑定、手机号取不到、支付回调不落地这些遗留问题都被集中处理过一遍。这篇文章不打算给你推广这套源码而是教你怎么把它当作可复现的起点——先用开发工具跑起来看懂喝酒场景需要的几个核心模块再决定往商城、记分还是社区方向改。适合接外包要快速交付的开发者也适合正在评估酒类小程序能不能做的产品人员以及刚接触微信小程序云开发的新手。2. 跑通源码的第一步开发工具、AppID 与项目目录三个关键点2.1 微信开发者工具里导入项目AppID 写错会卡在云开发初始化拿到“千寻百念修复版”的压缩包第一件事不是改界面而是创建一个能编译的项目。打开微信开发者工具选“导入项目”把根目录指到project.config.json所在的位置。大多数源码包会同时带有miniprogram和cloudfunctions两个文件夹前者才是小程序前端后者是云函数后端二者靠云开发环境串起来。导入时要分清“测试号”和真实 AppID。测试号能看页面但没有云开发能力用测试号打开这套源码wx.cloud.init会直接报“环境不存在”。你需要一个注册过的小程序账号在 mp.weixin.qq.com 后台拿到自己的 AppID填到开发者工具的 AppID 输入框。源码里如果保留了上一任开发者的 AppID也要在project.config.json里把它换成你自己的否则真机预览绑定的还是别人账号的云环境数据全乱。{ compileType: miniprogram, miniprogramRoot: miniprogram/, cloudfunctionRoot: cloudfunctions/, setting: { urlCheck: true, es6: true, enhance: true, postcss: true, minified: true }, appid: wx1234567890abcdef, projectname: hejiu-miniapp }这段配置里有三个地方直接影响能否跑通。miniprogramRoot告诉工具前端代码在哪个子目录cloudfunctionRoot管云函数目录这两个路径一旦和实际的文件夹结构对不上工具会一直提示找不到入口文件。setting.urlCheck是域名校验开关开发阶段可以关掉但正式发布前必须改回 true 并配好合法域名这个问题到第 5 章还会再踩一次。导入后如果工具右上角提示“当前环境未选择”说明云环境还没绑定。回到开发者工具顶部点“云开发”按钮开通环境记下环境 ID后面初始化代码要用。云开发环境 ID 是唯一的别人代码里的env字段不能直接沿用必须替换成你自己环境的 ID。2.2 翻一下源码包pages、cloudfunctions、utils 各自的职责跑通之前先把目录结构认全。这套源码的典型布局会包含pages、components、utils、cloudfunctions和styles几个目录各自承担不同的角色。路径 / 文件作用你通常要动它的时机project.config.json项目配置声明前端根目录、云函数根目录、AppID导入项目前必改app.json页面路由、窗口样式、底部标签栏加新页面时改app.js全局初始化包括wx.cloud.init改云环境 ID 时改pages/页面文件.wxml/.wxss/.js/.json四件套改业务逻辑时改cloudfunctions/云函数目录每个子目录一个函数改服务端逻辑后需要重新上传utils/公共工具比如随机算法、请求封装、金额格式化共用逻辑时改components/自定义组件比如酒局头像、订单卡片界面复用时改常见的翻车点pages里能看到页面文件但app.json的pages数组里没注册。新手改完界面保存工具报page pages/xxx/index is not found去 app.json 看一眼往往就能发现漏了路由。云函数目录不能和前端混着上传。开发工具里右键每个云函数目录选“上传并部署云端安装依赖”不是把整个cloudfunctions文件夹拖上去而是对单个函数文件夹操作。漏装依赖时云端日志会提示Cannot find module wx-server-sdk解决方法是重新上传并勾选“云端安装依赖”。2.3 让第一个页面亮起来的自检顺序编译报错与黑屏怎么查我一般按三个步骤验证源码能否算“跑通”第一步看编译有没有红字第二步看模拟器首页有没有渲染出导航栏第三步点一个需要云函数的功能看控制台有没有请求成功。只要这三步通过这个包就可以拿去做二次开发。最开始编译报错时优先级最高的是app.js里的云初始化。把环境 ID 填进去代码大致是这样// app.js App({ onLaunch() { if (!wx.cloud) { console.error(基础库版本过低请升级到 2.2.3 以上); return; } wx.cloud.init({ env: hejiu-release-2g8h9k, traceUser: true, }); }, });env填你刚开通的云开发环境 IDtraceUser打开后会往用户集合里记录访问信息方便看数据但在正式环境里会额外写一条记录介意就把这个参数去掉。这里有个容易忽略的细节环境 ID 是大小写敏感的Hejiu-...和hejiu-...在控制台上看起来一样代码里却可能匹配不到玄学报错多半出自这种复制粘贴产生的差异。自检时黑屏并不一定是代码坏了。先在工具栏把“不校验合法域名”打开再看调试器 Console 的报错。倒计时页面空白多半是云函数的 data 没在onLoad里及时 setData页面底部有 tabBar 却整体黑屏先怀疑app.json的 window 配置把导航栏背景色写成了透明。总之检查顺序是控制台报错 → 页面路由 → 云环境 → 数据请求每一步都能定位到明确的文件。3. 喝酒场景的三个核心功能划拳、记酒账与酒水下单3.1 骰子与划拳的随机逻辑客户端实现的公平性边界酒桌游戏模块里骰子和划拳在源码里大概率是纯前端实现。先说结论如果没有真金白银的赌注客户端Math.random()完全够用但如果玩法接入了积分、优惠券或者排行奖励随机结果就必须放到云函数里生成并把结果写入数据库否则用户清缓存重进就能反复刷结果。最常见的骰子玩法是“猜大小”或“两颗骰子猜点数”。抽取一个最小可运行工具函数// utils/game.js function rollDice(faces 6) { return Math.floor(Math.random() * faces) 1; } function playGuess(total, bet) { if (bet 2 || bet 12) return { ok: false, msg: 下注范围应为 2 到 12 }; const real rollDice(2) rollDice(2); return { ok: true, real, win: bet real, }; } module.exports { rollDice, playGuess };调用时只需要拿到win字段去驱动界面动画比如骰子转几圈再显示结果。注意Math.random()不适用于安全要求高的场景它只是伪随机数做娱乐可以做抽奖就要换云函数方案。还有一处细节很多源码会把“骰子点数”直接写在 WXML 里用>function judge(a, b) { if (a b) return draw; // 0 石头, 1 剪刀, 2 布 if ((a 1) % 3 b) return win; return lose; }这类函数在源码里经常散落在多个页面里每个页面复制一份。建议统一收进utils/game.js因为后面接排行榜或统计时所有胜局都要从同一套逻辑出不然会出现“A 页面算赢、B 页面算输”的怪问题。3.2 记酒账云开发数据库集合与用户数据隔离“记酒账”是喝酒类小程序里最容易被做成摆设的功能但其实它是留存最高的模块。用户酒局结束后记一杯三个月后回来查自己的饮酒记录这是很自然的回访理由。数据层面要做的就是按用户隔离读写。微信云开发的数据库在没有显式指定_openid时客户端添加记录会自动带一个_openid字段对应当前用户的 openid。读取时只要在查询条件里带上这个字段就不会串数据// pages/ledger/index.js const db wx.cloud.database(); Page({ onLoad() { this.loadRecords(); }, async loadRecords() { const res await db.collection(drink_records) .orderBy(createdAt, desc) .limit(20) .get(); this.setData({ records: res.data }); }, async addRecord(e) { const amount Number(e.detail.value.amount); if (!amount || amount 0) { wx.showToast({ title: 数量不对, icon: none }); return; } await db.collection(drink_records).add({ data: { amount, note: e.detail.value.note || , createdAt: db.serverDate(), }, }); this.loadRecords(); }, });这段代码在客户端直接操作数据库云开发会自动给记录打上_openid标记所以在loadRecords里不需要写where({ _openid: {openid} })这样的条件安全规则能保证用户只能看到自己的记录。注意db.serverDate()必须用云开发的时间服务不要传本机时间因为用户手机时间拔快慢两个小时排序就会错乱。如果需要在“酒局”维度上共享记录比如一场酒局三个人各记一杯那就要把drink_records改成带partyId字段再配合云函数统一读写。客户端直连数据库只适合纯个人笔记一旦涉及多人协作就把云函数作为唯一入口否则安全规则会变得很难写。3.3 酒水商城下单从商品到待支付的状态流转喝酒小程序里跑商城是常见需求。商品列表页友好问题常常出在下单环节。我先给一个云函数版的下单逻辑服务端强制从goods集合里读价格而不是信任前端传入的金额// cloudfunctions/createOrder/index.js const cloud require(wx-server-sdk); cloud.init(); const db cloud.database(); exports.main async (event) { const { OPENID } cloud.getWXContext(); const goodsRes await db.collection(goods).doc(event.goodsId).get(); const goods goodsRes.data; if (!goods || goods.status ! on) { return { code: 4001, msg: 商品已下架 }; } const count event.count || 1; const orderNo HJ Date.now() Math.random().toString(36).slice(-4); const orderRes await db.collection(orders).add({ data: { orderNo, openid: OPENID, goodsId: event.goodsId, count, amount: goods.price * count, status: pending, createdAt: db.serverDate(), }, }); return { code: 0, orderId: orderRes._id, orderNo }; };前端点击“去支付”先callFunction拿到orderId和orderNo再进入支付环节。这里最关键的纪律是金额永远以服务端计算为准。新手最容易直接在前端把price * count传进订单再传给云函数这等于把定价权交给了用户。哪怕只是做一个内部工具也要养成服务端算钱的习惯。订单状态可以拆成四档pending待支付、paid已支付、delivering配送中、done完成。源码里经常只做了前三档等支付回调更新成paid后就再没有后续动作。接单后让商家手动变更是可行的但没有状态机的话页面上的按钮会时显时隐体验很碎。4. 千寻百念修复版的改动重点登录、手机号获取与支付闭环4.1 微信小程序登录获取手机号open-type 加云函数在源码里的写法老版本源码里取手机号最常见的是两种旧写法一是getPhoneNumber里直接用e.detail.encryptedData和iv配合session_key解密二是把手机号明文写死在代码里。这两种现在都不行了。微信 2021 年后把手机号快速验证组件改成了“动态令牌”模式前端拿到的不是手机号而是一个临时code必须交给云函数换取手机号。前端按钮部分button open-typegetPhoneNumber bindgetphonenumberonGetPhone 微信授权手机号 /button前端逻辑部分// pages/login/index.js async onGetPhone(e) { if (e.detail.errMsg ! getPhoneNumber:ok) { wx.showToast({ title: 未授权手机号, icon: none }); return; } const res await wx.cloud.callFunction({ name: getPhone, data: { phoneCode: e.detail.code }, }); this.setData({ phone: res.result.phoneNumber }); }云函数部分// cloudfunctions/getPhone/index.js const cloud require(wx-server-sdk); cloud.init(); exports.main async (event) { const { OPENID } cloud.getWXContext(); const res await cloud.openapi.phonenumber.getPhoneNumber({ code: event.phoneCode, }); return { openid: OPENID, phoneNumber: res.phoneInfo.purePhoneNumber, }; };这个改动的核心在于手机号不再经过客户端而是由云开发直接调微信开放接口拿到后可以直接存库也可以做用户匹配。openapi.phonenumber.getPhoneNumber调用一次会消耗一次手机号验证额度不同主体每天的额度不一样真机测试几次就会把额度耗尽所以调试时别反复点尽量在后台看调用记录。开发工具的模拟器上点击授权返回的是模拟手机号这跟在真机上走真实逻辑是两套路径下文避坑章节会单独说。4.2 云开发里的微信支付下单云函数与回调函数一对一的设置云开发里的微信支付官方推荐用cloud.cloudPay.unifiedOrder发起。这个接口的配置项很集中但很多人第一次看到functionName字段会发愣因为普通微信支付的回调地址是 URL而云开发支付回调指向的是另一个云函数。// cloudfunctions/payOrder/index.js const cloud require(wx-server-sdk); cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }); exports.main async (event) { const res await cloud.cloudPay.unifiedOrder({ body: 酒类订单, outTradeNo: event.orderNo, spbillCreateIp: 127.0.0.1, subMchId: 1230000109, totalFee: event.totalFee, envId: cloud.DYNAMIC_CURRENT_ENV, functionName: payCallback, }); return res.payment; };subMchId是微信支付商户号支付回调函数payCallback必须已经上传部署到同一个云环境并且云函数目录名要和functionName完全一致。这个参数不一致时前端wx.requestPayment会报支付验证签名失败而且不会直接提示是回调函数缺失排查起来很绕。回调云函数要做的只有两件事校验returnCode为SUCCESS然后把订单状态从pending更新为paid。更新时用orderNo作条件不要用_id因为回调函数拿到的参数顺序和你前端传的不完全一致// cloudfunctions/payCallback/index.js const cloud require(wx-server-sdk); cloud.init(); const db cloud.database(); exports.main async (event) { const { outTradeNo, resultCode, returnCode } event; if (returnCode ! SUCCESS || resultCode ! SUCCESS) { return { errcode: 1, errmsg: 支付未成功 }; } await db.collection(orders).where({ orderNo: outTradeNo }) .update({ data: { status: paid, paidAt: db.serverDate() } }); return { errcode: 0 }; };这里要当心云函数默认超时时间通常只有 3 秒或 5 秒而支付初始化涉及网络交互和数据库写入如果日志里出现FunctionTimeLimit就要把该云函数config.json的timeout调到 20 秒左右这个细节很多修复版已经改了但你复制到自己项目后要再确认一遍。4.3 数据权限把默认开放读写的安全规则改成按用户出具云开发数据库建好之后默认权限是“仅创建者可读写”但“千寻百念修复版”这类二手源码经常会在修复过程中把权限开成“所有人可读”目的是让演示数据在测试环境下能直接看到。这个状态上线前必须改掉。在云开发控制台里选中orders、drink_records等集合切到“权限设置 → 自定义安全规则”先给最敏感的两个集合设置成严格模式{ read: doc._openid auth.openid, create: auth.openid ! , update: doc._openid auth.openid, delete: doc._openid auth.openid }如果是“酒局记录”这类需要多人查看的集合你可以给记录加一个memberOpenids数组字段用数组包含来判断而不是直接把集合改成所有人可读{ read: doc.memberOpenids.contains(auth.openid), create: auth.openid ! , update: doc.ownerOpenid auth.openid, delete: doc.ownerOpenid auth.openid }自定义安全规则是黑匣子写完后一定要在“模拟数据”里用不同 openid 测一遍。我自己经常遇到的情况是规则里用了doc.memberOpenids但某条测试记录根本没有memberOpenids字段读取时就返回空数组导致权限拒绝。先保证所有记录都带字段再上规则。5. 这套喝酒小程序源码的避坑手册真实调试与提审环境差异5.1 真机预览白屏但开发工具正常云环境没初始化到位现象开发者工具里页面渲染正常扫码打开真机预览后白屏控制台提示Cloud API isnt enabled或env not found。原因开发工具默认使用了本地调试环境AppID 还是源码里上一任开发者的云环境 ID 实际并不属于你。真机上跑的是真实请求后端连不上就直接白屏。解决先在project.config.json换成自己的 AppID再在 app.js 里把env换成自己开通的环境。做完这两步清缓存重新编译。还有一个办法是打开真机调试模式看 Network 面板请求失败时后端的错误码会直接暴露问题。5.2 云函数超时把订单卡在“待支付”现象用户点了支付转圈很久后提示“支付调用失败”订单状态停留在待支付。原因下单云函数里既要读商品、算金额又要写订单最后还要调微信支付下单接口默认 5 秒超时不够用尤其是网络波动时更容易触顶。解决在云函数目录下的config.json里加超时配置然后重新上传部署。{ permissions: { openapi: [] }, timeout: 20 }这里有个细节云函数目录下的config.json跟项目根目录的project.config.json不是同一个文件别改错地方。部署后到云开发控制台看函数配置里是否显示 20 秒如果还是 5 秒说明没生效重新右键上传一次。5.3 手机号验证组件在开发工具与真机上的“两个世界”现象开发工具里点击授权按钮返回13800000000或一串模拟号码真机上点击回调getPhoneNumber:fail或者后端报“code 无效”。原因开发工具的模拟器不会发起真实的手机号验证流程它走的是本地模拟数据而真机调用的是动态令牌。基础库版本低于 2.21.2 时接口参数都不同报错还不明显。解决把微信开发者工具的基础库切到最新稳定版然后在真机上测试后端云函数里做好errCode日志输出把errcode和errmsg打出来这样才能区分是额度限制、code 失效还是接口权限问题。手机号验证的服务端错误经常是“频繁调用”导致的调试时控制频率。5.4 换壳改皮翻车点AppID、域名和云函数上传对不上现象把源码里的品牌名改成自己的图片也换掉了但一打开某个功能就报“找不到云函数”。原因源码目录里可能有多个云函数改皮过程中动了目录名或者换了 AppID 之后开发工具重新拉取环境列表云函数没有重新上传。解决每改完一个云函数立刻右键上传确认上传时控制台显示的环境 ID 和 app.js 里一致。常见做法是在项目里建一个config/env.js把环境 ID、商户号、手机号云函数名统一放进去任何人都能一眼看出配没配错。5.5 提审被拒的现实原因酒类资质与诱导风险现象提交审核被拒理由涉及“酒类商品销售资质”或“涉嫌诱导不当饮酒”。原因微信对酒类内容有专门审核口径。商城涉及酒类交易需要提供《食品经营许可证》等资质如果页面文案出现“千杯不醉”“拼酒排行”“今晚不醉不归”会直接被判定为不良诱导。解决正文里把“拼酒”改成“适量饮酒提醒”并增加“未满 18 岁禁止使用”的提示使用“酒后不开车”等正向引导文案如果只是工具型应用不卖酒直接删除商品交易模块能显著降低过审难度。涉及真实酒水销售的场景资质问题不可绕过只能在主体资质和类目选择上提前准备。6. 上线前最后改一处把配置集中到白名单文件再提审前几章把功能跑通后建议动手做一次小重构把散落在各页面的环境 ID、商户号、回调函数名全部抽到一个公共配置文件。我一般会新建config/global.js内容大致是// config/global.js module.exports { cloudEnv: hejiu-prod-xxxx, payMchId: 1230000109, payCallbackName: payCallback, getPhoneFunctionName: getPhone, orderDefaultLimit: 20, };然后所有页面和云函数通过require引用这份配置。这样做的收益排第一的是提审前自查只需要看一个文件不用满项目搜subMchId。排第二的是后续换主体或换环境时改动收敛到一个文件不会出现改了三处漏一处的翻车。上线前花十分钟对照做一遍第一检查app.json有没有这个试试页面里的路由残留很多二手源码会把原来的支付单测试页留着提审时被当成完整功能第二把手机号授权和隐私协议弹窗流程走一遍微信现在强制要求在小程序管理后台填写用户隐私保护指引前端也必须在首次进入时弹出授权说明第三用体验版做一次全链路测试从登录、获取手机号到支付回调不要只看开发工具。我最早做酒类小程序时吃过一次亏源码跑得好好的真机上却永远白屏折腾了大半天才发现是上一任作者在app.js里写死了他自己的云环境 ID我换 AppID 后环境 ID 没跟着换。从那以后每次接手一套源码我第一件事就是全局搜索env、subMchId和appid三个关键词把显式写死的地方全清理掉。这套“先跑通、再集中配置、再提审”的顺序救过我很多次希望也帮到你。本文还有配套的精品资源点击获取