402 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			402 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
{% extends "base.html" %}
 | 
						||
 | 
						||
{% block title %}{{ product.name }} - 太白购物商城{% endblock %}
 | 
						||
 | 
						||
{% block head %}
 | 
						||
<link rel="stylesheet" href="{{ url_for('static', filename='css/product_detail.css') }}">
 | 
						||
<link rel="stylesheet" href="{{ url_for('static', filename='css/review.css') }}">
 | 
						||
{% endblock %}
 | 
						||
 | 
						||
{% block content %}
 | 
						||
<div class="container">
 | 
						||
    <!-- 面包屑导航 -->
 | 
						||
    <nav aria-label="breadcrumb" class="mb-3">
 | 
						||
        <ol class="breadcrumb">
 | 
						||
            <li class="breadcrumb-item"><a href="{{ url_for('main.index') }}">首页</a></li>
 | 
						||
            <li class="breadcrumb-item">
 | 
						||
                <a href="{{ url_for('main.product_list', category_id=product.category_id) }}">
 | 
						||
                    {{ product.category.name }}
 | 
						||
                </a>
 | 
						||
            </li>
 | 
						||
            <li class="breadcrumb-item active">{{ product.name }}</li>
 | 
						||
        </ol>
 | 
						||
    </nav>
 | 
						||
 | 
						||
    <div class="row">
 | 
						||
        <!-- 左侧:商品图片 -->
 | 
						||
        <div class="col-md-6">
 | 
						||
            {% if images %}
 | 
						||
            <!-- 主图显示区域 -->
 | 
						||
            <div id="productImageCarousel" class="carousel slide mb-3" data-bs-ride="carousel">
 | 
						||
                <div class="carousel-inner">
 | 
						||
                    {% for image in images %}
 | 
						||
                    <div class="carousel-item {% if loop.first or image.is_main %}active{% endif %}">
 | 
						||
                        <img src="{{ image.image_url }}" class="d-block w-100" alt="{{ product.name }}"
 | 
						||
                             style="height: 400px; object-fit: cover; border-radius: 8px;">
 | 
						||
                    </div>
 | 
						||
                    {% endfor %}
 | 
						||
                </div>
 | 
						||
                {% if images|length > 1 %}
 | 
						||
                <button class="carousel-control-prev" type="button" data-bs-target="#productImageCarousel" data-bs-slide="prev">
 | 
						||
                    <span class="carousel-control-prev-icon"></span>
 | 
						||
                </button>
 | 
						||
                <button class="carousel-control-next" type="button" data-bs-target="#productImageCarousel" data-bs-slide="next">
 | 
						||
                    <span class="carousel-control-next-icon"></span>
 | 
						||
                </button>
 | 
						||
                {% endif %}
 | 
						||
            </div>
 | 
						||
 | 
						||
            <!-- 缩略图 -->
 | 
						||
            {% if images|length > 1 %}
 | 
						||
            <div class="row">
 | 
						||
                {% for image in images %}
 | 
						||
                <div class="col-3 mb-2">
 | 
						||
                    <img src="{{ image.image_url }}" class="img-thumbnail thumbnail-image"
 | 
						||
                         alt="{{ product.name }}" style="height: 80px; object-fit: cover; cursor: pointer;"
 | 
						||
                         onclick="goToSlide({{ loop.index0 }})">
 | 
						||
                </div>
 | 
						||
                {% endfor %}
 | 
						||
            </div>
 | 
						||
            {% endif %}
 | 
						||
            {% else %}
 | 
						||
            <!-- 无图片占位 -->
 | 
						||
            <div class="bg-light d-flex align-items-center justify-content-center"
 | 
						||
                 style="height: 400px; border-radius: 8px;">
 | 
						||
                <i class="bi bi-image text-muted" style="font-size: 5rem;"></i>
 | 
						||
            </div>
 | 
						||
            {% endif %}
 | 
						||
        </div>
 | 
						||
 | 
						||
        <!-- 右侧:商品信息 -->
 | 
						||
        <div class="col-md-6">
 | 
						||
            <h2 class="mb-3">{{ product.name }}</h2>
 | 
						||
 | 
						||
            <!-- 品牌 -->
 | 
						||
            {% if product.brand %}
 | 
						||
            <p class="text-muted mb-2">
 | 
						||
                <strong>品牌:</strong>{{ product.brand }}
 | 
						||
            </p>
 | 
						||
            {% endif %}
 | 
						||
 | 
						||
            <!-- 价格 -->
 | 
						||
            <div class="price-section mb-4">
 | 
						||
                <div class="d-flex align-items-baseline">
 | 
						||
                    <span class="text-danger fw-bold" style="font-size: 2rem;">
 | 
						||
                        ¥<span id="currentPrice">{{ "%.2f"|format(product.price) }}</span>
 | 
						||
                    </span>
 | 
						||
                    {% if product.original_price and product.original_price > product.price %}
 | 
						||
                        <span class="text-muted text-decoration-line-through ms-3" style="font-size: 1.2rem;">
 | 
						||
                            ¥{{ "%.2f"|format(product.original_price) }}
 | 
						||
                        </span>
 | 
						||
                        <span class="badge bg-danger ms-2">
 | 
						||
                            省{{ "%.0f"|format(((product.original_price - product.price) / product.original_price * 100)) }}%
 | 
						||
                        </span>
 | 
						||
                    {% endif %}
 | 
						||
                </div>
 | 
						||
                <div class="mt-2">
 | 
						||
                    <small class="text-muted">销量:{{ product.sales_count }} | 浏览:{{ product.view_count }}</small>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
 | 
						||
            <!-- 商品规格选择 -->
 | 
						||
            {% if inventory_list and inventory_list|length > 1 %}
 | 
						||
            <div class="specs-section mb-4">
 | 
						||
                <h6>选择规格:</h6>
 | 
						||
                <div id="specsContainer">
 | 
						||
                    {% set spec_groups = {} %}
 | 
						||
                    {% for sku in inventory_list %}
 | 
						||
                        {% if sku.spec_combination %}
 | 
						||
                            {% for spec_name, spec_value in sku.spec_combination.items() %}
 | 
						||
                                {% if spec_name not in spec_groups %}
 | 
						||
                                    {% set _ = spec_groups.update({spec_name: []}) %}
 | 
						||
                                {% endif %}
 | 
						||
                                {% if spec_value not in spec_groups[spec_name] %}
 | 
						||
                                    {% set _ = spec_groups[spec_name].append(spec_value) %}
 | 
						||
                                {% endif %}
 | 
						||
                            {% endfor %}
 | 
						||
                        {% endif %}
 | 
						||
                    {% endfor %}
 | 
						||
 | 
						||
                    {% for spec_name, spec_values in spec_groups.items() %}
 | 
						||
                    <div class="spec-group mb-3">
 | 
						||
                        <label class="form-label">{{ spec_name }}:</label>
 | 
						||
                        <div class="spec-options">
 | 
						||
                            {% for spec_value in spec_values %}
 | 
						||
                            <button type="button" class="btn btn-outline-secondary spec-option me-2 mb-2"
 | 
						||
                                    data-spec-name="{{ spec_name }}" data-spec-value="{{ spec_value }}">
 | 
						||
                                {{ spec_value }}
 | 
						||
                            </button>
 | 
						||
                            {% endfor %}
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                    {% endfor %}
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
            {% endif %}
 | 
						||
 | 
						||
            <!-- 库存信息 -->
 | 
						||
            <div class="stock-section mb-4">
 | 
						||
                <div class="row">
 | 
						||
                    <div class="col-6">
 | 
						||
                        <strong>库存:</strong>
 | 
						||
                        <span id="stockCount" class="text-success">
 | 
						||
                            {% if inventory_list %}
 | 
						||
                                {% if inventory_list|length == 1 %}
 | 
						||
                                    {{ inventory_list[0].stock }}
 | 
						||
                                {% else %}
 | 
						||
                                    请选择规格
 | 
						||
                                {% endif %}
 | 
						||
                            {% else %}
 | 
						||
                                暂无库存
 | 
						||
                            {% endif %}
 | 
						||
                        </span>
 | 
						||
                        <span id="stockUnit">件</span>
 | 
						||
                    </div>
 | 
						||
                    {% if product.weight %}
 | 
						||
                    <div class="col-6">
 | 
						||
                        <strong>重量:</strong>{{ product.weight }}kg
 | 
						||
                    </div>
 | 
						||
                    {% endif %}
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
 | 
						||
            <!-- 购买数量 -->
 | 
						||
            <div class="quantity-section mb-4">
 | 
						||
                <label class="form-label"><strong>数量:</strong></label>
 | 
						||
                <div class="input-group" style="width: 150px;">
 | 
						||
                    <button class="btn btn-outline-secondary" type="button" onclick="changeQuantity(-1)">-</button>
 | 
						||
                    <input type="number" class="form-control text-center" id="quantity" value="1" min="1" max="999">
 | 
						||
                    <button class="btn btn-outline-secondary" type="button" onclick="changeQuantity(1)">+</button>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
 | 
						||
            <!-- 操作按钮 -->
 | 
						||
            <div class="action-buttons mb-4">
 | 
						||
                <div class="d-grid gap-2 d-md-flex">
 | 
						||
                    <button type="button" class="btn btn-warning btn-lg flex-fill" id="addToCartBtn"
 | 
						||
                            onclick="addToCart()" {% if not inventory_list %}disabled{% endif %}>
 | 
						||
                        <i class="bi bi-cart-plus"></i> 加入购物车
 | 
						||
                    </button>
 | 
						||
                    <button type="button" class="btn btn-danger btn-lg flex-fill" id="buyNowBtn"
 | 
						||
                            onclick="buyNow()" {% if not inventory_list %}disabled{% endif %}>
 | 
						||
                        <i class="bi bi-lightning-fill"></i> 立即购买
 | 
						||
                    </button>
 | 
						||
                </div>
 | 
						||
                <div class="mt-2">
 | 
						||
                    <button type="button" class="btn btn-outline-secondary" onclick="addToFavorites()">
 | 
						||
                        <i class="bi bi-heart"></i> 收藏商品
 | 
						||
                    </button>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
 | 
						||
            <!-- 服务承诺 -->
 | 
						||
            <div class="service-promises">
 | 
						||
                <h6>服务承诺:</h6>
 | 
						||
                <ul class="list-unstyled">
 | 
						||
                    <li><i class="bi bi-check-circle text-success"></i> 正品保证</li>
 | 
						||
                    <li><i class="bi bi-check-circle text-success"></i> 7天无理由退换</li>
 | 
						||
                    <li><i class="bi bi-check-circle text-success"></i> 全国包邮</li>
 | 
						||
                    <li><i class="bi bi-check-circle text-success"></i> 售后服务</li>
 | 
						||
                </ul>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
 | 
						||
    <!-- 商品详情标签页 -->
 | 
						||
    <div class="row mt-5">
 | 
						||
        <div class="col-12">
 | 
						||
            <ul class="nav nav-tabs" id="productDetailTabs" role="tablist">
 | 
						||
                <li class="nav-item" role="presentation">
 | 
						||
                    <button class="nav-link active" id="description-tab" data-bs-toggle="tab"
 | 
						||
                            data-bs-target="#description" type="button" role="tab">商品详情</button>
 | 
						||
                </li>
 | 
						||
                <li class="nav-item" role="presentation">
 | 
						||
                    <button class="nav-link" id="specs-tab" data-bs-toggle="tab"
 | 
						||
                            data-bs-target="#specs" type="button" role="tab">规格参数</button>
 | 
						||
                </li>
 | 
						||
                <li class="nav-item" role="presentation">
 | 
						||
                    <button class="nav-link" id="reviews-tab" data-bs-toggle="tab"
 | 
						||
                            data-bs-target="#reviews" type="button" role="tab"
 | 
						||
                            onclick="loadProductReviews({{ product.id }})">商品评价</button>
 | 
						||
                </li>
 | 
						||
            </ul>
 | 
						||
 | 
						||
            <div class="tab-content" id="productDetailTabContent">
 | 
						||
                <!-- 商品详情 -->
 | 
						||
                <div class="tab-pane fade show active" id="description" role="tabpanel">
 | 
						||
                    <div class="card">
 | 
						||
                        <div class="card-body">
 | 
						||
                            {% if product.description %}
 | 
						||
                                <div class="product-description">
 | 
						||
                                    {{ product.description|replace('\n', '<br>')|safe }}
 | 
						||
                                </div>
 | 
						||
                            {% else %}
 | 
						||
                                <p class="text-muted">暂无详细描述</p>
 | 
						||
                            {% endif %}
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
 | 
						||
                <!-- 规格参数 -->
 | 
						||
                <div class="tab-pane fade" id="specs" role="tabpanel">
 | 
						||
                    <div class="card">
 | 
						||
                        <div class="card-body">
 | 
						||
                            <table class="table table-striped">
 | 
						||
                                <tbody>
 | 
						||
                                    <tr>
 | 
						||
                                        <td width="150"><strong>商品名称</strong></td>
 | 
						||
                                        <td>{{ product.name }}</td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% if product.brand %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td><strong>商品品牌</strong></td>
 | 
						||
                                        <td>{{ product.brand }}</td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% endif %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td><strong>商品分类</strong></td>
 | 
						||
                                        <td>{{ product.category.name }}</td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% if product.weight %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td><strong>商品重量</strong></td>
 | 
						||
                                        <td>{{ product.weight }}kg</td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% endif %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td><strong>上架时间</strong></td>
 | 
						||
                                        <td>{{ product.created_at.strftime('%Y-%m-%d') }}</td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% if inventory_list %}
 | 
						||
                                    <tr>
 | 
						||
                                        <td><strong>库存信息</strong></td>
 | 
						||
                                        <td>
 | 
						||
                                            {% if inventory_list|length == 1 %}
 | 
						||
                                                {{ inventory_list[0].stock }}件
 | 
						||
                                            {% else %}
 | 
						||
                                                多规格商品,请选择具体规格查看库存
 | 
						||
                                            {% endif %}
 | 
						||
                                        </td>
 | 
						||
                                    </tr>
 | 
						||
                                    {% endif %}
 | 
						||
                                </tbody>
 | 
						||
                            </table>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
 | 
						||
                <!-- 商品评价 -->
 | 
						||
                <div class="tab-pane fade" id="reviews" role="tabpanel">
 | 
						||
                    <div class="card">
 | 
						||
                        <div class="card-body">
 | 
						||
                            <div id="reviewsContainer">
 | 
						||
                                <div class="text-center p-4 text-muted">
 | 
						||
                                    <i class="bi bi-star"></i> 点击标签页加载评价
 | 
						||
                                </div>
 | 
						||
                            </div>
 | 
						||
                        </div>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
 | 
						||
    <!-- 推荐商品 -->
 | 
						||
    {% if recommended_products %}
 | 
						||
    <div class="row mt-5">
 | 
						||
        <div class="col-12">
 | 
						||
            <h4><i class="bi bi-heart-fill text-danger"></i> 相关推荐</h4>
 | 
						||
            <hr>
 | 
						||
        </div>
 | 
						||
        {% for rec_product in recommended_products %}
 | 
						||
        <div class="col-lg-3 col-md-6 mb-4">
 | 
						||
            <div class="card h-100 product-card">
 | 
						||
                <a href="{{ url_for('main.product_detail', product_id=rec_product.id) }}" class="text-decoration-none">
 | 
						||
                    {% if rec_product.main_image %}
 | 
						||
                        <img src="{{ rec_product.main_image }}" class="card-img-top" alt="{{ rec_product.name }}"
 | 
						||
                             style="height: 200px; object-fit: cover;">
 | 
						||
                    {% else %}
 | 
						||
                        <div class="card-img-top bg-light d-flex align-items-center justify-content-center"
 | 
						||
                             style="height: 200px;">
 | 
						||
                            <i class="bi bi-image text-muted" style="font-size: 3rem;"></i>
 | 
						||
                        </div>
 | 
						||
                    {% endif %}
 | 
						||
                </a>
 | 
						||
                <div class="card-body">
 | 
						||
                    <h6 class="card-title">
 | 
						||
                        <a href="{{ url_for('main.product_detail', product_id=rec_product.id) }}"
 | 
						||
                           class="text-decoration-none text-dark">
 | 
						||
                            {{ rec_product.name[:40] }}{% if rec_product.name|length > 40 %}...{% endif %}
 | 
						||
                        </a>
 | 
						||
                    </h6>
 | 
						||
                    <div class="d-flex justify-content-between align-items-center">
 | 
						||
                        <span class="text-danger fw-bold">¥{{ "%.2f"|format(rec_product.price) }}</span>
 | 
						||
                        <small class="text-muted">销量{{ rec_product.sales_count }}</small>
 | 
						||
                    </div>
 | 
						||
                </div>
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
        {% endfor %}
 | 
						||
    </div>
 | 
						||
    {% endif %}
 | 
						||
