第14次:商品列表、热销商品及详情

第1步:定义获取商品列表的视图类ListView,本视图中完成了如下功能:

  1. 根据商品类别id获取商品类别信息,并根据类别信息反向查询到所有的该类别的商品。
  2. 根据页号和排序方式两个参数,获取某个页面的商品列表信息。
python 复制代码
#goods应用下views.py

from django.core.paginator import Paginator, EmptyPage
from django.http import HttpResponseNotFound, HttpResponseForbidden, JsonResponse
from django.shortcuts import render
from django.views import View

from contents.utils import get_categories
from goods.models import GoodsCategory, SKU
from orders.models import OrderGoods
from xiaoyu_mall_new import settings
from xiaoyu_mall_new.utils.response_code import RETCODE
from .constants import PER_PRODUCTS_LIMIT as per_goods_num
from .utils import get_breadcrumb


class ListView(View):
    def get(self, request, category_id, page_num):
        """提供商品列表页,
        category_id:商品类别id
        page_num:第几页,页号"""
        try:
            # 1 根据商品类别id获取该商品类别
            category = GoodsCategory.objects.get(id=category_id)
        except GoodsCategory.DoesNotExist:
            return HttpResponseNotFound('"参数category_id不存在"')

        # 2 接收sort参数,如果没有传递这个参数,那么使用默认的排序方式。分别对应html页面中的默认、人气和价格3种排序方式
        sort = request.GET.get('sort', 'default')
        # 默认排序 按价格排序 按人气排序
        if sort == 'price':
            sort_field = 'price'
        elif sort == 'hot':
            sort_field = '-sales'
        else:
            sort = 'default'
            sort_field = 'create_time'

        # 3 根据类别信息反向查询,获取商品列表
        skus = category.sku_set.filter(is_launched=True).order_by(sort_field)
        # 4 数据分页功能
        # 创建分页器
        paginator = Paginator(skus, per_goods_num)  # 对skus进行分页,每页显示5条数据
        # 获取用户当前要看的那一页数据
        try:
            page_skus = paginator.page(page_num)
        except EmptyPage:
            return HttpResponseForbidden('Empty Page')
        # 获取总的页码数,前端分页插件中需要使用
        total_page = paginator.num_pages
        # 查询商品分类
        categories = get_categories()
        # 5 查询面包屑导航:一级 ==>二级==>一级
        breadcrumb = get_breadcrumb(category)

        # 6 根据商品类别id,查询所有的在售商品
        skus = SKU.objects.filter(category_id=category_id, is_launched=True)
        # 把所有商品的sku id 存放在sku_li中
        sku_li = []  # 保存当前页所有的sku_id
        for sku in skus:
            sku_li.append(sku.id)
        # 7 获取每个sku-id的评论数量
        product_review_num = []
        for sid in sku_li:
            # 根据商品id获取已评论的订单
            order_goods_list = OrderGoods.objects.filter(sku_id=sid, is_commented=True)
            # 保存每件商品的评价内容
            product_review_content = []
            for order_goods in order_goods_list:
                product_review_content.append(order_goods.comment)
            product_review_num.append(len(product_review_content))
        # 获取每页各个商品的评价数量,并保存到列表中
        per_review_num = [product_review_num[i:i + per_goods_num] for i in
                          range(0, len(product_review_num), per_goods_num)]
        # 获取当前访问各个商品的数量
        cur_per_review_num = per_review_num[page_skus.number - 1]
        # 8 将每个商品数量赋值给每个商品sku对象
        # 通过zip函数将sku对象和评价数量进行组合,格式为:[(sku对象,商品评价数量)]
        for sku in list(zip(page_skus, cur_per_review_num)):
            # 动态添加商品评价数量review_num属性
            sku[0].review_num = sku[1]

        context = {
            'category_id': category_id,
            'sort': sort,
            'page_skus': page_skus,
            'page_num': page_num,
            'total_page': total_page,
            'categories': categories,
            'breadcrumb': breadcrumb,
        }

        print(context)
        return render(request, 'list.html', context)

在goods应用下定义constants.py,其中定义常量

python 复制代码
# 每页显示商品数量
PER_PRODUCTS_LIMIT = 5

