2021-01-28

购物车

购物车表创建

关联用户、关联商品、购买的数量

class Cart(models.Model):
    """
    购物车模型
    """
    user = models.ForeignKey('users.User', on_delete=models.CASCADE)
    goods = models.ForeignKey('goods.Goods', on_delete=models.CASCADE)
    goods_num = models.IntegerField(default=1)

    class Meta:
        db_table = 'cart'

    def __str__(self):
        return '购买了{}个{}'.format(self.goods_num, self.goods.name)

购物车的添加

需要进入到商品详情页

点击加入购物车(判断用户是否登录、用户登录的话,进行添加,否则跳转到登录页面)

// 加入购物车
        addCart() {
            // 需要判断是否登录
            if(this.token) {
                // 继续添加
                // 实例化表单
                let form_data = new FormData()
                // 添加数据
                form_data.append('token', this.token)
                form_data.append('goods_id', this.goods_id)
                form_data.append('goods_num', this.goods_num)
                // 发送请求
                this.axios({
                    url: '/cart/add_cart/',
                    method: 'post',
                    data: form_data
                }).then(res => {
                    console.log(res.data)
                })
            }else{
                // 跳转到登录页面
                this.$router.push({
                    name: 'Login',
                    query: {
                        redirect: this.$route.fullPath
                    }
                })
            }
        },

添加的接口

class AddCart(APIView):

    def post(self, request):
        token = request.data.get('token')
        goods_id = request.data.get('goods_id')
        goods_num = request.data.get('goods_num')  # 网页接收到的数据是字符串,需要进行整型转换
        # 解析token
        user_info = check_token(token)
        # 判断token是否失效
        if user_info:
            # 获取用户id
            user_id = user_info.get('user_id')
            # 获取当前用户的某个商品的对象,用来判断商品是否已经添加购物车之中
            cart_obj = Cart.objects.filter(user_id=user_id, goods_id=goods_id).first()
            # 判断商品是否已添加,如果已添加,修改数量
            if cart_obj:
                cart_obj.goods_num += int(goods_num)
                cart_obj.save()
                return Response({'msg': '数量添加成功', 'code': 200})
            # 否则的话,创建新的购物车
            else:
                Cart.objects.create(user_id=user_id, goods_id=goods_id, goods_num=goods_num)
                return Response({'msg': '添加成功', 'code': 200})
        else:
            return Response({'msg': '请重新登录', 'code': 400})

需要判断用户是否登录

再判断当前用户下是否已经购买过此商品

购买过的话,进行改变数量

否则的话,添加新的购物车

展示购物车

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXIwhEXN-1611814538006)(images\image-20201225140621933.png)]

判断用户是否登录

用户登录时,携带用户id进行获取当前用户下的购物车信息

没有登录时,跳转到登录页面

class CartView(APIView):

    """
    购物车展示
    """
    def get(self, request):
        user_id = request.query_params.get('user_id')
        # 通过用户id去购物车中过滤当前用户下的所有的商品信息
        cart_list = Cart.objects.filter(user_id=user_id)
        # 进行序列
        cart_serializer = ShowCartModelSerializer(cart_list, many=True)
        # 返回数据
        return Response(cart_serializer.data)

vue页面获取数据,并展示

<template>
    <div>
        
        <!-- 在这里引入头部信息 -->
        <my-header></my-header>

        <div class="search_bar clearfix">
            <a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a>
            <div class="sub_page_name fl">&nbsp;&nbsp;&nbsp;&nbsp;购物车</div>
            <div class="search_con fr">
                <input type="text" class="input_text fl" name="" placeholder="搜索商品">
                <input type="button" class="input_btn fr" name="" value="搜索">
            </div>		
        </div>

        <div class="total_count">全部商品<em>2</em>件</div>	
        <ul class="cart_list_th clearfix">
            <li class="col01">商品名称</li>
            <li class="col02">商品单位</li>
            <li class="col03">商品价格</li>
            <li class="col04">数量</li>
            <li class="col05">小计</li>
            <li class="col06">操作</li>
        </ul>
        <!-- 购物车展示 -->
        <ul class="cart_list_td clearfix" v-for="cart in cart_list" :key="cart.id">
            <li class="col01"><input type="checkbox" name="" checked></li>
            <li class="col02"><img :src="base_url + cart.goods.image"></li>
            <li class="col03">{{cart.goods.name}}<br><em>{{cart.goods.price}}元/kg</em></li>
            <li class="col04">kg</li>
            <li class="col05">{{cart.goods.price}}元</li>
            <li class="col06">
                <div class="num_add">
                    <a href="javascript:;" class="add fl">+</a>
                    <input type="text" class="num_show fl"  v-model="cart.goods_num">	
                    <a href="javascript:;" class="minus fl">-</a>	
                </div>
            </li>
            <li class="col07">{{(cart.goods.price * cart.goods_num).toFixed(2)}}元</li>
            <li class="col08"><a href="javascript:;">删除</a></li>
        </ul>

        <ul class="settlements">
            <li class="col01"><input type="checkbox" name="" checked=""></li>
            <li class="col02">全选</li>
            <li class="col03">合计(不含运费):<span>¥</span><em>42.60</em><br>共计<b>2</b>件商品</li>
            <li class="col04"><a href="place_order.html">去结算</a></li>
        </ul>

        <!-- 引用组件 -->
        <my-fooder></my-fooder>
    </div>
