[260210]
- 테이블 모드 추가 - 상품 선택하여 엑셀로 견적 내기 기능 추가. - 데이터는 세션 스토리지에 저장
This commit is contained in:
156
scripts/main.js
156
scripts/main.js
@@ -1,11 +1,12 @@
|
||||
/** 진입점: 이벤트 바인딩·초기 렌더·URL 모달 처리 */
|
||||
import { state, productsData } from './state.js';
|
||||
import { state, productsData, saveSelection } from './state.js';
|
||||
import {
|
||||
applyFilters,
|
||||
renderStatusChips,
|
||||
renderCategoryChips,
|
||||
bindCategoryFilter,
|
||||
} from './filters.js';
|
||||
import { ITEMS_PER_PAGE, STATUS_META } from './config.js';
|
||||
import { renderProducts, changePage } from './productList.js';
|
||||
import { openModal, closeModal } from './modal.js';
|
||||
import { scrollToImage } from './carousel.js';
|
||||
@@ -18,6 +19,58 @@ window.closeModal = closeModal;
|
||||
window.changePage = changePage;
|
||||
window.scrollToImage = scrollToImage;
|
||||
|
||||
// 뷰 전환 이벤트
|
||||
document.getElementById('view-grid').onclick = () => {
|
||||
state.viewMode = 'grid';
|
||||
updateViewButtons();
|
||||
renderProducts(state.currentPage);
|
||||
};
|
||||
|
||||
document.getElementById('view-table').onclick = () => {
|
||||
state.viewMode = 'table';
|
||||
updateViewButtons();
|
||||
renderProducts(state.currentPage);
|
||||
};
|
||||
|
||||
function updateViewButtons() {
|
||||
const isGrid = state.viewMode === 'grid';
|
||||
document.getElementById('view-grid').classList.toggle('bg-white', isGrid);
|
||||
document.getElementById('view-grid').classList.toggle('text-primary', isGrid);
|
||||
document.getElementById('view-table').classList.toggle('bg-white', !isGrid);
|
||||
document.getElementById('view-table').classList.toggle('text-primary', !isGrid);
|
||||
}
|
||||
|
||||
// [전역 함수] 체크박스 토글 및 합계 업데이트
|
||||
window.toggleSelectItem = (id) => {
|
||||
if (state.selectedIds.has(id)) state.selectedIds.delete(id);
|
||||
else state.selectedIds.add(id);
|
||||
|
||||
updateSummary();
|
||||
};
|
||||
|
||||
export function updateSummary() {
|
||||
const summary = document.getElementById('selection-summary');
|
||||
const countEl = document.getElementById('selected-count');
|
||||
const priceEl = document.getElementById('selected-total-price');
|
||||
|
||||
// 테이블 모드이면서 선택된 항목이 있을 때만 노출
|
||||
if (state.viewMode === 'table' && state.selectedIds.size > 0) {
|
||||
summary.classList.remove('hidden');
|
||||
summary.classList.add('flex');
|
||||
|
||||
const total = Array.from(state.selectedIds).reduce((sum, id) => {
|
||||
const p = productsData.find(item => item.id === id);
|
||||
return sum + (p ? p.price : 0);
|
||||
}, 0);
|
||||
|
||||
countEl.textContent = state.selectedIds.size;
|
||||
priceEl.textContent = `₩${total.toLocaleString()}`;
|
||||
} else {
|
||||
summary.classList.add('hidden');
|
||||
summary.classList.remove('flex');
|
||||
}
|
||||
}
|
||||
|
||||
// 검색 입력
|
||||
const searchInput = document.getElementById('search-input');
|
||||
if (searchInput) {
|
||||
@@ -98,3 +151,104 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const newId = Math.random().toString(36).substring(2, 10);
|
||||
console.log(`%c[NUMBER]: ${newId}`, 'color: #137fec; font-weight: bold; border: 1px solid #137fec; padding: 2px 5px; border-radius: 4px;');
|
||||
|
||||
/** 현재 페이지의 '선택 가능한' 항목들만 선택/해제 */
|
||||
window.toggleSelectAll = (isChecked) => {
|
||||
const startIndex = (state.currentPage - 1) * ITEMS_PER_PAGE;
|
||||
const currentPageProducts = state.visibleProducts.slice(startIndex, startIndex + ITEMS_PER_PAGE);
|
||||
|
||||
currentPageProducts.forEach(p => {
|
||||
const isSelectable = STATUS_META[p.status]?.selectable !== false;
|
||||
if (isSelectable) {
|
||||
if (isChecked) state.selectedIds.add(p.id);
|
||||
else state.selectedIds.delete(p.id);
|
||||
}
|
||||
});
|
||||
|
||||
saveSelection(); // 변경사항 저장
|
||||
updateSummary();
|
||||
renderProducts(state.currentPage);
|
||||
};
|
||||
|
||||
/** 선택 리셋 */
|
||||
window.resetSelection = () => {
|
||||
if (!confirm("선택된 내역을 모두 초기화할까요?")) return;
|
||||
state.selectedIds.clear();
|
||||
saveSelection(); // 스토리지 동기화
|
||||
updateSummary();
|
||||
renderProducts(state.currentPage);
|
||||
};
|
||||
|
||||
/** 선택 토글 시 스토리지 저장 추가 */
|
||||
window.toggleSelectItem = (id) => {
|
||||
const product = productsData.find(p => p.id === id);
|
||||
if (!product || STATUS_META[product.status]?.selectable === false) return;
|
||||
|
||||
if (state.selectedIds.has(id)) state.selectedIds.delete(id);
|
||||
else state.selectedIds.add(id);
|
||||
|
||||
saveSelection(); // 변경사항 저장
|
||||
updateSummary();
|
||||
};
|
||||
|
||||
/** 선택된 항목들을 CSV 파일로 내보내기 */
|
||||
window.exportToExcel = () => {
|
||||
if (state.selectedIds.size === 0) {
|
||||
alert("내보낼 상품을 선택해 주세요.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 선택된 데이터 추출 및 계산
|
||||
let totalCount = 0;
|
||||
let totalPrice = 0;
|
||||
|
||||
const rows = Array.from(state.selectedIds).map(id => {
|
||||
const p = productsData.find(item => item.id === id);
|
||||
if (p) {
|
||||
totalCount += 1;
|
||||
totalPrice += p.price;
|
||||
return [
|
||||
p.id,
|
||||
`"${p.title.replace(/"/g, '""')}"`,
|
||||
p.category,
|
||||
p.price,
|
||||
p.status,
|
||||
`"${p.description.replace(/"/g, '""')}"`
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}).filter(row => row !== null);
|
||||
|
||||
// 2. 헤더 및 푸터(합계) 설정
|
||||
const headers = ["상품 ID", "상품명", "카테고리", "가격", "상태", "상세설명"];
|
||||
|
||||
// 영수증 느낌을 위한 하단 합계 줄
|
||||
const footerEmpty = ["", "", "", "", "", ""]; // 빈 줄
|
||||
const footerTotal = [
|
||||
"TOTAL",
|
||||
`"총 ${totalCount}건의 항목"`,
|
||||
"",
|
||||
totalPrice,
|
||||
"",
|
||||
`"발행일: ${new Date().toLocaleString()}"`
|
||||
];
|
||||
|
||||
// 3. CSV 포맷 생성 (한글 깨짐 방지 BOM 추가)
|
||||
const csvContent = "\uFEFF" + [
|
||||
headers.join(","),
|
||||
...rows.map(row => row.join(",")),
|
||||
footerEmpty.join(","), // 간격 조절용 빈 줄
|
||||
footerTotal.join(",") // 합계 라인
|
||||
].join("\n");
|
||||
|
||||
// 4. 다운로드 실행
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
|
||||
const timestamp = new Date().toISOString().split('T')[0];
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", `inventory_receipt_${timestamp}.csv`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
Reference in New Issue
Block a user