社区/文章分享/用云开发实现的开源的外卖小程序,现在来啦

用云开发实现的开源的外卖小程序,现在来啦

最近微信小店开放了,赶着微信全面开放之前,把自己的小程序开源出来给大家使用~

小程序效果

开发心得

如何在项目中集成云开发

一开始项目并非基于云开发开发的,目前考虑用云开发,因此,需要在项目中开启云开发的相关选项。

首先,在小程序文件夹中建立 cloud 文件夹,并在 package 文件中配置,建立用户登录的云函数并上传到微信小程序云中。相关的操作可以参考官方文档

我在项目目录中添加了 cloudminiprogram 两个目录,并在 project.config.json 文件夹进行配置

{
   "miniprogramRoot": "./miniprogram"
   "cloudfunctionRoot": "./cloud/"
}

开通云开发

配置完成后,可以点击控制台中的「云开发」来开通云开发。

在云开发的界面中配置,并开通云开发。

开通数据库集合

云开发不会自动创建数据库集合,因此,你需要手动创建集合。分别创建 店铺表Seller、分类表Category、商品表Food、订单表Order、地址表Address、用户表*_User*。

数据操作

有了数据库的表后,就可以在代码中对数据进行操作了。

下方是我进行目录操作的代码。

const db = wx.cloud.database();
const { showModal } = require("../../utils/utils");

Page({
  onLoad: function (options) {
    // 管理员认证
    getApp().auth();
    if (options.objectId) {
      // 缓存数据
      this.setData({
        isEdit: true,
        objectId: options.objectId,
      });
      // 请求待编辑的分类对象
      db.collection("Category")
        .doc(options.objectId)
        .get()
        .then((res) => {
          // 获取分类信息
          this.setData({
            category: res.data,
          });
        });
    }
  },
  add: function (e) {
    var form = e.detail.value;
    if (form.title == "") {
      wx.showModal({
        title: "请填写分类名称",
        showCancel: false,
      });
      return;
    }
    form.priority = Number.parseInt(form.priority);

    // 添加或者修改分类
    // 修改模式
    if (this.data.isEdit) {
      const category = this.data.category;
      db.collection("Category")
        .doc(category._id)
        .update({
          data: form,
        })
        .then((res) => {
          console.log(res);
          showModal();
        });
    } else {
      db.collection("Category")
        .add({
          data: form,
        })
        .then((res) => {
          console.log(res);
          showModal();
        });
    }
  },
  showModal() {
    // 操作成功提示并返回上一页
    wx.showModal({
      title: this.data.isEdit ? "修改成功" : "添加成功",
      showCancel: false,
      success: () => {
        wx.navigateBack();
      },
    });
  },
  delete: function () {
    // 确认删除对话框
    wx.showModal({
      title: "确认删除",
      success: (res) => {
        if (res.confirm) {
          const category = this.data.category;
          db.collection("Category")
            .doc(category._id)
            .remove()
            .then((res) => {
              console.log(res);
              wx.showToast({
                title: "删除成功",
              });
              wx.navigateBack();
            });
        }
      },
    });
  },
});

联表查询

在使用数据库时,难免要进行联表查询,云开发支持在云函数侧进行联表查询,你可以参考我的代码,来实现联表查询的功能。

const cloud = require("wx-server-sdk");

cloud.init();

const db = cloud.database();

// 云函数入口函数
exports.main = async (event, context) => {
  const result = await db
    .collection("Food")
    .aggregate()
    .lookup({
      from: "Category",
      localField: "category",
      foreignField: "_id",
      as: "categories",
    })
    .end();
  // .orderBy('priority', 'asc')
  // .get()
  console.log(result);
  return result.list;
};

文件上传

在小程序的操作中,难免会遇到需要进行图片上传的场景。在进行图片上传时,云开发提供了方便的云存储供我们查询数据。

在获取到文件的本地路径后,调用 wx.cloud.uploadFile 即可上传文件。

