Загрузил проект на гит сурс
@@ -0,0 +1,15 @@
|
||||
RewriteEngine On
|
||||
Options -MultiViews
|
||||
|
||||
# 1) /index.html -> / (только при прямом запросе клиента)
|
||||
RewriteCond %{THE_REQUEST} \s/+index\.html(?:[\s?]|$) [NC]
|
||||
RewriteRule ^index\.html$ / [R=301,L,NC]
|
||||
|
||||
# 2) /page.html -> /page (только при прямом запросе клиента)
|
||||
RewriteCond %{THE_REQUEST} \s/+(prices|portfolio|reviews|privacy|requisites)\.html(?:[\s?]|$) [NC]
|
||||
RewriteRule ^(prices|portfolio|reviews|privacy|requisites)\.html$ /$1 [R=301,L,NC]
|
||||
|
||||
# 3) /page или /page/ -> /page.html (внутренний роутинг без редиректа)
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(prices|portfolio|reviews|privacy|requisites)/?$ $1.html [L,NC]
|
||||
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 699 KiB |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="50" fill="#4f6fa8" />
|
||||
<circle cx="50" cy="50" r="20" fill="none" stroke="#ffffff" stroke-width="10" />
|
||||
<line x1="50" y1="20" x2="50" y2="80" stroke="#ffffff" stroke-width="10" stroke-linecap="round" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 308 B |
|
After Width: | Height: | Size: 705 KiB |
|
After Width: | Height: | Size: 591 KiB |
|
After Width: | Height: | Size: 665 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 602 KiB |
|
After Width: | Height: | Size: 663 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 622 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 625 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 579 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 611 KiB |
|
After Width: | Height: | Size: 609 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 428 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 309 KiB |
|
After Width: | Height: | Size: 454 KiB |
|
After Width: | Height: | Size: 309 KiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 444 KiB |
|
After Width: | Height: | Size: 734 KiB |
|
After Width: | Height: | Size: 869 KiB |
|
After Width: | Height: | Size: 647 KiB |
@@ -0,0 +1,184 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Отделочные и малярные работы в Санкт-Петербурге: черновая и чистовая отделка, электрика и сантехника.">
|
||||
<title>Фриз | Отделочные работы в Санкт-Петербурге</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "LocalBusiness",
|
||||
"@id": "https://frieze-spb.ru/#business",
|
||||
"name": "Фриз",
|
||||
"legalName": "ИП Погребнякова Ольга Юрьевна",
|
||||
"url": "https://frieze-spb.ru/",
|
||||
"image": "https://frieze-spb.ru/image/logo-test.jpg",
|
||||
"telephone": "+7-921-741-26-46",
|
||||
"description": "Отделочные и малярные работы в Санкт-Петербурге и Ленинградской области: черновая и чистовая отделка, электрика и сантехника.",
|
||||
"address": {
|
||||
"@type": "PostalAddress",
|
||||
"addressLocality": "Санкт-Петербург",
|
||||
"addressRegion": "Санкт-Петербург",
|
||||
"addressCountry": "RU"
|
||||
},
|
||||
"areaServed": [
|
||||
{
|
||||
"@type": "City",
|
||||
"name": "Санкт-Петербург"
|
||||
},
|
||||
{
|
||||
"@type": "AdministrativeArea",
|
||||
"name": "Ленинградская область"
|
||||
}
|
||||
],
|
||||
"openingHoursSpecification": [
|
||||
{
|
||||
"@type": "OpeningHoursSpecification",
|
||||
"dayOfWeek": [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
],
|
||||
"opens": "10:00",
|
||||
"closes": "18:00"
|
||||
}
|
||||
],
|
||||
"sameAs": [
|
||||
"https://vk.com/ya_lo_ya"
|
||||
],
|
||||
"priceRange": "₽₽",
|
||||
"hasOfferCatalog": {
|
||||
"@type": "OfferCatalog",
|
||||
"name": "Услуги",
|
||||
"itemListElement": [
|
||||
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Черновые отделочные работы" } },
|
||||
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Чистовые отделочные работы" } },
|
||||
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Электромонтажные работы" } },
|
||||
{ "@type": "Offer", "itemOffered": { "@type": "Service", "name": "Сантехнические работы" } }
|
||||
]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<section class="hero reveal" id="hero">
|
||||
<img src="" alt="" class="hero__bg" id="heroBg" aria-hidden="true" style="display: none;">
|
||||
<div class="container">
|
||||
<h1>Отделочные малярные работы<br>в Санкт-Петербурге</h1>
|
||||
<p>
|
||||
Работаем в Санкт-Петербурге с 2009 года, чаще ведем объекты по дизайн-проектам, но беремся и за более
|
||||
простые варианты работ. Мы небольшая команда, специализирующаяся на малярных работах, поэтому
|
||||
хорошо знаем все нюансы и доводим все до идеального состояния
|
||||
</p>
|
||||
<a href="#contact" class="btn btn--primary">Оставить заявку</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="services section reveal" id="services">
|
||||
<div class="container">
|
||||
<h2>Услуги</h2>
|
||||
<div class="services__grid">
|
||||
<a class="card card--service" href="prices.html#chernovye-otdelochnye-raboty">
|
||||
<h3>Черновые отделочные работы</h3>
|
||||
<p>Стяжки, штукатурка, ГКЛ и подготовка поверхностей под чистовую отделку</p>
|
||||
<span class="card__link">Смотреть цены</span>
|
||||
</a>
|
||||
<a class="card card--service" href="prices.html#chistovye-otdelochnye-raboty">
|
||||
<h3>Чистовые отделочные работы</h3>
|
||||
<p>Покраска, обои, плитка, напольные покрытия и финишная отделка</p>
|
||||
<span class="card__link">Смотреть цены</span>
|
||||
</a>
|
||||
<a class="card card--service" href="prices.html#elektromontazhnye-raboty">
|
||||
<h3>Электромонтажные работы</h3>
|
||||
<p>Разводка кабеля, розетки, освещение, щиты и сопутствующий монтаж</p>
|
||||
<span class="card__link">Смотреть цены</span>
|
||||
</a>
|
||||
<a class="card card--service" href="prices.html#santehnicheskie-raboty">
|
||||
<h3>Сантехнические работы</h3>
|
||||
<p>Водоснабжение, канализация и установка сантехнических приборов</p>
|
||||
<span class="card__link">Смотреть цены</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="gallery section reveal" id="gallery">
|
||||
<div class="container">
|
||||
<h2>Примеры работ</h2>
|
||||
<div class="gallery__grid">
|
||||
<article class="work-card" data-images='["image/6.jpg", "image/3.jpg", "image/1.jpg"]'>
|
||||
<img src="image/6.jpg" alt="До и после: гостиная">
|
||||
<div class="work-card__label">До/После — Гостиная</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/4.jpg", "image/7.jpg", "image/2.jpg"]'>
|
||||
<img src="image/4.jpg" alt="До и после: кухня">
|
||||
<div class="work-card__label">До/После — Кухня</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/5.jpg", "image/1.jpg", "image/6.jpg"]'>
|
||||
<img src="image/5.jpg" alt="До и после: спальня">
|
||||
<div class="work-card__label">До/После — Спальня</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/2.jpg", "image/3.jpg", "image/7.jpg", "image/4.jpg"]'>
|
||||
<img src="image/2.jpg" alt="До и после: ванная">
|
||||
<div class="work-card__label">До/После — Ванная</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="contact section reveal" id="contact">
|
||||
<div class="container">
|
||||
<h2>Оставить заявку</h2>
|
||||
<form class="contact-form" id="contactForm">
|
||||
<label>
|
||||
<span>Имя</span>
|
||||
<input type="text" name="name" placeholder="Ваше имя" maxlength="80" pattern="[A-Za-zА-Яа-яЁё\\s-]{2,80}" title="Используйте только буквы, пробелы и дефис (2-80 символов)" autocomplete="name" required>
|
||||
</label>
|
||||
<label>
|
||||
<span>Телефон</span>
|
||||
<input type="tel" name="phone" placeholder="+7 (___) ___-__-__" required>
|
||||
</label>
|
||||
<div style="position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden;" aria-hidden="true">
|
||||
<label for="contactFaxField">Факс</label>
|
||||
<input type="text" id="contactFaxField" name="contact_fax" tabindex="-1" autocomplete="new-password">
|
||||
</div>
|
||||
<input type="hidden" name="started_at" id="contactStartedAt" value="">
|
||||
<label class="contact-form__consent">
|
||||
<span class="contact-form__consent-inner">
|
||||
<input type="checkbox" name="consent" value="1" id="consentCheckbox">
|
||||
<span>Я даю согласие на обработку персональных данных в соответствии с <a href="privacy.html" target="_blank" rel="noopener noreferrer">Политикой обработки персональных данных</a></span>
|
||||
</span>
|
||||
</label>
|
||||
<button class="btn btn--primary" type="submit">Отправить</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<div class="portfolio-modal" id="portfolioModal" aria-hidden="true">
|
||||
<div class="portfolio-modal__overlay" data-close></div>
|
||||
<div class="portfolio-modal__container">
|
||||
<button class="portfolio-modal__close" data-close aria-label="Закрыть">×</button>
|
||||
<div class="portfolio-modal__track" id="portfolioTrack"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Портфолио выполненных отделочных работ в Санкт-Петербурге.">
|
||||
<title>Фриз | Портфолио — Санкт-Петербург</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/portfolio">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<section class="section reveal">
|
||||
<div class="container">
|
||||
<h1>Портфолио работ</h1>
|
||||
<p>Несколько примеров реализованных объектов в Санкт-Петербурге и Ленобласти</p>
|
||||
|
||||
<div class="gallery__grid">
|
||||
<article class="work-card" data-images='["image/1.jpg", "image/4.jpg", "image/7.jpg"]'>
|
||||
<img src="image/1.jpg" alt="Ремонт студии в центре СПб">
|
||||
<div class="work-card__label">Студия, 28 м² — косметический ремонт за 18 дней</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/2.jpg", "image/5.jpg", "image/3.jpg", "image/6.jpg"]'>
|
||||
<img src="image/2.jpg" alt="Капитальный ремонт двухкомнатной квартиры">
|
||||
<div class="work-card__label">2-комнатная, 54 м² — капитальный ремонт под ключ</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/7.jpg", "image/1.jpg", "image/5.jpg"]'>
|
||||
<img src="image/7.jpg" alt="Отделка ванной комнаты">
|
||||
<div class="work-card__label">Ванная, 4.2 м² — плитка, сантехника, скрытые люки</div>
|
||||
</article>
|
||||
<article class="work-card" data-images='["image/3.jpg", "image/6.jpg", "image/2.jpg"]'>
|
||||
<img src="image/3.jpg" alt="Ремонт кухни в старом фонде">
|
||||
<div class="work-card__label">Кухня в старом фонде — подготовка стен и новая электрика</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<div class="portfolio-modal" id="portfolioModal" aria-hidden="true">
|
||||
<div class="portfolio-modal__overlay" data-close></div>
|
||||
<div class="portfolio-modal__container">
|
||||
<button class="portfolio-modal__close" data-close aria-label="Закрыть">×</button>
|
||||
<div class="portfolio-modal__track" id="portfolioTrack"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,769 @@
|
||||
window.PRICES_DATA = [
|
||||
{
|
||||
title: "Демонтажные работы",
|
||||
children: [
|
||||
{
|
||||
title: "Полы",
|
||||
items: [
|
||||
{ name: "Демонтаж плинтуса", price: "от 99 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Удаление слоев из керамзита, песка", price: "от 156 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устранение мелких дифектов пола", price: "от 167 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж ламината, паркетной доски", price: "от 173 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж паркета штучного", price: "от 332 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж паркета щитового", price: "от 332 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж деревянных полов", price: "от 398 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж линолеума, ковролина на клею", price: "от 216 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж линолеума, ковролина", price: "от 138 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж фанеры, ДВП", price: "от 218 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж лаг", price: "от 233 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж подложки из ДВП обмазанной битумной мастикой", price: "от 294 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж покрытия из битумной мастики", price: "от 375 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Расчистка пола от засыпки и шумоизоляции", price: "от 294 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж плиточного клея", price: "от 438 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Расшивка плиточных швов (пол)", price: "от 381 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж плинтуса из плитки", price: "от 449 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж порога из плитки", price: "от 596 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж плитки", price: "от 449 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж бетонного бортика", price: "от 953 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж стяжки до 4 см", price: "от 597 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стяжки до 6 см", price: "от 747 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Разборка гидроизоляции", price: "от 261 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Сухая уборка полов под метлу, щетку", price: "от 90 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Ремонт дощатых полов (протяжка саморезами)", price: "от 383 ₽/м²", amount: "1", unit: "м²" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Стены",
|
||||
items: [
|
||||
{ name: "Демонтаж пластикового уголка", price: "от 80 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Снятие обоев (стены)", price: "от 188 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Снятие многослойных трудноотделяемых обоев", price: "от 419 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Снятие побелки", price: "от 336 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка краски со стен ВЭ", price: "от 294 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка масляной краски со стен", price: "от 576 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка стен от \"жидких\" обоев", price: "от 234 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка стен от шпаклевки", price: "от 291 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Расшивка трещин/рустов", price: "от 333 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Насечка стен", price: "от 188 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Расшивка плиточных швов (стены)", price: "от 383 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж керамической плитки", price: "от 449 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Отбивка плиточного клея", price: "от 438 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Ошкуривание поверхности стен", price: "от 263 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж панелей ПВХ (без каркаса)", price: "от 117 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж облицовки стен из ДСП, вагонки", price: "от 366 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж панелей ПВХ (с каркасом)", price: "от 186 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж обшивки стен из ГКЛ на металлокарскасе", price: "от 447 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж \"дранки\" со стен", price: "от 525 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж утеплителя", price: "от 285 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Отбивка штукатурки со стен", price: "от 522 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж деревянных стен", price: "от 1 148 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж подоконного блока", price: "от 6 818 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж стен (перегородок) в 1/2 кирпич", price: "от 1 718 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стен (перегородок) в 1 кирпич", price: "от 2 153 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стен (перегородок) в 2 кирпича", price: "от 2 768 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стен из гипсолита, ПГП", price: "от 924 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стен из пеноблока", price: "от 966 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж стен из ацеида, ГВЛ, ГКЛ", price: "от 747 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж бетонных стен толщиной до 80 мм", price: "от 5 798 ₽/м²", amount: "1", unit: "м²" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Откосы",
|
||||
items: [
|
||||
{ name: "Демонтаж уголка с откосов, углов", price: "от 50 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж сэндвич панелей", price: "от 98 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Обрезка пены с откосов, углов", price: "от 51 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Очистка откосов, углов от шпаклевки", price: "от 294 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Очистка от краски откосов, углов", price: "от 279 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж бетонного подоконника", price: "от 1 089 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Отбивка штукатурки с откосов, углов", price: "от 381 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж откосов из ГКЛв", price: "от 210 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Потолки",
|
||||
items: [
|
||||
{ name: "Демонтаж лепнины без сохранения", price: "от 171 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж потолочного плинтуса", price: "от 138 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж подвесных потолков ГКЛ", price: "от 488 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж реечного потолка", price: "от 234 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж кассетного подвесного потолка (армстронг)", price: "от 177 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж панелей кассетного потолка без профиля (армстронг)", price: "от 98 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж потолочных панелей (на клею)", price: "от 156 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж натяжного потолка (включая профиль)", price: "от 180 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Снятие полистирольных плиток", price: "от 171 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж потолков из ацеида, гипсолита", price: "от 923 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка от побелки", price: "от 441 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка от краски ВЭ", price: "от 351 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка потолков от масляной краски", price: "от 936 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Снятие обоев (потолок)", price: "от 218 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Снятие многослойных трудноотделяемых обоев", price: "от 486 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Очистка потолка от шпаклевки", price: "от 426 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Отбивка штукатурки", price: "от 486 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Расшивка трещин рустов", price: "от 312 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Двери, окна",
|
||||
items: [
|
||||
{ name: "Демонтаж наличников", price: "от 98 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж дверной ручки / замка", price: "от 318 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж бетонного подоконника", price: "от 1 089 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж деревянной межкомнатной двери", price: "от 480 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж деревянной межкомнатной двери с сохранением", price: "от 1 332 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж наличников (с сохранением)", price: "от 482 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Снятие деревянной двери с петель", price: "от 383 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж металлической двери", price: "от 2 042 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Очистка наличников или дверной коробки от краски", price: "от 848 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж откосов из сэндвич /ПВХ панелей", price: "от 165 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж штукатурных откосов", price: "от 381 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж оконного блока (без сохранения)", price: "от 822 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж оконного блока (с сохранением)", price: "от 1 275 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж арки дверного проема (ГКЛ, дерево)", price: "от 1 212 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж подоконника", price: "от 455 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Очистка окна от краски", price: "от 1 872 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Прочие",
|
||||
items: [
|
||||
{ name: "Демонтаж встроенных шкафов и полок, антресолей", price: "от 1 122 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж карнизов", price: "от 284 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж вентиляционной решетки", price: "от 117 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж воздуховодов", price: "от 273 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Срез металлоконструкций", price: "от 117 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Сантехника",
|
||||
items: [
|
||||
{ name: "Демонтаж смесителя", price: "от 683 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж душевой кабины (без сохранения)", price: "от 1 164 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж душевой кабины (с сохранением)", price: "от 4 731 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж ванны (без сохранения)", price: "от 1 347 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж ванны (с сохранением)", price: "от 2 109 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж чугунной ванны (без сохранения)", price: "от 1 913 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж чугунной ванны (с сохранением)", price: "от 4 916 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж сантехнического шкафа", price: "от 774 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Демонтаж раковины", price: "от 674 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонной мойки", price: "от 773 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж унитаза", price: "от 966 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж стиральной машины", price: "от 966 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж полотенцесушителя (электро)", price: "от 525 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж водонагревателя", price: "от 1 260 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кранов вводных, счетчиков", price: "от 186 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кранов шаровых", price: "от 168 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж труб в/с", price: "от 284 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж труб канализации", price: "от 450 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Расчеканка чугунных труб", price: "от 5 168 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж радиатора", price: "от 773 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Очистка стояка от старой краски до 3м", price: "от 1 868 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Очистка радиатора от краски ( до 5 секций)", price: "от 1 934 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Очистка радиатора каждая следующая секция", price: "от 653 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кабины совмещенного санузла (из ацеида)", price: "от 15 780 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кабины раздельного санузла (из ацеида)", price: "от 18 780 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж бетонного пола сан тех кабины", price: "от 14 793 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Электрика",
|
||||
items: [
|
||||
{ name: "Демонтаж панели электроточки", price: "от 74 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж розеток и выключателей", price: "от 263 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж светильников", price: "от 186 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж люстры", price: "от 383 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж электрокабеля", price: "от 39 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Демонтаж автоматического выключателя", price: "от 186 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж электрического щита", price: "от 1 418 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пробивка отверстия в стене (бетон) ф 16-20", price: "от 1 283 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пробивка отверстия в стене (кирпич) ф 16-20", price: "от 714 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пробивка отверстия в стене (пеноблок, пазогребневый блок) ф 16-20", price: "от 578 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Штробление ниши под элщит до 12 модулей (бетон)", price: "от 6 381 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Штробление ниши под элщит 12-36 модулей (бетон)", price: "от 9 668 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Штробление ниши под элщит до 12 модулей (кирпич/Пено блок/пгп)", price: "от 2 691 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Штробление ниши под элщит 12-36 модулей (кирпич/Пено блок/пгп)", price: "от 5 343 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Черновые отделочные работы",
|
||||
children: [
|
||||
{
|
||||
title: "Полы",
|
||||
items: [
|
||||
{ name: "Грунтовка пола", price: "от 98 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка пола (второй и последующие слои)", price: "от 98 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка пола (бетон контактом)", price: "от 128 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Обработка анти плесенью(пол)", price: "от 206 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляция пола пленкой ПВХ", price: "от 147 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляция пола (смесью водостоп или жидким стеклом)", price: "от 461 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляция рулонными материалами", price: "от 642 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка пароизолирующих материалов", price: "от 186 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляционная лента (по периметру стен)", price: "от 176 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж демпферной ленты (кромочной ленты)", price: "от 147 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Укрытие пленкой пола", price: "от 81 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Подсыпка керамзита", price: "от 321 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка сетки (для стяжки)", price: "от 177 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Железнение стяжки", price: "от 186 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство стяжки по маякам до 4 см", price: "от 698 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство стяжки по маякам до 6 см", price: "от 1 049 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство стяжки по маякам свыше 6 см", price: "от 1 193 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство наливных полов до 3 см", price: "от 683 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Финишное выравнивание стяжки наливным полом", price: "от 533 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Заливка рустов после проведения демонтажа перегородок", price: "от 630 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство \"сухой стяжки\"", price: "от 2 310 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство \"полусухой\" (механизированной стяжки)", price: "от 2 775 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство деревянной обрешетки пола", price: "от 638 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка деревянных лаг", price: "от 533 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство тепло/звукоизоляции(полы)", price: "от 353 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство дощатых полов по лагам", price: "от 759 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка фанеры на дощатый пол", price: "от 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка фанеры на бетон", price: "от 863 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Распил фанеры", price: "от 90 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шлифовка фанеры", price: "от 332 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка ДВП", price: "от 399 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Временная застилка полов оргалитом", price: "от 90 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство подиума с обшивкой фанерой до 10 см сложной формы", price: "от 3 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Добавление фиброволокна в стяжку пола", price: "от 72 ₽/м²", amount: "1", unit: "м²" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Стены",
|
||||
items: [
|
||||
{ name: "Кирпичная кладка в 1/2 кирпича (черновой кирпич)", price: "от 1 688 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кирпичная кладка в 1 кирпич (черновой кирпич)", price: "от 2 223 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кирпичная кладка в 1 кирпич (облицовочный кирпич)", price: "от 4 440 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кирпичная кладка в 1/2 кирпича (облицовочный кирпич)", price: "от 3 375 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кладка стен из Пеноблоков", price: "от 1 718 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кладка перегородок из шлакоблоков", price: "от 1 881 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Кладка перегородок из пазогребневых блоков", price: "от 1 763 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Заужение дверного проема путем наращивания торца стен из ГКЛ до 50 см", price: "от 2 798 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Расширение дверного проема из кирпича,пазогреб./Пеноблоков до 10 см ( с одной стороны)", price: "от 1 518 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Расширение дверного проема бетонного до 80 мм", price: "от 7 823 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Подготовка дверного проема под скрытую дверь", price: "от 6 750 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Армирование проемов арматурой (с грунтовкой арматуры)", price: "от 891 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Армирование проемов уголком (с грунтовкой уголка)", price: "от 1 079 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж металлической штукатурной сетки (на дюбели)", price: "от 488 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж штукатурной сетки на стенах", price: "от 261 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Герметизация стыков, швов монтажной пеной", price: "от 186 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Герметизация стыков, швов силиконом", price: "от 675 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж отражающей теплоизоляции (Пенофол)", price: "от 201 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство теплоизоляции стен пеноплексом", price: "от 891 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство звукоизоляции стен системой ЗИПС вектор", price: "от 1 700 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство пароизоляции(стен)", price: "от 152 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Окраска металических деталей до 100мм", price: "от 180 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство тепло/звукоизоляции стен минеральной ватой", price: "от 480 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство перегородок из ГКЛ в 1 слой", price: "от 2 100 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство перегородок из ГКЛ в 2 слоя", price: "от 2 468 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Усиление ГКЛ перегородки ОСБ/фанерой", price: "от 975 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство ниш, ступеней из ГКЛ", price: "от 3 291 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство коробов из ГКЛ", price: "от 2 768 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство криволинейных коробов из ГКЛ на стенах", price: "от 3 960 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство ниш, ступеней из ГКЛ сложной формы", price: "от 4 125 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство арки из ГКЛ", price: "от 5 400 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Выравнивание стен листами ГКЛ", price: "от 941 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Выравнивание стен листами ГКЛ (1 слой) с устройством каркаса", price: "от 1 650 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Выравнивание стен листами ГКЛ (2 слоя) с устройством каркаса", price: "от 1 875 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство конструкции ниши ГКЛ с полками на металлокаркасе", price: "от 5 835 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Грунтовка стен", price: "от 98 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка стен (второй и последующие слои )", price: "от 98 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка стен (бетонконтактом)", price: "от 168 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Противогрибковая обработка стен спец. составом", price: "от 255 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляция (смесью водостоп или жидким стеклом)", price: "от 461 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен простая (под правило)", price: "от 656 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен по маякам до 3 см гипсовой смесью", price: "от 984 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен по маякам до 5 см гипсовой смесью", price: "от 1 134 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен по маякам свыше 5 см гипсовой смесью", price: "от 1 434 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен по маякам до 3 см цементной смесью", price: "от 1 284 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка стен по маякам до 5 см цементной смесью", price: "от 1 434 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Протяжка углов штукатуркой", price: "от 372 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Протягивание штукатуркой углов, зон плинтусов, потолков (до 30 см)", price: "от 428 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка малярного уголка, перфорированного", price: "от 186 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Нанесение малярной сетки", price: "от 180 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Базовая шпаклевка стен (с ошкуриванием)", price: "от 488 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Сплошная шпаклевка в 1 слой (с ошкуриванием)", price: "от 548 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка стен под оклейку обоями (с ошкуриванием)", price: "от 825 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Финишная шпаклевка стен под окраску (2 слоя с ошкуриванием)", price: "от 1 200 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка стен ГКЛ под оклейку обоями (с ошкуриванием)", price: "от 870 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Финишная Шпаклевка стен ГКЛ под окраску (2 слоя с ошкуриванием)", price: "от 900 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка коробов, ниш", price: "от 780 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Ошкуривание поверхности стен", price: "от 480 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Поклейка стеклохолста", price: "от 435 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство ниш глубиной до 7 см в кирпичных стенах", price: "от 2 250 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство деревянной обрешетки стены", price: "от 518 ₽/м²", amount: "1", unit: "м²" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Откосы",
|
||||
items: [
|
||||
{ name: "Грунтовка откосов, углов", price: "от 98 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка штукатурных уголков ( перфорированных)", price: "от 188 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штукатурка откосов до 40 см, углов", price: "от 683 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штукатурка откосов от 40 до 60 см, углов", price: "от 713 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штукатурка откосов арочных", price: "от 1 193 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Утепление откосов", price: "от 171 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Запенивание стыков", price: "от 189 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство откосов из ГКЛ", price: "от 1 238 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Оклейка стеклохолстом / малярной сеткой откосов", price: "от 323 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шпаклевка откосов, углов", price: "от 870 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Формирование дверного проема", price: "от 2 250 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шпаклевка откосов под окраску", price: "от 870 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Потолки",
|
||||
items: [
|
||||
{ name: "Грунтовка потолков", price: "от 150 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка потолков второй и последующие слои", price: "от 150 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Грунтовка потолков бетонконтактом", price: "от 225 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Гидроизоляция потолков", price: "от 600 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Обработка анти плесенью(потолок)", price: "от 294 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж металлической штукатурной сетки на потолке", price: "от 563 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка потолков простая (под провило)", price: "от 794 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка улучшенная до 1 см гипсовой смесью", price: "от 987 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Штукатурка потолков по маякам до 3 см гипсовой смесью", price: "от 1 265 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Заделка трещин рустов", price: "от 213 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство теплоизоляции пеноплексом", price: "от 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство тепло/звукоизоляции минеральной ватой", price: "от 938 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство шумоизоляционного мата на потолоке", price: "от 1 350 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство пароизоляции", price: "от 215 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство деревянной обрешетки", price: "от 555 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков из ГКЛ ( с устройством каркаса)", price: "от 2 475 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков из ГКЛ в 2 слоя ( с устройством каркаса)", price: "от 2 918 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство коробов из ГКЛ на потолке", price: "от 3 218 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство коробов из ГКЛ на потолке с нишей для скрытой подсветки", price: "от 3 683 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство потолков из ГКЛ в 2 уровня прямолинейного", price: "от 3 975 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков из ГКЛ в 2 уровня криволинейного", price: "от 4 860 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж ниши для парящего потолка из гипсокартона", price: "от 3 683 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж полки из ГКЛ для скрытой подсветки", price: "от 2 468 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж ниши из ГКЛ для скрытого карниза", price: "от 1 853 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство закладной на потолке", price: "от 300 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство криволинейных коробов из ГКЛ на потолке", price: "от 4 215 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка уголков перфорированных арочных", price: "от 338 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка уголков перфорированных", price: "от 263 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Проклейка швов ГКЛ серпянкой/малярной лентой", price: "от 188 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Поклейка стеклохолста(потолок)", price: "от 428 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж малярной сетки / серпянки", price: "от 188 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Сплошная шпаклевка в один слой", price: "от 563 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Базовая шпаклевка (с ошкуриванием)", price: "от 645 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка потолков в два слоя под обои", price: "от 786 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка потолков под покраску", price: "от 1 500 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка ГКЛ под оклейку обоями (с ошкуриванием)", price: "от 900 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Шпаклевка ГКЛ под окраску (2 слоя с ошкуриванием)", price: "от 1 800 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Малярные работы по нише для закарнизной конструкции (штукатурка, грунтовка, шпаклевка, окраска", price: "от 1 500 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шпаклевка криволинейного участка шириной до 250 мм", price: "от 1 011 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шпаклевка коробов, ниш", price: "от 828 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Шпаклевка полок для скрытой подсветки", price: "от 602 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Оклеивание потолков флизелином под окраску", price: "от 593 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Ошкуривание поверхности потолка", price: "от 263 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж фальш балки на потолок", price: "от 1 431 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Грунтовка коробов из ГКЛ", price: "от 83 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Чистовые отделочные работы",
|
||||
children: [
|
||||
{
|
||||
title: "Полы",
|
||||
items: [
|
||||
{ name: "Облицовка плиткой пола", price: "от 2 588 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой гексагон", price: "от 3 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Подрезка керамической плитки", price: "от 423 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка плиткой пола с декоративными вставками", price: "от 2 784 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой пола по диагонали", price: "от 3 488 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой пола елочкой", price: "от 4 266 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой пола \"панно\"", price: "от 3 831 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка мозаикой, мелкой плиткой (с затиркой)", price: "от 4 283 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиточным бордюром (с затиркой)", price: "от 1 281 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка плиткой менее 300х300", price: "от 3 218 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка пола разноразмерной плиткой", price: "от 3 159 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка керамогранитом по диагонали", price: "от 3 986 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка керамогранитом до 600 мм по одной стороне", price: "от 3 459 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка керамогранитом до 1200 мм по одной стороне", price: "от 4 838 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка Крупноформатным керамогранитом", price: "от 9 915 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Подрезка керамогранита до 600 мм", price: "от 782 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка керамогранита до 1200 мм", price: "от 1 359 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка керамогранита крупноформатного", price: "от 2 469 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Укладка плитки с разуклонкой в подиуме в строительном исполнении", price: "от 6 000 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство плинтуса из плитки", price: "от 1 380 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка порожков из плитки", price: "от 2 775 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Облицовка плиткой ступеней (с подрезкой и затиркой)", price: "от 3 161 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Затирка плитки", price: "от 294 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Затирка плитки эпоксидной затиркой", price: "от 1 301 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка ламината", price: "от 714 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка ламината и подложки с проклейкой стыков клеем", price: "от 884 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка ламината и подложки по диагонали", price: "от 1 338 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка нелакированного модульного паркета на фанеру", price: "от 3 315 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка инженерной доски", price: "от 3 183 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка паркетной доски", price: "от 2 241 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка паркетной доски (на клей)", price: "от 2 691 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка паркетной доски по диагонали", price: "от 2 796 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка массивной доски", price: "от 2 760 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка замкового пробкового пола", price: "от 740 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка кварцвиниловой плитки", price: "от 818 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка кварцвиниловой плитки на клей", price: "от 1 145 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка кварцвинила клеевого елочкой", price: "от 2 700 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Укладка кварцвинила замкового по диагонали", price: "от 1 500 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Настил линолеума коммерческого", price: "от 467 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Настил линолеума бытового , на клей", price: "от 570 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Настил линолеума бытового, ковролина", price: "от 440 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство ковровых покрытий плиточных", price: "от 833 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка пробкового компенсатора", price: "от 702 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж плинтусов пластиковых", price: "от 368 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж скрытого плинтуса/теневого профиля", price: "от 2 025 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штробление под плинтус/профиль скрытого монтажа", price: "от 350 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж микроплинтуса", price: "от 2 028 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка плинтусов деревянных, МДФ", price: "от 675 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка плинтусов из дюрополимера и полиуриетана", price: "от 825 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Запил углов плинтуса", price: "от 216 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Покраска напольного плинтуса", price: "от 353 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка порожков", price: "от 923 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Добавляется на установку плинтусов к криволинейным стенам", price: "от 297 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство плинтуса из плитки", price: "от 987 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Стены",
|
||||
items: [
|
||||
{ name: "Облицовка плиткой стен до 600 мм по одной стороне", price: "от 3 000 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой гексагон", price: "от 3 698 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой стен, с декоративными вставками", price: "от 3 104 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой стен по диагонали", price: "от 3 540 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой стен по диагонали, со вставками", price: "от 4 650 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка плиткой стен менее 200х200 мм", price: "от 3 750 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен мелкой плиткой на подложке (с затиркой)", price: "от 4 200 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен мелкой плиткой, мозаикой (с затиркой)", price: "от 4 806 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Подрезка керамической плитки", price: "от 675 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка резного края плитки под 45(стены)", price: "от 2 168 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка стен плиткой панно*", price: "от 7 425 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен композитными материалами (ЛОФТ)", price: "от 4 005 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство объемного керамического бордюра с подрезкой в углах", price: "от 1 530 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство бордюра из плитки (с затиркой)", price: "от 1 011 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка плиткой \"фартук\" (с затиркой и подрезкой)", price: "от 4 680 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка керамогранитом \"фартук\" (с затиркой и подрезкой)", price: "от 5 475 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Фартук из декоративного камня", price: "от 5 850 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка клинкерным кирпичом с затиркой", price: "от 4 200 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка Крупноформатным керамогранитом", price: "от 10 800 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен керамогранитом до 1200 мм по одной стороне", price: "от 5 166 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен керамогранитом до 600 мм по одной стороне", price: "от 2 570 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Подрезка керамогранита крупноформатного до 1200 мм", price: "от 1 359 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка керамогранита крупноформатного", price: "от 2 471 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка керамогранита крупноформатного под 45 гр.", price: "от 4 286 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка керамогранита 600", price: "от 782 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Высверливание коронкой отверстия в керамической плитке", price: "от 609 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Высверливание отверстий в керамограните", price: "от 668 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Облицовка стен декоративным камнем (с затиркой)", price: "от 3 519 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Затирка плитки(стены)", price: "от 330 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Затирка плитки эпоксидной затиркой", price: "от 1 301 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Затирка швов в керамической плитке нестандартного размера (10*10, рзноразмерной плитке , мраморной плитке)", price: "от 750 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Вставки из стеклоблоков поштучно в ниши, стены", price: "от 867 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Укладка стеклоблоков ( устройство перегородок, стен)", price: "от 5 928 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка углового профиля (для плитки)", price: "от 294 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка стеновыми ПВХ панелями (до 10м2)", price: "от 1 260 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стеновыми ПВХ панелями (свыше 10м2)", price: "от 879 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж стеновых ПВХ панелей с устройством каркаса", price: "от 1 739 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж стеновых 3D панелей на клей", price: "от 3 368 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж молдингов на стену", price: "от 630 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Запил молдингов под 45 градусов", price: "от 81 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж ламината на клей", price: "от 1 868 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стеновыми панелями (с устройством каркаса)", price: "от 1 761 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Облицовка стен деревянной вагонкой с устройством каркаса", price: "от 3 090 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Покрытие деревянных поверхностей лаком или тонирующим составом в 1 слой", price: "от 297 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен стеклянными/зеркальными элементами (размер менее 20*20)", price: "от 3 090 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен стеклянными/зеркальными элементами (размер более 20*20)", price: "от 2 520 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Декоративная штукатурка", price: "от 2 280 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Фактурная штукатурка", price: "от 981 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Венецианская штукатурка", price: "от 3 953 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Нанесение жидких обоев", price: "от 1 170 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен обоями шириной менее 700мм", price: "от 728 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен обоями без подбора", price: "от 720 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен обоями с подбором", price: "от 810 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен текстильными обоями", price: "от 939 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен обоями под окраску", price: "от 630 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклейка стен флизелиновым холстом (110,130,150 г/м2)", price: "от 465 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклеивание стен обоями шелкография", price: "от 1 413 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Поклейка обойного бордюра", price: "от 362 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Поклейка фотообоев/бумажных обоев", price: "от 3 123 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклеивание стен шелковыми обоями VIP класса, обоями типа соломка, пробковым покрытием", price: "от 4 296 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Оклеивание стены фреской/панно", price: "от 3 150 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Окраска молдингов стены", price: "от 368 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска кирпичной /бетонной стены( стиль лофт)", price: "от 672 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Окраска стен в 2 слоя", price: "от 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Окраска стен (цветная) до 3х цветов", price: "от 953 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Окраска обоев в 2 слоя", price: "от 413 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка люка \"невидимка\"", price: "от 4 149 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка люка (металл/ПВХ)", price: "от 1 113 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка пластикового декоративного уголка", price: "от 297 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Откосы",
|
||||
items: [
|
||||
{ name: "Окраска откосов, углов", price: "от 384 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Оклейка откосов обоями", price: "от 390 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка ПВХ уголка", price: "от 218 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство откосов из ПВХ панелей, сэндвич-панелей", price: "от 1 103 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка откосов плиткой", price: "от 2 018 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Облицовка откосов плиткой (торец 45 град, дополнительно)", price: "от 3 368 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрезка резного края плитки под 45 гр.", price: "от 2 168 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Потолки",
|
||||
items: [
|
||||
{ name: "Окраска потолка в 2 слоя", price: "от 518 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Декоративная штукатурка на потолке", price: "от 2 618 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка плинтуса потолочного (полиуритан)", price: "от 966 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка потолочных розеток декоративных", price: "от 1 155 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка потолочного плинтуса дюрополимер/полиуретан до 70 мм", price: "от 795 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка потолочного плинтуса дюрополимер/полиуретан более 70 мм", price: "от 1 395 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж плинтуса потолочного (полиуретан, с подбором рисунка)", price: "от 1 248 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска потолочного плинтуса", price: "от 368 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Поклейка обоев на потолок", price: "от 663 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Отделка готовых потолков типа \"Венецианская штукатурка\"", price: "от 3 831 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков из ПВХ панелей до 10м2", price: "от 1 152 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков из ПВХ панелей свыше 10м2", price: "от 1 347 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство потолков реечных свыше до 10м2", price: "от 1 454 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Обшивка потолка деревянной вагонкой с устройством каркаса", price: "от 3 212 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Поклейка панелей потолочных", price: "от 576 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Устройство кассетных подвесных потолков (\"Армстронг\")", price: "от 1 133 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Сверление отверстия в ГКЛ потолке", price: "от 189 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сверление отверстия в реечном потолке", price: "от 270 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Двери, окна",
|
||||
items: [
|
||||
{ name: "Окраска окна", price: "от 1 268 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка подоконников", price: "от 1 413 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка каменного подоконника (с подготовкой поверхности)", price: "от 3 840 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство подоконника из керамогранита (включая подготовку поверхности)", price: "от 4 650 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка отливов", price: "от 1 187 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска подоконников", price: "от 495 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Подрез деревянной двери", price: "от 780 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска двери", price: "от 1 581 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка арки в проем", price: "от 4 994 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Окраска оконных проемов с подготовкой", price: "от 2 225 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка антресольных дверок", price: "от 1 187 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж дверного ограничителя", price: "от 338 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска наличников", price: "от 368 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка межкомнатной двери под ключ", price: "от 7 500 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Шпаклевка дверей (с ошкуриванием)", price: "от 968 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Замуровать окна (между с/у и кухней)", price: "от 3 161 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Прочие",
|
||||
items: [
|
||||
{ name: "Скрытый карниз для парящих штор", price: "от 2 496 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка карнизов", price: "от 818 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж электрокарниза", price: "от 3 078 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж антресоли", price: "от 2 964 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Монтаж ЖК телевизора на стену", price: "от 3 951 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка рольставней", price: "от 4 392 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка полок", price: "от 1 053 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка зеркал", price: "от 1 685 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка экрана для радиатора из МДФ (без изготовления)", price: "от 972 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Электромонтажные работы",
|
||||
items: [
|
||||
{ name: "Штробление кирпичных/гипсолитовых/пеноблочных стен под элкабель", price: "от 450 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штробление бетонных стен под элкабель", price: "от 780 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Заделка штроб", price: "от 108 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Высверливание чаши под подрозетник в бетоне", price: "от 780 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Высверливание чаши под подрозетник в гипсолите/Пеноблоке", price: "от 420 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Высверливание отверстия под подрозетник в ГКЛ", price: "от 381 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Высверливание чаши под подрозетник в кирпиче", price: "от 668 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка подрозетника", price: "от 186 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка механизма, панели электроточки", price: "от 638 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка электроточки накладной", price: "от 488 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка диммера", price: "от 983 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка перекрестного выключателя", price: "от 1 028 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка проходного выключателя", price: "от 713 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка проходного 2х клавишного выключателя", price: "от 912 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка проходного 3х клавишного выключателя", price: "от 954 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка электроточки в ГКЛ", price: "от 612 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка 3х фазной розетки накладной", price: "от 702 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка светильника трекового", price: "от 518 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка 3х фазной розетки внутренней установки", price: "от 1 053 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж встраиваемого линейного освещения", price: "от 5 961 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка трекового освещения (без монтажа осветительных приборов)", price: "от 498 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка люстры (без сборки)", price: "от 2 168 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка встраиваемых светильников под окраску", price: "от 2 670 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка светильников точечных", price: "от 450 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка светильника настенного,бра", price: "от 956 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка светодиодной ленты", price: "от 563 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка светодиодной ленты в алюминиевом коробе", price: "от 623 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Прокладка кабеля в гофре", price: "от 570 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Прокладка кабеля", price: "от 375 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Прокладка кабеля телефонного/интернет UTP", price: "от 165 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка кабель-канала", price: "от 180 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж кабельного лотка металл", price: "от 261 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка контроллера для светодиодной ленты", price: "от 1 757 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка автоматического выключателя", price: "от 791 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка дифф автоматического выключателя", price: "от 1 218 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка УЗО", price: "от 1 389 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита накладного", price: "от 2 636 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Подключение к вводному щиту", price: "от 2 265 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Соединение медных проводов пайкой+термоусадка", price: "от 510 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Наращивание кабеля (спайка + терм усадка)", price: "от 510 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка распределительной коробки накладной", price: "от 855 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 6 автоматов кирпичной стене (ПГП,пеноблок)", price: "от 2 847 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 16 автоматов в кирпичной стене (ПГП,пеноблок)", price: "от 3 618 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 24 автоматов в кирпичной стене (ПГП,пеноблок)", price: "от 4 392 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита свыше 24 автоматов в кирпичной стене (ПГП,пеноблок)", price: "от 8 700 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 6 автоматов в бетонной стене", price: "от 4 317 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 12 автоматов в бетонной стене", price: "от 5 013 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 18 автоматов в бетонной стене", price: "от 5 718 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита до 24 автоматов в бетонной стене", price: "от 7 674 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж элщита свыше 24 автоматов в бетонной стене", price: "от 15 300 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексное расключение слаботочного щита", price: "от 2 310 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Прозвонка электрики (точка)", price: "от 249 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка вентилятора", price: "от 942 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка конвектора электрического", price: "от 1 779 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка звонка", price: "от 624 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка домофона (на старое место)", price: "от 890 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство инфракрасного теплого пола", price: "от 1 404 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка терморегулятора под теплый пол", price: "от 1 758 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство теплого пола из карбоновых матов (кабель)", price: "от 1 581 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Составление однолинейной схемы до 16 модулей", price: "от 7 500 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Составление однолинейной схемы от 16 до 24 модулей", price: "от 15 000 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Составление однолинейной схемы от 24 до 36 модулей", price: "от 22 500 ₽/шт", amount: "1", unit: "шт" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Сантехнические работы",
|
||||
items: [
|
||||
{ name: "Снятие и установка радиатора, без замены, для проведения работ по стенам при наличие шаровых кранов", price: "от 3 990 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж радиатора на готовое подключение", price: "от 4 868 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж вертикального радиатора с переносом труб ввода/вывода воды на стену", price: "от 9 450 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Перенос вывода/ввода воды радиатора на стену", price: "от 5 550 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж конвекторов напольных", price: "от 5 883 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штробление кирпичных стен до 7 см", price: "от 1 448 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штробление бетонных стен до 7 см", price: "от 2 768 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Штробление стен для прокладки труб ГВС и ХВС", price: "от 780 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Заделка сантехнических штроб", price: "от 177 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Пробивка отверстия в гипсолитовой стене ф50-110мм до 100 мм в толщине", price: "от 990 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пробивка отверстия в бетонной стене ф50--110мм до 100 мм толщины стен", price: "от 3 233 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пробивка отверстия в кирпичной стене ф50-110 мм до 100 мм в толщине", price: "от 1 673 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Утепление труб канализации/водоснабжения/теплоизоляция", price: "от 147 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство шумоизоляции труб стояка", price: "от 1 470 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство сан тех - шкафа (ГКЛ , Пеноблок)", price: "от 2 070 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка ванны", price: "от 5 451 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка ванны (\"джакузи\")", price: "от 7 314 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка ванны (чугун, камень)", price: "от 7 964 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка ванны стоимостью свыше 100000р", price: "от 15 900 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж стеклянных шторок на ванну", price: "от 5 618 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж пластиковых шторок на ванну", price: "от 2 898 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка душевой кабины ( размером 80*80)", price: "от 5 670 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройства поддона для душевой кабины", price: "от 5 138 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство подиума (кладка, стяжка, гидроизоляция)", price: "от 20 760 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж стеклянных шторок для душевого поддона", price: "от 10 320 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка сливного трапа", price: "от 2 435 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройства подиума с обшивкой фанерой до 10 см прямолинейного", price: "от 10 419 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство подиума с установкой поддона", price: "от 6 279 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка смесителей/гигиенического душа", price: "от 1 868 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка встраиваемого смесителя/гигиенического душа", price: "от 5 183 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка тропического душа", price: "от 3 204 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка душевой штанги", price: "от 1 418 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка сифона", price: "от 828 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Прокладка труб водоснабжения", price: "от 243 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Прокладка труб канализации", price: "от 743 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Монтаж заглушек на трубопроводе/канализации", price: "от 108 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка кухонной мойки", price: "от 1 656 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сборка коллектора до 5 выходов", price: "от 3 105 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сборка коллектора до 10 выходов", price: "от 5 175 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сборка коллектора свыше 10 выходов", price: "от 6 210 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка раковины стоимостью свыше 50000р", price: "от 5 483 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка раковины", price: "от 2 318 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж фильтра для воды под мойку", price: "от 1 677 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка фильтра грубой очистки (косой)", price: "от 1 118 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка магистрального фильтра", price: "от 810 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка самопромывного фильтра тонкой очистки", price: "от 2 889 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка манометра", price: "от 300 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка регулятора давления", price: "от 1 070 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка компенсатора гидроудара", price: "от 705 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка полотенцесушителя", price: "от 4 883 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка полотенцесушителя( электрического)", price: "от 2 018 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж водосчетчика без пломбировки", price: "от 1 869 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка и подключение стиральной машины", price: "от 2 574 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка водонагревателя до 100л", price: "от 4 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка водонагревателя свыше 100л", price: "от 6 300 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж проточного водонагревателя", price: "от 2 400 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж экрана под ванну (пластик)", price: "от 2 139 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж экрана под ванну (каркас для плитки)", price: "от 3 533 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Замена вводных кранов", price: "от 1 283 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка системы защиты от протечек воды \"Аквасторож\"", price: "от 7 377 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Пайка пропиленового фитинга ( угол, муфта, переход, тройник)", price: "от 201 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка латунного фитинга резьбового", price: "от 345 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка латунного фитинга резьбового/уголков металлических/сгонов/ниппелей/бочонка/удлинителя и пр.", price: "от 345 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка шарового крана/американки", price: "от 732 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка точки вентиляции", price: "от 702 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство вентиляционных каналов из гофрированных труб", price: "от 323 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство вентиляционных каналов из стальных оцинкованных труб", price: "от 873 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Устройство соединений при врезке в существующий вентканал", price: "от 258 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка Вентрешёток", price: "от 414 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка коллекторного щита накладного", price: "от 2 745 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Снятие-установка радиатора на существующие места (с заменой радиатора)", price: "от 2 745 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка системы сололифт", price: "от 8 058 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка кухонного фильтра очистки воды", price: "от 4 520 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка измельчителя отходов", price: "от 2 712 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексная разводка труб водоснабжения (1 точка)", price: "от 2 918 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексная разводка труб канализации (1 точка)", price: "от 2 781 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка точки водоснабжения (водорозетки)", price: "от 939 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексная разводка труб водоснабжения из сшитого полиэтилена \"Рехау\" до 10м (1 точка)", price: "от 3 353 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексная разводка труб водоснабжения из сшитого полиэтилена \"Рехау\" свыше 10м (1 точка)", price: "от 4 500 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка точки водоснабжения (водорозетки) \"Рехау\"", price: "от 1 503 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж водяных теплых полов до 5 м кв.", price: "от 2 574 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Монтаж водяных теплых полов более 5 м кв.", price: "от 1 656 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Комплексная прокладка воздуховодов до 3-х метров", price: "от 2 139 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Устройство вентиляционных каналов ПВХ труб", price: "от 683 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Установка \"тюльпана\"", price: "от 2 628 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка точки канализации", price: "от 1 875 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка унитаза , биде со сборкой", price: "от 5 202 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка унитаза без сборки", price: "от 2 829 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка унитаза без сборки на старые посадочные места", price: "от 1 242 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка \"инсталляции\"", price: "от 7 161 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка \"мойдодыра\"", price: "от 3 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Установка чаши \"инсталляции\"", price: "от 3 255 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Герметизация швов ванны /раковины /унитаза", price: "от 306 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска радиатора (до 5 секций)", price: "от 1 071 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Окраска радиатора каждая последующая секция", price: "от 291 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Окраска труб диаметром до 50мм", price: "от 276 ₽/пог.м", amount: "1", unit: "пог.м" },
|
||||
{ name: "Окраска труб диаметром свыше 50мм", price: "от 378 ₽/пог.м", amount: "1", unit: "пог.м" }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Подготовительные работы",
|
||||
items: [
|
||||
{ name: "Укрытие пленкой", price: "от 68 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Разборка/сборка мебели", price: "от 3 953 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сборка строительных подмостей", price: "от 2 070 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Перестановка мебели (стенка из 5 секций)", price: "от 2 606 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Перестановка мебели ( шкаф из 1 секции)", price: "от 1 731 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Перестановка мебели (перемещение дивана)", price: "от 1 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонного гарнитура без сохранения", price: "от 3 519 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонного гарнитура с сохранением", price: "от 11 181 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонного модуля (тумба/шкафчик)", price: "от 414 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонного фартука / столешницы", price: "от 414 ₽/м²", amount: "1", unit: "м²" },
|
||||
{ name: "Установка кухонного модуля (тумба/шкафчик)", price: "от 612 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж кухонной плиты без сохранения", price: "от 1 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Демонтаж газовой плиты", price: "от 1 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Вынос мусора из квартиры на лифте ( при условии наличия контейнера для сбора строительного мусора не далее 50 м от подъезда или места проведения работ) (за 1 кг)", price: "от 9 ₽/кг", amount: "1", unit: "кг" },
|
||||
{ name: "Уборка лестничных клеток", price: "от 1 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Вынос чугунной ванны по лестнице за каждый этаж", price: "от 1 380 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Сборка мебели 15% от стоимости", price: "от 3 906 ₽/шт", amount: "1", unit: "шт" },
|
||||
{ name: "Разгрузка материала", price: "от 9 ₽/кг", amount: "1", unit: "кг" },
|
||||
{ name: "При отсутствии лифта подъем на 1 этаж", price: "от 6 ₽/кг", amount: "1", unit: "кг" },
|
||||
{ name: "Работа/ час прораба (выезд)", price: "от 1 500 ₽/час", amount: "1", unit: "час" },
|
||||
{ name: "Комплексные подготовительные работы (Укрытие пленкой дверей/окон, временное освещение, временное водоснабжение, сборка подмостей)", price: "от 234 ₽/м²", amount: "1", unit: "м²" }
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Примерные цены на штучные отделочные и монтажные работы в Санкт-Петербурге.">
|
||||
<title>Фриз | Цены в Санкт-Петербурге</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/prices">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<section class="section reveal">
|
||||
<div class="container">
|
||||
<h1>Примерные цены на штучные работы</h1>
|
||||
<p>Итоговая стоимость зависит от состояния основания, объема и доступа к объекту</p>
|
||||
|
||||
<div class="price-accordion" id="priceAccordion">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<script src="prices-data.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,119 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Политика обработки персональных данных — Фриз">
|
||||
<title>Фриз | Политика обработки персональных данных</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/privacy">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<article class="section privacy-doc">
|
||||
<div class="container">
|
||||
<h1>Политика обработки персональных данных</h1>
|
||||
|
||||
<p class="privacy-doc__lead">
|
||||
Индивидуальный предприниматель Погребнякова Ольга Юрьевна<br>
|
||||
ИНН [укажите ИНН]<br>
|
||||
ОГРНИП [укажите ОГРНИП]<br>
|
||||
Адрес регистрации: [укажите адрес регистрации ИП]
|
||||
</p>
|
||||
|
||||
<p>Полные реквизиты: <a href="requisites.html">страница «Реквизиты ИП»</a></p>
|
||||
|
||||
<p class="privacy-doc__meta">Действует с: «01» января 2026 г.</p>
|
||||
|
||||
<h2>1. Общие положения</h2>
|
||||
<p>1.1. Настоящая Политика определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных у Индивидуального предпринимателя Погребняковой Ольги Юрьевны (далее — Оператор)</p>
|
||||
<p>1.2. Оператор ставит своей важнейшей целью соблюдение прав и свобод человека и гражданина при обработке его персональных данных</p>
|
||||
<p>1.3. Политика действует в отношении всех персональных данных, которые Оператор может получить от посетителей сайта <a href="https://frieze-spb.ru">https://frieze-spb.ru</a> (далее — Сайт)</p>
|
||||
|
||||
<h2>2. Какие персональные данные собирает Оператор</h2>
|
||||
<p>2.1. Оператор собирает только следующие персональные данные:</p>
|
||||
<ul>
|
||||
<li>Фамилия, имя, отчество (или просто имя, которое указал посетитель)</li>
|
||||
<li>Номер контактного телефона</li>
|
||||
<li>Адрес объекта (квартиры, дома), где планируются отделочные работы — только после того, как посетитель сам сообщит его Оператору для записи на замер</li>
|
||||
</ul>
|
||||
<p>2.2. Оператор НЕ собирает и НЕ обрабатывает: паспортные данные, СНИЛС, ИНН, данные банковских карт, биометрические данные (отпечатки пальцев, фото лица и т.п.)</p>
|
||||
|
||||
<h2>3. Цели сбора персональных данных</h2>
|
||||
<p>3.1. Оператор собирает и обрабатывает персональные данные только для следующих целей:</p>
|
||||
<ul>
|
||||
<li>Связь с посетителем сайта (звонок или сообщение) для уточнения деталей заявки</li>
|
||||
<li>Согласование даты и времени выезда специалиста на замер помещения</li>
|
||||
<li>Составление сметы на отделочные работы</li>
|
||||
<li>Заключение и исполнение договора подряда (если стороны приняли решение о сотрудничестве)</li>
|
||||
</ul>
|
||||
<p>3.2. Оператор НЕ использует персональные данные для: рассылки рекламы (без отдельного согласия), передачи третьим лицам, продажи, публикации в открытом доступе</p>
|
||||
|
||||
<h2>4. Как и где хранятся персональные данные</h2>
|
||||
<p>4.1. Заявки, отправленные через форму на Сайте, передаются на хостинг-площадку REG.RU и доставляются Оператору по электронной почте. Обработка выполняется только в объеме, необходимом для связи с клиентом</p>
|
||||
<p>4.2. Персональные данные могут храниться: в почтовом ящике Оператора (на серверах REG.RU или почтового провайдера, используемого Оператором), а также в мобильном телефоне Оператора (в списке контактов и истории звонков/сообщений). Доступ к устройствам защищен паролем/биометрией</p>
|
||||
<p>4.3. Оператор не использует CRM-системы, автоматические рассылки и не передает персональные данные в открытый доступ. Данные используются только для обработки заявок и связи с клиентом</p>
|
||||
|
||||
<h2>5. Как долго хранятся данные</h2>
|
||||
<p>5.1. Персональные данные хранятся:</p>
|
||||
<ul>
|
||||
<li>Если договор не заключён (позвонили, уточнили, но не стали заказывать услуги) — до 30 дней с момента последнего контакта. После этого номер телефона удаляется из телефона Оператора</li>
|
||||
<li>Если договор заключён и работы выполнены — персональные данные хранятся в течение 3 лет после окончания действия договора (требование налогового законодательства). После этого — удаляются</li>
|
||||
</ul>
|
||||
<p>5.2. В любой момент вы можете потребовать удалить ваши персональные данные досрочно (см. раздел 7)</p>
|
||||
|
||||
<h2>6. Передача персональных данных третьим лицам</h2>
|
||||
<p>6.1. Оператор не передает персональные данные третьим лицам, за исключением случаев, прямо предусмотренных законом (например, по требованию суда, полиции, прокуратуры)</p>
|
||||
<p>6.2. Для технической работы Сайта и приема заявок Оператор использует инфраструктуру REG.RU (хостинг/почтовые сервисы). Такая передача ограничивается только данными, которые пользователь сам указывает в форме</p>
|
||||
<p>6.3. Оператор не привлекает колл-центры, сторонние сервисы обзвона и рекламные платформы для обработки заявок. Все звонки и встречи осуществляются лично Оператором</p>
|
||||
|
||||
<h2>7. Ваши права</h2>
|
||||
<p>Вы, как субъект персональных данных, имеете право:</p>
|
||||
<p>7.1. Узнать, какие персональные данные о вас хранятся у Оператора. Для этого достаточно позвонить Оператору по телефону: +7 (921) 741-26-46 и назвать себя</p>
|
||||
<p>7.2. Потребовать исправить неверные или неточные данные</p>
|
||||
<p>7.3. Потребовать удалить ваши персональные данные полностью. Для этого позвоните Оператору или напишите на электронную почту: [укажите email] (если есть). Оператор обязан удалить данные в течение 10 рабочих дней</p>
|
||||
<p>7.4. Отозвать согласие на обработку персональных данных (например, вы передумали и не хотите больше получать звонки). После отзыва согласия Оператор обязан прекратить обработку и удалить ваши данные</p>
|
||||
|
||||
<h2>8. Как даётся согласие на обработку персональных данных</h2>
|
||||
<p>8.1. На Сайте в форме заявки (поля «Имя» и «Телефон») размещён чекбокс (галочка) с текстом: «Я даю согласие на обработку персональных данных в соответствии с Политикой обработки персональных данных» (словосочетание «Политикой обработки персональных данных» оформлено как ссылка на полный текст Политики)</p>
|
||||
<p>8.2. Отправляя заявку через Сайт с отмеченной галочкой, вы даёте письменное согласие на обработку ваших персональных данных в объёме и на условиях, изложенных в настоящей Политике</p>
|
||||
<p>8.3. Если вы заполняете заявку по телефону (диспетчер записывает ваш номер вручную), согласие считается полученным в устной форме и фиксируется фактом вашего обращения</p>
|
||||
|
||||
<h2>9. Меры защиты персональных данных</h2>
|
||||
<p>9.1. Оператор принимает следующие меры для защиты ваших данных:</p>
|
||||
<ul>
|
||||
<li>Телефон, где хранятся номера клиентов, защищён паролем или биометрией (отпечаток пальца / Face ID)</li>
|
||||
<li>Телефон не передаётся третьим лицам</li>
|
||||
<li>Доступ к панели хостинга и почте защищен сложным паролем, доступ предоставлен только Оператору</li>
|
||||
<li>Для сайта и почты регулярно обновляются пароли, используется актуальное программное окружение хостинга</li>
|
||||
<li>При утере или краже телефона Оператор немедленно блокирует его удалённо</li>
|
||||
</ul>
|
||||
|
||||
<h2>10. Изменение Политики</h2>
|
||||
<p>10.1. Оператор может изменять настоящую Политику. Актуальная версия всегда размещается по этому адресу: <a href="https://frieze-spb.ru/privacy">https://frieze-spb.ru/privacy</a></p>
|
||||
<p>10.2. Если изменения существенные (например, смена хостинг-провайдера, подключение новых каналов приема заявок или изменение состава обрабатываемых данных), на Сайте появится уведомление об этом</p>
|
||||
|
||||
<h2>11. Контактная информация</h2>
|
||||
<p>По всем вопросам, связанным с обработкой персональных данных, вы можете обратиться к Оператору:</p>
|
||||
<p>
|
||||
Индивидуальный предприниматель Погребнякова Ольга Юрьевна<br>
|
||||
Телефон: +7 (921) 741-26-46<br>
|
||||
Электронная почта: [укажите email, при появлении]<br>
|
||||
Режим работы: ежедневно с 9:00 до 18:00 по московскому времени
|
||||
</p>
|
||||
<p class="privacy-doc__meta">Дата публикации: 09 апреля 2026 г.</p>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Реквизиты индивидуального предпринимателя Погребняковой Ольги Юрьевны — отделочные работы Фриз, Санкт-Петербург.">
|
||||
<title>Фриз | Реквизиты ИП</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/requisites">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<article class="section privacy-doc reveal">
|
||||
<div class="container">
|
||||
<h1>Реквизиты индивидуального предпринимателя</h1>
|
||||
|
||||
<p class="privacy-doc__lead">
|
||||
Индивидуальный предприниматель Погребнякова Ольга Юрьевна<br>
|
||||
ИНН [укажите ИНН]<br>
|
||||
ОГРНИП [укажите ОГРНИП]<br>
|
||||
Адрес регистрации: [укажите адрес регистрации ИП]
|
||||
</p>
|
||||
|
||||
<p>Телефон: <a href="tel:+79217412646">+7 (921) 741-26-46</a><br>
|
||||
Электронная почта: [укажите email, при появлении]</p>
|
||||
|
||||
<p class="privacy-doc__meta">Сайт носит информационный характер. Услуги оказываются на территории Санкт-Петербурга и Ленинградской области</p>
|
||||
|
||||
<p><a href="privacy.html">Политика обработки персональных данных</a></p>
|
||||
</div>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Отзывы клиентов о выполненных отделочных работах в Санкт-Петербурге.">
|
||||
<title>Фриз | Отзывы — Санкт-Петербург</title>
|
||||
<link rel="canonical" href="https://frieze-spb.ru/reviews">
|
||||
<link rel="icon" type="image/svg+xml" href="image/favicon.svg">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div data-site-header></div>
|
||||
|
||||
<main>
|
||||
<section class="section reveal">
|
||||
<div class="container">
|
||||
<h1>Отзывы клиентов</h1>
|
||||
<p>Реальные отклики после завершения ремонта и сдачи объектов в городе и области</p>
|
||||
|
||||
<div class="reviews__grid">
|
||||
<article class="card">
|
||||
<h3>Мария, Петроградский район</h3>
|
||||
<p>"Сделали ванную под ключ за 12 дней, всё аккуратно и в оговоренный бюджет"</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Алексей, Васильевский остров</h3>
|
||||
<p>"Отлично подготовили стены в старом фонде, после покраски всё выглядит идеально"</p>
|
||||
</article>
|
||||
<article class="card">
|
||||
<h3>Ирина, Приморский район</h3>
|
||||
<p>"Помогли с закупкой материалов и вывозом мусора, очень удобно и без лишних хлопот"</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div data-site-footer></div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Host: frieze-spb.ru
|
||||
Sitemap: https://frieze-spb.ru/sitemap.xml
|
||||
@@ -0,0 +1,897 @@
|
||||
function getCurrentPageName() {
|
||||
const normalizedPath = window.location.pathname.replace(/\/+$/, "");
|
||||
const raw = (normalizedPath.split("/").pop() || "").toLowerCase();
|
||||
const normalized = raw.replace(/\.html$/, "");
|
||||
return normalized || "index";
|
||||
}
|
||||
|
||||
const isLocalDevHost =
|
||||
window.location.hostname === "localhost" ||
|
||||
window.location.hostname === "127.0.0.1";
|
||||
|
||||
function routeHref(page) {
|
||||
if (page === "index") {
|
||||
return isLocalDevHost ? "index.html" : "/";
|
||||
}
|
||||
return isLocalDevHost ? `${page}.html` : `/${page}`;
|
||||
}
|
||||
|
||||
function renderSharedLayout() {
|
||||
const currentPage = getCurrentPageName();
|
||||
const headerMount = document.querySelector("[data-site-header]");
|
||||
const footerMount = document.querySelector("[data-site-footer]");
|
||||
|
||||
if (headerMount) {
|
||||
const navItems = [
|
||||
{ page: "prices", href: routeHref("prices"), label: "Цены" },
|
||||
{ page: "portfolio", href: routeHref("portfolio"), label: "Портфолио" },
|
||||
{ page: "reviews", href: routeHref("reviews"), label: "Отзывы" },
|
||||
];
|
||||
|
||||
const navHtml = navItems
|
||||
.map((item) => {
|
||||
const isCurrent = currentPage === item.page;
|
||||
return `<a class="header-link${isCurrent ? " header-link--current" : ""}" href="${item.href}"${isCurrent ? ' aria-current="page"' : ""}>${item.label}</a>`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
headerMount.outerHTML = `
|
||||
<header class="header">
|
||||
<div class="container header__inner">
|
||||
<div class="header__left">
|
||||
<a href="${routeHref("index")}" class="logo">
|
||||
<img src="image/logo-test.jpg" alt="Фриз">
|
||||
</a>
|
||||
<nav class="header__nav" aria-label="Основная навигация">
|
||||
${navHtml}
|
||||
</nav>
|
||||
</div>
|
||||
<div class="header__actions">
|
||||
<div class="header__contact">
|
||||
<a class="phone-link" href="tel:+79217412646">+7 (921) 741-26-46</a>
|
||||
<span class="header__meta">Ежедневно 10:00-18:00</span>
|
||||
<span class="header__geo">Санкт-Петербург</span>
|
||||
</div>
|
||||
<a class="btn btn--outline" href="https://vk.com/ya_lo_ya" target="_blank" rel="noopener noreferrer">VK</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>`;
|
||||
}
|
||||
|
||||
if (footerMount) {
|
||||
const isPrivacyPage = currentPage === "privacy";
|
||||
const isRequisitesPage = currentPage === "requisites";
|
||||
|
||||
footerMount.outerHTML = `
|
||||
<a class="floating-call" href="tel:+79217412646" aria-label="Позвонить">Позвонить</a>
|
||||
<footer class="footer">
|
||||
<div class="container footer__inner">
|
||||
<div class="footer__brand">
|
||||
<p class="footer__copy">© <span id="year"></span> Фриз. Все права защищены.</p>
|
||||
<p class="footer__ip">ИП Погребнякова Ольга Юрьевна</p>
|
||||
<p class="footer__geo">Работаем в Санкт-Петербурге и Ленинградской области</p>
|
||||
</div>
|
||||
<div class="footer__legal">
|
||||
<a class="footer__link" href="${routeHref("requisites")}"${isRequisitesPage ? ' aria-current="page"' : ""}>Реквизиты ИП</a>
|
||||
<a class="footer__link" href="${routeHref("privacy")}"${isPrivacyPage ? ' aria-current="page"' : ""}>Политика обработки персональных данных</a>
|
||||
</div>
|
||||
<p class="footer__disclaimer">Информация на сайте не является публичной офертой и носит информационный характер</p>
|
||||
</div>
|
||||
</footer>`;
|
||||
}
|
||||
}
|
||||
|
||||
renderSharedLayout();
|
||||
|
||||
const currentYear = document.getElementById("year");
|
||||
if (currentYear) {
|
||||
currentYear.textContent = new Date().getFullYear();
|
||||
}
|
||||
|
||||
const reduceMotionMql = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||
|
||||
function easeInOutCubic(t) {
|
||||
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
||||
}
|
||||
|
||||
function smoothScrollTo(targetY) {
|
||||
const startY = window.scrollY || document.documentElement.scrollTop;
|
||||
const change = targetY - startY;
|
||||
if (reduceMotionMql.matches) {
|
||||
window.scrollTo(0, targetY);
|
||||
return;
|
||||
}
|
||||
if (Math.abs(change) < 2) {
|
||||
return;
|
||||
}
|
||||
const duration = Math.min(980, Math.max(480, Math.abs(change) * 0.62));
|
||||
const start = performance.now();
|
||||
|
||||
const step = (now) => {
|
||||
const t = Math.min(1, (now - start) / duration);
|
||||
window.scrollTo(0, startY + change * easeInOutCubic(t));
|
||||
if (t < 1) {
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
};
|
||||
requestAnimationFrame(step);
|
||||
}
|
||||
|
||||
document.addEventListener(
|
||||
"click",
|
||||
(e) => {
|
||||
if (document.documentElement.classList.contains("modal-open")) {
|
||||
return;
|
||||
}
|
||||
const a = e.target.closest("a");
|
||||
if (!a) {
|
||||
return;
|
||||
}
|
||||
const href = a.getAttribute("href");
|
||||
if (!href || href === "#" || href.charAt(0) !== "#") {
|
||||
return;
|
||||
}
|
||||
if (a.hasAttribute("download")) {
|
||||
return;
|
||||
}
|
||||
const el = document.querySelector(href);
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
const header = document.querySelector(".header");
|
||||
const headerH = header ? header.getBoundingClientRect().height : 0;
|
||||
const gap = 16;
|
||||
const y = el.getBoundingClientRect().top + window.scrollY - headerH - gap;
|
||||
smoothScrollTo(Math.max(0, y));
|
||||
history.pushState(null, "", href);
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
const isHomePage = () => {
|
||||
return getCurrentPageName() === "index";
|
||||
};
|
||||
|
||||
document.querySelectorAll("a.logo").forEach((link) => {
|
||||
const href = (link.getAttribute("href") || "").trim();
|
||||
const goesHome =
|
||||
href === "index.html" ||
|
||||
href === "./index.html" ||
|
||||
href === "/" ||
|
||||
href === "/index" ||
|
||||
href.endsWith("/index.html");
|
||||
if (!goesHome) {
|
||||
return;
|
||||
}
|
||||
link.addEventListener("click", (event) => {
|
||||
if (!isHomePage()) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (window.scrollY > 0) {
|
||||
smoothScrollTo(0);
|
||||
}
|
||||
if (window.location.hash) {
|
||||
history.replaceState(null, "", window.location.pathname + window.location.search);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const form = document.getElementById("contactForm");
|
||||
if (form) {
|
||||
form.setAttribute("novalidate", "novalidate");
|
||||
const nameInput = form.querySelector('input[name="name"]');
|
||||
const phoneInput = form.querySelector('input[name="phone"]');
|
||||
const honeypotInput = form.querySelector('input[name="contact_fax"]');
|
||||
const startedAtInput = form.querySelector('input[name="started_at"]');
|
||||
const submitButton = form.querySelector('button[type="submit"]');
|
||||
|
||||
if (startedAtInput) {
|
||||
startedAtInput.value = String(Date.now());
|
||||
}
|
||||
|
||||
if (phoneInput) {
|
||||
const formatPhone = (rawValue) => {
|
||||
const digits = rawValue.replace(/\D/g, "");
|
||||
const localDigits = digits.startsWith("7") ? digits.slice(1) : digits;
|
||||
const trimmed = localDigits.slice(0, 10);
|
||||
|
||||
if (!trimmed.length) {
|
||||
return "+7";
|
||||
}
|
||||
|
||||
let result = "+7";
|
||||
if (trimmed.length > 0) {
|
||||
result += ` (${trimmed.slice(0, 3)}`;
|
||||
}
|
||||
if (trimmed.length >= 3) {
|
||||
result += ")";
|
||||
}
|
||||
if (trimmed.length > 3) {
|
||||
result += ` ${trimmed.slice(3, 6)}`;
|
||||
}
|
||||
if (trimmed.length > 6) {
|
||||
result += `-${trimmed.slice(6, 8)}`;
|
||||
}
|
||||
if (trimmed.length > 8) {
|
||||
result += `-${trimmed.slice(8, 10)}`;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
phoneInput.addEventListener("focus", () => {
|
||||
if (!phoneInput.value.trim()) {
|
||||
phoneInput.value = "+7";
|
||||
} else {
|
||||
phoneInput.value = formatPhone(phoneInput.value);
|
||||
}
|
||||
});
|
||||
|
||||
phoneInput.addEventListener("input", () => {
|
||||
phoneInput.value = formatPhone(phoneInput.value);
|
||||
phoneInput.setSelectionRange(phoneInput.value.length, phoneInput.value.length);
|
||||
});
|
||||
|
||||
phoneInput.addEventListener("keydown", (event) => {
|
||||
const selectionStart = phoneInput.selectionStart;
|
||||
const selectionEnd = phoneInput.selectionEnd;
|
||||
const hasSelection =
|
||||
selectionStart !== null &&
|
||||
selectionEnd !== null &&
|
||||
selectionStart !== selectionEnd;
|
||||
const fullSelection =
|
||||
selectionStart === 0 && selectionEnd === phoneInput.value.length;
|
||||
|
||||
if (
|
||||
fullSelection &&
|
||||
(event.key === "Backspace" || event.key === "Delete")
|
||||
) {
|
||||
event.preventDefault();
|
||||
phoneInput.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(event.key === "Backspace" || event.key === "Delete") &&
|
||||
selectionStart !== null &&
|
||||
selectionStart <= 2 &&
|
||||
!hasSelection
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
phoneInput.addEventListener("blur", () => {
|
||||
if (phoneInput.value === "+7" || phoneInput.value === "+7 (") {
|
||||
phoneInput.value = "";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const consentInput = form.querySelector('input[name="consent"]');
|
||||
const consentLabel = form.querySelector(".contact-form__consent");
|
||||
const nameValidationRegex = /^[A-Za-zА-Яа-яЁё\s-]{2,80}$/;
|
||||
|
||||
const showFormToast = (message, variant = "warning") => {
|
||||
let toast = document.getElementById("formToast");
|
||||
if (!toast) {
|
||||
toast = document.createElement("div");
|
||||
toast.id = "formToast";
|
||||
toast.className = "form-toast";
|
||||
document.body.appendChild(toast);
|
||||
}
|
||||
toast.textContent = message;
|
||||
toast.classList.remove("form-toast--warning", "form-toast--success");
|
||||
toast.classList.add(`form-toast--${variant}`);
|
||||
toast.setAttribute("role", variant === "success" ? "status" : "alert");
|
||||
toast.setAttribute("aria-live", "polite");
|
||||
toast.classList.add("is-visible");
|
||||
clearTimeout(toast._hideTimer);
|
||||
const hideMs = variant === "success" ? 6000 : 5000;
|
||||
toast._hideTimer = window.setTimeout(() => {
|
||||
toast.classList.remove("is-visible");
|
||||
}, hideMs);
|
||||
toast.onclick = () => {
|
||||
clearTimeout(toast._hideTimer);
|
||||
toast.classList.remove("is-visible");
|
||||
};
|
||||
};
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (nameInput) {
|
||||
const normalizedName = nameInput.value.trim().replace(/\s+/g, " ");
|
||||
nameInput.value = normalizedName;
|
||||
if (!normalizedName) {
|
||||
showFormToast("Пожалуйста, укажите ваше имя", "warning");
|
||||
nameInput.focus();
|
||||
return;
|
||||
}
|
||||
if (!nameValidationRegex.test(normalizedName)) {
|
||||
showFormToast(
|
||||
"Имя должно содержать только буквы, пробелы и дефис (2-80 символов)",
|
||||
"warning"
|
||||
);
|
||||
nameInput.focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (phoneInput) {
|
||||
const phoneDigits = phoneInput.value.replace(/\D/g, "");
|
||||
const isPhoneValid = phoneDigits.length === 11 && phoneDigits.startsWith("7");
|
||||
if (!isPhoneValid) {
|
||||
showFormToast("Пожалуйста, укажите корректный номер телефона", "warning");
|
||||
phoneInput.focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (consentInput && !consentInput.checked) {
|
||||
consentLabel?.classList.add("contact-form__consent--error");
|
||||
consentLabel?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
showFormToast(
|
||||
"Чтобы отправить заявку, отметьте согласие на обработку персональных данных",
|
||||
"warning"
|
||||
);
|
||||
consentInput.focus();
|
||||
return;
|
||||
}
|
||||
consentLabel?.classList.remove("contact-form__consent--error");
|
||||
|
||||
if (startedAtInput && !startedAtInput.value) {
|
||||
startedAtInput.value = String(Date.now());
|
||||
}
|
||||
|
||||
const formData = new FormData(form);
|
||||
// Явно чистим honeypot: защищает от автозаполнения браузером.
|
||||
if (honeypotInput) {
|
||||
honeypotInput.value = "";
|
||||
}
|
||||
formData.delete("website");
|
||||
formData.set("contact_fax", "");
|
||||
if (!formData.get("consent")) {
|
||||
formData.set("consent", "1");
|
||||
}
|
||||
|
||||
if (submitButton) {
|
||||
submitButton.disabled = true;
|
||||
submitButton.setAttribute("aria-busy", "true");
|
||||
}
|
||||
|
||||
fetch("submit.php", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
})
|
||||
.then(async (response) => {
|
||||
let payload = null;
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch (error) {
|
||||
payload = null;
|
||||
}
|
||||
|
||||
if (!response.ok || !payload?.ok) {
|
||||
const errorMessage =
|
||||
payload?.message ||
|
||||
"Не удалось отправить заявку. Позвоните нам, пожалуйста, по телефону +7 (921) 741-26-46";
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
showFormToast("Спасибо! Заявка принята — скоро мы с вами свяжемся", "success");
|
||||
form.reset();
|
||||
if (startedAtInput) {
|
||||
startedAtInput.value = String(Date.now());
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
showFormToast(error.message, "warning");
|
||||
})
|
||||
.finally(() => {
|
||||
if (submitButton) {
|
||||
submitButton.disabled = false;
|
||||
submitButton.removeAttribute("aria-busy");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (consentInput) {
|
||||
consentInput.addEventListener("change", () => {
|
||||
if (consentInput.checked) {
|
||||
consentLabel?.classList.remove("contact-form__consent--error");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const revealItems = document.querySelectorAll(".reveal");
|
||||
const revealObserver = new IntersectionObserver(
|
||||
(entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry.isIntersecting) {
|
||||
return;
|
||||
}
|
||||
entry.target.classList.add("is-visible");
|
||||
observer.unobserve(entry.target);
|
||||
});
|
||||
},
|
||||
{
|
||||
threshold: 0.15,
|
||||
}
|
||||
);
|
||||
|
||||
revealItems.forEach((item) => revealObserver.observe(item));
|
||||
|
||||
const priceAccordion = document.getElementById("priceAccordion");
|
||||
|
||||
const fallbackPriceData = [
|
||||
{
|
||||
title: "Электромонтажные работы",
|
||||
items: [
|
||||
{ name: "Установка розетки", price: "от 650 ₽/шт" },
|
||||
{ name: "Установка выключателя", price: "от 550 ₽/шт" },
|
||||
{ name: "Монтаж подрозетника", price: "от 450 ₽/шт" },
|
||||
{ name: "Монтаж точки освещения", price: "от 1 200 ₽/шт" },
|
||||
{ name: "Монтаж потолочного светильника", price: "от 900 ₽/шт" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Плиточные работы",
|
||||
items: [
|
||||
{ name: "Укладка плитки 20x30", price: "от 350 ₽/шт" },
|
||||
{ name: "Укладка керамогранита 60x60", price: "от 900 ₽/шт" },
|
||||
{ name: "Запил плитки под 45 градусов", price: "от 500 ₽/пог.м" },
|
||||
{ name: "Затирка эпоксидная", price: "от 300 ₽/м²" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Сантехнические работы",
|
||||
items: [
|
||||
{ name: "Установка смесителя", price: "от 1 500 ₽/шт" },
|
||||
{ name: "Монтаж унитаза", price: "от 2 500 ₽/шт" },
|
||||
{ name: "Установка раковины с тумбой", price: "от 3 000 ₽/шт" },
|
||||
{ name: "Подключение полотенцесушителя", price: "от 2 800 ₽/шт" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function escapeHtml(value) {
|
||||
const text = String(value ?? "");
|
||||
return text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function normalizePriceItems(items) {
|
||||
if (!Array.isArray(items)) {
|
||||
return [];
|
||||
}
|
||||
return items.map((item) => ({
|
||||
name: typeof item?.name === "string" ? item.name : "",
|
||||
price: typeof item?.price === "string" ? item.price : "",
|
||||
amount: typeof item?.amount === "string" ? item.amount : "",
|
||||
unit: typeof item?.unit === "string" ? item.unit : "",
|
||||
total: typeof item?.total === "string" ? item.total : "",
|
||||
}));
|
||||
}
|
||||
|
||||
function normalizePriceData(data) {
|
||||
if (!Array.isArray(data)) {
|
||||
return JSON.parse(JSON.stringify(fallbackPriceData));
|
||||
}
|
||||
|
||||
return data.map((category) => {
|
||||
const children = Array.isArray(category?.children)
|
||||
? category.children.map((child) => ({
|
||||
title: typeof child?.title === "string" ? child.title : "",
|
||||
items: normalizePriceItems(child?.items),
|
||||
}))
|
||||
: [];
|
||||
|
||||
return {
|
||||
title: typeof category?.title === "string" ? category.title : "",
|
||||
items: normalizePriceItems(category?.items),
|
||||
children,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function loadPriceData() {
|
||||
const externalData =
|
||||
typeof window.PRICES_DATA !== "undefined" ? window.PRICES_DATA : null;
|
||||
if (externalData) {
|
||||
return normalizePriceData(externalData);
|
||||
}
|
||||
return JSON.parse(JSON.stringify(fallbackPriceData));
|
||||
}
|
||||
|
||||
function buildPriceList(items) {
|
||||
return items
|
||||
.map(
|
||||
(item) => {
|
||||
const rawPrice = String(item.price || "").trim();
|
||||
const desktopPrice = rawPrice
|
||||
.replace(/\s*\/\s*[^\s]+$/u, "")
|
||||
.trim();
|
||||
const mobilePrice = rawPrice
|
||||
.replace(/^от\s+/iu, "")
|
||||
.replace(/\s*\/\s*[^\s]+$/u, "")
|
||||
.trim();
|
||||
const derivedUnitMatch = rawPrice.match(/\/\s*([^\s]+)$/);
|
||||
const derivedUnit = derivedUnitMatch ? derivedUnitMatch[1] : "";
|
||||
const amountValue = item.amount || "1";
|
||||
const unitValue = item.unit || derivedUnit || "";
|
||||
const normalizedName = String(item.name || "").trim().replace(/\s+/g, " ");
|
||||
const fullName = escapeHtml(normalizedName);
|
||||
return `
|
||||
<li>
|
||||
<span class="price-work-name">${fullName}</span>
|
||||
<span class="price-value">
|
||||
<span class="price-value__full">${escapeHtml(desktopPrice || rawPrice)}</span>
|
||||
<span class="price-value__mobile">${escapeHtml(mobilePrice || rawPrice)}</span>
|
||||
</span>
|
||||
<span>${escapeHtml(amountValue)}</span>
|
||||
<span>${escapeHtml(unitValue || "—")}</span>
|
||||
</li>
|
||||
`;
|
||||
}
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function buildPriceTable(items) {
|
||||
return `
|
||||
<ul class="price-list">
|
||||
<li class="price-list__head" aria-hidden="true">
|
||||
<span>Виды работ</span>
|
||||
<span>Цена</span>
|
||||
<span>Кол-во</span>
|
||||
<span>Ед.изм</span>
|
||||
</li>
|
||||
${buildPriceList(Array.isArray(items) ? items : [])}
|
||||
</ul>
|
||||
`;
|
||||
}
|
||||
|
||||
function slugifyCategory(title) {
|
||||
const map = {
|
||||
а: "a",
|
||||
б: "b",
|
||||
в: "v",
|
||||
г: "g",
|
||||
д: "d",
|
||||
е: "e",
|
||||
ё: "e",
|
||||
ж: "zh",
|
||||
з: "z",
|
||||
и: "i",
|
||||
й: "y",
|
||||
к: "k",
|
||||
л: "l",
|
||||
м: "m",
|
||||
н: "n",
|
||||
о: "o",
|
||||
п: "p",
|
||||
р: "r",
|
||||
с: "s",
|
||||
т: "t",
|
||||
у: "u",
|
||||
ф: "f",
|
||||
х: "h",
|
||||
ц: "ts",
|
||||
ч: "ch",
|
||||
ш: "sh",
|
||||
щ: "sch",
|
||||
ъ: "",
|
||||
ы: "y",
|
||||
ь: "",
|
||||
э: "e",
|
||||
ю: "yu",
|
||||
я: "ya",
|
||||
};
|
||||
|
||||
return String(title || "")
|
||||
.toLowerCase()
|
||||
.split("")
|
||||
.map((ch) => map[ch] ?? ch)
|
||||
.join("")
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
function openPriceCategoryFromHash() {
|
||||
if (!priceAccordion) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hash = decodeURIComponent(location.hash.replace(/^#/, "")).trim();
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
const category = priceAccordion.querySelector(
|
||||
`.price-category#${CSS.escape(hash)}`
|
||||
);
|
||||
if (!(category instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toggle = category.querySelector(".price-category__toggle");
|
||||
const listWrap = toggle?.nextElementSibling;
|
||||
if (
|
||||
toggle instanceof HTMLElement &&
|
||||
listWrap instanceof HTMLElement &&
|
||||
listWrap.classList.contains("price-list-wrap")
|
||||
) {
|
||||
toggle.setAttribute("aria-expanded", "true");
|
||||
listWrap.hidden = false;
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
const header = document.querySelector(".header");
|
||||
const offset =
|
||||
header instanceof HTMLElement ? header.getBoundingClientRect().height + 12 : 12;
|
||||
const top = category.getBoundingClientRect().top + window.scrollY - offset;
|
||||
window.scrollTo({ top: Math.max(0, top), behavior: "smooth" });
|
||||
});
|
||||
}
|
||||
|
||||
function renderPriceAccordion(priceData) {
|
||||
if (!priceAccordion) {
|
||||
return;
|
||||
}
|
||||
|
||||
priceAccordion.innerHTML = priceData
|
||||
.map((category) => {
|
||||
const hasChildren =
|
||||
Array.isArray(category.children) && category.children.length > 0;
|
||||
const categoryId = slugifyCategory(category.title || "kategoriya");
|
||||
|
||||
if (hasChildren) {
|
||||
const childrenHtml = category.children
|
||||
.map(
|
||||
(child) => `
|
||||
<article class="price-subcategory">
|
||||
<button class="price-subcategory__toggle" type="button" aria-expanded="false">
|
||||
${escapeHtml(child.title || "Подкатегория")}
|
||||
</button>
|
||||
<div class="price-list-wrap" hidden>
|
||||
${buildPriceTable(child.items)}
|
||||
</div>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
|
||||
return `
|
||||
<article class="price-category" id="${escapeHtml(categoryId)}">
|
||||
<button class="price-category__toggle" type="button" aria-expanded="false">
|
||||
${escapeHtml(category.title || "Категория")}
|
||||
</button>
|
||||
<div class="price-list-wrap price-list-wrap--nested" hidden>
|
||||
<div class="price-subcategories">
|
||||
${childrenHtml}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
<article class="price-category" id="${escapeHtml(categoryId)}">
|
||||
<button class="price-category__toggle" type="button" aria-expanded="false">
|
||||
${escapeHtml(category.title || "Категория")}
|
||||
</button>
|
||||
<div class="price-list-wrap" hidden>
|
||||
${buildPriceTable(category.items)}
|
||||
</div>
|
||||
</article>
|
||||
`;
|
||||
})
|
||||
.join("");
|
||||
|
||||
openPriceCategoryFromHash();
|
||||
}
|
||||
|
||||
if (priceAccordion) {
|
||||
loadPriceData().then(renderPriceAccordion);
|
||||
|
||||
window.addEventListener("hashchange", openPriceCategoryFromHash);
|
||||
|
||||
priceAccordion.addEventListener("click", (event) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toggle = target.closest(
|
||||
".price-category__toggle, .price-subcategory__toggle"
|
||||
);
|
||||
if (!toggle || !(toggle instanceof HTMLElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const listWrap = toggle.nextElementSibling;
|
||||
if (!(listWrap instanceof HTMLElement) || !listWrap.classList.contains("price-list-wrap")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const expanded = toggle.getAttribute("aria-expanded") === "true";
|
||||
toggle.setAttribute("aria-expanded", String(!expanded));
|
||||
listWrap.hidden = expanded;
|
||||
});
|
||||
}
|
||||
|
||||
const LOGO_KEY = "remont-spb-logo";
|
||||
const DEFAULT_LOGO = "logo-interior-1.png";
|
||||
const logoOptions = [
|
||||
{ id: "logo-option-1.png", label: "1" },
|
||||
{ id: "logo-option-2.png", label: "2" },
|
||||
{ id: "logo-option-3.png", label: "3" },
|
||||
{ id: "logo-option-4.png", label: "4" },
|
||||
{ id: "logo-option-6.png", label: "5" },
|
||||
{ id: "logo-right-2.png", label: "6" },
|
||||
{ id: "logo-right-4.png", label: "7" },
|
||||
{ id: "logo-right-5.png", label: "8" },
|
||||
{ id: "logo-simple-1.png", label: "9" },
|
||||
{ id: "logo-simple-3.png", label: "10" },
|
||||
{ id: "logo-interior-1.png", label: "11" },
|
||||
{ id: "logo-interior-6.png", label: "12" },
|
||||
{ id: "logo-interior-8.png", label: "13" },
|
||||
{ id: "logo-interior-9.png", label: "14" },
|
||||
{ id: "logo-flat-2.png", label: "15" },
|
||||
{ id: "logo-flat-3.png", label: "16" },
|
||||
{ id: "logo-flat-5.png", label: "17" },
|
||||
];
|
||||
|
||||
const BG_KEY = "remont-spb-bg";
|
||||
const DEFAULT_BG = "bg-4.png";
|
||||
const bgOptions = [
|
||||
{ id: "none", label: "Без фона" },
|
||||
{ id: "bg-1.png", label: "Фон 1" },
|
||||
{ id: "bg-2.png", label: "Фон 2" },
|
||||
{ id: "bg-3.png", label: "Фон 3" },
|
||||
{ id: "bg-4.png", label: "Фон 4" },
|
||||
{ id: "bg-5.png", label: "Фон 5" },
|
||||
];
|
||||
|
||||
function applyLogo(logoId) {
|
||||
localStorage.setItem(LOGO_KEY, logoId);
|
||||
const logoPath = `image/${logoId}`;
|
||||
|
||||
const logoImgs = document.querySelectorAll(".logo img");
|
||||
logoImgs.forEach((img) => {
|
||||
img.src = logoPath;
|
||||
});
|
||||
}
|
||||
|
||||
function applyBg(bgId) {
|
||||
localStorage.setItem(BG_KEY, bgId);
|
||||
const heroBg = document.getElementById("heroBg");
|
||||
const heroSection = document.getElementById("hero");
|
||||
|
||||
if (heroBg && heroSection) {
|
||||
if (bgId === "none") {
|
||||
heroBg.style.display = "none";
|
||||
heroBg.src = "";
|
||||
} else {
|
||||
heroBg.style.display = "block";
|
||||
heroBg.src = `image/${bgId}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyBrandingDefaults() {
|
||||
// Применяем зафиксированные значения брендинга без UI-переключателя.
|
||||
applyLogo(DEFAULT_LOGO);
|
||||
applyBg(DEFAULT_BG);
|
||||
}
|
||||
|
||||
applyBrandingDefaults();
|
||||
|
||||
/* Portfolio Gallery Logic */
|
||||
const workCards = document.querySelectorAll('.work-card[data-images]');
|
||||
const portfolioModal = document.getElementById('portfolioModal');
|
||||
const portfolioTrack = document.getElementById('portfolioTrack');
|
||||
|
||||
if (portfolioModal && portfolioTrack) {
|
||||
const closeButtons = portfolioModal.querySelectorAll('[data-close]');
|
||||
|
||||
const openModal = (images) => {
|
||||
portfolioTrack.innerHTML = images
|
||||
.map(
|
||||
(src) =>
|
||||
`<div class="portfolio-modal__slide"><img src="${src}" alt="Фото объекта"></div>`
|
||||
)
|
||||
.join('');
|
||||
portfolioModal.classList.add('is-open');
|
||||
document.documentElement.classList.add('modal-open');
|
||||
document.body.classList.add('modal-open');
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
portfolioModal.classList.remove('is-open');
|
||||
document.documentElement.classList.remove('modal-open');
|
||||
document.body.classList.remove('modal-open');
|
||||
};
|
||||
|
||||
workCards.forEach(card => {
|
||||
card.addEventListener('click', () => {
|
||||
try {
|
||||
const images = JSON.parse(card.dataset.images);
|
||||
if (images && images.length) {
|
||||
openModal(images);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Ошибка при чтении картинок галереи', e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
closeButtons.forEach(btn => btn.addEventListener('click', closeModal));
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && portfolioModal.classList.contains('is-open')) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Логика перетаскивания (Drag-to-scroll)
|
||||
let isDown = false;
|
||||
let startX;
|
||||
let scrollLeft;
|
||||
|
||||
portfolioTrack.addEventListener('mousedown', (e) => {
|
||||
isDown = true;
|
||||
portfolioTrack.classList.add('is-dragging');
|
||||
startX = e.pageX - portfolioTrack.offsetLeft;
|
||||
scrollLeft = portfolioTrack.scrollLeft;
|
||||
});
|
||||
|
||||
portfolioTrack.addEventListener('mouseleave', () => {
|
||||
isDown = false;
|
||||
portfolioTrack.classList.remove('is-dragging');
|
||||
});
|
||||
|
||||
portfolioTrack.addEventListener('mouseup', () => {
|
||||
isDown = false;
|
||||
portfolioTrack.classList.remove('is-dragging');
|
||||
});
|
||||
|
||||
portfolioTrack.addEventListener('mousemove', (e) => {
|
||||
if (!isDown) return;
|
||||
e.preventDefault();
|
||||
const x = e.pageX - portfolioTrack.offsetLeft;
|
||||
const walk = (x - startX) * 2; // Скорость прокрутки при перетаскивании
|
||||
portfolioTrack.scrollLeft = scrollLeft - walk;
|
||||
});
|
||||
|
||||
// Прокрутка колесиком мыши (Wheel scroll)
|
||||
portfolioTrack.addEventListener('wheel', (e) => {
|
||||
if (e.deltaY !== 0) {
|
||||
e.preventDefault();
|
||||
portfolioTrack.scrollLeft += e.deltaY;
|
||||
}
|
||||
});
|
||||
|
||||
// Блокируем прокрутку страницы, пока открыта модалка
|
||||
portfolioModal.addEventListener(
|
||||
'wheel',
|
||||
(e) => {
|
||||
if (!portfolioModal.classList.contains('is-open')) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/prices</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/portfolio</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/reviews</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/privacy</loc>
|
||||
</url>
|
||||
<url>
|
||||
<loc>https://frieze-spb.ru/requisites</loc>
|
||||
</url>
|
||||
</urlset>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// Укажите почту, куда приходят заявки с сайта.
|
||||
// Пример: $recipientEmail = "zayavki@ваш-домен.ru";
|
||||
$recipientEmail = "kostiko040404@yandex.ru";
|
||||
|
||||
// По возможности укажите существующую почту вашего домена (лучше для доставляемости).
|
||||
// Пример: $senderEmail = "noreply@frieze-spb.ru";
|
||||
$senderEmail = "";
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
|
||||
http_response_code(405);
|
||||
echo json_encode([
|
||||
"ok" => false,
|
||||
"message" => "Метод не поддерживается",
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function respondError(string $message, int $code = 400): void
|
||||
{
|
||||
http_response_code($code);
|
||||
echo json_encode([
|
||||
"ok" => false,
|
||||
"message" => $message,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function sanitizeInput(string $value): string
|
||||
{
|
||||
$clean = trim($value);
|
||||
return preg_replace("/[\\x00-\\x1F\\x7F]/u", "", $clean) ?? "";
|
||||
}
|
||||
|
||||
function respondSuccess(): void
|
||||
{
|
||||
echo json_encode([
|
||||
"ok" => true,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
function loadRateLimitState(string $filePath): array
|
||||
{
|
||||
if (!is_file($filePath)) {
|
||||
return [];
|
||||
}
|
||||
$raw = file_get_contents($filePath);
|
||||
if ($raw === false || $raw === "") {
|
||||
return [];
|
||||
}
|
||||
$data = json_decode($raw, true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function storeRateLimitState(string $filePath, array $state): void
|
||||
{
|
||||
$encoded = json_encode($state, JSON_UNESCAPED_UNICODE);
|
||||
if ($encoded === false) {
|
||||
return;
|
||||
}
|
||||
@file_put_contents($filePath, $encoded, LOCK_EX);
|
||||
}
|
||||
|
||||
function isRateLimited(string $ip, int $nowTs): bool
|
||||
{
|
||||
$limitWindowSeconds = 10 * 60; // 10 минут
|
||||
$limitAttempts = 8;
|
||||
$rateFile = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . "frieze_spb_rate_limit.json";
|
||||
|
||||
$state = loadRateLimitState($rateFile);
|
||||
$freshState = [];
|
||||
|
||||
foreach ($state as $storedIp => $timestamps) {
|
||||
if (!is_array($timestamps)) {
|
||||
continue;
|
||||
}
|
||||
$validTs = [];
|
||||
foreach ($timestamps as $ts) {
|
||||
$intTs = (int)$ts;
|
||||
if ($intTs >= $nowTs - $limitWindowSeconds) {
|
||||
$validTs[] = $intTs;
|
||||
}
|
||||
}
|
||||
if ($validTs) {
|
||||
$freshState[$storedIp] = $validTs;
|
||||
}
|
||||
}
|
||||
|
||||
$currentIpHits = $freshState[$ip] ?? [];
|
||||
if (count($currentIpHits) >= $limitAttempts) {
|
||||
storeRateLimitState($rateFile, $freshState);
|
||||
return true;
|
||||
}
|
||||
|
||||
$currentIpHits[] = $nowTs;
|
||||
$freshState[$ip] = $currentIpHits;
|
||||
storeRateLimitState($rateFile, $freshState);
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = sanitizeInput((string)($_POST["name"] ?? ""));
|
||||
$phoneRaw = sanitizeInput((string)($_POST["phone"] ?? ""));
|
||||
$consent = (string)($_POST["consent"] ?? "");
|
||||
$honeypot = sanitizeInput((string)($_POST["contact_fax"] ?? ($_POST["website"] ?? "")));
|
||||
$startedAtRaw = sanitizeInput((string)($_POST["started_at"] ?? ""));
|
||||
|
||||
if ($honeypot !== "") {
|
||||
respondError("Не удалось отправить заявку. Пожалуйста, попробуйте еще раз.", 400);
|
||||
}
|
||||
|
||||
$nowTs = time();
|
||||
$formMinFillSeconds = 0.4;
|
||||
$startedAtMs = (int)$startedAtRaw;
|
||||
if ($startedAtMs > 0) {
|
||||
$elapsedSeconds = ((int)floor(microtime(true) * 1000) - $startedAtMs) / 1000;
|
||||
if ($elapsedSeconds < $formMinFillSeconds) {
|
||||
respondError("Слишком быстрая отправка формы. Попробуйте еще раз.", 429);
|
||||
}
|
||||
}
|
||||
|
||||
$clientIp = (string)($_SERVER["REMOTE_ADDR"] ?? "unknown");
|
||||
if (isRateLimited($clientIp, $nowTs)) {
|
||||
respondError("Слишком много заявок за короткое время. Повторите попытку позже.", 429);
|
||||
}
|
||||
|
||||
if ($name === "") {
|
||||
respondError("Укажите имя");
|
||||
}
|
||||
|
||||
// Нормализуем имя: убираем лишние пробелы внутри.
|
||||
$name = preg_replace("/\\s+/u", " ", $name) ?? $name;
|
||||
|
||||
if (mb_strlen($name) < 2 || mb_strlen($name) > 80) {
|
||||
respondError("Имя должно быть от 2 до 80 символов");
|
||||
}
|
||||
|
||||
if (!preg_match("/^[\\p{L}\\s-]+$/u", $name)) {
|
||||
respondError("Имя может содержать только буквы, пробелы и дефис");
|
||||
}
|
||||
|
||||
$phoneDigits = preg_replace("/\\D+/", "", $phoneRaw) ?? "";
|
||||
if (strlen($phoneDigits) !== 11 || strpos($phoneDigits, "7") !== 0) {
|
||||
respondError("Укажите корректный телефон");
|
||||
}
|
||||
|
||||
if ($consent !== "1") {
|
||||
respondError("Необходимо согласие на обработку данных");
|
||||
}
|
||||
|
||||
// Укажите email в файле submit-config.php (предпочтительно для REG.RU)
|
||||
// или в переменной окружения FORM_RECIPIENT_EMAIL.
|
||||
$recipientEmail = "";
|
||||
$senderEmail = "";
|
||||
$configFile = __DIR__ . "/submit-config.php";
|
||||
if (is_file($configFile)) {
|
||||
require $configFile;
|
||||
}
|
||||
|
||||
if ($recipientEmail === "") {
|
||||
$recipientEmail = getenv("FORM_RECIPIENT_EMAIL") ?: "you@example.com";
|
||||
}
|
||||
|
||||
if (substr($recipientEmail, -11) === "@example.com") {
|
||||
respondError("Не настроен email получателя заявок. Укажите адрес в submit-config.php.", 500);
|
||||
}
|
||||
|
||||
$host = strtolower((string)($_SERVER["HTTP_HOST"] ?? "frieze-spb.ru"));
|
||||
$host = preg_replace("/:\\d+$/", "", $host) ?? "frieze-spb.ru";
|
||||
$host = preg_replace("/[^a-z0-9\\.-]/", "", $host) ?? "frieze-spb.ru";
|
||||
if ($host === "") {
|
||||
$host = "frieze-spb.ru";
|
||||
}
|
||||
$defaultSenderEmail = "noreply@" . $host;
|
||||
$fromEmail = $senderEmail !== "" ? $senderEmail : $defaultSenderEmail;
|
||||
if (!filter_var($fromEmail, FILTER_VALIDATE_EMAIL)) {
|
||||
$fromEmail = $defaultSenderEmail;
|
||||
}
|
||||
|
||||
$subject = "Новая заявка с сайта frieze-spb.ru";
|
||||
$encodedSubject = "=?UTF-8?B?" . base64_encode($subject) . "?=";
|
||||
|
||||
$messageLines = [
|
||||
"Новая заявка с сайта",
|
||||
"",
|
||||
"Имя: " . $name,
|
||||
"Телефон: " . $phoneRaw,
|
||||
"Телефон (цифры): +" . $phoneDigits,
|
||||
"Дата/время: " . date("d.m.Y H:i:s"),
|
||||
"IP: " . (string)($_SERVER["REMOTE_ADDR"] ?? "не определен"),
|
||||
"User-Agent: " . (string)($_SERVER["HTTP_USER_AGENT"] ?? "не определен"),
|
||||
];
|
||||
|
||||
$body = implode("\r\n", $messageLines);
|
||||
|
||||
$headers = [
|
||||
"MIME-Version: 1.0",
|
||||
"Content-Type: text/plain; charset=UTF-8",
|
||||
"From: Frieze Site <" . $fromEmail . ">",
|
||||
"Reply-To: " . $recipientEmail,
|
||||
"X-Mailer: PHP/" . PHP_VERSION,
|
||||
];
|
||||
|
||||
$sent = mail($recipientEmail, $encodedSubject, $body, implode("\r\n", $headers), "-f" . $fromEmail);
|
||||
|
||||
if (!$sent) {
|
||||
respondError("Не удалось отправить заявку. Попробуйте позже или позвоните по телефону.", 500);
|
||||
}
|
||||
|
||||
respondSuccess();
|
||||
@@ -0,0 +1,465 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Синхронизация прайса сайта с Excel.
|
||||
|
||||
Как пользоваться:
|
||||
1. Откройте prices.xlsx и правьте таблицу на листе "Цены"
|
||||
2. Запустите файл "обновить-цены.bat" (двойной клик)
|
||||
3. Залейте на хостинг обновлённый prices-data.js
|
||||
|
||||
Колонки Excel:
|
||||
A Раздел | B Подкатегория | C Название | D Цена (число) | E Ед.изм | F Кол-во | G Показывать (Да/Нет)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import openpyxl
|
||||
from openpyxl.styles import Alignment, Font, PatternFill, Border, Side
|
||||
from openpyxl.utils import get_column_letter
|
||||
from openpyxl.worksheet.datavalidation import DataValidation
|
||||
except ImportError:
|
||||
print("Нужна библиотека openpyxl. Установите: pip install openpyxl")
|
||||
sys.exit(1)
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
XLSX_PATH = ROOT / "prices.xlsx"
|
||||
JS_PATH = ROOT / "prices-data.js"
|
||||
|
||||
YES_VALUES = {"да", "yes", "y", "1", "true", "+", "д"}
|
||||
|
||||
|
||||
def js_str(value: str) -> str:
|
||||
return json.dumps(value, ensure_ascii=False)
|
||||
|
||||
|
||||
def parse_prices_js(text: str) -> list[dict]:
|
||||
"""Parse controlled prices-data.js format into nested Python structure."""
|
||||
cats: list[dict] = []
|
||||
|
||||
# Top-level categories: either with children or with items
|
||||
# Split by top-level objects roughly via brace matching after window assignment
|
||||
body = re.sub(r"^[\s\S]*?window\.PRICES_DATA\s*=\s*", "", text.strip())
|
||||
body = re.sub(r";\s*$", "", body).strip()
|
||||
if not (body.startswith("[") and body.endswith("]")):
|
||||
raise ValueError("Некорректный формат prices-data.js")
|
||||
|
||||
# Tokenize top-level category objects by scanning braces
|
||||
inner = body[1:-1]
|
||||
objects: list[str] = []
|
||||
depth = 0
|
||||
start = None
|
||||
for i, ch in enumerate(inner):
|
||||
if ch == "{":
|
||||
if depth == 0:
|
||||
start = i
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
if depth == 0 and start is not None:
|
||||
objects.append(inner[start : i + 1])
|
||||
start = None
|
||||
|
||||
def parse_items(blob: str) -> list[dict]:
|
||||
items = []
|
||||
for item in re.finditer(
|
||||
r'\{\s*name:\s*("(?:\\.|[^"\\])*")\s*,\s*price:\s*("(?:\\.|[^"\\])*")\s*,\s*amount:\s*("(?:\\.|[^"\\])*")\s*,\s*unit:\s*("(?:\\.|[^"\\])*")\s*\}',
|
||||
blob,
|
||||
):
|
||||
items.append(
|
||||
{
|
||||
"name": json.loads(item.group(1)),
|
||||
"price": json.loads(item.group(2)),
|
||||
"amount": json.loads(item.group(3)),
|
||||
"unit": json.loads(item.group(4)),
|
||||
}
|
||||
)
|
||||
return items
|
||||
|
||||
for obj in objects:
|
||||
title_m = re.search(r'title:\s*("(?:\\.|[^"\\])*")', obj)
|
||||
if not title_m:
|
||||
continue
|
||||
title = json.loads(title_m.group(1))
|
||||
children_m = re.search(r"children:\s*\[([\s\S]*)\]\s*$", obj.strip().rstrip("}"))
|
||||
# Better: find children array bounds
|
||||
children_idx = obj.find("children:")
|
||||
|
||||
if children_idx != -1:
|
||||
ch_start = obj.find("[", children_idx)
|
||||
# find matching closing bracket for children array
|
||||
depth = 0
|
||||
ch_end = None
|
||||
for i in range(ch_start, len(obj)):
|
||||
if obj[i] == "[":
|
||||
depth += 1
|
||||
elif obj[i] == "]":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
ch_end = i
|
||||
break
|
||||
children_blob = obj[ch_start + 1 : ch_end] if ch_end else ""
|
||||
children = []
|
||||
# child objects
|
||||
depth = 0
|
||||
start = None
|
||||
for i, ch in enumerate(children_blob):
|
||||
if ch == "{":
|
||||
if depth == 0:
|
||||
start = i
|
||||
depth += 1
|
||||
elif ch == "}":
|
||||
depth -= 1
|
||||
if depth == 0 and start is not None:
|
||||
child_obj = children_blob[start : i + 1]
|
||||
ctitle_m = re.search(r'title:\s*("(?:\\.|[^"\\])*")', child_obj)
|
||||
if not ctitle_m:
|
||||
continue
|
||||
children.append(
|
||||
{
|
||||
"title": json.loads(ctitle_m.group(1)),
|
||||
"items": parse_items(child_obj),
|
||||
}
|
||||
)
|
||||
start = None
|
||||
cats.append({"title": title, "children": children})
|
||||
else:
|
||||
cats.append({"title": title, "items": parse_items(obj)})
|
||||
|
||||
return cats
|
||||
|
||||
|
||||
def fmt_price_number(value) -> str:
|
||||
try:
|
||||
num = float(value)
|
||||
if num.is_integer():
|
||||
num = int(num)
|
||||
return f"{num:,}".replace(",", " ")
|
||||
except Exception:
|
||||
return str(value).strip()
|
||||
|
||||
|
||||
def extract_number_from_price(price: str):
|
||||
"""'от 1 200 ₽/м²' -> 1200"""
|
||||
if price is None:
|
||||
return ""
|
||||
if isinstance(price, (int, float)):
|
||||
return price
|
||||
s = str(price)
|
||||
s = re.sub(r"^от\s+", "", s, flags=re.I)
|
||||
s = re.sub(r"\s*₽.*$", "", s)
|
||||
s = s.replace(" ", "").replace("\u00a0", "")
|
||||
s = s.replace(",", ".")
|
||||
try:
|
||||
num = float(s)
|
||||
return int(num) if num.is_integer() else num
|
||||
except Exception:
|
||||
return s
|
||||
|
||||
|
||||
def build_price_string(number, unit: str) -> str:
|
||||
unit = (unit or "").strip()
|
||||
num = fmt_price_number(number)
|
||||
if unit and unit != "—":
|
||||
return f"от {num} ₽/{unit}"
|
||||
return f"от {num} ₽"
|
||||
|
||||
|
||||
def flatten_for_excel(data: list[dict]) -> list[dict]:
|
||||
rows = []
|
||||
for cat in data:
|
||||
section = cat.get("title", "")
|
||||
children = cat.get("children") or []
|
||||
if children:
|
||||
for child in children:
|
||||
sub = child.get("title", "")
|
||||
for item in child.get("items") or []:
|
||||
rows.append(
|
||||
{
|
||||
"section": section,
|
||||
"subcategory": sub,
|
||||
"name": item.get("name", ""),
|
||||
"price": extract_number_from_price(item.get("price", "")),
|
||||
"unit": item.get("unit", ""),
|
||||
"amount": item.get("amount", "1"),
|
||||
"show": "Да",
|
||||
}
|
||||
)
|
||||
else:
|
||||
for item in cat.get("items") or []:
|
||||
rows.append(
|
||||
{
|
||||
"section": section,
|
||||
"subcategory": "",
|
||||
"name": item.get("name", ""),
|
||||
"price": extract_number_from_price(item.get("price", "")),
|
||||
"unit": item.get("unit", ""),
|
||||
"amount": item.get("amount", "1"),
|
||||
"show": "Да",
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def export_xlsx_from_js() -> None:
|
||||
if not JS_PATH.exists():
|
||||
print(f"Не найден {JS_PATH.name}")
|
||||
sys.exit(1)
|
||||
|
||||
data = parse_prices_js(JS_PATH.read_text(encoding="utf-8"))
|
||||
rows = flatten_for_excel(data)
|
||||
|
||||
wb = openpyxl.Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Цены"
|
||||
|
||||
headers = ["Раздел", "Подкатегория", "Название работы", "Цена", "Ед.изм", "Кол-во", "Показывать"]
|
||||
header_fill = PatternFill("solid", fgColor="1F4E79")
|
||||
header_font = Font(color="FFFFFF", bold=True)
|
||||
thin = Border(
|
||||
left=Side(style="thin", color="BDD7EE"),
|
||||
right=Side(style="thin", color="BDD7EE"),
|
||||
top=Side(style="thin", color="BDD7EE"),
|
||||
bottom=Side(style="thin", color="BDD7EE"),
|
||||
)
|
||||
|
||||
for col, title in enumerate(headers, start=1):
|
||||
cell = ws.cell(1, col, title)
|
||||
cell.fill = header_fill
|
||||
cell.font = header_font
|
||||
cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||
|
||||
for i, row in enumerate(rows, start=2):
|
||||
values = [
|
||||
row["section"],
|
||||
row["subcategory"],
|
||||
row["name"],
|
||||
row["price"],
|
||||
row["unit"],
|
||||
row["amount"],
|
||||
row["show"],
|
||||
]
|
||||
for col, value in enumerate(values, start=1):
|
||||
cell = ws.cell(i, col, value)
|
||||
cell.border = thin
|
||||
cell.alignment = Alignment(vertical="center", wrap_text=True)
|
||||
if col == 4:
|
||||
cell.alignment = Alignment(horizontal="right", vertical="center")
|
||||
|
||||
widths = [34, 18, 70, 12, 10, 10, 12]
|
||||
for i, width in enumerate(widths, start=1):
|
||||
ws.column_dimensions[get_column_letter(i)].width = width
|
||||
|
||||
ws.freeze_panes = "A2"
|
||||
ws.auto_filter.ref = f"A1:G{len(rows) + 1}"
|
||||
|
||||
dv = DataValidation(type="list", formula1='"Да,Нет"', allow_blank=False)
|
||||
dv.error = "Выберите Да или Нет"
|
||||
dv.errorTitle = "Показывать"
|
||||
ws.add_data_validation(dv)
|
||||
dv.add(f"G2:G{max(2, len(rows) + 200)}")
|
||||
|
||||
# Instruction sheet
|
||||
info = wb.create_sheet("Инструкция", 0)
|
||||
info["A1"] = "Как обновлять цены на сайте"
|
||||
info["A1"].font = Font(bold=True, size=14)
|
||||
lines = [
|
||||
"",
|
||||
"1) Редактируйте только лист «Цены».",
|
||||
"2) Можно менять названия, цены, единицы, количество.",
|
||||
"3) Чтобы временно скрыть позицию с сайта — поставьте в колонке «Показывать» значение «Нет».",
|
||||
"4) Чтобы удалить позицию навсегда — удалите строку.",
|
||||
"5) Чтобы добавить новую позицию — добавьте новую строку в конец таблицы.",
|
||||
"6) Для разделов с подкатегориями заполняйте и «Раздел», и «Подкатегория»",
|
||||
" (например: Раздел = Демонтажные работы, Подкатегория = Полы).",
|
||||
"7) Для разделов без подкатегорий оставьте «Подкатегория» пустой",
|
||||
" (например: Электромонтажные работы).",
|
||||
"8) В колонке «Цена» пишите только число, например: 650",
|
||||
" На сайте автоматически станет: от 650 ₽/шт (если ед.изм = шт).",
|
||||
"9) После правок закройте Excel и запустите файл «обновить-цены.bat».",
|
||||
"10) На хостинг REG.RU залейте обновлённый файл prices-data.js",
|
||||
" (и при желании сам prices.xlsx — для вашего удобного хранения).",
|
||||
"",
|
||||
"Важно: сайт сам Excel не читает. Сначала bat обновляет prices-data.js, потом этот файл идёт на сайт.",
|
||||
]
|
||||
for idx, line in enumerate(lines, start=2):
|
||||
info[f"A{idx}"] = line
|
||||
info.column_dimensions["A"].width = 110
|
||||
|
||||
wb.save(XLSX_PATH)
|
||||
print(f"Создан/обновлён Excel: {XLSX_PATH.name} ({len(rows)} строк)")
|
||||
|
||||
|
||||
def nest_from_rows(rows: list[dict]) -> list[dict]:
|
||||
"""Build nested PRICES_DATA from flat excel rows, preserving order."""
|
||||
result: list[dict] = []
|
||||
section_map: dict[str, dict] = {}
|
||||
child_map: dict[tuple[str, str], dict] = {}
|
||||
|
||||
for row in rows:
|
||||
section = row["section"]
|
||||
sub = row["subcategory"]
|
||||
item = {
|
||||
"name": row["name"],
|
||||
"price": build_price_string(row["price"], row["unit"]),
|
||||
"amount": str(row["amount"] or "1"),
|
||||
"unit": row["unit"] or "—",
|
||||
}
|
||||
|
||||
if section not in section_map:
|
||||
section_obj = {"title": section}
|
||||
section_map[section] = section_obj
|
||||
result.append(section_obj)
|
||||
|
||||
section_obj = section_map[section]
|
||||
|
||||
if sub:
|
||||
key = (section, sub)
|
||||
if key not in child_map:
|
||||
if "children" not in section_obj:
|
||||
section_obj["children"] = []
|
||||
child = {"title": sub, "items": []}
|
||||
child_map[key] = child
|
||||
section_obj["children"].append(child)
|
||||
child_map[key]["items"].append(item)
|
||||
else:
|
||||
if "items" not in section_obj:
|
||||
section_obj["items"] = []
|
||||
section_obj["items"].append(item)
|
||||
|
||||
# Cleanup: if a section has children, drop empty items key
|
||||
for section_obj in result:
|
||||
if section_obj.get("children"):
|
||||
section_obj.pop("items", None)
|
||||
elif "items" not in section_obj:
|
||||
section_obj["items"] = []
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def write_prices_js(data: list[dict]) -> None:
|
||||
parts = ["window.PRICES_DATA = ["]
|
||||
for ci, cat in enumerate(data):
|
||||
parts.append(" {")
|
||||
parts.append(f" title: {js_str(cat['title'])},")
|
||||
if cat.get("children"):
|
||||
parts.append(" children: [")
|
||||
for si, sub in enumerate(cat["children"]):
|
||||
parts.append(" {")
|
||||
parts.append(f" title: {js_str(sub['title'])},")
|
||||
parts.append(" items: [")
|
||||
for ii, item in enumerate(sub["items"]):
|
||||
comma = "," if ii < len(sub["items"]) - 1 else ""
|
||||
parts.append(
|
||||
" { "
|
||||
f"name: {js_str(item['name'])}, "
|
||||
f"price: {js_str(item['price'])}, "
|
||||
f"amount: {js_str(item['amount'])}, "
|
||||
f"unit: {js_str(item['unit'])} "
|
||||
f"}}{comma}"
|
||||
)
|
||||
parts.append(" ]")
|
||||
parts.append(" }" + ("," if si < len(cat["children"]) - 1 else ""))
|
||||
parts.append(" ]")
|
||||
else:
|
||||
parts.append(" items: [")
|
||||
for ii, item in enumerate(cat.get("items") or []):
|
||||
comma = "," if ii < len(cat["items"]) - 1 else ""
|
||||
parts.append(
|
||||
" { "
|
||||
f"name: {js_str(item['name'])}, "
|
||||
f"price: {js_str(item['price'])}, "
|
||||
f"amount: {js_str(item['amount'])}, "
|
||||
f"unit: {js_str(item['unit'])} "
|
||||
f"}}{comma}"
|
||||
)
|
||||
parts.append(" ]")
|
||||
parts.append(" }" + ("," if ci < len(data) - 1 else ""))
|
||||
parts.append("];")
|
||||
parts.append("")
|
||||
JS_PATH.write_text("\n".join(parts), encoding="utf-8")
|
||||
|
||||
|
||||
def import_xlsx_to_js() -> None:
|
||||
if not XLSX_PATH.exists():
|
||||
print(f"Не найден {XLSX_PATH.name}. Сначала создайте его командой: python update-prices.py --init")
|
||||
sys.exit(1)
|
||||
|
||||
wb = openpyxl.load_workbook(XLSX_PATH, data_only=True)
|
||||
if "Цены" not in wb.sheetnames:
|
||||
print("В Excel нет листа «Цены»")
|
||||
sys.exit(1)
|
||||
ws = wb["Цены"]
|
||||
|
||||
rows = []
|
||||
skipped = 0
|
||||
for r in range(2, ws.max_row + 1):
|
||||
section = ws.cell(r, 1).value
|
||||
sub = ws.cell(r, 2).value
|
||||
name = ws.cell(r, 3).value
|
||||
price = ws.cell(r, 4).value
|
||||
unit = ws.cell(r, 5).value
|
||||
amount = ws.cell(r, 6).value
|
||||
show = ws.cell(r, 7).value
|
||||
|
||||
section = str(section).strip() if section is not None else ""
|
||||
sub = str(sub).strip() if sub is not None else ""
|
||||
name = str(name).strip() if name is not None else ""
|
||||
unit = str(unit).strip() if unit is not None else ""
|
||||
amount = str(amount).strip() if amount is not None else "1"
|
||||
show_s = str(show).strip().lower() if show is not None else "да"
|
||||
|
||||
if not section and not name:
|
||||
continue
|
||||
if not name:
|
||||
skipped += 1
|
||||
continue
|
||||
if show_s not in YES_VALUES:
|
||||
skipped += 1
|
||||
continue
|
||||
if price in (None, ""):
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
rows.append(
|
||||
{
|
||||
"section": section or "Прочее",
|
||||
"subcategory": sub,
|
||||
"name": name,
|
||||
"price": price,
|
||||
"unit": unit,
|
||||
"amount": amount or "1",
|
||||
}
|
||||
)
|
||||
|
||||
data = nest_from_rows(rows)
|
||||
write_prices_js(data)
|
||||
total_items = sum(
|
||||
len(c.get("items") or [])
|
||||
+ sum(len(ch.get("items") or []) for ch in (c.get("children") or []))
|
||||
for c in data
|
||||
)
|
||||
print(f"Готово: {JS_PATH.name}")
|
||||
print(f"Разделов: {len(data)}")
|
||||
print(f"Позиций на сайте: {total_items}")
|
||||
if skipped:
|
||||
print(f"Пропущено строк (скрытые/пустые): {skipped}")
|
||||
print("Теперь залейте prices-data.js на хостинг REG.RU")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = sys.argv[1:]
|
||||
if "--init" in args or "--export" in args or not XLSX_PATH.exists():
|
||||
export_xlsx_from_js()
|
||||
if "--init" in args or "--export" in args:
|
||||
return
|
||||
import_xlsx_to_js()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,60 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo ================================
|
||||
echo Обновление прайса сайта из Excel
|
||||
echo ================================
|
||||
echo.
|
||||
|
||||
where python >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
echo [Ошибка] Python не найден.
|
||||
echo Установите Python с https://www.python.org/downloads/
|
||||
echo и отметьте галочку "Add python.exe to PATH".
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
python -c "import openpyxl" >nul 2>nul
|
||||
if errorlevel 1 (
|
||||
echo Устанавливаю библиотеку openpyxl...
|
||||
python -m pip install openpyxl
|
||||
if errorlevel 1 (
|
||||
echo [Ошибка] Не удалось установить openpyxl.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
if not exist "prices.xlsx" (
|
||||
echo Excel ещё нет — создаю prices.xlsx из текущего прайса сайта...
|
||||
python update-prices.py --init
|
||||
if errorlevel 1 (
|
||||
echo [Ошибка] Не удалось создать prices.xlsx
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
echo Создан файл prices.xlsx
|
||||
echo Откройте его, отредактируйте и снова запустите этот bat.
|
||||
echo.
|
||||
pause
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
python update-prices.py
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo [Ошибка] Обновление не выполнено.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo Готово.
|
||||
echo 1^) Проверьте сайт локально на странице Цены
|
||||
echo 2^) Залейте на REG.RU файл prices-data.js
|
||||
echo.
|
||||
pause
|
||||