diff --git a/local/components/era/calculator/class.php b/local/components/era/calculator/class.php new file mode 100644 index 0000000..d1ec624 --- /dev/null +++ b/local/components/era/calculator/class.php @@ -0,0 +1,265 @@ +iblockId = $arParams['IBLOCK_ID']; + + // Добавляем параметры для работы с ценами + if (!isset($arParams['PRICE_CODE'])) + $arParams['PRICE_CODE'] = array(); + + if (!isset($arParams['PRICE_VAT_INCLUDE'])) + $arParams['PRICE_VAT_INCLUDE'] = 'Y'; + + if (!isset($arParams['CONVERT_CURRENCY'])) + $arParams['CONVERT_CURRENCY'] = 'N'; + + if (!isset($arParams['CURRENCY_ID'])) + $arParams['CURRENCY_ID'] = ''; + + return $arParams; + } + + public function executeComponent() + { + if (!Loader::includeModule('iblock')) { + ShowError('Модуль iblock не установлен'); + return; + } + + if (!Loader::includeModule('catalog')) { + ShowError('Модуль catalog не установлен'); + return; + } + + // Проверяем, является ли запрос AJAX + $this->isAjax = $this->request->get('ajax') === 'Y'; + + // Получаем все значения для почвы + $this->arResult['SOIL_TYPES'] = $this->getPropertyEnumValues(58); + + // Получаем все значения для количества человек + $this->arResult['PEOPLE_COUNT'] = $this->getPropertyEnumValues(28); + + // Получаем значения для типа проживания + $this->arResult['LIVING_TYPES'] = $this->getPropertyEnumValues(61); + + // Получаем значения для грунтовых вод + $this->arResult['GROUND_WATER'] = $this->getPropertyEnumValues(57); + + if ($this->request->isPost() && ($this->request->getPost('calculate') === 'Y' || $this->isAjax)) { + $this->processCalculation(); + } + + if ($this->isAjax) { + $this->sendAjaxResponse(); + } else { + $this->includeComponentTemplate(); + } + } + + private function getPropertyEnumValues($propertyId) + { + $result = []; + $property_enums = CIBlockPropertyEnum::GetList( + ["SORT" => "ASC"], + ["PROPERTY_ID" => $propertyId] + ); + while($enum_fields = $property_enums->GetNext()) { + $result[$enum_fields["XML_ID"]] = [ + 'ID' => $enum_fields["ID"], + 'NAME' => $enum_fields["VALUE"], + 'XML_ID' => $enum_fields["XML_ID"] + ]; + } + return $result; + } + + private function calculateInstallationPrice($volume) + { + // Базовая стоимость установки + $basePrice = 35000; + + // Увеличиваем стоимость в зависимости от объема + $priceIncrease = floor($volume / 50) * 5000; + + $minPrice = $basePrice + $priceIncrease; + $maxPrice = $minPrice + 10000; + + return number_format($minPrice, 0, '.', ' ') . ' ₽ - ' . number_format($maxPrice, 0, '.', ' ') . ' ₽'; + } + + private function calculateVolume($request) + { + $totalVolume = 0; + + // Массив объемов для каждого прибора + $volumes = [ + 'bath' => 200, + 'toilet' => 10, + 'sink' => 20, + 'shower' => 50, + 'bidet' => 10, + 'jacuzzi' => 400, + 'washer' => 50, + 'dishwasher' => 50 + ]; + + // Проходим по каждому прибору + foreach ($volumes as $device => $volume) { + // Проверяем, включен ли прибор + if ($request->get($device) === 'Y') { + // Получаем количество приборов (1, 2 или 3) + $count = (int)$request->get($device . '_count'); + if ($count > 0 && $count <= 3) { + $totalVolume += $volume * $count; + } + } + } + + return $totalVolume; + } + + private function processCalculation() + { + $request = $this->request->getPostList(); + + // Логируем все пришедшие данные + AddMessage2Log(print_r($request->toArray(), true), 'CALC_LOG: REQUEST'); + + // Получаем объем из POST + $volume = (int)$request->get('volume'); + if ($volume <= 0) { + $volume = $this->calculateVolume($request); // fallback + } + + // Логируем рассчитанный объем + AddMessage2Log('Calculated volume: ' . $volume, 'CALC_LOG: VOLUME'); + + $soil = $request->get('soil'); + $people = $request->get('people'); + $living = $request->get('living'); + $ground_water = $request->get('ground_water'); + + // Формируем фильтр для выборки товаров + $filter = [ + 'IBLOCK_ID' => $this->iblockId, + 'ACTIVE' => 'Y' + ]; + + // Добавляем фильтр по почве если выбрано + if ($soil && isset($this->arResult['SOIL_TYPES'][$soil])) { + $filter['PROPERTY_58'] = $this->arResult['SOIL_TYPES'][$soil]['ID']; + } + + // Добавляем фильтр по количеству человек если выбрано + if ($people && isset($this->arResult['PEOPLE_COUNT'][$people])) { + $filter['PROPERTY_28'] = $this->arResult['PEOPLE_COUNT'][$people]['ID']; + } + + // Добавляем фильтр по типу проживания если выбрано + if ($living && isset($this->arResult['LIVING_TYPES'][$living])) { + $filter['PROPERTY_61'] = $this->arResult['LIVING_TYPES'][$living]['ID']; + } + + // Добавляем фильтр по грунтовым водам если выбрано + if ($ground_water && isset($this->arResult['GROUND_WATER'][$ground_water])) { + $filter['PROPERTY_57'] = $this->arResult['GROUND_WATER'][$ground_water]['ID']; + } + + // Логируем итоговый фильтр + AddMessage2Log(print_r($filter, true), 'CALC_LOG: FILTER'); + + // Добавляем фильтр по залповому сбросу + if ($volume > 0) { + $filter['>PROPERTY_SBROS_NUM'] = $volume; + } + + // Получаем товары + $elements = CIBlockElement::GetList( + ['SORT' => 'ASC'], + $filter, + false, + ['nPageSize' => 3], + ['*', 'PROPERTY_*'] + ); + + $this->arResult['ITEMS'] = []; + $prices = []; + + while ($element = $elements->GetNextElement()) { + $fields = $element->GetFields(); + $properties = $element->GetProperties(); + + // Получаем все картинки + if($fields['PREVIEW_PICTURE']) { + $fields['PREVIEW_PICTURE'] = CFile::GetPath($fields['PREVIEW_PICTURE']); + } + + // Формируем массив с полной информацией о товаре + $item = [ + 'ID' => $fields['ID'], + 'NAME' => $fields['NAME'], + 'PREVIEW_PICTURE' => $fields['PREVIEW_PICTURE'], + 'PREVIEW_TEXT' => $fields['PREVIEW_TEXT'], + 'DETAIL_PAGE_URL' => $fields['DETAIL_PAGE_URL'], + 'PRICE' => $properties['ATT_OLD_PRICE']['VALUE'], + 'PEOPLE_COUNT' => $properties['PEOPLE_COUNT']['VALUE'], + 'PERFORMANCE' => $properties['PERFORMANCE']['VALUE'], + 'RESET' => $properties['SBROS_NUM']['VALUE'], + 'POWER' => $properties['POWER']['VALUE'], + 'RATING' => $properties['REV_RATING']['VALUE'][0] + ]; + + // Добавляем цену в массив цен для расчета диапазона + if (!empty($item['PRICE'])) { + $prices[] = (float)$item['PRICE']; + } + + $this->arResult['ITEMS'][] = $item; + } + + // Логируем найденные товары + AddMessage2Log(print_r($this->arResult['ITEMS'], true), 'CALC_LOG: ITEMS'); + + // Устанавливаем диапазон цен из найденных товаров + if (!empty($prices)) { + $minPrice = min($prices); + $maxPrice = max($prices); + $this->arResult['INSTALLATION_PRICE'] = number_format($minPrice, 0, '.', ' ') . ' ₽ - ' . number_format($maxPrice, 0, '.', ' ') . ' ₽'; + } else { + $this->arResult['INSTALLATION_PRICE'] = 'Цена по запросу'; + } + + return true; + } + + private function sendAjaxResponse() + { + global $APPLICATION; + + $APPLICATION->RestartBuffer(); + + // Получаем HTML для товаров + ob_start(); + $this->includeComponentTemplate('ajax'); + $itemsHtml = ob_get_clean(); + + $response = [ + 'items' => $itemsHtml, + 'installation_price' => $this->arResult['INSTALLATION_PRICE'] + ]; + + echo json_encode($response); + die(); + } +} \ No newline at end of file diff --git a/local/components/era/calculator/templates/.default/ajax.php b/local/components/era/calculator/templates/.default/ajax.php new file mode 100644 index 0000000..f7abe97 --- /dev/null +++ b/local/components/era/calculator/templates/.default/ajax.php @@ -0,0 +1,56 @@ + +
+ + <?=$item['NAME']?> + +
+ +
/5
+ +
+ + +

