Files
sam-sales/plan/generate-pptx.js
aweso f6e127dfb8 쿠콘 문의사항 추가
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-12 14:53:23 +09:00

438 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 방화셔터 견적서 PPTX 생성 스크립트
* script.md 기반으로 5장 슬라이드 생성
*/
const PptxGenJS = require('pptxgenjs');
const fs = require('fs');
const path = require('path');
// 색상 정의 (# 없이)
const colors = {
primary: '0d9488', // Teal
secondary: '1e293b', // Slate 800
accent: 'dc2626', // Red
white: 'FFFFFF',
lightGray: 'f1f5f9',
darkGray: '64748b',
tableHeader: '0f766e',
tableAlt: 'f0fdfa'
};
// 프레젠테이션 생성
const pptx = new PptxGenJS();
// 레이아웃 설정 (16:9)
pptx.defineLayout({ name: 'CUSTOM_16x9', width: 10, height: 5.625 });
pptx.layout = 'CUSTOM_16x9';
// 메타데이터 설정
pptx.title = '방화셔터 견적서 프로세스';
pptx.subject = 'AI 기반 견적서 자동화';
pptx.author = 'SAM';
pptx.company = 'SAM';
// ========================================
// 슬라이드 1: 표지
// ========================================
function createCoverSlide() {
const slide = pptx.addSlide();
// 배경
slide.background = { color: colors.secondary };
// 상단 악센트 라인
slide.addShape('rect', {
x: 0, y: 0, w: 10, h: 0.15,
fill: { color: colors.primary }
});
// 회사 로고 영역
slide.addShape('rect', {
x: 0.5, y: 0.5, w: 1.5, h: 0.6,
fill: { color: colors.primary }
});
slide.addText('SAM', {
x: 0.5, y: 0.5, w: 1.5, h: 0.6,
fontSize: 20, bold: true, color: colors.white,
align: 'center', valign: 'middle'
});
// 메인 제목
slide.addText('방화셔터 견적 프로세스', {
x: 0.5, y: 2, w: 9, h: 1,
fontSize: 42, bold: true, color: colors.white,
align: 'center'
});
// 부제목
slide.addText('AI 기반 자동화 워크플로우', {
x: 0.5, y: 3, w: 9, h: 0.6,
fontSize: 22, color: colors.primary,
align: 'center'
});
// 프로젝트 정보
slide.addText('OO빌딩 방화셔터 교체공사', {
x: 0.5, y: 4, w: 9, h: 0.4,
fontSize: 16, color: colors.darkGray,
align: 'center'
});
// 날짜 및 수신처
slide.addText('2024년 10월 24일 | 수신: 건설사 담당자님 귀중', {
x: 0.5, y: 4.8, w: 9, h: 0.3,
fontSize: 12, color: colors.darkGray,
align: 'center'
});
console.log('✅ 슬라이드 1: 표지 생성 완료');
}
// ========================================
// 슬라이드 2: 견적 요약
// ========================================
function createSummarySlide() {
const slide = pptx.addSlide();
// 배경
slide.background = { color: colors.white };
// 상단 바
slide.addShape('rect', {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: colors.secondary }
});
slide.addText('견적 요약', {
x: 0.5, y: 0.2, w: 5, h: 0.5,
fontSize: 24, bold: true, color: colors.white
});
// 총 금액 박스
slide.addShape('rect', {
x: 1, y: 1.5, w: 8, h: 2,
fill: { color: colors.lightGray },
line: { color: colors.primary, width: 2 }
});
slide.addText('총 견적 금액', {
x: 1, y: 1.6, w: 8, h: 0.5,
fontSize: 16, color: colors.darkGray,
align: 'center'
});
slide.addText('일금 이천삼백사십오만원정', {
x: 1, y: 2.1, w: 8, h: 0.8,
fontSize: 32, bold: true, color: colors.secondary,
align: 'center'
});
slide.addText('₩ 23,450,000', {
x: 1, y: 2.8, w: 8, h: 0.5,
fontSize: 20, color: colors.primary,
align: 'center'
});
// 금액 구성
const breakdown = [
['항목', '금액'],
['제품비 (철재 방화셔터)', '₩ 18,700,000'],
['모터비 (600kg x 2)', '₩ 1,300,000'],
['설치비 (5개소)', '₩ 1,500,000'],
['운반비 (경기권)', '₩ 0'],
['특별 할인 (5%)', '- ₩ 1,050,000'],
['합계', '₩ 23,450,000']
];
slide.addTable(breakdown, {
x: 1.5, y: 3.7, w: 7, h: 1.6,
fontSize: 11,
color: colors.secondary,
border: { pt: 0.5, color: colors.darkGray },
fill: { color: colors.white },
colW: [4, 3],
align: 'left',
valign: 'middle'
});
// 부가세 안내
slide.addText('※ 부가세 별도', {
x: 7, y: 5.3, w: 2.5, h: 0.25,
fontSize: 10, color: colors.accent, bold: true
});
console.log('✅ 슬라이드 2: 견적 요약 생성 완료');
}
// ========================================
// 슬라이드 3: 세부 내역
// ========================================
function createDetailSlide() {
const slide = pptx.addSlide();
// 배경
slide.background = { color: colors.white };
// 상단 바
slide.addShape('rect', {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: colors.secondary }
});
slide.addText('세부 내역', {
x: 0.5, y: 0.2, w: 5, h: 0.5,
fontSize: 24, bold: true, color: colors.white
});
// 제품 정보 테이블
const productTable = [
['No', '제품명', '규격 (WxH)', '수량', '단가', '모터 사양', '금액', '비고'],
['1', '철재 방화셔터', '3.0m x 2.5m', '2', '85,000/㎡', '600kg', '12,750,000', '내화성적서 포함'],
['2', '철재 방화셔터', '2.5m x 3.0m', '2', '85,000/㎡', '600kg', '12,750,000', '내화성적서 포함'],
['3', '스크린 방화셔터', '2.0m x 2.0m', '1', '별도견적', '400kg', '5,200,000', '감지기 별도']
];
slide.addTable(productTable, {
x: 0.3, y: 1, w: 9.4, h: 1.8,
fontSize: 9,
color: colors.secondary,
border: { pt: 0.5, color: colors.darkGray },
colW: [0.5, 1.5, 1.2, 0.6, 1, 0.9, 1.2, 1.2],
align: 'center',
valign: 'middle'
});
// 부가 비용 테이블
slide.addText('부가 비용', {
x: 0.3, y: 3, w: 2, h: 0.4,
fontSize: 14, bold: true, color: colors.secondary
});
const additionalTable = [
['항목', '조건', '단가', '수량', '금액'],
['기본 설치비', '1개소당', '300,000', '5개소', '1,500,000'],
['고소작업비', '층고 5m 이상 시', '250,000/일', '해당없음', '0'],
['운반비', '서울/경기권', '0', '1식', '0']
];
slide.addTable(additionalTable, {
x: 0.3, y: 3.4, w: 9.4, h: 1.2,
fontSize: 9,
color: colors.secondary,
border: { pt: 0.5, color: colors.darkGray },
colW: [1.5, 2, 1.5, 1.2, 1.5],
align: 'center',
valign: 'middle'
});
// 계산식 설명
slide.addText('※ 면적 계산: 가로(m) × 높이(m) × 헤베당 단가', {
x: 0.3, y: 4.8, w: 5, h: 0.25,
fontSize: 9, color: colors.darkGray
});
slide.addText('※ 모터 선택 기준: 400kg(소형), 600kg(중형), 1000kg(대형)', {
x: 0.3, y: 5.05, w: 5, h: 0.25,
fontSize: 9, color: colors.darkGray
});
// 유효기간 경고
slide.addShape('rect', {
x: 5.5, y: 4.7, w: 4.2, h: 0.7,
fill: { color: 'fef2f2' },
line: { color: colors.accent, width: 1 }
});
slide.addText('⚠️ 본 견적서는 제출일로부터 15일간 유효함', {
x: 5.5, y: 4.7, w: 4.2, h: 0.7,
fontSize: 10, bold: true, color: colors.accent,
align: 'center', valign: 'middle'
});
console.log('✅ 슬라이드 3: 세부 내역 생성 완료');
}
// ========================================
// 슬라이드 4: 시험성적서/특허증
// ========================================
function createCertificateSlide() {
const slide = pptx.addSlide();
// 배경
slide.background = { color: colors.white };
// 상단 바
slide.addShape('rect', {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: colors.secondary }
});
slide.addText('품질 인증', {
x: 0.5, y: 0.2, w: 5, h: 0.5,
fontSize: 24, bold: true, color: colors.white
});
// 인증서 카드 1
slide.addShape('rect', {
x: 0.5, y: 1.2, w: 4.3, h: 3.8,
fill: { color: colors.lightGray },
line: { color: colors.primary, width: 1 }
});
slide.addText('🔥', {
x: 0.5, y: 1.5, w: 4.3, h: 0.8,
fontSize: 40, align: 'center'
});
slide.addText('내화 시험성적서', {
x: 0.5, y: 2.3, w: 4.3, h: 0.5,
fontSize: 18, bold: true, color: colors.secondary,
align: 'center'
});
slide.addText([
{ text: '한국건설기술연구원 인증\n', options: { fontSize: 11, color: colors.darkGray } },
{ text: '\n1시간 내화 성능 합격\n', options: { fontSize: 14, bold: true, color: colors.primary } },
{ text: '\nKS F 2268-1 기준 충족\n', options: { fontSize: 10, color: colors.darkGray } },
{ text: '인증번호: KFI-2024-1234', options: { fontSize: 9, color: colors.darkGray } }
], {
x: 0.7, y: 2.9, w: 3.9, h: 2,
align: 'center', valign: 'top'
});
// 인증서 카드 2
slide.addShape('rect', {
x: 5.2, y: 1.2, w: 4.3, h: 3.8,
fill: { color: colors.lightGray },
line: { color: colors.primary, width: 1 }
});
slide.addText('📜', {
x: 5.2, y: 1.5, w: 4.3, h: 0.8,
fontSize: 40, align: 'center'
});
slide.addText('특허 등록증', {
x: 5.2, y: 2.3, w: 4.3, h: 0.5,
fontSize: 18, bold: true, color: colors.secondary,
align: 'center'
});
slide.addText([
{ text: '대한민국 특허청\n', options: { fontSize: 11, color: colors.darkGray } },
{ text: '\n하향식 스크린 방화셔터\n', options: { fontSize: 14, bold: true, color: colors.primary } },
{ text: '\n특허 제10-2024-0056789호\n', options: { fontSize: 10, color: colors.darkGray } },
{ text: '등록일: 2024.03.15', options: { fontSize: 9, color: colors.darkGray } }
], {
x: 5.4, y: 2.9, w: 3.9, h: 2,
align: 'center', valign: 'top'
});
console.log('✅ 슬라이드 4: 품질 인증 생성 완료');
}
// ========================================
// 슬라이드 5: 회사 소개
// ========================================
function createCompanySlide() {
const slide = pptx.addSlide();
// 배경
slide.background = { color: colors.white };
// 상단 바
slide.addShape('rect', {
x: 0, y: 0, w: 10, h: 0.8,
fill: { color: colors.secondary }
});
slide.addText('회사 소개 및 연락처', {
x: 0.5, y: 0.2, w: 5, h: 0.5,
fontSize: 24, bold: true, color: colors.white
});
// 회사 로고 영역
slide.addShape('rect', {
x: 0.5, y: 1.2, w: 3, h: 1.5,
fill: { color: colors.primary }
});
slide.addText('SAM\n방화셔터', {
x: 0.5, y: 1.2, w: 3, h: 1.5,
fontSize: 28, bold: true, color: colors.white,
align: 'center', valign: 'middle'
});
// 회사 소개
slide.addText([
{ text: '㈜샘방화셔터\n\n', options: { fontSize: 20, bold: true, color: colors.secondary } },
{ text: '20년 전통의 방화셔터 전문 제조기업\n', options: { fontSize: 12, color: colors.darkGray } },
{ text: '국내 최고 품질의 철재 및 스크린 방화셔터 생산', options: { fontSize: 12, color: colors.darkGray } }
], {
x: 3.8, y: 1.2, w: 5.7, h: 1.5,
valign: 'middle'
});
// 연락처 정보
slide.addShape('rect', {
x: 0.5, y: 3, w: 9, h: 2.3,
fill: { color: colors.lightGray }
});
const contactInfo = [
['📍 주소', '서울특별시 강서구 공항대로 123, SAM빌딩 5층'],
['📞 전화', '02-1234-5678'],
['📠 팩스', '02-1234-5679'],
['📧 이메일', 'estimate@samfireshutter.co.kr'],
['🌐 웹사이트', 'www.samfireshutter.co.kr']
];
slide.addTable(contactInfo, {
x: 0.8, y: 3.2, w: 8.4, h: 1.9,
fontSize: 12,
color: colors.secondary,
border: { pt: 0 },
fill: { color: colors.lightGray },
colW: [1.5, 6.9],
align: 'left',
valign: 'middle'
});
// 담당자 정보
slide.addText('담당: 박지민 대리 (영업지원팀) | 직통: 010-1234-5678', {
x: 0.5, y: 5.35, w: 9, h: 0.25,
fontSize: 10, color: colors.primary,
align: 'right'
});
console.log('✅ 슬라이드 5: 회사 소개 생성 완료');
}
// ========================================
// 메인 실행
// ========================================
async function main() {
console.log('🚀 방화셔터 견적서 PPTX 생성 시작\n');
try {
// 슬라이드 생성
createCoverSlide();
createSummarySlide();
createDetailSlide();
createCertificateSlide();
createCompanySlide();
// 파일 저장
const outputPath = path.join(__dirname, 'pptx', 'fire_shutter_estimate.pptx');
await pptx.writeFile({ fileName: outputPath });
console.log('\n🎉 PPTX 생성 완료!');
console.log(`📁 저장 위치: ${outputPath}`);
// 파일 크기 확인
const stats = fs.statSync(outputPath);
console.log(`📏 파일 크기: ${(stats.size / 1024).toFixed(1)} KB`);
} catch (error) {
console.error('❌ 생성 실패:', error.message);
throw error;
}
}
main();