This commit is contained in:
sjk
2025-11-28 15:18:10 +08:00
parent ad4a600af9
commit 5683f35942
188 changed files with 53680 additions and 1062 deletions

419
web/assets/js/cart.js Normal file
View File

@@ -0,0 +1,419 @@
// Cart Page JavaScript - 使用真实API
console.log('=== cart.js 已加载 ===');
$(document).ready(function() {
console.log('=== cart.js $(document).ready ===');
initCartPage();
});
function initCartPage() {
console.log('=== initCartPage 开始 ===');
loadCartItems();
loadRecommendations();
bindCartEvents();
console.log('=== initCartPage 完成 ===');
// 监听语言切换
$(document).on('languageChanged', function() {
loadCartItems();
loadRecommendations();
});
}
// 加载购物车商品 - 从API获取
function loadCartItems() {
// 调用后端API获取购物车数据
API.get('/cart')
.then(data => {
console.log('购物车数据:', data);
const cartItems = data.items || [];
if (cartItems.length === 0) {
$('#cartContent').hide();
$('#cartEmpty').show();
updateCartCount(0);
return;
}
$('#cartEmpty').hide();
$('#cartContent').show();
renderCartItems(cartItems);
updateCartCount(data.total_quantity || cartItems.reduce((sum, item) => sum + item.quantity, 0));
})
.catch(error => {
console.error('加载购物车失败:', error);
Toast.error(error.message || '加载购物车失败');
$('#cartContent').hide();
$('#cartEmpty').show();
});
}
// 渲染购物车商品列表
function renderCartItems(cartItems) {
const lang = i18n.currentLang;
// 生成购物车表格HTML
let cartHtml = `
<table class="cart-table">
<thead>
<tr>
<th><input type="checkbox" id="selectAll" ${isAllSelected(cartItems) ? 'checked' : ''}></th>
<th>${i18n.t('product')}</th>
<th>${i18n.t('price')}</th>
<th>${i18n.t('quantity')}</th>
<th>${i18n.t('total')}</th>
</tr>
</thead>
<tbody>
`;
// 添加商品行
cartItems.forEach(item => {
const product = item.product || {};
const sku = item.sku || {};
const itemName = product.name || '未知商品';
const itemImage = product.main_image || product.image || 'https://picsum.photos/200/200?random=default';
// 价格转换:分 → 元
const itemPrice = PriceUtils.fenToYuan(sku.price || product.price || 0);
const itemTotal = PriceUtils.fenToYuan((sku.price || product.price || 0) * item.quantity);
// 规格信息
let specsHtml = '';
if (sku.spec_values && Object.keys(sku.spec_values).length > 0) {
specsHtml = '<div class="cart-product-specs">';
for (const [key, value] of Object.entries(sku.spec_values)) {
specsHtml += `<span class="spec-tag">${key}: ${value}</span>`;
}
specsHtml += '</div>';
}
cartHtml += `
<tr data-cart-id="${item.id}" data-product-id="${item.product_id}" data-sku-id="${item.sku_id || 0}">
<td>
<input type="checkbox" class="item-checkbox" data-cart-id="${item.id}" ${item.selected ? 'checked' : ''}>
</td>
<td data-label="${i18n.t('product')}">
<div class="cart-product">
<div class="cart-product-image">
<img src="${itemImage}" alt="${itemName}">
</div>
<div class="cart-product-info">
<div class="cart-product-name">
<a href="product-detail.html?id=${item.product_id}">${itemName}</a>
</div>
${specsHtml}
<button class="cart-product-remove" data-cart-id="${item.id}" data-product-id="${item.product_id}" data-sku-id="${item.sku_id || 0}">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
${i18n.t('remove')}
</button>
</div>
</div>
</td>
<td data-label="${i18n.t('price')}" class="cart-price">
¥${itemPrice.toFixed(2)}
</td>
<td data-label="${i18n.t('quantity')}" class="cart-quantity">
<div class="quantity-selector">
<button class="qty-btn minus" data-product-id="${item.product_id}" data-sku-id="${item.sku_id || 0}">-</button>
<input type="number" class="qty-input" value="${item.quantity}" min="1" max="99" data-product-id="${item.product_id}" data-sku-id="${item.sku_id || 0}">
<button class="qty-btn plus" data-product-id="${item.product_id}" data-sku-id="${item.sku_id || 0}">+</button>
</div>
</td>
<td data-label="${i18n.t('total')}" class="cart-total-price">
¥${itemTotal.toFixed(2)}
</td>
</tr>
`;
});
// 计算已选商品的小计和总计
const selectedItems = cartItems.filter(item => item.selected);
const subtotal = calculateSubtotal(selectedItems);
const total = subtotal; // 暂不计算折扣
cartHtml += `
</tbody>
</table>
<div class="cart-summary">
<h3>${i18n.t('cart_totals')}</h3>
<div class="summary-row">
<span>${i18n.t('subtotal')}</span>
<span class="price" id="subtotalAmount">¥${PriceUtils.fenToYuan(subtotal).toFixed(2)}</span>
</div>
<div class="summary-row">
<span>${i18n.t('shipping')}</span>
<span class="price" id="shippingAmount">${i18n.t('free')}</span>
</div>
<div class="summary-row total">
<span>${i18n.t('total')}</span>
<span class="price" id="totalAmount">¥${PriceUtils.fenToYuan(total).toFixed(2)}</span>
</div>
<div class="shipping-notice">
${i18n.t('free_shipping_notice')}
</div>
<button class="btn btn-primary btn-checkout" id="checkoutBtn" ${selectedItems.length === 0 ? 'disabled' : ''}>
${i18n.t('proceed_to_checkout')}
</button>
</div>
`;
$('#cartContent').html(cartHtml);
}
// 判断是否全选
function isAllSelected(cartItems) {
return cartItems.length > 0 && cartItems.every(item => item.selected);
}
// 计算小计(已选商品)
function calculateSubtotal(selectedItems) {
return selectedItems.reduce((sum, item) => {
const price = (item.sku && item.sku.price) || (item.product && item.product.price) || 0;
return sum + (price * item.quantity);
}, 0);
}
// 加载推荐商品
function loadRecommendations() {
// 调用商品列表API获取推荐商品
API.get('/products/list', { page: 1, size: 4 })
.then(data => {
const products = data.products || data.list || [];
renderRecommendations(products.slice(0, 4));
})
.catch(error => {
console.error('加载推荐商品失败:', error);
// 失败时不显示推荐区域
$('.recommendations-section').hide();
});
}
// 渲染推荐商品
function renderRecommendations(products) {
const lang = i18n.currentLang;
let recommendationsHtml = '';
products.forEach(product => {
const productName = product.name || '商品名称';
const category = product.category_name || '商品分类';
const currentPrice = PriceUtils.fenToYuan(product.price || 0);
const originalPrice = product.original_price ? PriceUtils.fenToYuan(product.original_price) : null;
const mainImage = product.main_image || product.image || 'https://picsum.photos/400/400?random=default';
recommendationsHtml += `
<div class="recommendation-card">
<div class="recommendation-image">
<img src="${mainImage}" alt="${productName}">
${product.stock > 0 ? '' : '<span class="recommendation-badge">售罄</span>'}
</div>
<div class="recommendation-info">
<div class="recommendation-category">${category}</div>
<div class="recommendation-name">${productName}</div>
<div class="recommendation-price">
<span class="price-current">¥${currentPrice.toFixed(2)}</span>
${originalPrice ? `<span class="price-original">¥${originalPrice.toFixed(2)}</span>` : ''}
</div>
<button class="recommendation-add-btn" data-product-id="${product.id}" ${product.stock <= 0 ? 'disabled' : ''}>
${product.stock > 0 ? i18n.t('add_to_cart') : '已售罄'}
</button>
</div>
</div>
`;
});
$('#recommendationsGrid').html(recommendationsHtml);
}
// 绑定购物车事件
function bindCartEvents() {
console.log('=== 绑定购物车事件 ===');
// 全选/取消全选
$(document).off('change', '#selectAll').on('change', '#selectAll', function() {
const selected = $(this).is(':checked');
selectAllItems(selected);
});
// 单个商品选择
$(document).off('change', '.item-checkbox').on('change', '.item-checkbox', function() {
const cartId = $(this).data('cart-id');
const selected = $(this).is(':checked');
selectCartItem(cartId, selected);
});
// 数量增加
$(document).off('click', '.qty-btn.plus').on('click', '.qty-btn.plus', function() {
console.log('点击了+按钮');
const productId = $(this).data('product-id');
const skuId = $(this).data('sku-id');
const $input = $(this).siblings('.qty-input');
const currentQty = parseInt($input.val());
console.log('+ 按钮参数:', { productId, skuId, currentQty });
updateQuantity(productId, skuId, currentQty + 1);
});
// 数量减少
$(document).off('click', '.qty-btn.minus').on('click', '.qty-btn.minus', function() {
console.log('点击了-按钮');
const productId = $(this).data('product-id');
const skuId = $(this).data('sku-id');
const $input = $(this).siblings('.qty-input');
const currentQty = parseInt($input.val());
console.log('- 按钮参数:', { productId, skuId, currentQty });
if (currentQty > 1) {
updateQuantity(productId, skuId, currentQty - 1);
}
});
// 数量输入框变化
$(document).off('change', '.qty-input').on('change', '.qty-input', function() {
console.log('输入框数量变化');
const productId = $(this).data('product-id');
const skuId = $(this).data('sku-id');
let newQuantity = parseInt($(this).val());
console.log('输入框参数:', { productId, skuId, newQuantity });
if (isNaN(newQuantity) || newQuantity < 1) {
newQuantity = 1;
} else if (newQuantity > 99) {
newQuantity = 99;
}
$(this).val(newQuantity);
updateQuantity(productId, skuId, newQuantity);
});
// 移除商品
$(document).off('click', '.cart-product-remove').on('click', '.cart-product-remove', function() {
const productId = $(this).data('product-id');
const skuId = $(this).data('sku-id');
removeItem(productId, skuId);
});
// 结算按钮
$(document).off('click', '#checkoutBtn').on('click', '#checkoutBtn', function() {
if (!$(this).prop('disabled')) {
window.location.href = 'checkout.html';
}
});
// 添加推荐商品
$(document).off('click', '.recommendation-add-btn').on('click', '.recommendation-add-btn', function() {
const productId = $(this).data('product-id');
if (!$(this).prop('disabled')) {
addRecommendedProduct(productId);
}
});
}
// 全选/取消全选
function selectAllItems(selected) {
API.put('/cart/select-all', { selected: selected })
.then(() => {
loadCartItems();
})
.catch(error => {
Toast.error(error.message || '操作失败');
// 恢复选中状态
$('#selectAll').prop('checked', !selected);
});
}
// 选择/取消选择单个商品
function selectCartItem(cartId, selected) {
API.put(`/cart/${cartId}/select`, { selected: selected })
.then(() => {
loadCartItems();
})
.catch(error => {
Toast.error(error.message || '操作失败');
// 恢复选中状态
$(`.item-checkbox[data-cart-id="${cartId}"]`).prop('checked', !selected);
});
}
// 更新商品数量
function updateQuantity(productId, skuId, quantity) {
console.log('updateQuantity 参数:', { productId, skuId, quantity });
if (!productId) {
console.error('productId 不能为空');
Toast.error('商品ID不能为空');
return;
}
const data = { quantity: quantity };
if (skuId && skuId != 0) {
data.sku_id = parseInt(skuId);
}
const url = `/cart/${productId}`;
console.log('更新购物车请求URL:', url, '数据:', data);
API.put(url, data)
.then(() => {
Toast.success('修改成功');
loadCartItems();
})
.catch(error => {
console.error('更新购物车失败:', error);
Toast.error(error.message || '修改数量失败');
loadCartItems(); // 刷新以恢复原数量
});
}
// 移除商品
function removeItem(productId, skuId) {
Toast.confirm({
title: '确认删除',
message: '确定要从购物车中删除该商品吗?',
confirmText: '确定',
cancelText: '取消'
}).then(confirmed => {
if (confirmed) {
let url = `/cart/${productId}`;
if (skuId && skuId != 0) {
url += `?sku_id=${skuId}`;
}
API.delete(url)
.then(() => {
Toast.success('已删除');
loadCartItems();
})
.catch(error => {
Toast.error(error.message || '删除失败');
});
}
});
}
// 添加推荐商品到购物车
function addRecommendedProduct(productId) {
API.post('/cart', {
product_id: parseInt(productId),
quantity: 1
})
.then(() => {
Toast.success(i18n.t('product_added_to_cart') || '已添加到购物车');
loadCartItems();
})
.catch(error => {
Toast.error(error.message || '添加失败');
});
}
// 更新购物车数量显示
function updateCartCount(count) {
$('#cartCount').text(count);
$('.cart-count').text(count);
}