前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >手把手教你做个煎饼小程序,摊子开起来

手把手教你做个煎饼小程序,摊子开起来

作者头像
腾讯云开发TCB
发布2024-09-12 16:36:04
发布2024-09-12 16:36:04
14400
代码可运行
举报
文章被收录于专栏:云开发云开发
运行总次数:0
代码可运行

前言

周饼伦在街头摊煎饼,摊后人群熙熙攘攘。他忙得不可开交,既要记住面前小哥要加的培根,又要记住身后奶奶要加的生菜,这时又来了个小妹妹,点的煎饼既要培根又要腊肠。他把鸡蛋打进煎饼后,竟突然忘了前面光头大叔要加的料,是火腿还是鸡柳?一时记不清,好像是火腿,对。然而当把煎饼交给大叔,大叔却怒了,说要的是鸡柳。😡

这可咋办?周饼伦赶忙道歉,大叔却语重心长地说:“试试用小程序云开发吧!最近的数据模型新功能好用得很!” 周饼伦亮出祖传手艺,边摊煎饼边开发小程序,把新开发的小程序点餐页面二维码贴在摊前。从此再没出过错,终于能安心摊煎饼啦!

设计思路

客户扫摊子上面贴的二维码后,会进入点餐页面,在选好要加的配料之后,点击确定就可以点餐,随后,即可在云后台上看到食客提交的数据

实现过程

周饼伦就把当前摊位的主食、配菜,以及各自相应的价格贴在了摊位上,也要把食客的点餐内容记在脑里或者用笔写在纸上。

点餐页要实现两个功能:1.展示当前摊位有的主食、配菜、口味 2.提交订单到周饼伦的订单页面。

煎饼摊子主食(staple food)目前只有摊饼、青菜饼,主食下面有的配菜(side dish),有鸡柳、生菜、鸡蛋、火腿、腊肠。

同理,数据库里面也需要呈现相应的结构。

数据表的实现

数据模型现在提供了一种便捷的能力来,可以快速创建一套可用的数据表来记录摊煎饼的相关数据。

在云后台中新增了一个基于 MySQL 的数据模型,数据模型相当于一张纸,可以在上面记录任何想要记录的数据,比如周饼伦摊位的提供的菜品

创建了基于云开发MySQL数据库的主食表,主食表中包含主食名称,主食价格

字段的详细设置如下

加了主食、配菜两个表之后,将当前的主食和配菜一起加进数据表中

现在就实现了记录当前摊子的主食和配菜。还需要一个订单表,来记录用户的点餐数据

配菜的类型是一个数组文本,用来记录配菜的类型,结构如下

接着需要分别设置每个数据模型的权限。在使用小程序查看订单时,也是以用户的身份来读取的,所以,需要配置用户权限,通过页面访问来控制用户能够访问到哪些页面

至此,数据表就已经大功告成!现在完全可以使用三个表来记录当前摊子的菜品、营业情况。

但是,别忘了周饼伦的目的不止于此,为了周饼伦实现早日暴富,当上CEO,所以,还要利用小程序实现一个界面,来给”上帝“们点餐,并且提供各位CEO查看订单

小程序实现过程

一. 初始化 SDK

在云后台的数据管理中的右侧中,可以方便的查询到使用的文档

新建一个基于云开发的小程序,删除不必要的页面,并且按照文档的步骤进行初始化👇

1.按照指引在 miniprogram 目录下初始化 npm 环境并安装 npm 包

请注意,这里需要在 miniprogram 目录下初始化 npm ,不然需要编辑 project.config.json 手动指定 npm 包的位置

在 miniprogram 目录下打开终端

2.初始化当前 npm 并且安装 @cloudbase/wx-cloud-client-sdk npm 包

代码语言:javascript
代码运行次数:0
复制
npm init -y & npm install @cloudbase/wx-cloud-client-sdk --save

3.在小程序中构建 npm

4.在小程序 app.js 中初始化环境

代码语言:javascript
代码运行次数:0
复制
// app.js
App({
  globalData: {
    // 在这里提供全局变量 models 数据模型方法,方便给页面使用
    models: null
  },
  onLaunch: async function () {
    const {
      init
    } = require('@cloudbase/wx-cloud-client-sdk')
    // 指定云开发环境 ID
    wx.cloud.init({
      env: "ju-9g1guvph88886b02",
    });
    const client = init(wx.cloud);
    const models = client.models;
    // 可以取消注释查看效果
    // const { data } = await models.stapleFood.list({
    //   filter: {
    //     where: {}
    //   },
    //   pageSize: 10,
    //   pageNumber: 1,
    //   getCount: true,
    // });
    // console.log('当前的主食数据:');
    // console.log(data.records);
  }
});