上面代码中用的get_breadcrumb(category)函数定义在goods/utils.py中,参数为类别对象。

python 复制代码
def get_breadcrumb(category):
    """
    获取面包屑导航
    :param category:类别对象:一级 二级  三级
    :return:一级:返回一级  二级:返回一级+二级  三级:一级+二级+三级
    """
    breadcrumb = {
        'cat1': '',
        'cat2': '',
        'cat3': '',
    }
    if category.parent == None:  			# 一级类别
        breadcrumb['cat1'] = category
    elif category.subs.count() == 0:  		# 三级类别
        cat2 = category.parent
        breadcrumb['cat1'] = cat2.parent
        breadcrumb['cat2'] = cat2
        breadcrumb['cat3'] = category
    else:  									# 二级类别
        breadcrumb['cat1'] = category.parent
        breadcrumb['cat2'] = category
    return breadcrumb

第2步:定义热销排行视图类,用于展示与商品列表同类别的、销量前2名的商品,

python 复制代码
#goods应用下views.py
class HostGoodsView(View):
    """热销排行"""

    def get(self, request, category_id):
        # 1 查询热销数据(结果为SKU模型类的对象列表)
        skus = SKU.objects.filter(category_id=category_id, is_launched=True).order_by('-sales')[:2]
        # 2 将模型列表转字典构造JSON数据
        hot_skus = []
        for sku in skus:
            sku_dict = {
                'id': sku.id,
                'name': sku.name,
                'price': sku.price,
                # 'default_image_url': settings.STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
                'default_image_url': "http://localhost:8000/" + settings.STATIC_URL + 'images/goods/' + sku.default_image.url + '.jpg'
            }
            hot_skus.append(sku_dict)
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'hot_skus': hot_skus})

第3步:定义展示商品详情的视图类,获取用户点击的商品。

python 复制代码
#goods应用下views.py
class DetailView(View):
    """商品详情页"""

    def get(self, request, sku_id):
        """提供商品详情页"""
        # 获取当前sku的信息
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return render(request, '404.html')
        # 查询商品频道分类
        categories = get_categories()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 构建当前商品的规格键
        sku_specs = sku.specs.order_by('spec_id')
        sku_key = []
        for spec in sku_specs:
            sku_key.append(spec.option.id)
        # 获取当前商品的所有SKU
        skus = sku.spu.sku_set.all()
        # 构建不同规格参数(选项)的sku字典
        spec_sku_map = {}
        for s in skus:
            # 获取sku的规格参数
            s_specs = s.specs.order_by('spec_id')
            # 用于形成规格参数-sku字典的键
            key = []
            for spec in s_specs:
                key.append(spec.option.id)
            # 向规格参数-sku字典添加记录
            spec_sku_map[tuple(key)] = s.id
        # 获取当前商品的规格信息
        goods_specs = sku.spu.specs.order_by('id')
        # 若当前sku的规格信息不完整,则不再继续
        if len(sku_key) < len(goods_specs):
            return
        for index, spec in enumerate(goods_specs):
            key = sku_key[:]
            # 该spu商品的所有规格选项
            spec_options = spec.options.all()
            for option in spec_options:
                # 在规格参数sku字典中查找符合当前规格的sku
                key[index] = option.id  # 设置当前商品的规格参数
                option.sku_id = spec_sku_map.get(tuple(key))
            spec.spec_options = spec_options
        # 渲染页面
        context = {
            'categories': categories,
            'breadcrumb': breadcrumb,
            'sku': sku,
            'stock': sku.stock,
            'specs': goods_specs,
        }
        return render(request, 'detail.html', context)

第4步:定义订单评价视图类,查询某个商品的评价信息,由于尚未完成订单的支付功能,系统中没有订单信息,所以这里是查询不到评价的。

python 复制代码
class GoodsCommentView(View):
    """订单商品评价信息"""

    def get(self, request, sku_id):
        # 获取被评价的订单商品信息
        order_goods_list = OrderGoods.objects.filter(sku_id=sku_id, is_commented=True).order_by('-create_time')[:30]
        comment_list = []
        for order_goods in order_goods_list:
            username = order_goods.order.user.username
            comment_list.append({
                'username': username[0] + '***' + username[-1]
                if order_goods.is_anonymous else username,
                'comment': order_goods.comment,
                'score': order_goods.score,
            })
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK',
                             'comment_list': comment_list})

