/
disadykov
/
potolok-calc
Обзор
Документация
Войти
/
disadykov
/
potolok-calc
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
script.js
368 строк
14 KB
Denis Sadykov
Create: index.html, script.js, styles.css
02 июл 2026, 03:29
Верифицирован
02 июл 2026, 03:29
2590699
Код
Авторство
О чём код?
// Конфигурация цен const PRICES = { material: { fabric: 800, // Текстиль film: 600, // ПВХ пленка baskin: 500, // Баскин steklovy: 750, // Стекловолокно two_color: 650, // Двухцветный ПВХ satin: 620, // Сатиновый glossy: 580, // Глянцевый matte: 550, // Матовый fabric_3d: 900, // Текстиль 3D perforated: 700 // Перфорированный }, accessories: { light: 150, // Точечный светильник star: 250, // Звезда/светящийся элемент innerCorner: 80, // Внутренний угол outerCorner: 120, // Внешний угол fan: 500, // Монтаж вентилятора skirt: 150, // Плинтус print: 1500 // Фотопечать }, services: { demontage: 2000, // Демонтаж preparation: 1500, // Подготовка stain: 3000 // Выведение пятен }, surcharges: { multiLevel: 0.30, // +30% за многоуровневый curved: 0.25, // +25% за криволинейную форму arch: 0.20 // +20% за арочную конструкцию } }; // Базовая цена за квадратный метр (зависит от материала) let basePrice = PRICES.material.fabric; // Цены на способы фиксации const fixationPrices = { 'no_harpoon': 300, // Без гарпуна на клей 'harpoon': 500, // Классический гарпун 'combined': 700, // Комбинированный способ 'reinforced': 900, // Усиленное крепление 'cutting': 400, // Крепление с подрезкой 'double_harpoon': 700, // Двойной гарпун 'hidden': 900, // Скрытый гарпун 'quick': 400 // Быстрый монтаж }; // Объект для хранения текущих значений параметров const state = { area: 10, material: 'fabric', perimeter: 10, profile: 'basic', multiLevel: false, curved: false, arch: false, lights: 0, stars: 0, innerCorners: 0, outerCorners: 0, fan: false, skirt: false, print: false, demontage: false, preparation: false, stain: false, fixation: 'no_harpoon' }; // Элементы DOM const elements = { totalPrice: document.getElementById('totalPrice'), areaSlider: document.getElementById('areaSlider'), areaValue: document.getElementById('areaValue'), areaInput: document.getElementById('areaInput'), areaIncrease: document.getElementById('areaIncrease'), areaDecrease: document.getElementById('areaDecrease'), perimeterSlider: document.getElementById('perimeterSlider'), perimeterValue: document.getElementById('perimeterValue'), perimeterInput: document.getElementById('perimeterInput'), perimeterIncrease: document.getElementById('perimeterIncrease'), perimeterDecrease: document.getElementById('perimeterDecrease'), profileSelect: document.getElementById('profileSelect'), lightsSlider: document.getElementById('lightsCount'), lightsValue: document.getElementById('lightsValue'), starsSlider: document.getElementById('spotsCount'), starsValue: document.getElementById('spotsValue'), innerCornersSlider: document.getElementById('cornersCount'), innerCornersValue: document.getElementById('cornersValue'), outerCornersSlider: document.getElementById('outerCornersCount'), outerCornersValue: document.getElementById('outerCornersValue'), materialSelect: document.getElementById('materialSelect'), fixationCheckboxes: document.querySelectorAll('input[name="fixation"]') }; // Инициализация при загрузке страницы function init() { updateBasePrice(); setupEventListeners(); calculatePrice(); } // Установка базовой цены в зависимости от материала function updateBasePrice() { basePrice = PRICES.material[state.material]; } // Обновление области ввода площади function updateAreaInput() { elements.areaInput.value = state.area.toFixed(1); } // Обновление области ввода периметра function updatePerimeterInput() { elements.perimeterInput.value = state.perimeter.toFixed(1); } // Получение цены профиля function getProfilePrice() { const profileOption = elements.profileSelect.options[elements.profileSelect.selectedIndex]; return parseInt(profileOption.dataset.price) || 0; } // Получение цены фиксации function getFixationPrice() { return fixationPrices[state.fixation] || 0; } // Обновление значения периметра в UI function updatePerimeterValue() { elements.perimeterValue.textContent = state.perimeter.toFixed(1); } // Настройка обработчиков событий function setupEventListeners() { // Слайдер площади elements.areaSlider.addEventListener('input', (e) => { let newArea = parseFloat(e.target.value); // Ограничиваем значение if (newArea < 1) newArea = 1; if (newArea > 500) newArea = 500; state.area = newArea; elements.areaValue.textContent = state.area.toFixed(1); updateAreaInput(); calculatePrice(); }); // Кнопка увеличения площади elements.areaIncrease.addEventListener('click', () => { state.area = Math.min(state.area + 0.5, 500); elements.areaSlider.value = state.area; elements.areaValue.textContent = state.area.toFixed(1); updateAreaInput(); calculatePrice(); }); // Кнопка уменьшения площади elements.areaDecrease.addEventListener('click', () => { state.area = Math.max(state.area - 0.5, 1); elements.areaSlider.value = state.area; elements.areaValue.textContent = state.area.toFixed(1); updateAreaInput(); calculatePrice(); }); // Поле ввода площади elements.areaInput.addEventListener('input', (e) => { let newArea = parseFloat(e.target.value); // Валидация значения if (isNaN(newArea) || newArea < 1) newArea = 1; if (newArea > 500) newArea = 500; state.area = newArea; elements.areaSlider.value = state.area; elements.areaValue.textContent = state.area.toFixed(1); updateAreaInput(); calculatePrice(); }); // Слайдер периметра elements.perimeterSlider.addEventListener('input', (e) => { let newPerimeter = parseFloat(e.target.value); // Ограничиваем значение if (newPerimeter < 1) newPerimeter = 1; if (newPerimeter > 500) newPerimeter = 500; state.perimeter = newPerimeter; elements.perimeterValue.textContent = state.perimeter.toFixed(1); updatePerimeterInput(); calculatePrice(); }); // Кнопка увеличения периметра elements.perimeterIncrease.addEventListener('click', () => { state.perimeter = Math.min(state.perimeter + 0.5, 500); elements.perimeterSlider.value = state.perimeter; elements.perimeterValue.textContent = state.perimeter.toFixed(1); updatePerimeterInput(); calculatePrice(); }); // Кнопка уменьшения периметра elements.perimeterDecrease.addEventListener('click', () => { state.perimeter = Math.max(state.perimeter - 0.5, 1); elements.perimeterSlider.value = state.perimeter; elements.perimeterValue.textContent = state.perimeter.toFixed(1); updatePerimeterInput(); calculatePrice(); }); // Поле ввода периметра elements.perimeterInput.addEventListener('input', (e) => { let newPerimeter = parseFloat(e.target.value); // Валидация значения if (isNaN(newPerimeter) || newPerimeter < 1) newPerimeter = 1; if (newPerimeter > 500) newPerimeter = 500; state.perimeter = newPerimeter; elements.perimeterSlider.value = state.perimeter; elements.perimeterValue.textContent = state.perimeter.toFixed(1); updatePerimeterInput(); calculatePrice(); }); // Выпадающий список профиля elements.profileSelect.addEventListener('change', (e) => { state.profile = e.target.value; calculatePrice(); }); // Слайдеры аксессуаров elements.lightsSlider.addEventListener('input', (e) => { state.lights = parseInt(e.target.value); if (state.lights < 0) state.lights = 0; if (state.lights > 100) state.lights = 100; elements.lightsValue.textContent = state.lights; calculatePrice(); }); elements.starsSlider.addEventListener('input', (e) => { state.stars = parseInt(e.target.value); if (state.stars < 0) state.stars = 0; if (state.stars > 100) state.stars = 100; elements.starsValue.textContent = state.stars; calculatePrice(); }); elements.innerCornersSlider.addEventListener('input', (e) => { state.innerCorners = parseInt(e.target.value); if (state.innerCorners < 0) state.innerCorners = 0; if (state.innerCorners > 100) state.innerCorners = 100; elements.innerCornersValue.textContent = state.innerCorners; calculatePrice(); }); elements.outerCornersSlider.addEventListener('input', (e) => { state.outerCorners = parseInt(e.target.value); if (state.outerCorners < 0) state.outerCorners = 0; if (state.outerCorners > 100) state.outerCorners = 100; elements.outerCornersValue.textContent = state.outerCorners; calculatePrice(); }); // Выпадающий список материала elements.materialSelect.addEventListener('change', (e) => { state.material = e.target.value; updateBasePrice(); calculatePrice(); }); // radio кнопки выбора способа фиксации (взаимоисключающие) elements.fixationCheckboxes.forEach((radio) => { radio.addEventListener('change', (e) => { if (e.target.checked) { state.fixation = e.target.value; calculatePrice(); } }); }); // Чекбоксы const checkboxes = [ { id: 'multiLevel', key: 'multiLevel' }, { id: 'curved', key: 'curved' }, { id: 'arch', key: 'arch' }, { id: 'fan', key: 'fan' }, { id: 'skirt', key: 'skirt' }, { id: 'print', key: 'print' }, { id: 'demontage', key: 'demontage' }, { id: 'preparation', key: 'preparation' }, { id: 'stain', key: 'stain' } ]; checkboxes.forEach(check => { document.getElementById(check.id).addEventListener('change', (e) => { state[check.key] = e.target.checked; calculatePrice(); }); }); } // Форматирование цены function formatPrice(price) { return price.toLocaleString('ru-RU', { style: 'currency', currency: 'RUB', maximumFractionDigits: 0 }); } // Расчет стоимости function calculatePrice() { // Базовая стоимость: площадь × цена за м² let totalPrice = state.area * basePrice; // Дополнительные параметры let accessoriesCost = 0; let servicesCost = 0; let surchargesPercent = 0; let profileCost = 0; let fixationCost = 0; // Стоимость профиля profileCost = state.perimeter * getProfilePrice(); // Стоимость фиксации fixationCost = getFixationPrice(); // Стоимость аксессуаров accessoriesCost += state.lights * PRICES.accessories.light; accessoriesCost += state.stars * PRICES.accessories.star; accessoriesCost += state.innerCorners * PRICES.accessories.innerCorner; accessoriesCost += state.outerCorners * PRICES.accessories.outerCorner; if (state.fan) accessoriesCost += PRICES.accessories.fan; if (state.skirt) accessoriesCost += PRICES.accessories.skirt; if (state.print) accessoriesCost += PRICES.accessories.print; // Стоимость дополнительных услуг if (state.demontage) servicesCost += PRICES.services.demontage; if (state.preparation) servicesCost += PRICES.services.preparation; if (state.stain) servicesCost += PRICES.services.stain; // Надбавки за сложность if (state.multiLevel) surchargesPercent += PRICES.surcharges.multiLevel; if (state.curved) surchargesPercent += PRICES.surcharges.curved; if (state.arch) surchargesPercent += PRICES.surcharges.arch; // Применение надбавок if (surchargesPercent > 0) { totalPrice *= (1 + surchargesPercent); } // Итоговая стоимость totalPrice += accessoriesCost + servicesCost + profileCost + fixationCost; // Обновление отображения elements.totalPrice.textContent = formatPrice(Math.round(totalPrice)); // Анимация изменения цены elements.totalPrice.style.transform = 'scale(1.1)'; setTimeout(() => { elements.totalPrice.style.transform = 'scale(1)'; }, 200); } // Инициализация init();