二. 下单页面的实现

首先创建一个页面 goods-list 页面作为首页

顾客如果浏览下单页面,那么就需要看到当前可以选择的主食、配菜,还有他们分别的价格。所以首先我们需要把主食、配菜加载进来

代码语言:javascript
代码运行次数:0
复制
// 加载主食
const stapleFood = (await models.stapleFood.list({
  filter: {
    where: {}
  },
  pageSize: 100, // 一次性加载完,
  pageNumber: 1,
  getCount: true,
})).data.records;

// 加载配菜
const sideDish = (await models.sideDish.list({
  filter: {
    where: {}
  },
  pageSize: 100, // 一次性加载完,
  pageNumber: 1,
  getCount: true,
})).data.records;
代码语言:javascript
代码运行次数:0
复制
// pages/goods-list/index.js
Page({
  data: {
    // 总价格
    totalPrize: 0,
    // 选中的主食
    selectedStapleFoodName: '',
    // 选中的配菜
    selectedSideDishName: [],
    // 所有的主食
    stapleFood: [],
    // 所有的配菜
    sideDish: [],

以下是全部的js代码

代码语言:javascript
代码运行次数:0
复制
// pages/goods-list/index.js
Page({
  data: {
    // 总价格
    totalPrize: 0,
    // 选中的主食
    selectedStapleFoodName: '',
    // 选中的配菜
    selectedSideDishName: [],
    // 所有的主食
    stapleFood: [],
    // 所有的配菜
    sideDish: [],
  },

  async onLoad(options) {
    const models = getApp().globalData.models;
    console.log('models', models)

    // 加载主食
    const stapleFood = (await models.stapleFood.list({
      filter: {
        where: {}
      },
      pageSize: 100, // 一次性加载完,
      pageNumber: 1,
      getCount: true,
    })).data.records;

    // 加载配菜
    const sideDish = (await models.sideDish.list({
      filter: {
        where: {}
      },
      pageSize: 100, // 一次性加载完,
      pageNumber: 1,
      getCount: true,
    })).data.records;

    console.log({
      stapleFood,
      sideDish
    });

    this.setData({
      stapleFood: stapleFood,
      sideDish: sideDish
    })
  },

  // 选中主食
  onSelectStapleFood(event) {
    this.setData({
      selectedStapleFoodName: event.currentTarget.dataset.data.name
    });

    this.computeTotalPrize();
  },

  // 选中配菜
  onSelectedSideDish(event) {
    console.log(event);
    // 选中配菜名字
    const sideDishName = event.currentTarget.dataset.data.name;

    // 如果已经选中,则取消选中
    if (this.data.selectedSideDishName.includes(sideDishName)) {
      this.setData({
        selectedSideDishName: this.data.selectedSideDishName.filter((name) => (name !== sideDishName))
      });
    } else {
      // 未选中,则选中
      this.setData({
        selectedSideDishName: this.data.selectedSideDishName.concat(sideDishName)
      });
    }

    this.computeTotalPrize();
  },

  // 重新计算价格
  computeTotalPrize() {
    // 主食价格
    let staplePrize = 0;
    if (this.data.selectedStapleFoodName) {
      staplePrize = this.data.stapleFood.find((staple) => staple.name === this.data.selectedStapleFoodName).prize;
    }

    // 配菜价格
    let sideDish = 0;
    this.data.selectedSideDishName.forEach((sideDishName) => {
      sideDish += this.data.sideDish.find((sideDishItem) => (
        sideDishItem.name === sideDishName
      )).prize;
    });

    // 总价格
    this.setData({
      totalPrize: staplePrize + sideDish
    })
  },

  // 提交
  async onSubmit() {
    // 提示正在加载中
    wx.showLoading({
      title: '正在提交订单',
    });

    const models = getApp().globalData.models;
    const { data } = await models.order.create({
      data: {
          served: false,  // 是否已出餐
          sideDish: this.data.selectedSideDishName,  // 配菜
          stapleFoodName: this.data.selectedStapleFoodName,  // 主食名称
          prize: this.data.totalPrize,  // 订单总价格
        }
    });

    console.log(data);
    wx.hideLoading();
  }
});

接着来实现页面

代码语言:javascript
代码运行次数:0
复制
<!--pages/goods-list/index.wxml-->
<view>
  <view class="title">
    <image src='/asset/pancake.png'></image>
    <text class="title">请选择主食</text>
  </view>

  <!-- 主食展示 -->
  <view class="staple-food">
    <view wx:for="{{stapleFood}}" wx:key="_id">
      <view bindtap="onSelectStapleFood" data-data="{{item}}" class="staple-food-item {{selectedStapleFoodName === item.name ? 'selected' : ''}}">
        <image src="{{item.imageUrl}}"></image>
        <view class="prize">{{item.prize}}¥</view>
      </view>
    </view>
  </view>

  <!-- 选择配菜 -->
  <view class="title">
    <image src='/asset/sideDish.png'></image>
    请选择配菜
  </view>

  <!-- 配菜展示 -->
  <view class="side-dish">
    <view wx:for="{{sideDish}}" wx:key="_id">
      <!-- 使得class动态绑定支持 includes 语法 -->
      <wxs module="tool">
        var includes = function (array, text) {
          return array.indexOf(text) !== -1
        }
        module.exports.includes = includes;
      </wxs>
      <view class="side-dish-item {{tool.includes(selectedSideDishName, item.name) ? 'selected' : ''}}" bindtap="onSelectedSideDish" data-data="{{item}}">
        <image src="{{item.imageUrl}}"></image>
        <view class="prize">{{item.prize}}¥</view>
      </view>
    </view>
  </view>

  <!-- 底部菜单 -->
  <view class="bottom-content">
    <view class='bottom-info'>
      <view wx:if="{{!!selectedStapleFoodName}}">主食:{{selectedStapleFoodName}}</view>
      <view wx:if="{{selectedSideDishName.length !== 0}}">配菜:{{selectedSideDishName}}</view>
    </view>

    <view class="bottom-operate">
      <view class="total-prize">当前价格<text class="prize">{{totalPrize}}¥</text></view>
      <view class="submit-button {{!selectedStapleFoodName ? 'disabled' : ''}}" bind:tap="onSubmit">下单</view>
    </view>
  </view>
</view>

再添加一点点的样式

代码语言:javascript
代码运行次数:0
复制
/* pages/goods-list/index.wxss */
.title {
  display: flex;
  align-items: center;
  gap: 16rpx;
  padding: 0 20rpx;
}

.title image {
  height: 46rpx;
  width: 46rpx;
}

.staple-food {
  display: flex;
  margin-bottom: 60rpx;
  overflow: auto;
}

.staple-food-item {
  margin: 20rpx 10rpx;
  display: flex;
  flex-direction: column;
  border: 1px solid #f3f0ee;
  box-shadow: 6rpx 6rpx 6rpx #dfdfdf, -6rpx -6rpx 6rpx #dfdfdf;
  border-radius: 6rpx;
  padding: 8rpx;
}

.staple-food-item.selected, .side-dish-item.selected {
  box-shadow: 6rpx 6rpx 6rpx #58b566, -6rpx -6rpx 6rpx #58b566, 6rpx -6rpx 6rpx #58b566, -6rpx 6rpx 6rpx #58b566;
}

.staple-food-item image {
  border-radius: 6rpx;
  width: 300rpx;
  height: 300rpx;
}

.prize {
  padding: 6rpx 6rpx 0;
  text-align: right;
  color: orangered
}

.side-dish {
  padding: 20rpx 12rpx;
  display: flex;
  gap: 12rpx;
  overflow: auto;
}

.side-dish image {
  height: 200rpx;
  width: 200rpx;
}

.side-dish-item {
  border-radius: 8px;
  padding: 16rpx;
  box-shadow: 6rpx 6rpx 6rpx #dfdfdf, -6rpx -6rpx 6rpx #dfdfdf;
}

.bottom-content {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
}

.bottom-info {
  padding: 30rpx;
  display: flex;
  flex-direction: column;
  color: grey;
  font-size: 0.5em;
}

.bottom-content .total-prize {
  padding: 0 30rpx;
}

.bottom-operate {
  border-top: 1px solid #dfdfdf;
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  height: 100rpx;
}

.submit-button {
  width: 350rpx;
  color: white;
  background: #22b85c;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.submit-button.disabled {
  background: grey;
  /* 注意,这里设置了当按钮置灰的时候,不可点击 */
  pointer-events: none;
}

于是,煎饼摊的小程序就大功告成了!

接着就可以在云后台管理订单了,在将订单完成之后,即可在云后台将订单的状态修改成已完成。

我们还可以做的更多…

是否可以在订单中新增一个点餐号,这样就知道是哪个顾客点的餐?是否可以使用数据模型的关联关系将配菜、主食和订单关联起来?

是否可以在小程序中创建一个管理订单的页面?是否可以添加优惠券数据表,来给客户一些限时优惠?

期待大家的体验反馈

代码地址:

https://github.com/vancece/qiLiXiang/tree/main

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-09-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云开发CloudBase 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据表的实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档