</template>

<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
    // 注册组件
    components: {
        'my-fooder': Fooder,
        'my-header': Header
    },
    data() {
        return {
            user_id: sessionStorage.getItem('user_id'),
            cart_list: [],
            base_url: 'http://127.0.0.1:8000'
        }
    },
    methods: {
        // 获取购物车信息
        getCart() {
            this.axios({
                url: '/cart/cart/?user_id=' + this.user_id
            }).then(res => {
                console.log(res.data)
                this.cart_list = res.data
            })
        }
    },
    created() {
        this.getCart()
    }
}
</script>

路由守卫

当进入某一个路由地址,进行判断,判断用户是否登录,sessionStoage里面获取user_id

import Vue from 'vue'
import Router from 'vue-router'
import Cart from '@/components/Cart'

Vue.use(Router)

const router =  new Router({
  mode: 'history',
  routes: [
    {
      path: '/cart',
      name: 'Cart',
      component: Cart,
      meta: {
        // 用来判断当前进入用户是否已登录,如果未登录的话,进行登录
        is_login: true
      }
    }
  ]
})

router.beforeEach((to, from, next) => {
    // 先进行判断,判断要进入的路由是否需要进行登录
    if(to.meta.is_login) {
        // 需要登录,进行登录判断
        let user_id = sessionStorage.getItem('user_id')
        if(user_id) {
            next()
        }else{
            next({
                name: 'Login',
                query: {
                    redirect: to.fullPath
                }
            })
        }
    }else{
		// 不需要登录 时要做的事情 
        next()
    }
})

export default router

购物车

加减数量接口

class AddNumView(APIView):
    """
    购物车加数量
    """
    def post(self, request):
        # 获取前端提交的购物车id
        cart_id = request.data.get('cart_id')
        # 通过购物车id,获取购物车的对象
        try:
            cart_obj = Cart.objects.get(pk=cart_id)
        except Cart.DoesNotExist:
            # 返回数据有误
            return Response({'msg': '数据有误', 'code': 400})
        # 对象存在 进行加数量
        else:
            cart_obj.goods_num += 1
            cart_obj.save()
            return Response({'msg': '添加成功', 'code': 200})


class MinusNumView(APIView):
    """
    购物车加数量
    """
    def post(self, request):
        # 获取前端提交的购物车id
        cart_id = request.data.get('cart_id')
        # 通过购物车id,获取购物车的对象
        try:
            cart_obj = Cart.objects.get(pk=cart_id)
        except Cart.DoesNotExist:
            # 返回数据有误
            return Response({'msg': '数据有误', 'code': 400})
        # 对象存在 进行加数量
        else:
            if cart_obj.goods_num > 1:
                cart_obj.goods_num -= 1
                cart_obj.save()
                return Response({'msg': '减成功', 'code': 200})
            else:
                return Response({'msg': '数量不足', 'code': 400})

加减数量页面方法

