刘大福 發表於 2020-7-28 15:17:00

实战丨如何制作一个完整的外卖小程序(已开源)

<p>最近微信小店开放了,赶着微信全面开放之前,把自己的小程序开源出来给大家使用~</p>
<h2 id="小程序效果">小程序效果</h2>
<p><img src="https://postimg.aliavv.com/mbp/aa0ix.jpg"></p>
<p><img src="https://postimg.aliavv.com/mbp/g88x7.jpg"></p>
<p><img src="https://postimg.aliavv.com/mbp/xscij.jpg"></p>
<h2 id="开发心得">开发心得</h2>
<h3 id="如何在项目中集成云开发">如何在项目中集成云开发</h3>
<p>一开始项目并非基于云开发而开发的,目前考虑用云开发,因此,需要在项目中开启云开发的相关选项。</p>
<p>首先,在小程序文件夹中建立 <code>cloud</code> 文件夹,并在package文件中配置,建立用户登录的云函数并上传到微信小程序云中。相关的操作可以参考官方文档。</p>
<p>我在项目目录中添加了 <code>cloud</code> 和 <code>miniprogram</code> 两个目录,并在 <code>project.config.json</code> 文件夹进行配置</p>
<pre><code class="language-json">{
   "miniprogramRoot": "./miniprogram"
   "cloudfunctionRoot": "./cloud/"
}
</code></pre>
<h3 id="开通云开发">开通云开发</h3>
<p>配置完成后,可以点击控制台中的「云开发」来开通云开发。</p>
<p><img src="https://postimg.aliavv.com/mbp/p2tpq.jpg"></p>
<p>在云开发的界面中配置,并开通云开发。</p>
<p><img src="https://postimg.aliavv.com/mbp/odmum.jpg"></p>
<h3 id="开通数据库集合">开通数据库集合</h3>
<p>云开发不会自动创建数据库集合,因此,你需要手动创建集合。分别创建 店铺表<em>Seller</em>、分类表<em>Category</em>、商品表<em>Food</em>、订单表<em>Order</em>、地址表<em>Address</em>、用户表<em>_User</em>。</p>
<p><img src="https://postimg.aliavv.com/mbp/sy4gv.jpg"></p>
<h3 id="数据操作">数据操作</h3>
<p>有了数据库的表后,就可以在代码中对数据进行操作了。</p>
<p>下方是我进行目录操作的代码。</p>
<pre><code class="language-javascript">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 =&gt; {
      // 获取分类信息
          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 =&gt; {
          console.log(res)
          showModal()
      })
    } else {
      db.collection('Category')
      .add({
          data: form
      })
      .then(res =&gt; {
          console.log(res)
          showModal()
      })
    }
},
showModal() {
    // 操作成功提示并返回上一页
    wx.showModal({
      title: this.data.isEdit ? '修改成功' : '添加成功',
      showCancel: false,
      success: () =&gt; {
      wx.navigateBack()
      }
    })
},
delete: function() {
    // 确认删除对话框
    wx.showModal({
      title: '确认删除',
      success: res =&gt; {
      if (res.confirm) {
          const category = this.data.category
          db.collection('Category')
            .doc(category._id)
            .remove()
            .then(res =&gt; {
            console.log(res)
            wx.showToast({
                title: '删除成功'
            })
            wx.navigateBack()
            })
      }
      }
    })
}
})
</code></pre>
<h3 id="联表查询">联表查询</h3>
<p>在使用数据库时,难免要进行联表查询,<strong>云开发支持在云函数侧进行联表查询</strong>,你可以参考我的代码,来实现联表查询的功能。</p>
<pre><code class="language-javascript">const cloud = require('wx-server-sdk')

cloud.init()

