2025-07-09 05:33:23 +08:00

402 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% 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 %}