<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
    data() {
        return {
            
        }
    },
    methods: {
        // 购物车减数量
        minusNum(cart_id) {
            // 实例化
            let form_data = new FormData()
            // 添加数据
            form_data.append('cart_id', cart_id)
            // 发送请求
            this.axios({
                url: '/cart/minus_num/',
                method: 'post',
                data: form_data
            }).then(res => {
                console.log(res.data)
                if(res.data.code == 200) {
                    // 重新调用获取购物车的方法
                    this.getCart()
                }
            })
        },
        // 购物车加数量
        addNum(cart_id) {
            // 实例化
            let form_data = new FormData()
            // 添加数据
            form_data.append('cart_id', cart_id)
            // 发送请求
            this.axios({
                url: '/cart/add_num/',
                method: 'post',
                data: form_data
            }).then(res => {
                console.log(res.data)
                if(res.data.code == 200) {
                    // 重新调用获取购物车的方法
                    this.getCart()
                }
            })
        },
        // 获取购物车信息
        getCart() {
            this.axios({
                url: '/cart/cart/?user_id=' + this.user_id
            }).then(res => {
                console.log(res.data)
                this.cart_list = res.data
            })
        }
    },
    created() {
        this.getCart()
    }
}
</script>

全选与多选并计算金额

<template>
    <div>
        
        <!-- 在这里引入头部信息 -->
        <my-header></my-header>

        <div class="search_bar clearfix">
            <a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a>
            <div class="sub_page_name fl">&nbsp;&nbsp;&nbsp;&nbsp;购物车</div>
            <div class="search_con fr">
                <input type="text" class="input_text fl" name="" placeholder="搜索商品">
                <input type="button" class="input_btn fr" name="" value="搜索">
            </div>		
        </div>

        <div class="total_count">全部商品<em>2</em>件</div>	
        <ul class="cart_list_th clearfix">
            <li class="col01">商品名称</li>
            <li class="col02">商品单位</li>
            <li class="col03">商品价格</li>
            <li class="col04">数量</li>
            <li class="col05">小计</li>
            <li class="col06">操作</li>
        </ul>
        <!-- 购物车展示 -->
        <ul class="cart_list_td clearfix" v-for="cart in cart_list" :key="cart.id">
            <li class="col01"><input type="checkbox" name="" @click="multipleChoice(cart.id, cart.goods.price, cart.goods_num)" v-model="checkBox_list" :value="cart.id"></li>
            <li class="col02"><img :src="base_url + cart.goods.image"></li>
            <li class="col03">{{cart.goods.name}}<br><em>{{cart.goods.price}}元/kg</em></li>
            <li class="col04">kg</li>
            <li class="col05">{{cart.goods.price}}元</li>
            <li class="col06">
                <div class="num_add">
                    <a href="javascript:;" class="add fl" @click="addNum(cart.id)">+</a>
                    <input type="text" class="num_show fl"  v-model="cart.goods_num">	
                    <a href="javascript:;" class="minus fl" @click="minusNum(cart.id)">-</a>	
                </div>
            </li>
            <li class="col07">{{(cart.goods.price * cart.goods_num).toFixed(2)}}元</li>
            <li class="col08"><a href="javascript:;" @click="delCart(cart.id)">删除</a></li>
        </ul>

        <ul class="settlements">
            <li class="col01"><input type="checkbox" name="" v-model="checked" @click="selectAll"></li>
            <li class="col02">全选</li>
            <li class="col03">合计(不含运费):<span>¥</span><em>{{(total).toFixed(2)}}</em><br>共计<b>{{checkBox_list.length}}</b>件商品</li>
            <li class="col04"><a href="place_order.html">去结算</a></li>
        </ul>

        <!-- 引用组件 -->
        <my-fooder></my-fooder>
    </div>
</template>