第5步:订单商品模型,定义在orders应用models.py中

python 复制代码
from django.db import models

# Create your models here.
from xiaoyu_mall_new.utils.models import BaseModel
from users.models import User, Address
from goods.models import SKU


class OrderInfo(BaseModel):
    """订单信息"""
    PAY_METHODS_ENUM = {
        "CASH": 1,
        "ALIPAY": 2
    }
    PAY_METHOD_CHOICES = (
        (1, "货到付款"),
        (2, "支付宝"),
    )
    ORDER_STATUS_ENUM = {
        "UNPAID": 1,
        "UNSEND": 2,
        "UNRECEIVED": 3,
        "UNCOMMENT": 4,
        "FINISHED": 5
    }
    ORDER_STATUS_CHOICES = (
        (1, "待支付"),
        (2, "待发货"),
        (3, "待收货"),
        (4, "待评价"),
        (5, "已完成"),
        (6, "已取消"),
    )
    order_id = models.CharField(max_length=64, primary_key=True, verbose_name="订单号")
    user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name="下单用户")
    address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name="收货地址")
    total_count = models.IntegerField(default=1, verbose_name="商品总数")
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="商品总金额")
    freight = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="运费")
    pay_method = models.SmallIntegerField(choices=PAY_METHOD_CHOICES, default=1, verbose_name="支付方式")
    status = models.SmallIntegerField(choices=ORDER_STATUS_CHOICES, default=1, verbose_name="订单状态")

    class Meta:
        db_table = "tb_order_info"
        verbose_name = '订单基本信息'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.order_id
    
class OrderGoods(BaseModel):
    """订单商品"""
    SCORE_CHOICES = (
        (0, '0分'),
        (1, '20分'),
        (2, '40分'),
        (3, '60分'),
        (4, '80分'),
        (5, '100分'),
    )
    order = models.ForeignKey(OrderInfo, related_name='skus',on_delete=models.CASCADE, verbose_name="订单")
    sku = models.ForeignKey(SKU, on_delete=models.PROTECT,verbose_name="订单商品")
    count = models.IntegerField(default=1, verbose_name="数量")
    price = models.DecimalField(max_digits=10, decimal_places=2,verbose_name="单价")
    comment = models.TextField(default="", verbose_name="评价信息")
    score = models.SmallIntegerField(choices=SCORE_CHOICES, default=5,verbose_name='满意度评分')
    is_anonymous = models.BooleanField(default=False,verbose_name='是否匿名评价')
    is_commented = models.BooleanField(default=False,verbose_name='是否评价了')

    class Meta:
        db_table = "tb_order_goods"
        verbose_name = '订单商品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.sku.name

对上面的模型生成迁移文件,并执行迁移文件。

第5步:定义路由,goods应用下urls.py配置路由。

python 复制代码
from django.urls import path

from goods import views

app_name = 'goods'
urlpatterns = [
    path('list/<int:category_id>/<int:page_num>/', views.ListView.as_view(), name='list'),
    path('hot/<int:category_id>/', views.HostGoodsView.as_view()),
    path('detail/<int:sku_id>/', views.DetailView.as_view(), name='detail'),
]

根路由中增加

python 复制代码
path('', include('goods.urls')),

第6步:查询到的商品列表展示在list.html模板中