const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) =&gt; {
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
}
</code></pre>
<h3 id="文件上传">文件上传</h3>
<p>在小程序的操作中,难免会遇到需要进行图片上传的场景。在进行图片上传时,云开发提供了方便的云存储供我们查询数据。</p>
<p>在获取到文件的本地路径后,调用 <code>wx.cloud.uploadFile</code> 即可上传文件。</p>
<pre><code class="language-javascript">chooseImage() {
    wx.chooseImage({
      count: 1, // 默认9
      sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
      success: res =&gt; {
      const tempFilePaths = res.tempFilePaths
      const file = tempFilePaths
      const name = utils.random_filename(file) //上传的图片的别名,建议可以用日期命名
      console.log(name)
      wx.cloud.uploadFile({
          cloudPath: name,
          filePath: file, // 文件路径
      }).then(res =&gt; {
          console.log(res)
          const fileId = res.fileID
      // 将文件id保存到数据库表中
          db.collection('Seller').doc(this.data.seller._id)
          .update({
            data: {
            logo_url: fileId
            }
          }).then(() =&gt; {
            wx.showToast({
            title: '上传成功'
            })
            // 渲染本地头像
            this.setData({
            new_logo: fileId
            })
          }, err =&gt; {
            console.log(err)
            wx.showToast({
            title: '上传失败'
            })
          })
      })
      }
    })
}
</code></pre>
<h3 id="微信支付逻辑的实现">微信支付逻辑的实现</h3>
<p>作为一个商城,难免会有微信支付相关逻辑的实现。在这种情况下,可以借助云开发提供的微信支付云调用功能实现快速的 API 调用和接口的实现。</p>
<h4 id="绑定商户">绑定商户</h4>
<p>在使用云开发提供的微信支付时,需要先执行微信支付的绑定,在云开发控制台添加相应的商户号</p>
<p><img src="https://postimg.aliavv.com/mbp/kt425.jpg"></p>
<p>添加后微信会发来通知</p>
<p><img src="https://postimg.aliavv.com/mbp/7qwx3.jpg"></p>
<p>根据提示,开通账号即可。</p>
<p><img src="https://postimg.aliavv.com/mbp/fgizc.jpg"></p>
<blockquote>
<p>如果不绑定,将报“受理关系不存在”的错误</p>
<p><img src="https://postimg.aliavv.com/mbp/56aea.jpg"></p>
</blockquote>
<h4 id="函数代码调用">函数代码调用</h4>
<p>配置完成后,只需要在云函数中调用微信支付的接口,就可以实现相关调用的能力</p>
<pre><code class="language-javascript">const cloud = require('wx-server-sdk')

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

// 云函数入口函数
exports.main = async (event, context) =&gt; {
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
}

</code></pre>
<p>这里 <code>functionName: 'pay_cb'</code>指的就是支付成功后,微信支付那侧给我的回调信息,后面我们就用它来更新我们的订单状态</p>
<h4 id="小程序端代码调用">小程序端代码调用</h4>
<p>调用云函数后,会获得微信支付所需要的各种参数,</p>
<p><img src="https://postimg.aliavv.com/mbp/8ogsq.jpg"></p>
<p>这个时候,就可以在小程序端调用微信支付接口,进行支付,相关代码可以参考</p>
<pre><code class="language-javascript">const { result: payData } = res
wx.requestPayment({
    timeStamp: payData.timeStamp,
    nonceStr: payData.nonceStr,
    package: payData.package,
    signType: 'MD5',
    paySign: payData.paySign,
    success: res =&gt; {
      console.log('支付成功', res)
      wx.showModal({
      title: '支付成功',
      showCancel: false,
      success: () =&gt; {
          // 跳转订单详情页
          wx.navigateTo({
            url: '/order/detail/detail?objectId=' + order._id
          })
      }
      })
    },
...
</code></pre>
<h4 id="微信支付回调处理">微信支付回调处理</h4>
<p>微信统一下单里一个pay_cb回调函数,它是一个云函数,后续微信支付的支付信息将会发送在这个函数中,相应的,我们需要编写处理的方法</p>
<pre><code class="language-javascript">// 云函数入口文件
const cloud = require('wx-server-sdk')

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

// 云函数入口函数
exports.main = async (event, context) =&gt; {
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 }
}
}
</code></pre>
<h2 id="总结">总结</h2>
<p>云开发体验下来,优点自不必多说,微信登录与支付原生支持,调用与调试都很方便,特别是不用启本地服务开发,真的好用;</p>
<p>这个小程序的源码我已经开源了,你可以访问 Gitee 获取源码,自行使用~</p><br><br>
来源:https://www.cnblogs.com/CloudBase/p/13391297.html
頁: [1]
查看完整版本: 实战丨如何制作一个完整的外卖小程序(已开源)