677 lines
37 KiB
Plaintext
677 lines
37 KiB
Plaintext
<!-- Calculator Header -->
|
|
<section class="bg-gradient-to-r from-blue-600 to-purple-600 py-16">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4" data-aos="fade-up">
|
|
프로젝트 견적 계산기
|
|
</h1>
|
|
<p class="text-xl text-blue-100 max-w-3xl mx-auto" data-aos="fade-up" data-aos-delay="200">
|
|
원하는 서비스와 요구사항을 선택하면 실시간으로 정확한 견적을 계산해드립니다
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Calculator Form -->
|
|
<section class="py-16 bg-gray-50">
|
|
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="bg-white rounded-3xl shadow-2xl overflow-hidden">
|
|
<div class="p-8 md:p-12">
|
|
<form id="calculator-form">
|
|
<!-- Step 1: Service Selection -->
|
|
<div class="calculator-step active" id="step-1">
|
|
<div class="text-center mb-8">
|
|
<h2 class="text-3xl font-bold text-gray-900 mb-4">1단계: 서비스 선택</h2>
|
|
<p class="text-gray-600">필요한 서비스를 선택해주세요 (복수 선택 가능)</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6" id="services-grid">
|
|
<!-- Services will be loaded dynamically -->
|
|
</div>
|
|
|
|
<div class="text-center mt-8">
|
|
<button type="button" class="next-step bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors disabled:bg-gray-300 disabled:cursor-not-allowed" disabled>
|
|
다음 단계
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Project Details -->
|
|
<div class="calculator-step" id="step-2">
|
|
<div class="text-center mb-8">
|
|
<h2 class="text-3xl font-bold text-gray-900 mb-4">2단계: 프로젝트 세부사항</h2>
|
|
<p class="text-gray-600">프로젝트의 복잡도와 일정을 선택해주세요</p>
|
|
</div>
|
|
|
|
<div class="space-y-8">
|
|
<!-- Project Complexity -->
|
|
<div>
|
|
<label class="block text-lg font-semibold text-gray-900 mb-4">프로젝트 복잡도</label>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div class="complexity-option" data-value="simple">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-green-600 text-2xl mb-2">🌟</div>
|
|
<div class="font-semibold">간단함</div>
|
|
<div class="text-sm text-gray-600">기본 기능, 표준 디자인</div>
|
|
<div class="text-sm text-green-600 font-medium mt-2">-30% 할인</div>
|
|
</div>
|
|
</div>
|
|
<div class="complexity-option" data-value="medium">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-blue-600 text-2xl mb-2">⭐</div>
|
|
<div class="font-semibold">보통</div>
|
|
<div class="text-sm text-gray-600">중간 복잡도, 커스텀 기능</div>
|
|
<div class="text-sm text-blue-600 font-medium mt-2">표준 가격</div>
|
|
</div>
|
|
</div>
|
|
<div class="complexity-option" data-value="complex">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-orange-600 text-2xl mb-2">🚀</div>
|
|
<div class="font-semibold">복잡함</div>
|
|
<div class="text-sm text-gray-600">고급 기능, 통합 시스템</div>
|
|
<div class="text-sm text-orange-600 font-medium mt-2">+50% 추가</div>
|
|
</div>
|
|
</div>
|
|
<div class="complexity-option" data-value="enterprise">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-purple-600 text-2xl mb-2">💎</div>
|
|
<div class="font-semibold">엔터프라이즈</div>
|
|
<div class="text-sm text-gray-600">대규모, 높은 복잡도</div>
|
|
<div class="text-sm text-purple-600 font-medium mt-2">+100% 추가</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timeline -->
|
|
<div>
|
|
<label class="block text-lg font-semibold text-gray-900 mb-4">희망 완료 시기</label>
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
|
<div class="timeline-option" data-value="rush">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-red-600 text-2xl mb-2">⚡</div>
|
|
<div class="font-semibold">긴급 (2주 이내)</div>
|
|
<div class="text-sm text-red-600 font-medium mt-2">+80% 추가</div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-option" data-value="fast">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-orange-600 text-2xl mb-2">🔥</div>
|
|
<div class="font-semibold">빠름 (2-4주)</div>
|
|
<div class="text-sm text-orange-600 font-medium mt-2">+40% 추가</div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-option selected" data-value="standard">
|
|
<div class="p-4 border-2 border-blue-500 rounded-lg cursor-pointer hover:border-blue-500 transition-colors bg-blue-50">
|
|
<div class="text-blue-600 text-2xl mb-2">⏰</div>
|
|
<div class="font-semibold">표준 (1-3개월)</div>
|
|
<div class="text-sm text-blue-600 font-medium mt-2">표준 가격</div>
|
|
</div>
|
|
</div>
|
|
<div class="timeline-option" data-value="flexible">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="text-green-600 text-2xl mb-2">🌱</div>
|
|
<div class="font-semibold">여유 (3개월+)</div>
|
|
<div class="text-sm text-green-600 font-medium mt-2">-20% 할인</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-between mt-8">
|
|
<button type="button" class="prev-step bg-gray-300 text-gray-700 px-8 py-3 rounded-lg font-semibold hover:bg-gray-400 transition-colors">
|
|
이전 단계
|
|
</button>
|
|
<button type="button" class="next-step bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors disabled:bg-gray-300 disabled:cursor-not-allowed" disabled>
|
|
다음 단계
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 3: Additional Features -->
|
|
<div class="calculator-step" id="step-3">
|
|
<div class="text-center mb-8">
|
|
<h2 class="text-3xl font-bold text-gray-900 mb-4">3단계: 추가 기능</h2>
|
|
<p class="text-gray-600">필요한 추가 기능을 선택해주세요 (선택사항)</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div class="feature-option" data-value="seo-optimization" data-price="300000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">SEO 최적화</span>
|
|
<span class="text-blue-600 font-bold">₩300,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">검색엔진 최적화 및 메타 태그 설정</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="feature-option" data-value="analytics-setup" data-price="150000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">분석 도구 설정</span>
|
|
<span class="text-blue-600 font-bold">₩150,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">Google Analytics, 태그 매니저 설정</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="feature-option" data-value="social-integration" data-price="200000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">소셜 미디어 연동</span>
|
|
<span class="text-blue-600 font-bold">₩200,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">Facebook, Instagram, 카카오톡 연동</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="feature-option" data-value="payment-gateway" data-price="500000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">결제 시스템</span>
|
|
<span class="text-blue-600 font-bold">₩500,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">신용카드, 간편결제 시스템 연동</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="feature-option" data-value="multilingual" data-price="400000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">다국어 지원</span>
|
|
<span class="text-blue-600 font-bold">₩400,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">한국어, 영어, 중국어 등 다국어</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="feature-option" data-value="admin-panel" data-price="600000">
|
|
<div class="p-4 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<span class="font-semibold">관리자 패널</span>
|
|
<span class="text-blue-600 font-bold">₩600,000</span>
|
|
</div>
|
|
<p class="text-sm text-gray-600">콘텐츠 관리, 사용자 관리 시스템</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Custom Requirements -->
|
|
<div class="mt-8">
|
|
<label class="block text-lg font-semibold text-gray-900 mb-4">특별 요구사항</label>
|
|
<textarea id="custom-requirements" rows="4" placeholder="특별한 기능이나 요구사항이 있다면 자세히 설명해주세요..." class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"></textarea>
|
|
</div>
|
|
|
|
<div class="flex justify-between mt-8">
|
|
<button type="button" class="prev-step bg-gray-300 text-gray-700 px-8 py-3 rounded-lg font-semibold hover:bg-gray-400 transition-colors">
|
|
이전 단계
|
|
</button>
|
|
<button type="button" class="calculate-btn bg-green-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-green-700 transition-colors">
|
|
견적 계산하기
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Step 4: Results -->
|
|
<div class="calculator-step" id="step-4">
|
|
<div class="text-center mb-8">
|
|
<h2 class="text-3xl font-bold text-gray-900 mb-4">견적 결과</h2>
|
|
<p class="text-gray-600">계산된 프로젝트 견적을 확인하세요</p>
|
|
</div>
|
|
|
|
<div id="calculation-results" class="space-y-6">
|
|
<!-- Results will be loaded here -->
|
|
</div>
|
|
|
|
<!-- Contact Form -->
|
|
<div class="mt-12 bg-gray-50 p-8 rounded-2xl">
|
|
<h3 class="text-2xl font-bold text-gray-900 mb-6 text-center">견적 요청하기</h3>
|
|
<p class="text-gray-600 text-center mb-6">정확한 견적을 받으시려면 연락처를 남겨주세요</p>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<input type="text" id="contact-name" placeholder="이름" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
</div>
|
|
<div>
|
|
<input type="email" id="contact-email" placeholder="이메일" required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
</div>
|
|
<div>
|
|
<input type="tel" id="contact-phone" placeholder="연락처" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
</div>
|
|
<div>
|
|
<input type="text" id="contact-company" placeholder="회사명 (선택사항)" class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6">
|
|
<textarea id="project-description" rows="4" placeholder="프로젝트에 대해 자세히 설명해주세요..." required class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"></textarea>
|
|
</div>
|
|
|
|
<div class="text-center mt-6">
|
|
<button type="button" id="submit-estimate" class="bg-blue-600 text-white px-8 py-3 rounded-lg font-semibold hover:bg-blue-700 transition-colors">
|
|
견적 요청 보내기
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-center mt-8">
|
|
<button type="button" class="restart-calculator bg-gray-300 text-gray-700 px-8 py-3 rounded-lg font-semibold hover:bg-gray-400 transition-colors">
|
|
다시 계산하기
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Calculator JavaScript -->
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
let currentStep = 1;
|
|
let selectedServices = [];
|
|
let selectedComplexity = 'medium';
|
|
let selectedTimeline = 'standard';
|
|
let selectedFeatures = [];
|
|
let customRequirements = '';
|
|
let calculationResult = null;
|
|
|
|
// Load services
|
|
loadServices();
|
|
|
|
// Event listeners
|
|
document.addEventListener('click', function(e) {
|
|
if (e.target.classList.contains('next-step')) {
|
|
nextStep();
|
|
} else if (e.target.classList.contains('prev-step')) {
|
|
prevStep();
|
|
} else if (e.target.classList.contains('calculate-btn')) {
|
|
calculateEstimate();
|
|
} else if (e.target.classList.contains('restart-calculator')) {
|
|
restartCalculator();
|
|
} else if (e.target.closest('.service-option')) {
|
|
toggleService(e.target.closest('.service-option'));
|
|
} else if (e.target.closest('.complexity-option')) {
|
|
selectComplexity(e.target.closest('.complexity-option'));
|
|
} else if (e.target.closest('.timeline-option')) {
|
|
selectTimeline(e.target.closest('.timeline-option'));
|
|
} else if (e.target.closest('.feature-option')) {
|
|
toggleFeature(e.target.closest('.feature-option'));
|
|
}
|
|
});
|
|
|
|
document.getElementById('submit-estimate').addEventListener('click', submitEstimate);
|
|
|
|
async function loadServices() {
|
|
try {
|
|
const response = await fetch('/api/calculator/services');
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
displayServices(data.allServices);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading services:', error);
|
|
// Display default services
|
|
displayDefaultServices();
|
|
}
|
|
}
|
|
|
|
function displayServices(services) {
|
|
const container = document.getElementById('services-grid');
|
|
container.innerHTML = '';
|
|
|
|
services.forEach(service => {
|
|
const serviceDiv = document.createElement('div');
|
|
serviceDiv.className = 'service-option';
|
|
serviceDiv.dataset.serviceId = service._id;
|
|
serviceDiv.innerHTML = `
|
|
<div class="p-6 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold">${service.name}</h3>
|
|
<span class="text-blue-600 font-bold">₩${service.pricing.basePrice.toLocaleString()}</span>
|
|
</div>
|
|
<p class="text-gray-600 text-sm mb-4">${service.shortDescription}</p>
|
|
<div class="flex items-center justify-between">
|
|
<span class="px-3 py-1 bg-blue-100 text-blue-600 text-xs rounded-full">${service.category}</span>
|
|
<span class="text-xs text-gray-500">${service.estimatedTime.min}-${service.estimatedTime.max} ${service.estimatedTime.unit}</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.appendChild(serviceDiv);
|
|
});
|
|
}
|
|
|
|
function displayDefaultServices() {
|
|
const container = document.getElementById('services-grid');
|
|
container.innerHTML = `
|
|
<div class="service-option" data-service-id="web-dev">
|
|
<div class="p-6 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold">웹 개발</h3>
|
|
<span class="text-blue-600 font-bold">₩500,000</span>
|
|
</div>
|
|
<p class="text-gray-600 text-sm mb-4">현대적이고 반응형 웹사이트 개발</p>
|
|
<div class="flex items-center justify-between">
|
|
<span class="px-3 py-1 bg-blue-100 text-blue-600 text-xs rounded-full">development</span>
|
|
<span class="text-xs text-gray-500">2-8 weeks</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="service-option" data-service-id="mobile-app">
|
|
<div class="p-6 border-2 border-gray-200 rounded-lg cursor-pointer hover:border-blue-500 transition-colors">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold">모바일 앱</h3>
|
|
<span class="text-blue-600 font-bold">₩800,000</span>
|
|
</div>
|
|
<p class="text-gray-600 text-sm mb-4">iOS/Android 네이티브 앱 개발</p>
|
|
<div class="flex items-center justify-between">
|
|
<span class="px-3 py-1 bg-blue-100 text-blue-600 text-xs rounded-full">development</span>
|
|
<span class="text-xs text-gray-500">4-12 weeks</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function toggleService(element) {
|
|
const serviceId = element.dataset.serviceId;
|
|
const border = element.querySelector('div');
|
|
|
|
if (selectedServices.includes(serviceId)) {
|
|
selectedServices = selectedServices.filter(id => id !== serviceId);
|
|
border.classList.remove('border-blue-500', 'bg-blue-50');
|
|
border.classList.add('border-gray-200');
|
|
} else {
|
|
selectedServices.push(serviceId);
|
|
border.classList.remove('border-gray-200');
|
|
border.classList.add('border-blue-500', 'bg-blue-50');
|
|
}
|
|
|
|
updateStepButtons();
|
|
}
|
|
|
|
function selectComplexity(element) {
|
|
document.querySelectorAll('.complexity-option').forEach(el => {
|
|
el.querySelector('div').classList.remove('border-blue-500', 'bg-blue-50');
|
|
el.querySelector('div').classList.add('border-gray-200');
|
|
});
|
|
|
|
selectedComplexity = element.dataset.value;
|
|
element.querySelector('div').classList.remove('border-gray-200');
|
|
element.querySelector('div').classList.add('border-blue-500', 'bg-blue-50');
|
|
updateStepButtons();
|
|
}
|
|
|
|
function selectTimeline(element) {
|
|
document.querySelectorAll('.timeline-option').forEach(el => {
|
|
el.querySelector('div').classList.remove('border-blue-500', 'bg-blue-50');
|
|
el.querySelector('div').classList.add('border-gray-200');
|
|
});
|
|
|
|
selectedTimeline = element.dataset.value;
|
|
element.querySelector('div').classList.remove('border-gray-200');
|
|
element.querySelector('div').classList.add('border-blue-500', 'bg-blue-50');
|
|
updateStepButtons();
|
|
}
|
|
|
|
function toggleFeature(element) {
|
|
const featureValue = element.dataset.value;
|
|
const border = element.querySelector('div');
|
|
|
|
if (selectedFeatures.includes(featureValue)) {
|
|
selectedFeatures = selectedFeatures.filter(f => f !== featureValue);
|
|
border.classList.remove('border-blue-500', 'bg-blue-50');
|
|
border.classList.add('border-gray-200');
|
|
} else {
|
|
selectedFeatures.push(featureValue);
|
|
border.classList.remove('border-gray-200');
|
|
border.classList.add('border-blue-500', 'bg-blue-50');
|
|
}
|
|
}
|
|
|
|
function updateStepButtons() {
|
|
const nextButton = document.querySelector(`#step-${currentStep} .next-step`);
|
|
if (nextButton) {
|
|
if (currentStep === 1) {
|
|
nextButton.disabled = selectedServices.length === 0;
|
|
} else if (currentStep === 2) {
|
|
nextButton.disabled = !selectedComplexity || !selectedTimeline;
|
|
}
|
|
}
|
|
}
|
|
|
|
function nextStep() {
|
|
if (currentStep < 4) {
|
|
document.getElementById(`step-${currentStep}`).classList.remove('active');
|
|
currentStep++;
|
|
document.getElementById(`step-${currentStep}`).classList.add('active');
|
|
updateStepButtons();
|
|
}
|
|
}
|
|
|
|
function prevStep() {
|
|
if (currentStep > 1) {
|
|
document.getElementById(`step-${currentStep}`).classList.remove('active');
|
|
currentStep--;
|
|
document.getElementById(`step-${currentStep}`).classList.add('active');
|
|
updateStepButtons();
|
|
}
|
|
}
|
|
|
|
async function calculateEstimate() {
|
|
customRequirements = document.getElementById('custom-requirements').value;
|
|
|
|
const requestData = {
|
|
selectedServices,
|
|
projectComplexity: selectedComplexity,
|
|
timeline: selectedTimeline,
|
|
additionalFeatures: selectedFeatures,
|
|
customRequirements
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/calculator/calculate', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(requestData)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
calculationResult = data.estimate;
|
|
displayResults(data.estimate, data.selectedServices);
|
|
nextStep();
|
|
} else {
|
|
alert('견적 계산 중 오류가 발생했습니다: ' + data.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Calculation error:', error);
|
|
alert('견적 계산 중 오류가 발생했습니다. 다시 시도해주세요.');
|
|
}
|
|
}
|
|
|
|
function displayResults(estimate, services) {
|
|
const container = document.getElementById('calculation-results');
|
|
|
|
container.innerHTML = `
|
|
<div class="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-8 rounded-2xl text-center">
|
|
<h3 class="text-3xl font-bold mb-2">예상 견적</h3>
|
|
<div class="text-5xl font-bold mb-4">${estimate.range.formatted}</div>
|
|
<div class="text-lg">예상 소요시간: ${estimate.timeline.formatted}</div>
|
|
<div class="text-sm mt-2 opacity-80">신뢰도: ${estimate.confidence}%</div>
|
|
</div>
|
|
|
|
<div class="bg-white border-2 border-gray-200 rounded-2xl p-6">
|
|
<h4 class="text-xl font-bold mb-4">견적 상세 내역</h4>
|
|
<div class="space-y-3">
|
|
<div class="flex justify-between">
|
|
<span>기본 서비스</span>
|
|
<span class="font-semibold">₩${estimate.breakdown.baseServices.toLocaleString()}</span>
|
|
</div>
|
|
${estimate.breakdown.complexityAdjustment !== 0 ? `
|
|
<div class="flex justify-between">
|
|
<span>복잡도 조정</span>
|
|
<span class="font-semibold ${estimate.breakdown.complexityAdjustment > 0 ? 'text-red-600' : 'text-green-600'}">
|
|
${estimate.breakdown.complexityAdjustment > 0 ? '+' : ''}₩${estimate.breakdown.complexityAdjustment.toLocaleString()}
|
|
</span>
|
|
</div>
|
|
` : ''}
|
|
${estimate.breakdown.timelineAdjustment !== 0 ? `
|
|
<div class="flex justify-between">
|
|
<span>일정 조정</span>
|
|
<span class="font-semibold ${estimate.breakdown.timelineAdjustment > 0 ? 'text-red-600' : 'text-green-600'}">
|
|
${estimate.breakdown.timelineAdjustment > 0 ? '+' : ''}₩${estimate.breakdown.timelineAdjustment.toLocaleString()}
|
|
</span>
|
|
</div>
|
|
` : ''}
|
|
${estimate.breakdown.additionalFeatures > 0 ? `
|
|
<div class="flex justify-between">
|
|
<span>추가 기능</span>
|
|
<span class="font-semibold">+₩${estimate.breakdown.additionalFeatures.toLocaleString()}</span>
|
|
</div>
|
|
` : ''}
|
|
${estimate.breakdown.customRequirements > 0 ? `
|
|
<div class="flex justify-between">
|
|
<span>특별 요구사항</span>
|
|
<span class="font-semibold">+₩${estimate.breakdown.customRequirements.toLocaleString()}</span>
|
|
</div>
|
|
` : ''}
|
|
<hr class="my-3">
|
|
<div class="flex justify-between text-lg font-bold">
|
|
<span>총 예상 비용</span>
|
|
<span>₩${estimate.total.toLocaleString()}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
${estimate.recommendations && estimate.recommendations.length > 0 ? `
|
|
<div class="bg-yellow-50 border-2 border-yellow-200 rounded-2xl p-6">
|
|
<h4 class="text-xl font-bold mb-4 text-yellow-800">추천 사항</h4>
|
|
<ul class="space-y-2">
|
|
${estimate.recommendations.map(rec => `<li class="flex items-start"><span class="text-yellow-600 mr-2">•</span>${rec}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
` : ''}
|
|
|
|
<div class="bg-gray-50 rounded-2xl p-6">
|
|
<h4 class="text-xl font-bold mb-4">선택된 서비스</h4>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
${services.map(service => `
|
|
<div class="flex justify-between items-center p-3 bg-white rounded-lg">
|
|
<span>${service.name}</span>
|
|
<span class="font-semibold text-blue-600">₩${service.basePrice.toLocaleString()}</span>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async function submitEstimate() {
|
|
const name = document.getElementById('contact-name').value;
|
|
const email = document.getElementById('contact-email').value;
|
|
const phone = document.getElementById('contact-phone').value;
|
|
const company = document.getElementById('contact-company').value;
|
|
const description = document.getElementById('project-description').value;
|
|
|
|
if (!name || !email || !description) {
|
|
alert('이름, 이메일, 프로젝트 설명은 필수 입력 항목입니다.');
|
|
return;
|
|
}
|
|
|
|
const requestData = {
|
|
services: selectedServices,
|
|
projectType: 'custom',
|
|
timeline: selectedTimeline,
|
|
budget: calculationResult ? calculationResult.range.formatted : '',
|
|
description,
|
|
contactInfo: {
|
|
name,
|
|
email,
|
|
phone,
|
|
company
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/contact/estimate', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(requestData)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
alert('견적 요청이 성공적으로 전송되었습니다! 곧 연락드리겠습니다.');
|
|
// Reset form or redirect
|
|
} else {
|
|
alert('견적 요청 전송 중 오류가 발생했습니다: ' + data.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('Submit error:', error);
|
|
alert('견적 요청 전송 중 오류가 발생했습니다. 다시 시도해주세요.');
|
|
}
|
|
}
|
|
|
|
function restartCalculator() {
|
|
currentStep = 1;
|
|
selectedServices = [];
|
|
selectedComplexity = 'medium';
|
|
selectedTimeline = 'standard';
|
|
selectedFeatures = [];
|
|
customRequirements = '';
|
|
calculationResult = null;
|
|
|
|
// Reset UI
|
|
document.querySelectorAll('.calculator-step').forEach(step => step.classList.remove('active'));
|
|
document.getElementById('step-1').classList.add('active');
|
|
|
|
// Reset selections
|
|
document.querySelectorAll('.service-option, .complexity-option, .timeline-option, .feature-option').forEach(el => {
|
|
const border = el.querySelector('div');
|
|
border.classList.remove('border-blue-500', 'bg-blue-50');
|
|
border.classList.add('border-gray-200');
|
|
});
|
|
|
|
// Set default timeline selection
|
|
document.querySelector('.timeline-option[data-value="standard"] div').classList.remove('border-gray-200');
|
|
document.querySelector('.timeline-option[data-value="standard"] div').classList.add('border-blue-500', 'bg-blue-50');
|
|
|
|
// Clear form inputs
|
|
document.getElementById('custom-requirements').value = '';
|
|
document.getElementById('contact-name').value = '';
|
|
document.getElementById('contact-email').value = '';
|
|
document.getElementById('contact-phone').value = '';
|
|
document.getElementById('contact-company').value = '';
|
|
document.getElementById('project-description').value = '';
|
|
|
|
updateStepButtons();
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.calculator-step {
|
|
display: none;
|
|
}
|
|
|
|
.calculator-step.active {
|
|
display: block;
|
|
}
|
|
|
|
.service-option, .complexity-option, .timeline-option, .feature-option {
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.service-option:hover, .complexity-option:hover, .timeline-option:hover, .feature-option:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
</style> |