</div>
 | 
						||
 | 
						||
<!-- 库存数据(用于JavaScript) -->
 | 
						||
<script type="application/json" id="inventoryData">
 | 
						||
{% if inventory_data %}
 | 
						||
{{ inventory_data|tojson }}
 | 
						||
{% else %}
 | 
						||
[]
 | 
						||
{% endif %}
 | 
						||
</script>
 | 
						||
 | 
						||
<script>
 | 
						||
// 设置全局变量供JS使用
 | 
						||
window.productId = {{ product.id }};
 | 
						||
window.currentProductId = {{ product.id }};
 | 
						||
window.isLoggedIn = {% if session.user_id %}true{% else %}false{% endif %};
 | 
						||
</script>
 | 
						||
 | 
						||
<!-- 图片查看模态框 -->
 | 
						||
<div class="modal fade" id="imageModal" tabindex="-1">
 | 
						||
    <div class="modal-dialog modal-lg">
 | 
						||
        <div class="modal-content">
 | 
						||
            <div class="modal-header">
 | 
						||
                <h5 class="modal-title">查看图片</h5>
 | 
						||
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 | 
						||
            </div>
 | 
						||
            <div class="modal-body text-center">
 | 
						||
                <img id="modalImage" src="" class="img-fluid" alt="评价图片">
 | 
						||
            </div>
 | 
						||
        </div>
 | 
						||
    </div>
 | 
						||
</div>
 | 
						||
{% endblock %}
 | 
						||
 | 
						||
{% block scripts %}
 | 
						||
<script src="{{ url_for('static', filename='js/product_detail.js') }}"></script>
 | 
						||
<script src="{{ url_for('static', filename='js/review.js') }}"></script>
 | 
						||
<script>
 | 
						||
// 处理登录状态检查
 | 
						||
{% if not session.user_id %}
 | 
						||
function addToCart() {
 | 
						||
    if (confirm('请先登录后再加入购物车,是否前往登录?')) {
 | 
						||
        window.location.href = '/auth/login?next=' + encodeURIComponent(window.location.pathname);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
function buyNow() {
 | 
						||
    if (confirm('请先登录后再购买,是否前往登录?')) {
 | 
						||
        window.location.href = '/auth/login?next=' + encodeURIComponent(window.location.pathname);
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
function addToFavorites() {
 | 
						||
    if (confirm('请先登录后再收藏,是否前往登录?')) {
 | 
						||
        window.location.href = '/auth/login?next=' + encodeURIComponent(window.location.pathname);
 | 
						||
    }
 | 
						||
}
 | 
						||
{% endif %}
 | 
						||
</script>
 | 
						||
{% endblock %}
 |