<script>
// 导入组件
import Fooder from './Fooder'
import Header from './Header'
export default {
    // 注册组件
    components: {
        'my-fooder': Fooder,
        'my-header': Header
    },
    data() {
        return {
            user_id: sessionStorage.getItem('user_id'),
            cart_list: [],
            base_url: 'http://127.0.0.1:8000',
            checkBox_list: [],
            checked: false,
            total: 0

        }
    },
    methods: {
        // 删除购物车
        delCart(cart_id) {
            let form_data = new FormData()
            // 添加数据
            form_data.append('cart_id', cart_id)
            // 发送请求
            this.axios({
                url: '/cart/del_cart/',
                method: 'delete',
                data: form_data
            }).then(res => {
                console.log(res.data)
                if(res.data.code == 200) {
                    this.getCart()
                }
            })
        },
        // 计算总价
        sumTotal() {
            for(let i in this.cart_list) {
                this.total += this.cart_list[i].goods.price * this.cart_list[i].goods_num
            }
            return this.total
        },
        // 全选
        selectAll() {
            // 判断全选的状态
            if(this.checked) {
                // 为true时,全不选
                this.checkBox_list = []
                this.total = 0
            }else{
                this.total = 0
                this.checkBox_list = []
                this.cart_list.forEach(item => {
                    this.checkBox_list.push(item.id)
                })
                // 商品全选时,计算总价
                this.sumTotal()
                console.log(this.checkBox_list)
            }
        },
        // 多选
        multipleChoice(cart_id, goods_price, goods_num) {
            // 判断购物车id在不在列表中
            // includes(element)  判断元素在不在列表中
            if(this.checkBox_list.includes(cart_id)){
                // 如果在里面的话,进行切除  splice(开始位置, 切除几个元素)   indexOf(element) 获取元素下标
                this.checkBox_list.splice(this.checkBox_list.indexOf(cart_id), 1)
                // 取消选中,减去对应的金额
                this.total -= goods_price * goods_num
            }else{
                this.checkBox_list.push(cart_id)
                this.total += goods_price * goods_num
            }

            if(this.checkBox_list.length == this.cart_list.length) {
                this.checked = true
            }else{
                this.checked = false
            }
            
            console.log(this.checkBox_list)
        },
        // 购物车减数量
        minusNum(cart_id) {
            // 实例化
            let form_data = new FormData()
            // 添加数据
            form_data.append('cart_id', cart_id)
            // 发送请求
            this.axios({
                url: '/cart/minus_num/',
                method: 'post',
                data: form_data
            }).then(res => {
                console.log(res.data)
                if(res.data.code == 200) {
                    // 重新调用获取购物车的方法
                    this.getCart()
                }
            })
        },
        // 购物车加数量
        addNum(cart_id) {
            // 实例化
            let form_data = new FormData()
            // 添加数据
            form_data.append('cart_id', cart_id)
            // 发送请求
            this.axios({
                url: '/cart/add_num/',
                method: 'post',
                data: form_data
            }).then(res => {
                console.log(res.data)
                if(res.data.code == 200) {
                    // 重新调用获取购物车的方法
                    this.getCart()
                }
            })
        },
        // 获取购物车信息
        getCart() {
            this.axios({
                url: '/cart/cart/?user_id=' + this.user_id
            }).then(res => {
                console.log(res.data)
                this.cart_list = res.data
            })
        }
    },
    created() {
        this.getCart()
    }
}
</script>

删除购物车的接口

class DelCartView(APIView):
    """
    删除购物车
    """
    def delete(self, request):
        cart_id = request.data.get('cart_id')
        # 通过购物车id,查找购物车对象
        cart_obj = Cart.objects.filter(pk=cart_id).delete()
        # 返回
        return Response({'msg': '删除成功', 'code': 200})

购物车组件

<template>
    <div>
        <div class="guest_cart fr">
            <a href="#" class="cart_name fl">我的购物车</a>
            <div class="goods_count fl" id="show_count">{{cart_num}}</div>
        </div>
    </div>
</template>

<script>
import axios from 'axios'
export default {
    props: {
        cart_num: {
            default: 0
        }
    }   
}
</script>

首页

<template>
    <div>
        <div class="search_bar clearfix">          
            <!-- 购物车组件 -->
            <my-cart :cart_num="cart_num"></my-cart>
        </div>

    </div>
</template>

<script>
import MyCart from './MyCart'
export default {
    // 注册组件
    components: {
        'my-cart': MyCart
    },
    data() {
        return {
            
            user_id: sessionStorage.getItem('user_id'),
            cart_num: 0
        }
    },
    methods: {
        // 购物车展示数量
        getCart() {
            if(this.user_id) {
                this.axios({
                    url: '/cart/cart_count/?user_id=' + this.user_id
                }).then(res => {
                    console.log(res.data)
                    if(res.data.code == 200) {
                        this.cart_num = res.data.cart_num
                    }
                })
            }
        },
        
    },
    created() {
        
        // 页面加载时,获取购物车数据
        this.getCart()
    }
}
</script>

上一篇:javaFX系列之launcher启动器:两种启动javaFX的方式及launch(args[])参数设置和获取


下一篇:LED Decorative Light Supplier - LED Neon Application: 5 Advantages