uniapp云开发全栈实战:从零搭建带支付和短信的电商小程序

2026-06-19 0 299

年初帮朋友做一个小众食品的微信小程序,时间紧又不想折腾服务器。之前就听过uniapp的uniCloud,但一直没真正用过。这次硬着头皮上,结果出乎意料地顺滑——数据库、云函数、用户认证、支付全都内置了,而且前端调用就像本地API一样方便。唯一需要自己兜底的就是支付和短信这两块逻辑,在官方文档和社区里翻了几晚,总算串成了一条完整的交易链路。

下面我就把这个电商小程序的搭建过程完整还原出来,从用户短信登录、商品展示、下单到微信支付回调全流程都有。跟着走一遍,基本就能上手uniCloud开发了。

环境准备与uniCloud服务空间创建

在HBuilderX里新建一个uniapp项目,选择“hello uni-app”模板或者空模板,然后在项目根目录上右键点击“创建uniCloud云开发环境”。选择阿里云或腾讯云均可(本例选阿里云),然后会自动在项目里生成uniCloud文件夹,里面有cloudfunctionsdatabase等目录。

接下来需要关联服务空间:在浏览器中登录uniCloud控制台,新建一个服务空间,然后回到HBuilderX里右键云函数目录选择“关联服务空间”,选中刚才创建的空间。

第一步:用户认证——短信验证码登录

很多电商小程序都要求手机号,我们直接用uniCloud的短信验证码能力。首先在云函数目录新建一个名为send-sms的云函数,文件内容:

// cloudfunctions/send-sms/index.js
'use strict';
exports.main = async (event, context) => {
  const { phone } = event;
  if (!/^1d{10}$/.test(phone)) {
    return { code: 1, msg: '手机号格式不正确' };
  }
  
  const db = uniCloud.database();
  // 生成6位随机码
  const code = Math.floor(100000 + Math.random() * 900000).toString();
  
  try {
    // 调用uniCloud短信服务(需在服务空间开通短信功能)
    const res = await uniCloud.sendSms({
      app: false, // 小程序端用true可能会涉及收费模板,这里用false走云函数调用
      phone: phone,
      templateId: '你的短信模板ID', // 在uniCloud控制台短信管理里申请
      data: {
        code: code,
        minute: '5'
      }
    });
    
    // 将验证码存入数据库,5分钟有效
    await db.collection('sms-codes').add({
      phone: phone,
      code: code,
      createTime: Date.now(),
      expireTime: Date.now() + 5 * 60 * 1000
    });
    
    return { code: 0, msg: '发送成功' };
  } catch (e) {
    return { code: 1, msg: '发送失败:' + e.message };
  }
}

前端调用:

// 页面中
uniCloud.callFunction({
  name: 'send-sms',
  data: { phone: '13812345678' }
}).then(res => {
  if (res.result.code === 0) {
    uni.showToast({ title: '验证码已发送' });
  }
});

用户输入验证码后,我们再调用一个云函数login-by-sms来验证并生成uni-id token:

// cloudfunctions/login-by-sms/index.js
'use strict';
const uniID = require('uni-id'); // 需要在云函数目录安装uni-id
exports.main = async (event, context) => {
  const { phone, code } = event;
  const db = uniCloud.database();
  const res = await db.collection('sms-codes')
    .where({ phone, code })
    .orderBy('createTime', 'desc')
    .limit(1)
    .get();
    
  if (res.data.length === 0) {
    return { code: 1, msg: '验证码错误' };
  }
  const record = res.data[0];
  if (Date.now() > record.expireTime) {
    return { code: 1, msg: '验证码已过期' };
  }
  
  // 查找或创建用户
  const uniIdIns = uniID.createInstance({ context });
  const user = await uniIdIns.getUserByUid({ uid: phone }) || 
               await uniIdIns.register({ username: phone, password: phone });
  // 登录获取token
  const loginRes = await uniIdIns.login({ username: phone, password: phone });
  if (loginRes.code === 0) {
    // 删除验证码记录
    await db.collection('sms-codes').doc(record._id).remove();
    return { code: 0, token: loginRes.token, uid: loginRes.uid };
  }
  return { code: 1, msg: '登录异常' };
}

前端拿到token后存入uni.setStorageSync('uni_id_token', token),后续请求带上。

第二步:商品列表与详情——云数据库操作

在uniCloud的web控制台新建数据表goods,添加几条示例商品。然后前端直接使用uniCloud.database()查询:

// 商品列表页
const db = uniCloud.database();
db.collection('goods')
  .where({ status: 'on' })
  .orderBy('sellCount', 'desc')
  .limit(20)
  .get()
  .then(res => {
    this.goodsList = res.result.data;
  });

因为数据库的访问权限可以在云函数里设定,如果是公开数据,可以直接在前端查询。但如果要保护字段(如成本价),就需要在云函数里查询后过滤。这里我们对公开的商品信息直接用前端查询,可以免去一次网络调用。

商品详情页:

db.collection('goods').doc(goodsId).get().then(res => {
  this.goodsInfo = res.result.data[0];
});

第三步:下单与微信支付核心流程

这是最复杂的部分。微信支付的流程是:前端调用云函数创建订单、云函数调用支付接口返回支付参数、前端调起支付、后端接收支付回调并更新订单状态。

新建云函数pay-order

