315 lines
8.8 KiB
JavaScript
315 lines
8.8 KiB
JavaScript
let selectedItems = new Set();
|
||
|
||
// 页面加载完成后初始化
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
updateSelectAllState();
|
||
updateTotalPrice();
|
||
});
|
||
|
||
// 全选/取消全选
|
||
document.getElementById('selectAll').addEventListener('change', function() {
|
||
const checkboxes = document.querySelectorAll('.item-checkbox:not(:disabled)');
|
||
checkboxes.forEach(checkbox => {
|
||
checkbox.checked = this.checked;
|
||
if (this.checked) {
|
||
selectedItems.add(parseInt(checkbox.value));
|
||
} else {
|
||
selectedItems.delete(parseInt(checkbox.value));
|
||
}
|
||
});
|
||
updateTotalPrice();
|
||
});
|
||
|
||
// 单个商品选择
|
||
document.querySelectorAll('.item-checkbox').forEach(checkbox => {
|
||
checkbox.addEventListener('change', function() {
|
||
const cartId = parseInt(this.value);
|
||
if (this.checked) {
|
||
selectedItems.add(cartId);
|
||
} else {
|
||
selectedItems.delete(cartId);
|
||
}
|
||
updateSelectAllState();
|
||
updateTotalPrice();
|
||
});
|
||
});
|
||
|
||
// 更新全选状态
|
||
function updateSelectAllState() {
|
||
const selectAllCheckbox = document.getElementById('selectAll');
|
||
const availableCheckboxes = document.querySelectorAll('.item-checkbox:not(:disabled)');
|
||
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:not(:disabled):checked');
|
||
|
||
if (availableCheckboxes.length === 0) {
|
||
selectAllCheckbox.disabled = true;
|
||
selectAllCheckbox.checked = false;
|
||
} else {
|
||
selectAllCheckbox.disabled = false;
|
||
selectAllCheckbox.checked = availableCheckboxes.length === checkedCheckboxes.length;
|
||
}
|
||
}
|
||
|
||
// 更新总价
|
||
function updateTotalPrice() {
|
||
let totalPrice = 0;
|
||
let selectedCount = 0;
|
||
|
||
selectedItems.forEach(cartId => {
|
||
const cartItem = document.querySelector(`[data-cart-id="${cartId}"]`);
|
||
if (cartItem) {
|
||
const itemTotal = parseFloat(cartItem.querySelector('.item-total').textContent);
|
||
const quantity = parseInt(cartItem.querySelector('.quantity-input').value);
|
||
totalPrice += itemTotal;
|
||
selectedCount += quantity;
|
||
}
|
||
});
|
||
|
||
document.getElementById('selectedCount').textContent = selectedCount;
|
||
document.getElementById('selectedTotal').textContent = totalPrice.toFixed(2);
|
||
document.getElementById('finalTotal').textContent = totalPrice.toFixed(2);
|
||
|
||
// 更新结算按钮状态
|
||
const checkoutBtn = document.getElementById('checkoutBtn');
|
||
checkoutBtn.disabled = selectedItems.size === 0;
|
||
}
|
||
|
||
// 修改数量
|
||
function changeQuantity(cartId, delta) {
|
||
const input = document.querySelector(`[data-cart-id="${cartId}"].quantity-input`);
|
||
if (!input) return;
|
||
|
||
const currentValue = parseInt(input.value);
|
||
const newValue = currentValue + delta;
|
||
|
||
if (newValue >= 1) {
|
||
updateQuantity(cartId, newValue);
|
||
}
|
||
}
|
||
|
||
// 更新数量
|
||
function updateQuantity(cartId, quantity) {
|
||
if (quantity < 1) return;
|
||
|
||
fetch('/cart/update', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
cart_id: cartId,
|
||
quantity: parseInt(quantity)
|
||
})
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 更新页面显示
|
||
const cartItem = document.querySelector(`[data-cart-id="${cartId}"]`);
|
||
const quantityInput = cartItem.querySelector('.quantity-input');
|
||
quantityInput.value = quantity;
|
||
cartItem.querySelector('.item-total').textContent = data.item_total.toFixed(2);
|
||
|
||
// 简单的按钮状态更新
|
||
const minusBtn = cartItem.querySelector('button[onclick*="-1"]');
|
||
const plusBtn = cartItem.querySelector('button[onclick*="1"]');
|
||
|
||
if (minusBtn) {
|
||
minusBtn.disabled = quantity <= 1;
|
||
}
|
||
|
||
// 暂时不限制最大值,避免选择器错误
|
||
if (plusBtn) {
|
||
plusBtn.disabled = false;
|
||
}
|
||
|
||
// 更新总价
|
||
updateTotalPrice();
|
||
|
||
// 更新全局购物车数量
|
||
updateCartBadge(data.cart_count);
|
||
|
||
// 显示成功消息
|
||
showSuccessMessage('数量更新成功');
|
||
} else {
|
||
alert(data.message || '更新失败');
|
||
location.reload();
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('网络错误,请重试');
|
||
location.reload();
|
||
});
|
||
}
|
||
|
||
// 删除商品
|
||
function removeItem(cartId) {
|
||
if (!confirm('确定要删除这件商品吗?')) {
|
||
return;
|
||
}
|
||
|
||
fetch('/cart/remove', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
cart_id: cartId
|
||
})
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// 从页面中移除商品
|
||
const cartItem = document.querySelector(`[data-cart-id="${cartId}"]`);
|
||
cartItem.remove();
|
||
|
||
// 从选中列表中移除
|
||
selectedItems.delete(cartId);
|
||
|
||
// 更新显示
|
||
updateSelectAllState();
|
||
updateTotalPrice();
|
||
updateCartBadge(data.cart_count);
|
||
|
||
showSuccessMessage('商品已删除');
|
||
|
||
// 如果购物车为空,刷新页面
|
||
if (data.cart_count === 0) {
|
||
setTimeout(() => {
|
||
location.reload();
|
||
}, 1000);
|
||
}
|
||
} else {
|
||
alert(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('删除失败');
|
||
});
|
||
}
|
||
|
||
// 清空购物车
|
||
function clearCart() {
|
||
if (!confirm('确定要清空购物车吗?')) {
|
||
return;
|
||
}
|
||
|
||
fetch('/cart/clear', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
showSuccessMessage('购物车已清空');
|
||
setTimeout(() => {
|
||
location.reload();
|
||
}, 1000);
|
||
} else {
|
||
alert(data.message);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Error:', error);
|
||
alert('清空失败');
|
||
});
|
||
}
|
||
|
||
// 去结算
|
||
function checkout() {
|
||
if (selectedItems.size === 0) {
|
||
alert('请选择要购买的商品');
|
||
return;
|
||
}
|
||
|
||
const params = new URLSearchParams();
|
||
selectedItems.forEach(cartId => {
|
||
params.append('items', cartId);
|
||
});
|
||
|
||
window.location.href = `/cart/checkout?${params.toString()}`;
|
||
}
|
||
|
||
// 显示成功消息
|
||
function showSuccessMessage(message) {
|
||
const alert = document.createElement('div');
|
||
alert.className = 'alert alert-success alert-dismissible fade show position-fixed';
|
||
alert.style.cssText = 'top: 20px; right: 20px; z-index: 1050; min-width: 300px;';
|
||
alert.innerHTML = `
|
||
${message}
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
`;
|
||
|
||
document.body.appendChild(alert);
|
||
|
||
setTimeout(() => {
|
||
if (alert.parentNode) {
|
||
alert.remove();
|
||
}
|
||
}, 3000);
|
||
}
|
||
|
||
// 更新购物车徽章
|
||
// 验证数量输入
|
||
function validateQuantityInput(input) {
|
||
// 只允许数字
|
||
input.value = input.value.replace(/[^0-9]/g, "");
|
||
|
||
// 如果为空或0,显示1
|
||
if (input.value === "" || parseInt(input.value) < 1) {
|
||
input.value = "1";
|
||
}
|
||
|
||
// 检查最大值
|
||
const maxStock = parseInt(input.getAttribute("max")) || 999;
|
||
if (parseInt(input.value) > maxStock) {
|
||
input.value = maxStock.toString();
|
||
}
|
||
}
|
||
|
||
// 从输入框更新数量
|
||
function updateQuantityFromInput(cartId, input) {
|
||
let quantity = parseInt(input.value);
|
||
|
||
// 验证输入
|
||
if (isNaN(quantity) || quantity < 1) {
|
||
quantity = 1;
|
||
input.value = "1";
|
||
}
|
||
|
||
const maxStock = parseInt(input.getAttribute("max")) || 999;
|
||
if (quantity > maxStock) {
|
||
quantity = maxStock;
|
||
input.value = maxStock.toString();
|
||
}
|
||
|
||
// 更新数量
|
||
updateQuantity(cartId, quantity);
|
||
}
|
||
|
||
// 处理键盘事件
|
||
function handleQuantityKeyPress(event, cartId, input) {
|
||
// 回车键确认
|
||
if (event.key === "Enter") {
|
||
input.blur();
|
||
return;
|
||
}
|
||
|
||
// 只允许数字键
|
||
if (!/[0-9]/.test(event.key) && !["Backspace", "Delete", "Tab", "Escape", "Enter", "Home", "End", "ArrowLeft", "ArrowRight"].includes(event.key)) {
|
||
event.preventDefault();
|
||
}
|
||
}
|
||
|
||
function updateCartBadge(count) {
|
||
const badge = document.querySelector('.cart-badge');
|
||
if (badge) {
|
||
badge.textContent = count;
|
||
badge.style.display = count > 0 ? 'inline' : 'none';
|
||
}
|
||
}
|