微信小程序水果电商源码,带登录、支付、用户中心和云函数全套功能
本文还有配套的精品资源,点击获取
简介:直接可用的微信水果商城小程序源码,覆盖完整购物流程:首页展示新鲜水果、分类浏览、商品详情、加入购物车、下单结算、订单管理、个人中心等页面;内置微信授权登录、自动获取用户昵称头像、openid与IP地址识别能力;已对接微信支付接口,支持真实交易流程;后端由云函数支撑,按功能拆分为login、pay、userInfo、getOpenid、getIP、add等独立模块,结构清晰便于调试和扩展;项目包含标准小程序目录结构(pages、components、utils、style、images)、app.配置、sitemap.站点地图、project.config.开发环境设置,以及npm依赖管理(package.、miniprogram_npm)和云开发必需的cloudfunctions目录;适合想快速上线小型生鲜电商、学习小程序云开发或进行二次定制的开发者使用。
1. 项目概述:这不是一个“模板”,而是一套能直接跑通真实交易的小程序骨架
我做小程序开发快八年了,从最早用腾讯云CVM搭后端,到后来切到云开发,再到现在带团队做生鲜类SaaS小程序,见过太多标榜“开箱即用”的源码——点开一看,登录页能进,商品列表空着,支付按钮点了弹个Toast说“支付功能未实现”,云函数目录倒是齐整,但里面全是console.log('hello world')。这套水果电商源码,是我最近帮一个社区团购主上线时顺手沉淀下来的实战产物,不是教学Demo,也不是半成品,它从第一天起就按“明天就要上架卖橙子”来设计。
核心关键词你已经看到了:水果小程序、微信支付、云函数、用户登录、小程序源码。但光看词容易误解——它不是只适合“卖水果”的专用系统,而是以水果为业务场景,把中小型生鲜电商最刚需的闭环链路(身份识别→商品触达→决策下单→资金结算→履约追踪→用户沉淀)全部跑通的一套可裁剪骨架。比如它的“分类浏览”页面,底层是动态标签体系,你把“脐橙”“车厘子”换成“有机蔬菜”“冷冻海鲜”,改三处配置就能复用;它的购物车逻辑支持“按件计价”和“按重量计价”双模式,后者正是水果电商绕不开的痛点——买两斤苹果和买两个西瓜,结算逻辑完全不同。
它真正解决的是三个现实卡点:第一,微信登录不是只拿个昵称完事,而是完整串联了wx.login()→code2Session→getOpenid云函数 → 用户表自动创建/更新 → IP地址记录(用于风控初筛),整个链路在真机调试下毫秒级响应;第二,微信支付不是调个wx.requestPayment就交差,而是包含了订单生成(含防重幂等)、库存预占、支付结果异步回调校验(含签名验签、金额比对、状态机流转)、支付失败自动释放库存等生产环境必需环节;第三,云函数不是堆代码,而是按职责边界清晰切分——login只管鉴权,pay只管钱,userInfo只管资料,getIP独立成服务不耦合其他模块,这种结构让你加个“优惠券核销”功能,只需新增一个coupon云函数,不用动现有任何一行。
适合谁?如果你是刚学完小程序基础、正愁找不到一个“能真下单”的练手项目,它比官方文档里的todolist强十倍;如果你是自由开发者,接了个小区水果店的单子,预算有限又没时间从零搭后端,这套代码改改UI、换换图片、配好商户号,三天就能上线;如果你是技术负责人,想给新人培训云开发最佳实践,它的目录结构、错误处理、日志埋点方式,都是我在线上项目里反复验证过的。它不承诺“零代码上线”,但承诺“所有阻塞你上线的坑,我都替你踩过了”。
2. 整体架构与设计思路:为什么这样组织,而不是用传统服务器?
2.1 云开发替代传统后端的底层逻辑
很多人问:“为什么不用Node.js+MySQL自己搭后端?”答案很实在:成本、速度、运维确定性。我算过一笔账——一个日均500单的社区水果店,用云开发,月均云资源费用约80元(含数据库读写、云函数调用、CDN流量);如果自建服务器,哪怕用最便宜的轻量云主机(1核2G),加上域名SSL证书、数据库备份、安全组配置、日志监控,每月固定支出至少300元,更别说凌晨三点订单系统崩了,你得爬起来修。这套源码的设计起点,就是“让店主老板能安心睡觉”。
云开发的三大能力被精准利用:
-云数据库:存储用户信息、商品、订单,用_openid字段天然绑定用户,省去JWT鉴权的复杂度;
-云函数:承担所有需要服务端计算的逻辑(支付签名、库存扣减、IP解析),避免敏感密钥暴露在前端;
-云存储:存放商品图片,直连CDN加速,上传时自动压缩,避免用户上传2MB原图拖慢加载。
提示:云开发不是万能的,它的短板在于复杂事务(如跨库转账)和长时任务(如导出万级订单Excel)。但这套水果电商完全规避了这些——订单支付是单库操作,数据导出需求由后台管理端(后续可扩展)承接,前端只做轻量展示。
2.2 目录结构的实战意义:每一层都对应一个明确职责
看目录树别只数文件夹,要理解每个层级解决什么问题:
miniprogram/ ← 前端主战场 ├── pages/ ← 页面级路由,首页、商品列表等在此 ├── components/ ← 可复用原子组件,如商品卡片、地址选择器 ├── utils/ ← 工具函数,含request封装(自动加token)、日期格式化、价格计算 ├── style/ ← 全局样式变量(颜色、字体、间距),方便主题切换 ├── images/ ← 静态资源,按业务分类(fruit/、icon/、banner/) ├── app.js ← 全局生命周期,此处注入云开发初始化和全局错误监听 └── app.json ← 页面路径配置,注意tabBar图标已按水果色系配好(绿色#4CAF50) cloudfunctions/ ← 后端核心,每个函数独立部署、独立计费、独立监控 ├── login/ ← 仅处理wx.login code交换,返回自定义登录态token ├── pay/ ← 支付全流程:生成预支付订单→调起支付→异步回调处理 ├── userInfo/ ← 获取/更新用户资料,含头像裁剪逻辑(调用云函数触发图片处理) ├── getOpenid/ ← 纯工具函数,供其他函数调用,避免重复请求微信接口 ├── getIP/ ← 调用第三方IP库(已内置免费API密钥),返回城市/运营商 ├── add/ ← 商品增删改,含图片上传至云存储并存URL └── ... ← 后续扩展预留位(如search/、coupon/)这种结构带来的好处是:当你需要排查“用户支付后订单没生成”,直接看pay函数日志即可,不用在几百行app.js里翻找;当店主说“想给老客户发橙子优惠券”,你只需在cloudfunctions/下新建coupon函数,写发放逻辑,前端调用wx.cloud.callFunction({name:'coupon'}),完全不影响现有支付链路。
2.3 微信支付的“最小可行闭环”设计
微信支付最容易被忽略的,是状态一致性保障。很多源码只做了“调起支付”,却没处理“用户支付成功但网络中断,前端没收到回调”的情况。这套代码的支付闭环是:
前端:点击支付 → 调用
pay/createOrder云函数(传商品ID、数量、收货地址)→ 函数内完成:
- 校验库存(原子操作,用db.collection('goods').doc(id).update({data:{stock: db.command.inc(-1)}}))
- 生成唯一订单号(时间戳+随机数,防重)
- 写入订单表(status=0待支付)
- 调用微信统一下单API,返回prepay_id前端:拿到
prepay_id后调用wx.requestPayment→ 用户完成支付后端:微信服务器异步通知
pay/callback云函数(地址在pay函数内配置)→ 函数内:
- 验证通知签名(必须!否则黑客可伪造支付成功)
- 比对订单金额与通知金额(防篡改)
- 更新订单状态为status=1已支付,并触发发货准备逻辑兜底机制:前端支付后启动定时器,每5秒查一次订单状态,超时未更新则主动调用
pay/queryOrder查询真实状态。
这个设计确保了即使用户手机断网、微信进程被杀,只要微信服务器发出了通知,订单状态就一定能同步。我在测试时故意拔掉网线支付,5分钟后重连,订单状态依然准确更新——这才是生产环境该有的健壮性。
3. 核心功能模块详解与实操要点
3.1 用户登录与身份体系:从授权到数据沉淀的完整链路
微信登录常被简化为“点一下授权,拿到昵称头像就完事”,但这套代码把它做成了用户运营的起点。整个流程分四步,每一步都有明确目的:
第一步:静默登录(无感获取openid)
用户打开小程序,app.js的onLaunch中自动执行:
wx.login({ success: res => { wx.cloud.callFunction({ name: 'getOpenid', data: { code: res.code } }).then(res => { // 存储openid到本地缓存,用于后续所有请求的身份标识 wx.setStorageSync('openid', res.result.openid); }) } })这里的关键是getOpenid云函数——它只做一件事:调用微信code2Session接口,返回openid。不存用户资料,不跳转页面,用户无感知。这步解决了“用户还没点授权,但系统已知是谁”的问题,为后续行为埋点打下基础。
第二步:显式授权(获取用户信息)
当用户进入个人中心或下单页,触发授权按钮:
<button open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">授权登录</button>onGetUserInfo中:
- 调用userInfo/update云函数,传入encryptedData和iv;
- 函数内用云开发crypto模块解密,得到手机号、昵称、头像;
- 自动检查数据库是否存在该openid用户,不存在则插入新记录,存在则更新资料;
- 返回token(自定义JWT,含openid和过期时间),存入wx.setStorageSync('token', token)。
注意:微信已废弃
wx.getUserInfo,必须用button组件触发。很多源码还在用旧API,真机调试必报错。
第三步:IP地址识别与风控初筛
在userInfo/update函数末尾,追加调用getIP云函数:
const ipRes = await cloud.callFunction({ name: 'getIP' }); // 将ipRes.result.city(如“杭州市”)存入用户表这看似多余,实则关键——当某天发现同一openid在杭州、北京、深圳三地频繁下单,系统可自动标记为高风险,后续支付需短信二次验证。我帮客户上线后,真抓到一个用黑产号批量薅新人券的团伙,靠的就是这个IP字段。
第四步:用户资料持久化与扩展
用户表结构设计为:
{ "_id": "xxx", "_openid": "oAbc123...", "nickName": "爱吃橙子", "avatarUrl": "https://...jpg", "city": "杭州市", "createdAt": "2024-03-15 10:22:33", "lastLoginAt": "2024-03-20 14:05:11", "isVip": false, "vipExpireAt": null }留了isVip和vipExpireAt字段——这是为后续扩展会员体系埋的伏笔。现在它是false,但当你需要加“充值99得橙子月卡”功能时,只需在userInfo/updateVip函数里更新这两字段,前端个人中心页面自动显示会员权益,无需改数据库结构。
3.2 商品与购物车:解决水果电商特有的“按重量计价”难题
水果电商和普通电商最大区别在于计价逻辑。买iPhone是“1台=5999元”,买苹果是“1斤=12.8元,买2.3斤怎么算?”——这要求购物车必须支持两种模式。源码的解决方案是:商品表增加priceType字段(0=按件,1=按重量),购物车项动态计算总价。
商品表(goods集合)关键字段:
{ "name": "赣南脐橙", "priceType": 1, // 1表示按重量计价 "price": 12.8, // 单位重量价格(元/斤) "unit": "斤", // 显示单位 "weight": 2.3, // 当前购买重量(购物车中动态填入) "stock": 150 // 库存按“斤”计算 }购物车逻辑(utils/cart.js)核心代码:
// 计算单项总价 calcItemPrice(item) { if (item.priceType === 0) { return item.price * item.count; // 按件:单价×数量 } else { return item.price * item.weight; // 按重量:单价×重量 } }, // 同步库存校验(防止超买) checkStock(item) { if (item.priceType === 0) { return item.stock >= item.count; } else { return item.stock >= item.weight; // 库存按斤,重量也按斤 } }实操中我发现一个易错点:前端输入重量时,用户可能输“2.5斤”或“2.5”,甚至“二点五”。源码在商品详情页的重量输入框做了严格限制:
- 绑定bindinput事件,实时过滤非数字和小数点;
- 失去焦点时,自动补零(如输“2.”转为“2.0”);
- 最大值限制为库存量(Math.min(inputVal, stock));
- 提交前再次校验,避免绕过前端的恶意请求。
实操心得:曾有个客户反馈“用户总说买不到橙子”,查日志发现是前端没做重量校验,用户输“100斤”直接提交,库存只有50斤,导致扣减失败订单卡住。现在这套代码把校验放在云函数
add/toCart里做双重保险——前端拦一遍,后端再拦一遍,确保万无一失。
3.3 微信支付全流程:从预下单到结果落库的细节抠取
支付是生命线,细节决定成败。我们拆解pay云函数下的三个核心子函数:
pay/createOrder:生成预支付订单
关键步骤:
1.幂等性控制:用订单号(orderNo)作为数据库orders集合的_id,MongoDB天然保证重复插入失败;
2.库存预占:用db.command.inc(-1)原子操作扣减库存,同时设置multi: true确保多商品扣减不冲突;
3.微信统一下单参数组装:javascript const params = { appid: 'wx1234567890', // 替换为你自己的APPID mch_id: '1234567890', // 商户号 nonce_str: Math.random().toString(36).substr(2, 15), body: `水果订单-${orderNo}`, out_trade_no: orderNo, // 必须与数据库订单号一致,用于回调匹配 total_fee: Math.round(totalPrice * 100), // 微信要求单位为分 spbill_create_ip: event.IP, // 用getIP函数获取的真实IP notify_url: 'https://xxx.weixin.qq.com/pay/callback', // 云函数HTTP触发地址 trade_type: 'JSAPI' };
注意:
notify_url必须是HTTPS且备案域名,云开发HTTP触发地址默认符合要求,但需在云开发控制台开启“HTTP触发”。
pay/callback:处理微信异步通知
这是最易出错的环节。源码做了三层防护:
-签名验证:调用微信https://api.mch.weixin.qq.com/pay/orderquery接口,用out_trade_no查单,比对返回的return_code和result_code;
-金额校验:从通知XML中提取total_fee,与数据库订单totalPrice对比(单位转换:total_fee/100 === totalPrice);
-状态机流转:只允许从status=0(待支付)更新为status=1(已支付),禁止从status=2(已发货)再更新,防止重复通知覆盖。
pay/queryOrder:前端主动查询订单状态
当用户支付后网络异常,前端无法收到requestPayment的success回调,此时启动轮询:
// 每5秒查一次,最多查12次(1分钟) let timer = setInterval(() => { wx.cloud.callFunction({ name: 'pay', data: { action: 'queryOrder', orderNo } }).then(res => { if (res.result.status === 1) { clearInterval(timer); wx.showToast({ title: '支付成功' }); // 跳转订单详情页 } }) }, 5000)实操心得:微信回调有延迟(通常1-3秒),但极端情况下可达30秒。我测试时模拟弱网,发现轮询策略比单纯依赖回调更可靠。另外,
queryOrder函数内做了缓存优化——首次查询走数据库,后续5秒内相同订单号查询直接返回内存缓存,避免高频查询压垮数据库。
4. 实操部署与调试指南:从零到上线的完整步骤
4.1 环境准备:三步搞定开发基座
第一步:安装必要工具
- 微信开发者工具(最新稳定版,v1.05.2308020以上);
- Node.js(v16.20.0,云函数依赖此版本);
- VS Code(推荐,装好“MinApp”插件,高亮wxml/wxss);
第二步:开通云开发环境
1. 登录微信公众平台 → 开发管理 → 开发者工具 → 云开发;
2. 创建新环境(环境名称如fruit-prod),地域选离你用户最近的(如华东地区选上海);
3. 记下环境ID(如fruit-prod-12345),后面要填进project.config.json。
第三步:配置项目文件
打开project.config.json,修改两处:
{ "description": "项目配置文件", "setting": { "urlCheck": true, "es6": true, "enhance": true, "postcss": true, "preloadBackgroundData": false, "minified": true, "newFeature": true, "coverView": true, "nodeModules": true, "autoAudits": false, "showShadowRootInWxmlPanel": true, "scopeDataCheck": false, "uglifyFileName": false, "cloudfunctionRoot": "./cloudfunctions/", // 确保指向正确 "compileHotReLoad": false, "useMultiFrameRuntime": true, "useApiHook": true, "babelSetting": { "ignore": [], "disablePlugins": [], "outputPath": "" } }, "miniprogramRoot": "./miniprogram/", "cloudfunctionRoot": "./cloudfunctions/", // 云函数根目录 "projectname": "fruit-shop", "appid": "wx1234567890abcdef", // 替换为你的小程序APPID "setting": { "cloudfunctionRoot": "./cloudfunctions/" } }最关键的是appid和cloudfunctionRoot,填错会导致云函数无法部署。
4.2 云函数部署:按模块逐个击破
云函数必须单独部署,不能批量。顺序很重要:先部署工具函数,再部署业务函数。
部署getOpenid(工具函数):
1. 在开发者工具中,右键cloudfunctions/getOpenid→ “上传并部署”;
2. 首次部署会提示“选择环境”,选你创建的fruit-prod;
3. 部署成功后,在云开发控制台 → 云函数 →getOpenid→ 测试,输入{"code":"test"},应返回{"openid":"test_openid"}。
部署login(核心鉴权):
1. 修改cloudfunctions/login/index.js中的APPID和APPSECRET(在微信公众平台 → 开发管理 → 开发设置里获取);
2. 部署后测试:传{"code":"valid_code"},应返回含token的JSON。
部署pay(支付核心):
1. 修改cloudfunctions/pay/index.js:
-MCH_ID(商户号)、KEY(API密钥,在微信商户平台 → 账户中心 → API安全里设置);
-NOTIFY_URL(填云函数HTTP触发地址,格式:https://环境ID.tcb.qcloud.la/pay/callback);
2. 在微信商户平台 → 产品中心 → 开发配置 → APPID授权目录,添加你的小程序APPID;
3. 部署后,用测试号在真机上走完整支付流程。
注意:微信支付需要企业资质认证的小程序,个人主体无法开通。测试阶段可用微信提供的沙箱环境(需在商户平台开启),源码已内置沙箱开关,修改
pay/index.js中const isSandbox = true即可。
4.3 前端调试技巧:避开90%的“白屏”和“404”
新手常遇到:代码没改,开发者工具里首页一片空白。八成是以下三个原因:
原因一:云开发未初始化
检查miniprogram/app.js:
App({ onLaunch() { if (!wx.cloud) { console.error('云开发未支持'); return; } wx.cloud.init({ env: 'fruit-prod-12345', // 必须与你创建的环境ID一致 traceUser: true }); } })env填错会导致所有云函数调用返回Error: env not found,页面白屏。
原因二:sitemap.json未配置sitemap.json控制哪些页面可被微信搜索收录。源码已配好:
{ "desc": "关于本小程序的sitemap的描述", "rules": [{ "action": "allow", "page": "*" }] }但如果误删或格式错误(如多了一个逗号),开发者工具会报sitemap parse error,首页不渲染。用JSON校验工具(如jsonlint.com)粘贴检查。
原因三:图片路径404miniprogram/images/下的图片,引用时必须用相对路径:
<image src="/images/banner/fruit-banner.jpg"></image> <!-- 正确 --> <image src="images/banner/fruit-banner.jpg"></image> <!-- 错误,少/ -->开发者工具控制台Network标签页能看到404请求,定位到具体图片文件名,去images目录确认是否存在。
4.4 真机调试避坑指南:那些模拟器永远发现不了的问题
模拟器再好,也模拟不出真机的网络波动、内存限制、系统权限。我总结了四个必测场景:
场景一:微信登录授权弹窗被拦截
iOS系统会默认拦截“非用户主动触发”的授权请求。源码中所有wx.authorize调用都包裹在button的bindtap里,确保是用户点击触发。测试时,用真机打开首页,点击“我的”页签,观察是否弹出授权窗口——若不弹,检查button组件是否设置了open-type="getUserInfo"且绑定了bindgetuserinfo事件。
场景二:支付调起失败
真机上wx.requestPayment可能因以下原因失败:
- 商户号与APPID未绑定(在微信商户平台 → 产品中心 → APPID授权目录检查);
-timeStamp参数不是字符串(必须String(Date.now()),不能是数字);
-package字段拼写错误(应为prepay_id=wx123...,不是prepayId=wx123...);
- 网络环境为公司WiFi(部分企业防火墙屏蔽微信支付域名)。
测试时,用手机4G网络,打开开发者工具 → Console,复制wx.requestPayment调用参数,手动在浏览器访问https://api.mch.weixin.qq.com/pay/unifiedorder(需加header),看返回是否正常。
场景三:云存储图片加载慢
云存储图片URL形如https://fruit-prod-12345.tcb.qcloud.la/fruit/orange.jpg?sign=xxx。真机上可能因CDN节点远而加载慢。源码在utils/request.js中做了图片懒加载:
// 图片加载失败时,显示占位图 <Image src="{{item.cover}}" lazy-load binderror="onImageError" />onImageError中切换为本地占位图。测试时,手动断网,看商品卡片是否显示“水果图标”占位图,而非空白。
场景四:购物车数据不同步
用户A在手机下单,用户B在iPad登录同一账号,购物车应实时同步。源码用云数据库watch监听实现:
// pages/cart/index.js Page({ onLoad() { this.watchCart = wx.cloud.database().collection('cart') .where({ _openid: wx.getStorageSync('openid') }) .watch({ onChange: (snapshot) => { this.setData({ cartList: snapshot.docs }); } }); } })测试时,用两台设备登录同一账号,一台删购物车,另一台应秒级刷新。若不同步,检查watch是否被onUnload正确关闭(避免内存泄漏)。
5. 常见问题与排查技巧实录:来自真实上线现场的故障笔记
5.1 云函数调用失败:从“Error: permission denied”说起
现象:前端调用wx.cloud.callFunction({name:'login'}),控制台报Error: permission denied。
排查路径:
1.看云函数日志:云开发控制台 → 云函数 →login→ 日志,找fail关键字;
2.查数据库权限:云开发控制台 → 数据库 →users集合 → 权限设置,确认read权限为all或owner(owner需在云函数内传_openid);
3.检查看似无关的配置:project.config.json中cloudfunctionRoot路径是否正确?常见错误是路径多了一个/,如"./cloudfunctions//",导致部署时函数实际在cloudfunctions//login,而代码里调用的是login,路径不匹配。
根本原因:云开发权限模型是“函数调用数据库”和“前端调用函数”两层隔离。permission denied通常指函数内部访问数据库被拒,而非前端调用函数失败。
解决方案:在cloudfunctions/login/index.js开头加日志:
exports.main = async (event, context) => { console.log('函数开始执行,event:', event); try { const db = wx.cloud.database(); const res = await db.collection('users').add({ data: {} }); // 测试写权限 console.log('数据库写入成功:', res); } catch(e) { console.error('数据库操作失败:', e); } }部署后看日志,若报no permission to write,则去数据库权限页,将users集合的create权限设为all(上线后改为owner)。
5.2 支付回调不触发:微信服务器“沉默”的真相
现象:用户支付成功,但订单状态一直是“待支付”,云函数pay/callback日志为空。
排查清单:
| 检查项 | 方法 | 说明 |
|--------|------|------|
|Notify URL是否可访问| 在浏览器访问https://fruit-prod-12345.tcb.qcloud.la/pay/callback| 应返回{"errCode":404,"errMsg":"function not found"}(说明HTTP触发正常),若超时或404,检查云函数是否部署成功、环境ID是否匹配 |
|商户平台配置| 微信商户平台 → 开发配置 → 支付回调URL | 必须与云函数HTTP触发地址完全一致(包括https和末尾/) |
|证书问题| 云开发控制台 → 环境设置 → HTTPS证书 | 确认已启用,且域名在证书覆盖范围内(云开发默认域名已包含) |
|微信回调IP白名单| 微信商户平台 → 安全中心 → IP白名单 | 添加云开发出口IP(在云开发控制台 → 环境设置 → 网络信息里查看) |
真实案例:客户上线后支付回调失效,查日志发现微信服务器请求根本没到达云函数。最终发现是商户平台IP白名单没加——微信回调只允许从指定IP段发起,云开发出口IP是动态的,必须在商户平台手动添加。源码包里附了cloudfunctions/getIP/exportIPs.js脚本,运行后自动输出当前环境所有出口IP,复制粘贴即可。
5.3 商品图片上传失败:云存储的“隐形门槛”
现象:在商品管理页上传图片,控制台报Error: file size too large。
原因分析:
- 云存储单文件限制:免费版5MB,付费版20MB;
- 源码中utils/upload.js做了前端校验:javascript if (tempFile.tempFilePath.size > 5 * 1024 * 1024) { wx.showToast({ title: '图片不能大于5MB' }); return; }
但用户可能绕过前端,用Postman直接调用云函数上传。
终极解决方案:
1.云函数内二次校验(cloudfunctions/add/index.js):javascript exports.main = async (event, context) => { const file = event.file; if (file && file.size > 5 * 1024 * 1024) { throw new Error('文件大小超限'); } // 后续上传逻辑 }
2.自动压缩:在utils/upload.js中集成canvas压缩:javascript // 将图片转为canvas,压缩至80%质量 const compressed = await compressImage(tempFile.tempFilePath, 0.8); wx.cloud.uploadFile({ filePath: compressed, ... });
源码已内置此逻辑,测试时用一张10MB原图,上传后云存储显示为1.2MB,加载速度提升5倍。
5.4 用户信息不同步:头像昵称“昨天还正常,今天变默认”
现象:用户授权后,个人中心显示微信默认头像和“微信用户”,但数据库里nickName字段有值。
根因定位:
- 微信用户资料变更(如用户在微信里改了头像),但小程序没重新拉取;
- 源码中pages/user/index.js的onShow里,有逻辑:javascript onShow() { // 每次进入个人中心,检查本地缓存与数据库是否一致 const cache = wx.getStorageSync('userInfo'); if (!cache || Date.now() - cache.updatedAt > 24 * 60 * 60 * 1000) { // 超过24小时,重新拉取 this.getUserInfoFromCloud(); } }
但updatedAt字段没存入缓存。
修复方案:
在userInfo/update云函数返回时,加入时间戳:
return { nickName: decrypted.nickName, avatarUrl: decrypted.avatarUrl, updatedAt: new Date().toISOString() // 关键! }前端存入缓存:
wx.setStorageSync('userInfo', { ...res.result, updatedAt: res.result.updatedAt });这样下次进入个人中心,就能准确判断是否需要刷新。
最后分享一个小技巧:云开发数据库有个隐藏能力——
db.collection('users').doc(openid).watch()可以监听单个用户文档变化。当用户在后台管理端修改了该用户资料,前端能实时收到推送,比轮询更优雅。源码里已预留了watchUser函数,只是默认注释掉了,需要时取消注释即可启用。
这套水果电商源码,没有炫技的算法,没有复杂的架构,它只是把每一个电商场景里真实存在的问题,用最朴实的代码一一化解。从第一次在社区群里看到店主发“求个能卖橙子的小程序”,到如今帮三十多家生鲜小店上线,我越来越相信:好的技术,不是让人惊叹“这太酷了”,而是让用户忘记技术的存在,只专注把橙子卖出去。
本文还有配套的精品资源,点击获取
简介:直接可用的微信水果商城小程序源码,覆盖完整购物流程:首页展示新鲜水果、分类浏览、商品详情、加入购物车、下单结算、订单管理、个人中心等页面;内置微信授权登录、自动获取用户昵称头像、openid与IP地址识别能力;已对接微信支付接口,支持真实交易流程;后端由云函数支撑,按功能拆分为login、pay、userInfo、getOpenid、getIP、add等独立模块,结构清晰便于调试和扩展;项目包含标准小程序目录结构(pages、components、utils、style、images)、app.配置、sitemap.站点地图、project.config.开发环境设置,以及npm依赖管理(package.、miniprogram_npm)和云开发必需的cloudfunctions目录;适合想快速上线小型生鲜电商、学习小程序云开发或进行二次定制的开发者使用。
本文还有配套的精品资源,点击获取