chooseImage() {
    wx.chooseImage({
      count: 1, // 默认9
      sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
      success: res => {
        const tempFilePaths = res.tempFilePaths
        const file = tempFilePaths[0]
        const name = utils.random_filename(file) //上传的图片的别名,建议可以用日期命名
        console.log(name)
        wx.cloud.uploadFile({
          cloudPath: name,
          filePath: file, // 文件路径
        }).then(res => {
          console.log(res)
          const fileId = res.fileID
        // 将文件id保存到数据库表中
          db.collection('Seller').doc(this.data.seller._id)
          .update({
            data: {
              logo_url: fileId
            }
          }).then(() => {
            wx.showToast({
              title: '上传成功'
            })
            // 渲染本地头像
            this.setData({
              new_logo: fileId
            })
          }, err => {
            console.log(err)
            wx.showToast({
              title: '上传失败'
            })
          })
        })
      }
    })
  }

微信支付逻辑的实现

作为一个商城,难免会有微信支付相关逻辑的实现。在这种情况下,可以借助云开发提供的微信支付云调用功能实现快速的 API 调用和接口的实现。

绑定商户

在使用云开发提供的微信支付时,需要先执行微信支付的绑定,在云开发控制台添加相应的商户号

添加后微信会发来通知

根据提示,开通账号即可。

如果不绑定,将报“受理关系不存在”的错误

函数代码调用

配置完成后,只需要在云函数中调用微信支付的接口,就可以实现相关调用的能力

const cloud = require("wx-server-sdk");

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
});

// 云函数入口函数
exports.main = async (event, context) => {
  console.log("请求中");
  console.log(cloud.getWXContext().ENV);
  let { orderId, amount, body } = event;
  const wxContext = cloud.getWXContext();
  const res = await cloud.cloudPay.unifiedOrder({
    body: body,
    outTradeNo: orderId,
    spbillCreateIp: "127.0.0.1",
    subMchId: "1447716902",
    totalFee: amount,
    envId: "dinner-cloud",
    functionName: "pay_cb",
  });
  return res.payment;
};

这里 functionName: 'pay_cb'指的就是支付成功后,微信支付那侧给我的回调信息,后面我们就用它来更新我们的订单状态

小程序端代码调用

调用云函数后,会获得微信支付所需要的各种参数,

这个时候,就可以在小程序端调用微信支付接口,进行支付,相关代码可以参考

const { result: payData } = res
  wx.requestPayment({
    timeStamp: payData.timeStamp,
    nonceStr: payData.nonceStr,
    package: payData.package,
    signType: 'MD5',
    paySign: payData.paySign,
    success: res => {
      console.log('支付成功', res)
      wx.showModal({
        title: '支付成功',
        showCancel: false,
        success: () => {
          // 跳转订单详情页
          wx.navigateTo({
            url: '/order/detail/detail?objectId=' + order._id
          })
        }
      })
    },
...

微信支付回调处理

微信统一下单里一个 pay_cb 回调函数,它是一个云函数,后续微信支付的支付信息将会发送在这个函数中,相应的,我们需要编写处理的方法

// 云函数入口文件
const cloud = require("wx-server-sdk");

cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  env: cloud.DYNAMIC_CURRENT_ENV,
});
const db = cloud.database();

// 云函数入口函数
exports.main = async (event, context) => {
  console.log("支付回调");
  console.log(event);
  console.log(cloud.getWXContext().ENV);
  const orderId = event.outTradeNo;
  const resultCode = event.resultCode;
  if (resultCode === "SUCCESS") {
    const res = await db
      .collection("Order")
      .doc(orderId)
      .update({
        data: {
          status: 1,
        },
      });
    console.log(res);
    return { errcode: 0 };
  }
};

总结

云开发体验下来,优点自不必多说,微信登录与支付原生支持,调用与调试都很方便,特别是不用启本地服务开发,真的好用;

这个小程序的源码我已经开源了,你可以访问 Gitee 获取源码,自行使用~