document.addEventListener("DOMContentLoaded", function () {
// 판매자별 테이블 접기
const container = document.getElementById('tables-container');
if (!container) return;
const tables = Array.from(container.querySelectorAll('.order_content'));
if (tables.length === 0) return;
const vendorGroups = {};
tables.forEach((table) => {
const vendorElement = table.querySelector('.vendor-name');
const vendor = vendorElement ? vendorElement.innerText.trim() : null;
if (!vendor) return;
if (!vendorGroups[vendor]) {
vendorGroups[vendor] = [];
}
vendorGroups[vendor].push(table);
});
container.innerHTML = '';
Object.entries(vendorGroups).forEach(([vendor, vendorTables]) => {
const section = document.createElement('div');
section.className = 'vendor-section';
const header = document.createElement('div');
header.className = 'vendor-header';
const titleSpan = document.createElement('span');
titleSpan.className = 'vendor-title';
titleSpan.innerText = vendor;
const iconSpan = document.createElement('span');
iconSpan.className = 'vendor-toggle-icon';
iconSpan.innerText = '▼';
header.appendChild(titleSpan);
header.appendChild(iconSpan);
const group = document.createElement('div');
group.className = 'vendor-group';
vendorTables.forEach((table, i) => {
if (i !== 0) {
table.style.display = 'none';
}
group.appendChild(table);
});
header.addEventListener('click', () => {
const isOpen = header.classList.toggle('open');
iconSpan.innerText = isOpen ? '▲' : '▼';
const allTablesInGroup = group.querySelectorAll('.order_content');
allTablesInGroup.forEach((t, i) => {
if (i === 0) return;
t.style.display = isOpen ? 'table' : 'none';
});
});
section.appendChild(header);
section.appendChild(group);
container.appendChild(section);
});
기능 설명
tables-container내 모든.order_content테이블을 판매자(.vendor-name)별로 그룹화- 각 판매자 그룹을
<div class="vendor-section">로 묶고,
<div class="vendor-header">요소에는 판매자명(.vendor-title)과 토글 아이콘(.vendor-toggle-icon)을 추가- 초기 렌더링 시 그룹 내 두 번째 테이블부터
display: none처리하여 접힌 상태로 표시- 판매자 헤더 클릭 시
header.classList.toggle('open')으로 열림 상태 토글- 아이콘(
▼ ↔ ▲) 변경- 그룹 내 나머지
.order_content테이블들을display: table↔display: none으로 토글
// 각 상품 계산
document.querySelectorAll('.order_content').forEach(table => {
const row = table.querySelector('tr:nth-of-type(2)');
if (!row) return;
const originalEl = row.querySelector('.price_original');
const saleEl = row.querySelector('.price_total');
const discountEl = row.querySelector('.discount-rate');
const quantityEl = row.querySelector('.quantity');
const quantity = parseInt(quantityEl?.innerText || '1', 10);
const originalUnit = parseInt(originalEl?.dataset.unit || '0', 10);
const discountRate = parseFloat((discountEl?.innerText || '0').replace('%', '')) || 0;
if (!isNaN(discountRate) && originalUnit > 0 && quantity > 0) {
const original = originalUnit * quantity;
originalEl.innerText = original.toLocaleString();
const discountedUnitPrice = originalUnit * (1 - discountRate / 100);
const flooredDiscountedUnitPrice = Math.floor(discountedUnitPrice);
const sale = flooredDiscountedUnitPrice * quantity;
saleEl.dataset.unit = sale;
saleEl.innerText = sale.toLocaleString();
const pointEl = row.querySelector('input.point');
const discountedPriceForPoint = parseInt(saleEl?.dataset.unit || '0', 10);
if (!isNaN(discountedPriceForPoint) && quantity > 0 && pointEl) {
const userRank = pointEl.dataset.rank;
let pointRate = 0;
switch (userRank) {
case 'VVIP':
pointRate = 0.05;
break;
case 'VIP':
pointRate = 0.04;
break;
case 'GOLD':
pointRate = 0.03;
break;
case 'SILVER':
pointRate = 0.02;
break;
case 'FAMILY':
pointRate = 0.01;
break;
default:
pointRate = 0;
break;
}
const point = Math.floor(discountedPriceForPoint * pointRate);
pointEl.value = point.toString();
}
}
});
기능 설명
두 번째
<tr>(상품 정보 행) 선택const row = table.querySelector('tr:nth-of-type(2)');수량 파싱
<td class="quantity">텍스트에서 숫자로 파싱 (quantity)원가 단가 파싱
row.querySelector('.price_original').dataset.unit에서originalUnit추출할인율 파싱
<td class="discount-rate">텍스트에서%제거 후 숫자로 파싱 (discountRate)원가 합계 계산
const original = originalUnit * quantity; originalEl.innerText = original.toLocaleString();할인 단가 계산
const discountedUnitPrice = originalUnit * (1 - discountRate / 100); const flooredDiscountedUnitPrice = Math.floor(discountedUnitPrice); const sale = flooredDiscountedUnitPrice * quantity; saleEl.dataset.unit = sale; saleEl.innerText = sale.toLocaleString();포인트 적립 계산
input.point.dataset.rank에서userRank읽어옴
switch문으로 등급별 적립률 설정
VVIP: 5%VIP: 4%GOLD: 3%SILVER: 2%FAMILY: 1%- 그 외: 0%
const point = Math.floor(discountedPriceForPoint × pointRate)계산 후
pointEl.value = point.toString()
// 전체 포인트 요약 업데이트
let totalEarnedPoint = 0;
document.querySelectorAll('.point').forEach(pointEl => {
const pointValue = pointEl?.value.replace(/[^\d]/g, ''); // value 속성에서 숫자만 추출
console.log('pointValue:', pointValue); // 추출된 값 확인
const point = parseInt(pointValue, 10);
if (!isNaN(point)) {
totalEarnedPoint += point;
}
});
document.getElementById('summary-point').innerText = totalEarnedPoint.toLocaleString();
document.querySelector('input[name="totalPoint"]').value = totalEarnedPoint;
기능 설명
모든
<input class="point">요소 순회document.querySelectorAll('.point').forEach(pointEl => { ... });숫자만 추출 및 파싱
const pointValue = pointEl.value.replace(/[^\d]/g, ''); const point = parseInt(pointValue, 10);유효한 숫자인 경우 누적
if (!isNaN(point)) { totalEarnedPoint += point; }DOM 업데이트
#summary-point요소에totalEarnedPoint를 천 단위 콤마로 표시- 히든 필드
input[name="totalPoint"]에 동일한 값을 할당
// 쿠폰 모달 창
const modal = document.getElementById("couponModal");
const showCouponModalButton = document.getElementById("showCouponModalButton");
const closeButton = modal?.querySelector(".close-button");
let selectedCouponBenefit = null;
let previouslySelectedItem = null;
let selectedCouponData = null;
// 모달 열기 버튼 클릭
if (showCouponModalButton && modal) {
showCouponModalButton.onclick = function () {
const vendorElements = document.querySelectorAll(".vendor-name");
const vendorSet = new Set();
vendorElements.forEach(el => vendorSet.add(el.textContent.trim()));
const couponItems = document.querySelectorAll(".coupon-item");
couponItems.forEach(item => {
const issuedBy = item.getAttribute("data-issued-by")?.trim();
const couponState = item.getAttribute("data-state")?.trim();
// 발행자 일치 또는 관리자이고 미사용 상태인 경우만 보이도록
item.style.display = (vendorSet.has(issuedBy) || issuedBy === "관리자") && couponState === "미사용"
? "block"
: "none";
item.classList.remove("selected");
item.style.border = "1px solid #ccc";
item.onclick = function () {
if (previouslySelectedItem) {
previouslySelectedItem.style.border = "1px solid #ccc";
previouslySelectedItem.classList.remove("selected");
}
this.classList.add("selected");
this.style.border = "2px solid red";
selectedCouponBenefit = this.querySelector("p")?.innerText;
previouslySelectedItem = this;
// 선택된 쿠폰 데이터 저장
selectedCouponData = {
issueNo: this.dataset.issueNo,
issuedBy: this.getAttribute("data-issued-by"),
benefit: selectedCouponBenefit
};
};
});
// 모달 열릴 때마다 버튼 이벤트 다시 바인딩
const applyCouponButton = modal.querySelector(".modal-buttons button");
if (applyCouponButton) {
applyCouponButton.onclick = function () {
if (selectedCouponData) {
document.getElementById("couponData").value = selectedCouponData.issueNo;
document.getElementById('summary-coupon-discount').innerText = '-' + selectedCouponData.benefit;
updateOrderSummary();
modal.style.display = "none";
selectedCouponBenefit = null;
previouslySelectedItem = null;
selectedCouponData = null;
} else {
alert("적용할 쿠폰을 선택해주세요.");
}
};
}
modal.style.display = "block";
};
}
// 모달 닫기 (× 버튼)
if (closeButton && modal) {
closeButton.onclick = function () {
modal.style.display = "none";
const couponItems = modal.querySelectorAll(".coupon-item");
couponItems.forEach(item => {
item.classList.remove("selected");
item.style.border = "1px solid #ccc";
});
};
}
// 모달 외부 클릭 시 닫기
window.onclick = function (event) {
if (event.target === modal) {
modal.style.display = "none";
const couponItems = modal.querySelectorAll(".coupon-item");
couponItems.forEach(item => {
item.classList.remove("selected");
item.style.border = "1px solid #ccc";
});
}
};
기능 설명
- 모달 열기 (
#showCouponModalButton클릭)
- 모든
.vendor-name텍스트를vendorSet(판매자 집합)으로 수집- 각
.coupon-item요소를 순회하면서
data-issued-by가vendorSet에 포함되거나 “관리자”인 경우data-state === "미사용"인 경우만 표시- 초기화:
classList.remove("selected"),border: 1px solid #ccc- 쿠폰 클릭 시 (
item.onclick):
- 이전 선택 항목 경계선과
selected클래스 제거- 현재 클릭된 항목에
class="selected",border: 2px solid red적용selectedCouponData = { issueNo, issuedBy, benefit }저장- “할인 혜택 받기” 버튼 클릭 시 (
applyCouponButton.onclick):
selectedCouponData.issueNo를#couponData히든 필드에 할당#summary-coupon-discount에benefit형식으로 표시updateOrderSummary()호출하여 요약 갱신- 모달 숨기기 및 선택 변수 초기화
modal.style.display = "block"으로 모달 표시- 모달 닫기
- × 버튼 클릭 또는 모달 바깥 클릭 시
modal.style.display = "none"- 모든
.coupon-item요소에 대해classList.remove("selected")및border: 1px solid #ccc초기화