document.addEventListener("DOMContentLoaded", function () {
// 주문 버튼 클릭 시 체크된 상품 없으면 경고
const orderForm = document.getElementById('order-form');
const orderButton = document.getElementById('order-button');
orderButton.addEventListener('click', function (e) {
const checkedItems = orderForm.querySelectorAll('input[name="cartNo"]:checked');
if (checkedItems.length === 0) {
e.preventDefault(); // 폼 제출 막기
alert('주문할 상품을 선택해주세요.');
}
});
// … 이하 생략
});
기능 설명
DOMContentLoaded이벤트 내에서 초기화orderButton클릭 시
orderForm.querySelectorAll('input[name="cartNo"]:checked')로 선택된 체크박스 개수 검사- 한 개도 선택되지 않았다면
preventDefault()로 폼 제출을 막고 경고 메시지 표시
// 수량 +, - 버튼 및 체크박스들
const plusBtns = document.querySelectorAll('.btn-plus');
const minusBtns = document.querySelectorAll('.btn-minus');
const checkAll = document.querySelector('#check-all');
const itemCheckboxes = document.querySelectorAll('.cart_content input[type="checkbox"]');
// 요약 정보 업데이트 함수
function updateSummary() {
let totalCount = 0;
let originalTotalAmount = 0;
let discountTotal = 0;
let actualPayAmount = 0;
const uniqueVendors = new Set();
const deliveryFeePerVendor = 2500;
const freeShippingLimit = 1000000;
// 체크된 각 상품에 대해 계산
itemCheckboxes.forEach((cb) => {
if (cb.checked) {
const cartContent = cb.closest('.cart_content');
const quantity = parseInt(cartContent.querySelector('.quantity').textContent);
const priceOriginalEl = cartContent.querySelector('.price_original');
const priceTotalEl = cartContent.querySelector('.price_total');
const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
const unitTotal = parseInt(priceTotalEl.dataset.unit);
const itemDiscount = (unitOriginal - unitTotal) * quantity;
const itemOriginalPrice = unitOriginal * quantity;
const itemTotalPrice = unitTotal * quantity;
const vendorNameEl = cartContent.querySelector('.vendor-name');
if (vendorNameEl) {
uniqueVendors.add(vendorNameEl.textContent.trim());
}
totalCount += quantity;
originalTotalAmount += itemOriginalPrice;
discountTotal += itemDiscount;
actualPayAmount += itemTotalPrice;
}
});
const orderAmount = originalTotalAmount - discountTotal;
// 판매자별 최대 배송비 계산
const vendorDeliveryMap = new Map();
itemCheckboxes.forEach((cb) => {
if (cb.checked) {
const cartContent = cb.closest('.cart_content');
const deliveryFeeEl = cartContent.querySelector('.price_delivery');
const vendorNameEl = cartContent.querySelector('.vendor-name');
const vendor = vendorNameEl ? vendorNameEl.textContent.trim() : '';
const rawDeliveryFee = deliveryFeeEl?.dataset.deliveryFee;
const deliveryFee = parseInt(rawDeliveryFee || '0');
if (vendor) {
const currentMax = vendorDeliveryMap.get(vendor) || 0;
if (!isNaN(deliveryFee)) {
vendorDeliveryMap.set(vendor, Math.max(currentMax, deliveryFee));
} else {
vendorDeliveryMap.set(vendor, Math.max(currentMax, 0));
}
}
}
});
// 배송비 최종 합계
let shippingCost = 0;
vendorDeliveryMap.forEach((fee) => {
if (fee > 0) {
shippingCost += deliveryFeePerVendor;
}
});
if (totalCount === 0 || orderAmount >= freeShippingLimit) {
shippingCost = 0;
}
const finalTotal = orderAmount + shippingCost;
const shippingText =
totalCount === 0 ? '0'
: orderAmount >= freeShippingLimit ? '무료'
: shippingCost.toLocaleString() + '원';
// 요약 DOM 업데이트
document.getElementById('summary-count').textContent = totalCount;
const checkAllLabel = document.querySelector('label[for="check-all"]');
if (checkAllLabel) {
checkAllLabel.textContent = `전체선택(${totalCount})`;
}
document.getElementById('summary-amount').textContent = originalTotalAmount.toLocaleString();
document.getElementById('summary-discount').textContent = '-' + discountTotal.toLocaleString();
document.getElementById('summary-shipping').textContent = shippingText;
document.getElementById('summary-total').textContent = finalTotal.toLocaleString() + '원';
}
기능 설명
- 체크된 상품을 순회하면서
- 수량(
.quantity), 원가 단가(.price_original.dataset.unit), 할인 단가(.price_total.dataset.unit)를 파싱itemDiscount = (원가 단가 − 할인 단가) × 수량itemOriginalPrice = 원가 단가 × 수량itemTotalPrice = 할인 단가 × 수량- 각 값을 누적하여
totalCount(총 수량)originalTotalAmount(상품 원가 합계)discountTotal(총 할인 금액)actualPayAmount(총 결제 금액, 실제로는 사용되지 않지만 계산해 둠)uniqueVendors에 판매자명 추가(배송비 계산 시 중복 방지용)orderAmount = originalTotalAmount − discountTotal- 판매자별 최대 배송비(
vendorDeliveryMap) 계산
- 각 체크된 상품의
data-delivery-fee값을 파싱- 판매자별로 최대 배송비만 보관(
Math.max)- 최종 배송비(
shippingCost) 계산
- 배송비가 0보다 큰 판매자마다
deliveryFeePerVendor(2,500원) 추가- 주문 수량이 0이거나
orderAmount ≥ freeShippingLimit(1,000,000원)인 경우 배송비 0 처리finalTotal = orderAmount + shippingCost- 텍스트로 표시할
shippingText
totalCount === 0→'0'orderAmount ≥ freeShippingLimit→'무료'- 그 외 →
shippingCost를 천 단위 콤마로 표시 후'원'붙임- 다음 DOM 요소들에 값 할당
#summary-count←totalCountlabel[for="check-all"]←전체선택(totalCount)#summary-amount←originalTotalAmount(천 단위 콤마)#summary-discount←"-discountTotal"(천 단위 콤마)#summary-shipping←shippingText#summary-total←finalTotal원(천 단위 콤마 +'원')
// 수량 조절 버튼
plusBtns.forEach((btn) => {
btn.addEventListener('click', () => {
const cartContent = btn.closest('.cart_content');
const quantityEl = cartContent.querySelector('.quantity');
let count = parseInt(quantityEl.textContent);
count++;
quantityEl.textContent = count;
const priceOriginalEl = cartContent.querySelector('.price_original');
const priceTotalEl = cartContent.querySelector('.price_total');
const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
const unitTotal = parseInt(priceTotalEl.dataset.unit);
priceOriginalEl.textContent = (unitOriginal * count).toLocaleString() + '원';
priceTotalEl.textContent = (unitTotal * count).toLocaleString() + '원';
const cartNoInput = cartContent.querySelector('input[name="cartNo"]');
const cartNoValue = cartNoInput.value;
updateCartProductCount(cartNoValue, count);
updateSummary();
});
});
minusBtns.forEach((btn) => {
btn.addEventListener('click', () => {
const cartContent = btn.closest('.cart_content');
const quantityEl = cartContent.querySelector('.quantity');
let count = parseInt(quantityEl.textContent);
if (count > 1) {
count--;
quantityEl.textContent = count;
const priceOriginalEl = cartContent.querySelector('.price_original');
const priceTotalEl = cartContent.querySelector('.price_total');
const unitOriginal = parseInt(priceOriginalEl.dataset.unit);
const unitTotal = parseInt(priceTotalEl.dataset.unit);
priceOriginalEl.textContent = (unitOriginal * count).toLocaleString() + '원';
priceTotalEl.textContent = (unitTotal * count).toLocaleString() + '원';
const cartNoInput = cartContent.querySelector('input[name="cartNo"]');
const cartNoValue = cartNoInput.value;
updateCartProductCount(cartNoValue, count);
updateSummary();
}
});
});
기능 설명
plusBtns(‘+’ 버튼) 클릭 시
- 해당
.cart_content요소 내의.quantity값을 1 증가원가 합계 = unitOriginal × count계산 후priceOriginalEl.textContent업데이트(#,###원)할인 합계 = unitTotal × count계산 후priceTotalEl.textContent업데이트(#,###원)updateCartProductCount(cartNo, count)호출하여 서버에 수량 변경 요청updateSummary()호출하여 요약 정보 갱신minusBtns(‘-’ 버튼) 클릭 시
count > 1인 경우에만 수량 1 감소- 이후 로직은
plusBtns와 동일하게 가격과 서버, 요약 갱신
// 수량 변경 업데이트
function updateCartProductCount(cartNo, newQuantity) {
const formData = new URLSearchParams();
formData.append("cartNo", cartNo);
formData.append("newQuantity", newQuantity);
fetch('/update/cartProdCount', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData.toString()
})
.then(response => response.json())
.then(data => {
console.log('Cart updated:', data);
})
.catch(error => {
console.error('Error updating cart:', error);
});
}
기능 설명
cartNo와newQuantity를URLSearchParams로 직렬화하여 POST 요청/update/cartProdCount엔드포인트로 전송- 성공 시 콘솔에 결과 출력, 실패 시 에러 로그 출력
// 체크박스 변화 시 요약 업데이트
itemCheckboxes.forEach(cb => cb.addEventListener('change', updateSummary));
// 전체 선택 기능
checkAll.addEventListener('change', function () {
const isChecked = this.checked;
itemCheckboxes.forEach(cb => cb.checked = isChecked);
updateSummary();
});
기능 설명
- 개별
.cart_content input[type="checkbox"]의change이벤트를 구독하여 변경 시updateSummary()호출#check-all체크박스 클릭 시
isChecked상태에 맞춰 모든itemCheckboxes를 체크/해제updateSummary()호출하여 요약 갱신
// 초기화 시 전체 해제 및 요약 초기 계산
itemCheckboxes.forEach(cb => cb.checked = false);
updateSummary();
기능 설명
- 페이지 로드시 모든 상품 체크박스를 해제
- 최초 한 번
updateSummary()호출로 요약 정보를 0으로 초기화