superlishunqin 170db69eb4 version_1
2025-07-14 05:06:05 +08:00

297 lines
15 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 %}订单结算 - 太白购物商城{% endblock %}
{% block head %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/checkout.css') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
{% endblock %}
{% block content %}
<div class="container">
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{{ url_for('main.index') }}">首页</a></li>
<li class="breadcrumb-item"><a href="{{ url_for('cart.index') }}">购物车</a></li>
<li class="breadcrumb-item active">订单结算</li>
</ol>
</nav>
<div class="row">
<div class="col-lg-8">
<!-- 收货地址 -->
<div class="card checkout-section">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="bi bi-geo-alt-fill"></i> 收货地址</h5>
<a href="{{ url_for('address.add') }}" class="btn add-address-btn">
<i class="bi bi-plus-circle"></i> 新增地址
</a>
</div>
<div class="card-body">
<div class="address-container" id="addressList">
{% for address in addresses %}
<div class="address-card {% if address.is_default %}selected{% endif %}"
data-address-id="{{ address.id }}" onclick="selectAddress({{ address.id }})">
<div class="address-card-body">
<div class="address-header">
<div class="address-receiver">
<h6 class="receiver-name">
<i class="bi bi-person-fill"></i>
{{ address.receiver_name }}
</h6>
<p class="receiver-phone">
<i class="bi bi-telephone-fill"></i>
{{ address.receiver_phone }}
</p>
</div>
<div class="custom-radio">
<input type="radio" name="address_id" value="{{ address.id }}"
{% if address.is_default %}checked{% endif %}>
<span class="radio-mark"></span>
</div>
</div>
<div class="address-content">
<p class="address-text">
<i class="bi bi-geo-alt"></i>
{{ address.get_full_address() }}
</p>
</div>
<div class="address-footer">
{% if address.is_default %}
<span class="default-badge">
<i class="bi bi-star-fill"></i>
默认地址
</span>
{% else %}
<span></span>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% if not addresses %}
<div class="col-12">
<div class="text-center py-4">
<i class="bi bi-geo-alt text-muted" style="font-size: 3rem;"></i>
<h5 class="text-muted mt-3">暂无收货地址</h5>
<p class="text-muted">请先添加收货地址,然后继续下单</p>
<a href="{{ url_for('address.add') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> 立即添加
</a>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<!-- 商品信息 -->
<div class="card checkout-section">
<div class="card-header">
<h5><i class="bi bi-box-seam"></i> 商品信息</h5>
</div>
<div class="card-body">
{% for item in cart_items %}
<div class="product-item">
<div class="row align-items-center">
<div class="col-md-2">
<img src="{{ item.product.main_image or '/static/images/default-product.jpg' }}"
class="img-fluid rounded" alt="{{ item.product.name }}">
</div>
<div class="col-md-6">
<h6>{{ item.product.name }}</h6>
{% if item.spec_combination %}
<p class="text-muted mb-0">{{ item.spec_combination }}</p>
{% endif %}
{% if item.product.brand %}
<small class="text-muted">{{ item.product.brand }}</small>
{% endif %}
</div>
<div class="col-md-2 text-center">
<span class="text-muted">× {{ item.quantity }}</span>
</div>
<div class="col-md-2 text-end">
<span class="fw-bold">¥{{ "%.2f"|format(item.get_total_price()) }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<!-- 配送方式 -->
<div class="card checkout-section">
<div class="card-header">
<h5><i class="bi bi-truck"></i> 配送方式</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="shipping_method"
value="standard" id="shipping_standard" checked onchange="updateShippingFee()">
<label class="form-check-label" for="shipping_standard">
<strong>标准配送</strong><br>
<small class="text-muted">免费 • 3-5个工作日</small>
</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="shipping_method"
value="express" id="shipping_express" onchange="updateShippingFee()">
<label class="form-check-label" for="shipping_express">
<strong>次日达</strong><br>
<small class="text-muted">+10元 • 次日送达</small>
</label>
</div>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="radio" name="shipping_method"
value="same_day" id="shipping_same_day" onchange="updateShippingFee()">
<label class="form-check-label" for="shipping_same_day">
<strong>当日达</strong><br>
<small class="text-muted">+20元 • 当日送达</small>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- 支付方式 -->
<div class="card checkout-section">
<div class="card-header">
<h5><i class="bi bi-credit-card"></i> 支付方式</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method"
value="wechat" id="payment_wechat" checked>
<label class="form-check-label" for="payment_wechat">
<i class="bi bi-wechat text-success me-2"></i>
<strong>微信支付</strong>
</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method"
value="alipay" id="payment_alipay">
<label class="form-check-label" for="payment_alipay">
<i class="bi bi-alipay text-primary me-2"></i>
<strong>支付宝</strong>
</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method"
value="bank" id="payment_bank">
<label class="form-check-label" for="payment_bank">
<i class="bi bi-credit-card text-info me-2"></i>
<strong>银行卡</strong>
</label>
</div>
</div>
<div class="col-md-3">
<div class="form-check">
<input class="form-check-input" type="radio" name="payment_method"
value="simulate" id="payment_simulate">
<label class="form-check-label" for="payment_simulate">
<i class="bi bi-gear-fill text-warning me-2"></i>
<strong>模拟支付</strong>
<br><small class="text-muted">测试模式</small>
</label>
</div>
</div>
</div>
<!-- 模拟支付说明 -->
<div class="alert alert-warning mt-3" id="simulatePaymentNotice" style="display: none;">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>模拟支付模式</strong><br>
这是开发测试功能,选择此支付方式后可以直接模拟支付成功或失败,无需真实付款。
实际生产环境中,此选项将被移除。
</div>
</div>
</div>
<!-- 备注 -->
<div class="card checkout-section">
<div class="card-header">
<h5><i class="bi bi-chat-text"></i> 订单备注</h5>
</div>
<div class="card-body">
<textarea class="form-control" id="orderRemark" rows="3"
placeholder="如有特殊需求请在此说明(选填)"></textarea>
</div>
</div>
</div>
<!-- 订单摘要 -->
<div class="col-lg-4">
<div class="card position-sticky" style="top: 20px;">
<div class="card-header">
<h5><i class="bi bi-receipt"></i> 订单摘要</h5>
</div>
<div class="card-body">
<div class="order-summary">
<div class="price-row">
<span>商品总价:</span>
<span id="subtotal">¥{{ "%.2f"|format(total_amount) }}</span>
</div>
<div class="price-row">
<span>运费:</span>
<span id="shippingFee">¥{{ "%.2f"|format(shipping_fee) }}</span>
</div>
<hr>
<div class="price-row total-price">
<span>应付总额:</span>
<span id="totalAmount">¥{{ "%.2f"|format(final_amount) }}</span>
</div>
</div>
<button class="btn btn-danger w-100 mt-3 btn-lg" onclick="submitOrder()">
<i class="bi bi-check-circle"></i> 提交订单
</button>
<div class="mt-3 text-center">
<small class="text-muted">
点击"提交订单"表示您同意
<a href="#" class="text-decoration-none">《用户协议》</a>
</small>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/checkout.js') }}"></script>
<script>
// 监听支付方式变化,显示/隐藏模拟支付说明
document.addEventListener('DOMContentLoaded', function() {
const paymentMethods = document.querySelectorAll('input[name="payment_method"]');
const simulateNotice = document.getElementById('simulatePaymentNotice');
paymentMethods.forEach(method => {
method.addEventListener('change', function() {
if (this.value === 'simulate') {
simulateNotice.style.display = 'block';
} else {
simulateNotice.style.display = 'none';
}
});
});
});
</script>
{% endblock %}