cart
Trang giỏ hàng.
- Tệp giao diện:
cart.html - Đường dẫn:
/gio-hang - Controller:
App\Modules\Cart\CartController::cartPage
Ngoài những biến dưới đây, slot này còn nhận toàn bộ biến toàn cục.
Biến của trang
| Biến | Kiểu | Mô tả | Từ phiên bản |
|---|---|---|---|
cart |
Cart |
Giỏ hàng hiện tại kèm danh sách dòng hàng. | 1.0 |
quote |
CartQuote | null |
Bảng tính tiền từ máy chủ (tạm tính, giảm giá, thuế, tổng). | 1.0 |
Mã đầy đủ
Toàn bộ tệp cart.html của bộ giao diện mặc định. Chép về templates/<bộ giao diện của bạn>/cart.html rồi sửa theo ý muốn.
<div class="container page-content">
<h1 class="page-title">Giỏ hàng</h1>
{% if cart.items.size > 0 %}
<div class="cart-layout">
<div class="cart-items">
{% for item in cart.items %}
{% assign q = item.quote %}
<div class="cart-item" data-variant-id="{{ item.variant_id }}"
x-data="{ loading: false, qty: {{ item.quantity }} }">
{% if item.cover_image_url %}
<img src="{{ item.cover_image_url }}" alt="{{ item.product_title }}" class="cart-item__img">
{% endif %}
<div class="cart-item__info">
{% if item.product_url %}
<a href="{{ item.product_url }}" class="cart-item__name">{{ item.product_title }}</a>
{% else %}
<span class="cart-item__name">{{ item.product_title }}</span>
{% endif %}
{% if item.variant_title %}<p class="cart-item__variant">{{ item.variant_title }}</p>{% endif %}
{% if q %}
<p class="cart-item__price">
<span class="price-final">{{ q.final_unit_price | money }}</span>
{% if q.base_price != q.final_unit_price %}
<span class="price-strike"><s>{{ q.base_price | money }}</s></span>
{% endif %}
</p>
{% if q.applied_product_discounts.size > 0 %}
<ul class="cart-item__discounts">
{% for pd in q.applied_product_discounts %}
{% if pd.discount_type == 'buy_x_get_y' %}
<li class="line-discount-row line-discount-row--bogo">🎁 {{ pd.promotion_title }} (mua kèm tặng kèm) (-{{ pd.amount | money }})</li>
{% else %}
<li class="line-discount-row">Ưu đãi sản phẩm: {{ pd.promotion_title }} (-{{ pd.amount | money }})</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if q.margin_floor_clamped %}
<p class="cart-item__floor-note"><small>Đã áp giá tối thiểu</small></p>
{% endif %}
{% else %}
<p class="cart-item__price">{{ item.unit_price | money }}</p>
{% endif %}
</div>
<div class="cart-item__qty">
<button class="qty-btn" :disabled="loading || qty <= 1"
@click="loading = true; xStore.cart.addItem({ variant_id: {{ item.variant_id }}, quantity: Math.max(1, qty - 1) }).then(function() { qty = Math.max(1, qty - 1); window.location.reload(); }).finally(function() { loading = false; })">−</button>
<span class="cart-qty-val" x-text="qty"></span>
<button class="qty-btn" :disabled="loading || qty >= 99"
@click="loading = true; xStore.cart.addItem({ variant_id: {{ item.variant_id }}, quantity: qty + 1 }).then(function() { qty = Math.min(99, qty + 1); window.location.reload(); }).finally(function() { loading = false; })">+</button>
</div>
<div class="cart-item__subtotal">
{% if q %}{{ q.line_total | money }}{% else %}{{ item.line_total | money }}{% endif %}
</div>
<button class="cart-item__remove" :disabled="loading" aria-label="Xóa"
@click="loading = true; xStore.cart.removeItem({{ item.variant_id | json | escape }}).finally(function() { window.location.reload(); })">✕</button>
</div>
{% endfor %}
</div>
<div class="cart-summary">
{% if quote %}
<div class="cart-summary__row">
<span>Tạm tính</span><span>{{ quote.subtotal | money }}</span>
</div>
{% if quote.total_loyalty_discount > 0 %}
<div class="cart-summary__row cart-summary__row--discount">
<span>Ưu đãi thành viên{% if quote.customer_group_title %} ({{ quote.customer_group_title }}){% endif %}</span>
<span>-{{ quote.total_loyalty_discount | money }}</span>
</div>
{% endif %}
{% for d in quote.cart_discounts %}
{% if d.discount_type == 'free_shipping' %}
<div class="cart-summary__row cart-summary__row--free-shipping">
<span>🚚 {{ d.promotion_title }}</span>
<span>Miễn phí vận chuyển</span>
</div>
{% else %}
<div class="cart-summary__row cart-summary__row--discount">
<span>{{ d.promotion_title }}</span>
<span>-{{ d.amount | money }}</span>
</div>
{% endif %}
{% endfor %}
{% if quote.has_free_shipping %}
<div class="cart-free-shipping-banner">
🚚 Đơn hàng của bạn được miễn phí vận chuyển
</div>
{% endif %}
{% if quote.prices_include_tax %}
<div class="cart-summary__row cart-summary__row--total">
<span>Tổng cộng (đã bao gồm thuế)</span>
<span>{{ quote.total_with_tax | money }}</span>
</div>
{% if quote.tax_lines.size > 0 %}
<div class="cart-summary__row cart-summary__row--tax-note">
<small>
Đã bao gồm
{% for tl in quote.tax_lines %}
{{ tl.name }}: {{ tl.amount | money }}{% unless forloop.last %}, {% endunless %}
{% endfor %}
</small>
</div>
{% endif %}
{% else %}
<div class="cart-summary__row">
<span>Tổng trước thuế</span>
<span>{{ quote.total | money }}</span>
</div>
{% for tl in quote.tax_lines %}
<div class="cart-summary__row cart-summary__row--tax">
<span>{{ tl.name }}</span>
<span>{{ tl.amount | money }}</span>
</div>
{% endfor %}
<div class="cart-summary__row cart-summary__row--total">
<span>Tổng cộng</span>
<span>{{ quote.total_with_tax | money }}</span>
</div>
{% endif %}
{% else %}
{# Fallback when backend engine is unreachable — show local unit_price snapshots. #}
<div class="cart-summary__row">
<span>Tạm tính</span><span>{{ cart.total_amount | money }}</span>
</div>
<div class="cart-summary__row cart-summary__row--total">
<span>Tổng cộng</span><span>{{ cart.total_amount | money }}</span>
</div>
{% endif %}
<p class="cart-summary__note">Phí vận chuyển tính khi thanh toán</p>
<a href="/thanh-toan" class="btn btn--primary btn--block btn--lg">Tiến hành thanh toán</a>
<a href="/san-pham" class="btn btn--outline btn--block">Tiếp tục mua sắm</a>
</div>
</div>
{% else %}
<div class="empty-state">
<p>Giỏ hàng của bạn đang trống.</p>
<a href="/san-pham" class="btn btn--primary">Mua sắm ngay</a>
</div>
{% endif %}
</div>