9
头图

上篇文章uniapp云函数教程① :登录篇,我们实现了简单的登录与注册逻辑。这篇文章我们来实现一个商品列表的增删改查实战小项目。源码见文末。

扫码体验

.png浏览器访问

1.数据库设计

我们需要2张表:商品分类表(mall_type)以及商品表(mall_shop),商品表通过键key来和商品分类表进行关联

1.1商品分类表(mall_type)

image.png

{
  "bsonType": "object",
  "required": [],
  "permission": {
    "read": false,
    "create": false,
    "update": false,
    "delete": false
  },
  "properties": {
    "_id": {
      "description": "ID,系统自动生成"
    },
    "name": {
      "description": "商品一级分类"
    }
  }
}

1.2商品表(mall_shop)

image.png

{
  "bsonType": "object",
  "required": [],
  "permission": {
    "read": false,
    "create": false,
    "update": false,
    "delete": false
  },
  "properties": {
    "_id": {
      "description": "ID,系统自动生成"
    },
    "name": {
      "description": "商品名称"
    },
    "key": {
      "description": "对应的一级分类Id"
    },
    "icon": {
      "description": "商品图片"
    },
    "price": {
      "description": "价格"
    }
  }
}

以下仅展示关键代码,具体代码可至源码查看

2.商品列表界面开发

这里直接使用uviewui垂直分类的代码
image.png

3.商品入库界面开发

3.1商品分类功能开发

image.png

3.1.1商品分类添加功能

新建云函数addType,上传部署以及上传运行,添加PATH/http/addtype

'use strict';
exports.main = async (event, context) => {
    const db = uniCloud.database(); //代码块为cdb
    const dbCmd = db.command
    const collection = db.collection('mall_type');

    let queryStringParameters = event.queryStringParameters
    let name = queryStringParameters['name']
    let callback = {}
    let isHasRes = await collection.where({
            name: dbCmd.eq(name)
        })
        .get()
    //简单做一下重复校验
    if (isHasRes.data.length) {
        callback = {
            mesg: '商品分类重复',
            code: 500
        }
    } else {
        let res = await collection.add({
            name: queryStringParameters['name']
        })
        callback = {
            mesg: '添加成功',
            code: 200,
            id: res.id
        }
    }

    return callback
};

添加表单以及接口

<u-form :model="form" ref="uForm">
    <u-form-item label="商品分类" prop="name" label-width='150'>
        <u-input v-model="form.name" placeholder="衣服、酒水等等" />
    </u-form-item>
</u-form>
<u-button @click="submit" type="primary" >提交</u-button>
addType() {
    uni.showLoading({
        title: '添加中'
    });
    uni.request({
        url: 'https://**.com/http/addtype',
        data: {
            name: this.form.name
        },
        success: (res) => {
            if (res.data.code == 200) {
                uni.showToast({
                    icon: 'success',
                    title: '添加成功'
                });
                this.$refs.uForm.resetFields()
            } else {
                uni.showToast({
                    icon: 'error',
                    title: res.data.mesg || '添加失败'
                });
            }
        },
        complete: () => {
            uni.hideLoading();
            this.getType()
        }
    })
},
3.1.2商品分类查询功能

新建云函数getType,上传部署以及上传运行,添加PATH/http/gettype

exports.main = async (event, context) => {
    const db = uniCloud.database(); //代码块为cdb
    const res = await db.collection('mall_type').get()
    return res
};

添加展示当前有多少分类界面,这里采用tag的形式,也方便做删除

<u-tag :text="item.name" v-for="(item,index) in typeList" :key="index" />
getType() {
    uni.showLoading({
        title: '获取分类中'
    });
    uni.request({
        url: 'https://**.com/http/gettype',
        success: (res) => {
            this.typeList = res.data.data || []
            uni.hideLoading()
        }
    })
}
3.1.2商品分类删除功能

新建云函数delType,上传部署以及上传运行,添加PATH/http/deltype

'use strict';
exports.main = async (event, context) => {
    const db = uniCloud.database(); 
    const dbCmd = db.command

    let id = event.queryStringParameters['id']
    const collection = db.collection('mall_type');
    let res = await collection.where({
        _id: dbCmd.eq(id)
    }).remove()
    
    return res
};

添加tag上的方法,以及删除二次弹窗

<u-tag :text="item.name" v-for="(item,index) in typeList" :key="index" closeable @close="tagClick(item,index)" />
<u-modal v-model="show" content="是否删除商品类型?" @confirm='confirm' show-cancel-button></u-modal>
tagClick(item, index) {
    this.show = true;
    this.selectItem = item
},
confirm() {
    uni.request({
        url: 'https://**.com/http/deltype',
        data: {
            id: this.selectItem._id
        },
        success: (res) => {
            uni.showToast({
                icon: 'success',
                title: '删除成功'
            });
            this.getType()
        }
    })
}

3.2商品功能开发

image.png

3.2.1商品添加功能

新建云函数addShop,上传部署以及上传运行,添加PATH/http/addshop

'use strict';
exports.main = async (event, context) => {
    const db = uniCloud.database(); //代码块为cdb
    const dbCmd = db.command
    const collection = db.collection('mall_shop');
    //因为数据有base64图片,所以改为body获取
    let body = JSON.parse(event.body)
    let name = body['name']
    let key = body['key']
    let icon = body['icon']
    let price = body['price']
    let callback = {}
    let isHasRes = await collection.where({
            name: dbCmd.eq(name)
        })
        .get()

    if (isHasRes.data.length) {
        callback = {
            mesg: '商品重复',
            code: 500
        }
    } else {
        let res = await collection.add({
            name: name,
            key: key,
            icon: icon,
            price: price,
        })
        callback = {
            mesg: '添加成功',
            code: 200,
            id: res.id
        }
    }

    //返回数据给客户端
    return callback
};

