261 lines
13 KiB
HTML
261 lines
13 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}订单结算 - 太白购物商城{% endblock %}
|
||
|
||
{% block head %}
|
||
<link rel="stylesheet" href="{{ url_for('static', filename='css/checkout.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"></i> 收货地址</h5>
|
||
<a href="{{ url_for('address.add') }}" class="btn btn-outline-primary btn-sm">
|
||
<i class="bi bi-plus"></i> 新增地址
|
||
</a>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row" id="addressList">
|
||
{% for address in addresses %}
|
||
<div class="col-md-6 mb-3">
|
||
<div class="card address-card {% if address.is_default %}selected{% endif %}"
|
||
data-address-id="{{ address.id }}" onclick="selectAddress({{ address.id }})">
|
||
<div class="card-body">
|
||
<div class="d-flex justify-content-between align-items-start">
|
||
<div>
|
||
<h6 class="mb-1">{{ address.receiver_name }}</h6>
|
||
<p class="text-muted mb-1">{{ address.receiver_phone }}</p>
|
||
<p class="mb-0">{{ address.get_full_address() }}</p>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="address_id"
|
||
value="{{ address.id }}" {% if address.is_default %}checked{% endif %}>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 商品信息 -->
|
||
<div class="card checkout-section">
|
||
<div class="card-header">
|
||
<h5><i class="bi bi-box"></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 %}
|