+ +
+
+ +

Пользователей:

+ + +

Производительность: м³/сут

+ + +

Залповый сброс: л

+ + +

Питание:

+ +
+ +
+ +
+ + +
+
+
+ +
+

Нужен септик для бизнеса?

+
Наш менеджер свяжется с вами в ближайшее время
+
+ + + +
Нажимая кнопку «Заказать звонок», вы подтверждаете свое согласие на обработку персональных данных
+
+
+ \ No newline at end of file diff --git a/local/components/era/calculator/templates/.default/template.php b/local/components/era/calculator/templates/.default/template.php new file mode 100644 index 0000000..5ecdbf0 --- /dev/null +++ b/local/components/era/calculator/templates/.default/template.php @@ -0,0 +1,383 @@ + + +
+

Рассчитать септик онлайн

+
+ +
+

Участок, септик

+
+
+
Почва
+ +
+ +
+
Количество людей
+ +
+ +
+
Проживание
+ +
+ +
+
Глубина залегания труб
+ +
+
+
+ + +
+ +
+ +
+

Залповый сброс

+
+
+
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + + +
+
+
+ +
+

Примерная стоимость монтажа

+
+ ₽ - ₽ +
+
Точную цену можно узнать после консультации
+ +
+
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/local/components/era/html.map/.description.php b/local/components/era/html.map/.description.php new file mode 100644 index 0000000..cd6b32f --- /dev/null +++ b/local/components/era/html.map/.description.php @@ -0,0 +1,11 @@ + "HTML-карта сайта", + "DESCRIPTION" => "Автоматическая html-карта сайта с древовидной структурой.", + "ICON" => "", + "PATH" => array( + "ID" => "era" + ), +); \ No newline at end of file diff --git a/local/components/era/html.map/.parameters.php b/local/components/era/html.map/.parameters.php new file mode 100644 index 0000000..17223bc --- /dev/null +++ b/local/components/era/html.map/.parameters.php @@ -0,0 +1,6 @@ + array() +); \ No newline at end of file diff --git a/local/components/era/html.map/class.php b/local/components/era/html.map/class.php new file mode 100644 index 0000000..9c30bcc --- /dev/null +++ b/local/components/era/html.map/class.php @@ -0,0 +1,25 @@ +arResult['TREE'] = $this->getSiteTree(); + $this->includeComponentTemplate(); + } + + private function getSiteTree() + { + // TODO: Реализовать сбор структуры сайта, разделов, фильтров + // Пример: получить разделы каталога + $tree = []; + // ... + return $tree; + } +} \ No newline at end of file diff --git a/local/components/era/html.map/templates/.default/template.php b/local/components/era/html.map/templates/.default/template.php new file mode 100644 index 0000000..58cc9cb --- /dev/null +++ b/local/components/era/html.map/templates/.default/template.php @@ -0,0 +1,25 @@ + +
+

HTML-карта сайта

+ + + +

Карта сайта пуста.

+ +
\ No newline at end of file diff --git a/local/php_interface/include/components/bitrix/news/services/.description.php b/local/php_interface/include/components/bitrix/news/services/.description.php new file mode 100644 index 0000000..92e66fc --- /dev/null +++ b/local/php_interface/include/components/bitrix/news/services/.description.php @@ -0,0 +1,5 @@ + "Услуги (кастомный шаблон)", + "DESCRIPTION" => "Шаблон для компонента bitrix:news (услуги)", +); \ No newline at end of file diff --git a/local/php_interface/include/components/bitrix/news/services/style.css b/local/php_interface/include/components/bitrix/news/services/style.css new file mode 100644 index 0000000..bf00845 --- /dev/null +++ b/local/php_interface/include/components/bitrix/news/services/style.css @@ -0,0 +1,43 @@ +.services-list { + display: flex; + flex-wrap: wrap; + gap: 24px; +} +.service-item { + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 16px; + width: 300px; + box-shadow: 0 2px 8px rgba(0,0,0,0.04); + background: #fff; + display: flex; + flex-direction: column; + align-items: flex-start; +} +.service-item h2 { + font-size: 1.2em; + margin: 0 0 8px 0; +} +.service-item img { + max-width: 100%; + border-radius: 4px; + margin-bottom: 8px; +} +.service-desc { + margin-bottom: 8px; + color: #444; +} +.service-price { + font-weight: bold; + color: #1a7f37; + margin-bottom: 8px; +} +.service-item a { + margin-top: auto; + color: #1976d2; + text-decoration: none; + font-weight: 500; +} +.service-item a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/local/php_interface/include/components/bitrix/news/services/template.php b/local/php_interface/include/components/bitrix/news/services/template.php new file mode 100644 index 0000000..c2fc9bd --- /dev/null +++ b/local/php_interface/include/components/bitrix/news/services/template.php @@ -0,0 +1,21 @@ + +
+ +
+

+ + " alt=""> + +
+ +
+ +
+ Цена: +
+ + ">Подробнее +
+ +
\ No newline at end of file diff --git a/local/php_interface/include/events.php b/local/php_interface/include/events.php new file mode 100644 index 0000000..d15c28a --- /dev/null +++ b/local/php_interface/include/events.php @@ -0,0 +1,126 @@ +GetList(array("TYPE_ID" => "CONSULTATION_REQUEST")); +if (!$eventTypeResult->Fetch()) { + // Создаем тип почтового события + $eventType->Add(array( + "EVENT_NAME" => "CONSULTATION_REQUEST", + "NAME" => "Заявка на консультацию", + "LID" => "ru", + "DESCRIPTION" => "#NAME# - Имя клиента\n#PHONE# - Телефон\n#EMAIL_TO# - Email получателя" + )); +} + +// Проверяем существование шаблона +$eventMessageResult = $eventMessage->GetList( + array(), + array("TYPE_ID" => "CONSULTATION_REQUEST") +); +if (!$eventMessageResult->Fetch()) { + // Создаем шаблон почтового события + $eventMessage->Add(array( + "ACTIVE" => "Y", + "EVENT_NAME" => "CONSULTATION_REQUEST", + "LID" => SITE_ID, + "EMAIL_FROM" => "#DEFAULT_EMAIL_FROM#", + "EMAIL_TO" => "#EMAIL_TO#", + "SUBJECT" => "Новая заявка на консультацию", + "BODY_TYPE" => "html", + "MESSAGE" => ' + + + + + +

Поступила новая заявка на консультацию!

+ +

Имя клиента: #NAME#

+

Телефон: #PHONE#

+ +
+

Сообщение сгенерировано автоматически.

+ +' + )); +} + +// === Настройка почтового события для новых заказов === +$eventTypeResult = $eventType->GetList(array("TYPE_ID" => "SALE_NEW_ORDER_CUSTOM")); +if (!$eventTypeResult->Fetch()) { + // Создаем тип почтового события + $eventType->Add(array( + "EVENT_NAME" => "SALE_NEW_ORDER_CUSTOM", + "NAME" => "Новый заказ", + "LID" => "ru", + "DESCRIPTION" => "#ORDER_ID# - Номер заказа\n#ORDER_DATE# - Дата заказа\n#USER_NAME# - Имя покупателя\n#USER_PHONE# - Телефон\n#USER_EMAIL# - Email\n#PRICE# - Сумма заказа\n#CURRENCY# - Валюта\n#EMAIL# - Email получателя" + )); +} + +// Проверяем существование шаблона +$eventMessageResult = $eventMessage->GetList( + array(), + array("TYPE_ID" => "SALE_NEW_ORDER_CUSTOM") +); +if (!$eventMessageResult->Fetch()) { + // Создаем шаблон почтового события + $eventMessage->Add(array( + "ACTIVE" => "Y", + "EVENT_NAME" => "SALE_NEW_ORDER_CUSTOM", + "LID" => SITE_ID, + "EMAIL_FROM" => "#DEFAULT_EMAIL_FROM#", + "EMAIL_TO" => "#EMAIL#", + "SUBJECT" => "Новый заказ #ORDER_ID#", + "BODY_TYPE" => "html", + "MESSAGE" => ' + + + + + +

Поступил новый заказ!

+ +

Номер заказа: #ORDER_ID#

+

Дата заказа: #ORDER_DATE#

+

Имя покупателя: #USER_NAME#

+

Телефон: #USER_PHONE#

+

Email: #USER_EMAIL#

+

Сумма заказа: #PRICE# #CURRENCY#

+ +
+

Перейти к заказу в административной панели

+

Сообщение сгенерировано автоматически.

+ +' + )); +} + +// === Обработка формы консультации из футера === +if ( + $_SERVER['REQUEST_METHOD'] === 'POST' && + isset($_POST['consultation_form']) && + !empty($_POST['name']) && + !empty($_POST['phone']) +) { + CEvent::Send( + "CONSULTATION_REQUEST", + SITE_ID, + array( + "NAME" => htmlspecialchars($_POST['name']), + "PHONE" => htmlspecialchars($_POST['phone']), + "EMAIL_TO" => COption::GetOptionString("main", "email_from") + ) + ); + // Можно добавить редирект или JSON-ответ, если это ajax + if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { + header('Content-Type: application/json'); + echo json_encode(["success" => true]); + exit; + } else { + // Обычный редирект после отправки + header('Location: ' . $_SERVER['HTTP_REFERER']); + exit; + } +} \ No newline at end of file