- Универсальным: Будет работать в любой форме (BF204N, T702 и т.д.), а не только в одной.
- Структурированным: Данные (Цены/Модели) вынесем наверх, чтобы ты (или клиент) мог легко менять прайс, не копаясь в логике.
- Стильным: Вместо теней сделаем opacity (прозрачность) для неактивных полей — это тот самый минимализм.
Что нужно сделать в Tilda (Подготовка):
- Добавь блок с формой (Идеально BF204N — там поля в ряд, или любой вертикальный).
- Настрой 3 выпадающих списка (Select) и 1 скрытое поле (Hidden):
- 1 поле: Имя переменной brand. Варианты: Выбрать бренд (оставь один вариант).
- 2 поле: Имя переменной model. Варианты: — (оставь прочерк).
- 3 поле: Имя переменной problem. Варианты: —.
- 4 поле (Скрытое): Имя переменной total_price (сюда упадет итоговая сумма для CRM).
- Добавь внизу формы Текстовое поле (или используй заголовок поля), куда мы будем выводить цену красиво. Дай этому тексту класс price-display.
Твой Новый Код (Clean & Modern)
Вставляй в
T123.
HTML
<style>/* СТИЛИ */ /* Скрываем поля пока не выбран предыдущий (Минимализм) */ .t-input-group_model, .t-input-group_problem { opacity: 0.3; pointer-events: none; transition: all 0.4s ease; } /* Класс активации поля */ .is-active-input { opacity: 1 !important; pointer-events: auto !important; } /* Стиль для вывода цены */ .price-result-box { margin-top: 20px; padding: 20px; border: 1px solid #eee; background: #fafafa; border-radius: 8px; text-align: center; display: none; /* Скрыт по умолчанию */ } .price-result-title { font-size: 14px; color: #888; text-transform: uppercase; letter-spacing: 1px; } .price-result-value { font-size: 32px; font-weight: 700; color: #111; /* Твой черный цвет */ margin-top: 10px; } /* Анимация появления */ .fade-in { animation: fadeIn 0.5s; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } </style> <script>document.addEventListener("DOMContentLoaded", function() { // --- БАЗА ДАННЫХ (ПРАЙС) --- // Формат: Бренд -> Модель -> [Услуга, Цена] const repairData = { "Apple": { "iPhone 11": [ { name: "Замена дисплея (Original)", price: 8500 }, { name: "Замена дисплея (Копия)", price: 4500 }, { name: "Замена АКБ", price: 3500 } ], "iPhone 12 / 12 Pro": [ { name: "Замена дисплея (Original)", price: 12000 }, { name: "Замена стекла", price: 6000 }, { name: "Ремонт FaceID", price: 4000 } ], "iPhone 13": [ { name: "Замена дисплея (Original)", price: 18000 }, { name: "Замена заднего стекла", price: 7000 } ] }, "Samsung": { "Galaxy S21": [ { name: "Замена экрана", price: 14000 }, { name: "Замена разъема", price: 2500 } ], "Galaxy A52": [ { name: "Замена экрана", price: 6000 }, { name: "Прошивка", price: 1500 } ] }, "Xiaomi": { "Redmi Note 10": [ { name: "Замена модуля", price: 4500 }, { name: "Чистка динамика", price: 1000 } ] } }; // --- ЛОГИКА --- // Находим поля по именам переменных Tilda const brandSelect = document.querySelector('select[name="brand"]'); const modelSelect = document.querySelector('select[name="model"]'); const problemSelect = document.querySelector('select[name="problem"]'); const hiddenInput = document.querySelector('input[name="total_price"]'); // Скрытое поле // Находим контейнеры полей для блокировки const modelGroup = modelSelect.closest('.t-input-group'); const problemGroup = problemSelect.closest('.t-input-group'); // Создаем блок для вывода цены (если его нет в дизайне, создаем программно) // Ищем кнопку отправки, чтобы вставить цену ПЕРЕД ней const submitBtn = document.querySelector('.t-form__submit'); const priceBox = document.createElement('div'); priceBox.className = 'price-result-box'; priceBox.innerHTML = ` <div class="price-result-title">Стоимость ремонта:</div> <div class="price-result-value">0 ₽</div> <div style="font-size:12px; color:#999; margin-top:5px;">Запчасть + Работа</div> `; if(submitBtn) { submitBtn.parentNode.insertBefore(priceBox, submitBtn); } // Инициализация: Заполняем Бренды function initBrands() { brandSelect.innerHTML = '<option value="">Выберите бренд</option>'; for (let brand in repairData) { let option = document.createElement('option'); option.value = brand; option.text = brand; brandSelect.add(option); } // Добавляем классы идентификаторы для CSS modelGroup.classList.add('t-input-group_model'); problemGroup.classList.add('t-input-group_problem'); } initBrands(); // 1. ПРИ ВЫБОРЕ БРЕНДА brandSelect.addEventListener('change', function() { const selectedBrand = this.value; // Сброс зависимых полей modelSelect.innerHTML = '<option value="">Выберите модель</option>'; problemSelect.innerHTML = '<option value="">Выберите проблему</option>'; problemGroup.classList.remove('is-active-input'); priceBox.style.display = 'none'; if (selectedBrand && repairData[selectedBrand]) { // Заполняем Модели for (let model in repairData[selectedBrand]) { let option = document.createElement('option'); option.value = model; option.text = model; modelSelect.add(option); } // Разблокируем поле Модели modelGroup.classList.add('is-active-input'); } else { modelGroup.classList.remove('is-active-input'); } }); // 2. ПРИ ВЫБОРЕ МОДЕЛИ modelSelect.addEventListener('change', function() { const selectedBrand = brandSelect.value; const selectedModel = this.value; // Сброс проблем problemSelect.innerHTML = '<option value="">Выберите проблему</option>'; priceBox.style.display = 'none'; if (selectedBrand && selectedModel) { const services = repairData[selectedBrand][selectedModel]; // Заполняем Услуги services.forEach(service => { let option = document.createElement('option'); option.value = service.name; // В value пишем название option.setAttribute('data-price', service.price); // Цену прячем в атрибут option.text = service.name; problemSelect.add(option); }); // Разблокируем поле Проблемы problemGroup.classList.add('is-active-input'); } else { problemGroup.classList.remove('is-active-input'); } }); // 3. ПРИ ВЫБОРЕ ПРОБЛЕМЫ (ФИНАЛ) problemSelect.addEventListener('change', function() { const selectedOption = this.options[this.selectedIndex]; const price = selectedOption.getAttribute('data-price'); if (price) { // Анимация показа цены priceBox.style.display = 'block'; priceBox.classList.add('fade-in'); // Форматируем цену (12000 -> 12 000) const formattedPrice = parseInt(price).toLocaleString('ru-RU'); priceBox.querySelector('.price-result-value').textContent = formattedPrice + ' ₽'; // Записываем данные в скрытое поле для заявки // Формат: iPhone 12 / Замена стекла / 6000р const finalString = `${brandSelect.value} - ${modelSelect.value}: ${selectedOption.value} (Цена: ${formattedPrice}р)`; hiddenInput.value = finalString; // Перезапуск анимации setTimeout(() => priceBox.classList.remove('fade-in'), 500); } else { priceBox.style.display = 'none'; } }); }); </script>
В чем кайф этой версии:
- JSON-структура (repairData): Смотри, как легко теперь править прайс. Это просто вложенный список. Хочешь добавить Xiaomi? Просто допиши строку.
- UX "Step-by-Step": Поля Модель и Проблема сначала полупрозрачные и неактивные (opacity: 0.3). Они "загораются" только когда выберешь предыдущий пункт. Это ведет пользователя за руку.
- Авто-создание блока цены: Скрипт сам находит кнопку "Отправить" и рисует над ней красивый блок с итоговой ценой. Тебе не надо верстать его в Zero.
- Скрытое поле: Скрипт сам собирает строку "Samsung Galaxy S21: Замена экрана (Цена: 14 000р)" и кладет её в hiddenInput. В заявке ты получишь полную инфу, а не разрозненные куски.
Пробуй внедрять. Если нужно подкорректировать стили (например, сделать шрифт цены неоновым под твой стиль) — пиши, поправим CSS.