这里图片直接使用base64进行保存
添加表单以及接口

<u-form :model="form" ref="uForm" label-width='150'>
    <u-form-item label="商品名称" prop="name">
        <u-input v-model="form.name" placeholder="请输入商品名称" />
    </u-form-item>
    <u-form-item label="商品价格" prop="price">
        <u-input v-model="form.price" placeholder="请输入商品价格" type='number' />
    </u-form-item>
    <u-form-item label="商品类型" label-width="150" prop="keyLabel">
        <u-input type="select" :select-open="selectShow" v-model="form.keyLabel" placeholder="请选择商品类型"
            @click="selectShow = true"></u-input>
    </u-form-item>
    <u-form-item label="商品图片(<1MB)" prop="icon" label-width="150">
        <u-upload :max-size="1 * 1024 * 1024" ref="uUpload" width="160" height="160" @on-choose-complete='changeImg' :auto-upload="false" max-count="1"></u-upload>
    </u-form-item>
</u-form>
<u-button @click="submit" type="primary">提交</u-button>
<u-select mode="single-column" :list="typeList" v-model="selectShow" @confirm="selectConfirm"></u-select>

图片上传改为自行上传,并取到图片的base64

changeImg(){
    let file = this.$refs.uUpload.lists[0]
    var fr = new FileReader();
    fr.onloadend = function(e) {
        this.form.icon = e.target.result;
    }.bind(this);
    fr.readAsDataURL(file.file);
},
addShop() {
    uni.showLoading({
        title: '添加中'
    });
    uni.request({
        url: 'https://f**.com/http/addshop',
        method: 'POST',
        data: {
            key: this.form.key,
            price: this.form.price,
            name: this.form.name,
            icon: this.form.icon,
        },
        success: (res) => {
            if (res.data.code == 200) {
                uni.showToast({
                    icon: 'success',
                    title: '添加成功'
                });
            //    this.$refs.uForm.resetFields()
            } else {
                uni.showToast({
                    icon: 'error',
                    title: res.data.mesg || '添加失败'
                });
            }
        },
        complete: () => {
            uni.hideLoading();
        }
    })
},
3.2.2商品查询功能

新建云函数getShop,上传部署以及上传运行,添加PATH/http/getshop
这里的数据格式按照uview商品模板的数据格式来组件即可

[
  {
    name: "xxx",
    foods: [
      {
        name: "xx",
        key: "xx",
        icon: "xx",
        price: "xx"
      }
    ]
  }
];
'use strict';
exports.main = async (event, context) => {
    const db = uniCloud.database(); //代码块为cdb
    const dbCmd = db.command
    //查询商品分类
    const typeRes = await db.collection('mall_type').get()
    const collection = db.collection('mall_shop');
    let shopList = []
    let typeList = typeRes.data || []
    for (var i = 0; i < typeList.length; i++) {
        //查询商品分类下的所属商品
        let list = await collection.where({
                key: dbCmd.eq(typeList[i]._id)
            })
            .get()
        let obj = {
            name: typeList[i].name,
            foods: list.data || []
        }
        shopList.push(obj)
    }

    return {
        data: shopList
    }
};

回到刚才的商城模板页面,添加获取商品的代码,并将tabbar的模拟数据替换为真实数据

getShop(){
    uni.showLoading({
        title: '获取商品中'
    });
    uni.request({
        url: 'https://f**.com/http/getShop',
        success: (res) => {
            this.tabbar = res.data.data || []
            uni.hideLoading()
        }
    })
},
3.2.3商品删除功能

新建云函数delShop,上传部署以及上传运行,添加PATH/http/delshop

'use strict';
exports.main = async (event, context) => {
    const db = uniCloud.database(); //代码块为cdb
    const dbCmd = db.command


    let id = event.queryStringParameters['id']
    const collection = db.collection('mall_shop');
    let res = await collection.where({
        _id: dbCmd.eq(id)
    }).remove()
    //返回数据给客户端
    return res
};

在商城列表,我们为商品添加一个长按(longpress)删除的功能,大约在mallMenu.vue24行。并添加二次确认弹窗

<view class="thumb-box" v-for="(item1, index1) in item.foods" :key="index1"  @longpress='del(item1)'>
<image class="item-menu-image" :src="item1.icon" mode=""></image>
<view class="item-menu-name">{{item1.name}}</view>
</view>
、、、
、、、
<u-modal v-model="show" content="是否删除商品?" @confirm='confirm' show-cancel-button></u-modal>
del(item){
    this.delItem = item
    this.show = true
},
confirm(){
    uni.request({
        url: 'https://**.com/http/delshop',
        data: {
            id: this.delItem._id
        },
        success: (res) => {
            uni.showToast({
                icon: 'success',
                title: '删除成功'
            });
            this.getShop()
        }
    })
}

至此,商品的入库、查看、删除功能便开发完成了

结尾

商品图片素材包下载
源码下载
源码下载gitee
WX20210922-091703.png


雾岛听风
12.1k 声望8.6k 粉丝

丰富自己,胜过取悦别人。