html 复制代码
{#<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">#}
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>小鱼商城-商品列表</title>
    <link rel="stylesheet" type="text/css" href="{{ static('css/jquery.pagination.css') }}">
    <link rel="stylesheet" type="text/css" href="{{ static('css/reset.css') }}">
    <link rel="stylesheet" type="text/css" href="{{ static('css/main.css') }}">
    <script type="text/javascript" src="{{ static('js/jquery-1.12.4.min.js') }}"></script>
    <script type="text/javascript" src="{{ static('js/vue-2.5.16.js') }}"></script>
    <script type="text/javascript" src="{{ static('js/axios-0.18.0.min.js') }}"></script>
</head>
<body>
<div id="app">
    <div class="header_con">
        <div class="header" v-cloak>
            <div class="welcome fl">欢迎来到小鱼商城!</div>
            <div class="fr">
                <div v-if="username" class="login_btn fl">
                    欢迎您:<em>[[ username ]]</em>
                    <span>|</span>
                    <a href="{{ url('users:logout') }}">退出</a>
                </div>
                <div v-else class="login_btn fl">
                    <a href="{{ url('users:login') }}">登录</a>
                    <span>|</span>
                    <a href="{{ url('users:register') }}">注册</a>
                </div>
                <div class="user_link fl">
                    <span>|</span>
                    <a href="{{ url('users:info') }}">用户中心</a>
                    <span>|</span>
                    {#                    <a href="{{ url('carts:info') }}">我的购物车</a>#}
                    <span>|</span>
                    {#                    <a href="{{ url('users:myorderinfo',args=(1,)) }}">我的订单</a>#}
                </div>
            </div>
        </div>
    </div>
    <div class="search_bar clearfix">
        <a href="{{ url('contents:index') }}" class="logo fl"><img src="{{ static('images/logo.png') }}"></a>
        <div class="search_wrap fl">
            <form method="get" action="/search/" class="search_con">
                <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
                <input type="submit" class="input_btn fr" name="" value="搜索">
            </form>
            <ul class="search_suggest fl">
                <li><a href="#">索尼微单</a></li>
                <li><a href="#">优惠15元</a></li>
                <li><a href="#">美妆个护</a></li>
                <li><a href="#">买2免1</a></li>
            </ul>
        </div>
        <div @mouseenter="get_carts" class="guest_cart fr" v-cloak>
            {#            <a href="{{ url('carts:info') }}" class="cart_name fl">我的购物车</a>#}
            <div class="goods_count fl" id="show_count">[[ cart_total_count ]]</div>
            <ul class="cart_goods_show">
                <li v-for="sku in carts">
                    <img :src="sku.default_image_url" alt="商品图片">
                    <h4>[[ sku.name ]]</h4>
                    <div>[[ sku.count ]]</div>
                </li>
            </ul>
        </div>
    </div>
    <div class="navbar_con">
        <div class="navbar">
            <div class="sub_menu_con fl">
                <h1 class="fl">商品分类</h1>
                <ul class="sub_menu">
                    {% for group in categories.values() %}
                        <li>
                            <div class="level1">
                                {% for channel in group.channels %}
                                    <a href="{{ channel.url }}">{{ channel.name }}</a>
                                {% endfor %}
                            </div>
                            <div class="level2">
                                {% for cat2 in group.sub_cats %}
                                    <div class="list_group">
                                        <div class="group_name fl">{{ cat2.name }} &gt;</div>
                                        <div class="group_detail fl">
                                            {% for cat3 in cat2.sub_cats %}
                                                <a href="/list/{{ cat3.id }}/1/">{{ cat3.name }}</a>
                                            {% endfor %}
                                        </div>
                                    </div>
                                {% endfor %}
                            </div>
                        </li>
                    {% endfor %}
                </ul>
            </div>

            <ul class="navlist fl">
                <li><a href="">首页</a></li>
                <li class="interval">|</li>
                <li><a href="">真划算</a></li>
                <li class="interval">|</li>
                <li><a href="">抽奖</a></li>
            </ul>
        </div>
    </div>
    <div class="breadcrumb">
        <a href="javascript:;">{{ breadcrumb.cat1.name }}</a>
        <span>></span>
        <a href="javascript:;">{{ breadcrumb.cat2.name }}</a>
        <span>></span>
        <a href="javascript:;">{{ breadcrumb.cat3.name }}</a>
    </div>


    <div class="main_wrap clearfix">
        <div class="l_wrap fl clearfix">
            <div class="new_goods">
                <h3>热销排行</h3>
                <ul>
                    <li v-for="sku in hot_skus">
{#                        <a :href="sku.url"><img :src="sku.default_image_url"></a>#}
                        <a :href="sku.url"><img :src="sku.default_image_url"></a>
                        <h4><a :href="sku.url">[[ sku.name ]]</a></h4>
                        <div class="price">¥[[ sku.price ]]</div>
                    </li>
                </ul>

            </div>
        </div>
        <div class="r_wrap fr clearfix">
            <div class="sort_bar">
                <a href="{{ url('goods:list',args=(category_id,1)) }}?sort=default"
                   {% if sort=='default' %}class="active" {% endif %}>默认</a>
                <a href="{{ url('goods:list',args=(category_id,1)) }}?sort=price"
                   {% if sort=='price' %}class="active" {% endif %}>价格</a>
                <a href="{{ url('goods:list',args=(category_id,1)) }}?sort=hot" {% if sort=='hot' %} class="active" {%
                   endif %}>人气</a>
            </div>
            <ul class="goods_type_list clearfix">
                {% for sku in page_skus %}
                    <li>
                        <a href="{{ url('goods:detail',args=(sku.id,)) }}">
                            <img src="/static/images/goods/{{ sku.default_image }}.jpg"></a>
                        <h4><a href="{{ url('goods:detail',args=(sku.id,)) }}">
                            {{ sku.name }}</a></h4>
                        <div class="operate">
                            <span class="price">¥{{ sku.price }}</span>
                            <span class="unit">{{ sku.review_num }}条评价</span>
                            <a href="#" class="add_goods" title="加入购物车"></a>
                        </div>
                    </li>
                {% endfor %}
            </ul>
            {# 前端分页器插件内容 #}
            <div class="pagenation">
                <div id="pagination" class="page"></div>
            </div>
        </div>
    </div>
    <div class="footer">
        <div class="foot_link">
            <a href="#">关于我们</a>
            <span>|</span>
            <a href="#">联系我们</a>
            <span>|</span>
            <a href="#">招聘人才</a>
            <span>|</span>
            <a href="#">友情链接</a>
        </div>
        <p>CopyRight © 2024 北京小鱼商业股份有限公司 All Rights Reserved</p>
        <p>电话:010-****888 京ICP备*******8号</p>
    </div>
</div>
<script type="text/javascript">
    let category_id = "{{ category_id }}";
</script>
<script type="text/javascript" src="{{ static('js/common.js') }}"></script>
<script type="text/javascript" src="{{ static('js/list.js') }}"></script>
<script type="text/javascript" src="{{ static('js/jquery.pagination.min.js') }}"></script>
<script>
    $(function () {
        $('#pagination').pagination({
            currentPage: {{ page_num }},
            totalPage: {{ total_page }},
            callback: function (current) {
                location.href = '/list/{{ category_id }}/' + current + '/?sort={{ sort }}';
            }
        })
    });
</script>
</body>
</html>

第7步:商品详情页面

html 复制代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>小鱼商城-商品详情</title>
    <link rel="stylesheet" type="text/css" href="{{ static('css/reset.css') }}">
    <link rel="stylesheet" type="text/css" href="{{ static('css/main.css') }}">
    <script type="text/javascript" src="{{ static('js/vue-2.5.16.js') }}"></script>
    <script type="text/javascript" src="{{ static('js/axios-0.18.0.min.js') }}"></script>
</head>
<body>
<div id="app">
    <div class="header_con">
        <div class="header" v-cloak>
            <div class="welcome fl">欢迎来到小鱼商城!</div>
            <div class="fr">
                <div v-if="username" class="login_btn fl">
                    欢迎您:<em>[[ username ]]</em>
                    <span>|</span>
                    <a href="{{ url('users:logout') }}">退出</a>
                </div>
                <div v-else class="login_btn fl">
                    <a href="{{ url('users:login') }}">登录</a>
                    <span>|</span>
                    <a href="{{ url('users:register') }}">注册</a>
                </div>
                <div class="user_link fl">
                    <span>|</span>
                    <a href="{{ url('users:info') }}">用户中心</a>
                    <span>|</span>
                    {#                    <a href="{{ url('carts:info') }}">我的购物车</a>#}
                    <span>|</span>
                    {#                    <a href="{{ url('users:myorderinfo',args=(1,)) }}">我的订单</a>#}
                </div>
            </div>
        </div>
    </div>
    <div class="search_bar clearfix">
        <a href="{{ url('contents:index') }}" class="logo fl"><img src="{{ static('images/logo.png') }}"></a>
        <div class="search_wrap fl">
            <form method="get" action="/search/" class="search_con">
                <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
                <input type="submit" class="input_btn fr" name="" value="搜索">
            </form>
            <ul class="search_suggest fl">
                <li><a href="#">索尼微单</a></li>
                <li><a href="#">优惠15元</a></li>
                <li><a href="#">美妆个护</a></li>
                <li><a href="#">买2免1</a></li>
            </ul>
        </div>
        <div @mouseenter="get_carts" class="guest_cart fr" v-cloak>
            {#            <a href="{{ url('carts:info') }}" class="cart_name fl">我的购物车</a>#}
            <div class="goods_count fl" id="show_count">[[ cart_total_count ]]</div>
            <ul class="cart_goods_show">
                <li v-for="sku in carts">
                    <img :src="sku.default_image_url" alt="商品图片">
                    <h4>[[ sku.name ]]</h4>
                    <div>[[ sku.count ]]</div>
                </li>
            </ul>
        </div>
    </div>
    <div class="navbar_con">
        <div class="navbar">
            <div class="sub_menu_con fl">
                <h1 class="fl">商品分类</h1>
                <ul class="sub_menu">
                    {% for group in categories.values() %}
                        <li>
                            <div class="level1">
                                {% for channel in group.channels %}
                                    <a href="{{ channel.url }}">{{ channel.name }}</a>
                                {% endfor %}
                            </div>
                            <div class="level2">
                                {% for cat2 in group.sub_cats %}
                                    <div class="list_group">
                                        <div class="group_name fl">{{ cat2.name }} &gt;</div>
                                        <div class="group_detail fl">
                                            {% for cat3 in cat2.sub_cats %}
                                                <a href="/list/{{ cat3.id }}/1/">{{ cat3.name }}</a>
                                            {% endfor %}
                                        </div>
                                    </div>
                                {% endfor %}
                            </div>
                        </li>
                    {% endfor %}
                </ul>
            </div>
            <ul class="navlist fl">
                <li><a href="">首页</a></li>
                <li class="interval">|</li>
                <li><a href="">真划算</a></li>
                <li class="interval">|</li>
                <li><a href="">抽奖</a></li>
            </ul>
        </div>
    </div>
    <div class="breadcrumb">
        <a href="javascript:;">{{ breadcrumb.cat1.name }}</a>
        <span>></span>
        <a href="javascript:;">{{ breadcrumb.cat2.name }}</a>
        <span>></span>
        <a href="javascript:;">{{ breadcrumb.cat3.name }}</a>
    </div>
    <div class="goods_detail_con clearfix">
        <div class="goods_detail_pic fl"><img src="/static/images/goods/{{ sku.default_image }}.jpg"></div>
        <div class="goods_detail_list fr">
            <h3>{{ sku.name }}</h3>
            <p>{{ sku.caption }}</p>
            <div class="price_bar">
                <span class="show_pirce">¥<em>{{ sku.price }}</em></span>
                <a href="javascript:;" class="goods_judge" v-cloak>[[ comments.length ]]人评价</a>
            </div>
            <div class="goods_num clearfix">
                <div class="num_name fl">数 量:</div>
                <div class="num_add fl">
                    <input v-model="sku_count" @blur="check_sku_count" type="text" class="num_show fl">
                    <a @click="on_addition" class="add fr">+</a>
                    <a @click="on_minus" class="minus fr">-</a>
                </div>
            </div>
            {% for spec in specs %}
                <div class="type_select">
                    <label>{{ spec.name }}:</label>
                    {% for option in spec.spec_options %}
                        {% if option.sku_id == sku.id %}
                            <a href="javascript:;" class="select">{{ option.value }}</a>
                        {% elif option.sku_id %}
                            <a href="{{ url('goods:detail', args=(option.sku_id, )) }}">{{ option.value }}</a>
                        {% else %}
                            <a href="javascript:;">{{ option.value }}</a>
                        {% endif %}
                    {% endfor %}
                </div>
            {% endfor %}
            <div class="total" v-cloak>总价:<em>[[ sku_amount ]]元</em></div>
            <div class="operate_btn">
                <a @click="add_carts" class="add_cart" id="add_cart">加入购物车</a>
            </div>
        </div>
    </div>
    <div class="main_wrap clearfix">
        <div class="l_wrap fl clearfix">
            <div class="new_goods">
                <h3>热销排行</h3>
                <ul>
                    <li v-for="sku in hot_skus">
                        <a :href="sku.url"><img :src="sku.default_image_url"></a>
                        <h4><a :href="sku.url">[[ sku.name ]]</a></h4>
                        <div class="price">¥[[ sku.price ]]</div>
                    </li>
                </ul>
            </div>
        </div>
        <div class="r_wrap fr clearfix">
            <ul class="detail_tab clearfix">
                <li @click="on_tab_content('detail')" :class="tab_content.detail?'active':''">商品详情</li>
                <li @click="on_tab_content('pack')" :class="tab_content.pack?'active':''">规格与包装</li>
                <li @click="on_tab_content('service')" :class="tab_content.service?'active':''">售后服务</li>
                <li @click="on_tab_content('comment')" :class="tab_content.comment?'active':''">商品评价([[
                    comments.length ]])
                </li>
            </ul>
            <div @click="on_tab_content('detail')" class="tab_content" :class="tab_content.detail?'current':''">
                <dl>
                    <dt>商品详情:</dt>
                    <dd>{{ sku.spu.desc_detail|safe }}</dd>
                </dl>
            </div>
            <div @click="on_tab_content('pack')" class="tab_content" :class="tab_content.pack?'current':''">
                <dl>
                    <dt>规格与包装:</dt>
                    <dd>{{ sku.spu.desc_pack|safe }}</dd>
                </dl>
            </div>
            <div @click="on_tab_content('service')" class="tab_content" :class="tab_content.service?'current':''">
                <dl>
                    <dt>售后服务:</dt>
                    <dd>{{ sku.spu.desc_service|safe }}</dd>
                </dl>
            </div>
            {# 商品评价内容#}
            <div @click="on_tab_content('comment')" class="tab_content" :class="tab_content.comment?'current':''">
                <ul class="judge_list_con">
                    <li class="judge_list fl" v-for="comment in comments">
                        <div class="user_info fl">
                            <b>[[comment.username]]</b>
                        </div>
                        <div class="judge_info fl">
                            <div :class="comment.score_class"></div>
                            <div class="judge_detail">[[comment.comment]]</div>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <div class="footer">
        <div class="foot_link">
            <a href="#">关于我们</a>
            <span>|</span>
            <a href="#">联系我们</a>
            <span>|</span>
            <a href="#">招聘人才</a>
            <span>|</span>
            <a href="#">友情链接</a>
        </div>
        <p>CopyRight © 2024 北京小鱼商业股份有限公司 All Rights Reserved</p>
        <p>电话:010-****888 京ICP备*******8号</p>
    </div>
</div>
<script type="text/javascript">
    let category_id = "{{ sku.category.id }}";
    let sku_price = "{{ sku.price }}";
    let sku_id = "{{ sku.id }}";
    let stock = "{{ stock }}"
</script>
<script type="text/javascript" src="{{ static('js/common.js') }}"></script>
<script type="text/javascript" src="{{ static('js/detail.js') }}"></script>
</body>
</html>
相关推荐
struggle20257 分钟前
torchmd-net开源程序是训练神经网络潜力
c++·人工智能·python·深度学习·神经网络
软件开发技术深度爱好者18 分钟前
python中学物理实验模拟:凸透镜成像和凹透镜成像
开发语言·python
PHP武器库34 分钟前
想学编程,java,python,php先学哪个比较好?
java·python·php
鱼鱼说测试1 小时前
jmeter工具简单认识
开发语言·python
网小鱼的学习笔记1 小时前
flask静态资源与模板页面、模板用户登录案例
后端·python·flask
aiweker2 小时前
python web开发-Flask数据库集成
前端·python·flask
deephub2 小时前
机器学习异常检测实战:用Isolation Forest快速构建无标签异常检测系统
人工智能·python·机器学习·异常检测
电院工程师3 小时前
基于机器学习的侧信道分析(MLSCA)Python实现(带测试)
人工智能·python·嵌入式硬件·安全·机器学习·密码学
AndrewHZ3 小时前
【Python与生活】如何实现一个条形码检测算法?
人工智能·pytorch·python·深度学习·算法·生活
19893 小时前
【Dify精讲】第14章:部署架构与DevOps实践
运维·人工智能·python·ai·架构·flask·devops