// cloudfunctions/pay-order/index.js
'use strict';
const uniPay = require('uni-pay'); // 需要安装uni-pay依赖
exports.main = async (event, context) => {
  const { goodsId, quantity, addressId } = event;
  const db = uniCloud.database();
  
  // 1. 获取商品信息
  const goodsRes = await db.collection('goods').doc(goodsId).get();
  if (goodsRes.data.length === 0) return { code: 1, msg: '商品不存在' };
  const goods = goodsRes.data[0];
  
  // 2. 生成订单号
  const orderNo = 'OD' + Date.now() + Math.floor(Math.random() * 1000);
  const orderData = {
    orderNo,
    userId: context.UNIID_USERID, // 从uni-id token解析
    goodsId,
    goodsName: goods.name,
    price: goods.price,
    quantity,
    totalFee: goods.price * quantity,
    status: 'unpaid',
    createTime: Date.now(),
    addressId
  };
  await db.collection('orders').add(orderData);
  
  // 3. 调用uni-pay发起微信支付
  const payIns = uniPay.initWeixin({ ... }); // 需要微信支付商户相关配置
  const payParams = await payIns.getOrderInfo({
    openid: context.UNIID_OPENID, // 需要前端传入code换取
    orderNo: orderNo,
    totalFee: orderData.totalFee,
    body: goods.name,
    // ...其他参数
  });
  
  return { code: 0, payParams, orderNo };
}

前端下单后调起支付:

uniCloud.callFunction({
  name: 'pay-order',
  data: { goodsId: 'xxx', quantity: 2, addressId: 'addr1' }
}).then(res => {
  if (res.result.code === 0) {
    const payParams = res.result.payParams;
    // 微信小程序支付
    uni.requestPayment({
      provider: 'wxpay',
      ...payParams,
      success: () => {
        uni.showToast({ title: '支付成功' });
      },
      fail: (e) => {
        console.error('支付失败', e);
      }
    });
  }
});

支付回调云函数pay-callback(需要在微信支付后台配置回调URL指向这个云函数的URL化地址):

// cloudfunctions/pay-callback/index.js
exports.main = async (event, context) => {
  const db = uniCloud.database();
  const xml2js = require('xml2js');
  const parser = new xml2js.Parser({ explicitArray: false });
  const result = await parser.parseStringPromise(event.body);
  const { return_code, out_trade_no } = result.xml;
  
  if (return_code === 'SUCCESS') {
    await db.collection('orders').where({ orderNo: out_trade_no }).update({ status: 'paid' });
    // 可以在这里发模板消息等
  }
  return { code: 'SUCCESS', message: 'OK' };
}

第四步:订单列表与状态同步

用户在下单后需要查看订单状态,订单列表可以直接在前端查询:

const db = uniCloud.database();
db.collection('orders')
  .where({ userId: this.uid })
  .orderBy('createTime', 'desc')
  .get()
  .then(res => {
    this.orderList = res.result.data;
  });

如果希望支付成功后实时更新状态,可以在支付回调里通过uniCloud.push发送推送,或者使用uni-cloud的数据库实时监听。这里我们用简单轮询:在订单详情页设定定时器查询订单状态,当状态变为paid时停止轮询并展示成功界面。

第五步:添加购物车与本地状态管理

购物车数据可以存在本地,用我们在上一篇文章讲过的Pinia或直接uni.setStorageSync。但考虑到电商习惯,购物车最好和云端同步,免得换设备丢失。可以在云数据库新建carts表,通过云函数操作:

// 添加购物车云函数
exports.main = async (event, context) => {
  const { goodsId, count } = event;
  const db = uniCloud.database();
  const userId = context.UNIID_USERID;
  await db.collection('carts').add({
    userId, goodsId, count,
    createTime: Date.now()
  });
  return { code: 0 };
}

前端调用时传入token,云函数自动获取用户ID。

容易踩到的坑和应对

  • 短信模板审批:uniCloud的短信签名和模板必须审核通过才能用,而且小程序内使用有严格限制。可以使用测试模板先调试,但上线前一定要改成企业认证的模板。
  • 支付配置:微信支付商户需要与小程序绑定,并配置API密钥和证书。uni-pay封装了大部分操作,但证书路径等必须正确配置在云函数的config或环境变量中。
  • token过期:uni-id的token有有效期,前端需要处理TOKEN_EXPIRED错误,自动调用刷新token接口或重新登录。
  • 云函数冷启动:首次调用可能较慢,可以配置定时触发器保活,或者使用付费版提升性能。

总结

用uniapp + uniCloud做完这个电商小程序,最大的感受是后端工作量被大幅压缩了。以前写支付接口、短信服务、订单管理,都得自己搭服务器、开端口、调SDK,现在一通云函数调下来,后台管理页面都省了(uniCloud web控制台可直接管理数据)。更重要的是,前端和云函数用同一种JavaScript语言,端到端的类型一致性让人心情舒畅。

如果你也在计划快速试水一个带支付能力的小程序,真心推荐先把uniCloud跑通,它带来的速度感,会让你把更多心思花在产品本身,而不是运维和联调上。

uniapp云开发全栈实战:从零搭建带支付和短信的电商小程序
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 uniapp uniapp云开发全栈实战:从零搭建带支付和短信的电商小程序 https://www.taomawang.com/web/uniapp/2240.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务