96 Commits

Author SHA1 Message Date
erjemin 19a595fb10 minor: изменения в замерах времени исполнения вьюшки 2026-04-20 23:23:05 +03:00
erjemin 917d62cc21 mod: split catalog modules and refactor profile manufacture view 2026-04-20 22:23:42 +03:00
erjemin 71b5089a61 fix: явное указание типов 2026-04-20 01:02:16 +03:00
erjemin 9e27089638 minor: в отдельный catalog_profiles.py выделены все вьюхи для каталога профилей 2026-04-20 00:54:11 +03:00
erjemin af67b69418 mod: рефакторинг catalog_profile_model и обновление дорожной карты README 2026-04-20 00:43:27 +03:00
erjemin af2489f923 minor: ticks стал видимым 2026-04-20 00:33:13 +03:00
erjemin 0b6536b8f4 mod: simplify catalog profile views 2026-04-19 23:43:13 +03:00
erjemin c930e059a0 mod: catalog_profile и документация 2026-04-18 15:39:39 +03:00
erjemin c0b41cd866 add: SITEMAP_RUNBOOK.md; mod: README.md — обновлена документация проекта 2026-04-18 13:48:28 +03:00
erjemin b348c8fe81 mod: rework sitemap generation and seo coverage 2026-04-18 13:28:15 +03:00
erjemin e7da2cdeb9 mod: migrate to poetry and add django debug toolbar for dev 2026-04-17 16:07:19 +03:00
erjemin d5719015b0 mod: switch secrets config to .env 2026-04-17 15:18:05 +03:00
erjemin bcc10de4d4 minor: комментарии fix имя файла 2026-04-16 21:28:18 +03:00
erjemin 55f9a74231 del: нет логам в репозитории 2026-04-16 21:20:24 +03:00
erjemin 49c19d9f92 mod: добавлен сервис пересчета рейтинга 2026-04-16 21:15:19 +03:00
erjemin 67a8c093f5 mod: add favicon 2026-04-16 21:13:53 +03:00
erjemin e0a5a5739b minor: del print 2026-04-16 21:12:31 +03:00
erjemin 3e67d6cf71 mod: switch dev to sqlite and add static fallback paths 2026-04-16 21:10:58 +03:00
erjemin 917bcb42c8 minor: del print 2026-04-16 20:37:45 +03:00
erjemin 5bdb97f5e8 add: initial commit — Django 4.1 project (2022 version), docs, security templates 2026-04-16 15:55:21 +03:00
erjemin e2091b72b1 Static: недостающие файлы из error.log 2023-03-04 00:20:53 +03:00
erjemin 446cbe8c5c SEO: Title & Description 2023-03-04 00:19:41 +03:00
erjemin bdca8dfc6a SEO: Title & Description (каталог профилей) 2023-02-17 22:01:15 +03:00
erjemin 111dd7bd33 SEO: Title & Description 2023-02-17 19:18:18 +03:00
erjemin 57a522f4b7 minor: недостающая статика (png) 2023-02-17 19:12:02 +03:00
erjemin 2b37f709a9 minor: недостающая статика (css, js) 2023-02-15 23:51:25 +03:00
erjemin f480dc3666 minor: favicon.svg 2023-02-10 20:39:25 +03:00
erjemin 2da036e4e0 minor: убрал отладочный print() 2023-01-29 23:01:26 +03:00
erjemin 28620ce2a9 minor: excel-шаблоны для загрузки и заполнения 2023-01-29 22:57:14 +03:00
erjemin 574ae84321 minor: первый экран, изменен текст (SEO) 2023-01-29 18:20:48 +03:00
erjemin 796cb89525 minor: кеш картинок и шаблонов (++) 2023-01-19 00:52:52 +03:00
erjemin 0e8839bf18 minor: кеш картинок и шаблонов (+) 2023-01-19 00:46:06 +03:00
erjemin dbd622e456 minor: кеш картинок и шаблонов 2023-01-18 00:38:03 +03:00
erjemin 741dd2685e minor: вот так работает в продашн 2023-01-18 00:15:58 +03:00
erjemin c01873144e ini для uwsgi (tested) 2023-01-14 04:22:25 +03:00
erjemin 8387d36abf конфиг для nginx (tested) 2023-01-14 04:21:41 +03:00
erjemin 2bc0869104 обновленные пакеты окружения для dev на mac-m1 (python 3.10.9) 2023-01-14 04:04:08 +03:00
erjemin 8c7972178c имя файла к touch-reload для девопа 2023-01-14 04:02:05 +03:00
erjemin c338a17dd8 передергивает touch-reload при изменении кеш-шаблона 2023-01-14 03:49:55 +03:00
erjemin 3cc4ae39f7 minor 2023-01-14 02:42:49 +03:00
erjemin d789b2443a пакеты окружения (дев/прод) 2023-01-14 02:19:58 +03:00
erjemin 25beecdf60 пакеты окружения (дев/прод) 2023-01-14 02:19:39 +03:00
erjemin 5eb2f304a3 доки по профилям монблан 2023-01-14 02:18:46 +03:00
erjemin 0246c1de8c minor (error -- был пустой slag для текущей серии) 2023-01-14 01:43:14 +03:00
erjemin 4196cd64d8 minor (без переменной template) 2023-01-14 01:17:59 +03:00
erjemin 60b6582f1b minor (исправлены типы переменных для совместимости с продакшн) 2023-01-13 22:23:24 +03:00
erjemin 4a91928bc7 картинки для блога 2023-01-13 22:13:17 +03:00
erjemin b322331366 картинки к сериям домов 2023-01-13 22:08:21 +03:00
erjemin e041110059 логотипы компаний из базы 2023-01-13 21:57:56 +03:00
erjemin ae1b851db7 touch-reload.txt 2023-01-13 19:46:51 +03:00
erjemin 28aa35d617 nginx conf-file for production 2023-01-13 19:18:04 +03:00
erjemin b296ad79e9 favicon & other static 2023-01-13 17:27:16 +03:00
erjemin fbea58b1c4 Служебное -- формирование sitemap-файлов 2023-01-10 01:21:28 +03:00
erjemin 30084dd6ac minor -- точные размеры в мм. в заголовке и крошках 2023-01-09 23:30:49 +03:00
erjemin c961b64036 minor -- размеры и мм. тоже 2023-01-09 23:29:57 +03:00
erjemin ad74f0a51e Служебное -- главные служебные (если есть и нет аутентификации) 2023-01-08 19:41:12 +03:00
erjemin 78ec6077b6 Служебное -- главна и аутентификация 2023-01-08 19:36:48 +03:00
erjemin c68fa5be07 Служебное -- страница для тестирования верстки текста в блоге 2023-01-08 18:14:27 +03:00
erjemin ee1dd31d54 Переадресация для старых, внешних ссылок 2023-01-08 01:38:14 +03:00
erjemin 6066e5df29 Подгружаемый блок с детальным описанием состава рейтинга -- готово 2023-01-07 04:51:11 +03:00
erjemin 8704f4125b удалён лишний шаблон 2023-01-07 03:42:47 +03:00
erjemin 2777f3fde2 Вьюшка и шаблон: сравнение оконных наборов -- готово 2023-01-07 03:42:14 +03:00
erjemin 4b9ca319f9 кеш картинки со схемами открывания 2022-12-31 13:54:15 +03:00
erjemin 56d7af5c9d перенос и переименование шаблонов 2022-12-31 05:13:12 +03:00
erjemin 0368c1c34e Вьюшка: подгружаемые фреймы с ценами одного типового окна -- готово 2022-12-31 05:01:39 +03:00
erjemin fbdf95b66f minor 2022-12-31 04:44:38 +03:00
erjemin 8fdaf6935e minor (переименование шаблонов) 2022-12-31 04:44:11 +03:00
erjemin 8272bdb25f Вьюшка: Подгружаемых фреймов ценовых предложений -- minor 2022-12-31 04:36:40 +03:00
erjemin 6a4c315cdc Вьюшка: Подгружаемых фреймов ценовых предложений -- готово 2022-12-31 04:33:59 +03:00
erjemin f2c89abe1c Вьюшка : Выдача предложений -- minor (убраны отладочные print) 2022-12-31 02:57:49 +03:00
erjemin 37a605ef09 Вьюшка и шаблоны: Выдача предложений -- готово 2022-12-31 02:55:09 +03:00
erjemin 28a680fdf1 Отдельный каталог для шаблонов выпадающей окон -- minor 2022-12-30 19:58:56 +03:00
erjemin 9bcbc73602 Выпадающее окно после ввода адреса -- готово 2022-12-30 19:52:42 +03:00
erjemin 8ca1f5b36e Кеш-картинки схем открывания (большие и маленькие) 2022-12-30 15:31:17 +03:00
erjemin 6c4dcd1cb7 Ценовая выдача для одного окна 2022-12-30 15:30:05 +03:00
erjemin 5a38181cd3 Оптимизация + на мини-картинках схем открывания рисуется спейсер и москитная сетка 2022-12-29 17:25:41 +03:00
erjemin 5738ee9c9e Шаблон: "Каталог / Производители и поставщики окон / Компания" -- minor 2022-12-29 16:10:26 +03:00
erjemin 9535424e6a Шаблон: "Каталог / Производители и поставщики окон / Компания" -- minor: seo, Yandex.map 2022-12-29 15:56:14 +03:00
erjemin 4e03fead67 Вьюшка и шаблон: "Каталог / Производители и поставщики окон / Компания" -- готово 2022-12-29 15:46:16 +03:00
erjemin 5de28c8bfb Вьюшка: "Каталог / Производители и поставщики окон" -- minor 2022-12-29 00:18:53 +03:00
erjemin de45931ff4 Вьюшка и шаблон: "Каталог / Производители и поставщики окон" -- готово 2022-12-29 00:17:27 +03:00
erjemin d27d0e7173 Шаблоны prerender: "Каталог / Типовые серии зданий / Информация по серии" -- minor, SEO 2022-12-27 15:21:38 +03:00
erjemin f3a8a65afe Шаблон: "Каталог / Типовые серии зданий / Информация по серии" и "Статистика" -- minor seo 2022-12-27 15:19:08 +03:00
erjemin 72b71c7810 Шаблон и css: "Каталог / Оконные проёмы и балконные блоки" -- минор 2022-12-27 14:57:34 +03:00
erjemin 6bd8143d83 avatar image (для блога и "о компании") 2022-12-27 14:17:04 +03:00
erjemin a970b7109b prerender small-image со схемами открывания (2022-12-27) 2022-12-27 14:15:16 +03:00
erjemin 99b8ba80d5 Вьюшка и шаблон: "Каталог / Оконные проёмы и балконные блоки" -- готово 2022-12-27 14:13:29 +03:00
erjemin 7cc438d1c5 миграции 2022-12-26 18:30:26 +03:00
erjemin 034ec20c26 Про кеширующие шаблоны 2022-12-26 18:30:09 +03:00
erjemin 90ddc0d88c Вьюшка: "Информация по всем сериям домой" -- minor
перенесли одну формирования навигации по сериям
2022-12-26 18:28:52 +03:00
erjemin 6e92eca67a prerender image со схемами открывания (2022-12-26 минор) 2022-12-26 18:13:57 +03:00
erjemin 6a9c0e4568 Шаблоны prerender: "Каталог / Типовые серии зданий / Информация по серии" -- minor 2022-12-26 18:08:33 +03:00
erjemin 265732bae8 Шаблон: "Каталог / Типовые серии зданий / Информация по серии" -- minor (data, last modified, еxpires) 2022-12-26 18:04:35 +03:00
erjemin cded4e407e prerender image со схамами открывания (2022-12-26) 2022-12-26 18:02:20 +03:00
erjemin f996dd891e prerender image со схамами открывания (2022-12-26) 2022-12-26 17:42:59 +03:00
erjemin 748a1882e5 Вьюшка: "Каталог / Типовые серии зданий / Информация по серии" -- prerender template (2022-12-26) -
Эти шаблоны надо периодически удалять. Они нужны для скорости. Но если меняются данные по серии, размерам окон, появляются новые ком.предложения -- их надо удалять и тогда построятся новые.
2022-12-26 17:34:28 +03:00
386 changed files with 21914 additions and 1084 deletions
+140
View File
@@ -0,0 +1,140 @@
# Django Configuration Example
# Все настройки читаются из переменных окружения (DEV/PROD без распознавания хоста)
# Для локальной разработки можно скопировать файл в .env.local и экспортировать его.
# ============================================================================
# DJANGO
# ============================================================================
# Django SECRET_KEY - сгенерируйте с помощью:
# python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())'
DJANGO_SECRET_KEY=your-super-secret-key-here-change-me
# Режим отладки (НИКОГДА не True на продакшене!)
DEBUG=False
# Допустимые хосты (разделены запятой без пробелов)
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
# Базовый публичный URL сайта (используется для абсолютных URL в sitemap.xml)
SITE_BASE_URL=https://yourdomain.com
# Админы для email-оповещений Django (формат: Имя:email,Имя2:email2)
ADMINS=Admin:admin@example.com
# ============================================================================
# DATABASE
# ============================================================================
# Database backend (по умолчанию SQLite)
DATABASE_ENGINE=django.db.backends.sqlite3
# Имя/путь базы данных:
# - для SQLite: только имя файла (полный путь соберется в settings.py через PROJECT_ROOT/database)
# - для MySQL/MariaDB: имя базы
DATABASE_NAME=oknadria.sqlite3
# Для MySQL/MariaDB (используются, если DATABASE_ENGINE=django.db.backends.mysql)
# DATABASE_HOST=localhost
# DATABASE_PORT=3306
# DATABASE_USER=name-for-db-user
# DATABASE_PASSWORD=your-db-password-here
# Пути вычисляются автоматически внутри settings.py от PROJECT_ROOT
TOUCH_RELOAD=/app/logs/touch-reload.txt
# Подкаталог в MEDIA_ROOT, где хранится кеш sitemap-файлов
SITEMAP_SUBDIR=_serv_sitemap
# ============================================================================
# EMAIL
# ============================================================================
# Email backend
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
# SMTP Settings
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_USE_SSL=False
EMAIL_HOST_USER=your-email@example.com
EMAIL_HOST_PASSWORD=your-email-password
# Default from email
DEFAULT_FROM_EMAIL=noreply@example.com
SERVER_EMAIL=admin@example.com
# ============================================================================
# SECURITY
# ============================================================================
# HTTPS and secure cookies (включить на продакшене)
SECURE_SSL_REDIRECT=False
SESSION_COOKIE_SECURE=False
CSRF_COOKIE_SECURE=False
# ============================================================================
# CAPTCHA
# ============================================================================
# Google reCAPTCHA v2
# Получите на https://www.google.com/recaptcha/admin
# ВАЖНО: Никогда не коммитьте реальные ключи в git!
CAPTCHA_PUBLIC_KEY=your-recaptcha-public-key-here
CAPTCHA_PRIVATE_KEY=your-recaptcha-private-key-here
# ============================================================================
# EXTERNAL APIs
# ============================================================================
# Yandex Maps
# Получите на https://developer.tech.yandex.ru/
YANDEX_MAPS_API_KEY=your-yandex-maps-api-key
# ============================================================================
# LOGGING
# ============================================================================
# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_LEVEL=INFO
# ============================================================================
# CACHE (опционально, если используется Redis)
# ============================================================================
# CACHE_BACKEND=redis
# CACHE_LOCATION=redis://localhost:6379/1
# ============================================================================
# CELERY (опционально, если используется Celery)
# ============================================================================
# CELERY_BROKER_URL=redis://localhost:6379/0
# CELERY_RESULT_BACKEND=redis://localhost:6379/0
# ============================================================================
# ИНСТРУКЦИЯ ПО ИСПОЛЬЗОВАНИЮ
# ============================================================================
# 1. Скопируйте этот файл:
# cp .env.sample .env.local
#
# 2. Отредактируйте значения в .env.local:
# nano .env.local
#
# 3. Убедитесь, что .env.local в .gitignore:
# grep ".env" .gitignore
#
# 4. Экспортируйте переменные перед запуском Django:
# set -a; source .env.local; set +a
#
# ВАЖНО:
# - НИКОГДА не коммитьте .env.local или файлы с реальными значениями в git!
# - На продакшене используйте переменные окружения, установленные в:
# - systemd service файл
# - Docker env vars
# - Kubernetes secrets
# - AWS Systems Manager Parameter Store
# - HashiCorp Vault
+31
View File
@@ -133,3 +133,34 @@ dmypy.json
# Pyre type checker
.pyre/
# MacOS specific files
.DS_Store
# Database dumps and backups (CRITICAL - NEVER commit production data!)
SQL/
*.sql
*.dump
*.backup
*.sql.gz
db.json
db.json.zip
# API keys, certificates, and credentials
*.key
*.pem
*.p12
*.p8
*.crt
*.cert
# IDE and editor specific
.vscode/settings.json
.idea/vcs.xml
.idea/inspectionProfiles/
# Project specific ignore patterns
.github/
.log/
.logs/
sitemap*.xml
+230
View File
@@ -0,0 +1,230 @@
# AGENTS.md — Окнардия: Оконный Агрегатор
**Версия**: 0.2.0 | **Язык**: Python 3.12+ + Django 6.0+ | **БД**: MariaDB/MySQL
Этот документ обеспечивает AI-агентов (Copilot, Claude, Cursor и т.д.) контекстом для эффективной работы с проектом.
## Архитектура и назначение
**Окнардия** — это агрегатор для сравнения цен на установку оконных конструкций в зданиях типового (серийного) строительства в России. Пользователи вводят адрес дома → система распознаёт серию строения → выдаёт типовые размеры оконных проемов → показывает предложения от поставщиков на установку (замену) окон.
Архитектура двухуровневая:
- **Основной проект**: `oknardia/` (Django settings, URL routing, models, templates)
- **Приложение логики**: `web/` (views, вспомогательные функции, кеширование схем окон)
## Критические компоненты и модели данных
### Основные модели (oknardia/models.py)
**Иерархия зданий:**
- `Seria_Info` — серия типового строения (P-44, 5-этажка и т.п.), поддерживает self-referential FK для древовидной структуры
- `Building_Info` — конкретный адрес с ссылкой на серию; содержит ~30 полей метаданных (площадь, износ, материалы)
- `Apartment_Type` — типовой план квартиры в серии; содержит связь M2M с `Win_MountDim`
- `MountDim2Apartment` — через-таблица между проёмами и квартирами
**Каталог и цены:**
- `PVCprofiles` — PVC-профили (окна), содержат рейтинг (0…+5) и tech-specs
- `Glazing` — стеклопакеты с изоляционными параметрами и рейтингом
- `SetKit` — готовый "набор" (профиль + стеклопакет + фурнитура + монтаж), связывает компоненты и хранит бизнес-условия
- `PriceOffer` — финальная цена для конкретного проёма и набора от конкретного пользователя
**Дополнительные сущности:**
- `OurUser` — собственная система пользователей (расширение Django User)
- `MerchantBrand` / `MerchantOffice` — организационная иерархия поставщиков
- `BlogPosts` — универсальная таблица для блога и каталога (одна таблица, флаги `bCatalog`, `bPublished`)
- Несколько LOG-таблиц: `LogMeasure`, `LogDemand`, `LogVisitPriceReport`
**Именование полей** (обязательное соглашение):
- `s*` = String/Char
- `i*` = Integer
- `f*` = Float/Decimal
- `b*` = Boolean
- `d*` = DateTime/Date
- `k*` = Foreign Key (связь)
- `p*` = Path/Media
- Например: `sSetName` — название набора, `fSetRating` — рейтинг набора
### Кеширование и специфика
1. **Картинки схем окон** генерируются автоматически в:
- `public/static/img/_flap.cfg` — большие картинки схем открывания
- `public/static/img/_miniflap.cfg` — миниатюры для таблиц
- **Важно**: не удалять просто так, они переиспользуются; если схема архивируется, картинка остаётся без явного удаления
2. **Pre-render HTML-шаблоны** для серий в `oknardia/templates/seria_info/prepared/`
- Создаются при первом обращении к странице серии
- **Требуют ручной очистки** при изменении цен/спецификаций или настройки cronjob на удаление
3. **Кольцевой буфер логирования** (настройка `MAX_LEN_RING_LOG_BUFFER=250` в settings)
## Workflow и точки входа
### Основной сценарий пользователя:
1. **Главная** (`/`) → `views.main_init()` — отслеживание кук посещений
2. **Автокомплит адреса** (`/autocomplete_addr`) → `autocomplete_addr.autocomplete_addr()` — подсказки при вводе
3. **Поиск по адресу** (`/get_address`) → `views.get_address()` — распознание серии здания
4. **Ценовая выдача** (`/{build_id}/{apart_id}/*`) → `prices.report_price()` — основной отчёт с фильтрацией и пагинацией по фреймам
### Каталоги и отчёты:
- `catalog.py` — каталог профилей, производителей, серий (с методом `catalog_seria_info()`)
- `report1.py` — сравнение наборов (`compare_offers()`) с расчётом рейтинговых компонент
- `report2.py` — рейтинги и ранжирование (фильтрация по звёздочкам и весам)
- `diagrams.py` — статистика и аналитика
### Система пользователей:
- `user_manager.py` — регистрация, логин/logout, восстановление пароля, верификация email
- Использует собственные таблицы `OurUser` + стандартный Django `User`
## Специфические технологии и паттерны
### Конфигурация через settings.py:
- **Двойной хост** (DEV и PROD) по `socket.gethostname()` — разные БД, media-пути, сценарии отладки
- Настройки ранжирования через веса (более 20 констант типа `RANK_STEP_*`, `RARING_*`)
- Google Captcha и Yandex Maps API ключи из `my_secret.py`
### Импорт конфиденциальных данных:
```python
from oknardia.my_secret import * # в settings.py и models.py
```
**⚠️ Важно**: `my_secret.py` содержит пароли БД, SECRET_KEY и должен быть в `.gitignore`
### Использование JSON в моделях:
- Поле `sProfileDescription` (Profiles), `sGlazingDescription`, `sSetDescription` — JSON или HTML в TextField
- Нет явной валидации структуры JSON при сохранении
### Система рейтинга и ранжирования:
- Каждый компонент (профиль, стеклопакет, набор) имеет рейтинг
- Веса рейтинга задают важность каждого атрибута (теплопередача, звукоизоляция и т.п.)
- `report1.show_rating_components()` раскрывает формулу расчёта рейтинга
### Интернационализация:
- `LANGUAGE_CODE = 'ru-RU'`, `TIME_ZONE = 'Europe/Moscow'`
- `USE_I18N = True`, `FIRST_DAY_OF_WEEK = 1` (понедельник)
- Все названия моделей и help_text на русском языке
## Конвенции кодирования
Из `.github/copilot-instructions.md`:
**Обязательные правила:**
- **Язык**: отвечай на русском, комментарии кода на русском
- **Стиль**: PEP 8 для Python, используй современные возможности (Python 3.12+, Django 6.0+)
- **Управление зависимостями**: `poetry` (вместо pip/requirements.txt)
- **Переменные окружения**: секреты в `.env`, не в коде
- **Git коммиты**:
- `add: <описание>` — новая функция/файл
- `fix: <описание>` — баг
- `mod: <описание>` — переработка кода
- `minor: <описание>` — форматирование, опечатки, мелкие комменты
- **Удаление старого кода**: помечать меткой `# Удалить:`, не стирать просто
- **Тон**: неформальный, профессиональный, образность допускается (как с коллегой)
⚠️ **Исключения**:
- Не удаляй старый код без явного указания
- Всегда уточняй перед `git commit` / `git push`
- Если модель требует миграций, опиши шаги для `python manage.py makemigrations/migrate`
## Типичные рабочие циклы
### Добавление нового фильтра в ценовую выдачу:
1. Добавить поле в модель (например, `SetKit`) → создать миграцию
2. Обновить фильтрацию в `prices.report_price()` → использовать Q-объекты
3. Обновить template для выбора фильтра (`templates/price/*.html`)
4. Проверить влияние на рейтинг в `report1.py` если нужно
### Обновление рейтинга и ранжирования:
1. Модифицировать вес в settings.py (RANK_STEP_*, RARING_*)
2. Пересчитать рейтинг в моделях через функцию `save()` или создать management-command
3. Проверить результаты в `report2.ratings()` и `report2.profiles_rating()`
### Кеширование и производительность:
- Картинки схем кешируются автоматически; при добавлении новой схемы нужно явно вызвать функцию генерации
- Pre-render HTML нужно чистить при обновлении ценовых данных (см. управление файлами в `seria_info/prepared/`)
- БД индексирована на часто используемых полях (`db_index=True`)
### Разработка на macOS:
- При установке `mysqlclient` может потребоваться `brew install mariadb-connector-c`
- Подробнее см. README.md, раздел "Некоторые заметки относительно разработки"
## Структура папок
```
oknardia/
├── manage.py
├── oknardia/
│ ├── models.py # ВСЕ модели (1900+ строк)
│ ├── settings.py # конфиг, импорт my_secret.py
│ ├── urls.py # маршруты (113 строк)
│ ├── admin.py
│ ├── views.py # главная, контакты, тариф
│ └── my_secret.py # CONFIDENTIAL: пароли, ключи
├── web/
│ ├── views.py # основная логика
│ ├── add_func.py # утилиты (геокод, расстояния)
│ ├── prices.py # отчёты ценовой выдачи
│ ├── report1.py # сравнение наборов
│ ├── report2.py # рейтинги и ранжирование
│ ├── catalog.py # каталоги
│ ├── diagrams.py # статистика
│ ├── blog.py # список и посты блога
│ ├── autocomplete_addr.py # автокомплит адресов
│ ├── user_manager.py # логин, регистрация
│ └── service.py # служебные функции (sitemap, очистка)
├── templates/ # Django шаблоны (Jinja2-like)
│ ├── base.html
│ ├── index.html # главная
│ ├── seria_info/prepared/ # пре-рендер кеш
│ ├── price/
│ ├── catalog/
│ └── ...
└── public/
├── static/
│ ├── img/_flap.cfg/ # схемы окон (большие)
│ ├── img/_miniflap.cfg/ # схемы окон (мини)
│ ├── css/
│ ├── js/
│ └── ...
└── media/ # загружаемые файлы
```
## Отладка и команды
```bash
# Разработка
python manage.py runserver # локальный сервер
python manage.py makemigrations # подготовить миграцию
python manage.py migrate # применить миграцию
# Администрирование
python manage.py shell # интерпретатор с контекстом Django
python manage.py createsuperuser # создать админа
python manage.py collectstatic # собрать статику для продакшена
# Служебные (см. service.py)
# Находятся в urls.py: /service/make_sitemaps, /service/make_rating
```
## Типичные ошибки и подводные камни
1. **Забывчивость миграций**: при добавлении полей в модель сразу создавай миграцию
2. **Нарушение именования полей**: новые поля должны начинаться с префикса (s, i, f, b, d, k, p)
3. **Незакешированные картинки**: если добавляешь новую схему открывания, вызови функцию генерации явно
4. **Неочищенные pre-render шаблоны**: могут вызвать устаревание данных на страницах серий
5. **Foreign Key ON_DELETE**: используется в основном `DO_NOTHING` и `SET_NULL`, будь осторожен при удалении
6. **Двойной хост**: убедись, что используешь правильные переменные из `my_secret.py` для текущей машины
7. **Индексирование БД**: большинство полей для поиска уже имеют `db_index=True`, но проверь при добавлении фильтров
8. **SEO-даты и свежесть контента**: при переделке вьюх/шаблонов отдельно проверяй, нужны ли ещё `last_update`, `PUB_DAT`, `Date4Meta` и `Last4Meta`; если дата не участвует в смысловой логике страницы, лучше оставить базовые `{% now %}` из `base.html`, а не тащить лишний контекст во вьюху и не нагружать бекенд.
## Реферальные ссылки (для более глубокого изучения)
- **Django 6.0+ docs**: https://docs.djangoproject.com/en/stable/
- **MariaDB/MySQL**: Конфиг БД в settings.py, ENGINE = "django.db.backends.mysql"
- **Система рейтинга**: см. functions в report1.py и constants в settings.py (RANK_*, RARING_*)
- **Фронтенд**: Bootstrap 3.3.7 (в static/bootstrap-3.3.7-dist.zip), jQuery, Yandex Maps API
---
**Автор инструкций**: проанализировано 16.04.2026
**Версия документа**: 1.0
**Последнее обновление**: инструкции в `.github/copilot-instructions.md`
+57 -2
View File
@@ -1,8 +1,63 @@
# Оконный агрегатор «Окнардия»
### Переделка под Python 3.8 и Django 4.1
### Переделка под Python 3.12 и Django 5.2
### Актуальная памятка дорожная карта
#### Готово:
* Изменена база данных используемая в проекте (SQLite вместо MariaDB).
* Окружение проекта теперь настраивается через `poetry` вместо `pip` и `requirements.txt`.
* Проект получает настройки и секреты через переменные окружения (`.env`) вместо `my_secret*.py`.
* Рефакторинг создания `sitemap.xml`: raw ⟶ ORM, создание через Django-команду `generate_sitemaps` в медиа-файлы.
* Рефакторинг URL `/catalog/profil/`: raw SQL ⟶ ORM, убран `last_update`, измененs SEO `description` и `keywords`.
* Распилен `oknardia/web/catalog.py` на тематические модули (`catalog_companies.py`, `catalog_profiles.py`, `catalog_series.py`, `catalog_openings.py`) с вынесением общей логики в `catalog_utils.py`; маршруты обновлены без изменения внешних URL.
* Рефакторинг `catalog_profile_model` (`/catalog/profile/...`): raw SQL ⟶ ORM, упрощена логика, вынесены helper-функции, сокращено дублирование расчёта цветов рейтинга, нормализована подготовка `LIST_OTHER`/`MERCHANTS`/`PROFILES`/`PROFILE_DETAIL`, сохранена совместимость шаблонов.
* Рефакторинг `catalog_profile_manufacture` (`/catalog/profile/<id>-<manufacturer>`): упрощена валидация URL, убран дублирующий код маппинга для `PROFILES` и `MERCHANTS` через общие хелперы, стандартизирован хвост контекста (`LAST_VISIT`, `LOG_VISIT`, `ticks`) через `_append_visit_context`.
#### Планы, задачи, маркеры и идеи на будущее:
* Переделать все raw SQL-запросы на ORM (для перехода на SQLite и для лучшей поддержки разных СУБД в будущем).
* Для легаси-страниц (шаблоны и вьюхи) поэтапно проверять (если нужно убирать) старые SEO-хвосты вроде `last_update` / `PUB_DAT` / `Date4Meta` / `Last4Meta`: если дата не несёт смысловой нагрузки, лучше оставлять базовые `{% now %}` из `base.html`, а не тащить лишний контекст во вьюху.
* Шаблоны `report/report_last_user_visit.html` и `report/report_log_user_visit.html` сделать с конентом
подгружаемым через AJAX (использовать HTMX, напрмемер) и убрать вызовы `get_last_user_visit_list` и `get_last_all_user_visit_list` их соответствующих вьюх. Это должно разгрузить бекенд и, возможно, сделать кеширование.
* Упаковать всё в контейнеры (Django + Gunicorn + WhiteNoise...
##### Некоторые заметки относительно разработки на macOS:
См. также:
* [`AGENTS.md`](AGENTS.md) – контекст проекта для AI-ассистентов (архитектура, конвенции, рабочие сценарии).
* [`SETUP.md`](SETUP.md) – пошаговая настройка окружения, запуск проекта и базовые команды разработки.
* Сервисные утилиты:
- [`SITEMAP_RUNBOOK.md`](SITEMAP_RUNBOOK.md) – sitemap (генерация, веса, cron, nginx)
---
Легаси-материалы старого README, которые могут быть полезны для понимания устройства проекта и его
администрирования, а также для будущей реорганизации документации.
### Немного о механике кеширования:
#### Кеширование картинок со схемами открывания окон
Картинки со схемами открывания создаются в папках:
* `public/static/img/_flap.cfg` -- большие картинки
* `public/static/img/_miniflap.cfg` -- маленькие картинки (для таблиц с ценами)
Эти картинки создаются автоматически. Можно не удалять. Даже если какая-то схема открывания или размер проёма станет
неактуальным, лишняя картинка просто будет лежать в папке (вдруг такой проём появится снова).
#### Кеширование шаблонов
В папке `oknardia/oknardia/templates/seria_info/prepared` создаются пре-рендер шаблоны с информацией о сериях домов.
Эти шаблоны надо периодически удалять. Они нужны для скорости. Но если меняются данные по серии, размерам окон, появляются
новые коммерческие предложения -- их надо удалять и тогда построятся новые. Вообще на быстрых серверах скорость может
не быть проблемой, так что возможно стоит просто настроить через crone ежедневное или еженедельное удаление этих
пре-рендер шаблонов. При обращении к соответсвующий страницам эти шаблоны будут пересозданы автоматически.
### Некоторые заметки относительно разработки (DEV) на macOS:
Т.к. MariaDB "сидит" в контейнере Dockers могут возникнуть трудности при установке коннектора к базам данных MySQL/MariaDB. Примерно такие:
```txt
+311
View File
@@ -0,0 +1,311 @@
# 🚀 SETUP.md — Первичная настройка Окнардии
**Версия**: 0.2.0 | **Дата**: 16.04.2026
Этот документ описывает пошаговую настройку проекта для разработки и деплоя.
## 📋 Предварительные требования
- **Python**: 3.12+
- **Django**: 6.0+
- **MariaDB/MySQL**: 5.7+ или 8.0+
- **Redis** (опционально, для кеширования): 6.0+
- **Poetry** (для управления зависимостями)
### На macOS:
```bash
# Установка зависимостей (если не установлены)
brew install mariadb-connector-c
brew install redis # опционально
```
## 🔑 Шаг 1: Конфигурация секретов
### 1.1 Создайте файл `my_secret.py`
```bash
cd oknardia/oknardia
cp my_secret.py.template my_secret.py
nano my_secret.py # отредактируйте значения
```
**Что нужно заполнить:**
- IP адреса и хосты (MY_HOST_HOME2, MY_DATABASE_HOST_DEV2)
- Пароль БД (MY_DATABASE_PASSWORD_DEV)
- Email credentials (MY_EMAIL_HOST_USER_DEV, MY_EMAIL_HOST_PASSWORD_DEV)
- Пути к файлам (MY_MEDIA_ROOT_DEV2, MY_STATIC_ROOT_DEV2)
- SECRET_KEY (сгенерируйте новый!)
### 1.2 (Опционально) Создайте файл `.env.local`
```bash
cd /path/to/project
cp .env.example .env.local
nano .env.local # отредактируйте значения
```
**Примечание**: либо используйте `my_secret.py`, либо `.env.local`, выбирайте удобный способ.
## 🗄️ Шаг 2: Настройка БД
### 2.1 Создайте БД и пользователя
```bash
# Подключитесь к MySQL
mysql -u root -p
# В MySQL консоли:
CREATE DATABASE django_oknardia_dev;
CREATE USER 'web'@'localhost' IDENTIFIED BY 'your-password';
GRANT ALL PRIVILEGES ON django_oknardia_dev.* TO 'web'@'localhost';
FLUSH PRIVILEGES;
EXIT;
```
### 2.2 Выполните миграции
```bash
cd /path/to/project/oknardia
python manage.py migrate
```
### 2.3 Создайте суперпользователя
```bash
python manage.py createsuperuser
```
## 📦 Шаг 3: Установка зависимостей
### Вариант 1: Poetry (рекомендуется)
```bash
# Установите poetry (если не установлен)
curl -sSL https://install.python-poetry.org | python3 -
# Установите зависимости
poetry install
# Активируйте виртуальное окружение
poetry shell
```
### Вариант 2: pip (классический способ)
```bash
python -m venv venv
source venv/bin/activate # На Windows: venv\Scripts\activate
pip install -r requirements.txt
```
## 🏃 Шаг 4: Запуск разработки
### 4.1 Запустите локальный сервер
```bash
cd oknardia
python manage.py runserver
```
Откройте браузер: **http://127.0.0.1:8000**
### 4.2 Запустите задачи Celery (опционально)
```bash
celery -A oknardia worker -l info
```
## 📁 Шаг 5: Создание необходимых директорий
```bash
# Статика и медиа файлы
mkdir -p public/media
mkdir -p public/static
mkdir -p public/static/img/_flap.cfg
mkdir -p public/static/img/_miniflap.cfg
# Логи
mkdir -p logs
# Сгенерируйте статику
python manage.py collectstatic --noinput
```
## 🧪 Шаг 6: Тестирование
```bash
# Запустите тесты
python manage.py test
# С покрытием (если установлен coverage)
coverage run --source='.' manage.py test
coverage report
```
## 🔐 Шаг 7: Проверка безопасности
### 7.1 Django встроенная проверка
```bash
python manage.py check --deploy
```
### 7.2 Проверка на утечки секретов
```bash
# Установите инструмент
pip install truffleHog
# Проверьте репозиторий
truffleHog filesystem . --json
```
## ✅ Проверка готовности
Убедитесь, что все работает:
```bash
# 1. Статус БД
python manage.py dbshell < /dev/null && echo "✓ Database OK"
# 2. Статус приложений Django
python manage.py check && echo "✓ Django OK"
# 3. Статус файлов
test -d public/media && test -d public/static && echo "✓ Directories OK"
# 4. Тесты
python manage.py test 2>&1 | tail -5
```
## 🚀 Развертывание на продакшене
### Для разных хостов
**Masterhost VDS:**
```bash
# Установка окружения
export DJANGO_SECRET_KEY="your-production-key"
export DATABASE_PASSWORD="production-db-password"
export DATABASE_HOST="localhost"
export DEBUG="False"
# Запуск через uWSGI + Nginx
uwsgi --ini config/oknardia.ini
```
**Docker (рекомендуется):**
```bash
docker build -t oknardia:latest .
docker run -d \
-e DJANGO_SECRET_KEY="..." \
-e DATABASE_PASSWORD="..." \
-p 8000:8000 \
oknardia:latest
```
## 🛠️ Полезные команды
```bash
# Управление миграциями
python manage.py makemigrations # Создать миграцию
python manage.py migrate # Применить миграции
python manage.py migrate --fake-initial # Подделать первую миграцию
# Управление данными
python manage.py shell # Интерпретатор Python с контекстом Django
python manage.py dumpdata > backup.json # Резервная копия данных
python manage.py loaddata backup.json # Восстановление данных
# Статика и медиа
python manage.py collectstatic # Собрать статику для продакшена
python manage.py findstatic # Найти файлы статики
# Администрирование
python manage.py createsuperuser # Создать администратора
python manage.py changepassword username # Изменить пароль
# Очистка
python manage.py clearsessions # Удалить старые сессии
python manage.py remove_stale_contenttypes # Удалить устаревшие типы контента
# Служебные
python manage.py check # Проверить конфигурацию
python manage.py check --deploy # Проверка для продакшена
```
## 📚 Дополнительные ресурсы
- [Django документация](https://docs.djangoproject.com/en/stable/)
- [AGENTS.md](./AGENTS.md) — архитектура и конвенции проекта
- [README.md](./README.md) — основная информация о проекте
- [SECURITY_AUDIT_REPORT.md](./SECURITY_AUDIT_REPORT.md) — отчёт безопасности
## ❓ Решение проблем
### Проблема: `mysqlclient` не устанавливается на macOS
**Решение:**
```bash
brew install mariadb-connector-c
pip install mysqlclient
# или
brew unlink mariadb-connector-c # после установки
```
### Проблема: `ModuleNotFoundError: No module named 'oknardia'`
**Решение:**
```bash
# Убедитесь, что находитесь в правильной директории
cd /path/to/project/oknardia
python manage.py runserver
```
### Проблема: `OperationalError: (2002, "Can't connect to local MySQL server")`
**Решение:**
```bash
# Проверьте, что MySQL запущен
# macOS:
brew services start mariadb
# Linux:
sudo systemctl start mysql
# Проверьте credentials в my_secret.py или .env
```
### Проблема: миграции не применяются
**Решение:**
```bash
# Проверьте статус миграций
python manage.py showmigrations
# Примените все миграции
python manage.py migrate --run-syncdb
# Если проблема в конкретной миграции
python manage.py migrate app_name 0001 --fake
python manage.py migrate app_name
```
## 🤝 Общие вопросы
**Q: Где хранятся секреты?**
A: В `my_secret.py` (в .gitignore) или переменных окружения (.env)
**Q: Как запустить проект без интернета?**
A: Установите все зависимости заранее, используйте локальное хранилище медиа
**Q: Как работает система рейтинга?**
A: Смотрите [AGENTS.md](./AGENTS.md), раздел "Система рейтинга и ранжирования"
---
**Версия документа**: 1.0
**Последнее обновление**: 16.04.2026
**Автор**: GitHub Copilot
+102
View File
@@ -0,0 +1,102 @@
# SITEMAP_RUNBOOK.md
## Что изменено
- Генерация sitemap выполняется только через custom management command: `generate_sitemaps`.
- Генерация через интерфейс `/service/*` и URL-роуты удалена.
- Файлы sitemap хранятся в media-каталоге: `MEDIA_ROOT/_serv_sitemap`.
- `robots.txt` указывает на `https://oknardia.ru/media/_serv_sitemap/sitemap.xml`.
- Глубина `compare_offers` по-молчанию ограничена диапазоном `2..4`.
- В `lastmod` записывается только дата (`YYYY-MM-DD`), без времени.
## Что сейчас входит в sitemap
- главная страница `/`;
- список и карточки блога (`/blog/Pn`, `/blogpost/...`);
- каталог профилей: корень, производители и карточки моделей;
- каталог серий домов и детальные страницы типовых серий;
- каталог оконных компаний и карточки брендов;
- каталог стандартных оконных проёмов;
- страница рейтинга профилей;
- страницы цен по адресам и по одиночным проёмам;
- страницы `compare_offers` (с `changefreq=monthly` и пониженным приоритетом).
## Ручной запуск
Из каталога `oknardia/`:
```bash
poetry run python manage.py generate_sitemaps
```
С явными параметрами:
```bash
poetry run python manage.py generate_sitemaps \
--compare-min-depth 2 \
--compare-max-depth 4 \
--max-items 40000 \
--max-file-size 5242880 \
--max-files-qty 998
```
## Параметры команды
- `--compare-min-depth` — минимальная глубина комбинаций `compare_offers` (по умолчанию `2`).
- `--compare-max-depth` — максимальная глубина комбинаций `compare_offers` (по умолчанию `4`).
- `--max-items` — лимит URL в одном sitemap-файле (по умолчанию `40000`).
- `--max-file-size` — лимит размера sitemap-файла в байтах (по умолчанию `5242880`).
- `--max-files-qty` — лимит количества вложенных sitemap-файлов (по умолчанию `998`).
## Важные переменные окружения
- `SITE_BASE_URL` — базовый URL сайта (например, `https://oknardia.ru`).
- `SITEMAP_SUBDIR` — подкаталог в `MEDIA_ROOT` для sitemap (по умолчанию `_serv_sitemap`).
## Что добавить в контейнер
Минимально (после миграций и перед запуском веб-процесса):
```bash
poetry run python manage.py generate_sitemaps || true
```
> `|| true` можно убрать, если хотите падать при любой ошибке генерации.
## Вариант для расписания (когда определитесь)
Можно запускать команду по расписанию любым внешним scheduler:
```bash
poetry run python manage.py generate_sitemaps
```
- через cron хоста,
- или через отдельный scheduler-контейнер.
### Пример внешнего cron на хосте
Пример строки для `crontab -e` на хост-машине (запуск раз в 3 дня в 03:30) с явным именем контейнера `oknarida-backend`:
```bash
30 3 */3 * * /usr/bin/docker exec -i oknarida-backend /bin/sh -lc 'cd /app/oknardia && poetry run python manage.py generate_sitemaps --compare-min-depth 2 --compare-max-depth 4 --max-items 40000 --max-file-size 5242880 --max-files-qty 998' >> /var/log/oknardia-sitemap.log 2>&1
```
> Если путь проекта внутри контейнера отличается от `/app/oknardia`, просто замени `cd /app/oknardia` на фактический путь.
## Прокси/NGINX
Можно хранить физические файлы в media-volume и при этом проксировать/алиасить корневой URL `sitemap.xml` на файл из `media/_serv_sitemap`.
Допустимо, что файл доступен по двум URL (корневой и media), но в `robots.txt` должен быть указан один канонический вариант.
### NGINX snippet (alias для корневого sitemap)
```nginx
# Корневой sitemap.xml (для привычного для поисковиков URL)
location = /sitemap.xml {
alias /<путь-к-каталогку-с-докер-приложением>/media/_serv_sitemap/sitemap.xml;
default_type application/xml;
add_header Cache-Control "public, max-age=300";
}
```
+110
View File
@@ -0,0 +1,110 @@
# Разработка сайта OKNARDIA.RU
# == Конфикурационный файл nginx oknardia.conf
# Описываем апстрим-потоки которые должен подключить Nginx
# Для каждого сайта надо настроить свйо поток, со своим уникальным именем.
# Если будете настраивать несколько python (django) сайтов - измените название upstream
upstream oknardia-django {
# расположение файла Unix-сокет для взаимодействие с uwsgi
server unix:/home/web/oknardia-ru/socket/oknardia.sock;
# server ///home/web/oknardia-ru/socket/oknardia.sock;
# также можно использовать веб-сокет (порт) для взаимодействие с uwsgi. Но это медленнее
# server 127.0.0.1:8001; # для взаимодействия с uwsgi через веб-порт
keepalive_requests 200;
}
# конфигурируем сервер
server {
server_name tmp.cube2.ru; # доменное имя сайта
listen 80; # managed by Certbot
## listen 443 ssl http2; # managed by Certbot
## ssl_certificate /etc/letsencrypt/live/cadpoint.ru/fullchain.pem; # managed by Certbot
## ssl_certificate_key /etc/letsencrypt/live/cadpoint.ru/privkey.pem; # managed by Certbot
## include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
## ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
# server_name 90.156.203.25; # доменное имя сайта
charset utf-8; # кодировка по умолчанию
access_log /home/web/oknardia-ru/logs/oknardia-access.log; # логи с доступом
error_log /home/web/oknardia-ru/logs/oknardia-error.log; # логи с ошибками
client_max_body_size 100M; # максимальный объем файла для загрузки на сайт (max upload size)
error_page 404 /404.html;
error_page 500 /500.html;
location /media { alias /home/web/oknardia-ru/public/media; } # Расположение media-файлов Django
location /static { alias /home/web/oknardia-ru/public/static; } # Расположение static-файлов Django
location /robots.txt { root /home/web/oknardia-ru/public; } # Расположение robots.txt
location /favicon.ico { root /home/web/oknardia-ru/public; } # Расположение favicon.ico
location /favicon.gif { root /home/web/oknardia-ru/public; } # Расположение favicon
location /favicon.png { root /home/web/oknardia-ru/public; } # Расположение favicon
location /favicon.svg { root /home/web/oknardia-ru/public; } # Расположение favicon
location /author.txt { root /home/web/oknardia-ru/public; } # Расположение author.txt
location = /404.html {
root /home/web/oknardia-ru/oknardia/templates/404.html;
internal;
}
location = /500.html {
root /home/web/oknardia-ru/oknardia/templates/500.html;
internal;
}
# location ~ \.(html|htm|ico|svg|png|gif|jpg|jpeg)$ {
location ~ \.(xml|html|htm|ico|svg|png|gif|jpg|jpeg)$ {
root /home/web/oknardia-ru/public; # Расположение статичных *.xml, *.html и *.txt
}
location / {
uwsgi_pass oknardia-django; # upstream обрабатывающий обращений
include uwsgi_params; # конфигурационный файл uwsgi;
proxy_set_header Host $host;
# ограничение количества запросов c одного IP-адреса с помощью модуля Limit_Req_Module
# limit_req zone=one burst=20 nodelay;
# one — имя зоны настроеной в /etc/nginx/nginx.conf (для всех сайтов сервера) в блоке http {…}
# burst — максимальный всплеск активности, можно регулировать до какого значения запросов
# в секунду может быть всплеск запросов;
# nodelay — незамедлительно, при достижении лимита подключений, выдавать код 503
# (Service Unavailable) для этого IP
fastcgi_keep_conn on;
uwsgi_read_timeout 1800; # некоторые запросы на Raspbery pi очень долго обрабатываются. Например, переиндексация.
uwsgi_send_timeout 200; # на всякий случай время записи в сокет
}
}
# переадресация с www на "без" www
server {
server_name www.tmp.cube2.ru;
listen 80;
return 301 http://tmp.cube2.ru$request_uri;
## listen 443 ssl; # managed by Certbot
## ssl_certificate /etc/letsencrypt/live/cadpoint.ru/fullchain.pem; # managed by Certbot
## ssl_certificate_key /etc/letsencrypt/live/cadpoint.ru/privkey.pem; # managed by Certbot
## include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
## ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
# переадресация с http на https
##server {
## if ($host = oknardia.ru) {
## return 301 https://$host$request_uri;
## } # managed by Certbot
##
## listen 80;
## server_name cadpoint.ru;
## return 404; # managed by Certbot
##}
# переадресация с http на https для www
##server {
## if ($host = www.cadpoint.ru) {
## return 301 https://cadpoint.ru$request_uri;
## } # managed by Certbot
##
## listen 80;
## server_name www.cadpoint.ru;
## return 404; # managed by Certbot
##}
+63
View File
@@ -0,0 +1,63 @@
# === Конфигурационный файл uwsgi cadpoint.ini
[uwsgi]
# НАСТРОЙКИ ДЛЯ DJANGO
# Корневая папка проекта (полный путь)
chdir = /home/web/oknardia-ru/oknardia
# Django wsgi файл rsvo_new/wsgi.py записываем так:
module = oknardia.wsgi
# полный путь к виртуальному окружению
home = /home/web/oknardia-ru/env
# полный путь к файлу сокета
socket = /home/web/oknardia-ru/socket/oknardia.sock
# Исходящие сообщения в лог
daemonize = /home/web/oknardia-ru/logs/oknardia_uwsgi.log
# ЗАГАДОЧНЫЕ НАСТРОЙКИ, ПО ИДЕЕ ОНИ НУЖНЫ, НО И БЕЗ НИХ ВСЁ РАБОТАЕТ
# расположение wsgi.py
wsgi-file = /home/web/oknardia-ru/oknardia/oknardia/wsgi.py
# расположение виртуального окружения (как оно работает если этот параметр не указан, не ясно)
virtualenv = /home/web/oknardia-ru/env
# имя файла при изменении которого происходит авторестарт приложения
# (когда этого параметра нет, то ничего не авторестартится, но с ним все рестартится.
# Cтоит изменить любой Python-исходник проекта, как изменения сразу вступают в силу.
touch-reload = /home/web/oknardia-ru/logs/touch-reload.txt
py-autoreload = 5
# НАСТРОЙКИ ОБЩИЕ
# быть master-процессом
master = true
# максимальное количество процессов
processes = 1
# если uWSGI установлен как сервис через apt-get то нужно установить еще плагин:
# sudo apt-get install uwsgi-plugin-python
# и добавить в этот конфиг: plugin = python
plugin = python3
# права доступа к файлу сокета. По умолчанию должно хватать 664. Но каких-то прав не хватает, поэтому 666.
chmod-socket = 666
# очищать окружение от служебных файлов uwsgi по завершению
vacuum = true
# количество секунд после которых подкисший процесс будет перезапущен
# Так как некоторе скрипты требуют изрядно времени (особенно полная переиндексация) то ставим значение побольше
harakiri = 2600
# В общем случае, при некотых значениях harakiri логах uWSGI может вываливаться предупреждение:
# WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers
# можно оставить harakiri закомментированным, но нам нужно 900 и на него не ругается. Ругается на 30.
# разрешаем многопоточность
enable-threads = true
vacuum = true
thunder-lock = true
max-requests = 500
# пользователь и группа пользователей от имени которых запускать uWSGI
# указываем www-data: к этой группе относится nginx, и ранее мы включили в эту группу нашего [user]
# uid = nginx
# gid = nginx
# uid = root
# gid = root
uid = web
gid = web
print = ---------------- Запущен uWSGI для oknardia.ru ----------------
+3
View File
@@ -0,0 +1,3 @@
# Это папака для хранения базы данных SQLite, не должна быть в репозитории.
*.*
*
+1 -1
View File
@@ -258,7 +258,7 @@ class Migration(migrations.Migration):
('iWinWidth', models.DecimalField(decimal_places=1, help_text='Ширина, см.', max_digits=5, verbose_name='Ширина')),
('iWinHight', models.DecimalField(decimal_places=1, help_text='Высота, см.', max_digits=5, verbose_name='Высота')),
('iWinDepth', models.DecimalField(decimal_places=1, help_text='Глубина, см.', max_digits=3, verbose_name='Глубина')),
('sFlapConfig', models.CharField(help_text='Рекомендуемая гор.архитектурой конфигурации открывания (МЕТАЯЗЫК)', max_length=32, verbose_name='Открывание')),
('flap_config', models.CharField(help_text='Рекомендуемая гор.архитектурой конфигурации открывания (МЕТАЯЗЫК)', max_length=32, verbose_name='Открывание')),
('sDescripion', models.CharField(blank=True, help_text='Описание для простоты последующего поиска и SEO', max_length=64, null=True, verbose_name='Описание')),
('bIsDoor', models.BooleanField(default=False, help_text='Это Дверь', verbose_name='Дверь')),
('bIsNearDoor', models.BooleanField(default=False, help_text='Это окно рядом с дверью (может быть глухим)', verbose_name='Глухое')),
+97 -51
View File
@@ -12,31 +12,49 @@ https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
from oknardia.my_secret import *
import socket
import environ
def _env_admins(raw_items: list[str]) -> tuple[tuple[str, str], ...]:
# Формат: "Имя1:email1,Имя2:email2"
admins: list[tuple[str, str]] = []
for item in raw_items:
if ":" not in item:
continue
admin_name, admin_email = item.split(":", maxsplit=1)
admin_name = admin_name.strip()
admin_email = admin_email.strip()
if admin_name and admin_email:
admins.append((admin_name, admin_email))
return tuple(admins)
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
PROJECT_ROOT = BASE_DIR.parent
PUBLIC_ROOT = PROJECT_ROOT / 'public'
STATIC_SOURCE_ROOT = PUBLIC_ROOT / 'static'
env = environ.Env()
environ.Env.read_env(str(PROJECT_ROOT / '.env'))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-pd&1$j6z*1w#(j*16b+(@@#&2)+@x^^ot4)zqt-e67*1+$^qch'
SECRET_KEY = env(
'DJANGO_SECRET_KEY',
default='django-insecure-pd&1$j6z*1w#(j*16b+(@@#&2)+@x^^ot4)zqt-e67*1+$^qch',
)
# SECURITY WARNING: don't run with debug turned on in production!
# ПРЕДУПРЕЖДЕНИЕ БЕЗОПАСНОСТИ: не работайте в режиме DEBUG в продашене!
if socket.gethostname() in MY_HOST_DEV:
DEBUG = TEMPLATE_DEBUG = True
else:
# Все остальные хосты (подразумевается продакшн)
DEBUG = TEMPLATE_DEBUG = False
DEBUG = TEMPLATE_DEBUG = env.bool('DEBUG', default=False)
ALLOWED_HOSTS = MY_ALLOWED_HOSTS
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['127.0.0.1', 'localhost'])
# Настройки сообщений об ошибках когда все упало и т.п.
ADMINS = MY_ADMINS
ADMINS = _env_admins(env.list('ADMINS', default=[]))
# Application definition
@@ -50,6 +68,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'django.contrib.humanize',
'django.contrib.sitemaps',
'oknardia.apps.OknardiaConfig',
'web.apps.WebConfig',
@@ -65,6 +84,13 @@ MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# Разрешенные IP для отладки (нужно для django-debug-toolbar).
INTERNAL_IPS = env.list('INTERNAL_IPS', default=['127.0.0.1', 'localhost'])
if DEBUG:
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware', *MIDDLEWARE]
ROOT_URLCONF = 'oknardia.urls'
TEMPLATES = [
@@ -107,65 +133,81 @@ USE_I18N = True
USE_TZ = True
FIRST_DAY_OF_WEEK = 1 # 1'st day week -- monday
SHORT_DATE_FORMAT = 'Y-m-d'
SHORT_DATETIME_FORMAT = 'Y-m-d H:M:S'
DATETIME_FORMAT = 'Y-m-d H:M:S'
SHORT_DATETIME_FORMAT = 'Y-m-d H:i:s'
DATETIME_FORMAT = 'Y-m-d H:i:s'
# Статические файлы (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = 'static/'
MEDIA_URL = 'media/'
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
if DEBUG: # DEBUG: заменяем настройки прода, на настройки девопа
MEDIA_ROOT = MY_MEDIA_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_MEDIA_ROOT_DEV2
# STATIC_ROOT = MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2
STATICFILES_DIRS = [
MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2,
]
# путь к каталогу static (в эту переменную использовать для указания пути где будут делаться кэш-блоки для шаблонов)
STATIC_BASE_PATH = MY_STATIC_BASE_PATH_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_BASE_PATH_DEV2
MEDIA_ROOT = str(PUBLIC_ROOT / 'media')
# STATIC_ROOT отделен от исходной статики, чтобы избежать staticfiles.E002.
STATIC_ROOT = str(PUBLIC_ROOT / 'static_collected')
# Базовый URL сайта нужен для абсолютных URL в sitemap.xml.
SITE_BASE_URL = env('SITE_BASE_URL', default='https://oknardia.ru').rstrip('/')
# Файлы sitemap храним в media-volume, чтобы переживали пересоздание контейнера.
SITEMAP_SUBDIR = env('SITEMAP_SUBDIR', default='_serv_sitemap').strip('/ ')
SITEMAP_ROOT = str(Path(MEDIA_ROOT) / SITEMAP_SUBDIR)
SITEMAP_URL_PREFIX = f"{MEDIA_URL.rstrip('/')}/{SITEMAP_SUBDIR}"
SITEMAP_INDEX_URL = f"{SITE_BASE_URL}{SITEMAP_URL_PREFIX}/sitemap.xml"
# Каталоги, откуда Django читает исходную статику в DEBUG-режиме.
STATICFILES_DIRS = [
str(STATIC_SOURCE_ROOT)
] if STATIC_SOURCE_ROOT.is_dir() else []
# Путь к каталогу static для генерации кэш-файлов и служебных JS.
STATIC_BASE_PATH = str(STATIC_SOURCE_ROOT)
database_engine = env('DATABASE_ENGINE', default='django.db.backends.sqlite3')
if database_engine == 'django.db.backends.sqlite3':
# Для SQLite принимаем только имя файла из env и кладем БД в PROJECT_ROOT/database.
sqlite_db_filename = Path(env('DATABASE_NAME', default='oknadria.sqlite3')).name
sqlite_db_path = PROJECT_ROOT / 'database' / sqlite_db_filename
DATABASES = {
'default': {
'ENGINE': "django.db.backends.mysql",
'HOST': MY_DATABASE_HOST_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_DATABASE_HOST_DEV2,
'PORT': MY_DATABASE_PORT_DEV, # Set to "" for default. Not used with sqlite3.
'NAME': MY_DATABASE_NAME_DEV, # Not used with sqlite3.
'USER': MY_DATABASE_USER_DEV, # Not used with sqlite3.
'PASSWORD': MY_DATABASE_PASSWORD_DEV, # Not used with sqlite3.
# 'OPTIONS': { 'autocommit': True, }
'ENGINE': 'django.db.backends.sqlite3',
'NAME': str(sqlite_db_path),
}
}
TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD
else:
MEDIA_ROOT = MY_MEDIA_ROOT_PROD
# STATICFILES_DIRS = [MY_STATIC_ROOT_PROD1, ]
STATIC_ROOT = MY_STATIC_ROOT_PROD
# путь к каталогу static (в эту переменную использовать для указания пути где будут делаться кэш-блоки для шаблонов)
STATIC_BASE_PATH = MY_STATIC_BASE_PATH_PROD
DATABASES = {
'default': {
'ENGINE': "django.db.backends.mysql",
'HOST': MY_DATABASE_HOST_PROD, # Set to "" for localhost. Not used with sqlite3.
'PORT': MY_DATABASE_PORT_PROD, # Set to "" for default. Not used with sqlite3.
'NAME': MY_DATABASE_NAME_PROD, # Not used with sqlite3.
'USER': MY_DATABASE_USER_PROD, # Not used with sqlite3.
'PASSWORD': MY_DATABASE_PASSWORD_PROD, # Not used with sqlite3.
# 'OPTIONS': { 'autocommit': True, }
'ENGINE': database_engine,
'HOST': env('DATABASE_HOST', default='localhost'),
'PORT': env('DATABASE_PORT', default='3306'),
'NAME': env('DATABASE_NAME', default=''),
'USER': env('DATABASE_USER', default=''),
'PASSWORD': env('DATABASE_PASSWORD', default=''),
}
}
TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD
TOUCH_RELOAD = env('TOUCH_RELOAD', default='')
#########################################
# настройки для почтового сервера (они одинаковые для DEV и PROD)
EMAIL_HOST = MY_EMAIL_HOST_DEV
EMAIL_PORT = MY_EMAIL_PORT_DEV
EMAIL_HOST_USER = MY_EMAIL_HOST_USER_DEV
EMAIL_HOST_PASSWORD = MY_EMAIL_HOST_PASSWORD_DEV
SERVER_EMAIL = DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USE_TLS = True
EMAIL_BACKEND = env(
'EMAIL_BACKEND',
default='django.core.mail.backends.smtp.EmailBackend',
)
EMAIL_HOST = env('EMAIL_HOST', default='localhost')
EMAIL_PORT = env.int('EMAIL_PORT', default=25)
EMAIL_HOST_USER = env('EMAIL_HOST_USER', default='')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD', default='')
EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', default=True)
EMAIL_USE_SSL = env.bool('EMAIL_USE_SSL', default=False)
DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL', default=EMAIL_HOST_USER)
SERVER_EMAIL = env('SERVER_EMAIL', default=DEFAULT_FROM_EMAIL)
EMAIL_SUBJECT_PREFIX = 'OKNARDIA ERR: ' # префикс для оповещений об ошибках и необработанных исключениях
SECURE_SSL_REDIRECT = env.bool('SECURE_SSL_REDIRECT', default=False)
SESSION_COOKIE_SECURE = env.bool('SESSION_COOKIE_SECURE', default=False)
CSRF_COOKIE_SECURE = env.bool('CSRF_COOKIE_SECURE', default=False)
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
@@ -173,8 +215,8 @@ EMAIL_SUBJECT_PREFIX = 'OKNARDIA ERR: ' # префикс для оповещ
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# ключи для Google Captha
CAPTCHA_PUBLIC_KEY = MY_CAPTCHA_PUBLIC_KEY
CAPTCHA_PRIVATE_KEY = MY_CAPTCHA_PRIVATE_KEY
CAPTCHA_PUBLIC_KEY = env('CAPTCHA_PUBLIC_KEY', default='')
CAPTCHA_PRIVATE_KEY = env('CAPTCHA_PRIVATE_KEY', default='')
# количество коммерческих предложений во фреме отчета
OFFER_PER_FRAME = 5
@@ -265,3 +307,7 @@ CATALOG_RECORD_FOR_PROFILE_MODEL = 1
CATALOG_RECORD_FOR_PROFILE_MANUFACTURER = 100
CATALOG_SORTER_MAGIC_NUMBER_ADV = 5
CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1
MAX_LEN_RING_LOG_BUFFER = 250 # МАКСИМАЛЬНЫЙ РАЗМЕР КОЛЬЦЕВОГО БУФЕРА
YANDEX_MAPS_API_KEY = env('YANDEX_MAPS_API_KEY', default='')
+57 -16
View File
@@ -15,11 +15,11 @@
2. Добавьте URL-адрес в urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path
from django.urls import include, path, re_path
from django.conf.urls.static import static
from oknardia.settings import *
from web import views, autocomplete_addr, user_manager, blog, diagrams, report2, catalog
from web import views, autocomplete_addr, user_manager, blog, diagrams, report1, report2, catalog, prices, service, \
catalog_profiles, catalog_series, catalog_openings, catalog_companies
urlpatterns = [
path('admin/', admin.site.urls),
@@ -28,9 +28,12 @@ urlpatterns = [
re_path(r'^$', views.main_init),
# обработчик автокомлита (подсказки во время ввода адреса на главной странице)
re_path(r'^autocomplete_addr$', autocomplete_addr.autocomplete_addr),
# обработка адреса введеного в форме поиска
re_path(r'^get_address$', views.get_address),
# ОБРАБОТЧИКИ АВТОРИЗАЦИИ
# Вызов шаблона подгружаем captcha
re_path(r'^captcha', user_manager.captcha),
re_path(r'^captcha$', user_manager.captcha),
# Обработчик информации и статусов пользователя и, или подгрузка шаблона login-logout.html
re_path(r'^login-logout', user_manager.menu_login_logout),
# Обработчик форма login-logout-restore. После обработки пере-подгружает шаблон login-logout-after.html
@@ -49,27 +52,65 @@ urlpatterns = [
re_path(r'^tariff[/*]$', views.tariff),
re_path(r'^contact[/*]$', views.contact),
re_path(r'^stat_all[/*]$', diagrams.statistic_menu),
re_path(r'^stat/series/analiz[/*]$', diagrams.statistic_menu), # дубль для старых ссылок
re_path(r'^stat/series/geo[/*]$', diagrams.statistic_menu), # дубль для старых ссылок
re_path(r'^stat/rating[/*]$', report2.ratings),
re_path(r'^stat/rating/profiles_rank[/*]$', report2.profiles_rating),
# --- Каталог
# --- --- Каталог профилей
# --- КАТАЛОГ
re_path(r'^catalog[/*]$', catalog.catalog_root),
re_path(r'^catalog/profile[/*]$', catalog.catalog_profile),
# --- --- КАТАЛОГ ПРОФИЛЕЙ
re_path(r'^catalog/profile[/*]$', catalog_profiles.catalog_profile),
re_path(r'^catalog/profile/(?P<manufacture_id>\d+)-(?P<manufacture_name>\S*)'
r'/(?P<model_id>\d+)-(?P<model_name>\S*)[/*]$', catalog.catalog_profile_model),
r'/(?P<model_id>\d+)-(?P<model_name>\S*)[/*]$',
catalog_profiles.catalog_profile_model),
re_path(r'^catalog/profile/(?P<manufacture_id>\d+)-(?P<manufacture_name>\S*)[/*]$',
catalog.catalog_profile_manufacture),
catalog_profiles.catalog_profile_manufacture),
# --- --- Каталог серий типового строительства
re_path(r'^catalog/seria[/*]$', catalog.catalog_seria),
re_path(r'^catalog/seria/(?P<seria_name_translit>[^/]*)/all(?P<seria_id>\d+)[/*]$', catalog.catalog_seria_info),
re_path(r'^catalog/seria[/*]$', catalog_series.catalog_seria),
re_path(r'^catalog/seria/(?P<seria_name_translit>[^/]*)/all(?P<seria_id>\d+)[/*]$',
catalog_series.catalog_seria_info),
re_path(r'^seria_[^/]*/all(?P<seria_id>\d+)/\S*$', catalog.report_all_info_seria_redirect), # для старых ссылок
# --- --- Каталог стандартных проёмов и схем открывания длч типовых серий строительства
re_path(r'^catalog/standard_opening[/*]$', catalog_openings.standard_opening),
# --- --- Каталог производителей окон
re_path(r'^catalog/company[/*]$', catalog_companies.catalog_company),
re_path(r'^catalog/company/(?P<company_id>\d+)-(?P<company_name_slug>\S*)[/*]$',
catalog_companies.catalog_company_detail),
# ЦЕНОВЫЕ ПРЕДЛОЖЕНИЯ
# --- Одиночное окно
re_path(r'^tsena-odnogo-okna/(?P<win_width_mm>\d+)x(?P<win_height_mm>\d+)mm/tip(?P<win_id>\d+)[/*]$',
prices.report_one_win_price),
re_path(r'^next_price_one_flap_frame/idW(?P<win_id>\d+)N(?P<frame_begin_n>\d+)\S*$', prices.next_one_win_price),
# --- Ценовая выдача
re_path(r'^(?P<build_id>\d+)/(?P<apart_id>\d+)/(?P<slug>[\s\S]*)$', prices.report_price),
# --- Подгружаемый фрейм ценовая выдачи
re_path(r'^next_price_frame/idA(?P<apart_id>\d+)MDPO(?P<mount_dim_per_offer>\d+)LON(?P<address_longitude>\d+)'
r'LAT(?P<address_latitude>\d+\.*\d*)N(?P<frame_begin_n>\d+\.*\d*)\S*[/*]$', prices.next_price_frame),
# СРАВНЕНИЕ ОКОННЫХ НАБОРОВ
re_path(r'^compare_sets/(?P<to_compare>[\s\S]+|.*)$', report1.compare_offers), # дубль для старых ссылок
re_path(r'^compare_offers/(?P<to_compare>[\s\S]+|.*)$', report1.compare_offers),
re_path(r'^specification_set/\d$', views.main_init), # заглушка (позже будет спецификация оконного набора)
# отображение всех составлющих рейтинга
re_path( r'^show_rating_components/(?P<win_set>\d+)$', report1.show_rating_components),
# СЛУЖЕБНЫЕ СТРАНИЦЫ (для администратора)
# --- страничка "главная сервис-утилит"
re_path(r'^service[/*]$', service.service),
# --- страничка для тестирования верстки текста в блоге
re_path(r'^service/tmp[/*]$', service.tmp),
# --- страничка "нет доступа"
re_path(r'^service/not-denice[/*]$', service.not_denice),
re_path(r'^service/make_rating[/*]$', service.make_rating),
]
if DEBUG:
# ___ ____ _ _____ _ _ _____ _
# | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| |
# |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| |
# |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_|
# |___|
urlpatterns = [path('__debug__/', include('debug_toolbar.urls')), *urlpatterns]
# Медиа-файлы
urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT)
# ___ ____ _ _____ _ _ _____ _
# | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| |
# |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| |
# |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_|
# |___|
+5 -1
View File
@@ -17,6 +17,10 @@
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>{% block Title %}{% endblock %} : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link rel="icon" href="https://oknardia.ru/favicon.svg" type="image/svg+xml ">
<link rel="icon" href="https://oknardia.ru/favicon.png" type="image/png">
<link rel="icon" href="https://oknardia.ru/favicon.gif" type="image/gif">
<link rel="icon" href="https://oknardia.ru/favicon.ico" type="image/x-icon">
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" />{# <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />#}
<link href="{% static 'css/bootstrap-theme.min.css' %}" rel="stylesheet" type="text/css" />{# <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />#}
<link href="{% static 'css/oknardia1.css' %}" rel="stylesheet" type="text/css" />{% block Top_CSS1 %}{% endblock %}{% block Top_CSS2 %}{% endblock %}{% block Top_CSS3 %}{% endblock %}
@@ -81,7 +85,7 @@
{# <!-- Yandex.Metrika counter --> #}(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>{# <!--/LiveInternet--> #}
</span>
<small>© oknardia.ru, 2015-{% now "Y" %}. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: {{ ticks }}{{ TAU }} сек---></small>
<small>© oknardia.ru, 2015-{% now "Y" %}. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: {{ ticks }}{{ TAU }} сек---> {{ ticks }}{{ TAU }} сек </small>
</div>
</div>{% endblock %}
{# ######################################## Нижнее меню-футер КОНЕЦ ######################################## #}
+96
View File
@@ -0,0 +1,96 @@
{% extends "base.html" %}
{% load static %}{% load filters %}
{% block Title %}Каталог изготовителей и поставщиков окон{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Каталог изготовителей окон, партнёры «Окнардия», рейтинг, {% for i in COMPANIES %}{{ i.sMerchantName }}, {% endfor %} средняя цена окна{% endblock %}
{% block Keywords %}Оконные компании, {% for i in COMPANIES %}{{ i.sMerchantName }}, {% endfor %} изготовители окон, производители окон, постащики окон, партнёры, каталог компаний, каталог оконных компаний, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %}
{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %}
{% block Author4Meta %}: Каталог изготовителей окон{% endblock %}
{% block CopyrightAuthor4Meta %}: Каталог изготовителей окон{% endblock %}
{% block Top_Meta1 %}{# <!-- BEGIN Дополнительные Metatags --> #}
<meta itemprop="author" content="Каталог «Окнардия»" />{% if IMG_FOR_BLOG %}
<meta itemprop="image" content="https://oknardia.ru/media/{{ IMG_FOR_BLOG }}" />{% else %}
<meta itemprop="image" content="https://oknardia.ru/static/img/MerDY3gpU0w.jpg" />{% endif %}
<meta itemprop="datePublished" content="{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}" />
<span itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<meta itemprop="articleSection" content="Каталог производителей окон" />
<meta itemprop="headline" content="Компании-партнёры «Окнардии», их рейтинг, число оконных наборов и вариантов расчёта цен для типовых проёмов, средняя цена окна..." />
<meta name="news_keywords" content="{{ HEADER }}" />
<link rel="canonical" href="https://oknardia.ru/catalog/company/" />
<link rel="standout" href="https://oknardia.ru/catalog/company/" />
<!-- Разметка для соц-сетей Facebook Open Graph -->
<meta property="fb:admins" name="admins" content="100000084781830" />
<meta property="fb:pages" content="276108456054163" />
<meta property="fb:app_id" content="258354027974262" />
<meta property="fb:profile_id" name="profile_id" content="https://www.facebook.com/oknardia/" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:site_name" content="oknardia.ru" />
<meta property="og:url" content="https://oknardia.ru//catalog/company/" />
<meta property="og:type" content="article" />
<meta property="og:title" content="Каталог производителей окон | oknardia.ru" />
<meta property="og:description" content="Компании-партнеры «Окнардии», их средний рейтинг, число оконных наборов и вариантов расчета цен для типовых проёмов, средняя цена окна..." />
<meta property="og:image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<link rel="image_src" href="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<!-- Разметка для соц-сетей Twitter Card -->
<meta name="twitter:title" content="Каталог производителей окон | oknardia.ru" />
<meta name="twitter:description" content="Компании-партнеры «Окнардии», их средний рейтинг, число оконных наборов и вариантов расчета цен для типовых проёмов, средняя цена окна..." />
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@oknardia" />
<meta name="twitter:domain" content="oknardia.ru" />
<meta property="twitter:url" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<meta name="relap-image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}">
{# <!-- END Дополнительные Metatags --> #}{% endblock %}
{% block Main_Content %}
<div class="container-fluid">
{# <!--- Хлебные крошки: НАЧАЛО --> #}<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog">Каталог</a></li>
<li>Производители и&nbsp;поставщики окон</li>
</ol>
<h1>Производители и&nbsp;поставщики окон</h1>
</div>
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
<dIv class="row">
<div class="col-md-11 col-xs-12">
<p>Компании-партнёры &laquo;Окнардии&raquo;, их средний рейтинг, число оконных наборов и&nbsp;вариантов расчёта цен для типовых проёмов, средняя цена окна:</p>
</div>
</dIv>
<div class="row">{% for i in COMPANIES %}
<div class="col-lg--2 col-md-3 col-sm-4 col-xs-6">
<h2>{{ i.sMerchantName }}</h2>
<p><img src="/media/{{ i.pMerchantLogo }}" style="height:40px;width:auto;" /></p>
<p><nobr class="badge badge4price" title="Средний Рейтинг «Окнардии» для оконных наборов компании «{{ i.sMerchantName }}»{% if i.RatingAVG > -0.01 %} — {{ i.RatingAVG|stringformat:".2f" }} баллов{% endif %}"><small class="xx">Средний рейтинг наборов:</small> {% for Star in i.STARS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if i.RatingAVG > -0.01 %} {{ i.RatingAVG|stringformat:".2f" }}{% endif %}</nobr></p>
<p>В ценовом агрегаторе {{ i.NumSets }}. Размещено {{ i.NumOffers }} цен типовых проёмов. Средняя цена предложения: <nobr><strong>{{ i.PriceAVG|stringformat:".2f"|price_format }}<small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small></strong></nobr> <small>(без учета скидок)</small></p>
<p><a href="/catalog/company/{{ i.id }}-{{ i.sMerchantMainURL }}" class="btn btn-info btn-sm">Подробнее&hellip;</a><br />
<small class="xx">Последнее обновление цен: {{ i.lastUpdate }}</small></p>
</div>{% endfor %}
<DIV class="col-xs-12" style="height:6em;"></DIV>
</dIv>
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>{% endblock %}
+143
View File
@@ -0,0 +1,143 @@
{% extends "base.html" %}
{% load static %}{% load filters %}
{% block Title %}Окна «{{ COMPANY }}» : Каталог производителей окон{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}«{{ COMPANY }}», описание компании «{{ COMPANY }}», оконные наборы от «{{ COMPANY }}» и их состав, характеристики «{{ COMPANY }}», рейтинг «{{ COMPANY }}», средние цены и отклонение цен «{{ COMPANY }}».{% endblock %}
{% block Keywords %}{{ COMPANY }}, компания {{ COMPANY }}, окна {{ COMPANY }}, изготовитель окон {{ COMPANY }}, производитель окон {{ COMPANY }}, поставщик окон {{ COMPANY }}, партнёр, каталог компаний, каталог оконных компаний, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %}
{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %}
{% block Author4Meta %}: Каталог изготовителей окон{% endblock %}
{% block CopyrightAuthor4Meta %}: Каталог изготовителей окон{% endblock %}
{% block Top_Meta1 %}{# <!-- BEGIN Дополнительные Metatags --> #}
<meta itemprop="author" content="Каталог «Окнардия»" />{% if IMG_FOR_BLOG %}
<meta itemprop="image" content="https://oknardia.ru/media/{{ IMG_FOR_BLOG }}" />{% else %}
<meta itemprop="image" content="https://oknardia.ru/static/img/MerDY3gpU0w.jpg" />{% endif %}
<meta itemprop="datePublished" content="{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}" />
<span itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<meta itemprop="articleSection" content="Каталог производителей окон" />
<meta itemprop="headline" content="Изготовитель окон «{{ COMPANY }}», описание, производимые им оконные наборы и их состав, характеристики, рейтинг, средние цены и отклонение цен." />
<meta name="news_keywords" content="{{ HEADER|striptags }}" />
<link rel="canonical" href="https://oknardia.ru/catalog/company/{{ COMPANY_ID }}-{{ COMPANY_T }}" />
<link rel="standout" href="https://oknardia.ru/catalog/company/{{ COMPANY_ID }}-{{ COMPANY_T }}" />
<!-- Разметка для соц-сетей Facebook Open Graph -->
<meta property="fb:admins" name="admins" content="100000084781830" />
<meta property="fb:pages" content="276108456054163" />
<meta property="fb:app_id" content="258354027974262" />
<meta property="fb:profile_id" name="profile_id" content="https://www.facebook.com/oknardia/" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:site_name" content="oknardia.ru" />
<meta property="og:url" content="https://oknardia.ru//catalog/company/{{ COMPANY_ID }}-{{ COMPANY_T }}" />
<meta property="og:type" content="article" />
<meta property="og:title" content="Окна «{{ COMPANY }}» | oknardia.ru" />
<meta property="og:description" content="Окна «{{ COMPANY }}», описание окон «{{ COMPANY }}», производимые им оконные наборы и их состав, характеристики, рейтинг, средние цены и отклонение цен." />
<meta property="og:image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<link rel="image_src" href="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<!-- Разметка для соц-сетей Twitter Card -->
<meta name="twitter:title" content="Производителей окон «{{ COMPANY }}» | oknardia.ru" />
<meta name="twitter:description" content="Изготовитель окон «{{ COMPANY }}», описание, производимые им оконные наборы и их состав, характеристики, рейтинг, средние цены и отклонение цен." />
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@oknardia" />
<meta name="twitter:domain" content="oknardia.ru" />
<meta property="twitter:url" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<meta name="relap-image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}">
{# <!-- END Дополнительные Metatags --> #}{% endblock %}
{% block Top_JS5 %}<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>{% endblock %}
{% block Main_Content %}
<div class="container-fluid">
{# <!--- Хлебные крошки: НАЧАЛО --> #}<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog">Каталог</a></li>
<li><a href="/catalog/company">Производители и поставщики окон</a></li>
<li>{{ COMPANY }}</li>
</ol>
<h1>{{ COMPANY }}</h1>
</div>
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
<dIV class="row">{% for i in SETS %}
{# ЛЕВАЯ КОЛОНКА: НАЧАЛО #}<div class="col-md-5 col-xs-12 catalog">{% if forloop.first %}
<p><img src="/media/{{ i.pMerchantLogo }}" style="height:40px;width:auto;" atl="Логотип «{{ COMPANY }}»" /></p>{% if i.sMerchantDescription %}
<p>{{ i.sMerchantDescription|safe }}</p>{% endif %}
<table>
<thead>
<tr><th colspan="2"><big>Контактная информация:</big></th></tr>
</thead>
<tbody>
<tr>
<td>телефоны:</td>
<td>{{ i.sOfficePhones|safe }}</td>
</tr>{% if i.sOfficeDescription %}<tr>
<td>часы&nbsp;работы:</td>
<td>{{ i.sOfficeDescription|safe }}</td>
</tr>{% endif %}<tr>
<td>email:</td>
<td><script type="text/javascript">document.write("<a href='mailto:{% for j in i.sOfficeEmails %}{% if not forloop.first %}"{% endif %}{{ j }}{% if not forloop.last %}"+{% endif %}{% endfor %}?subject=Запрос через «Окнардия»: - '>{% for j in i.sOfficeEmails %}{% if not forloop.first %}"{% endif %}{{ j }}{% if not forloop.last %}"+{% endif %}{% endfor %}</a>");</script></td>
</tr><tr>
<td>сайт:</td>
<td><a href="{{ i.sMerchantMainURL.URL }}" target="_blank" rel="nofollow">{{ i.sMerchantMainURL.URL_VIEW }}</a></td>
</tr><tr>
<td>офис<sup>*</sup>:</td>
<td>{{ i.sOfficeName }}</td>
</tr><tr>
<td>адрес:</td>
<td><a data-toggle="collapse" href="#collapse_it" aria-expanded="false" aria-controls="collapse_it">{{ i.sOfficeAddress }}</a></td>
</tr><tr class="collapse" id="collapse_it">
<td colspan="2"><script type="text/javascript">ymaps.ready(init);var myMap,myPlacemark;function init(){myMap=new ymaps.Map("office-map",{center:[{{ i.fOfficeGeoCode_Latitude|stringformat:".7f" }},{{ i.fOfficeGeoCode_Longitude|stringformat:".7f" }}],zoom:16,controls:['zoomControl', 'typeSelector']});myMap.behaviors.disable('scrollZoom');myPlacemark=new ymaps.Placemark([{{ i.fOfficeGeoCode_Latitude|stringformat:".7f" }},{{ i.fOfficeGeoCode_Longitude|stringformat:".7f" }}],{balloonContentHeader:'{{ i.sOfficeName }}',balloonContentBody:'{{ i.sOfficeAddress }}.<br>тел.: {{ i.sOfficePhones }}',hintContent:'{{ i.sOfficeName }} — {{ i.sOfficeAddress }}'},{preset:"islands#dotIcon",iconColor:'#414997'});myMap.geoObjects.add(myPlacemark);}</script><div id="office-map" style="width:100%;height:300px"></div></td>
</tr>
</tbody>
</table>
<p class="small-note"><big style="color:red">*</big> — Офис предоставивший расчеты для оконного агрегатора &laquo;Окнардия&raquo;.</p>
{% endif %}</div>{# ЛЕВАЯ КОЛОНКА: КОНЕЦ #}
<style>
table.head3{width: 100%;}
table.head3 tr > td:first-of-type {padding: 0;padding-right: 1ex;}
table.head3 tr > td:last-of-type {padding-left: 1ex;vertical-align: baseline;}
table.head3 tr > td:last-of-type > nobr.badge4price {margin-top: 24px;font-size: small}
</style>
{# ПРАВАЯ КОЛОНКА: НАЧАЛО #}<div class="col-md-6 col-xs-12">
<table class="head3">
<tr>
<td><h3>Оконный набор: &laquo;{{ i.sSetName|safe }}&raquo;</h3></td>
<td align="right"><nobr class="badge badge4price" title="Рейтинг «Окнардии» для оконного набора «{{ i.sSetName }}»{% if i.fSetRating.RATING > -0.01 %} — {{ i.fSetRating.RATING|stringformat:".2f" }} баллов{% endif %}">{% for Star in i.fSetRating.STARS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if i.fSetRating.RATING > -0.01 %} {{ i.fSetRating.RATING|stringformat:".2f" }}{% endif %}</nobr></td>
</tr>
</table>
<P>В этом наборе применен {% if i.iProfileCameras != "—" %}профиль <a href="/catalog/profile/{{ i.idPVC }}-{{ i.sProfileManufacturer.NAME_T }}/{{ i.idPVC }}-{{ i.sProfileName.NAME_T }}/">{{ i.sProfileBriefDescription }}</a>{% else %} <a href="catalog/profile/{{ i.idPVC }}-{{ i.sProfileManufacturer.NAME_T }}/{{ i.idPVC }}-{{ i.sProfileName.NAME_T }}/">{{ i.sProfileBriefDescription|lower }}</a>{% endif %} производства <a href="/catalog/profile/{{ i.idPVC }}-{{ i.sProfileManufacturer.NAME_T }}/">{{ i.sProfileManufacturer.NAME }}</a>. {% if i.iProfileCameras != "—"%} Число камер рамы и&nbsp;створки —&nbsp;{{ i.iProfileCameras }}.{% endif %} {{ i.fProfileSeals|capfirst }} уплотнения. {% if i.iProfileCameras in LIST_NOT %}Основа: {% else %}Армирование {% endif %} {{ i.sProfileReinforcement }}. Цвет профиля: {{ i.sProfileColor|lower }}. Устанавливается {{ i.sGlazingBriefDescription|lower|safe }}{% if i.sGlazingManufacturer != "—//—" %}{% if i.sGlazingManufacturer not in LIST_NOT %}, производства {{ i.sGlazingManufacturer }}{% endif %}{% endif %}. {% if i.sGlazingToning|lower == "нет" %}Без тонирования{% else %}Тонирование: {{ i.sGlazingToning|lower }}{% endif %}. Формула стеклопакета: <nobr>{{ i.sGlazingMark }}.</nobr> Цвет уплотнителя контуров и&nbsp;стеклопакета {{ i.sProfileSealDescription }}. Используется фурнитура {{ i.sSetImplementAll }}{% if i.sSetImplementHandles != "" %}, ручки {{ i.sSetImplementHandles }}{% endif %}{% if i.sSetImplementCatch != "" %}, фиксатор открывания {{ i.sSetImplementCatch }}{% endif %}. {% if i.sSetClimateControl != "" %} Каждое окно оборудовано системой климат-контроля —&nbsp;{{ i.sSetClimateControl }}.{% endif %}</P>
<P>{% if i.sSetSill|lower not in LIST_NOT %}Оконный подоконник {{ i.sSetSill|safe }}.{% endif %} {% if i.sSetPanes|lower not in LIST_NOT %}Внешний водоотлив {{ i.sSetPanes|safe }}.{% endif %} {% if i.sSetSlope|lower not in LIST_NOT %}Внутренней откос {{ i.sSetSlope|safe }}.{% endif %}{% if i.sSetSill|lower in LIST_NOT and i.sSetPanes|lower in LIST_NOT and i.sSetSlope|lower in LIST_NOT %}Подоконники, внешние водоотливы и&nbsp;внутренние откосы не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что закзчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetSill|lower in LIST_NOT and i.sSetPanes|lower in LIST_NOT %}Подоконники и&nbsp;внешние водоотливы не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что закзчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetSill|lower in LIST_NOT and i.sSetSlope|lower in LIST_NOT %}Внешние водоотливы и&nbsp;внутренние откосы не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что закзчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetPanes|lower in LIST_NOT and i.sSetSlope|lower in LIST_NOT %}Подоконники и&nbsp;внутренние откосы не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что закзчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetPanes|lower in LIST_NOT %}Внешние оконные водоотливы не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что заказчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetSlope|lower in LIST_NOT %}Внутренние откосы и&nbsp;их&nbsp;отделка не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что заказчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% elif i.sSetSill|lower in LIST_NOT %}Оконные подоконники не&nbsp;включены в&nbsp;набор. Производитель &laquo;{{ COMPANY }}&raquo; предполагает, что заказчик этого набора закупит их&nbsp;отдельно у&nbsp;него или&nbsp;других поставщиков.{% endif %}</P>
<P>{% if i.bSetUninstallInstall %}Установка новых и&nbsp;демонтаж старых оконных конструкций {{ i.sSetUninstallInstall|safe }}. {% endif %}{% if i.bSetDelivery %}Доставка {{ i.sSetDelivery|safe }}. {% endif %}{% if not i.bSetDelivery and not i.bSetUninstallInstall %}В&nbsp;стоимость набора не&nbsp;входит демонтаж и&nbsp;установка. Эти услуги оплачиваются отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}Примерно {{ i.sSetUninstallInstall|safe }}, или заказчик может провести все работы самостоятельно. {% endif %}Доставка тоже не&nbsp;входит в&nbsp;стоимость, осуществляется заказчиком самостоятельно или оплачивается отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}{{ i.sSetDelivery|safe|capfirst }}. {% endif %}{% elif not i.bSetDelivery %}Доставка&nbsp;не входит в&nbsp;стоимость, осуществляется заказчиком самостоятельно или оплачивается отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}{{ i.sSetDelivery|safe|capfirst }}. {% endif %}{% elif not i.bSetUninstallInstall %}В&nbsp;стоимость набора не&nbsp;входит демонтаж и&nbsp;установка. Эти услуги оплачиваются отдельно.{% if i.sSetUninstallInstall not in LIST_NOT %} Примерно {{ i.sSetUninstallInstall|safe }}. Или заказчик может провести все работы самостоятельно.{% endif %}{% endif %}</P>{% if i.sSetOtherConditions not in LIST_NOT %}
<P>Прочие условия —&nbsp;{{ i.sSetOtherConditions|safe }}</P>{% endif %}
{# Скидки -- {{ i.sOfficeDiscountMetaFormula }}<br>#}
<p style='background-color:#f0f0f0;color:silver;padding:5ex 10ex;'>Извините, графики ценового распределения для оконного набора &laquo;{{ i.sSetName|safe }}&raquo; компании &laquo;{{ i.sMerchantName }}&raquo; подготавливаются.<br />&nbsp;<br />Зайдите позже.</p>
<p><small class="xx">Оконный набор создан {{ i.earlyCreation }}, последнее обновление цен {{ i.lastUpdate }}</small></p>
</div>{# ПРАВАЯ КОЛОНКА: КОНЕЦ #}{% endfor %}
{# РАСПОРКА: начало #}<DIV class="col-xs-12" style="height:6em;"></DIV>{# РАСПОРКА: конец #}
</dIV>
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>{% endblock %}
@@ -1,17 +1,13 @@
{% extends "base.html" %}
{% load static %}
{% block Title %} Каталог оконных профилей{% endblock %}
{% block Title %}Каталог оконных профилей{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Каталог оконных профилей{% endblock %}
{% block Description %}Подберите оконный профиль под свои требования: в каталоге «Окнардии» собраны производители, марки и ключевые характеристики.{% endblock %}
{% block Keywords %}каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Date4Meta %}{{ CATALOG_LAST_UPDATE|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ CATALOG_LAST_UPDATE|date:"c" }}{% endblock %}
{% block Keywords %}оконные профили, каталог профилей, сравнение профилей, производители оконных профилей, характеристики оконных профилей, oknardia {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Author4Meta %}: Каталог{% endblock %}
@@ -27,7 +23,7 @@
<li>Оконные профили</li>
</ol>
<h1>Каталог оконных профилей</h1>
<p>Узнать о&nbsp;производителях, познакомиться с&nbsp;детальными характеристики и&nbsp;описаниями оконных профилей можно кликнув по&nbsp;ссылкам. Сейчас в&nbsp;каталоге &laquo;Окнардии&raquo; представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в&nbsp;базе). Последнее обновление {{ CATALOG_LAST_UPDATE_W }}.</p>
<p>Узнать о&nbsp;производителях, познакомиться с&nbsp;детальными характеристики и&nbsp;описаниями оконных профилей можно кликнув по&nbsp;ссылкам. Сейчас в&nbsp;каталоге &laquo;Окнардии&raquo; представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в&nbsp;базе).</p>
</div>
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
<div class="row">
@@ -1,13 +1,13 @@
{% extends "base.html" %}
{% load static %}
{% block Title %} Каталог :: Оконные профили производства {{ CATALOG_MANUFACT }}{% endblock %}
{% block Title %}Оконные профили производства {{ CATALOG_MANUFACT }} : Каталог{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Оконные профили {{ CATALOG_MANUFACT }}{% endblock %}
{% block Description %}Оконные профили {{ CATALOG_MANUFACT }} ({% for i in PROFILES %}{% if forloop.first %}{{ i.PROFILE_NAME }}{% else %}{% if not forloop.last %}, {{ i.PROFILE_NAME }}{% else %} и {{ i.PROFILE_NAME }}{% endif %}{% endif %}{% endfor %}){% endblock %}
{% block Keywords %}{{ CATALOG_MANUFACT }}, оконные профили {{ CATALOG_MANUFACT }}, производитель {{ CATALOG_MANUFACT }}, каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Keywords %}{{ CATALOG_MANUFACT }}, оконные профили {{ CATALOG_MANUFACT }}, производитель {{ CATALOG_MANUFACT }}, {% for i in PROFILES %}{{ i.PROFILE_NAME }}, {% endfor %}каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %}
@@ -1,11 +1,11 @@
{% extends "base.html" %}
{% load static %}
{% block Title %} Каталог :: Оконные профили {{ CATALOG_MODEL.sProfileName }}{% endblock %}
{% block Title %}Оконный профиль {{ CATALOG_MODEL.sProfileName }} : Каталог{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Описание и характеристики оконного профиля {{ CATALOG_MODEL.sProfileName }} производства {{ CATALOG_MODEL.sProfileManufacturer }}{% endblock %}
{% block Description %}Характеристики оконного профиля {{ CATALOG_MODEL.sProfileName }} производства {{ CATALOG_MODEL.sProfileManufacturer }}{% endblock %}
{% block Keywords %}оконный профиль {{ CATALOG_MODEL.sProfileName }}, характеристики профиля {{ CATALOG_MODEL.sProfileName }}, описание профиля {{ CATALOG_MODEL.sProfileName }}, производитель оконный профилей {{ CATALOG_MODEL.sProfileManufacturer }}, каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
@@ -28,8 +28,8 @@
<meta itemprop="articleSection" content="Каталог «Окнардия»: оконные профили {{ CATALOG_MODEL.sProfileName }}" />
<meta itemprop="headline" content="Описание и характеристики оконных профилей {{ CATALOG_MODEL.sProfileName }} производства {{ CATALOG_MODEL.sProfileManufacturer }}" />
<meta name="news_keywords" content="{{ CATALOG_MODEL.sProfileName }}, характеристики {{ CATALOG_MODEL.sProfileName }}, описание {{ CATALOG_MODEL.sProfileName }}, оконные профили {{ CATALOG_MODEL.sProfileName }}, {{ CATALOG_MODEL.sProfileManufacturer }}, производитель {{ CATALOG_MODEL.sProfileManufacturer }}, каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия" />
<link rel="canonical" href="https://oknardia.ru//catalog/profile/{{ CATALOG_URL2 }}" />
<link rel="standout" href="https://oknardia.ru//catalog/profile/{{ CATALOG_URL2 }}" />
<link rel="canonical" href="https://oknardia.ru//catalog/profile/{{ CATALOG_URL2 }}/" />
<link rel="standout" href="https://oknardia.ru//catalog/profile/{{ CATALOG_URL2 }}/" />
<!-- Разметка для соц-сетей Facebook Open Graph -->
<meta property="fb:admins" name="admins" content="100000084781830" />
<meta property="fb:pages" content="276108456054163" />
@@ -1,11 +1,11 @@
{% extends "base.html" %}
{% load static %}
{% block Title %}Серии типового строительства{% endblock %}
{% block Title %}Серии типового строительства : Каталог{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Серии типового строительства | Каталог «Окнардия»{% endblock %}
{% block Description %}Каталог серий зданий и типовое панельное строительство оконного агрегатора Окнардия{% endblock %}
{% block Keywords %}типовое строительство, панельные серии, серии домов, серии зданий, типовые дома, типовые здания, каталог серий типового строительства, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
@@ -13,9 +13,9 @@
{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %}
{% block Author4Meta %}: Каталог серий домов{% endblock %}
{% block Author4Meta %}Серии домов : {% endblock %}
{% block CopyrightAuthor4Meta %}: Каталог серий домов{% endblock %}
{% block CopyrightAuthor4Meta %}Cерии домов : {% endblock %}
{% block Top_Meta1 %}{# <!-- BEGIN Дополнительные Metatags --> #}
<meta itemprop="author" content="Каталог «Окнардия»" />{% if IMG_FOR_BLOG %}
+121
View File
@@ -0,0 +1,121 @@
{% extends "base.html" %}{% load static %}
{% block Title %} Стандартные оконные проёмы типовых серий домов :: каталог{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов...{% endblock %}
{% block Keywords %}оконные проёмы, стандартные окна, стандартные оконные проемы, каталог, каталог оконных проёмов, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %}
{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %}
{% block Author4Meta %}: Каталог «Окнардия»{% endblock %}
{% block CopyrightAuthor4Meta %}: Каталог «Окнардия»{% endblock %}
{% block Top_Meta1 %}{# <!-- BEGIN Дополнительные Metatags --> #}
<meta itemprop="author" content="Каталог «Окнардия»" />{% if IMG_FOR_BLOG %}
<meta itemprop="image" content="https://oknardia.ru/media/{{ IMG_FOR_BLOG }}" />{% else %}
<meta itemprop="image" content="https://oknardia.ru/static/img/MerDY3gpU0w.jpg" />{% endif %}
<meta itemprop="datePublished" content="{{ PUB_DAT|date:"c" }}" />
<span itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="Каталог «Окнардия»" /></span>
<meta itemprop="articleSection" content="Каталог «Окнардия»" />
<meta itemprop="headline" content="Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов..." />
<meta name="news_keywords" content="{{ HEADER|striptags }}" />
<link rel="canonical" href="https://oknardia.ru//catalog/" />
<link rel="standout" href="https://oknardia.ru//catalog/" />
<!-- Разметка для соц-сетей Facebook Open Graph -->
<meta property="fb:admins" name="admins" content="100000084781830" />
<meta property="fb:pages" content="276108456054163" />
<meta property="fb:app_id" content="258354027974262" />
<meta property="fb:profile_id" name="profile_id" content="https://www.facebook.com/oknardia/" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:site_name" content="oknardia.ru" />
<meta property="og:url" content="https://oknardia.ru//catalog/" />
<meta property="og:type" content="article" />
<meta property="og:title" content="Каталог «Окнардия» | oknardia.ru" />
<meta property="og:description" content="Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов..." />
<meta property="og:image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:"https://oknardia.ru/static/img/MerDY3gpU0w.jpg" }}" />
<link rel="image_src" href="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:"https://oknardia.ru/static/img/MerDY3gpU0w.jpg" }}" />
<!-- Разметка для соц-сетей Twitter Card -->
<meta name="twitter:title" content="Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов... | oknardia.ru"/>
<meta name="twitter:description" content="Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов..." />
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@oknardia" />
<meta name="twitter:domain" content="oknardia.ru" />
<meta property="twitter:url" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
<meta name="relap-image" content="{% if IMG_FOR_BLOG %}https://oknardia.ru/media/{% endif %}{{ IMG_FOR_BLOG|default:'https://oknardia.ru/static/img/MerDY3gpU0w.jpg' }}" />
{# <!-- END Дополнительные Metatags --> #}{% endblock %}
{% block Main_Content %}
<div class="container-fluid">
{# <!--- Хлебные крошки: НАЧАЛО --> #}<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog">Каталог</a></li>
<li>Оконные проёмы и балконные блоки</li>
</ol>
</div>
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
<dIv class="row">
{# ПЕРВЫЙ РАЗДЕЛ #}<div class="col-md-9 col-xs-8">
<h1>Стандартные оконные проёмы и&nbsp;балконные блоки</h1>
<p>Ценовая выдача «Окнардии» основана на базе стандартных оконных проёмов в типовых сериях домов. Для каждого проёма существуют рекомендованные организациями-проектировщиками схемы открывание, но партнёры «Окнардии» могут предложить свои, более расширенные или наоборот сокращенные. В таблице приведены параметры стандартных проёмов базы.</p>
</div>
{# реклама Oknardia 250x250 СБОКУ #}<div class="col-md-3 col-xs-4 float-right">{% include "ad/bannet-250x250.html" %}</div>
<div class="col-md-11 col-xs-12 catalog scrolled">
<table class="table-striped table-hover table-responsive flap-catalog">
<thead>
<tr>
<th colspan="3" class="c">Размеры (мм)</th>
<th rowspan="2" class="b c">Стандартная<br>схема<br>открывания</th>
<th colspan="2" class="c">Балконный блок</th>
<th rowspan="2">Описание окна</th>
<th rowspan="2">Типовые серии домов где встречается данный оконный проём</th>
<th rowspan="2"></th>
</tr>
<tr>
<th class="r b">Ш</th>
<th class="x b">&times;</th>
<th class="x b">В</th>
<th class="c b">Окно</th>
<th class="c b">Дверь</th>
</tr>
</thead>
<tbody>{% for i in LIST_WIN_OPENING %}
<tr>
<td data-sort="{{ i.W|stringformat:".0f" }}">{{ i.W|stringformat:".0f" }}</td>
<td>&times;</td>
<td data-sort="{{ i.H|stringformat:".0f" }}">{{ i.H|stringformat:".0f" }}</td>
<td data-sort="{{ i.FLAP_CONFIG }}"><img src="{% static i.URL2IMG %}" title="{{ i.DESCRIPTION_L }}, {{ i.W|stringformat:".0f" }}×{{ i.H|stringformat:".0f" }} мм." alt="{{ i.DESCRIPTION_L }}, {{ i.W|stringformat:".0f" }}×{{ i.H|stringformat:".0f" }} мм." /></td>
<td data-sort="{% if i.IS_NEAR_DOOR %}1{% else %}0{% endif %}">{% if i.IS_NEAR_DOOR %}да{% else %}—{% endif %}</td>
<td data-sort="{% if i.IS_DOOR %}1{% else %}0{% endif %}">{% if i.IS_DOOR %}да{% else %}—{% endif %}</td>
<td>{{ i.DESCRIPTION }}</td>
<td>{% for j in i.INCLUDING_IN_SERIA %}<a href="/catalog/seria/{{ j.NAME_T }}/all{{ j.ID }}">{{ j.NAME }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>
<td><a class="btn btn-default btn-xs" href="/tsena-odnogo-okna/{{ i.W|stringformat:".0f" }}x{{ i.H|stringformat:".0f" }}mm/tip{{ i.ID }}">цены</a></td>
{# {% for j in SERIAS %}#}
{# <td>{% if j.id in i.INCLUDING_IN_SERIA %}#{% endif %}</td>{% endfor %}#}
</tr>{% endfor %}
</tbody>
</table>
</div>
<DIV class="col-xs-12" style="height:6em;"></DIV>
</dIv>
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>{% endblock %}
+1 -1
View File
@@ -44,7 +44,7 @@ function init () {
<div id="box" class="col-md-9 col-md-offset-2"><!--- Сюда подгружаем центральный popup --->
{% if not CONFIRM_OK %}
{% include "popup_index.html" %}
{% include "popup/popup_index.html" %}
{% elif CONFIRM_OK == "YES" %}
{% include "user_manager/popup_cofirm_email_ok.html" %}
{% elif CONFIRM_OK == "NO" %}
+26
View File
@@ -0,0 +1,26 @@
{% load static %}
<script type="text/javascript">
if ( document.getElementById("box") == null ) window.location.replace("/"); // проверяем, а не вызвали-ли этот popup отдельно
myMap.setCenter([{{ LONGITUDE|default:"37.77" }},{{ LATITUDE|default:"55.68" }}]);
$(document).ready(function(){
setTimeout("window.location.href='/'", 50000);
});
</script>
<h1>Ошибка адреса</h1>
<div>
<p>Это могло произойти по следующим причинам:</p>
<ul>
<li><b>Ошибка при вводе адреса <i>«{{ addr }}»</i>.</b><br />
Если вы&nbsp;ошиблись при указании адреса <a href="/">попробуйте ввести адрес ещё раз</a> или
<a href="/stat_all/#s_map">найдите его на карте типовых серий</a> жилого строительства.<br>&nbsp;</li>
<li><b>Адрес <i>«{{ addr }}»</i> отсутствует в&nbsp;нашей базе.</b><br />
Приносим извинения, но&nbsp;пока нами обработаны только типовые серии Москвы и&nbsp;Подмосковья, Санкт-Петербурга
и&nbsp;Ленинградской области.<br />
Свяжитесь с&nbsp;нами чтобы мы&nbsp;ускорили оцифровку и&nbsp;поиск партнеров в&nbsp;вашем&nbsp;регионе.</li>
</ul>
<div style="float:right;font-size:xx-small">TICKs: {{ ticks|floatformat:4 }}</div>
</div>
@@ -44,12 +44,12 @@
$('.show_delayed').fade_obj();
});
</script>
<h1>Выбирайте окна в квартиру<!-- ({{ NV }})-->:</h1>
{% if NV <= 1 %}
<h1>Узнайте стоимость установки окон в&nbsp;квартиру от&nbsp;разных поставщиков<!-- ({{ NV }})-->:</h1>
{% if NV <= 3 %}
<ol>
<li class="show_delayed">Вводите адрес дома или выберите его из подсказки,</li>
<li class="show_delayed">укажите тип квартиры,</li>
<li class="show_delayed">получите актуальные цены и сравнивайте характеристики предложений.</li>
<li class="show_delayed">Введите адрес дома (или выберите адрес из&nbsp;подсказки),</li>
<li class="show_delayed">укажите тип планировки квартиры</li>
<li class="show_delayed">и получите актуальные цены, сравнивайте характеристики предложений и&nbsp;условия установки.</li>
</ol>
{% endif %}
<form class="show_delayed" method="post" id="input_address">
@@ -0,0 +1,71 @@
{% load static %}{% load filters %}
<script type="text/javascript">
if (document.getElementById("box") == null) window.location.replace("/"); // проверяем, а не вызвали-ли этот popup отдельно
myMap.setCenter([{{ LONGITUDE|default:"37.77" }}, {{ LATITUDE|default:"55.68" }}], 15);
$(document).ready(function () {
$(".collapse").on("shown.bs.collapse", function () {
$("#box").css({
"top": "15%"
});
});
$(".collapse").on("hidden.bs.collapse", function () {
$("#box").css({
"top": "20%"
});
});
});
</script>
<div class="panel-heading">
<button type="button" class="close" data-dismiss="modal" onmouseout="window.location.href='/';"><span aria-hidden="true">&times;</span><span class="sr-only">Неверный адрес</span></button>
Здание по адресу: {{ addr }} <span class="text-muted" style="font-size:x-small;">(id:{{ ADDRESS_ID }})</span>
</div>
{% if LIST_APART %}<h1>Укажите типовую планировку вашей квартиры:</h1>
<div class="btn-toolbar" style="width:80%">{% for I_APART in LIST_APART %}
<button type="button" class="btn btn-default" style="margin:1ex"
accesskey="{{ I_APART.id }}"
onclick="window.location.href='/{{ ADDRESS_ID }}/{{ I_APART.id }}/{{ addr_T }}';try{yaCounter32997984.reachGoal('CHOICE_APP');}catch(e){}">
{{ I_APART.sNameApartment|safe }}
</button>{% endfor %}
</div>
{% else %}
<script type="text/javascript">
function uClick( i ) {
try {
yaCounter32997984.reachGoal('FIND');
ga('send', 'event', 'CLICK', 'ClickSearch', 'SearchAddress');
_tmr.push({id: '2018432', type: 'reachGoal', goal: 'ClcSrh'});
}
catch (e) {
}
$.ajax({
url: "/get_address", //Адрес подгружаемой страницы
type: "POST", //Тип запроса
dataType: "html", //Тип данных
data: "csrfmiddlewaretoken={{ csrf_token }}&address="+$('#a'+i).html(),
success: function (html) {
$("#box").html(html)
}
});
return false;
}
</script>
<h1>Нет данных по этому дому</h1>
<div style="width:80%">
<p>К&nbsp;сожалению база &laquo;Окнардии&raquo; только формируется. Пока у&nbsp;нас нет данных по&nbsp;типовым квартирам для дома по этому адресу. Ближащие адреса, по которым есть информация:</p>
<ul style="list-style:none;">{% for i in NEAR_KNOWN_ADDRESS %}
<li>
<!-- Расстояние до дома -->
<nobr class="badge badge4price" title="Удалённость — {{ i.R2|stringformat:"0.2f" }} км."><b class="glyphicon glyphicon-map-marker"></b> {{ i.R2|stringformat:"0.2f"|price_format }}&thinsp;км.</nobr> &nbsp; <a href="#" onclick="uClick({{ forloop.counter0 }})" id="a{{ forloop.counter0 }}">{{ i.sAddress }}</a>
</li>
{% endfor %}</ul>
<p>С небольшой погрешностью (±6%) мы&nbsp;можем дать ценовые предложения под ваши требования, но потребуется самостоятельный замер проёмов.</p>
<button type="button" class="btn btn-default" style="margin:1ex"
accesskey="1" onclick="window.location.href='/order_by_dim'">
Подобрать предложения по&nbsp;предварительным замерам <span class="glyphicon glyphicon-search"></span>
</button>
<p style="font-size:xx-small;width:80%"><small>Сделав замер, и сообщив его нам, вы&nbsp;поможете наполнению базы &laquo;Окнардии&raquo;, вашим соседям и&nbsp;сотням людей проживающих в&nbsp;домах таких&nbsp;же серий или проектов. В&nbsp;благодарность за&nbsp;содействие мы&nbsp;подготовим и&nbsp;вышлем самые актуальные предложения по&nbsp;email, а&nbsp;также предоставим купон, предоставляющий скидку на&nbsp;сумму <b>500&nbsp;рублей</b> при установке окон любым из&nbsp;наших партнёров. Если согласны <a href="/send_order_and_info">перейдите по&nbsp;ссылке</small>:<br /></a>.</p>
</div>{% endif %}
<a class="text-muted" data-toggle="collapse" href="#collapse_it" onclick="yaCounter32997984.reachGoal('ClickBuildingDetails');" style="float:right;margin-bottom:1ex;">Подробная информация по зданию <small class="glyphicon-chevron-down glyphicon"></small></a>
{% include "report/build_info_in_table.html" %}
+207
View File
@@ -0,0 +1,207 @@
{% extends "base.html" %}
{% load static %}
{% load filters %}
{% block Title %}Цены на окна для {{ ADDRESS }} — дом серии {{ APART|safe }}{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Description %}Цены на окна для серии {{ APART|safe }} по адресу {{ ADDRESS }}. Размер окон (см.): {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}{% if forloop.last %}.{% else %}; {% endif %}{% endfor %} Оконные наборы: {% for CurOffer in PRICE_FRAME %}{{ CurOffer.SETS_NAME }}  {{ CurOffer.FIN_PRICE|stringformat:".0f" }} рублей{% if forloop.last %}.{% else %}; {% endif %}{% endfor %}{% endblock %}
{% comment %}{% block Description %}Цены на плаcтиковые окна для серии {{ BASE_SERIA }} ({{ APART }} квартира, {{ ADDRESS }}) :: {% for CurOffer in PRICE_FRAME %}Поставщик: {{ CurOffer.MERCHANT }}; Комплектация: {{ CurOffer.SETS_NAME }}; Цена: {{ CurOffer.FIN_PRICE }}₽ :: {% endfor %}{% endblock %}{% endcomment %}
{% block Keywords %}цены окон, серия {{ BASE_SERIA }}, {{ BASE_SERIA }}, стоимость окон, окна для {{ BASE_SERIA }}, размеры окон, проемы серии {{ BASE_SERIA }}, окна в {{ APART|safe }}, скидки на окна, {{ ADDRESS }}, оконный профиль, {% for CurOffer in PRICE_FRAME %}{{ CurOffer.MERCHANT }}, {{ CurOffer.PVC_NAME }}, {{ CurOffer.PVC_MANUFACTURER }}, {{ CurOffer.GLAZING_MARK }}, {% endfor %} характеристики пластиковых окон, {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см., {% endfor %}{{ META_KEYWORDS|default:"" }}{% endblock %}
{% block Top_JS3%}<script type="text/javascript">
function show_phone_num( id ){ // колапсатор для отображения контатной информации постафшика окон
$('#tel'+id).collapse('show');
$('#hid'+id).collapse('hide');
try {
yaCounter32997984.reachGoal('ShowPhone')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewPhone"});
} catch (e) {
}
}
function show_dtl( id ){ // колапсаторы для отобращения детальной информации оконого набора
$('#dtl'+id).collapse('show');
$('#btn'+id+' a .glyphicon-chevron-down').remove();
var ContentInA = $('#btn'+id+' a').text();
$('#btn'+id).empty();
$('#btn'+id).text(ContentInA);
try {
yaCounter32997984.reachGoal('ShowDetails')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewDetails"});
} catch (e) {
}
}
$(window).load( // уменьшение картинок .half для ретина-дисплеев
function(){var images = $('.half');images.each(function(i){$(this).width($(this).width()/2);});}
);
var count = 0;
var ForCompare = document.getElementsByName('ForCompare');
$(window).load( // подсчитать сколько прочеканных оферов для сравнения (нужно, когда на страничку возращаются через back, ее подгрущают или она приходит из кеша
function(){
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
count++;
// alert(count);
$('#NumberOfSelected').html(count)
}
);
var ToURL = '';
function Click2CompareOffers(){ // вызывается при клике "сравнить коммерческие предложения"
try{yaCounter32997984.reachGoal('CompareOffers')}catch(e){}
//ForCompare = $('[name]=ForCompare');
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
ToURL += ForCompare[i].value +',';
if (ToURL.match(/[,]/g).length > 1 && ToURL.match(/[,]/g).length < 7 )
location.href = '/compare_offers/' + ToURL.slice(0,-1);
else {
$('#modal-exclamation').modal('show');
ToURL = '';
}
}
function ChangeCountCheckedBox(CHK_ID){ // изменение числа выбранных для сравнения оферов
if ($("#CHK"+CHK_ID).is(":checked")) count++;
else count--;
$("#NumberOfSelected").html(count)
}
function get_more_info_about_building() {
try{yaCounter32997984.reachGoal("ClickBuildingDetails");}catch(e){}
}
$(function () { // инициализация и обработка поповеров рейтинга
$('[data-toggle="popover"]').popover({
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"), function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
})
})
</script>{% endblock %}
{% block Top_CSS1 %}<link rel="stylesheet" type="text/css" href="{% static "css/csshake-vertical.min.css" %}">{% endblock %}
{% block Main_Content %}
<span itemscope itemtype="http://schema.org/Product">
<div class="row col-md-12">
<div class="col-md-9">
<h1>Цены на окна для серии {{ APART|safe }} <small>({{ ADDRESS }})</small></h1>
</div>
<div class="col-md-9">
<p>Квартира имеет проёмы (окна и балконные двери) следующих размеров: {% for I_WIN_DIM in FLAP_DIM %}{% if not forloop.first %}{% if forloop.last %} и&nbsp;{% else %}, {% endif %}{% endif %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}&nbsp;см. —&nbsp;{{ I_WIN_DIM.iQuantity }}&nbsp;шт.{% endfor %} Проект (<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">типовая серия {{ BASE_SERIA }}</a>) предполагает следующие схемы открывания окон:</p>
</div>
{# Микроразмектка: названеи продукта #}<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})" />
</div>
<div class="row col-md-12 ShowBigFlapPictures">
<div class="col-sm-9">
{% include 'report/show_big_flap_pictures.html' %}
</div>
<div class="col-sm-3 visible-md visible-lg ap_list">
<h6>Другие типовые квартиры в&nbsp;этом доме:</h6>
<ul>{% for I_APART in APARTMENT_IN_BUILDING %}
{% if I_APART.APT_ID == '!' %}<li>{{ I_APART.APT_NAME|safe }}</li>{% else %}<li><a href="/{{ BUILD_ID }}/{{ I_APART.APT_ID }}/{{ ADDRESS_T }}">{{ I_APART.APT_NAME|safe }}</a></li>{% endif %}{% endfor %}
</ul>
<a href="/catalog/seria/{{ BASE_SERIA_LAT }}/all{{ BASE_SERIA_ID }}">Информация по серии {{ BASE_SERIA }}</a>
</div>
</div>
<div class="row col-md-12">
<div class="col-md-12">
<p id="tab-note">Таблица содержит цены поставщиков. Клик на&nbsp;название отобразит детальные спецификации каждого предложения: марку профиля рамы и&nbsp;створки, схему стеклопакета, тип фурнитуры, элементы отделки (отлив, подоконник, откос, клапан <nobr>климат-контроля</nobr>) и&nbsp;сопутствующие услуги. Предложения выводятся покадрово, получите следующий кадр кнопкой &laquo;Ещё коммерческие предложения окон&raquo; под таблицей. Просмотреть и&nbsp;сравнить технические характеристик стеклопакетов, профилей и&nbsp;детальное описание сопутствующих услуг возможно с&nbsp;помощью кнопки &laquo;Сравнить выбранные&raquo;.</p>
</div>
{# Микроразмектка: названеи продукта #}
<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})"/>
</div>
<form class="col-md-12" method="get" action="\" id="compare_offers">
{% csrf_token %}
<table class="table" id="price-list">
<thead>
<tr>
<th><b class="glyphicon glyphicon-th-list" title="Добавление набора окон в список сравнения" aria-label="Добавление набора окон в список сравнения"></b></th>
<th>Поставщик окон и название оконного набора<small><br />
кликните чтобы увидеть описание и характеристики предложения</small>
</th>
<th colspan="2">Схема<small><br />
открывания</small></th>
<th>Цена,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
одно окно</small></th>
<th>N</th>
<th colspan="2" class="hidden-xs hidden-sm">Cумма,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
однотипные окна</small></th>
<th>Стоимость, <b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
все окна квартиры</small></th>
<th>Скидка</th>
<th>Итого<small><br />
за все окна с учетом скидки</small></th>
</tr>
</thead>
<tbody id="offers">
{% include "price/price_list_frame.html" %}
</tbody>
</table>
</form>
</span>
{% with SERIA_BASE=BASE_SERIA %}{% include "report/build_info_in_table.html" %}{% endwith %}
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
<p id="shadow_buffer"></p>
</div>
{# модальное окно #}
<div class="modal fade bs-example-modal-sm" id="modal-exclamation" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="mySmallModalLabel">Внимание:</h4>
</div>
<div class="modal-body">
<p>Извините, для сравнения коммерческих предложений окон нужно выбрать не менее двух и не более шести позиций.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Спасибо, все понятно.</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}
+150
View File
@@ -0,0 +1,150 @@
{% load static %}{% load filters %}
{% for CurOffer in PRICE_FRAME %}
<tr>
<td colspan="11" style="font-size:xx-small;border-top:double black;border-bottom: solid 1px white;padding: 0;"></td>
</tr>{% for CurInOffer in CurOffer.DIM %}
<tr>
{% if forloop.first %}
<th rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}" title="Добавить коммерческое предложение окон к сравнению">{# красивые чекбоксы BEGIN #}<div class="checkbox"><label><input id="CHK{{ CurOffer.SETS_ID }}" type="checkbox" name="ForCompare" value="{{ CurOffer.SETS_ID }}" onChange="ChangeCountCheckedBox({{ CurOffer.SETS_ID }});" /><span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span></label></div>{# красивые чекбоксы END #}</th>
<td rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}"{% if CurOffer.IS_COMMERCIAL %} style="background-image: url(/media/{{ CurOffer.MERCHANT_LOGO }})"{% endif %} title="Краткая спецификация коммерческого предложения">
<span itemprop="description">
<h3 class="set-name shake-trigger" id="btn{{ CurOffer.SETS_ID }}"><a href="javascript://" onclick="show_dtl({{ CurOffer.SETS_ID }})">{{ CurOffer.MERCHANT }}  {{ CurOffer.SETS_NAME }}<i class="glyphicon glyphicon-chevron-down shake-vertical"></i></a></h3>
<DiV id="dtl{{ CurOffer.SETS_ID }}" class="collapse">■ Профиль: <a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_NAME_T }}">{{ CurOffer.PVC_NAME|safe }}</a> (<a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}">{{ CurOffer.PVC_MANUFACTURER }}</a>)
&nbsp;{{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
&nbsp;Тонирование:&nbsp;{{ CurOffer.GLAZING_TONING }}
{% if CurOffer.PVC_SEAL %}■&nbsp;Уплотнитель:&nbsp;{{ CurOffer.PVC_SEAL }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT %}■&nbsp;Фурнитура:&nbsp;{{ CurOffer.SETS_IMPLEMENT|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_R %}■&nbsp;Ручки:&nbsp;{{ CurOffer.SETS_IMPLEMENT_R|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_P %}■&nbsp;Петли:&nbsp;{{ CurOffer.SETS_IMPLEMENT_P|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_Z %}■&nbsp;Запоры:&nbsp;{{ CurOffer.SETS_IMPLEMENT_Z|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_O %}■&nbsp;Ограничители:&nbsp;{{ CurOffer.SETS_IMPLEMENT_O|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_F %}■&nbsp;Фиксаторы:&nbsp;{{ CurOffer.SETS_IMPLEMENT_F|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_CLIMATE_CONTROL %}<span {% if CurOffer.SETS_CLIMATE_CONTROL|capfirst != "Нет" or CurOffer.SETS_CLIMATE_CONTROL|length > 3 %}class="bullet-green"{% endif %}>■&nbsp;Климат-контроль:&nbsp;{{ CurOffer.SETS_CLIMATE_CONTROL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SILL %}<span {% if CurOffer.SETS_SILL|capfirst == "Нет" or CurOffer.SETS_SILL|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Подоконник:&nbsp;{{ CurOffer.SETS_SILL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SLOPE %}<span {% if CurOffer.SETS_SLOPE|capfirst == "Нет" or CurOffer.SETS_SLOPE|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Откос:&nbsp;{{ CurOffer.SETS_SLOPE|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_PANES %}<span {% if CurOffer.SETS_PANES|capfirst == "Нет" or CurOffer.SETS_PANES|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Водоотлив:&nbsp;{{ CurOffer.SETS_PANES|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_UNINSTALL_INSTALL %}<span {% if CurOffer.SETS_UNINSTALL_INSTALL_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Демонтаж/монтаж:&nbsp;{{ CurOffer.SETS_UNINSTALL_INSTALL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_DELIVERY %}<span {% if CurOffer.SETS_DELIVERY_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Доставка:&nbsp;{{ CurOffer.SETS_DELIVERY|capfirst|safe }}</span>{% endif %}{% comment %} {% if CurOffer.SETS_OTHER %}■&nbsp;Прочие условия:&nbsp;{{ CurOffer.SETS_OTHER|capfirst|safe }}
{% endif %}{% endcomment %}
</DiV>
<!-- Расстояние до офиса поставщика -->
<nobr>{% if CurOffer.DISTANCE != -1 %}<nobr class="badge badge4price" title="Удалённость офиса — {{ CurOffer.DISTANCE|stringformat:"0.1f" }} км."><b class="glyphicon glyphicon-map-marker"></b> {{ CurOffer.DISTANCE|stringformat:"0.1f"|price_format }}&thinsp;км.</nobr>{% endif %}</nobr>
<!-- Дата обновления -->
<nobr class="badge badge4price" title="Дата обновления коммерческого предложения окон — {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}"><b class="glyphicon glyphicon-calendar"></b> {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}</nobr>
<!-- Звездочки рейтинга -->
<nobr class="badge badge4price" title="Рейтинг «Окнардии»{% if CurOffer.SETS_RATING > -0.1 %} — {{ CurOffer.SETS_RATING|stringformat:".2f" }} баллов{% endif %}"><a
href="javascript://"
id-set="{{ CurOffer.SETS_ID }}"
data-trigger="focus" tabindex="0"
title="{% if CurOffer.SETS_RATING > 0.01 %}<b> Рейтинг {{ CurOffer.SETS_RATING|stringformat:".2f" }}</b> для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит&nbsp;из:{% else %}Рейтинг не присвоен{% endif %}"
data-toggle="popover">рейтинг</a>:&nbsp;{% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %} {{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %}</nobr>
</span>
<span itemprop="brand" itemscope itemtype="http://schema.org/Brand">
<meta itemprop="name" content="{{ CurOffer.MERCHANT }}" />
<meta itemprop="logo" content="https://oknardia.ru/media/{{ CurOffer.MERCHANT_LOGO }}" />
</span></td>
<!--- Конец большой ячейки со спецификацией оконного предложения --->
{% endif %}
<td class="rnw" title="{{ CurInOffer.QUANTITY }} × {{ CurInOffer.DESCRIPTION }} — {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм.">{% for BUL in CurInOffer.BULLET %}<span class="color-bullet" style="background-image:url({% static "img/svg/mark" %}{{ BUL }}.svg);"></span>{% endfor %}</td>
<td class="rnw" title="Схема открывания окна или двери {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм."><img src="{% static CurInOffer.IMG_MINI %}" alt="Схема открывания: {{ CurInOffer.DESCRIPTION }} — {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм." /></td>
<td class="rnw" title="Цена {{ CurInOffer.PRICE|stringformat:".2f" }} рублей.">{{ CurInOffer.PRICE|stringformat:".2f"|price_format }}</td>
<td title="Количество: {{ CurInOffer.QUANTITY }} шт.">×{{ CurInOffer.QUANTITY }}</td>
<td class="rnw hidden-xs hidden-sm">=</td>
<td class="rnw hidden-xs hidden-sm" title="Сумма {{ CurInOffer.SUBTOTAL|stringformat:".2f" }} рублей за {{ CurInOffer.QUANTITY }} шт.">{{ CurInOffer.SUBTOTAL|stringformat:".2f"|price_format }}</td>
{% if forloop.first %}<!-- FIRST -->
<td class="rnw" title="Стоимость {{ CurOffer.TOTAL|stringformat:".2f" }} рублей за все окна квартиры {{ APART|safe }}.">{{ CurOffer.TOTAL|stringformat:".2f"|price_format }}</td>
<th{% if CurOffer.DISCOUNT_COLOR2 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR2 }};"{% endif %} title="{% if CurOffer.DISCOUNT < 0.1 %}Нет скидки{% else %}Скидка — {{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}">{% if CurOffer.DISCOUNT < 0.1 %}{% else %}&minus;{{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}</th>
<th{% if CurOffer.DISCOUNT_COLOR1 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR1 }};"{% endif %} itemprop="offers" itemscope itemtype="http://schema.org/Offer" title="Итого за все окна с учетом скидки: {{ CurOffer.FIN_PRICE|stringformat:".2f" }} рублей">
Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }}&thinsp;<small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small>
<meta itemprop="price" content="{{ CurOffer.FIN_PRICE }}" />
<meta itemprop="priceCurrency" content="RUB" />
</th>
{% if CurOffer.DIM|length == 1 %}
</tr><tr>
<td colspan="6">&nbsp;</td>
<td colspan="3">
{% endif %}
{% elif forloop.counter0 == 1 %}
<td colspan="3" rowspan="{{ CurOffer.DIM|length|add:"-1" }}">
{% endif %}
{% if forloop.counter0 == 1 or CurOffer.DIM|length == 1 %}
<stong>{{ CurOffer.OFFICE_NAME }}</stong><br />
<div id="hid{{ CurOffer.SETS_ID }}" class="collapse in">
<a class="btn btn-info btn-xs shake-trigger" data-toggle="collapse" data-target="#tel{{ CurOffer.SETS_ID }}" onclick="show_phone_num({{ CurOffer.SETS_ID }})"><b class="glyphicon glyphicon-phone-alt shake-vertical"></b> Показать телефон</a>
</div>
<div id="tel{{ CurOffer.SETS_ID }}" class="collapse">
<small>{{ CurOffer.OFFICE_ADDRESS }}</small><br /> <b class="glyphicon glyphicon-phone-alt"></b> {{ CurOffer.OFFICE_PHONES }}<br />
<small><nobr>Пожалуйста, скажите, что нашли цены на oknardia.ru</nobr></small>
</div>
</td>
{% endif %}
</tr>{% endfor %}<!----- ПРОВЕРКА --->{% endfor %}
<Tr id="preloader_{{ N }}">
<tH colspan="11"><center><img src="{% static "img/preloader.gif" %}" alt="подгружаю цены на окна..." height="64" width="64" /></center></tH>
</Tr>
<tR id="load_and_banner_{{ N }}">
<!-- сюда подгружаем следующий фрейм прайслиста --->
<script type="application/javascript">
function get_next_pricelist_frame( ) {
try{yaCounter32997984.reachGoal("MoreOffer");}catch(e){}
// заменяем ряд с кнопочками кнопочками на рекламу
// $("#load_and_banner_{{ N }}").html("<th colspan=10>РЕКЛАМА TMP</th>");
// добавляем ячейки с дополнительными ценами и новые кнопочки
$("#load_and_banner_{{ N }}").css({"display":"none"});
$("#preloader_{{ N }}").css({"display":"table-row","transition":"1s"});// подсчитать сколько прочеканных оферов для сравнения
$("#tmp").load(
"/next_price_frame/idA{{ APPARTMENT_ID }}MDPO{{ MOUNT_DIM_PER_OFFER }}LON0LAT0N{{ N }}",
function (){
window.frame = $("#tmp").html();
$("#price-list > tbody").append(window.frame);
}
);
window.setTimeout(
function show_adv() {
$("#load_and_banner_{{ N }}").html("<td colspan='11' bgcolor='#CCCCCC' align='center'><center><a href='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/link?partner=e-serg&&utm_content=banner&width=728&height=90' target='_blank'><img src='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/image?partner=e-serg&utm_content=banner&width=728&height=90' width='728px' height='90px'></a><small><br/>↑ Здесь могла бы быть ваша реклама ↑</small></center></td>");
$("#load_and_banner_{{ N }}").css({"display":"table-row","transition":"all 5s"});
$("#preloader_{{ N }}").css({"display":"none","transition":"1s"});
// (adsbygoogle=window.adsbygoogle || []).push({});
window.count = 0;
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
window.count++;
$("#NumberOfSelected").html(window.count);
$('[data-toggle="popover"]').popover({ // реинициализировать подгружаемые поповеры
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"),
function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
});
},
2800);
}
</script>
<td colspan="2"><a class="btn btn-info btn-block" data-toggle="collapse" onclick="Click2CompareOffers();">Сравнить выбранные (<span id="NumberOfSelected">0</span>) <small class="glyphicon-stats glyphicon"></small></a><p id="tmp"></p></td>
<td colspan="8">{% if N != "-1" %}<a href="javascript://" class="btn btn-info btn-block" onclick="get_next_pricelist_frame();">Ещё коммерческие предложения окон &nbsp;<small class="glyphicon-refresh glyphicon"></small></a>{% endif %}</td>
<td><a data-toggle="collapse" href="#collapse_it" onclick="get_more_info_about_building()" class="shake-trigger">Подробная информация по зданию <small class="glyphicon-chevron-down glyphicon shake-vertical"></small></a></td>
</tR>
+245
View File
@@ -0,0 +1,245 @@
{% extends "base.html" %}{% load static %}
{% load filters %}
{% block Title %}Цены на типовое окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. для домов серий {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}{{ I.sName }}{% endfor %}{% endfor %}{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Top_JS4 %}
<script type="text/javascript" src="//www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages: ["corechart"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Схема открывания', 'Число предложений'], {% for I in LIST_FLAP_VARIATION %}
['{{ I.STR_NUM }}', {{ I.id }}]{% if not forloop.last %}, {% endif %}{% endfor %}
]);
var options = {
legend: {position: "none"},
backgroundColor: 'none',
pieHole: 0.386,
chartArea: {width: '80%', height: '90%'},
pieStartAngle: 5,
pieSliceTextStyle: {fontSize: 12},
is3D: true,
slices: {0: {offset: 0.1}},
tooltip: {textStyle: {fontSize: 11, color: 'black', opacity: 0.8}, showColorCode: true}
};
var chart = new google.visualization.PieChart(document.getElementById('donutchart'));
chart.draw(data, options);
}
</script>{% endblock %}
{% block Description %}Цены на типовое окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. для домов серий {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}{{ I.sName }}{% endfor %}{% endfor %}.{% endblock %}
{% comment %}{% block Description %}Цены на пластиковые окна для серии {{ BASE_SERIA }} ({{ APART }} квартира, {{ ADDRESS }}) :: {% for CurOffer in PRICE_FRAME %}Поставщик: {{ CurOffer.MERCHANT }}; Комплектация: {{ CurOffer.SETS_NAME }}; Цена: {{ CurOffer.FIN_PRICE }}₽ :: {% endfor %}{% endblock %}{% endcomment %}
{% block Keywords %}цены на окно, типовое окно, {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}{% endfor %} cм., {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }}{% endfor %} см., стоимость окна, {% for I in SERIA_FOR_WIN %}серия {{ I.sName }}, {% endfor %}типовой проём, {{ META_KEYWORDS|default:"" }}{% endblock %}
{% block Top_JS3%}<script type="text/javascript">
function show_phone_num( id ){ // колапсатор для отображения контатной информации постафшика окон
$('#tel'+id).collapse('show');
$('#hid'+id).collapse('hide');
try {
yaCounter32997984.reachGoal('ShowPhone')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewPhone"});
} catch (e) {
}
}
function show_dtl( id ){ // колапсаторы для отобращения детальной информации оконого набора
$('#dtl'+id).collapse('show');
$('#btn'+id+' a .glyphicon-chevron-down').remove();
var ContentInA = $('#btn'+id+' a').text();
$('#btn'+id).empty();
$('#btn'+id).text(ContentInA);
try {
yaCounter32997984.reachGoal('ShowDetails')
} catch (e) {
}
try {
var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: "2018432", type: "reachGoal", goal: "ViewDetails"});
} catch (e) {
}
}
$(window).load( // уменьшение картинок .half для ретина-дисплеев
function(){var images = $('.half');images.each(function(i){$(this).width($(this).width()/2);});}
);
var count = 0;
var ForCompare = document.getElementsByName('ForCompare');
$(window).load( // подсчитать сколько прочеканных оферов для сравнения (нужно, когда на страничку возращаются через back, ее подгрущают или она приходит из кеша
function(){
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
count++;
// alert(count);
$('#NumberOfSelected').html(count)
}
);
var ToURL = '';
function Click2CompareOffers(){ // вызывается при клике "сравнить коммерческие предложения"
try{yaCounter32997984.reachGoal('CompareOffers')}catch(e){}
//ForCompare = $('[name]=ForCompare');
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
ToURL += ForCompare[i].value +',';
if (ToURL.match(/[,]/g).length > 1 && ToURL.match(/[,]/g).length < 7 )
location.href = '/compare_offers/' + ToURL.slice(0,-1);
else {
$('#modal-exclamation').modal('show');
ToURL = '';
}
}
function ChangeCountCheckedBox(CHK_ID){ // изменение числа выбранных для сравнения оферов
if ($("#CHK"+CHK_ID).is(":checked")) count++;
else count--;
$("#NumberOfSelected").html(count)
}
function get_more_info_about_building() {
try{yaCounter32997984.reachGoal("ClickBuildingDetails");}catch(e){}
}
$(function () { // инициализация и обработка поповеров рейтинга
$('[data-toggle="popover"]').popover({
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"), function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
})
})
</script>{% endblock %}
{% block Top_CSS1 %}<link rel="stylesheet" type="text/css" href="{% static "css/csshake-vertical.min.css" %}">{% endblock %}
{% block Main_Content %}<div class="container-fluid">
{# <!--- Хлебные крошки: НАЧАЛО --> #}<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog">Каталог</a></li>
<li><a href="/catalog/standard_opening/">Оконные проёмы и балконные блоки</a></li>
<li>Окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth_mm|floatformat:0 }}&times;{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %}&nbsp;мм. </li>
</ol>
<h1>Стандартные оконные проёмы и&nbsp;балконные блоки</h1>
</div>
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
<span itemscope itemtype="http://schema.org/Product">
<div class="row">
<div class="col-md-9">
<h1>Цены на окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth_mm|floatformat:0 }}&times;{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %}&nbsp;мм. <small>(типовое)</small></h1>
</div>
<div class="col-md-9">
<p>Типовой проём {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:1 }}&times;{{ I_WIN_DIM.iWinHight|floatformat:1 }}{% endfor %}&nbsp;cм. представлен в домах серий: {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}<a href="/catalog/seria/{{ I.sNameLat }}/all{{ I.id }}">{{ I.sName }}</a>{% endfor %}. База «Окнардии» размещено {{ NUM_TOTAL_OFFER_N_WORD }} цен для окон в такой проем (из них в архиве {{ NUM_ARCHIVE_OFFER }}). Предложено {{ NUM_FLAP_VARIATION_IN_WORD }} открывания от {{ NUM_TOTAL_FIRM_N_WORD }}.</p>
</div>
{# Микроразмектка: названеи продукта #}<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})" />
</div>
<div class="row ShowBigFlapPictures">
<div class="col-sm-7 col-xs-12 ">{% include 'report/show_big_flap_pictures.html' %}</div>
<div class="col-sm-2 col-xs-7 ap_list">
<h6>Наиболее частые предложения схем открывания:</h6>
<ul>{% for I in LIST_FLAP_VARIATION %}
{% if not I.IMG_MINI == '' %}<li><img src="{% static I.IMG_MINI %}" alt="Схема открывания {{ I.sOfferFlapConfig }}" title="Схема открывания {{ I.sOfferFlapConfig }} — {{ I.id }} шт." vspace="2" /> — {{ I.STR_NUM }}</li>{% endif %}{% endfor %}
</ul>
<div id="donutchart" style="width:100%;"></div>
</div>
<div class="col-sm-3 col-xs-5 ap_list">
<h6>Типовые серии домой, в которых встречается данный типовой проём:</h6>
<ul>{% for I in SERIA_FOR_WIN %}
<li><a href="/catalog/seria/{{ I.sNameLat }}/all{{ I.id }}">{{ I.sName }}</a>
<small>входит в {{ I.num_variation_of_apartment }}</small></li>
{% endfor %}</ul>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p id="tab-note">В таблице представлены только цены поставщиков из базы «Окнардия». Клик на&nbsp;названии набора отобразит детальную спецификацию каждого предложения: профиль рамы и&nbsp;створки, схему стеклопакета, фурнитуру, элементы отлива, подоконника, откоса, системы <nobr>климат-контроля</nobr>) и&nbsp;сопутствующие услуги. Предложения выводятся блоками. Очередной блок выводится кнопкой &laquo;Ещё коммерческие предложения окон&raquo; под таблицей. Детальные технические характеристики стеклопакетов, профилей и&nbsp;описание сопутствующих услуг можно посмотреть и сравнить с&nbsp;помощью кнопки &laquo;Сравнить выбранные&raquo;.</p>
</div>
{# Микроразмектка: названеи продукта #}
<meta itemprop="name" content="Окна {{ APART|safe }} ({{ ADDRESS }})"/>
</div>
<form class="row" method="get" action="\" id="compare_offers"><div class="col-md-12">
{% csrf_token %}
<table class=" table" id="price-list">
<thead>
<tr>
<th><b class="glyphicon glyphicon-th-list" title="Добавление набора окон в список сравнения" aria-label="Добавление набора окон в список сравнения"></b></th>
<th>Поставщик окон и название набора<small><br />
кликните чтобы отобразить описание и характеристики предложения</small>
</th>
<th>Схема<small><br />
открывания</small></th>
<!-- th>Цена,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
одно окно</small></th>
<th>N</th>
<th colspan="2" class="hidden-xs hidden-sm">Cумма,<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
однотипные окна</small></th -->
<th style="text-align:right;">Стоимость,&nbsp;<b class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></b><small><br />
окна для типового проёма</small></th>
<th style="text-align:center;">Скидка</th>
<th>Итого<small><br />
за типовое окно с учётом скидки</small></th>
</tr>
</thead>
<tbody id="offers">
{% include "price/price_offers_for_one_window_frame.html" %}
</tbody>
</table></div>
</form></span><p id="shadow_buffer"></p>
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
{# модальное окно #}
<div class="modal fade bs-example-modal-sm" id="modal-exclamation" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="mySmallModalLabel">Внимание:</h4>
</div>
<div class="modal-body">
<p>Извините, для сравнения коммерческих предложений окон нужно выбрать не менее двух и не более шести позиций.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Спасибо, все понятно.</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}
@@ -0,0 +1,141 @@
{% load static %}{% load filters %}{% for CurOffer in PRICE_FRAME %}
<tr>
<td colspan="7" style="font-size:xx-small;border-top:double black;border-bottom: solid 1px white;padding: 0;"></td>
</tr>{% for CurInOffer in CurOffer.DIM %}
<tr>
{% if forloop.first %}
<th rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}" title="Добавить коммерческое предложение окна к сравнению">{# красивые чекбоксы BEGIN #}<div class="checkbox"><label><input id="CHK{{ CurOffer.SETS_ID }}" type="checkbox" name="ForCompare" value="{{ CurOffer.SETS_ID }}" onChange="ChangeCountCheckedBox({{ CurOffer.SETS_ID }});" /><span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span></label></div>{# красивые чекбоксы END #}</th>
<td rowspan="{% if CurOffer.DIM|length == 1 %}2{% else %}{{ CurOffer.DIM|length }}{% endif %}"{% if CurOffer.IS_COMMERCIAL %} style="background-image: url(/media/{{ CurOffer.MERCHANT_LOGO }})"{% endif %} title="Краткая спецификация коммерческого предложения">
<span itemprop="description">
<h3 class="set-name shake-trigger" id="btn{{ CurOffer.SETS_ID }}"><a href="javascript://" onclick="show_dtl({{ CurOffer.SETS_ID }})">{{ CurOffer.MERCHANT }}  {{ CurOffer.SETS_NAME }}<i class="glyphicon glyphicon-chevron-down shake-vertical"></i></a></h3>
<DiV id="dtl{{ CurOffer.SETS_ID }}" class="collapse">■ Профиль: <a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_NAME_T }}">{{ CurOffer.PVC_NAME|safe }}</a> (<a href="/catalog/profile/{{ CurOffer.PVC_ID }}-{{ CurOffer.PVC_MANUFACTURER_T }}">{{ CurOffer.PVC_MANUFACTURER }}</a>)
&nbsp;{{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
&nbsp;Тонирование:&nbsp;{{ CurOffer.GLAZING_TONING }}
{% if CurOffer.PVC_SEAL %}■&nbsp;Уплотнитель:&nbsp;{{ CurOffer.PVC_SEAL }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT %}■&nbsp;Фурнитура:&nbsp;{{ CurOffer.SETS_IMPLEMENT|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_R %}■&nbsp;Ручки:&nbsp;{{ CurOffer.SETS_IMPLEMENT_R|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_P %}■&nbsp;Петли:&nbsp;{{ CurOffer.SETS_IMPLEMENT_P|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_Z %}■&nbsp;Запоры:&nbsp;{{ CurOffer.SETS_IMPLEMENT_Z|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_O %}■&nbsp;Ограничители:&nbsp;{{ CurOffer.SETS_IMPLEMENT_O|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_IMPLEMENT_F %}■&nbsp;Фиксаторы:&nbsp;{{ CurOffer.SETS_IMPLEMENT_F|capfirst|safe }}
{% endif %}{% if CurOffer.SETS_CLIMATE_CONTROL %}<span {% if CurOffer.SETS_CLIMATE_CONTROL|capfirst != "Нет" or CurOffer.SETS_CLIMATE_CONTROL|length > 3 %}class="bullet-green"{% endif %}>■&nbsp;Климат-контроль:&nbsp;{{ CurOffer.SETS_CLIMATE_CONTROL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SILL %}<span {% if CurOffer.SETS_SILL|capfirst == "Нет" or CurOffer.SETS_SILL|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Подоконник:&nbsp;{{ CurOffer.SETS_SILL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_SLOPE %}<span {% if CurOffer.SETS_SLOPE|capfirst == "Нет" or CurOffer.SETS_SLOPE|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Откос:&nbsp;{{ CurOffer.SETS_SLOPE|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_PANES %}<span {% if CurOffer.SETS_PANES|capfirst == "Нет" or CurOffer.SETS_PANES|length < 3 %}class="bullet-red"{% endif %}>&nbsp;Водоотлив:&nbsp;{{ CurOffer.SETS_PANES|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_UNINSTALL_INSTALL %}<span {% if CurOffer.SETS_UNINSTALL_INSTALL_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Демонтаж/монтаж:&nbsp;{{ CurOffer.SETS_UNINSTALL_INSTALL|capfirst|safe }}</span>
{% endif %}{% if CurOffer.SETS_DELIVERY %}<span {% if CurOffer.SETS_DELIVERY_B %}class="bullet-green"{% else %}class="bullet-red"{% endif %}>&nbsp;Доставка:&nbsp;{{ CurOffer.SETS_DELIVERY|capfirst|safe }}</span>{% endif %}{% comment %} {% if CurOffer.SETS_OTHER %}■&nbsp;Прочие условия:&nbsp;{{ CurOffer.SETS_OTHER|capfirst|safe }}
{% endif %}{% endcomment %}
</DiV>
<!-- Дата обновления -->
<nobr class="badge badge4price" title="Дата обновления коммерческого предложения окон — {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}"><b class="glyphicon glyphicon-calendar"></b> {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }}</nobr>
<!-- Звездочки рейтинга -->
<nobr class="badge badge4price" title="Рейтинг «Окнардии»{% if CurOffer.SETS_RATING > -0.1 %} — {{ CurOffer.SETS_RATING|stringformat:".2f" }} баллов{% endif %}"><a
href="javascript://"
id-set="{{ CurOffer.SETS_ID }}"
data-trigger="focus" tabindex="0"
title="{% if CurOffer.SETS_RATING > 0.01 %}<b> Рейтинг {{ CurOffer.SETS_RATING|stringformat:".2f" }}</b> для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит&nbsp;из:{% else %}Рейтинг не присвоен{% endif %}"
data-toggle="popover">рейтинг</a>:&nbsp;{% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}<b class="glyphicon glyphicon-star-empty"></b>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %} {{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %}</nobr>
</span>
<span itemprop="brand" itemscope itemtype="http://schema.org/Brand">
<meta itemprop="name" content="{{ CurOffer.MERCHANT }}" />
<meta itemprop="logo" content="https://oknardia.ru/media/{{ CurOffer.MERCHANT_LOGO }}" />
</span></td>
<!--- Конец большой ячейки со спецификацией оконного предложения --->
{% endif %}
<td class="rnw" title="Схема открывания окна или двери {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм."><img src="{% static CurInOffer.IMG_MINI %}" alt="Схема открывания: {{ CurInOffer.DESCRIPTION }} — {{ CurInOffer.WIDTH|stringformat:".0f" }}0x{{ CurInOffer.HIGHT|stringformat:".0f" }}0 мм." /></td>
{% if forloop.first %}<!-- FIRST -->
<td class="rnw" title="Стоимость {{ CurOffer.TOTAL|stringformat:".2f" }} рублей за все окна квартиры {{ APART|safe }}.">{{ CurOffer.TOTAL|stringformat:".2f"|price_format }}</td>
<th{% if CurOffer.DISCOUNT_COLOR2 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR2 }};"{% endif %} title="{% if CurOffer.DISCOUNT < 0.1 %}Нет скидки{% else %}Скидка — {{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}">{% if CurOffer.DISCOUNT < 0.1 %}{% else %}&minus;{{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %}</th>
<th{% if CurOffer.DISCOUNT_COLOR1 != "" %} style="background-color:{{ CurOffer.DISCOUNT_COLOR1 }};"{% endif %} itemprop="offers" itemscope itemtype="http://schema.org/Offer" title="Итого за все окна с учетом скидки: {{ CurOffer.FIN_PRICE|stringformat:".2f" }} рублей">
Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }}&thinsp;<small class="glyphicon glyphicon-ruble" aria-label="₽ (руб.)" title="₽ (руб.)"></small>
<meta itemprop="price" content="{{ CurOffer.FIN_PRICE }}" />
<meta itemprop="priceCurrency" content="RUB" />
</th>
{% if CurOffer.DIM|length == 1 %}
</tr><tr>
<td colspan="2">&nbsp;</td>
<td colspan="3">
{% endif %}
{% elif forloop.counter0 == 1 %}
<td colspan="3" rowspan="{{ CurOffer.DIM|length|add:"-1" }}">
{% endif %}
{% if forloop.counter0 == 1 or CurOffer.DIM|length == 1 %}
<stong>{{ CurOffer.OFFICE_NAME }}</stong><br />
<div id="hid{{ CurOffer.SETS_ID }}" class="collapse in">
<a class="btn btn-info btn-xs shake-trigger" data-toggle="collapse" data-target="#tel{{ CurOffer.SETS_ID }}" onclick="show_phone_num({{ CurOffer.SETS_ID }})"><b class="glyphicon glyphicon-phone-alt shake-vertical"></b> Показать телефон</a>
</div>
<div id="tel{{ CurOffer.SETS_ID }}" class="collapse">
<small>{{ CurOffer.OFFICE_ADDRESS }}</small><br /> <b class="glyphicon glyphicon-phone-alt"></b> {{ CurOffer.OFFICE_PHONES }}<br />
<small><nobr>Пожалуйста, скажите, что нашли цены на oknardia.ru</nobr></small>
</div>
</td>
{% endif %}
</tr>{% endfor %}<!----- ПРОВЕРКА --->{% endfor %}
<Tr id="preloader_{{ N }}">
<tH colspan="7"><center><img src="{% static "img/preloader.gif" %}" alt="подгружаю цены на окна..." height="64" width="64" /></center></tH>
</Tr>
<tR id="load_and_banner_{{ N }}">
<!-- сюда подгружаем следующий фрейм прайслиста --->
<script type="application/javascript">
function get_next_pricelist_frame( ) {
try{yaCounter32997984.reachGoal("MoreOffer");}catch(e){}
// заменяем ряд с кнопочками кнопочками на рекламу
// $("#load_and_banner_{{ N }}").html("<th colspan=10>РЕКЛАМА TMP</th>");
// добавляем ячейки с дополнительными ценами и новые кнопочки
$("#load_and_banner_{{ N }}").css({"display":"none"});
$("#preloader_{{ N }}").css({"display":"table-row","transition":"1s"});// подсчитать сколько прочеканных оферов для сравнения
$("#tmp").load(
"/next_price_one_flap_frame/idW{{ WIN_ID }}N{{ N }}",
function (){
window.frame = $("#tmp").html();
$("#price-list > tbody").append(window.frame);
}
);
window.setTimeout(
function show_adv() {
$("#load_and_banner_{{ N }}").html("<td colspan='8' bgcolor='#CCCCCC' align='center'><center><a href='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/link?partner=e-serg&&utm_content=banner&width=728&height=90' target='_blank'><img src='https://api.ozon.ru/partner-tools.affiliates/pankarta/11052421746600/image?partner=e-serg&utm_content=banner&width=728&height=90' width='728px' height='90px'></a><small><br/>↑ Здесь могла бы быть ваша реклама ↑</small></center></td>");
$("#load_and_banner_{{ N }}").css({"display":"table-row","transition":"all 5s"});
$("#preloader_{{ N }}").css({"display":"none","transition":"1s"});
// (adsbygoogle=window.adsbygoogle || []).push({});
window.count = 0;
for (var i=0; i < ForCompare.length; i++)
if (ForCompare[i].checked)
window.count++;
$("#NumberOfSelected").html(window.count);
$('[data-toggle="popover"]').popover({ // реинициализировать подгружаемые поповеры
placement: "top",
html: true,
content: function () {
// сохранить текущий контекст
var _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id-set"),
function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
});
},
2800);
}
</script>
<td colspan="2"><a class="btn btn-info btn-block" data-toggle="collapse" onclick="Click2CompareOffers();">Сравнить выбранные (<span id="NumberOfSelected">0</span>) <small class="glyphicon-stats glyphicon"></small></a><p id="tmp"></p></td>
<td colspan="5">{% if N != "-1" %}<a href="javascript://" class="btn btn-info btn-block" onclick="get_next_pricelist_frame();">Ещё коммерческие предложения окон &nbsp;<small class="glyphicon-refresh glyphicon"></small></a>{% endif %}</td>
</tR>
+83
View File
@@ -0,0 +1,83 @@
<!--- Информация о строении --->{% load filters %}
<table id="collapse_it" class="table table-condensed collapse">
<tbody>{% if ADDRESS %}
<tr>
<td colspan="8" style="background:whitesmoke;border-top:double;">Дом по адресу: <strong>{{ ADDRESS }}</strong></td>
</tr>{% endif %}<tr>
<td>Проект:</td>
<td>{{ SERIA|safe }}</td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td>Площадь участка, м²:</td>
<td><nobr>{{ LAND|capfirst|default:"Нет данных"|price_format }}</nobr></td>
<td>&nbsp;&nbsp;&nbsp;</td>
<td>Кадастровый номер участка:</td>
<td><nobr>{{ CADASTRE_NUM|capfirst }}</nobr></td>
</tr><tr>
<td>Типовая серия:</td>
<td><nobr>{{ SERIA_BASE|safe|default:"Нет данных" }}</nobr></td>
<td></td>
<td>Общаяя площадь помещений, м²:</td>
<td><nobr>{{ TOTAL_AREA|capfirst|default:"Нет данных"|price_format }}</nobr></td>
<td></td>
<td>Инвентарный номер:</td>
<td><nobr>{{ INVENTORY_NUM|capfirst|default:"Нет данных" }}</nobr></td>
</tr><tr>
<td>Число квартир:</td>
<td><nobr>{{ NUM_APARTMENTS|capfirst|default:"Нет данных" }}</nobr></td>
<td></td>
<td colspan="2">из них:</td>
<td></td>
<td>Тип здания:</td>
<td><nobr>{{ TYPE_BUILDING|capfirst|default:"Нет данных" }}</nobr></td>
</tr><tr>
<td>Этажей:</td>
<td>{{ STOREYS|capfirst|default:"Нет данных" }}</td>
<td></td>
<td><nobr>• помещений общего пользования, м²:</nobr></td>
<td><nobr>{{ COMMON_AREA|default:"Нет данных"|price_format }}</nobr></td>
<td></td>
<td>Класс энергоэффективности:</td>
<td><nobr>{{ ENERGY_EFFICIENCY|capfirst|default:"Нет данных" }}</nobr></td>
</tr><tr>
<td>Подъездов:</td>
<td>{{ NUM_ENTERANCES|capfirst|default:"Нет данных" }}</td>
<td></td>
<td>• нежилых помещений, м²:</td>
<td><nobr>{{ UNINHABITED_AREA|capfirst|default:"Нет данных"|price_format }}</nobr></td>
<td></td>
<td>Число счетов:</td>
<td>{{ NUM_ACCOUNTS|capfirst|default:"Нет данных"|price_format }}</td>
</tr><tr>
<td>Лифтов:</td>
<td>{{ NUM_ELEVATORS|capfirst|default:"Нет данных" }}</td>
<td></td>
<td>• жилых помещений, м²:</td>
<td>{{ RESIDENTIAL_AREA|capfirst|default:"Нет данных"|price_format }}</td>
<td></td>
<td>Число жителей:</td>
<td>{{ NUM_RESIDENTS|capfirst|default:"Нет данных"|price_format }}</td>
</tr><tr>
<td><nobr>Грузовых лифтов:</nobr></td>
<td><nobr>Нет данных</nobr></td>
<td></td>
<td>• приватизированных помещений, м²:</td>
<td><nobr>{{ PRIVATE_AREA|capfirst|default:"Нет данных"|price_format }}</nobr></td>
<td></td>
<td rowspan="3">Управляющая компания:</td>
<td rowspan="3">{{ MANAGEMENT_CO|safe|default:"Нет данных" }}</td>
</tr><tr>
<td>Год постройки:</td>
<td>{{ COMMISSIONING_YEAR|capfirst|default:"Нет данных" }}</td>
<td></td>
<td>• государственных помещений, м²:</td>
<td><nobr>{{ GOVERNMENT_AREA|capfirst|default:"Нет данных"|price_format }}</nobr></td>
<td rowspan="2" style="border-top:none;"></td>
</tr><tr>
<td>Cтепень износа:</td>
<td title="Износ фундамента: {{ CONDITION_FOUNDATION|capfirst|default:"" }} // Износ несущих конструкций: {{ CONDITION_WALL|capfirst|default:"" }} // Износ перекрытий: {{ CONDITION_OVERLAP|capfirst|default:"" }}">{{ CONDITION_HOUSE|capfirst|default:"Нет данных" }}</td>
<td></td>
<td>• мунициальных помещений, м²:</td>
<td><nobr>{{ MUNICIPAL_AREA|capfirst|default:"Нет данных"|price_format }}</nobr></td>
</tr>
</tbody>
</table>
+265
View File
@@ -0,0 +1,265 @@
{% extends "base.html" %}
{% load static %}
{% load filters %}
{% block Title %} Сравнение характеристик оконных профилей: {% for PROFILE in LIST_PROFILE %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ PROFILE }}{% endfor %}. Сравнение характеристик стеклопакетов: {% for GLAZING in LIST_GLAZING %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ GLAZING }}{% endfor %}. Сравнение предложений окон: {% for MERCANT in LIST_MERCHANT %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ MERCANT }}{% endfor %}.{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Description %}Сравнение характеристик окон от поставщиков: {% for MERCANT in LIST_MERCHANT %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ MERCANT }}{% endfor %}. Сравнение профилей пластиковых окон: {% for PROFILE in LIST_PROFILE %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ PROFILE }}{% endfor %}. Сравнение характеристик стеклопакетов: {% for GLAZING in LIST_GLAZING %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ GLAZING }}{% endfor %}.{% endblock %}
{% block Keywords %}сравнение профилей пластиковых окон, {% for PROFILE in LIST_PROFILE %}{{ PROFILE }}, {% endfor %}сравнение стеклопакетов, {% for GLAZING in LIST_GLAZING %}{{ GLAZING }}, {% endfor %}сравнение поставщиков пластиковых окон, {% for MERCANT in LIST_MERCHANT %}{{ MERCANT }}, {% endfor %}характеристики пластиковых окон.{% endblock %}
{% block Top_JS3%}<script type="text/javascript">
$(function () {
$('[data-toggle="popover"]').popover({
placement: "bottom",
html: true,
content: function () {
// сохранить текущий контекст
let _this = this;
$('#shadow_buffer').load('/show_rating_components/' + $(_this).attr("id"), function (response, status, xhr) {
if (status == "error")
$(_this).attr({'data-content': "Ошибка " + xhr.status + " (" + xhr.statusText + ")"});
else
$(_this).attr({'data-content': response});
$(_this).popover('show');
try{yaCounter32997984.reachGoal("ShowRating");}catch(e){};
});
}
})
})
</script>{% endblock %}
{% block Top_CSS1 %}{% endblock %}
{% block Main_Content %}<!--- ------------------------------------------------------------------------------------------------------------------------- --->
<div class="row col-xs-12">
<div class="col-md-9 col-xs-8">
<h1>Сравнении оконных наборов:{% for Count in SET_LIST %}{% if forloop.first %} {% else %}{% if forloop.last %} и&nbsp;{% else %}, {% endif %}{% endif %}{{ Count.SET_NAME }}{% if forloop.last %}.{% endif %}{% endfor %}</h1>
<p>Оконный набор&nbsp;&mdash; это комплект оконного профиля (рамы и&nbsp;сворки), стеклопакета, фурнитуры и&nbsp;уплотнителей&nbsp;&mdash; готовое окно в&nbsp;сборе для установки в&nbsp;проём. В&nbsp;набор может входить отлив, подоконник, откос, встраиваемые системы <nobr>климат-контроля</nobr>, оконная фурнитура открывания, запоры, уплотнители, москитная сетка&hellip; а&nbsp;также сопутствующие услуги: демонтаж старых и&nbsp;установка новых окон, доставка, гарантийное обслуживание, уборка, вынос и&nbsp;утилизация строительного мусора, защитное укрытие мебели на&nbsp;время монтажа и&nbsp;другое.</p>
<h4>В&nbsp;таблицу сравнения услуг и&nbsp;условий, входящих в&nbsp;оконные наборы, добавлены следующие производители и&nbsp;поставщики:</h4>
<ul>{% for MERCANT in LIST_MERCHANT %}
<li>{{ MERCANT }}.</li>{% endfor %}
</ul>
<h4>В&nbsp;средней части таблице вы&nbsp;сможете сравнить характеристики оконных профилей в&nbsp;наборах:</h4>
<ul>{% for PROFILE in LIST_PROFILE %}
<li>{{ PROFILE }}.</li>{% endfor %}
</ul>
<h4>Нижний блок таблицы посвящен характеристикам и&nbsp;сравнению стеклопакетов в&nbsp;наборах. Формулы выбранных стеклопакетов:</h4>
<ul>{% for GLAZING in LIST_GLAZING %}
<li>{{ GLAZING }}.</li>{% endfor %}
</ul>
</div>
{# реклама Oknardia 250x250 СБОКУ #}<div class="col-md-2 col-xs-3 float-right">{% include "ad/bannet-250x250.html" %}</div>
</div>
<div class="raw" style="padding: 1em 0;">
<div class="col-sm-12">
<table class="table col-md-12 table-condensed" id="compare_table">
<thead>
<tr style="background:white;">
<th class="col-sm-2">Поставщик:<br /><small style="font-size:small;font-weight:100;">компания, предлагающая установку окон</small></th>{% for Count in SET_LIST %}
<th class="col-xs-1" title="Установку окон предлагает компания «{{ Count.MERCHANT }}»"><h2 style="font-size:1em;margin:0;font-weight:bold;">{{ Count.MERCHANT }}</h2><br />
<img src="http://oknardia.ru/media/{{ Count.MERCHANT_LOGO }}" style="height: 25px;width:auto;" alt="{{ Count.MERCHANT }}"><br />
<div class="url"><nobr>{% if Count.IS_COMMERCIAL %}<a href="{{ Count.MERCHANT_URL }}" target="_blank" rel="nofollow">{{ Count.MERCHANT_URL_SHOT|truncatechars:30 }}</a>{% else %}{{ Count.MERCHANT_URL_SHOT|truncatechars:30 }}{% endif %}</nobr><br /><a href="/catalog/company/{{ Count.MERCHANT_ID }}-{{ Count.MERCHANT_T }}/">в&nbsp;каталоге</a></div>
</th>{% endfor %}
</tr><tr>
<th>Название набора:</th>{% for Count in SET_LIST %}
<th title="Название оконного набора: «{{ Count.SET_NAME }}»">{{ Count.SET_NAME|truncatechars:25 }}</th>{% endfor %}
</tr><tr class="rating">
<th><nobr>Рейтиг «Окнардии»:</nobr></th>{% for Count in SET_LIST %}
<td{% if Count.RATING_SET_COLOR != "" %} style="background:{{ Count.RATING_SET_COLOR }};"{% endif %}>
<nobr title="Рейтинг «Окнардии» для окон набора «{{ Count.SET_NAME }}» компании «{{ Count.MERCHANT }}» — {% if Count.RATING_SET_N > 0.1 %}{{ Count.RATING_SET_N|stringformat:".2f" }}{% else %}не присвоен{% endif %}"><!-- НАЧАЛО звездочки рейтинга -->{% for Star in Count.RATING_SET %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if Count.RATING_SET_N > 0.1 %}<tt class="badge">{{ Count.RATING_SET_N|stringformat:".2f" }}</tt>{% endif %}<!-- КОНЕЦ бедж --> <a
href="javascript://"
id="{{ Count.SET_ID }}"
title="{% if Count.RATING_SET_N > 0.01 %}<b> Рейтинг {{ Count.RATING_SET_N|stringformat:".2f" }}</b> для оконого набора «{{ Count.SET_NAME }}» компании «{{ Count.MERCHANT }}» состоит&nbsp;из:{% else %}Рейтинг не присвоен{% endif %}"
data-toggle="popover">детали</a></nobr></td>{% endfor %}
</tr>
</thead>
<tbody>
<tr>
<th>Фурнитура:</th>{% for Count in SET_LIST %}
<td title="Оконнaя фурнитура и установочные изделия: {{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}">{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th><sup></sup>Ручки:</th>{% for Count in SET_LIST %}
<td title="Фурнитура оконных ручек: {% if Count.SET_IMPLEMENTS_HANDLES == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_HANDLES|capfirst|safe }}{% endif %}">{% if Count.SET_IMPLEMENTS_HANDLES == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_HANDLES|capfirst|safe }}{% endif %}</td>{% endfor %}
</tr><tr>
<th><sup></sup>Петли:</th>{% for Count in SET_LIST %}
<td title="Фурнитура оконных петель: {% if Count.SET_IMPLEMENTS_HINGES == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_HINGES|capfirst|safe }}{% endif %}">{% if Count.SET_IMPLEMENTS_HINGES == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_HINGES|capfirst|safe }}{% endif %}</td>{% endfor %}
</tr><tr>
<th><sup></sup>Механизмы запирания:</th>{% for Count in SET_LIST %}
<td title="Фурнитура механизма закрывания окна: {% if Count.SET_IMPLEMENTS_LATCH == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_LATCH|capfirst|safe }}{% endif %}">{% if Count.SET_IMPLEMENTS_LATCH == "" %}{{ Count.SET_IMPLEMENTS_ALL|capfirst|safe }}{% else %}{{ Count.SET_IMPLEMENTS_LATCH|capfirst|safe }}{% endif %}</td>{% endfor %}
</tr><tr>
<th><sup></sup>Ограничители:</th>{% for Count in SET_LIST %}
<td{% if not Count.SET_IMPLEMENTS_LIMITER == "" %} title="Фурнитура ораничителей открывания окна: {{ Count.SET_IMPLEMENTS_LIMITER|capfirst|safe }}"{% endif %}>{% if Count.SET_IMPLEMENTS_LIMITER == "" %}—{% else %}{{ Count.SET_IMPLEMENTS_LIMITER|capfirst|safe }}{% endif %}</td>{% endfor %}
</tr><tr>
<th><sup></sup>Фиксаторы открывания:</th>{% for Count in SET_LIST %}
<td{% if not Count.SET_IMPLEMENTS_CATCH == "" %} title="Фурнитура фиксатора открывания окна: {{ Count.SET_IMPLEMENTS_CATCH|capfirst|safe }}"{% endif %}>{% if Count.SET_IMPLEMENTS_CATCH == "" %}—{% else %}{{ Count.SET_IMPLEMENTS_CATCH|capfirst|safe }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Климат-контроль:</th>{% for Count in SET_LIST %}
<td{% if Count.SET_CLIMATE_CONTROL|length > 3 %} style="background:#7fff7f;"{% endif %} title="Оконная система климат-контроля: {{ Count.SET_CLIMATE_CONTROL|capfirst|safe }}">{{ Count.SET_CLIMATE_CONTROL|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Подоконники:</th>{% for Count in SET_LIST %}
<td{% if Count.SET_STILL|capfirst == "Нет" or Count.SET_STILL|length < 4 %} style="background:#ff7f7f;"{% endif %} title="Подоконники: {{ Count.SET_STILL|capfirst|safe }}">{{ Count.SET_STILL|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Водоотливы:</th>{% for Count in SET_LIST %}
<td{% if Count.SET_PANES|capfirst == "Нет" or Count.SET_PANES|length < 4 %} style="background:#ff7f7f;"{% endif %} title="Водоотливы: {{ Count.SET_PANES|capfirst|safe }}">{{ Count.SET_PANES|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Откосы:</th>{% for Count in SET_LIST %}
<td{% if Count.SET_SLOPE|capfirst == "Нет" or Count.SET_SLOPE|length < 4 %} style="background:#ff7f7f;"{% endif %} title="Откосы: {{ Count.SET_SLOPE|capfirst|safe }}">{{ Count.SET_SLOPE|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Доставка:</th>{% for Count in SET_LIST %}
<td style="background:{% if Count.SET_DELIVERY_B %}#7fff7f{% else %}#ff7f7f{% endif %};" title="Условия доставки окон: {{ Count.SET_DELIVERY|capfirst }}">{{ Count.SET_DELIVERY|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Демонтаж/Монтаж:</th>{% for Count in SET_LIST %}
<td style="background:{% if Count.SET_UNINSTALL_INSTALL_B %}#7fff7f{% else %}#ff7f7f{% endif %};" title="Демонтаж старых и монтаж новых окон: {{ Count.SET_UNINSTALL_INSTALL|capfirst|safe }}">{{ Count.SET_UNINSTALL_INSTALL|capfirst|safe }}</td>{% endfor %}
</tr><tr>
<th>Прочие условия:</th>{% for Count in SET_LIST %}
<td{% if not Count.SET_OTHER_CONDITIONS == "" %} title="Прочие условия окон набора «{{ Count.SET_NAME }}» от компании «{{ Count.MERCHANT }}»: {{ Count.SET_OTHER_CONDITIONS|capfirst|safe }}"{% endif %}><small>{{ Count.SET_OTHER_CONDITIONS|capfirst|safe }}</small></td>{% endfor %}
</tr>
</tbody>
<thead>
<tr>
<th class="centre" colspan="{{ SET_LIST|length|add:"1" }}">{% include "ad/bannet-wide.html" %}</th>
</tr><tr>
<th class="centre" colspan="{{ SET_LIST|length|add:"1" }}">Профиль, используемый в наборе</th>
</tr>
</thead>
<tbody>
<tr>
<th>Название профиля:</th>{% for Count in SET_LIST %}
<th><h3 style="font-size:1em;margin:0;" title="Название оконного профиля (модель): {{ Count.PROFILE_NAME|capfirst|safe }}"><a href="/catalog/profile/{{ Count.PROFILE_ID }}-{{ Count.PROFILE_MANUFACTURER_T }}/{{ Count.PROFILE_ID }}-{{ Count.PROFILE_NAME_T }}/">{{ Count.PROFILE_NAME|capfirst|safe }}</a></h3></th>{% endfor %}
</tr><tr>
<th>Производитель профиля:</th>{% for Count in SET_LIST %}
<td title="Производитель оконного профилы: {{ Count.PROFILE_MANUFACTURER|capfirst|safe }}"><a href="/catalog/profile/{{ Count.PROFILE_ID }}-{{ Count.PROFILE_MANUFACTURER_T }}/">{{ Count.PROFILE_MANUFACTURER|capfirst|safe }}</a></td>{% endfor %}
</tr><tr>
<th>Цвет:</th>{% for Count in SET_LIST %}
<td{% if not Count.PROFILE_NUM_COLOR == "" %} title="Цвет оконного профиля: {{ Count.PROFILE_NUM_COLOR|capfirst }}"{% endif %}>{% if Count.PROFILE_NUM_COLOR == "" %}—{% else %}{{ Count.PROFILE_NUM_COLOR|capfirst }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Число камер рамы/створки (<i>шт.</i>):</th>{% for Count in SET_LIST %}
<td{% if not Count.PROFILE_NUM_CAMERAS_COLOR == "" %} style="background:{{ Count.PROFILE_NUM_CAMERAS_COLOR }};"{% endif %}{% if Count.PROFILE_NUM_CAMERAS != "" %} title="Число камер профиля оконной рамы/створки: {{ Count.PROFILE_NUM_CAMERAS }} шт."{% endif %}>{{ Count.PROFILE_NUM_CAMERAS }}</td>{% endfor %}
</tr><tr>
<th>Контуров уплотненения (<i>шт.</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_NUM_SEALS_COLOR != "" %} style="background:{{ Count.PROFILE_NUM_SEALS_COLOR }};"{% endif %}{% if Count.PROFILE_NUM_SEALS > 0 %} title="Число контуров уплотнения створки к раме: {{ Count.PROFILE_NUM_SEALS }} шт."{% endif %}>{% if Count.PROFILE_NUM_SEALS > 0 %}{{ Count.PROFILE_NUM_SEALS }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Монтажная ширина профиля (<i>мм</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_THICKNESS_COLOR != "" %} style="background:{{ Count.PROFILE_THICKNESS_COLOR }};"{% endif %}{% if Count.PROFILE_THICKNESS > 5 %} title="Монтажная ширина оконного профиля: {{ Count.PROFILE_THICKNESS }} мм."{% endif %}>{% if Count.PROFILE_THICKNESS > 5 %}{{ Count.PROFILE_THICKNESS }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Максимальная толщина стеклопакета (<i>мм</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_GLAZING_THICKNESS_COLOR != "" %} style="background:{{ Count.PROFILE_GLAZING_THICKNESS_COLOR }};"{% endif %}{% if Count.PROFILE_GLAZING_THICKNESS > 4 %} title="Максимальная толщина стеклопакета для уставноки с створку: {{ Count.PROFILE_GLAZING_THICKNESS }} мм"{% endif %}>{% if Count.PROFILE_GLAZING_THICKNESS > 4 %}{{ Count.PROFILE_GLAZING_THICKNESS }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Сопротивление теплопередаче <nobr><i>Ro</i> (<i>м²×°C/Вт</i>):</nobr></th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_HEAT_TRANSFER_COLOR != "" %} style="background:{{ Count.PROFILE_HEAT_TRANSFER_COLOR }};"{% endif %}{% if Count.PROFILE_HEAT_TRANSFER > 0.1 %} title="Сопротивление теплопередаче (Ro) оконного профиля: {{ Count.PROFILE_HEAT_TRANSFER|stringformat:".2f" }} м²×°C/Вт"{% endif %}>{% if Count.PROFILE_HEAT_TRANSFER > 0.1 %}{{ Count.PROFILE_HEAT_TRANSFER|stringformat:".2f" }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент звукоизоляции, (<i>дБ</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_SOUND_PROOFING_COLOR != "" %} style="background:{{ Count.PROFILE_SOUND_PROOFING_COLOR }};"{% endif %}{% if Count.PROFILE_SOUND_PROOFING > 1 %} title="Коэффициент звукоизоляции оконного профиля: {{ Count.PROFILE_SOUND_PROOFING|stringformat:".1f" }} дБ"{% endif %}>{% if Count.PROFILE_SOUND_PROOFING > 1 %}{{ Count.PROFILE_SOUND_PROOFING|stringformat:".1f" }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Высота в световом проеме, рама+створка (<i>мм</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_HEIGHT_COLOR != "" %} style="background:{{ Count.PROFILE_HEIGHT_COLOR }};"{% endif %}{% if Count.PROFILE_HEIGHT > 15 %} title="Высота в световом проеме, рама+створка: {{ Count.PROFILE_HEIGHT }} мм"{% endif %}>{% if Count.PROFILE_HEIGHT > 15 %}{{ Count.PROFILE_HEIGHT }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Фальц рамы (<i>мм</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_RABBET_COLOR != "" %} style="background:{{ Count.PROFILE_RABBET_COLOR }};"{% endif %}{% if Count.PROFILE_RABBET > 1 %} title="Высота фальца рамы: {{ Count.PROFILE_RABBET }} мм"{% endif %}>{% if Count.PROFILE_RABBET > 1 %}{{ Count.PROFILE_RABBET }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Армирование профиля:</th>{% for Count in SET_LIST %}
<td title="Армирование или другие особенности профиля: {{ Count.PROFILE_REINFORCEMENT }}">{{ Count.PROFILE_REINFORCEMENT }}</td>{% endfor %}
</tr><tr>
<th>Штапик:</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_FILLET != "" %} title="Характеристики штапика: {{ Count.PROFILE_FILLET }}"{% endif %}>{% if Count.PROFILE_FILLET != "" %}{{ Count.PROFILE_FILLET }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Уплотнитель:</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_SEAL_DESCRIPTION != "" %} title="Хараектеристики уплотнитель стеклопакета и контуров рама-створка: {{ Count.PROFILE_SEAL_DESCRIPTION|lower }}"{% endif %}>{% if Count.PROFILE_SEAL_DESCRIPTION != "" %}{{ Count.PROFILE_SEAL_DESCRIPTION|capfirst }}{% else %}—{% endif %}</td>{% endfor %}
</tr><tr>
<th>Прочие характеристики:</th>{% for Count in SET_LIST %}
<td{% if Count.PROFILE_OTHER != "" %} title="Прочие характеристики рамы и створки: {{ Count.PROFILE_OTHER }}"{% endif %}><small>{% if Count.PROFILE_OTHER != "" %}{{ Count.PROFILE_OTHER }}{% else %}—{% endif %}</small></td>{% endfor %}
</tr>
</tbody>
<thead>
<tr>
<th class="centre" colspan="{{ SET_LIST|length|add:"1" }}">{% include "ad/bannet-wide.html" %}</th>
</tr><tr>
<th class="centre" colspan="{{ SET_LIST|length|add:"1" }}">Стеклопакет, используемый в наборе</th>
</tr>
</thead>
<tbody>
<tr>
<th>Краткое описание:</th>{% for Count in SET_LIST %}
<td title="Краткое описание стекопакета: {{ Count.GLAZING_BRIEF_DESCRIPTION|safe|lower }}"><h3 style="font-size:small;margin:0;">{{ Count.GLAZING_BRIEF_DESCRIPTION|safe|capfirst }}</h3></td>{% endfor %}
</tr><tr>
<th>Производитель стеклопакета:</th>{% for Count in SET_LIST %}
<td{% if not Count.GLAZING_MANUFACTURER == "//" %} title="Компания производитель стеклопакета: {{ Count.GLAZING_MANUFACTURER|capfirst }}"{% endif %}>{% if Count.GLAZING_MANUFACTURER == "—//—" %}—{% else %}{{ Count.GLAZING_MANUFACTURER|capfirst }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Схема стеклопакета:</th>{% for Count in SET_LIST %}
<td title="Схема стеклопакета: {{ Count.GLAZING_MARK }}">{{ Count.GLAZING_MARK }}</td>{% endfor %}
</tr><tr>
<th>Камер в стеклопакете:</th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_CAMERAS_COLOR != "" %} style="background:{{ Count.GLAZING_CAMERAS_COLOR }};"{% endif %}{% if not Count.GLAZING_CAMERAS_NUM < 1 %} title="Количество камер в стеклопакете: {{ Count.GLAZING_CAMERAS_NUM }}"{% endif %}>{% if Count.GLAZING_CAMERAS_NUM < 1 %}{% else %}{{ Count.GLAZING_CAMERAS_NUM }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Толщина стеклопакета <i>(мм)</i>:</th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_THICKNESS_COLOR != "" %} style="background:{{ Count.GLAZING_THICKNESS_COLOR }};"{% endif %}{% if not Count.GLAZING_THICKNESS < 3 %} title="Общая толщина стеклопакета: {{ Count.GLAZING_THICKNESS }} мм"{% endif %}>{% if Count.GLAZING_THICKNESS < 3 %}{% else %}{{ Count.GLAZING_THICKNESS }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Сопротивление теплопередаче <nobr><i>Ro</i> (<i>м²×°C/Вт</i>):</nobr></th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_HEAT_TRANSFER_COLOR != "" %} style="background:{{ Count.GLAZING_HEAT_TRANSFER_COLOR }};"{% endif %}{% if not Count.GLAZING_HEAT_TRANSFER < 0.1 %} title="Сопротивление теплопередаче (Ro) стеклопакета: {{ Count.GLAZING_HEAT_TRANSFER|stringformat:".2f" }} м²×°C/Вт"{% endif %}>{% if Count.GLAZING_HEAT_TRANSFER < 0.1 %}{% else %}{{ Count.GLAZING_HEAT_TRANSFER|stringformat:".2f" }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент звукоизоляции (<i>дБ</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_SOUNDPROOFING_COLOR != "" %} style="background:{{ Count.GLAZING_SOUNDPROOFING_COLOR }};"{% endif %}{% if not Count.GLAZING_SOUNDPROOFING < 10 %} title="Коэффициент звукоизоляции стеклопакета: {{ Count.GLAZING_SOUNDPROOFING|stringformat:".1f" }} дБ"{% endif %}>{% if Count.GLAZING_SOUNDPROOFING < 10 %}{% else %}{{ Count.GLAZING_SOUNDPROOFING|stringformat:".1f" }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент светопропускания (<i>%</i>):</th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_LIGHT_TRANSMISSION_COLOR != "" %} style="background:{{ Count.GLAZING_LIGHT_TRANSMISSION_COLOR }};"{% endif %}{% if not Count.GLAZING_LIGHT_TRANSMISSION < 1 %} title="Коэффициент светопропускания стеклопакета: {{ Count.GLAZING_LIGHT_TRANSMISSION|stringformat:".0f" }}%"{% endif %}>{% if Count.GLAZING_LIGHT_TRANSMISSION < 1 %}{% else %}{{ Count.GLAZING_LIGHT_TRANSMISSION|stringformat:".0f" }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент солнцепропускания (<i>%</i>)</th>{% for Count in SET_LIST %}
<td{% if Count.GLAZING_PASSING_SUN_COLOR != "" %} style="background:{{ Count.GLAZING_PASSING_SUN_COLOR }};"{% endif %}{% if not Count.GLAZING_PASSING_SUN < 1 %} title="Коэффициент солнцепропускания стеклопакета: {{ Count.GLAZING_PASSING_SUN|stringformat:".0f" }}%"{% endif %}>{% if Count.GLAZING_PASSING_SUN < 1 %}{% else %}{{ Count.GLAZING_PASSING_SUN|stringformat:".0f" }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент светоотражения, внешний/внутренний (<i>%</i>):</th>{% for Count in SET_LIST %}
<td{% if not Count.GLAZING_LIGHT_REFLECTION == "/" %} title="Коэффициент светоотражения стеклопакета (внешний/внутренний): {{ Count.GLAZING_LIGHT_REFLECTION }}%"{% endif %}>{% if Count.GLAZING_LIGHT_REFLECTION == "—/—" %}—&nbsp;/&nbsp;—{% else %}{{ Count.GLAZING_LIGHT_REFLECTION }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Коэффициент теплоотражения/теплопоглощения (<i>%</i>):</th>{% for Count in SET_LIST %}
<td{% if not Count.GLAZING_REFLECTION_AND_ABSORPTION == "/" %} title="Коэффициент теплоотражения/теплопоглощения стеклопакета: {{ Count.GLAZING_REFLECTION_AND_ABSORPTION }}%"{% endif %}>{% if Count.GLAZING_REFLECTION_AND_ABSORPTION == "—/—" %}—&nbsp;/&nbsp;—{% else %}{{ Count.GLAZING_REFLECTION_AND_ABSORPTION }}{% endif %}</td>{% endfor %}
</tr><tr>
<th>Тонирование стеклопакета:</th>{% for Count in SET_LIST %}
<td title="Тонирование стеклопакета: {{ Count.GLAZING_TONING|lower }}">{{ Count.GLAZING_TONING|capfirst }}</td>{% endfor %}
</tr>
</tbody>
{% if SET_LIST|length > 2 %}<tbody style="border-bottom: solid 3px !important;">
<tr>
<th></th>{% for Count in SET_LIST %}
<th title="Удалить набор компании «{{ Count.MERCHANT }}» ({{ Count.SET_NAME }}) из сравнения"><a href="/compare_offers/{{ Count.URL_W_DEL }}"><b class="glyphicon glyphicon-trash"></b></a></th>{% endfor %}
</tr>
</tbody>{% endif %}
</table>
</div>
</div>
<div class="raw" style="padding: 1em 0;">
<div class="col-xs-7 col-md-offset-1" id="add2compare">{% if SET_LIST|length < 6 %}
<h4>Добавить к сравнению оконные наборы:</h4>
<UL>{% for Count in LIST_TO_ADD %}
<li><a href="/compare_offers/{{ Count.ID_LIST }}"><b class="glyphicon glyphicon-plus-sign"></b>{{ Count.MERCHANT }} — {{ Count.SET_NAME }}</a> <nobr style="padding: 0 1ex">{% for Star in Count.R_STAR %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %} {% if Count.R > 0.02 %}<tt class="badge">{{ Count.R|stringformat:".2f" }}</tt>{% endif %}</nobr>{% if Count.DATA_MODIFY != "" %}<small style="font-size: xx-small;"> — обновлен {{ Count.DATA_MODIFY }}</small>{% endif %}</li> {% endfor %}
</UL>{% endif %}
</div><dIV class="col-xs-4">
<h4>Цветовое кодирование:</h4>
<p><small>Помочь разобраться в&nbsp;комплектациях, условиях поставки, характеристиках оконных профилей и&nbsp;стеклопакетов поможет цвет фона ячеек таблицы. <span style="background:#83ff83;">Зеленый цвет</span>&nbsp;&mdash; лучшие значения, чем насыщение цвет, тем более высокие потребительская характеристика у&nbsp;того или иного параметра. <span style="background:#ff7f7f;">Красный цвет</span>&nbsp;&mdash; отсутствие отдельных элементов или услуг комплексного предложения.</small></p>
{# реклама Oknardia 250x250 СБОКУ #}{% include "ad/bannet-250x250.html" %}
</dIV>
</div>
{# --- Баннер: НАЧАЛО --- #}
<div class="row"><div class="col-md-12 col-xs-12"><hr class="dotted-black" />{% include "ad/bannet-wide.html" %}</div></div>
{# --- Баннер: конец --- #}
<div class="row">
{% include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
<p id="shadow_buffer"></p>
<!--- ------------------------------------------------------------------------------------------------------------------------- --->{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}
+20
View File
@@ -0,0 +1,20 @@
{# отображение рейтинга #}{% load static %}
<table class="pop-tab" width="100%" style="border: none !important;">
<tbody style="border: none !important;">
<tr style="border: none !important; border-left: none !important;">
<td style="border: none !important;">Услуги:</td>
<td style="border: none !important;"><nobr><!-- НАЧАЛО звездочки рейтинга -->{% for Star in RATING_SERVIZ_STARS %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if RATING_SERVIZ > 0 %}<tt class="badge">{{ RATING_SERVIZ|stringformat:".2f" }}</tt>{% else %}<tt class="badge">не присвоен</tt>{% endif %}<!-- КОНЕЦ бедж --></nobr></td>
</tr><tr style="border: none !important;">
<td style="border: none !important;">Оконный&nbsp;профиль:</td>
<td style="border: none !important;"><nobr><!-- НАЧАЛО звездочки рейтинга -->{% for Star in RATING_PVC_STARS %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if RATING_PVC > 0 %}<tt class="badge">{{ RATING_PVC|stringformat:".2f" }}</tt>{% else %}<tt class="badge">не присвоен</tt>{% endif %}<!-- КОНЕЦ бедж --></nobr></td>
</tr><tr style="border: none !important;">
<td style="border: none !important;">Стеклопакет:</td>
<td style="border: none !important;"><nobr><!-- НАЧАЛО звездочки рейтинга -->{% for Star in RATING_GLAZ_STARS %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if RATING_GLAZ > 0 %}<tt class="badge">{{ RATING_GLAZ|stringformat:".2f" }}</tt>{% else %}<tt class="badge">не присвоен</tt>{% endif %}<!-- КОНЕЦ бедж --></nobr></td>
</tr><tr style="border: none !important;">
<td style="border: none !important;">От&nbsp;пользователей:</td>
<td style="border: none !important;"><nobr><!-- НАЧАЛО звездочки рейтинга -->{% for Star in RATING_OFFER_STARS %}{% if Star == 0 %}<i class="glyphicon glyphicon-star-empty"></i>{% else %}<b class="glyphicon glyphicon-star"></b>{% endif %}{% endfor %}<!-- КОНЕЦ звездочки рейтинга НАЧАЛО бедж --> {% if RATING_OFFER > 0 %}<tt class="badge">{{ RATING_OFFER|stringformat:".2f" }}</tt>{% else %}<tt class="badge">не присвоен</tt>{% endif %}<!-- КОНЕЦ бедж --></nobr></td>
</tr><tr style="border: none !important;">
<td colspan="2" style="background:ghostwhite;padding:1ex;border: none !important;"><small>В базе {{ NUM_OFFERS }}. Обновление цен {{ DATA_OFFER_UPDATE }}.<!-- Время исполнения: {{ ticks|stringformat:".4f" }}--></small></td>
</tr>
</tbody>
</table>
@@ -7,10 +7,6 @@
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %}
{% block Description %}Дома серии {{ THIS_SERIA_NAME }}: детальная информация{% endblock %}
{% block Keywords %} {{ THIS_SERIA_NAME }}, серия {{ THIS_SERIA_NAME }}, проект {{ THIS_SERIA_NAME }}, года постройки зданий серии {{ THIS_SERIA_NAME }}, размеры окон в домах серии {{ THIS_SERIA_NAME }}, оконные проемы зданий серии {{ THIS_SERIA_NAME }}, дома серии {{ THIS_SERIA_NAME }} на карте, установка окон, цены на пластиковые окна{% endblock %}
@@ -72,7 +68,7 @@
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия {{ THIS_SERIA_NAME }}: ввод в эксплуатацию по годам</h2>
<h2 class="header">Здания серия {{ THIS_SERIA_NAME }}: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
{% include 'seria_info/yaer_graph.html' %}
@@ -84,7 +80,7 @@
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии {{ THIS_SERIA_NAME }} на карте</h2>
<h2 class="header">Строения серии {{ THIS_SERIA_NAME }} на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
@@ -94,22 +90,23 @@
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии {{ THIS_SERIA_NAME }}</nobr></h3>
<p>Совокупно во всех зданиях типового проекта:</p>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>{{ ACCOUNTS|price_format }}</strong> квартир.</li>
<li>Проживает <strong>{{ APARTMENTS|price_format }}</strong> семей <small>(<strong>{{ RESIDENTS|price_format }}</strong> человек)</small>.</li>
<li><strong>{{ RESIDENTIAL_M2|stringformat:".1f"|price_format }} м²</strong> жилых помещений.</li>
<li><strong>{{ MUNICIPAL_M2|stringformat:".1f"|price_format }} м²</strong> — муниципальное жильё.</li>
<li><strong>{{ GOVERNMENT_M2|stringformat:".1f"|price_format }} м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
<li>Максимальный износ жилого фонда серии {{ THIS_SERIA_NAME }} <strong>{{ CONDITION_MAX|stringformat:".2f" }}%</strong>. Минимальный <strong>{{ CONDITION_MIN|stringformat:".2f" }}%</strong>. </li>
<li><strong>{{ MUNICIPAL_M2|stringformat:".1f"|price_format }} м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>{{ GOVERNMENT_M2|stringformat:".1f"|price_format }} м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии {{ THIS_SERIA_NAME }}&nbsp;<strong>{{ CONDITION_MAX|stringformat:".2f" }}%</strong>. Минимальный&nbsp;<strong>{{ CONDITION_MIN|stringformat:".2f" }}%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">{# <div class="col-md-4"> #}
<h5>Информация о&nbsp;других, отличных от&nbsp;{{ THIS_SERIA_NAME }}, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а также рекомендации по замене окон:</h5>
<h5>Информация о&nbsp;других, отличных от&nbsp;{{ THIS_SERIA_NAME }}, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d">{% include 'seria_info/seria_nav.html' %}</div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
+2 -2
View File
@@ -23,12 +23,12 @@ $(window).load(function(){let images = $('.half');images.each(function(i){$(this
{% block Main_Content %}<div class="container-fluid">
<div class="row">
<div class="col-md-9"><h1>Статистика</h1></div>
<div class="col-md-9"><h1>Типовые серии домов в&nbsp;базе &laquo;Окнардия&raquo;</h1></div>
</div>
<div class="row">
<div class="col-md-10"><a name="s_graph"></a>
<h2 class="header">Распределение типовых серии в жилом фонде<sup><small style="color: darkred;">*</small></sup></h2>
<h2 class="header">Распределение типовых серий в&nbsp;жилом фонде<sup><small style="color: darkred;">*</small></sup></h2>
</div>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,368 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:31:05.856942+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:31:05.857034+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:31:05.857082+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии ПД-4: детальная информация" />
<meta name="keywords" content=" ПД-4, серия ПД-4, проект ПД-4, года постройки зданий серии ПД-4, размеры окон в домах серии ПД-4, оконные проемы зданий серии ПД-4, дома серии ПД-4 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии ПД-4 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия ПД-4</li>
</ol>
<h1>СЕРИЯ ПД-4</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии ПД-4: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/116x142H216WN(G)(L_).png" alt="Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:134px;min-width:13ex;">
<nobr>1160×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ<br />
<a href="/tsena-odnogo-okna/1160x1420mm/tip2">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/067x216H216D-(L).png" alt="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:77px;min-width:13ex;">
<nobr>670×2160&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4<br />
<a href="/tsena-odnogo-okna/670x2160mm/tip16">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/116x142H216W-(G_)(L).png" alt="Окно двустворчатое для серии ПД-4. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серии ПД-4. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:134px;min-width:13ex;">
<nobr>1160×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Окно двустворчатое для серии ПД-4<br />
<a href="/tsena-odnogo-okna/1160x1420mm/tip45">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/147x142H216W-(G)(L_).png" alt="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:170px;min-width:13ex;">
<nobr>1470×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ<br />
<a href="/tsena-odnogo-okna/1470x1420mm/tip1">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap4">
<div><img src="/static/img/_flap.cfg/206x142H216W-(G)(G)(L).png" alt="Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4. Размер 2060x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4. Размер 2060x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:238px;min-width:13ex;">
<nobr>2060×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markE.svg');"></span></nobr><br />
Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4<br />
<a href="/tsena-odnogo-okna/2060x1420mm/tip10">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии ПД-4</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия ПД-4: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1961",4,"color: #99a899"],
["1962",11,"color: #99c499"],
["1963",6,"color: #99b099"],
["1964",1,"color: #999c99"],
["1995",1,"color: #999c99"],
["1996",6,"color: #99b099"],
["1997",13,"color: #99cc99"],
["1998",6,"color: #99b099"],
["1999",11,"color: #99c499"],
["2000",9,"color: #99bc99"],
["2001",8,"color: #99b899"],
["2002",6,"color: #99b099"],
["2003",6,"color: #99b099"],
["2004",5,"color: #99ac99"],
["2005",1,"color: #999c99"],
["2006",2,"color: #99a099"],
["2008",2,"color: #99a099"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии ПД-4 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии ПД-4 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.564053,37.570941],[55.562907,37.570366],[55.563656,37.569306],[55.662364,37.779098],[55.748812,37.985073],[55.663486,37.765363],[55.490585,37.297512],[55.663888,37.769397],[55.633760,37.739600],[55.632916,37.738575],[55.632987,37.769558],[55.655437,37.764519],[55.863576,37.432025],[55.864818,37.431154],[55.567667,37.570923],[55.568110,37.571606],[55.568089,37.569701],[55.568354,37.568192],[55.568777,37.568821],[55.568782,37.566880],[55.569011,37.565353],[55.569494,37.566126],[55.569443,37.564168],[55.858074,37.568120],[55.739448,37.853048],[55.739868,37.853874],[55.550723,37.556208],[55.551599,37.556622],[55.550611,37.558167],[55.550101,37.558059],[55.550244,37.559173],[55.550789,37.559056],[55.546190,37.557780],[55.546908,37.558751],[55.548294,37.559451],[55.548660,37.560224],[55.545258,37.557879],[55.546083,37.558805],[55.546699,37.559460],[55.546842,37.560251],[55.736650,37.846760],[55.736883,37.847927],[55.735748,37.847119],[55.843222,37.386903],[55.842464,37.387622],[55.854704,37.360897],[55.855441,37.359504],[55.855896,37.358462],[55.837702,37.390532],[55.838668,37.390415],[55.750707,37.992790],[55.747819,37.988370],[55.750707,37.991775],[55.750727,37.989807],[55.750758,37.988783],[55.750778,37.987777],[55.956965,38.063846],[55.958321,38.062122],[55.922696,37.722361],[55.662699,37.766306],[55.840502,37.527399],[55.840442,37.528424],[55.654625,37.606137],[55.653898,37.606155],[55.840629,37.529852],[55.633932,37.747253],[55.631966,37.768175],[55.863379,37.430714],[55.857235,37.568201],[55.548044,37.560871],[55.854082,37.362136],[59.881525,30.454595],[59.883905,30.487096],[59.882049,30.483602],[59.881313,30.482003],[59.880600,30.480413],[59.879931,30.478858],[59.874110,30.476658],[59.880911,30.469776],[59.878130,30.464234],[59.881214,30.461710],[59.879371,30.463425],[59.881074,30.462859],[59.879827,30.464198],[59.879191,30.464333],[59.879647,30.465240],[59.881498,30.464620],[59.881850,30.465249],[59.879827,30.466273],[59.880017,30.466902],[59.880419,30.467728],[59.880433,30.468645],[59.881728,30.477421],[55.745336,38.023171],[55.746015,38.021311],[55.428066,37.561059],[55.923473,37.724086],[55.924204,37.722397]];
let forURL = [386,388,10894,20193,71407,982,2134,12210,12704,12750,12833,12869,13603,13621,14936,14937,14938,14939,14940,14941,14946,14947,14948,15636,22141,22148,26758,26760,26761,26762,26763,26764,26767,26768,26769,26771,26772,26773,26774,26775,27668,27669,27724,32273,32274,32291,32293,32297,32302,32303,71401,71429,71436,71471,71474,71476,80428,80430,97640,983,20787,20788,1110,1111,9538,12718,12830,13625,15635,26770,32285,37770,39797,39801,39810,39815,39819,39829,40580,51926,51929,51930,51931,51934,51936,51937,51939,51941,51942,51943,51948,51953,51978,71533,71542,77732,97641,97647];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии ПД-4</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии ПД-4 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии ПД-4</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>16024</strong> квартир.</li>
<li>Проживает <strong>14641</strong> семей <small>(<strong>69926</strong> человек)</small>.</li>
<li><strong>825653.9 м²</strong> жилых помещений.</li>
<li><strong>22532.1 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>28434.2 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии ПД-4&nbsp;<strong>30.00%</strong>. Минимальный&nbsp;<strong>1.40%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;ПД-4, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,346 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:30:27.483379+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:30:27.483423+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:30:27.483448+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии К-7: детальная информация" />
<meta name="keywords" content=" К-7, серия К-7, проект К-7, года постройки зданий серии К-7, размеры окон в домах серии К-7, оконные проемы зданий серии К-7, дома серии К-7 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии К-7 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия К-7</li>
</ol>
<h1>СЕРИЯ К-7</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии К-7: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/132x153H153W-(G)(L_).png" alt="Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:215px;min-width:13ex;">
<nobr>1320×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9<br />
<a href="/tsena-odnogo-okna/1320x1530mm/tip23">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/188x153H153W-(G_)(G_)(L).png" alt="Окно трёхстворчатое для серии К9 и 1-515/9Ш. Размер 1880x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии К9 и 1-515/9Ш. Размер 1880x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:307px;min-width:13ex;">
<nobr>1880×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Окно трёхстворчатое для серии К9 и 1-515/9Ш<br />
<a href="/tsena-odnogo-okna/1880x1530mm/tip38">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии К-7</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия К-7: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1926",1,"color: #999a99"],
["1929",3,"color: #999c99"],
["1959",7,"color: #99a099"],
["1960",6,"color: #999f99"],
["1961",25,"color: #99b399"],
["1962",23,"color: #99b199"],
["1963",48,"color: #99cc99"],
["1964",36,"color: #99bf99"],
["1965",10,"color: #99a399"],
["1966",18,"color: #99ac99"],
["1967",2,"color: #999b99"],
["1976",1,"color: #999a99"],
["1978",1,"color: #999a99"],
["1984",1,"color: #999a99"],
["1989",1,"color: #999a99"],
["1991",1,"color: #999a99"],
["1996",1,"color: #999a99"],
["1998",1,"color: #999a99"],
["2000",1,"color: #999a99"],
["2003",1,"color: #999a99"],
["2004",1,"color: #999a99"],
["2010",11,"color: #99a499"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии К-7 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии К-7 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.862510,37.560440],[55.861646,37.560170],[55.861863,37.558885],[55.863510,37.559371],[55.872774,37.549642],[55.858518,37.561293],[55.859261,37.561329],[55.860064,37.561419],[55.860009,37.560655],[55.859797,37.559936],[55.851551,37.432007],[55.852435,37.431989],[55.769393,37.475243],[55.769524,37.471560],[55.769524,37.471560],[55.774087,37.462918],[55.775358,37.460951],[55.775798,37.460421],[55.862853,37.558400],[55.863181,37.558885],[55.673610,37.497575],[55.672661,37.495887],[55.788672,37.785557],[55.788692,37.787336],[55.668965,37.510987],[55.668894,37.509514],[55.666096,37.509846],[55.666096,37.509119],[55.666091,37.508409],[55.774482,37.474426],[55.774482,37.474426],[55.774482,37.474426],[55.775322,37.471255],[55.774862,37.471767],[55.774958,37.471102],[55.775039,37.470428],[55.776112,37.462676],[55.776208,37.462002],[55.776310,37.461337],[55.871976,37.641459],[55.871471,37.636176],[55.872062,37.635602],[55.871334,37.634676],[55.871991,37.634865],[55.871920,37.634119],[55.871198,37.633185],[55.871854,37.633365],[55.872087,37.642950],[55.885186,37.656407],[55.885635,37.656047],[55.886347,37.655481],[55.886796,37.655140],[55.884731,37.656766],[55.855138,37.645294],[55.854401,37.644710],[55.855841,37.644980],[55.856326,37.642698],[55.855542,37.642150],[55.855108,37.639635],[55.855108,37.639635],[55.856801,37.640390],[55.856801,37.640390],[55.856331,37.639159],[55.857043,37.638692],[55.880960,37.644513],[55.882707,37.648349],[55.882141,37.649274],[55.883232,37.650020],[55.883035,37.651717],[55.874471,37.627813],[55.874294,37.625837],[55.874865,37.626493],[55.875971,37.626852],[55.875334,37.623465],[55.875031,37.624921],[55.875890,37.625424],[55.874758,37.623061],[55.871723,37.631963],[55.871784,37.632619],[55.878405,37.620061],[55.473265,37.539006],[55.343200,37.638458],[55.343200,37.638458],[55.343200,37.638458],[55.860630,37.473114],[55.865273,37.471372],[55.863121,37.425477],[55.857700,37.425656],[55.857745,37.424147],[55.723100,37.567590],[55.723962,37.568408],[55.723775,37.569009],[55.723212,37.568713],[55.867834,37.673169],[55.867177,37.673268],[55.865945,37.678505],[55.867692,37.674714],[55.822428,37.587290],[55.821897,37.584990],[55.822620,37.584730],[55.823312,37.584182],[55.878243,37.633167],[55.878758,37.628110],[55.878066,37.623232],[55.878152,37.622432],[55.879329,37.621669],[55.878233,37.621651],[55.878314,37.620851],[55.879601,37.639653],[55.772456,37.471821],[55.772548,37.471165],[55.772968,37.473420],[55.773054,37.472791],[55.773570,37.474022],[55.773667,37.473366],[55.773763,37.472710],[55.773763,37.472710],[55.770704,37.470734],[55.770487,37.472827],[55.770704,37.473959],[55.771935,37.471120],[55.771403,37.470877],[55.660800,37.519207],[55.661978,37.514733],[55.661978,37.514733],[55.661978,37.514733],[55.661978,37.514733],[55.661237,37.513422],[55.660937,37.513853],[55.660892,37.514661],[55.875319,37.634407],[55.875511,37.631999],[55.875935,37.635188],[55.882853,37.641144],[55.872127,37.636347],[55.873198,37.635709],[55.874395,37.634766],[55.861444,37.555220],[55.861752,37.556469],[55.854224,37.650091],[55.810840,37.569207],[55.853001,37.422970],[55.853087,37.423761],[55.859499,37.474974],[55.856962,37.477067],[55.858306,37.476878],[55.857068,37.479582],[55.857639,37.480139],[55.859221,37.479573],[55.858488,37.480489],[55.857750,37.481343],[55.821042,37.584586],[55.820329,37.587191],[55.821138,37.585251],[55.821269,37.585880],[55.820430,37.583805],[55.800701,37.727302],[55.796840,37.615345],[55.794836,37.615470],[55.821295,37.582556],[55.821457,37.583230],[55.822068,37.582484],[55.822473,37.580643],[55.822625,37.581298],[55.822776,37.581963],[55.858473,37.559371],[55.859398,37.558472],[55.859600,37.559200],[55.859539,37.557430],[55.859539,37.557430],[55.859539,37.557430],[55.476664,37.295131],[55.476490,37.296209],[55.481087,37.300117],[55.475888,37.295086],[55.672184,37.495033],[55.671712,37.494180],[55.768203,37.711347],[55.870662,37.464625],[55.872157,37.463610],[55.866031,37.472135],[55.858513,37.475010],[55.893243,37.539940],[55.651821,37.553765],[55.805832,37.817492],[55.808245,37.816603],[55.861595,37.555831],[55.673016,37.754556],[55.804941,37.614832],[55.719794,37.802814],[55.717492,37.809614],[59.737400,30.462752],[59.737686,30.462123],[59.736090,30.464405],[59.735813,30.465042],[59.736806,30.462859],[59.737074,30.462231],[59.736108,30.465608],[59.733273,30.466614],[59.734167,30.468070],[59.733273,30.466614],[59.734167,30.468070]];
let forURL = [172,173,174,175,217,218,251,255,256,257,1521,1522,2819,2821,2823,2828,2833,2835,3517,3518,6168,6173,6531,6533,6738,6739,6772,6775,6778,6968,6969,6970,6973,6974,6975,6976,6987,6988,6989,8139,8151,8152,8159,8160,8161,8169,8170,8180,8300,8302,8305,8307,8316,9162,9163,9164,9165,9166,9168,9169,9170,9171,9172,9173,9727,9740,9743,9747,9755,9856,9860,9865,9866,9867,9869,9871,9873,9877,9878,9881,9937,10233,10234,10236,12173,12195,13600,14497,14503,15383,15392,15393,15394,20459,20460,20489,20490,20621,20622,20624,20626,20967,20974,20986,20987,20988,20989,20990,20994,21566,21567,21574,21575,21581,21582,21583,21584,21606,21625,21634,21640,21641,21961,22691,22692,22693,22694,22704,22710,22712,24914,24916,24920,24938,24948,24967,24971,26531,26538,26881,28275,28491,28492,28961,28962,28968,28982,28986,28988,28989,28990,29242,29243,29245,29247,29256,29418,30266,30291,30912,30913,30915,30918,30919,30920,31583,31584,31585,31586,31587,31588,2154,2155,2168,2174,6180,6185,19284,7965,7968,12166,28959,15424,22687,23546,23563,26537,27593,30279,29517,29525,45464,45465,45499,45500,45502,45503,45505,45535,45538,45555,45558];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии К-7</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии К-7 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии К-7</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>19354</strong> квартир.</li>
<li>Проживает <strong>16839</strong> семей <small>(<strong>82948</strong> человек)</small>.</li>
<li><strong>539518.2 м²</strong> жилых помещений.</li>
<li><strong>93304.8 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>27709.9 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии К-7&nbsp;<strong>69.00%</strong>. Минимальный&nbsp;<strong>4.80%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;К-7, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,359 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:28:02.157690+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:28:02.157739+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:28:02.157763+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии 1-335: детальная информация" />
<meta name="keywords" content=" 1-335, серия 1-335, проект 1-335, года постройки зданий серии 1-335, размеры окон в домах серии 1-335, оконные проемы зданий серии 1-335, дома серии 1-335 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии 1-335 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия 1-335</li>
</ol>
<h1>СЕРИЯ 1-335</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"><p>Пятиэтажка 1&ndash;335 проектировалась Ленинградским Отделением Горстройпроекта (архитекторы Баныкин&nbsp;Б. Н., Артемьева И. Б. и&nbsp;Смирнова Л. А.) и&nbsp;стала одним из&nbsp;первых зданий &laquo;полукаркасной&raquo; схемы (неполный каркас и&nbsp;навесные панели). Возводилась по&nbsp;всей территории СССР с&nbsp;1956 года. Последние здания серии сданы в&nbsp;эксплуатацию в&nbsp;1968 году.</p>
<p>Проект 1&ndash;335 так и&nbsp;не&nbsp;получил дальнейшей модернизации, <nobr>из-за</nobr> ряда недостатков. Так, профильные навесные бетонные панели толщиной 30&nbsp;см.&nbsp;приводили к&nbsp;теплопотерям, и&nbsp;замена на&nbsp;керамзитбетонные (40&nbsp;см.) для регионов с&nbsp;суровым климатом не&nbsp;спасало. Внешняя облицовка утепляющими материалами увеличивала стоимость и&nbsp;эксплуатационные расходы, потому 1&ndash;335 возводились только в&nbsp;Ленинграде, где климат мягче.</p>
<p>Внешний вид 1&ndash;335 не&nbsp;сильно отличается от&nbsp;других панельных зданий того периода. Серию можно узнать по&nbsp;боковому фасаду: без балконов, две панели без окон в&nbsp;центре или по&nbsp;краям. Как и&nbsp;у&nbsp;многих &laquo;хрущёвок&raquo;, серия 1&ndash;335 с&nbsp;железной четырёхскатной крышей (поздние модификации строились с&nbsp;плоской крышей без чердаков), секции без лифта (по&nbsp;четыре квартиры: 1-, 2- и&nbsp;<nobr>3-комнатные</nobr>), потолки 255&nbsp;см., санузер совмещенный.</p>
<p>Оконные проемы серии 1&ndash;335 на&nbsp;10&ndash;15&nbsp;см шире чем у&nbsp;других &laquo;хрущёвок&raquo;, но&nbsp;максимум пять этажей подразумевают низкие ветровые нагрузки. Это означает, что при замене окон использование усиленных профилей не&nbsp;обязательно. Кроме того, нецелесообразно использование стеклопакетов с&nbsp;заполнением инертным газом и&nbsp;высоким сопротивлением теплопередаче&nbsp;&mdash; утечки тепла через панели сведут на&nbsp;нет их&nbsp;преимущество. Благодаря хорошей вытяжной вентиляции здания можно сэкономить на&nbsp;встраиваемых в&nbsp;окна клапанах <nobr>климат-контроля</nobr>.</p></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии 1-335: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/126x138H207WN(G)(L).png" alt="Окно двустворчатое «Хрущевка» на балкон (серии 1-335). Размер 1260x1380 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое «Хрущевка» на балкон (серии 1-335). Размер 1260x1380 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:152px;min-width:13ex;">
<nobr>1260×1380&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно двустворчатое «Хрущевка» на балкон (серии 1-335)<br />
<a href="/tsena-odnogo-okna/1260x1380mm/tip49">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/068x207H207D-(L).png" alt="Дверь на балкон «Хрущевка» (серии 1-335, 507, 510, 511 и 515/5). Размер 680x2070 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон «Хрущевка» (серии 1-335, 507, 510, 511 и 515/5). Размер 680x2070 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:82px;min-width:13ex;">
<nobr>680×2070&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Дверь на балкон «Хрущевка» (серии 1-335, 507, 510, 511 и 515/5)<br />
<a href="/tsena-odnogo-okna/680x2070mm/tip40">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/128x138H207W-(G)(L).png" alt="Окно двустворчатое «Хрущевка» (серии 1-335). Размер 1280x1380 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое «Хрущевка» (серии 1-335). Размер 1280x1380 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:154px;min-width:13ex;">
<nobr>1280×1380&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Окно двустворчатое «Хрущевка» (серии 1-335)<br />
<a href="/tsena-odnogo-okna/1280x1380mm/tip48">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/194x138H207W-(G)(L)(L).png" alt="Окно трёхстворчатое «Хрущевка» (серии 1-335). Размер 1940x1380 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое «Хрущевка» (серии 1-335). Размер 1940x1380 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:234px;min-width:13ex;">
<nobr>1940×1380&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно трёхстворчатое «Хрущевка» (серии 1-335)<br />
<a href="/tsena-odnogo-okna/1940x1380mm/tip47">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии 1-335</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия 1-335: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1956",1,"color: #999a99"],
["1957",1,"color: #999a99"],
["1959",11,"color: #99a499"],
["1960",25,"color: #99b299"],
["1961",50,"color: #99cc99"],
["1962",37,"color: #99be99"],
["1963",7,"color: #99a099"],
["1964",29,"color: #99b699"],
["1965",18,"color: #99ab99"],
["1966",20,"color: #99ad99"],
["1967",18,"color: #99ab99"],
["1968",1,"color: #999a99"],
["1969",1,"color: #999a99"],
["2000",2,"color: #999b99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии 1-335 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии 1-335 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.797847,37.813495],[55.797857,37.814241],[55.797908,37.818579],[55.797898,37.817825],[55.797888,37.817061],[55.802568,37.813504],[55.802077,37.812534],[55.802103,37.814483],[55.788960,37.786366],[55.819772,37.623492],[55.819793,37.622792],[55.732342,37.425171],[55.787118,37.454672],[55.869617,37.673969],[55.799456,37.812677],[55.799467,37.813441],[55.799477,37.814178],[55.798667,37.814627],[55.798677,37.815310],[55.799527,37.818508],[55.799507,37.817762],[55.799502,37.816998],[55.798692,37.816639],[55.798682,37.815974],[55.796618,37.482897],[60.009534,30.415527],[60.009521,30.417270],[59.988005,30.419004],[59.987839,30.417926],[60.011163,30.432703],[55.802614,37.817430],[55.802143,37.818364],[55.682295,37.745268],[55.874466,37.712605],[60.094954,29.975173],[60.101176,29.978479],[59.928690,30.414494],[59.972613,30.430331],[60.016348,30.369965],[59.922864,30.422193],[60.019298,30.409329],[60.019451,30.408700],[60.019536,30.411467],[60.019212,30.411997],[60.019068,30.412662],[59.925173,30.422687],[59.924050,30.422408],[59.924055,30.423010],[59.922747,30.423298],[59.955512,30.436647],[59.955611,30.435245],[59.955687,30.433637],[59.955773,30.432110],[59.955863,30.430502],[59.966174,30.434886],[59.969912,30.434203],[59.972830,30.434428],[59.972199,30.432640],[59.972186,30.427933],[59.920997,30.423801],[59.921205,30.424474],[59.927017,30.429155],[59.927640,30.431661],[59.928735,30.430251],[60.009215,30.433476],[60.009926,30.432047],[60.017306,30.411871],[60.013564,30.406984],[59.967399,30.433242],[59.969299,30.433071],[59.925398,30.417009],[59.926792,30.418725],[59.926512,30.420396],[59.958363,30.424178],[59.957890,30.426729],[59.957751,30.428247],[59.958647,30.429424],[59.958440,30.430790],[59.958850,30.413210],[55.591447,37.642060],[55.590562,37.642411],[55.681696,37.571857],[55.681427,37.572585],[55.681189,37.573321],[55.674529,37.578594],[55.674184,37.578235],[55.673864,37.577912],[59.932180,30.414656],[59.930304,30.413254],[59.929849,30.414692],[59.930660,30.415105],[59.929366,30.415033],[59.929227,30.417045],[59.929673,30.416560],[59.929799,30.421160],[59.930178,30.423369],[59.930944,30.427942],[59.928181,30.414288],[59.927860,30.415105],[59.927860,30.415105],[59.926990,30.416174],[59.926990,30.416174],[59.925642,30.415851],[59.924339,30.417405],[59.923667,30.418312],[59.922990,30.419273],[59.923410,30.420495],[59.921913,30.420755],[59.922305,30.421986],[59.921971,30.423001],[59.920830,30.422292],[59.932017,30.415348],[59.928519,30.421043],[59.927915,30.420513],[59.930886,30.416183],[59.928009,30.421654],[59.928009,30.421654],[59.927671,30.422004],[59.929344,30.417611],[59.927220,30.421276],[59.927125,30.422579],[59.928627,30.418447],[59.928095,30.418357],[59.926774,30.422983],[59.928460,30.416965],[59.926142,30.422633],[59.927482,30.417764],[59.923775,30.425867],[59.927243,30.419291],[59.927071,30.420252],[59.925777,30.421806],[59.924474,30.423549],[59.923595,30.423612],[59.923707,30.424618],[59.922959,30.423926],[59.922373,30.424295],[59.922900,30.425732],[59.922048,30.426882],[59.982658,30.411673],[59.986596,30.422786],[59.920636,30.423387],[59.921412,30.425112],[59.921813,30.425525],[59.921615,30.426280],[59.923423,30.428131],[59.925196,30.428436],[59.927044,30.427699],[59.926684,30.430421],[59.927247,30.430565],[59.927901,30.428876],[59.927906,30.430340],[59.928573,30.431032],[59.932414,30.322022],[59.932085,30.321725],[59.931544,30.321105],[59.931314,30.320512],[59.933681,30.323207],[59.933510,30.323055],[59.932748,30.322336],[59.924957,30.417162],[59.925087,30.418195],[59.925002,30.420719],[59.926224,30.416857],[59.925547,30.420387],[59.895615,30.422094],[59.895226,30.421016],[59.894450,30.420782],[59.894780,30.419641],[59.973320,30.425301],[59.972181,30.424061],[59.973325,30.428768],[60.017004,30.375435],[60.016780,30.376738],[60.013227,30.402645],[59.965660,30.401774],[60.015597,30.369713],[60.014522,30.369686],[60.014576,30.370477],[60.014248,30.374115],[60.014113,30.374869],[60.013353,30.374762],[59.964332,30.435326],[59.971105,30.433044],[59.974923,30.404226],[59.972839,30.422283],[60.007888,30.431284],[60.009215,30.433476],[60.012210,30.415240],[59.968142,30.435155],[59.958341,30.426020],[59.958602,30.430134],[59.973284,30.432487],[60.016492,30.394228],[60.013771,30.402250],[60.012534,30.405376],[60.016447,30.372911],[59.930403,30.412554],[60.012669,30.403786],[60.010659,30.412644],[60.010717,30.413488],[60.009193,30.419839],[60.009004,30.420477],[60.014009,30.375624],[59.973766,30.404837],[59.973910,30.403687],[59.972762,30.403723],[59.973136,30.404155],[59.973239,30.405655],[59.973816,30.407532],[60.006984,30.429173],[60.007047,30.431544],[60.007663,30.429451],[60.016901,30.373163],[59.955647,30.434464],[59.955818,30.431302],[59.972019,30.406688],[59.984283,30.402600],[59.983671,30.406625],[59.954119,30.433332],[59.954092,30.434086],[55.032480,82.904197]];
let forURL = [500,501,506,507,508,1186,1187,1188,6532,10981,10982,15807,15993,19036,23453,23454,23455,23456,23457,23512,23513,23514,23515,23516,25685,42831,42833,47423,47428,53621,1195,1196,5964,19285,36627,36648,40749,42235,42826,43196,43811,43812,43815,43817,43818,44775,44777,44778,44782,44947,44948,44951,44955,44959,44998,45003,45008,45010,47599,48689,48690,48705,48713,48715,53618,53620,54364,54392,54485,54487,54693,54699,54700,56026,56029,56032,56033,56036,56047,9494,9495,17262,17263,17264,18444,18445,18446,38621,40744,40746,40750,40751,40754,40756,40760,40763,40770,43156,43157,43158,43163,43165,43176,43178,43184,43191,43192,43194,43195,43197,43203,44740,44743,44745,44747,44748,44749,44750,44751,44753,44755,44757,44758,44760,44761,44762,44765,44768,44770,44772,44774,44776,44779,44780,44781,44783,44784,44785,46886,47434,48688,48691,48692,48693,48696,48700,48702,48709,48710,48711,48712,48714,49929,49930,49931,49932,49933,49934,49935,54687,54690,54694,54696,54697,40667,40669,40672,40675,42229,51740,42233,42798,42808,42814,43407,44361,44419,44420,44422,44423,44424,44996,45006,50273,51741,53614,53619,54381,54491,56027,56034,42239,42807,42813,42818,42871,43146,42815,42828,42829,42843,42844,44417,46392,46395,46396,46397,46398,50266,53610,53612,53613,42882,44950,44957,46399,46880,46883,47193,47194,58339];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии 1-335</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии 1-335 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии 1-335</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>19742</strong> квартир.</li>
<li>Проживает <strong>20521</strong> семей <small>(<strong>98798</strong> человек)</small>.</li>
<li><strong>904827.7 м²</strong> жилых помещений.</li>
<li><strong>6470.2 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>31829.0 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии 1-335&nbsp;<strong>70.00%</strong>. Минимальный&nbsp;<strong>6.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;1-335, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,387 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:31:02.370699+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:31:02.370777+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:31:02.370817+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии П-55: детальная информация" />
<meta name="keywords" content=" П-55, серия П-55, проект П-55, года постройки зданий серии П-55, размеры окон в домах серии П-55, оконные проемы зданий серии П-55, дома серии П-55 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии П-55 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия П-55</li>
</ol>
<h1>СЕРИЯ П-55</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"><p>Типовой проект жилой серии П-55 <nobr>и П-55М</nobr> проектировался в&nbsp;конце 1970-х как шумозащитный. Размещение домов предполагалось вдоль больших автомагистралей или на&nbsp;границе промышленных зон. Возведением серии занимались в&nbsp;основном ДСК-4 и&nbsp;АО «Моспромстроиматериалов». Повышенная шумоизоляция достигалась благодаря использованию специальных трёхслойных керамзитбетонных панелей и&nbsp;оригинальной планировкой, благодаря которой на&nbsp;неблагоприятную сторону выходили главным образом нежилые помещения. Кроме того, внешний фасад имел минимальное число балконов, таким образом уменьшая проникновение пыли в&nbsp;жилые комнаты.</p>
<p>Внешний фасад серии П-55 и&nbsp;П-55М выстраивался уступами, что значительной степени отражало шум. Сверх того, дома серии часто строили в&nbsp;виде Г- и&nbsp;П-образных конструкций и&nbsp;снабжали арками, что повышало защиту дворов. Но&nbsp;даже рядные&nbsp;— обычно двух- и&nbsp;трехсекционные блок-дома&nbsp;— в&nbsp;силу большой высотности<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>10−14 этажей) являлись достаточным препятствием для проникновения шума и&nbsp;пыли в&nbsp;дворы, в&nbsp;стороны которых выходили окна жилых комнат и&nbsp;большое число балконов.</p>
<p>Являясь поздними<span style="margin-right:0.44em;"> </span><span style="margin-left:-0.44em;">«</span>брежневскими» серией панельного строительства, в&nbsp;П-55 значительное внимание уделялось удобству: в&nbsp;подъездах расположено по&nbsp;два пассажирских лифта, большинство квартир с&nbsp;несколькими балконами, много трёх- и&nbsp;четырёхкомнатных квартир. Кроме того, проект П-55 отличает более высокие чем у&nbsp;предыдущих серий <nobr>потолки<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>2 м 65 см)</nobr> и&nbsp;увеличенные размеры ванной и&nbsp;туалетной комнаты. Улучшенная серия П-55М ещё более комфортна: вторые санузлы в&nbsp;трёх- и&nbsp;четырёхкомнатных квартирах; входной блок подъезда и&nbsp;лифт адаптирован для инвалидов-колясочников.</p>
<strong><p>В&nbsp;силу расположенности зданий серий П-55 вдоль шумных магистралей и&nbsp;промышленных зон, замена окон в&nbsp;них предполагает установку более качественных, дорогих, но&nbsp;и&nbsp;более защищённых конструкций<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>особенно для внешнего фасада). В&nbsp;первую очередь следует отдавать предпочтение предложениям с&nbsp;повышенной шумоизоляцией:</p>
<ul><li>двухкамерные стеклопакеты высокой звукоизоляции<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>32 дБ&nbsp;и&nbsp;более) с&nbsp;несимметричными камерами или заполненные инертным газом;</li>
<li>пятикамерные<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>и&nbsp;выше) профили с&nbsp;шумовой защитой на&nbsp;ниже 3-го класса<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>коэффициент звукоизоляции от&nbsp;35 дБ)</li>
<li>три и&nbsp;более контура уплотнения.</li></ul></strong></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии П-55: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/087x142H216WN(G).png" alt="Окно на балкон для серии П-30, П-46 и П-55. Размер 870x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно на балкон для серии П-30, П-46 и П-55. Размер 870x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:100px;min-width:13ex;">
<nobr>870×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно на балкон для серии П-30, П-46 и П-55<br />
<a href="/tsena-odnogo-okna/870x1420mm/tip12">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/067x216H216D-(L).png" alt="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:77px;min-width:13ex;">
<nobr>670×2160&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4<br />
<a href="/tsena-odnogo-okna/670x2160mm/tip16">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/147x142H216W-(G)(L_).png" alt="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:170px;min-width:13ex;">
<nobr>1470×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ<br />
<a href="/tsena-odnogo-okna/1470x1420mm/tip1">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/206x142H216W-(G)(G)(L).png" alt="Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4. Размер 2060x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4. Размер 2060x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:238px;min-width:13ex;">
<nobr>2060×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно трёхстворчатое для серии КОПЭ, П-55 и ПД-4<br />
<a href="/tsena-odnogo-okna/2060x1420mm/tip10">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии П-55</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия П-55: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1911",1,"color: #999b99"],
["1926",1,"color: #999b99"],
["1938",1,"color: #999b99"],
["1958",1,"color: #999b99"],
["1959",1,"color: #999b99"],
["1960",1,"color: #999b99"],
["1961",1,"color: #999b99"],
["1965",1,"color: #999b99"],
["1966",1,"color: #999b99"],
["1967",2,"color: #999d99"],
["1972",1,"color: #999b99"],
["1981",9,"color: #99ac99"],
["1982",4,"color: #99a199"],
["1983",7,"color: #99a899"],
["1984",8,"color: #99aa99"],
["1985",6,"color: #99a699"],
["1986",5,"color: #99a499"],
["1987",12,"color: #99b399"],
["1988",5,"color: #99a499"],
["1989",7,"color: #99a899"],
["1990",5,"color: #99a499"],
["1991",8,"color: #99aa99"],
["1992",13,"color: #99b599"],
["1993",8,"color: #99aa99"],
["1994",16,"color: #99bc99"],
["1995",23,"color: #99cc99"],
["1996",4,"color: #99a199"],
["1997",10,"color: #99af99"],
["1998",2,"color: #999d99"],
["1999",4,"color: #99a199"],
["2000",4,"color: #99a199"],
["2001",3,"color: #999f99"],
["2002",3,"color: #999f99"],
["2003",4,"color: #99a199"],
["2004",4,"color: #99a199"],
["2005",2,"color: #999d99"],
["2006",5,"color: #99a499"],
["2009",1,"color: #999b99"],
["2011",1,"color: #999b99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии П-55 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии П-55 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.984295,37.165136],[55.988117,37.157159],[55.700628,37.851754],[55.699218,37.854449],[55.775322,37.489850],[55.758737,37.820825],[55.758311,37.820502],[55.747844,37.817313],[55.870950,37.569135],[55.872885,37.568309],[55.874804,37.567536],[55.876046,37.566916],[55.877617,37.566368],[55.878692,37.566162],[55.876748,37.709488],[55.682234,37.855581],[55.545992,37.529852],[55.630944,37.479906],[55.629450,37.478127],[55.628647,37.475531],[55.543516,37.511544],[55.662273,37.532816],[55.661877,37.529807],[55.636356,37.747639],[55.634237,37.748601],[55.542202,37.512640],[55.686127,37.920871],[55.686051,37.857953],[55.683011,37.854404],[55.681250,37.852275],[55.852834,37.438071],[55.879662,37.571597],[55.806287,37.417994],[55.826068,37.807458],[55.636717,37.671166],[55.637088,37.667519],[55.637347,37.663836],[55.637459,37.660575],[55.636255,37.678649],[55.636448,37.675648],[55.864293,37.592258],[55.865621,37.593587],[55.795089,37.574022],[55.794953,37.572288],[55.587031,37.674777],[55.624281,37.664958],[55.623722,37.665884],[55.652105,37.744037],[55.724089,37.621390],[55.724900,37.621696],[55.724829,37.623151],[55.728322,37.622504],[55.722294,37.621534],[55.721265,37.623196],[55.726583,37.622064],[55.878117,37.698906],[55.877041,37.697783],[55.536405,37.580526],[55.537928,37.580921],[55.539574,37.581307],[55.772193,37.489571],[55.711584,37.755302],[55.712431,37.758554],[55.710788,37.752050],[55.742787,37.403621],[55.889386,37.675532],[55.890643,37.675163],[55.892117,37.674813],[55.859256,37.602058],[55.745407,37.785638],[55.703175,37.845547],[55.872546,37.590515],[55.846517,37.454753],[55.862878,37.447431],[55.865354,37.446470],[55.824187,37.803874],[55.824723,37.804790],[55.825285,37.805814],[55.878814,37.700882],[55.871147,37.590416],[55.717523,37.407295],[55.822837,37.757260],[55.823798,37.758275],[55.824026,37.759300],[55.741070,37.432232],[55.854517,37.683060],[55.879435,37.723115],[55.852501,37.680320],[55.784916,37.447917],[55.786465,37.447935],[55.856432,37.449641],[55.858554,37.448833],[55.800691,37.571704],[55.801283,37.571659],[55.801374,37.570330],[55.802664,37.569512],[55.802422,37.568713],[55.687066,37.566970],[55.682610,37.453765],[55.841134,37.527768],[55.841311,37.529151],[55.707912,37.481460],[55.706944,37.481864],[55.705858,37.480750],[55.705387,37.479950],[55.721128,37.567087],[55.822149,37.512074],[55.737461,37.584631],[55.724778,37.567069],[55.869849,37.660314],[55.828142,37.583661],[55.827100,37.585278],[55.826159,37.586778],[55.877304,37.679673],[55.875324,37.674535],[55.682305,37.454654],[55.681828,37.453693],[55.775251,37.642195],[55.788196,37.615066],[55.671747,37.746157],[55.703946,37.845098],[55.702368,37.848466],[55.545997,37.531927],[55.864783,37.475755],[55.689583,37.860477],[55.687731,37.859345],[55.567519,37.566961],[55.567519,37.566961],[55.567219,37.569171],[55.573831,37.582071],[55.577907,37.576843],[55.578503,37.574004],[55.578528,37.572603],[55.568313,37.587632],[55.569286,37.583472],[55.742874,37.852545],[55.742417,37.855734],[55.742990,37.858141],[55.743036,37.859111],[55.743406,37.862354],[55.744556,37.868014],[55.744733,37.869460],[55.745022,37.870430],[55.745448,37.872721],[55.745909,37.875056],[55.589274,37.640659],[55.648062,37.470042],[55.664218,37.747217],[55.668198,37.764007],[55.687335,37.564123],[55.677712,37.444440],[55.719906,37.412056],[55.852192,37.438206],[55.673184,37.816828],[55.865793,37.598250],[55.867667,37.592258],[55.862439,37.608859],[55.873541,37.705095],[55.683133,37.585449],[55.674199,37.748358],[55.673879,37.749508],[55.893970,37.542024],[55.875087,37.676205],[55.731881,37.589743],[55.830407,37.580104],[55.865384,37.679026],[55.676834,37.444826],[55.651242,37.725298],[55.869071,37.443488],[55.764420,37.702706],[55.740700,37.847990],[55.798303,37.402875],[55.798141,37.396497],[55.707781,37.742869],[55.707187,37.741360],[55.706776,37.740354],[55.718654,37.511275],[55.859670,37.499839],[55.826832,37.825290],[55.806125,37.614644],[55.539487,37.532187],[55.535121,37.517752],[55.535473,37.514967],[55.892345,37.541395],[55.664136,37.293927],[55.662928,37.291098],[55.896357,37.542356],[60.004600,30.452798],[60.004942,30.453840],[59.955741,30.428238],[59.963917,30.303004],[60.009008,30.432595],[55.749258,38.000147],[55.408900,37.559936],[55.681646,37.866082]];
let forURL = [1660,1663,6878,6879,6944,7456,7459,7470,8401,8403,8405,8409,8410,8411,9800,10490,10617,10839,10843,10848,11079,11114,11116,12716,12717,13016,13937,14399,14402,14407,14477,16716,16808,16943,16956,16974,16975,16984,16987,16999,17030,17033,17252,17254,19136,19303,19305,19398,19447,19448,19449,19450,19451,19455,19460,19590,19591,20434,20435,20436,20862,22802,22809,22843,23073,23107,23108,23109,23247,24241,25175,25787,26358,26397,26415,28657,28658,28659,29699,31165,32025,32105,32106,32107,32336,32752,32763,32776,2947,2951,26383,29217,3652,3653,3654,3655,3656,17278,4481,9536,9537,13347,13348,13349,13350,15973,16379,16453,17771,20473,20605,20607,20609,23111,23114,23272,25089,27185,28382,5961,6882,6883,10615,12184,14388,14391,14913,14914,14951,25727,27337,27343,27344,27366,27369,27692,27699,27702,27703,27706,27709,27710,27711,27713,27716,9481,10741,13453,13468,16493,21660,32013,14480,14676,15150,15166,15154,23337,15277,18265,18273,31484,19056,19361,20614,26023,23287,24133,26427,27086,27682,27903,27913,28142,28150,28148,28641,28969,29377,30281,30664,30689,30692,31476,101581,101583,31489,43357,43358,47186,52972,53615,71678,77269,94744];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии П-55</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии П-55 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии П-55</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>26772</strong> квартир.</li>
<li>Проживает <strong>31072</strong> семей <small>(<strong>171092</strong> человек)</small>.</li>
<li><strong>1724085.9 м²</strong> жилых помещений.</li>
<li><strong>232384.8 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>70828.3 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии П-55&nbsp;<strong>60.80%</strong>. Минимальный&nbsp;<strong>1.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;П-55, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,368 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:29:49.428154+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:29:49.428202+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:29:49.428224+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии 1Р-303: детальная информация" />
<meta name="keywords" content=" 1Р-303, серия 1Р-303, проект 1Р-303, года постройки зданий серии 1Р-303, размеры окон в домах серии 1Р-303, оконные проемы зданий серии 1Р-303, дома серии 1Р-303 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии 1Р-303 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия 1Р-303</li>
</ol>
<h1>СЕРИЯ 1Р-303</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии 1Р-303: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/062x132H210WN(G).png" alt="Окно одностворчатое на балкон для серии 1P-303. Размер 620x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно одностворчатое на балкон для серии 1P-303. Размер 620x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:73px;min-width:13ex;">
<nobr>620×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно одностворчатое на балкон для серии 1P-303<br />
<a href="/tsena-odnogo-okna/620x1320mm/tip73">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/120x132H210WN(G)(L_).png" alt="Окно двустворчатое на балкон для серии 1P-303. Размер 1200x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое на балкон для серии 1P-303. Размер 1200x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:142px;min-width:13ex;">
<nobr>1200×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Окно двустворчатое на балкон для серии 1P-303<br />
<a href="/tsena-odnogo-okna/1200x1320mm/tip74">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/068x210H210D-(G).png" alt="Дверь на балкон для серий 1P-303, 1P-303.16 и 1ЛГ-504. Размер 680x2100 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серий 1P-303, 1P-303.16 и 1ЛГ-504. Размер 680x2100 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:80px;min-width:13ex;">
<nobr>680×2100&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Дверь на балкон для серий 1P-303, 1P-303.16 и 1ЛГ-504<br />
<a href="/tsena-odnogo-okna/680x2100mm/tip77">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/128x132H210W-(G)(L).png" alt="Окно двустворчатое для серии МГ-601 и 1P-303. Размер 1280x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серии МГ-601 и 1P-303. Размер 1280x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:152px;min-width:13ex;">
<nobr>1280×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно двустворчатое для серии МГ-601 и 1P-303<br />
<a href="/tsena-odnogo-okna/1280x1320mm/tip52">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap4">
<div><img src="/static/img/_flap.cfg/186x132H210W-(G)(L_)(L).png" alt="Окно трёхстворчатое для серии 1P-303. Размер 1860x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии 1P-303. Размер 1860x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:221px;min-width:13ex;">
<nobr>1860×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markE.svg');"></span></nobr><br />
Окно трёхстворчатое для серии 1P-303<br />
<a href="/tsena-odnogo-okna/1860x1320mm/tip72">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии 1Р-303</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия 1Р-303: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1960",2,"color: #999e99"],
["1964",6,"color: #99aa99"],
["1965",6,"color: #99aa99"],
["1966",5,"color: #99a799"],
["1967",5,"color: #99a799"],
["1968",7,"color: #99ac99"],
["1969",6,"color: #99aa99"],
["1970",7,"color: #99ac99"],
["1971",10,"color: #99b599"],
["1972",7,"color: #99ac99"],
["1973",11,"color: #99b899"],
["1974",11,"color: #99b899"],
["1975",5,"color: #99a799"],
["1976",8,"color: #99af99"],
["1977",3,"color: #99a199"],
["1978",5,"color: #99a799"],
["1979",2,"color: #999e99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии 1Р-303 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии 1Р-303 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.476082,37.305048],[55.474919,37.303701],[56.014202,37.467644],[56.015701,37.463933],[56.014806,37.462900],[56.015877,37.462712],[56.015228,37.462505],[56.014705,37.462029],[56.014594,37.466772],[56.014947,37.465604],[55.650785,37.407268],[55.790762,37.966235],[55.790534,37.968886],[55.792706,37.960441],[55.791425,37.960414],[55.791218,37.961052],[55.791946,37.962445],[55.792792,37.964448],[55.791987,37.965616],[55.793288,37.968957],[55.893480,37.451088],[55.893415,37.450072],[56.369417,37.531586],[56.365553,37.532717],[56.369177,37.539958],[56.364486,37.532484],[56.364815,37.533086],[56.363892,37.534029],[56.364002,37.534981],[56.365523,37.539266],[56.366206,37.539724],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.348422,37.524992],[56.354193,37.549983],[56.341488,37.519647],[56.341318,37.520716],[56.341099,37.521776],[56.334408,37.535655],[56.334752,37.536526],[56.338509,37.546956],[56.336987,37.546911],[56.336423,37.545968],[56.337806,37.548061],[56.338444,37.547630],[56.337875,37.547288],[56.338130,37.548869],[56.341064,37.547270],[56.337257,37.552193],[56.337027,37.549327],[56.339682,37.544962],[56.338404,37.519126],[56.337716,37.515111],[56.340161,37.536212],[56.339732,37.538296],[56.355894,37.527741],[56.341702,37.518533],[56.339382,37.518785],[56.284079,37.486760],[56.283480,37.488269],[56.283405,37.487640],[55.939802,36.710148],[55.939958,36.711603],[55.939303,36.711828],[55.939504,36.712574],[55.940427,36.712583],[55.939313,36.709169],[55.938632,36.709421],[55.938859,36.710157],[55.906471,37.729997],[55.904195,37.726574],[55.901031,37.723825],[55.900153,37.722837],[55.899320,37.721840],[55.898492,37.722828],[55.906592,37.728649],[55.892092,37.715695],[55.892274,37.714923],[55.943240,37.777158],[55.907460,37.728631],[55.909060,37.725200],[55.908439,37.723690],[55.905719,37.731874],[55.906254,37.730940],[55.891850,37.716576],[56.458328,38.093087],[56.738616,37.532969],[56.738611,37.531631],[56.739031,37.530948],[56.739322,37.528172],[56.739994,37.528684],[56.741134,37.529376],[56.741573,37.529484],[56.742773,37.529430],[56.742462,37.538341],[56.725561,37.516126],[56.738942,37.528936],[56.740749,37.528531],[55.694885,37.750963],[56.047650,37.481855],[56.047042,37.481271],[56.046509,37.480256],[56.048329,37.482232],[56.047243,37.480714],[56.048053,37.482798],[56.046771,37.481729],[56.367946,37.536634],[56.319774,36.760005],[56.365069,37.538224],[56.366410,37.538898],[55.939857,36.713346],[55.942086,36.712133],[55.941556,36.712259],[55.941344,36.711630],[55.941133,36.710984],[55.939207,36.710957]];
let forURL = [2259,2263,75796,75797,75800,75802,75803,75804,75805,75807,14599,69570,69573,69963,69965,69966,69967,69968,69973,69976,81184,81199,86240,86246,86252,86260,86267,86272,86273,86275,86276,86283,86288,86290,86295,86296,86297,86299,86300,86301,86302,86304,86429,86449,86450,86451,86469,86470,86533,86540,86542,86544,86545,86546,86549,86550,86552,86554,86569,86570,86585,86595,86596,86613,86631,86677,86778,86779,86780,89386,89390,89391,89392,89394,89413,89414,89415,97269,97278,97290,97294,97298,97299,97308,97703,97704,98024,98059,98068,98069,98076,98079,98090,109134,111240,111241,111242,111247,111248,111249,111252,111257,111266,111302,114852,114853,114854,83160,83161,83162,83167,83169,83175,83176,86243,91347,86274,86277,89393,89395,89396,89397,89398,89416];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии 1Р-303</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии 1Р-303 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии 1Р-303</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>7899</strong> квартир.</li>
<li>Проживает <strong>9247</strong> семей <small>(<strong>45176</strong> человек)</small>.</li>
<li><strong>345222.8 м²</strong> жилых помещений.</li>
<li><strong>64146.2 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>0.0 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии 1Р-303&nbsp;<strong>60.00%</strong>. Минимальный&nbsp;<strong>10.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;1Р-303, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,379 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:30:35.978140+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:30:35.978187+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:30:35.978209+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии МГ-601: детальная информация" />
<meta name="keywords" content=" МГ-601, серия МГ-601, проект МГ-601, года постройки зданий серии МГ-601, размеры окон в домах серии МГ-601, оконные проемы зданий серии МГ-601, дома серии МГ-601 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии МГ-601 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия МГ-601</li>
</ol>
<h1>СЕРИЯ МГ-601</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии МГ-601: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/117x132H225WN(G).png" alt="Окно одностворчатое, балкон для серии МГ-601. Размер 1170x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно одностворчатое, балкон для серии МГ-601. Размер 1170x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:130px;min-width:13ex;">
<nobr>1170×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно одностворчатое, балкон для серии МГ-601<br />
<a href="/tsena-odnogo-okna/1170x1320mm/tip53">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/167x132H225WN(G)(L)(L).png" alt="Окно трёхстворчатое, балкон для серии МГ-601. Размер 1670x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое, балкон для серии МГ-601. Размер 1670x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:185px;min-width:13ex;">
<nobr>1670×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Окно трёхстворчатое, балкон для серии МГ-601<br />
<a href="/tsena-odnogo-okna/1670x1320mm/tip54">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/082x225H225D-(L).png" alt="Дверь на балкон для серии II-68 и МГ-601. Размер 820x2250 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серии II-68 и МГ-601. Размер 820x2250 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:91px;min-width:13ex;">
<nobr>820×2250&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Дверь на балкон для серии II-68 и МГ-601<br />
<a href="/tsena-odnogo-okna/820x2250mm/tip19">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/128x132H225W-(G)(L).png" alt="Окно двустворчатое для серии МГ-601 и 1P-303. Размер 1280x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серии МГ-601 и 1P-303. Размер 1280x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:142px;min-width:13ex;">
<nobr>1280×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно двустворчатое для серии МГ-601 и 1P-303<br />
<a href="/tsena-odnogo-okna/1280x1320mm/tip52">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap4">
<div><img src="/static/img/_flap.cfg/194x132H225W-(G)(L)(L).png" alt="Окно трёхстворчатое для серии МГ-601. Размер 1940x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии МГ-601. Размер 1940x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:215px;min-width:13ex;">
<nobr>1940×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markE.svg');"></span></nobr><br />
Окно трёхстворчатое для серии МГ-601<br />
<a href="/tsena-odnogo-okna/1940x1320mm/tip51">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap5">
<div><img src="/static/img/_flap.cfg/258x132H225W-(G)(L)(G)(L).png" alt="Окно четырёхстворчатое для серии МГ-601. Размер 2580x1320 (Ш х В, мм.). Типовая схема открывания." title="Окно четырёхстворчатое для серии МГ-601. Размер 2580x1320 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:286px;min-width:13ex;">
<nobr>2580×1320&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markF.svg');"></span></nobr><br />
Окно четырёхстворчатое для серии МГ-601<br />
<a href="/tsena-odnogo-okna/2580x1320mm/tip50">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии МГ-601</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия МГ-601: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1963",2,"color: #99a099"],
["1964",1,"color: #999c99"],
["1965",1,"color: #999c99"],
["1966",4,"color: #99a799"],
["1967",9,"color: #99b999"],
["1968",7,"color: #99b299"],
["1969",12,"color: #99c499"],
["1970",10,"color: #99bd99"],
["1971",13,"color: #99c899"],
["1972",14,"color: #99cc99"],
["1973",8,"color: #99b699"],
["1974",3,"color: #99a399"],
["1975",6,"color: #99ae99"],
["1976",4,"color: #99a799"],
["1977",1,"color: #999c99"],
["1978",1,"color: #999c99"],
["1979",3,"color: #99a399"],
["1988",1,"color: #999c99"],
["1993",1,"color: #999c99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии МГ-601 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии МГ-601 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.725919,37.465919],[55.725189,37.461885],[55.726644,37.469791],[55.746056,37.593542],[55.658830,37.497701],[55.659302,37.497153],[55.658820,37.496587],[55.659277,37.496057],[55.660815,37.487236],[55.657545,37.492994],[55.658865,37.490182],[55.660754,37.493021],[55.728327,37.520752],[55.749288,37.793894],[55.749623,37.793480],[55.750175,37.796490],[55.749841,37.796903],[55.748432,37.787004],[55.748098,37.787408],[55.681316,37.665857],[55.679138,37.665444],[55.674534,37.500576],[55.673854,37.499291],[55.673169,37.498016],[55.671727,37.495455],[55.668295,37.514607],[55.667213,37.513008],[55.666142,37.511356],[55.669366,37.516215],[55.753139,37.823772],[55.753022,37.824553],[55.775510,37.685988],[55.767681,37.666917],[55.749035,37.790318],[55.748706,37.790714],[55.709906,37.503846],[55.709429,37.502983],[55.708942,37.502148],[55.778669,37.476249],[55.680559,37.671399],[55.702495,37.669881],[55.675687,37.664824],[55.674306,37.665147],[55.675017,37.664985],[55.672422,37.496731],[55.670448,37.517761],[55.652415,37.598851],[55.651572,37.598878],[55.776391,37.687659],[55.710748,37.393542],[55.711072,37.394530],[55.711600,37.395697],[55.709186,37.475962],[55.630878,37.599552],[55.630583,37.598330],[55.709617,37.474695],[55.708668,37.474264],[55.703160,37.469719],[55.702652,37.467958],[55.703454,37.468021],[55.704681,37.460610],[55.705239,37.461499],[55.705767,37.460161],[55.704641,37.476717],[55.705138,37.475423],[55.704037,37.474794],[55.707537,37.467069],[55.706756,37.466027],[55.707755,37.465640],[55.857523,37.496345],[55.858710,37.494602],[55.855487,37.498276],[55.855775,37.497791],[55.856361,37.502444],[55.856790,37.502381],[55.857468,37.507574],[55.857705,37.506927],[55.658982,37.512559],[55.658413,37.513125],[55.658520,37.515039],[55.658048,37.514607],[55.656204,37.516144],[55.655742,37.515802],[55.859069,37.505651],[55.859281,37.504987],[55.859888,37.498716],[55.858347,37.500702],[55.860741,37.502992],[55.860524,37.503630],[55.653903,37.559541],[55.654295,37.559415],[55.637266,37.512793],[55.859413,37.498797],[55.797260,37.725217],[55.797776,37.728263],[55.796719,37.721993],[55.619411,37.592240],[55.691232,37.590874],[55.691775,37.590758],[59.829739,30.332676],[60.013344,30.260388]];
let forURL = [1239,1241,1246,3593,6780,6781,6782,6783,10315,10329,10341,10344,4321,12895,12896,12899,12900,13783,13784,6001,6002,6151,6162,6169,6181,6727,6737,6752,6869,7715,7716,11833,11972,12890,12891,21132,21133,21134,21596,27608,28404,6005,6013,6008,6174,6864,10704,10706,11836,12123,12124,12125,13388,30064,30065,13390,13391,20280,20282,20283,20295,20296,20297,20304,20305,20307,21687,21688,21689,19472,19475,19480,19483,29155,29156,29160,29161,22667,22670,22671,22675,22680,22681,22984,22985,28966,28972,28981,28984,29498,29500,23149,28964,29820,29824,29892,29980,30228,30229,40658,41168];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии МГ-601</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии МГ-601 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии МГ-601</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>13011</strong> квартир.</li>
<li>Проживает <strong>13342</strong> семей <small>(<strong>57998</strong> человек)</small>.</li>
<li><strong>654281.7 м²</strong> жилых помещений.</li>
<li><strong>89075.3 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>22511.2 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии МГ-601&nbsp;<strong>42.00%</strong>. Минимальный&nbsp;<strong>14.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;МГ-601, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
@@ -0,0 +1,362 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:30:12.705452+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:30:12.705501+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:30:12.705527+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии ГМС-2001: детальная информация" />
<meta name="keywords" content=" ГМС-2001, серия ГМС-2001, проект ГМС-2001, года постройки зданий серии ГМС-2001, размеры окон в домах серии ГМС-2001, оконные проемы зданий серии ГМС-2001, дома серии ГМС-2001 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии ГМС-2001 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия ГМС-2001</li>
</ol>
<h1>СЕРИЯ ГМС-2001</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии ГМС-2001: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/116x142H216WN(G)(L_).png" alt="Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ. Размер 1160x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:134px;min-width:13ex;">
<nobr>1160×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно двустворчатое, балкон для серий ГМС-1, П-44, ПД-4 и КОПЭ<br />
<a href="/tsena-odnogo-okna/1160x1420mm/tip2">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/146x142H216WN(G)(L_).png" alt="Окно двустворчатое, балкон для серии КОПЭ и П-44T. Размер 1460x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, балкон для серии КОПЭ и П-44T. Размер 1460x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:168px;min-width:13ex;">
<nobr>1460×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Окно двустворчатое, балкон для серии КОПЭ и П-44T<br />
<a href="/tsena-odnogo-okna/1460x1420mm/tip8">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/067x216H216D-(L).png" alt="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4. Размер 670x2160 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:77px;min-width:13ex;">
<nobr>670×2160&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Дверь на балкон для серии ГМС-1, П-3, П-42, П-43, П-55 и ПД-4<br />
<a href="/tsena-odnogo-okna/670x2160mm/tip16">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/077x142H216W-(G).png" alt="Окно одностворчатое для серий ГМС-1. Размер 770x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно одностворчатое для серий ГМС-1. Размер 770x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:89px;min-width:13ex;">
<nobr>770×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно одностворчатое для серий ГМС-1<br />
<a href="/tsena-odnogo-okna/770x1420mm/tip46">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap4">
<div><img src="/static/img/_flap.cfg/147x142H216W-(G)(L_).png" alt="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ. Размер 1470x1420 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:170px;min-width:13ex;">
<nobr>1470×1420&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markE.svg');"></span></nobr><br />
Окно двустворчатое для ГМС-1, П-30/44/46/55, ПД-4, 1-504 и КОПЭ<br />
<a href="/tsena-odnogo-okna/1470x1420mm/tip1">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии ГМС-2001</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия ГМС-2001: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["2003",5,"color: #99ae99"],
["2004",7,"color: #99b699"],
["2005",6,"color: #99b299"],
["2006",5,"color: #99ae99"],
["2007",5,"color: #99ae99"],
["2008",8,"color: #99bb99"],
["2009",12,"color: #99cc99"],
["2010",8,"color: #99bb99"],
["2011",10,"color: #99c399"],
["2012",2,"color: #99a199"],
["2013",3,"color: #99a599"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии ГМС-2001 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии ГМС-2001 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.820182,37.873143],[55.698203,37.914915],[55.698903,37.915831],[55.700735,37.917484],[55.658068,37.602067],[55.842302,37.550890],[55.843555,37.553073],[55.844667,37.556208],[55.845213,37.556235],[55.866031,37.472135],[55.866389,37.473168],[55.682468,37.928318],[55.713537,37.402794],[55.714090,37.401662],[55.713922,37.400719],[55.872097,37.558526],[55.876496,37.485969],[55.877157,37.485807],[55.544290,37.565380],[55.544036,37.566072],[55.844177,37.548896],[55.841807,37.549597],[55.670153,37.791145],[55.669650,37.790507],[55.505159,37.576492],[55.671153,37.791944],[55.672326,37.794379],[55.681128,37.924230],[55.681275,37.926862],[55.532029,37.502786],[55.701815,37.915382],[55.700826,37.914367],[55.712964,37.894020],[55.714247,37.887875],[55.922404,37.542599],[55.923392,37.543120],[55.927694,37.545276],[55.928718,37.544009],[55.926469,37.540138],[55.419136,37.495123],[55.417526,37.496758],[55.421987,37.483211],[55.421767,37.482178],[55.421118,37.481639],[55.415324,37.481001],[55.415027,37.483930],[55.414910,37.481819],[55.833461,37.286840],[55.833137,37.285295],[55.832586,37.288142],[55.878248,37.509478],[55.879571,37.511212],[55.826584,37.593650],[55.827530,37.593605],[55.827408,37.595330],[55.713755,37.889762],[55.668655,37.789914],[55.713136,37.891657],[55.745042,37.986313],[55.745068,37.983321],[55.744835,37.984884],[55.743603,37.985630],[55.742585,37.985073],[55.744110,37.982782],[55.416887,37.480939],[55.416346,37.480678],[55.415860,37.481208],[55.418252,37.499480],[55.419008,37.498959],[55.419861,37.498788],[55.420219,37.497683]];
let forURL = [3325,6419,6425,6428,10726,11198,11201,11208,11209,12167,12171,13930,14103,14118,14119,15680,15777,15778,16681,16682,19168,19173,19733,19734,20017,20210,20211,21700,21701,23098,25893,25915,26433,26444,31497,31499,31503,31504,31509,77303,77304,77322,77324,77325,77340,77500,77501,92345,92346,92348,11723,11724,19721,19722,19723,26448,20206,26450,71418,71419,71420,71421,71422,71423,77333,77336,77338,78458,78459,78473,78474];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии ГМС-2001</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии ГМС-2001 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии ГМС-2001</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>12585</strong> квартир.</li>
<li>Проживает <strong>18198</strong> семей <small>(<strong>64618</strong> человек)</small>.</li>
<li><strong>862529.2 м²</strong> жилых помещений.</li>
<li><strong>188963.6 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>28750.5 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии ГМС-2001&nbsp;<strong>8.10%</strong>. Минимальный&nbsp;<strong>1.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;ГМС-2001, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,357 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:30:08.002217+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:30:08.002293+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:30:08.002332+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии II-66: детальная информация" />
<meta name="keywords" content=" II-66, серия II-66, проект II-66, года постройки зданий серии II-66, размеры окон в домах серии II-66, оконные проемы зданий серии II-66, дома серии II-66 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии II-66 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия II-66</li>
</ol>
<h1>СЕРИЯ II-66</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии II-66: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/137x154H222WN(G)(L_).png" alt="Окно двустворчатое, балкон, для серий II-66. Размер 1370x1540 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, балкон, для серий II-66. Размер 1370x1540 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:154px;min-width:13ex;">
<nobr>1370×1540&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно двустворчатое, балкон, для серий II-66<br />
<a href="/tsena-odnogo-okna/1370x1540mm/tip56">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/068x222H222D-(L).png" alt="Дверь на балкон для серии 1-447, 1-464, 1-605 и II-66. Размер 680x2220 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон для серии 1-447, 1-464, 1-605 и II-66. Размер 680x2220 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:76px;min-width:13ex;">
<nobr>680×2220&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Дверь на балкон для серии 1-447, 1-464, 1-605 и II-66<br />
<a href="/tsena-odnogo-okna/680x2220mm/tip32">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/127x154H222W-(G_)(L).png" alt="Окно двустворчатое для серии II-66. Размер 1270x1540 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серии II-66. Размер 1270x1540 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:143px;min-width:13ex;">
<nobr>1270×1540&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Окно двустворчатое для серии II-66<br />
<a href="/tsena-odnogo-okna/1270x1540mm/tip55">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии II-66</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия II-66: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1971",1,"color: #999f99"],
["1972",1,"color: #999f99"],
["1973",1,"color: #999f99"],
["1974",1,"color: #999f99"],
["1975",3,"color: #99ac99"],
["1976",2,"color: #99a599"],
["1978",2,"color: #99a599"],
["1979",3,"color: #99ac99"],
["1980",3,"color: #99ac99"],
["1981",8,"color: #99cc99"],
["1982",6,"color: #99bf99"],
["1983",8,"color: #99cc99"],
["1984",6,"color: #99bf99"],
["1985",3,"color: #99ac99"],
["1986",2,"color: #99a599"],
["1987",7,"color: #99c599"],
["1988",1,"color: #999f99"],
["1989",2,"color: #99a599"],
["1990",2,"color: #99a599"],
["1991",1,"color: #999f99"],
["1994",2,"color: #99a599"],
["1995",1,"color: #999f99"],
["1998",1,"color: #999f99"],
["2005",1,"color: #999f99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии II-66 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии II-66 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.895298,37.535026],[55.591986,37.669953],[55.771925,37.572369],[55.770071,37.572980],[55.770218,37.573546],[55.588415,37.669046],[55.588349,37.670034],[55.814113,37.967547],[55.814548,37.968355],[55.627768,37.864780],[55.627961,37.863504],[55.939807,37.497836],[55.431238,37.505876],[55.431856,37.506235],[55.432490,37.506415],[55.891042,37.410421],[55.890487,37.410879],[55.889876,37.411364],[55.890275,37.482358],[55.882444,37.417769],[55.883080,37.416844],[55.881172,37.419682],[55.881798,37.418721],[55.892642,37.365272],[55.815696,37.314526],[55.815362,37.314050],[55.814973,37.313618],[55.825679,37.314732],[55.826862,37.312819],[55.828061,37.310663],[55.824445,37.316825],[55.678352,37.880779],[55.675737,37.870376],[55.692064,37.888989],[55.905169,37.727724],[55.899239,37.716468],[55.899668,37.716333],[55.915251,37.773385],[55.915659,37.773340],[55.921365,37.784964],[55.925021,37.766747],[55.925354,37.766612],[55.923917,37.761330],[55.922399,37.789743],[55.923554,37.719459],[55.924159,37.720672],[55.917127,37.745349],[55.917647,37.744459],[55.905951,37.716459],[55.905003,37.715381],[55.903474,37.711707],[55.912783,37.750119],[55.914156,37.751376],[55.912748,37.718830],[55.912143,37.717752],[55.911568,37.716692],[55.913798,37.720807],[55.913338,37.719873],[55.677951,37.257680],[55.677605,37.258237],[55.676189,37.259297],[56.037503,37.245948],[56.037227,37.245867],[54.884239,38.060774],[54.884239,38.060774],[54.884514,38.090437],[54.879645,38.062876],[54.879422,38.066514],[54.879479,38.065275],[54.884327,38.062059],[55.907753,37.719019],[55.906920,37.717573],[55.903474,37.711707],[55.914862,37.752032]];
let forURL = [564,12389,15033,15035,15036,18916,18917,69404,69410,70384,70385,70734,77137,77138,77140,80836,80837,80848,80997,81148,81149,81173,81180,81484,92491,92492,92493,92503,92507,92516,92537,94721,94725,95117,97275,97345,97346,97412,97413,97447,97564,97565,97570,97612,97648,97649,97660,97662,97763,97765,97770,98136,98139,98192,98197,98198,98236,98237,101184,101186,101187,110400,110401,110566,110567,110765,110772,110775,110777,110818,114847,114848,114849,114850];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии II-66</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии II-66 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии II-66</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>4295</strong> квартир.</li>
<li>Проживает <strong>5432</strong> семей <small>(<strong>28954</strong> человек)</small>.</li>
<li><strong>239948.6 м²</strong> жилых помещений.</li>
<li><strong>19670.9 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>0.0 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии II-66&nbsp;<strong>40.00%</strong>. Минимальный&nbsp;<strong>3.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;II-66, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
@@ -0,0 +1,382 @@
<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="2023-01-18T00:29:30.132829+03:00" />
<meta http-equiv="Last-Modified" content="2023-01-18T00:29:30.133023+03:00" />
<meta http-equiv="Expires" content="2023-01-18T00:29:30.133044+03:00" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Дома серии 1-515/9: детальная информация" />
<meta name="keywords" content=" 1-515/9, серия 1-515/9, проект 1-515/9, года постройки зданий серии 1-515/9, размеры окон в домах серии 1-515/9, оконные проемы зданий серии 1-515/9, дома серии 1-515/9 на карте, установка окон, цены на пластиковые окна" />
<meta name="author" content="OKNARDIA.RU" />
<meta name="copyright" lang="ru" content="OKNARDIA.RU" />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="Dynamic" />
<meta name="generator" content="OKNARDIA 0.3β by Python/Django" />
<title>Дома серии 1-515/9 — типовые проёмы, размеры окон, схемы открывания, планировки, здания на карте, история и статистика : ОКНАРДИЯ</title>
<link rel="alternate" href="https://oknardia.ru" hreflang="ru-ru" />
<link href="/static/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet" type="text/css" />
<link href="/static/css/oknardia1.css" rel="stylesheet" type="text/css" />
<script src="/static/js/jquery-2.1.1.min.js" type="text/javascript"></script>
<script src="/static/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(window).load(function () {
let images = $('.half');
images.each(function (i) {
$(this).width($(this).width() / 2);
});
});
</script>
<script type="text/javascript">$(document).ready(function(){ $('#login-logout').load('/login-logout' ); })</script>
</head>
<body style="padding-top:70px;">
<!--- Контент НАЧАЛО --->
<div class="container-fluid">
<div class="row">
<div class="col-md-11 col-xs-12">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/catalog/seria/">Типовые серии домов</a></li>
<li>Серия 1-515/9</li>
</ol>
<h1>СЕРИЯ 1-515/9</h1>
</div>
</div>
<div class="row">
<div class="col-md-12"></div>
</div>
<div class="row">
<div class="col-lg-10">
<h2 class="header">Дома серии 1-515/9: типовые размеры и схемы открывания</h2>
</div>
<div class="col-lg-12" style="padding:1em 0 0 0;margin-left:-1em">
<div class="win_discr pull-left" id="flap0">
<div><img src="/static/img/_flap.cfg/073x153H225WN(G).png" alt="Окно на балкон/лоджию для серии 1-515/9Ш и И-209А. Размер 730x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно на балкон/лоджию для серии 1-515/9Ш и И-209А. Размер 730x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:81px;min-width:13ex;">
<nobr>730×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markA.svg');"></span></nobr><br />
Окно на балкон/лоджию для серии 1-515/9Ш и И-209А<br />
<a href="/tsena-odnogo-okna/730x1530mm/tip36">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap1">
<div><img src="/static/img/_flap.cfg/132x153H225WN(G)(L_).png" alt="Окно двустворчатое, балкон, для серий II-18, II-68 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, балкон, для серий II-18, II-68 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:146px;min-width:13ex;">
<nobr>1320×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markB.svg');"></span></nobr><br />
Окно двустворчатое, балкон, для серий II-18, II-68 и 1-515/9<br />
<a href="/tsena-odnogo-okna/1320x1530mm/tip22">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap2">
<div><img src="/static/img/_flap.cfg/076x225H225D-(L).png" alt="Дверь на балкон/лоджию для серии II-18, II-57, И-209А и 1-515/9. Размер 760x2250 (Ш х В, мм.). Типовая схема открывания." title="Дверь на балкон/лоджию для серии II-18, II-57, И-209А и 1-515/9. Размер 760x2250 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:84px;min-width:13ex;">
<nobr>760×2250&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markC.svg');"></span></nobr><br />
Дверь на балкон/лоджию для серии II-18, II-57, И-209А и 1-515/9<br />
<a href="/tsena-odnogo-okna/760x2250mm/tip37">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap3">
<div><img src="/static/img/_flap.cfg/132x153H225W-(G)(L_).png" alt="Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9. Размер 1320x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:146px;min-width:13ex;">
<nobr>1320×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markD.svg');"></span></nobr><br />
Окно двустворчатое для серий II-18, II-68, II-49, К-7 и 1-515/9<br />
<a href="/tsena-odnogo-okna/1320x1530mm/tip23">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap4">
<div><img src="/static/img/_flap.cfg/149x113H225W-(G)(L).png" alt="Окно двустворчатое, кухня для серии 1-515/9. Размер 1490x1130 (Ш х В, мм.). Типовая схема открывания." title="Окно двустворчатое, кухня для серии 1-515/9. Размер 1490x1130 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:165px;min-width:13ex;">
<nobr>1490×1130&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markE.svg');"></span></nobr><br />
Окно двустворчатое, кухня для серии 1-515/9<br />
<a href="/tsena-odnogo-okna/1490x1130mm/tip35">цены только этого типового окна</a>
</div>
</div>
<div class="win_discr pull-left" id="flap5">
<div><img src="/static/img/_flap.cfg/188x153H225W-(G_)(G_)(L).png" alt="Окно трёхстворчатое для серии К9 и 1-515/9Ш. Размер 1880x1530 (Ш х В, мм.). Типовая схема открывания." title="Окно трёхстворчатое для серии К9 и 1-515/9Ш. Размер 1880x1530 (Ш х В, мм.). Типовая схема открывания." itemprop="image" /></div>
<div class="caption" style="width:208px;min-width:13ex;">
<nobr>1880×1530&thinsp;мм.</nobr><br />
<nobr><b>1&thinsp;шт.</b><span class="color-bullet" style="background-image:url('/static/img/svg/markF.svg');"></span></nobr><br />
Окно трёхстворчатое для серии К9 и 1-515/9Ш<br />
<a href="/tsena-odnogo-okna/1880x1530mm/tip38">цены только этого типового окна</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<h3 class="header">Оконные проёмы в типовых квартирах <nobr>серии 1-515/9</nobr></h3>
</div>
<div class="col-lg-8 col-xs-12 col-md-offset-1">
<!--- прешаблон начало ---><table style="padding:2px;">{% for row in TABLE_OF_WINDOWS %}
<tr class="tr2">
<td>{{ row.APART_NAME|safe }}</td>{% for col in row.WIN_IN_APART %}
<td class="cntr">{% if col.WIN_ID %}<nobr title="{{ col.WIN_Q }} × {{ col.WIN_DESCRIPTION }}: {{ col.WIN_WIDTH }}шт.: {{ col.WIN_HEIGHT }} (Ш×В, см.). Схема открывания: {{ col.WIN_FLAPCFG }}">{% for I_II in col.WIN_NUM %}<span style="background-image:url('/static/img/svg/mark{{ I_II }}.svg');">&nbsp;</span>{% endfor %}</nobr>{% else %}—{% endif %}</td>{% endfor %}
<td style="background:#f9f9f9;"><a href="#{{ row.APART_ID }}" class="badge" title="Оконных предложений для квартиры: {{ row.NUM_OFFERS }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ row.NUM_OFFERS }}</a></td>
</tr>{% endfor %}
<tr class="trZ">
<td style="font-size: xx-small;vertical-align:text-top">© 2015-2023, данные: oknardia.ru</td>{% for i in WIN_OFFER_AND_MERCHANT %}
<td class="cntr" style="background:#f9f9f9;"><a href="/tsena-odnogo-okna/{{ i.WIN_W|floatformat:0 }}0x{{ i.WIN_H|floatformat:0 }}0mm/tip{{ i.WIN_ID }}" class="badge" title="Ценовых предложений для окна: {{ i.WIN_OFFER }}"><small class="glyphicon glyphicon-tags" aria-hidden="true"></small>&nbsp;{{ i.WIN_OFFER }}</a></td>{% endfor %}
<td></td>
</tr>
</table>
<!--- прешаблон конец ---></div>
</div>
<div class="row">
<div class="col-md-9"><a name="s_graph"></a>
<h2 class="header">Здания серия 1-515/9: ввод в&nbsp;эксплуатацию по&nbsp;годам</h2>
</div>
<div class="col-md-9 col-md-offset-1" style="height:300px;font-size:large;">
<script type="text/javascript" src="https://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
// google.charts.load('current', {'packages':['bar']});
// google.charts.setOnLoadCallback(drawChart);
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
let data = google.visualization.arrayToDataTable([
["Год", "Введено в эксплуатацию", {role:'style'}],
["1968",4,"color: #99a799"],
["1969",11,"color: #99c199"],
["1970",8,"color: #99b699"],
["1971",6,"color: #99ae99"],
["1972",7,"color: #99b299"],
["1973",14,"color: #99cc99"],
["1974",11,"color: #99c199"],
["1975",9,"color: #99b999"],
["1976",5,"color: #99ab99"],
["1977",4,"color: #99a799"],
["1978",3,"color: #99a399"],
["1979",7,"color: #99b299"],
["1980",1,"color: #999c99"],
["1981",7,"color: #99b299"],
["1982",2,"color: #99a099"],
["1984",1,"color: #999c99"],
["1985",1,"color: #999c99"],
["1986",1,"color: #999c99"],
["1987",1,"color: #999c99"],
["1989",1,"color: #999c99"],
["1990",1,"color: #999c99"],
["1993",1,"color: #999c99"]
]);
let view = new google.visualization.DataView(data);
view.setColumns([0, 1,
{ calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation" },
2
]);
let options = {
animation:{
duration: 1500,
easing: 'in',
startup: true
},
backgroundColor: "#EEEEEE",
bar: {groupWidth: "76.4%"},
chartArea: {left: "2%", top: "5%", width: '96%', height: '85%'},
dataOpacity: 0.76,
explorer:{
maxZoomIn: 0.20,
maxZoomOut: 32 },
vAxis: {
baselineColor:'grey',
gridlines:{color: 'silver', count: 7},
minorGridlines:{color: '#dddddd', count: 3},
textPosition: 'in',
textStyle: {fontSize: 10}
},
hAxis: { textStyle: {fontSize: 10} },
isStacked: true,
tooltip: {
textStyle:{color: 'grey', fontSize: 10 },
trigger: 'selection'
},
annotations: {textStyle: { fontSize: 8, bold: true, color: 'black', opacity: 0.8 }},
legend: { position: "none" }
};
let chart = new google.visualization.ColumnChart(document.getElementById("graph"));
chart.draw(data, options);
}
</script>
<div id="graph" style="width:100%;height:100%">
<p>Для отображения гистограммы ввода в&nbsp;эксплуатацию зданий серии 1-515/9 нужна поддержка SVG.</p>
<noscript>
<p>Для визуализации отображения картографической информации с&nbsp;помощью Google.Charts нужно включить поддержку JavaScript.</p>
</noscript></div>
</div>
<div class="col-md-9 col-md-offset-1">
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
</div>
<div class="row">
<div class="col-md-7"><a name="s_map"></a>
<h2 class="header">Строения серии 1-515/9 на&nbsp;карте</h2>
</div>
<div class="col-md-7 col-lg-offset-1">
<p><small>Чтобы посмотреть цены на&nbsp;установку и&nbsp;замену окон от&nbsp;партнёров &laquo;Окнардия&raquo; в&nbsp;своей квартире: найдите дом на&nbsp;карте; кликните на&nbsp;него; перейдите по&nbsp;ссылке &laquo;Смотреть коммерческие предложения&raquo;. При необходимости смените типовую планировку квартиры (на&nbsp;странице ценовой выдачи, справа от&nbsp;изображения типовых проёмов и&nbsp;схем открывания).</small></p>
<div style="height:350px;">
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
<script type="text/javascript">
let points = [[55.706944,37.827266],[55.621470,37.597926],[56.121496,37.057958],[55.868299,37.618947],[55.935370,37.549444],[56.006507,37.792510],[55.676448,37.745322],[55.675418,37.745295],[55.839673,37.418128],[55.840674,37.419539],[55.755824,37.826422],[55.756158,37.828739],[55.586390,37.664348],[55.585911,37.664860],[55.579556,37.666126],[55.589376,37.642123],[55.869455,37.442428],[55.875935,37.646274],[55.873142,37.647100],[55.872784,37.612829],[55.874067,37.623196],[55.873461,37.626070],[55.670031,37.649741],[55.668701,37.649418],[55.580034,37.663530],[55.680098,37.646786],[55.608287,37.707063],[55.607595,37.707000],[55.705102,37.792016],[55.612263,37.702715],[55.679164,37.759380],[55.714729,37.734425],[55.902374,37.711374],[55.902318,37.707575],[56.395522,37.994892],[56.395307,37.993257],[56.395063,37.991793],[55.585438,37.665390],[55.584451,37.667267],[55.599524,37.654107],[55.579811,37.664833],[55.583749,37.666459],[55.663984,37.743768],[55.861767,37.427920],[55.718334,37.731946],[55.620886,37.601627],[55.621292,37.600495],[55.874309,37.557367],[55.591299,37.661823],[55.619335,37.604232],[55.676149,37.743813],[55.677732,37.757620],[55.678336,37.758150],[55.678595,37.767016],[55.675636,37.747756],[55.795256,37.686204],[55.744865,37.993607],[55.745787,38.006606],[56.015017,37.460762],[55.715256,37.729484],[55.715576,37.730697],[55.715890,37.731775],[55.716711,37.732027],[55.695225,37.742106],[55.580854,37.666126],[55.757207,37.834354],[55.753767,37.834174],[55.753757,37.835144],[55.753737,37.836106],[55.757197,37.835324],[55.757182,37.836276],[55.755601,37.834273],[55.755581,37.835234],[55.755566,37.836195],[55.751898,37.835099],[55.779580,37.477759],[55.679560,37.758626],[55.678930,37.758383],[55.678570,37.759147],[55.678174,37.759030],[55.680153,37.759704],[55.747692,38.004980],[55.715515,37.734156],[55.872410,37.467751],[55.680270,37.766729],[55.883929,37.535188],[55.876789,37.535448],[55.878839,37.534739],[55.750976,37.834300],[55.766400,37.714222],[55.678580,37.673268],[55.873577,37.652157],[55.704621,37.738054],[55.666924,37.571408],[55.667396,37.574435],[55.826215,37.751287],[55.678692,37.680616],[55.876688,37.556846],[55.824243,37.808006],[55.795393,37.973709],[55.704854,37.362819],[55.666381,37.290774],[55.666452,37.289418],[55.666457,37.287891],[55.705092,37.365361],[56.121496,37.057958],[56.121496,37.057958]];
let forURL = [1058,15349,110408,1076,2725,3340,5957,5958,9077,9078,9183,9186,12400,12402,20810,9480,26428,9706,9752,9824,9854,9889,10984,10988,20808,21377,896,897,11095,15446,22449,26285,97772,98224,114886,114887,114888,12404,12409,17059,20809,12410,13444,13597,14855,15344,15345,15685,17057,17349,18206,18221,22427,18230,18262,23260,71398,71741,75466,19434,19436,19438,19439,19607,20811,21004,21021,21022,21023,21005,21006,21010,21011,21012,21032,21599,22423,22424,22425,22428,22445,71590,26286,26855,26917,27148,27161,27166,27293,27443,27607,27741,28186,29616,29641,32103,593,15687,16936,69952,102416,101316,101317,101318,102399,110409,110410];
ymaps.ready(function () {
let myMap = new ymaps.Map('SeriaMap', {
center: [55.75, 37.57],
zoom: 10,
behaviors: ['default', 'scrollZoom'],
controls: [ 'rulerControl', 'zoomControl', 'geolocationControl', 'fullscreenControl' ]
});
// Создадим кластеризатор, вызвав функцию-конструктор.
clusterer = new ymaps.Clusterer({
preset: 'islands#invertedGrayClusterIcons',
groupByCoordinates: false,
hasHint: false,
viewportMargin: 0,
zoomMargin: 16,
clusterDisableClickZoom: false,
gridSize: 80
});
geoObjects = [];
add_str1 = '<a href="/';
add_str2 = '/0/">Смотреть коммерческие предложения</a>';
add_str3 = '<b>Здание серии 1-515/9</b>';
// Данные передаются в конструктор метки.
for(var i = 0, len = points.length; i < len; i++) {
geoObjects[i] = new ymaps.Placemark( points[i],
{ // Содержимое иконки, балуна и хинта.
balloonContent: add_str1 + forURL[i] + add_str2,
hintContent: add_str3
},
{ preset:'islands#circleIcon',iconColor: 'silver'} );
geoObjects[i].events
.add('mouseenter', function (e) {
e.get('target').options.set('preset', 'islands#yellowCircleIcon');
})
.add('mouseleave', function (e) {
e.get('target').options.set('preset', 'islands#grayCircleIcon');
});
}
// Добавляем метки в кластеризатор.
clusterer.add(geoObjects);
myMap.geoObjects.add(clusterer);
// позиционирование карты так, чтобы на ней были видны все объекты кластера.
myMap.setBounds(clusterer.getBounds(), { checkZoomRange: true });
});
</script>
<div id="SeriaMap" style="height:100%;width:100%;">
<noscript>
<p>Для отображения картографических данных по серии 1-515/9 с&nbsp;помощью &laquo;Яндекс.Карт&raquo; нужно включить поддержку JavaScript.</p>
</noscript>
</div></div>
<div style="font-size: xx-small;float: right">© 2015-2023, данные: oknardia.ru</div>
</div>
<diV class="col-md-4">
<h3 class="header">Статистика <nobr>серии 1-515/9</nobr></h3>
<p>Совокупно во&nbsp;всех зданиях типового проекта:</p>
<ul>
<li><strong>9781</strong> квартир.</li>
<li>Проживает <strong>18646</strong> семей <small>(<strong>85972</strong> человек)</small>.</li>
<li><strong>760689.2 м²</strong> жилых помещений.</li>
<li><strong>68401.4 м²</strong>&nbsp;— муниципальное жильё.</li>
<li><strong>43667.6 м²</strong> занимают государственные и&nbsp;городские службы, учреждения бытового обслуживания, магазины, офисы и&nbsp;тому подобное.</li>
<li>Максимальный износ жилого фонда серии 1-515/9&nbsp;<strong>46.00%</strong>. Минимальный&nbsp;<strong>10.00%</strong>. </li>
</ul>
</diV>
</div>
<div class="row">
<div class="col-md-4 col-lg-offset-8" style="margin-top: 1em;">
<h5>Информация о&nbsp;других, отличных от&nbsp;1-515/9, типовых сериях в&nbsp;базе &laquo;Окнардия&raquo;, типовых планировках квартир и&nbsp;оконных проёмах в&nbsp;них, а&nbsp;также рекомендации по&nbsp;замене&nbsp;окон:</h5>
<div class="href_d"><span><a href="/catalog/seria/1-335/all210/"><nobr>1-335</nobr></a></span><span><a href="/catalog/seria/1-447/all379/"><nobr>1-447</nobr></a></span><span><a href="/catalog/seria/1-510/all39/"><nobr>1-510</nobr></a></span><span><a href="/catalog/seria/1-511/all100/"><nobr>1-511</nobr></a></span><span><a href="/catalog/seria/1-5155/all41/"><nobr>1-515/5</nobr></a></span><span><a href="/catalog/seria/1-5159/all843/"><nobr>1-515/9</nobr></a></span><span><a href="/catalog/seria/1605/all375/"><nobr>1605</nobr></a></span><span><a href="/catalog/seria/1lg-502/all2420/"><nobr>1ЛГ-502</nobr></a></span><span><a href="/catalog/seria/1lg-504/all2100/"><nobr>1ЛГ-504</nobr></a></span><span><a href="/catalog/seria/1lg-507/all2105/"><nobr>1ЛГ-507</nobr></a></span><span><a href="/catalog/seria/1r-303/all3568/"><nobr>1Р-303</nobr></a></span><span><a href="/catalog/seria/1r-30316/all4080/"><nobr>1Р-303.16</nobr></a></span><span><a href="/catalog/seria/ii-18/all18/"><nobr>II-18</nobr></a></span><span><a href="/catalog/seria/ii-29/all72/"><nobr>II-29</nobr></a></span><span><a href="/catalog/seria/ii-49/all12/"><nobr>II-49</nobr></a></span><span><a href="/catalog/seria/ii-57/all68/"><nobr>II-57</nobr></a></span><span><a href="/catalog/seria/ii-66/all80/"><nobr>II-66</nobr></a></span><span><a href="/catalog/seria/ii-68/all24/"><nobr>II-68</nobr></a></span><span><a href="/catalog/seria/gms-2001/all522/"><nobr>ГМС-2001</nobr></a></span><span><a href="/catalog/seria/i-209a/all44/"><nobr>И-209А</nobr></a></span><span><a href="/catalog/seria/k-7/all19/"><nobr>К-7</nobr></a></span><span><a href="/catalog/seria/kope/all17/"><nobr>КОПЭ</nobr></a></span><span><a href="/catalog/seria/mg-601/all492/"><nobr>МГ-601</nobr></a></span><span><a href="/catalog/seria/p-3/all9/"><nobr>П-3</nobr></a></span><span><a href="/catalog/seria/p-30/all79/"><nobr>П-30</nobr></a></span><span><a href="/catalog/seria/p-43/all178/"><nobr>П-43</nobr></a></span><span><a href="/catalog/seria/p-44/all8/"><nobr>П-44</nobr></a></span><span><a href="/catalog/seria/p-44t/all22/"><nobr>П-44Т</nobr></a></span><span><a href="/catalog/seria/p-46/all29/"><nobr>П-46</nobr></a></span><span><a href="/catalog/seria/p-55/all255/"><nobr>П-55</nobr></a></span><span><a href="/catalog/seria/pd-4/all148/"><nobr>ПД-4</nobr></a></span></div>
<p style="text-align:right;padding-top:1em;padding-bottom:1em;"><a href="/stat_all/">Агрегированная информация<br />по&nbsp;типовым сериям домов<br />в&nbsp;базе &laquo;Окнардия&raquo;</a>.</p>
</div>
</div>
<div class="row">
{%include "report/report_last_user_visit.html" %}
{% include "report/report_log_user_visit.html" %}
</div>
</div>
<!---/ Контент КОНЕЦ --->
<nav class="navbar navbar-fixed-top navbar-default" role="navigation" id="header">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/"><nobr><img src="/static/img/oknardia_logo.svg" onerror="this.onerror=null;this.src='/static/img/oknardia_logo.gif';this.width=290;this.height=34" title="Перейти на гравную сраницу «Окнардия»" alt="Логотип «Окнардия — оконный агрегатор»" ></nobr></a>
</div>
<ul class="nav navbar-nav navbar-right">
<li><a href="/catalog">Каталог</a></li>
<li><a href="/stat/rating/">Рейтинги</a></li>
<li><a href="/blog">Блог</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" rel="nofollow">О проекте <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/stat_all">Статистика</a></li>
<li role="separator" class="divider"></li>
<li><a href="/contact">Контакты</a></li>
<li><a href="/blogpost/2/My_zhdem_vashi_prajs-listy!">Сотрудничество</a></li>
<li><a href="/tariff">Услуги и тарифы</a></li>
<!-- li class="divider"></li>
<li><a href="#" rel="nofollow">Обратная связь</a></li -->
</ul>
</li>
<li class="dropdown" id="login-logout"><!--- Сюда подгружают AJAX-ом блок login-logout ---><small><br />Авторизации.<noscript style="color:red;">Для авторизации необходимо включить JavaScript.</noscript></small></li>
</ul>
</div>
</nav>
<div class="row panel-footer">
<div class="col-xs-12">
<span style="top:-200px;left:-8000px;position: absolute;"><script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-9116991-5', 'auto'); ga('send', 'pageview');
var _tmr=_tmr||[];_tmr.push({id:"2018432",type:"pageView",start:(new Date()).getTime()});(function (d,w,id){if(d.getElementById(id))return;var ts=d.createElement("script");ts.type="text/javascript";ts.async=true;ts.id=id;ts.src=(d.location.protocol=="https:"?"https:":"http:")+"//top-fwz1.mail.ru/js/code.js";var f=function(){var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(ts, s);};if(w.opera=="[object Opera]"){ d.addEventListener("DOMContentLoaded",f,false);}else{f();}})(document,window,"topmailru-code");
</script><noscript><div style="position:absolute;left:-10000px;">
<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na" style="border:0;height:1px;width:1px" alt="" />
<img src="//mc.yandex.ru/watch/32997984" style="border:0;height:1px;width:1px" alt="" />
</div></noscript>
<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0;padding-top:8px;" rel="nofollow" alt="Рейтинг@Mail.ru"></a>
<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer" target="_blank" rel="nofollow"><img src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews" style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика" title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)" onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}" /></a>
<span id="rambler"><script id="top100Counter" type="text/javascript" src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript><a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853" alt="Rambler's Top100" border="0"/></a></noscript></span>
<script type="text/javascript"><!--
document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r"+escape(document.referrer)+((typeof(screen)=="undefined")?"":";s"+screen.width+"*"+screen.height+"*"+(screen.colorDepth?screen.colorDepth:screen.pixelDepth))+";u"+escape(document.URL)+";"+Math.random()+"' alt='' title='LiveInternet' style='border:0;padding-top:8px;'><\/a>");
(function(d,w,c){(w[c]=w[c]||[]).push(function(){try{w.yaCounter32997984=new Ya.Metrika({id:32997984,clickmap:true,trackLinks:true,accurateTrackBounce:true,webvisor:true,trackHash:true});}catch(e){}});var n=d.getElementsByTagName("script")[0],s=d.createElement("script"),f=function(){n.parentNode.insertBefore(s,n);};s.type="text/javascript";s.async=true;s.src="https://mc.yandex.ru/metrika/watch.js";if(w.opera=="[object Opera]"){d.addEventListener("DOMContentLoaded",f,false);}else{ f();}})(document,window,"yandex_metrika_callbacks");
//--></script>
</span>
<small>© oknardia.ru, 2015-2023. <a href="/blogpost/18/Ob-avtorskih-pravah">Все права защищены</a>.<!--- Время отработки скрипта: сек---></small>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex, nofollow" />
<title>ОКНАРДИЯ :: Служебное</title>
</head>
<body>
<h1>Служебные ссылки</h1>
<ul>
<li><b><a href="/service/tmp">Страница для тестирования верстки текста в блоге</a></b></li>
</ul><ul>
<li><a href="/service/make_JavaScripts4maps">Пересоздать JavaScript для карт на основе API Яндекс.Крат</a> (исполняется около 1 минуты)</li>
<li><a href="/service/make_SeriaInfoRoot">Построить id корневых серий</a> (исполняется около 1 часа)</li>
</ul><ul>
<li><a href="/service/del_CachingTemplate">Удалить кеширующие шаблоны</a> (для страниц про серии домов)</li>
</ul><ul>
<li><a href="/service/make_FillGeoCode">Добавить GeoCode для адресов где его нет</a></li>
</ul><ul>
<li><b><a href="/service/make_rating">Пересчитать рейтинги Профилей</a></b></li>
</ul>
</body>
</html>
+141
View File
@@ -0,0 +1,141 @@
<!DOCTYPE html>{% load static %}
<html lang="ru-RU">
<head>
<meta charset="utf-8"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="content-language" content="ru"/>
<meta http-equiv="Date" content="{% block Date4Meta %}{% now "c" %}{% endblock %}"/>
<meta http-equiv="Last-Modified" content="{% block Last4Meta %}{% now "c" %}{% endblock %}"/>
<meta http-equiv="Expires" content="{% block Expires4Meta %}{% now "c" %}{% endblock %}"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="description" content="
{% block Description %}{{ META_DESCRIPTION|default:"" }}Служебный интерфейс «Окнардия» закрыт{% endblock %}"/>
<meta name="keywords"
content="{% block Keywords %}цены на пластиковые окна, агрегатор окон, доступ закрыт{{ META_KEYWORDS|default:"" }}{% endblock %}"/>
<meta name="author" content="OKNARDIA.RU{% block Author4Meta %}{% endblock %}"/>
<meta name="copyright" lang="ru" content="OKNARDIA.RU{% block CopyrightAuthor4Meta %}{% endblock %}"/>
<meta name="robots" content="index,follow"/>
<meta name="document-state" content="{{ META_DOCUMENT_STATE|default:"Static" }}"/>
<meta name="generator" content="OKNARDIA 0.3β by Python/Django"/>
<title>ОКНАРДИЯ: Нет доступа в служебный интерфейс</title>
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" />{# <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />#}
<script src="{% static 'js/jquery-2.1.1.min.js' %}" type="text/javascript"></script>{# <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript"></script>#}
<script src="{% static 'js/bootstrap.min.js' %}" type="text/javascript"></script>{# <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" type="text/javascript"></script>#}{% block Top_JS1 %}{% endblock %}{% block Top_JS2 %}{% endblock %}{% block Top_JS3 %}{% endblock %}{% block Top_JS4 %}{% endblock %}{% block Top_JS5 %}{% endblock %}{% block Top_Meta1 %}{% endblock %}
<link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300" rel="stylesheet">
</head>
<body>
<div class="row">
<div class="col-xs-8 col-xs-offset-4">
<p>&nbsp;<br>&nbsp;<br></p>
<h1 style="font-family: 'Open Sans Condensed', sans-serif;
font-size: 5em;
font-weight: 900;
text-shadow: 1px 1px 6px silver;">Служебный интерфейс закрыт</h1>
<p style="font-family: 'Open Sans Condensed', sans-serif;font-size: 3ex;">Доступ только для админов! Поисковикам и
пользователям лезть сюда не за чем…</p>
</div>
</div>
<div style="height: 100% !important; width: 100% !important; background-image: url('/static/img/cubex.png');
background-repeat: no-repeat; background-position: 10% 85%; z-index:-2; position:absolute !important;
bottom: 0; right: 0;">
<div style="position: absolute; bottom: 0; right: 0;padding-bottom: 1ex;padding-right: 2ex;">
<script type="text/javascript">
{# <!-- Google Analylics --> #}(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o), m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-9116991-5', 'auto');
ga('send', 'pageview');
{# <!-- Rating@Mail.ru counter --> #}var _tmr = _tmr || [];
_tmr.push({id: "2018432", type: "pageView", start: (new Date()).getTime()});
(function (d, w, id) {
if (d.getElementById(id))return;
var ts = d.createElement("script");
ts.type = "text/javascript";
ts.async = true;
ts.id = id;
ts.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//top-fwz1.mail.ru/js/code.js";
var f = function () {
var s = d.getElementsByTagName("script")[0];
s.parentNode.insertBefore(ts, s);
};
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else {
f();
}
})(document, window, "topmailru-code");
{# <!-- LiveInternet counter --> #}
</script>
<noscript>
<div style="position:absolute;left:-10000px;">
{# <!-- Rating@Mail.ru nosript --> #}<img src="//top-fwz1.mail.ru/counter?id=2018432;js=na"
style="border:0;height:1px;width:1px" alt=""/>
{# <!-- Yandex.Metrika counter --> #}<img src="//mc.yandex.ru/watch/32997984"
style="border:0;height:1px;width:1px"
alt=""/>{# <!-- /Yandex.Metrika counter --> #}
</div>
</noscript>
{#<!-- Rating@Mail.ru logo -->#}<a target="_blank" href="http://top.mail.ru/jump?from=2018432"><img
src="//top-fwz1.mail.ru/counter?id=2018432;t=216;l=1" style="border:0" rel="nofollow"
alt="Рейтинг@Mail.ru"></a>{#<!-- //Rating@Mail.ru logo -->#}
{# <!-- Yandex.Metrika informer --> #}<a href="https://metrika.yandex.ru/stat/?id=32997984&amp;from=informer"
target="_blank" rel="nofollow"><img
src="https://informer.yandex.ru/informer/32997984/3_0_E0E0E0FF_C0C0C0FF_0_pageviews"
style="width:88px; height:31px; border:0;" alt="Яндекс.Метрика"
title="Яндекс.Метрика: данные за сегодня (просмотры, визиты и уникальные посетители)"
onclick="try{Ya.Metrika.informer({i:this,id:32997984,lang:'ru'});return false}catch(e){}"/></a>{# <!-- /Yandex.Metrika informer --> #}
{# <!-- begin of Top100 code --> #}<span id="rambler"><script id="top100Counter" type="text/javascript"
src="//counter.rambler.ru/top100.jcn?3148853"></script><noscript>
<a href="http://top100.rambler.ru/navi/3148853/"><img src="http://counter.rambler.ru/top100.cnt?3148853"
alt="Rambler's Top100" border="0"/></a>
</noscript></span>{# <!-- end of Top100 code --> #}
<script type="text/javascript"><!--
{#<!--LiveInternet counter-->#}document.write("<a href='//www.liveinternet.ru/click' target=_blank><img src='//counter.yadro.ru/hit?t50.2;r" + escape(document.referrer) + ((typeof(screen) == "undefined") ? "" : ";s" + screen.width + "*" + screen.height + "*" + (screen.colorDepth ? screen.colorDepth : screen.pixelDepth)) + ";u" + escape(document.URL) + ";" + Math.random() + "' alt='' title='LiveInternet' style='border:0;'><\/a>");
{# <!-- Yandex.Metrika counter --> #}(function (d, w, c) {
(w[c] = w[c] || []).push(function () {
try {
w.yaCounter32997984 = new Ya.Metrika({
id: 32997984,
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true,
trackHash: true
});
} catch (e) {
}
});
var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function () {
n.parentNode.insertBefore(s, n);
};
s.type = "text/javascript";
s.async = true;
s.src = "https://mc.yandex.ru/metrika/watch.js";
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else {
f();
}
})(document, window, "yandex_metrika_callbacks");
//--></script>
{# <!--/LiveInternet--> #}
</div>
<div style="position: absolute; bottom: 0; left: 0;padding-bottom: 1ex;padding-left: 2ex;font-size: x-small">
© <a href="/">oknardia.ru</a>, 2015-{% now "Y" %}.
</div>
</div>
</body>
</html>
+137
View File
@@ -0,0 +1,137 @@
{% extends "base.html" %}
{% load static %}
{% load filters %}
{% load humanize %}
{% block Title %}: Тарифы и услуги{% endblock %}
{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %}
{% block Description %}Тарифы и услуги маркетплейс-агрегатора Окнардия. Размещение предложений пластиковых и деревянных окон, обновление цен на окна, рекламные баннеры и виджеты на сайт оконной компании.{% endblock %}
{% block Keywords %}типовые проекты зданий, панельное строительство, {% for CountSeria in SERIA_NAV_DIM %}серия {{ CountSeria.SERIA_R }}, {{ CountSeria.SERIA_R }}, {% endfor %}, года простойки, регионы построки, распространенность{% endblock %}
{% block Top_JS1%}
<script type="text/javascript">
$(window).load(function(){var images = $('.half');images.each(function(i){$(this).width($(this).width()/2);});});
</script>
{% endblock %}
{% block Main_Content %}<!--- Контент НАЧАЛО --->
<dIv class="container-fluid" itemscope itemtype="http://schema.org/Article">
<div class="row">
<div class="col-md-11">
<ol class="breadcrumb">
<li><a href="/">Главная</a></li>
<li><a href="/blog/">Блог</a></li>
<li><a href="/blog/P1">Стр.2</a></li>
<li class="active">Питерские хрущёвки <nobr>1ЛГ-507</nobr> в&nbsp;базе &laquo;Окнардии&raquo;</li>
</ol>
</div>
<div class="header_blog">
<p class="col-xs-4"><span>{% now "d.F.Y (l) H:i" %}</span><br /><small><img src="/media/img_avatar/avatar_eserg_160x160.png" alt="Аватар: oknardia (администрация)" title="Аватар: oknardia (администрация)" /> <i>администрация</i></small></p>
<script type="text/javascript">(function() {
if (window.pluso)if (typeof window.pluso.start == "function") return;
if (window.ifpluso==undefined) { window.ifpluso = 1;
var d = document, s = d.createElement('script'), g = 'getElementsByTagName';
s.type = 'text/javascript'; s.charset='UTF-8'; s.async = true;
s.src = ('https:' == window.location.protocol ? 'https' : 'http') + '://share.pluso.ru/pluso-like.js';
var h=d[g]('body')[0];
h.appendChild(s);
}})();</script>
<p class="col-xs-7 pluso" style="" data-background="white" data-options="medium,square,line,horizontal,counter,theme=08" data-services="facebook,vkontakte,twitter,odnoklassniki,google,moimir,print,googlebookmark,tumblr,pinterest,email"></p>
<h1 class="col-md-11" itemprop="name">ЗАГОЛОВОК</h1>
</div>
</div>
<DiV class="row">
<DIv class="col-md-11">
<dIv style="padding-top: 1ex;font-size:120%" itemprop="articleBody">
<!--- Пост в блоге :: начало --->
<p>Против некоторых позиций в&nbsp;тарифах &laquo;Окнардии&raquo; давно стояла метка &laquo;с&nbsp;11.2017&raquo;. Она появилась почти два года назад, вместе с&nbsp;тарифами нашего оконного агрегатора когда закончилось <nobr>бета-тестирование</nobr>. И&nbsp;вот этот 11.2017 наступил. А&nbsp;значит цены на&nbsp;размещение цен на&nbsp;размещение оконных предложений меняются. Как и&nbsp;было обещано.</p>
<p><center><img src="/media/img_for_blog/tariff-changing.gif" /></center></p>
<p>Но&nbsp;перед тем, как рассказать детали напомним, что было сделано за&nbsp;эти два года</p><cut />
<ul>
<li>Размещено 22 оконных набора в&nbsp;предложениях. Размещаются как пластиковые, так и&nbsp;деревянные окна.</li>
<li>С&nbsp;&laquo;Окнардией&raquo; работают уже семь <nobr>оконных-компании</nobr> партнёра.</li>
<li>&mdash;&nbsp;Добавлен функционал сравнения характеристик оконных предложений и&nbsp;отдельных компонентов этих предложений.</li>
<li>Создан <a href="/catalog/profile/">каталог профилей</a>, <a href="/catalog/standard_opening/">стандартных проёмов</a>, <a href="/catalog/seria/">типовых серий домов</a>, <a href="https://oknardia.ru/catalog/company/">оконных компаний</a>. В&nbsp;будущем будет каталог стеклопакетов и&nbsp;фурнитуры&hellip; планов много.</li>
<li>Построен <a href="/blogpost/17/Nagljadnoe-sravnenie-harakteristik-okonnyh-profilej/">алгоритм расчёта реальных рейтингов</a> предложений, профилей, стеклопакетов и&nbsp;сервиса компаний. Рейтинги не&nbsp;на&nbsp;базе &laquo;общественного голосования&raquo;, &laquo;опросов&raquo; или измерением <nobr>&laquo;интернет-популярности&raquo;</nobr>, а&nbsp;на&nbsp;базе физических характеристик и&nbsp;измеримых параметров. Таким образом&nbsp;&mdash; это объектовые рейтинги.</li>
<li>Разработан <a href="https://widget.oknardia.ru/">виджет</a>, который позволяет оконной компании реализовать функционал &laquo;Окнардии&raquo; на&nbsp;собственном сайте.</li>
<li>Расширены <nobr><a href="/blogpost/16/Novye-media-vozmozhnosti-uchastnikam-Oknardii-/">медиа-возможности</a></nobr> проекта: баннеры, посты в&nbsp;блоге, специальное выделение.</li>
</ul>
<h3>Теперь о&nbsp;том, что меняется:</h3>
<ul>
<li>Повысились цены на&nbsp;<nobr>бизнес-пакеты</nobr>. В&nbsp;том числе и&nbsp;стартовый. Эти расценки анонсировались в&nbsp;примечаниях к&nbsp;каждому пакету, так что сюрпризом эти изменения не&nbsp;стали. В&nbsp;том числе стало недоступно бесплатное размещение полных наборов&nbsp;&mdash; коммерческих предложений для всех типовых проёмов нашей базы.</li>
<li>Введён новый пакет для бесплатного размещения. В&nbsp;его рамках возможно размещать цен только для третьи набора. Это 20&ndash;25 расчётов цен типовых проёмов. Выбравшим бесплатный, стартовый набор можно следовать двумя стратегиями: разместить цены на&nbsp;полный набор постепенно в&nbsp;течении квартала или обновлять цены только для проёмов, распространённых в&nbsp;вашем регионе.</li>
</ul>
<h3>И&nbsp;что не&nbsp;меняется:</h3>
<ul>
<li>Коммерческие предложения останутся в&nbsp;агрегаторе навсегда. А&nbsp;значит навсегда останутся детальные характеристики предложений, описание оконной компании и&nbsp;ссылки на&nbsp;её сайт.</li>
<li>Тарифы на&nbsp;медийное размещения остались без изменений.</li>
</ul>
<p><a href="/tariff">Новые тарифы размещены на&nbsp;сайте</a>. Скачать шаблоны для платного и&nbsp;бесплатного размещения <a href="/blogpost/2/My_zhdem_vashi_prajs-listy%21/">можно здесь</a>.</p>
&downarrow; &uparrow; &longrightarrow; &longleftarrow; &nearr; &nearr; &searr; &swarr; &nwarr;
<!--- Пост в блоге :: конец --->
</dIv>
</DIv>
</DiV>
<!-- Листалка: НАЧАЛО --><div class="row">
<div class="col-md-11">
<hr class="dotted-black" />
<nav aria-label="перелистывание записей блога">
<ul class="pager">
<li class="previous"><a href="/blogpost/9/Dobavleno-opisanie-serii-1LG-504"><span aria-hidden="true">&larr;</span> Предыдущая запись</a></li>
<li class="previous"></li>
<li class="next"><a href="/blogpost/11/Rejting-Oknardii-i-kak-on-ustroen-(chast-1)">Следующая запись <span aria-hidden="true">&rarr;</span></a></li>
</ul>
</nav>
</div>
</div><!--- Листалка: КОНЕЦ --->
</dIv>
<!---/ Контент КОНЕЦ --->
<div class="row col-md-12">
<div class="col-md-8" >
<details>
<summary>Коменты внутри</summary>
<p>
<details>
<summary>Первый</summary>
<p>Текст комментария 1</p>
</details>
<details>
<summary>Второй</summary>
<p>Текст комментария 2</p>
</details>
<details>
<summary>И внутри...</summary>
<p>
<details>
<summary>Третий</summary>
<p>Текст комментария 3</p>
</details>
</p>
</details>
</p>
</details>
</div>
</div>
{% endblock %}
{% comment %}
{% block Top_Nav_Bar %}
{# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #}
{% endblock %}
{% endcomment %}
+220 -21
View File
@@ -1,12 +1,15 @@
# -*- coding: utf-8 -*-
__author__ = 'Sergei Erjemin'
# from transliterate import translit
from PIL import Image, ImageDraw
from oknardia.settings import *
import django.utils.dateformat
import django.utils.timezone
import os
import re
import math
import re
import urllib3
import xml.dom.minidom
def safe_html_spec_symbols(s: str) -> str:
@@ -37,6 +40,7 @@ def safe_html_spec_symbols(s: str) -> str:
result = result.replace('<br>', ' ')
return result
# def Rus2Lat(RusString):
# return translit(re.sub(
# r'<[\s\S]*?>', '', re.sub(r'&[\S]*?;', '-', RusString)
@@ -54,9 +58,9 @@ def safe_html_spec_symbols(s: str) -> str:
#
#
# # Суммирует все цифры в строке через произвольные (не цифровые) разделители
# def SummThrought(StringWSlash):
# StringWSlash = re.sub( r"[^0-9]", u",", StringWSlash)
# ListTerms = StringWSlash.split(u',')
# def sum_through(string_w_slash):
# string_w_slash = re.sub( r"[^0-9]", u",", string_w_slash)
# ListTerms = string_w_slash.split(u',')
# Summ = 0
# for Count in ListTerms:
# try:
@@ -76,15 +80,17 @@ def get_rating_set_for_stars(rating: float = 0.) -> list:
# return []
rating_set = []
for CountStar in range(RARING_STAR):
if RARING_SET_MIN+CountStar * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR + 1. <= rating:
if RARING_SET_MIN + CountStar * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR + 1. <= rating:
rating_set.append(1)
else:
rating_set.append(0)
return rating_set
#
#
# # рассчитывает дистанцию в км. между двумя геокоординатами
# def GetGeoDistance(lon1, lat1, lat2, lon2):
# def get_geo_distance(lon1, lat1, lat2, lon2):
# lonA, latA, latB, lonB = map(math.radians, [lon1, lat1, lat2, lon2])
# distance = 2 * math.asin(math.sqrt(math.sin((latB - latA) / 2) ** 2 + math.cos(latA) * math.cos(latB) * math.sin(
# (lonB - lonA) / 2) ** 2)) * 6371.032 # РАДИУС ЗЕМЛИ 6371.032 КМ.
@@ -114,7 +120,7 @@ def get_flaps_for_big_pictures(query_set) -> dict:
for i in query_set: # найдём максимальную высоту проёма окна и двери
if i.iWinHight >= mount_max_h:
mount_max_h = i.iWinHight
if i.bIsDoor >= door_h:
if i.bIsDoor and i.iWinHight >= door_h:
door_h = i.iWinHight
# Проверяем есть ли папка для хранения картинки конфигурации проема и схемы открывания для данной серии.
if not os.path.exists(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_BIGIMGFLAPCONFIG}"):
@@ -136,6 +142,7 @@ def get_flaps_for_big_pictures(query_set) -> dict:
else:
img_file_name += u"-" # добавляем символ отдельное окно (не рядом с дверью)
# маскируем символы схемы открывания, которые не допустимы в названии файлов
# print(img_file_name)
img_file_name += i.sFlapConfig
img_file_name = img_file_name.replace(">", "G")
img_file_name = img_file_name.replace("<", "L")
@@ -143,11 +150,12 @@ def get_flaps_for_big_pictures(query_set) -> dict:
img_file_name = img_file_name.replace("]", ")")
img_file_name = img_file_name.replace("|", "I")
img_file_name = f"{PATH_FOR_BIGIMGFLAPCONFIG}/{img_file_name}.png"
# print(img_file_name)
# проверяем, есть ли файл с нужной картинкой схемам открывания?
if not os.path.isfile(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{img_file_name}"):
# картинки нет, вызываем функцию для ее создания
make_big_img_win_flap(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{img_file_name}", i.iWinWidth, i.iWinHight,
i.bIsDoor, i.sFlapConfig, mount_max_h, mount_bulk, door_h)
make_big_img_win_flap(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{img_file_name}", i.iWinWidth,
i.iWinHight, i.bIsDoor, i.sFlapConfig, mount_max_h, mount_bulk, door_h)
# чтобы получить разноцветные маркеры меток количества проемов
# получаем последовательность тип: AB, CD, E, FG, H
q_local = ""
@@ -158,12 +166,14 @@ def get_flaps_for_big_pictures(query_set) -> dict:
'url2img': f"img/{img_file_name}",
'iWinWidth': i.iWinWidth,
'iWinHight': i.iWinHight,
'iWinWidth_mm': int(i.iWinWidth*10),
'iWinHight_mm': int(i.iWinHight*10),
'iWinDepth': i.iWinDepth,
'iQuantity': i.iQuantity,
'sDescription': i.sDescripion,
'id': i.id,
'qStr': q_local,
'W': int((i.iWinWidth*250) / mount_max_h)
'W': int((i.iWinWidth * 250) / mount_max_h)
})
result.update({'FLAP_DIM': flaps_dim,
'WIN_DIM': query_set})
@@ -184,8 +194,13 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
:param height_door: int -- высота дверного проема
:return: None
"""
# width = int(width)
# height = int(height)
# height_max = int(height_max)
# height_mount_bulk = int(height_mount_bulk)
# height_door = int(height_door)
# создаем картинку с нужными размерами
img = Image.new("RGBA", (width * PICT_H / height_max, PICT_H), (255, 255, 255, 0))
img = Image.new("RGBA", (int(width * PICT_H / height_max), PICT_H), (255, 255, 255, 0))
# print(img_file_name_with_path)
# находим крайние точки периметра (если окно -- выравнено вверх; если дверь -- вниз)
top = 0
@@ -193,7 +208,7 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
bottom = img.size[1]
right = img.size[0]
draw = ImageDraw.Draw(img)
draw.rectangle((left, top, right-1, bottom-1), fill=(200, 200, 200, 50), outline=None)
draw.rectangle((left, top, right - 1, bottom - 1), fill=(200, 200, 200, 50), outline=None)
if is_door: # это дверь. Выравнивание по нижней кромке
top = bottom - (height * PICT_H / height_max)
else: # это не дверь... Выравниваем по верхней кромке
@@ -205,7 +220,7 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
draw.line((left, bottom, right, bottom), fill=(125, 125, 125), width=25)
draw.line((left, top, right, top), fill=(125, 125, 125), width=25)
draw.line((left, top, left, bottom), fill=(125, 125, 125), width=25)
draw.line((right, top, right, bottom-6), fill=(125, 125, 125), width=25)
draw.line((right, top, right, bottom - 6), fill=(125, 125, 125), width=25)
dim_flap = flap_analiz(flap_config)
@@ -218,7 +233,7 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
local_top = top
local_bottom = top
for i in dim_flap: # цикл по рядам створок
local_bottom += i["vRatio"]*flap_h/v_ratio_max
local_bottom += i["vRatio"] * flap_h / v_ratio_max
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
for j in i["row"]:
h_ratio_max += j["hRatio"]
@@ -304,7 +319,7 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
local_right = 0
local_left = 0
for j in i["row"]:
local_right += j["hRatio"]*right/h_ratio_max
local_right += j["hRatio"] * right / h_ratio_max
# Отрисовка створки. ПЕРИМЕТР
draw.rectangle((local_left, local_top, local_right, local_bottom), fill=None, outline=(0, 0, 0))
local_left = local_right
@@ -321,7 +336,7 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
draw.rectangle((left, 0, right - 1, (height_max - height) * PICT_H / height_max),
fill=(255, 255, 255, 0), outline=None)
# рисуем внешнюю тоненькую окантовку
draw.rectangle((left, top, right-1, bottom-1), fill=None, outline=(0, 0, 0))
draw.rectangle((left, top, right - 1, bottom - 1), fill=None, outline=(0, 0, 0))
del draw
# сохраняем картинку
# img.info = {"Comment": "123456"}
@@ -368,7 +383,7 @@ def flap_analiz(flap_config: str) -> list:
dim_flap[j]["row"][k]["hRatio"] += 1
continue
if in_flap and (flap_config[i].isdigit() and flap_config[i - 1].isdigit()):
dim_flap[j]["row"][k].update({"hRatio": dim_flap[j]["row"][k]["hRatio"]*10 + int(flap_config[i])})
dim_flap[j]["row"][k].update({"hRatio": dim_flap[j]["row"][k]["hRatio"] * 10 + int(flap_config[i])})
continue
if in_flap and flap_config[i].isdigit():
dim_flap[j]["row"][k].update({"hRatio": int(flap_config[i])})
@@ -382,8 +397,8 @@ def flap_analiz(flap_config: str) -> list:
or flap_config[i] == "=" # горизонтальная перегородка
or flap_config[i] == "X" # глухое окно
or flap_config[i] == "x" # ^
or flap_config[i] == u"х" # ^
or flap_config[i] == u"Х" # ^
or flap_config[i] == "х" # ^
or flap_config[i] == "Х" # ^
or flap_config[i] == "+" # ^
or flap_config[i] == "M" # москитная сетка
or flap_config[i] == "m" # ^
@@ -395,3 +410,187 @@ def flap_analiz(flap_config: str) -> list:
or flap_config[i] == "s"): # ^
dim_flap[j]["row"][k].update({"flap": dim_flap[j]["row"][k]["flap"] + flap_config[i]})
return dim_flap
def make_flap_mini_pictures(path_to_img_file: str, str_flap_config: str) -> None:
""" Функция создает файл мини-картинки схем открывания окна
:param path_to_img_file: путь к файлу с изображением
:param str_flap_config: строка с описанием схемы открывания
:param is_door:
:return:
"""
# print(path_to_img_file, str_flap_config, is_door)
dim_flap = flap_analiz(str_flap_config)
v_ratio_max = 0 # число всех долей (частей) для построения пропорций по вертикали
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
for i in dim_flap:
local_h_ratio_max = 0
v_ratio_max += i["vRatio"]
for j in i["row"]:
local_h_ratio_max += j["hRatio"]
if local_h_ratio_max > h_ratio_max:
h_ratio_max = local_h_ratio_max
img = Image.new("RGBA", (h_ratio_max * PICT_MINWI + (h_ratio_max + 1) * 3, PICT_MINIH + 6), (255, 255, 255, 0))
top = 0
left = 0
bottom = img.size[1]
right = img.size[0]
flap_h = bottom - top
draw = ImageDraw.Draw(img)
draw.rectangle((left, top, right, bottom), fill=(200, 200, 200, 50), outline=None)
# рисуем внешнюю рамку
draw.line((left, bottom - 1, right, bottom - 1), fill=(125, 125, 125), width=5) # нижняя
draw.line((left, top, right, top), fill=(125, 125, 125), width=5) # верхняя
draw.line((left, top, left, bottom), fill=(125, 125, 125), width=5) # левая
draw.line((right - 1, top, right - 1, bottom), fill=(125, 125, 125), width=5) # правая
############################################################
# НАЧИНАЕМ ОТРИСОВКУ СТВОРОК ОКНА НА КРТИНКУ
############################################################
local_top = top
local_bottom = top
for i in dim_flap: # цикл по рядам створок
local_bottom += i["vRatio"] * flap_h / v_ratio_max
local_right = 0
local_left = 0
for j in i["row"]:
local_right += j["hRatio"] * right / h_ratio_max
# отрисовка схему открывания створки
if "X" in j["flap"] or "x" in j["flap"] or "х" in j["flap"] or "Х" in j["flap"] or "+" in j["flap"]:
# глухое окно (рисуем крестик)
draw.line(((local_right + local_left) / 2 - 5, (local_bottom + local_top) / 2,
(local_right + local_left) / 2 + 5, (local_bottom + local_top) / 2),
fill=(105, 105, 225), width=1)
draw.line(((local_right + local_left) / 2, (local_bottom + local_top) / 2 - 5,
(local_right + local_left) / 2, (local_bottom + local_top) / 2 + 5),
fill=(105, 105, 225), width=1)
if "V" in j["flap"]: # откидное открывание
draw.line((local_right - 3, local_bottom - 4, (local_right + local_left) / 2, local_top + 3),
fill=(125, 225, 125), width=1)
draw.line((local_left + 3, local_bottom - 4, (local_right + local_left) / 2, local_top + 3),
fill=(125, 225, 125), width=1)
if ">" in j["flap"] or "G" in j["flap"]: # поворотное влево
draw.line((local_left + 3, local_top + 3, local_right - 3, (local_bottom + local_top) / 2),
fill=(225, 125, 125), width=1)
draw.line((local_left + 3, local_bottom - 3, local_right - 3, (local_bottom + local_top) / 2),
fill=(225, 125, 125), width=1)
if "<" in j["flap"] or "L" in j["flap"]: # поворотное вправо
draw.line((local_right - 3, local_bottom - 3, local_left + 3, (local_bottom + local_top) / 2),
fill=(225, 125, 125), width=1)
draw.line((local_right - 3, local_top + 3, local_left + 3, (local_bottom + local_top) / 2),
fill=(225, 125, 125), width=1)
if "Z" in j["flap"] or "S" in j["flap"] or "z" in j["flap"] or "s" in j["flap"]: # расширитель (спейсер)
draw.line(((local_left * 3 + local_right) / 4, (local_top * 3 + local_bottom) / 4,
(local_right * 3 - local_left) / 4, (local_top * 3 + local_bottom) / 4),
fill=(225, 125, 125), width=1)
draw.line(((local_left * 3 + local_right) / 4, (local_bottom * 3 + local_top) / 4,
(local_right * 3 - local_left) / 4, (local_bottom * 3 + local_top) / 4),
fill=(225, 125, 125), width=1)
draw.line(((local_left * 3 + local_right) / 4, (local_top * 3 + local_bottom) / 4,
(local_right * 3 - local_left) / 4, (local_bottom * 3 + local_top) / 4),
fill=(225, 125, 125), width=1)
if "M" in j["flap"] or "m" in j["flap"] or "м" in j["flap"] or "М" in j["flap"]: # москитная сетка
draw.rectangle((local_left, local_top, local_right, local_bottom), fill=(16, 125, 16, 50), outline=None)
# Отрисовка створки. ПЕРИМЕТР
draw.line((local_left, local_bottom, local_right, local_bottom), fill=(125, 125, 125), width=3)
draw.line((local_left, local_top, local_right, local_top), fill=(125, 125, 125), width=3)
draw.line((local_left, local_top, local_left, local_bottom), fill=(125, 125, 125), width=3)
draw.line((local_right, local_top, local_right, local_bottom), fill=(125, 125, 125), width=3)
local_left = local_right
local_top = local_bottom
del draw
# сохраняем картинку
img.save(path_to_img_file)
return
def get_flaps_for_mini_pictures(flap_config: str) -> str:
"""
Функция возвращает строку с именем файла мини-картинки для схемы открывания полученной в flap_config
:param flap_config: str - строка с схемой открывания.
:return: str - строка с именем файла мини-картинки.
"""
image_file_name = flap_config.upper()
image_file_name = image_file_name.replace(">", "G")
image_file_name = image_file_name.replace("<", "L")
image_file_name = image_file_name.replace("|", "I")
image_file_name = image_file_name.replace("[", "(")
image_file_name = image_file_name.replace("]", ")")
image_file_name = image_file_name.replace("/", "-")
image_file_name = image_file_name.replace("\\", "-")
image_file_name = image_file_name.replace(".", "-") + ".png"
image_file_name = f"{PATH_FOR_IMG}/{PATH_FOR_IMGFLAPCONFIG}/{image_file_name}"
if not os.path.isfile(f"{STATIC_BASE_PATH}/{image_file_name}"):
make_flap_mini_pictures(f"{STATIC_BASE_PATH}/{image_file_name}", flap_config.upper())
return image_file_name
def get_geo_distance(lon1: float, lat1: float, lat2: float, lon2: float) -> float:
""" Функция возвращает расстояние в км. между двумя геокоординатами.
:param lon1: float - долгота первой точки.
:param lat1: float - широта первой точки.
:param lat2: float - широта второй точки.
:param lon2: float - долгота второй точки.
:return: float - расстояние в км. между двумя геокоординатами.
"""
lon_a, lat_a, lat_b, lon_b = map(math.radians, [lon1, lat1, lat2, lon2])
distance = 2 * math.asin(math.sqrt(math.sin((lat_b - lat_a) / 2) ** 2 + math.cos(lat_a) * math.cos(lat_b)
* math.sin((lon_b - lon_a) / 2) ** 2)) * 6371.032 # РАДИУС ЗЕМЛИ 6371.032 КМ.
return distance
def get_yandex_geocode_by_address(address_string: str) -> list:
""" Функция получает от Яндекс-Карт геокоординаты соответсвующее адресу.
:param address_string: str -- строка с адресом (utf-8)
:return: geocode: list -- [Долгота (longitude), Широта (latitude)]
"""
geocode = [0, 0]
http = urllib3.PoolManager()
response_api = http.request('GET', f"http://geocode-maps.yandex.ru/1.x/?apikey={YANDEX_MAPS_API_KEY}"
f"&geocode={address_string}")
# print(response_api.data.decode('utf-8'))
try:
data = xml.dom.minidom.parseString(response_api.data.decode('utf-8'))
data = data.getElementsByTagName('pos')[0]
data = data.childNodes[0].data
data = tuple(data.split())
geocode[0] = float(data[0]) # Долгота (longitude): Восточная + (E) // Западная - (W)
geocode[1] = float(data[1]) # Широта (latitude): Северная + (N) // Южная - (S)
# print(geocode)
return geocode
except:
# Тут может быть много разных типов ошибок urllub3 связанных с получением данных от Яндекс-Карт
# Перечень исключений: https://urllib3.readthedocs.io/en/stable/reference/urllib3.exceptions.html
# Возвращаем нулевые координаты, как признак, что данные не получены.
return [0, 0]
def sum_through(string_w_slash: str) -> int:
""" Суммирует все цифры (числа) в строке через произвольные (не цифровые) разделители
:param string_w_slash: str -- строка с цифрами (числами) через разделители
:return: summ: int -- сумма цифр (чисел) в строке
"""
string_w_slash = re.sub(r"[^0-9]", ",", string_w_slash)
list_terms = string_w_slash.split(',')
sum_result = 0
for Count in list_terms:
try:
sum_result += int(Count)
except ValueError:
pass
return sum_result
def touch_reload_wsgi(s: str = ''):
""" Функция перезагружает WSGI-сервер.
:return: None
"""
with open(TOUCH_RELOAD, 'a', encoding="utf-8") as f:
f.write(f'\nreload wsgi by cash-template - {s} - '
f'{django.utils.dateformat.format(django.utils.timezone.now(), "Y-m-d H:i:s")}')
+14 -784
View File
@@ -1,20 +1,9 @@
# -*- coding: utf-8 -*-
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from django.template.loader import render_to_string
from django.utils import timezone
from oknardia.settings import *
from oknardia.models import PVCprofiles, Seria_Info, Win_MountDim, Building_Info
from oknardia.models import Seria_Info
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures
import time
import json
import random
import re
import os
import math
import pytils
def catalog_root(request: HttpRequest) -> HttpResponse:
@@ -25,787 +14,28 @@ def catalog_root(request: HttpRequest) -> HttpResponse:
:param request: HttpRequest -- входящий http-запрос
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
time_start = time.perf_counter()
# получаем из cookies последние визиты клиента
to_template = {
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)}
'ticks': float(time.perf_counter() - time_start)}
response = render(request, "catalog/catalog_root.html", to_template)
return response
def catalog_profile(request: HttpRequest) -> HttpResponse:
def report_all_info_seria_redirect(request: HttpRequest, seria_id: str = "12") -> HttpResponse:
""" Переадресация старых URL, т.к. их сколько-то есть (было) во внешних ссылках
:param request: HttpRequest -- запрос
:param seria_id: str -- id серии типового строительства
:return:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница со списком производителей и моделей (марками) профилей
:param request: HttpRequest -- входящий http-запрос
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
q_profile = PVCprofiles.objects.raw('SELECT'
' oknardia_pvcprofiles.id,'
' oknardia_pvcprofiles.sProfileName,'
' oknardia_pvcprofiles.sProfileBriefDescription,'
' oknardia_pvcprofiles.sProfileManufacturer,'
' oknardia_catalog2profile.sCatalogCardType,'
' oknardia_blogposts.sPostContent,'
' oknardia_blogposts.sPostHeader,'
'oknardia_pvcprofiles.dProfileModify,'
'MAX(oknardia_blogposts.dPostDataModify) AS lastBlog '
'FROM oknardia_catalog2profile'
' RIGHT OUTER JOIN oknardia_pvcprofiles'
' ON oknardia_catalog2profile.kProfile_id = oknardia_pvcprofiles.id'
' LEFT OUTER JOIN oknardia_blogposts'
' ON oknardia_catalog2profile.kBlogCatalog_id = oknardia_blogposts.id '
'GROUP BY oknardia_catalog2profile.sCatalogCardType,'
' oknardia_pvcprofiles.sProfileName,'
' oknardia_pvcprofiles.id,'
' oknardia_pvcprofiles.sProfileBriefDescription,'
' oknardia_pvcprofiles.sProfileManufacturer,'
' oknardia_blogposts.sPostHeader,'
' oknardia_blogposts.sPostContent,'
' oknardia_pvcprofiles.dProfileModify '
'ORDER BY oknardia_pvcprofiles.sProfileManufacturer,'
' oknardia_pvcprofiles.sProfileBriefDescription;')
to_template = {'CATALOG_PROFILE_NUM': pytils.numeral.get_plural(len(list(q_profile)), "профиль,профиля,профилей")}
list_profile_manufactures = []
tmp_profile_manufacture = ""
last_update = None
for i in q_profile:
if last_update is None:
last_update = i.dProfileModify
if last_update < i.dProfileModify:
last_update = i.dProfileModify
# if (i.lastBlog is not None) and (last_update < i.lastBlog):
# last_update = i.lastBlog
if tmp_profile_manufacture != i.sProfileManufacturer:
tmp_profile_manufacture = i.sProfileManufacturer
list_profile_manufactures.append({
"PROF_MAN_ID": i.id,
"PROF_MAN": i.sProfileManufacturer,
"PROF_MAN_T": pytils.translit.slugify(i.sProfileManufacturer).lower(),
"PROF_MAN_LIST": [{
"PROF_NAME_ID": i.id,
"PROF_NAME": i.sProfileBriefDescription,
"PROF_NAME_T": pytils.translit.slugify(i.sProfileName).lower(),
}]
})
# print("===", i.sProfileManufacturer, ">>> >>> >>>", Rus2Url(i.sProfileManufacturer))
elif len(list_profile_manufactures) == 0:
# Какая-то фигня. Похоже "пустой" производитель профиля (пустая строка). Ну его нафиг.
continue
else:
list_profile_manufactures[-1]["PROF_MAN_LIST"].append({
"PROF_NAME_ID": i.id,
"PROF_NAME": i.sProfileBriefDescription,
"PROF_NAME_T": pytils.translit.slugify(i.sProfileName).lower(),
})
# print(\"--- ---", i.sProfileBriefDescription, ">>>", Rus2Url(i.sProfileBriefDescription))
to_template.update({
'CATALOG_PROFILE_MAN1_NAME2': list_profile_manufactures,
'CATALOG_MANUFACT_NUM': len(list_profile_manufactures),
'CATALOG_MANUFACT_NUM_W':
pytils.numeral.sum_string(len(list_profile_manufactures), pytils.numeral.MALE, ("производитель",
"производителя",
"производителей")),
'CATALOG_LAST_UPDATE': last_update,
'CATALOG_LAST_UPDATE_W': pytils.dt.distance_of_time_in_words(time.mktime(last_update.timetuple()), accuracy=2),
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)
})
return render(request, "catalog/catalog_of_profiles.html", to_template)
def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture_name: str,
model_id: id, model_name: str) -> HttpResponse:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница с описанием марки профиля
:param request: HttpRequest -- входящий http-запрос
:param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription
:param manufacture_name: название производителя (транслитерированное pytils.translit.slugify())
:param model_id: id модели (марки) профиля
:param model_name: модель (марка) профиля (транслитерированное pytils.translit.slugify(sProfileName))
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
manufacture_id = int(manufacture_id)
model_id = int(model_id)
q_pvc_by_id = PVCprofiles.objects.get(id=model_id)
if pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer) != manufacture_name \
or pytils.translit.slugify(q_pvc_by_id.sProfileName) != model_name \
or manufacture_id != model_id:
return redirect(f"/catalog/profile/{model_id}-{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}/"
f"{model_id}-{pytils.translit.slugify(q_pvc_by_id.sProfileName)}")
to_template = {"CATALOG_MODEL": q_pvc_by_id,
"CATALOG_MAN2URL": manufacture_name,
"CATALOG_URL": f"{manufacture_id}-{manufacture_name}",
"CATALOG_URL2": f"{manufacture_id}-{manufacture_name}/{model_id}-{model_name}",
"PROFILE_RATING_STARS": get_rating_set_for_stars(q_pvc_by_id.fProfileRating)}
try:
got_json = json.loads(q_pvc_by_id.sProfileDescription)
# раскрашиваем кружочки рейтинга напротив характеристик профиля
if KEY_RATING in got_json:
# RatingReal = True # Рейтинг реальный (профиль представлен в ценовых предложениях)
# кружочки зелёные
rating = got_json[KEY_RATING]
color = int(255 - rating[RANK_PVCP_CAMERAS_NUM_NAME] * 255)
to_template.update({"RANK_PVCP_CAMERAS_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_SEALS_NAME] * 255)
to_template.update({"RANK_PVCP_SEALS_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_THICKNESS_NAME] * 255)
to_template.update({"RANK_PVCP_THICKNESS_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_G_THICKNESS_NAME] * 255)
to_template.update({"RANK_PVCP_G_THICKNESS_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_RABBET_NAME] * 255)
to_template.update({"RANK_PVCP_RABBET_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_HEAT_TRANSFER_NAME] * 255)
to_template.update({"RANK_PVCP_HEAT_TRANSFER_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_SOUNDPROOFING_NAME] * 255)
to_template.update({"RANK_PVCP_SOUNDPROOFING_COLOR": f"{color},255,{color}"})
color = int(255 - rating[RANK_PVCP_HEIGHT_NAME] * 255)
to_template.update({"RANK_PVCP_HEIGHT_COLOR": f"{color},255,{color}"})
elif KEY_RATING_VIRTUAL in got_json:
# RatingReal = False # Рейтинг виртуальный (профиль представлен в ценовых предложениях)
# кружочки серые
rating = got_json[KEY_RATING_VIRTUAL]
color = int(255 - rating[RANK_PVCP_CAMERAS_NUM_NAME] * 64)
to_template.update({"RANK_PVCP_CAMERAS_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_SEALS_NAME] * 64)
to_template.update({"RANK_PVCP_SEALS_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_THICKNESS_NAME] * 64)
to_template.update({"RANK_PVCP_THICKNESS_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_G_THICKNESS_NAME] * 64)
to_template.update({"RANK_PVCP_G_THICKNESS_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_RABBET_NAME] * 64)
to_template.update({"RANK_PVCP_RABBET_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_HEAT_TRANSFER_NAME] * 64)
to_template.update({"RANK_PVCP_HEAT_TRANSFER_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_SOUNDPROOFING_NAME] * 64)
to_template.update({"RANK_PVCP_SOUNDPROOFING_COLOR": f"{color},{color},{color}"})
color = int(255 - rating[RANK_PVCP_HEIGHT_NAME] * 64)
to_template.update({"RANK_PVCP_HEIGHT_COLOR": f"{color},{color},{color}"})
else:
pass
if KEY_HTML in got_json:
to_template.update({"EXTRA_INFO": got_json[KEY_HTML]})
except (TypeError, ValueError, KeyError):
pass
list_other = []
for i in q_pvc_by_id.sProfileOther.split(";"):
j = i.find(":")
list_other.append(u"<b>" + i[:j + 1] + u"</b>" + i[j + 1:])
to_template.update({"LIST_OTHER": list_other})
q_merchant = PVCprofiles.objects.raw(f"SELECT"
f" COUNT(oknardia_priceoffer.id) AS offers_by_merchant,"
f" oknardia_merchantbrand.sMerchantName,"
f" oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.id "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_pvcprofiles.id = {model_id} "
f"GROUP BY oknardia_merchantbrand.sMerchantName,"
f" oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.id "
f"ORDER BY offers_by_merchant DESC;")
list_merchant = []
for i in q_merchant:
list_merchant.append({
"MERCHANT_ID": i.id,
"MERCHANT_NAME": i.sMerchantName,
"MERCHANT_NAME_T": pytils.translit.slugify(i.sMerchantName),
"MERCHANT_LOGO_URL": i.pMerchantLogo,
"MERCHANT_OFFERS": i.offers_by_merchant,
})
to_template.update({'MERCHANTS': list_merchant})
q_profiles = PVCprofiles.objects.raw(f"SELECT oknardia_pvcprofiles.id,"
f" oknardia_pvcprofiles.fProfileRating,"
f" oknardia_pvcprofiles.sProfileBriefDescription,"
f" oknardia_pvcprofiles.sProfileName "
f"FROM oknardia_pvcprofiles "
f"WHERE oknardia_pvcprofiles.sProfileManufacturer ="
f" '{q_pvc_by_id.sProfileManufacturer}' "
f"ORDER BY oknardia_pvcprofiles.fProfileRating;")
list_profiles = []
for i in q_profiles:
if i.id != model_id:
list_profiles.append({
"PROFILE_NAME": i.sProfileBriefDescription,
"PROFILE_ID": i.id,
"PROFILE_URL": pytils.translit.slugify(i.sProfileName).lower(),
"PROFILE_RATING": i.fProfileRating,
"PROFILE_RATING_STARS": get_rating_set_for_stars(i.fProfileRating),
})
to_template.update({'PROFILES': list_profiles})
q_profiles_detail = PVCprofiles.objects.raw(f"SELECT"
f" oknardia_blogposts.*,"
f" oknardia_pvcprofiles.id,"
f" oknardia_catalog2profile.sCatalogCardType,"
f" oknardia_blogposts.iCatalogSort "
f"FROM oknardia_catalog2profile"
f" INNER JOIN oknardia_blogposts"
f" ON oknardia_catalog2profile.kBlogCatalog_id=oknardia_blogposts.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_catalog2profile.kProfile_id=oknardia_pvcprofiles.id "
f"WHERE oknardia_pvcprofiles.id = {model_id} "
f"AND oknardia_catalog2profile.sCatalogCardType ="
f" {CATALOG_RECORD_FOR_PROFILE_MODEL} "
f"ORDER BY oknardia_blogposts.iCatalogSort;")
list_profiles_detail = list(q_profiles_detail)
to_template.update({'PROFILE_DETAIL': list_profiles_detail})
list_img_for_blog = []
for i in list_profiles_detail:
if i.sImgForBlogSocial != "":
list_img_for_blog.append(i.sImgForBlogSocial)
if len(list_profiles_detail) > 0:
random.shuffle(list_img_for_blog)
to_template.update({'IMG_FOR_BLOG': list_img_for_blog[0]})
to_template.update({'PUB_DAT': q_pvc_by_id.dProfileModify})
if len(list_profiles_detail) > 0:
pub_data = sorted(list_profiles_detail, key=lambda item: item.dPostDataModify)[0].dPostDataModify
if pub_data.replace(tzinfo=None) < q_pvc_by_id.dProfileModify.replace(tzinfo=None):
to_template.update({'PUB_DAT': pub_data})
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)
})
return render(request, "catalog/catalog_of_profiles_model.html", to_template)
def catalog_profile_manufacture(request: HttpRequest, manufacture_id: int, manufacture_name: str) -> HttpResponse:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница с описанием производителя профилей и списком марки производимых им профилей
:param request: HttpRequest -- входящий http-запрос
:param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription
:param manufacture_name: название производителя (транслитерированное pytils.translit.slugify())
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
manufacture_id = int(manufacture_id)
q_pvc_by_id = PVCprofiles.objects.get(id=manufacture_id)
if pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer) != manufacture_name:
return redirect(f'/catalog/profile/{manufacture_id}-'
f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}')
else:
q_pvc_by_id = PVCprofiles.objects.order_by('id') \
.filter(sProfileManufacturer=q_pvc_by_id.sProfileManufacturer).first()
if q_pvc_by_id.id != manufacture_id:
return redirect(f'/catalog/profile/{q_pvc_by_id.id}-'
f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}')
to_template = {'CATALOG_MANUFACT': q_pvc_by_id.sProfileManufacturer,
'CATALOG_MAN2URL': manufacture_name,
'CATALOG_URL': f"{manufacture_id}-{manufacture_name}"}
try:
# получаем информацию о производителе (статью из блога)
manufacture_description = list(PVCprofiles.objects.raw(
f"SELECT "
f" oknardia_blogposts.* "
f"FROM oknardia_catalog2profile"
f" RIGHT OUTER JOIN oknardia_pvcprofiles"
f" ON oknardia_catalog2profile.kProfile_id = oknardia_pvcprofiles.id"
f" LEFT OUTER JOIN oknardia_blogposts"
f" ON oknardia_catalog2profile.kBlogCatalog_id = oknardia_blogposts.id "
f"WHERE oknardia_catalog2profile.sCatalogCardType = {CATALOG_RECORD_FOR_PROFILE_MANUFACTURER} "
f" AND oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}'"
f" AND oknardia_blogposts.bCatalog IS TRUE "
f"GROUP BY oknardia_blogposts.bCatalog "
f"LIMIT 1;"
))[0]
to_template.update({'PUB_DAT': manufacture_description.dPostDataModify})
if PATH_FOR_IMG_BLOG in manufacture_description.sImgForBlogSocial:
to_template.update({'IMG_FOR_BLOG': manufacture_description.sImgForBlogSocial})
to_template.update({'HEADER': manufacture_description.sPostHeader,
'CONTENT': re.sub(r'<cut[\s\S]*>', '', manufacture_description.sPostContent,
0, re.IGNORECASE)})
to_template.update({'TIZER': re.sub(r'<script[\s\S]*?</script>|<style[\s\S]*?</style>|<iframe[\s\S]*?</iframe>',
'', to_template["CONTENT"], 0, re.IGNORECASE)})
except (ObjectDoesNotExist, IndexError, TypeError, KeyError,):
pass
q_profiles = PVCprofiles.objects.raw(
f"SELECT oknardia_pvcprofiles.id,"
f" oknardia_pvcprofiles.fProfileRating,"
f" oknardia_pvcprofiles.sProfileBriefDescription,"
f" oknardia_pvcprofiles.sProfileName "
f"FROM oknardia_pvcprofiles "
f"WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}' "
f"ORDER BY oknardia_pvcprofiles.fProfileRating;"
)
list_profiles = []
for i in q_profiles:
list_profiles.append({
"PROFILE_NAME": i.sProfileBriefDescription,
"PROFILE_ID": i.id,
"PROFILE_URL": pytils.translit.slugify(i.sProfileName).lower(),
"PROFILE_RATING": i.fProfileRating,
"PROFILE_RATING_STARS": get_rating_set_for_stars(i.fProfileRating),
})
to_template.update({'PROFILES': list_profiles})
try:
q_share_of_offers = list(PVCprofiles.objects.raw(
f"SELECT"
f" 1 AS id,"
f" SUM(Q1.offers_by_model) AS offers_by_maufacture,"
f" Q2.tatal_offers-SUM(Q1.offers_by_model) AS offers_other "
f"FROM (SELECT COUNT(oknardia_priceoffer.id) AS offers_by_model"
f" FROM oknardia_priceoffer"
f" LEFT OUTER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" RIGHT OUTER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}') Q1,"
f" (SELECT COUNT(oknardia_priceoffer.id) AS tatal_offers"
f" FROM oknardia_priceoffer) AS Q2 "
f"LIMIT 1;"
))[0]
to_template.update({
'OFFERS_BY_MAUFACTURE': q_share_of_offers.offers_by_maufacture,
'OFFERS_OTHER': q_share_of_offers.offers_other,
'OFFERS_ANGLE': 90 + 180 * normalize(q_share_of_offers.offers_by_maufacture,
q_share_of_offers.offers_other + q_share_of_offers.offers_by_maufacture)
})
if q_share_of_offers is not None and q_share_of_offers.offers_by_maufacture != 0:
q_merchant = PVCprofiles.objects.raw(
f"SELECT"
f" COUNT(oknardia_priceoffer.id) AS offers_by_merchant,"
f" oknardia_merchantbrand.sMerchantName,"
f" oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.id "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_pvcprofiles.sProfileManufacturer = '{q_pvc_by_id.sProfileManufacturer}' "
f"GROUP BY oknardia_merchantbrand.sMerchantName,"
f" oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.id "
f"ORDER BY offers_by_merchant DESC;"
)
list_merchant = []
for i in q_merchant:
list_merchant.append({
"MERCHANT_ID": i.id,
"MERCHANT_NAME": i.sMerchantName,
"MERCHANT_NAME_T": pytils.translit.slugify(i.sMerchantName),
"MERCHANT_LOGO_URL": i.pMerchantLogo,
"MERCHANT_OFFERS": i.offers_by_merchant
})
to_template.update({'MERCHANTS': list_merchant})
except (ObjectDoesNotExist, IndexError, TypeError): # вообще-то, запрос q_share_of_offers всегда что-то вернёт,
pass # но на всякий случай
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)
})
return render(request, "catalog/catalog_of_profiles_manufacture.html", to_template)
# Каталог типовый серий зданий (пока переадресация)
def catalog_seria(request: HttpRequest) -> HttpResponse:
"""
КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница со всеми сериями зданий в базе окнардии
:param request: HttpRequest -- входящий http-запрос
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
try:
q_seria = Seria_Info.objects.raw('SELECT'
' oknardia_seria_info.id,'
' oknardia_seria_info.sURL2IMG,'
' oknardia_seria_info.sName '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
list_seria = []
for i in q_seria:
list_seria.append({
"ID": i.id,
"URL": i.sURL2IMG,
"NAME": i.sName,
"NAME_T": pytils.translit.slugify(i.sName)
})
to_template = {'SERIAS': list_seria}
except (ObjectDoesNotExist,):
to_template = {}
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)
})
return render(request, "catalog/catalog_seria.html", to_template)
def catalog_seria_info(request: HttpRequest, seria_name_translit: str = "II-49", seria_id: int = 12) -> HttpResponse:
"""
КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница детальной информацией по серии зданий
:param request: HttpRequest -- входящий http-запрос
:param seria_name_translit: str -- имя серии здания (транслитерированное pytils.translit.slugify())
:param seria_id: int -- id серии
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.time()
msg = ""
try:
seria_id = int(seria_id)
q_seria = Seria_Info.objects.get(id=seria_id)
if q_seria.id != q_seria.kRoot_id or seria_name_translit != pytils.translit.slugify(q_seria.sName):
return redirect(f"/catalog/seria/{pytils.translit.slugify(q_seria.sName)}/all{seria_id}")
except(ObjectDoesNotExist, ValueError,):
return redirect("/catalog/")
# если есть "облегченный" шаблон с частичным пре-рендером, то используем его.
light_template = f"{PATH_FOR_SERIA_INFO_HTML_INCLUDE}{str(seria_id)}_id.html"
light_template_w_path = f"{TEMPLATES[0]['DIRS'][0]}/{light_template}"
# print(f"{TEMPLATES[0]['DIRS'][0]}/{light_template}")
# print(light_template_w_path)
if os.path.isfile(light_template_w_path):
is_hard_template = False
else:
is_hard_template = True
to_template = {}
# получаем проемы использующиеся в данной серии домов
q_windows_in_seria = Win_MountDim.objects.raw(
f"SELECT DISTINCT"
f" oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,"
f" oknardia_win_mountdim.sDescripion, oknardia_win_mountdim.bIsDoor,"
f" oknardia_win_mountdim.bIsNearDoor, oknardia_win_mountdim.sFlapConfig,"
f" oknardia_win_mountdim.iWinDepth, oknardia_win_mountdim.id,"
f" 1 AS iQuantity "
f"FROM oknardia_mountdim2apartment"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_apartment_type"
f" ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id "
f"WHERE oknardia_apartment_type.kSeria_id = {seria_id}"
f" ORDER BY oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC;")
if is_hard_template:
# Получаем данные для отрисовки больших картинок с проёмами и передаём в "тяжёлый" шаблон
to_template.update(get_flaps_for_big_pictures(q_windows_in_seria))
# формируем строку для включения в SQL-запрос вида "(2,8,16,46,1)"
str_for_sql_in = "("
for count in q_windows_in_seria:
str_for_sql_in += str(count.id) + ","
str_for_sql_in = str_for_sql_in[:-1] + ")"
# print StringForSqlIN
# Получаем данные для таблички Окон по типам квартирах в серии дома
# " IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity," \
# tStart2 = time.time() # замер времени
q_win_in_apartment_in_seria = Win_MountDim.objects.raw(
f"SELECT"
f" oknardia_win_mountdim.id,"
f" oknardia_apartment_type.sNameApartment,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight,"
f" oknardia_apartment_type.id AS id_apart,"
f" IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity,"
f" COUNT(oknardia_priceoffer.id) AS NumOffers "
f"FROM oknardia_apartment_type"
f" INNER JOIN oknardia_win_mountdim"
f" LEFT OUTER JOIN oknardia_mountdim2apartment"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" AND oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id"
f" LEFT OUTER JOIN oknardia_priceoffer"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" LEFT OUTER JOIN oknardia_ouruser"
f" ON oknardia_ouruser.id = oknardia_priceoffer.kOfferFromUser_id "
f"WHERE oknardia_apartment_type.kSeria_id = {seria_id} "
f"AND oknardia_win_mountdim.id IN {str_for_sql_in} "
f"GROUP BY oknardia_apartment_type.id,"
f" oknardia_apartment_type.sNameApartment,"
f" oknardia_win_mountdim.id,"
f" oknardia_mountdim2apartment.iQuantity "
f"ORDER BY oknardia_apartment_type.iSort,"
f" oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC;")
list_win_in_seria = list(q_windows_in_seria)
total_column = len(list_win_in_seria) - 1
count_column = 0
min_offer_in_row = 1000000000
table_of_win_in_seria_by_apartmment = []
row_for_table = []
offer_and_merchant_per_win = [
{
"WIN_OFFER": 0,
"WIN_MERCHANT": 0,
"WIN_W": list_win_in_seria[i].iWinWidth,
"WIN_H": list_win_in_seria[i].iWinHight,
"WIN_ID": list_win_in_seria[i].id
} for i in range(total_column + 1)]
for count in q_win_in_apartment_in_seria:
if count.iQuantity != 0:
row_for_table.append({
"WIN_NUM": [chr(65 + count_column)],
"WIN_Q": count.iQuantity,
"WIN_ID": count.id,
"WIN_WIDTH": list_win_in_seria[count_column].iWinWidth,
"WIN_HEIGHT": list_win_in_seria[count_column].iWinHight,
"WIN_DESCRIPTION": list_win_in_seria[count_column].sDescripion,
"WIN_FLAPCFG": list_win_in_seria[count_column].sFlapConfig
})
if min_offer_in_row > count.NumOffers:
min_offer_in_row = count.NumOffers
if offer_and_merchant_per_win[count_column]["WIN_OFFER"] < count.NumOffers:
offer_and_merchant_per_win[count_column]["WIN_OFFER"] = count.NumOffers
else:
row_for_table.append({"WIN_NUM": ""})
if count_column < total_column:
count_column += 1
else:
# print row_for_table
table_of_win_in_seria_by_apartmment.append({"WIN_IN_APART": row_for_table,
"APART_NAME": count.sNameApartment,
"APART_ID": count.id_apart,
"NUM_OFFERS": min_offer_in_row})
count_column = 0
min_offer_in_row = 10000
row_for_table = []
# print(table_of_win_in_seria_by_apartmment)
# print(f"==============>{float(time.time()-tStart2)}<==============")
# print NumOffersPerColumn, NumMerchantPerColumn
to_template.update({"WIN_OFFER_AND_MERCHANT": offer_and_merchant_per_win,
"TABLE_OF_WINDOWS": table_of_win_in_seria_by_apartmment})
# для "тяжелого шаблона" получаем навигацию страницы, данные для карты и графика ввода в эксплуатацию
if is_hard_template:
# если вызывается "тяжелый" шаблон, то нужно подготовить тяжелые данные для построения навигации
seria_id, for_seria_nav = seria_nav(seria_id)
to_template.update(for_seria_nav) # данные для навигации по сериям
to_template.update(seria_info_year(seria_id)) # данные для графика ввода зданий серии в эксплуатацию
to_template.update(seria_info_geo_code(seria_id)) # данные для карты
# т.к. обрабатывается "тяжелый шаблон" надо создать "легкий шаблон"
# для его использования в будущем.
string_prerender = render_to_string("seria_info/all_seria_info_pre_light.html", to_template)
file = open(light_template_w_path, 'w')
# file.write(AA.encode('utf-8'))
file.write(string_prerender)
file.close()
else:
seria_name = Seria_Info.objects.get(id=seria_id).sName
to_template.update({'THIS_SERIA_NAME': seria_name})
# to_template.update({'LOG_VISIT': GetLastAllUserVisitSeriaList(SeriaName),
# 'ticks': float(time.time()-time_start)})
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.time() - time_start)
})
return render(request, light_template, to_template)
def seria_nav(seria_id: int = 12) -> (int, dict):
"""
Возвращает корректный seria_id и кортеж для построения навигации по сериям дома
:param seria_id: id серии
:return:
"""
q_seria = Seria_Info.objects.raw(
'SELECT oknardia_seria_info.id,'
' oknardia_seria_info.sName,'
' oknardia_seria_info.sSeriaDescription,'
' oknardia_seria_info.kRoot_id,'
' oknardia_seria_info.kParent_id '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
error_seria = True
for count_seria in q_seria:
if count_seria.id == int(seria_id):
error_seria = False
break
if error_seria:
# Ошибочный seria_id. Такой базовой серии нет и надо ее найти.
try:
query = Seria_Info.objects.get(id=int(seria_id))
if query.kRoot_id is not None:
# базовая серия прописана в kRoot_id
seria_id = query.kRoot_id
else:
# == корневой нет
# == ищем методом наименьших расстояний"
min_min = 100000000
min_id = seria_id
for count_seria in q_seria:
if math.fabs(int(seria_id) - count_seria.id) < min_min:
min_min = math.fabs(int(seria_id) - count_seria.id)
min_id = count_seria.id
seria_id = min_id
except ObjectDoesNotExist:
seria_id = q_seria[0].id
# print(f"-->{seria_id}<--")
return all_seria_nav(seria_id, q_seria)
def all_seria_nav(seria_id: int, q_seria) -> (int, dict):
seria_nav_dim = []
this_return = {}
for count_seria in q_seria:
one_seria = {}
one_seria.update({"SERIA_R": count_seria.sName, "ID2URL": count_seria.id})
if count_seria.id == seria_id:
this_return.update({"THIS_SERIA_NAME": count_seria.sName,
"THIS_SERIA_DESCRIPTION": count_seria.sSeriaDescription})
one_seria.update({"SERIA_L": ""})
else:
one_seria.update({"SERIA_L": pytils.translit.slugify(count_seria.sName)})
seria_nav_dim.append(one_seria)
this_return.update({"SERIA_NAV_DIM": seria_nav_dim})
return seria_id, this_return
def seria_info_year(seria_id: int = 12) -> dict:
""" Возвращает данные для графика распределения сдачи серии в эксплуатацию
:param seria_id: int -- id серии для которой нужно получить данные
:return: dict -- данные для графика распределения сдачи серии в эксплуатацию типа:
{"DATA4GRAPH": [{'YEAR': 1997, 'NUMS': 1, 'CLRS': '99'},
{'YEAR': 1998, 'NUMS': 15, 'CLRS': 'сс'},
{'YEAR': 1998, 'NUMS': 10, 'CLRS': 'a9'}
]
}
"""
seria_in_years = []
query = Seria_Info.objects.raw(
f"SELECT oknardia_building_info.iCommissioning_year as id,"
f" COUNT(oknardia_building_info.iCommissioning_year) AS NumInYear "
f"FROM oknardia_building_info"
f" INNER JOIN oknardia_seria_info"
f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id "
f"WHERE oknardia_seria_info.kRoot_id = {seria_id} "
f"GROUP BY oknardia_building_info.iCommissioning_year;"
)
max_per_year = 0
graph_color_light = 0xCC # самый светлый цвет на графике (максимальное значение)
graph_color_dark = 0x99 # самый темный цвет на графике (минимальное значение)
for YearCount in query:
if int(YearCount.NumInYear) > max_per_year:
max_per_year = int(YearCount.NumInYear)
# print("max", MaxPerYear)
for YearCount in query:
data_of_year = {}
try:
data_of_year.update({
"YEAR": int(YearCount.id),
"NUMS": YearCount.NumInYear,
"CLRS": str(hex(int(graph_color_dark + YearCount.NumInYear * (
graph_color_light - graph_color_dark) / max_per_year)))[2:]
})
except ValueError:
continue
seria_in_years.append(data_of_year)
# print(seria_in_years)
return {"DATA4GRAPH": seria_in_years}
def seria_info_geo_code(seria_id: str = '12') -> dict:
""" Возвращает массив геокоординат зданий одной серии
:param seria_id: str -- id серии для которой нужно получить данные
:return: dict -- массив геокоординат зданий серии
"""
data_return = {}
seria_to_geo = []
municipal_m2 = 0 # муниципальный фонд (кв.м)
residential_m2 = 0 # жилой фонд (кв.м)
government_m2 = 0 # государственные учреждения занимают (кв.м.)
residents = 0 # количество жильцов
apartments = 0 # число квартиры
accounts = 0 # количество лицевых счетов
condition_max = 0 # максимальное значение показателя состояния здания
condition_min = 1000000 # минимальное значение показателя состояния здания
query = Building_Info.objects.raw(
f"SELECT"
f" oknardia_building_info.id,"
f" oknardia_seria_info.kRoot_id as SerId,"
f" oknardia_building_info.sAddress,"
f" oknardia_building_info.fResidential_Area,"
f" oknardia_building_info.fMunicipal_Area,"
f" oknardia_building_info.fGovernment_Area,"
f" oknardia_building_info.iNum_Residents,"
f" oknardia_building_info.iNum_Apartments,"
f" oknardia_building_info.iNum_Accounts,"
f" oknardia_building_info.fCondition_House,"
f" oknardia_building_info.fGeoCode_Latitude,"
f" oknardia_building_info.fGeoCode_Longitude "
f"FROM oknardia_building_info"
f" INNER JOIN oknardia_seria_info"
f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id "
f"WHERE oknardia_seria_info.kRoot_id IN ({seria_id});"
)
for count in query:
if int(count.fGeoCode_Latitude) != 0 and int(count.fGeoCode_Longitude) != 0:
seria_to_geo.append({"LATITUDE": count.fGeoCode_Latitude,
"LONGITUDE": count.fGeoCode_Longitude,
"ADDR_ID": count.id,
"ADDR_LAT": pytils.translit.slugify(count.sAddress),
"ADDR_RUS": count.sAddress,
"SER_ID": count.SerId
})
if count.fMunicipal_Area > 0:
municipal_m2 += count.fMunicipal_Area
if count.fResidential_Area > 0:
residential_m2 += count.fResidential_Area
if count.fGovernment_Area > 0:
government_m2 += count.fGovernment_Area
if count.iNum_Residents > 0:
residents += count.iNum_Residents
if count.iNum_Residents > 0:
residents += count.iNum_Residents
if count.iNum_Apartments > 0:
apartments += count.iNum_Apartments
if count.iNum_Accounts > 0:
accounts += count.iNum_Accounts
if count.fCondition_House > 0:
if count.fCondition_House > condition_max:
condition_max = count.fCondition_House
if count.fCondition_House < condition_min:
condition_min = count.fCondition_House
data_return.update({"DATA4GEO": seria_to_geo,
"MUNICIPAL_M2": municipal_m2,
"RESIDENTIAL_M2": residential_m2,
"GOVERNMENT_M2": government_m2,
"RESIDENTS": residents,
"APARTMENTS": apartments,
"ACCOUNTS": accounts,
"CONDITION_MAX": condition_max,
"CONDITION_MIN": condition_min})
# print(seria_to_geo)
return data_return
if q_seria.id == q_seria.kRoot_id:
return redirect("f/catalog/seria/{pytils.translit.slugify(q_seria.sName)}/all{seria_id}")
except (Seria_Info.DoesNotExist, ValueError):
return redirect("/catalog/seria")
return redirect("/catalog/seria")
+161
View File
@@ -0,0 +1,161 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from django.utils import timezone
from oknardia.models import (
MerchantBrand,
)
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import get_rating_set_for_stars
import django.utils.dateformat
import time
import random
import re
import pytils
def catalog_company(request: HttpRequest) -> HttpResponse:
time_start = time.perf_counter()
to_template = {} # словарь, для передачи шаблону
q_company = MerchantBrand.objects.raw('SELECT'
' oknardia_merchantbrand.id,'
' oknardia_merchantbrand.sMerchantName,'
' oknardia_merchantbrand.pMerchantLogo,'
' oknardia_merchantbrand.sMerchantMainURL,'
' COUNT(oknardia_priceoffer.id) AS NumOffers,'
' AVG(oknardia_priceoffer.fOfferPrice) AS PriceAVG,'
' MAX(oknardia_priceoffer.dOfferModify) AS lastUpdate,'
' Q.NumSets,'
' Q.RatingAVG,'
' 1 AS STARS '
'FROM (SELECT'
' COUNT(oknardia_setkit.sSetName) AS NumSets,'
' oknardia_merchantoffice.kMerchantName_id AS Q_ID,'
' AVG(oknardia_setkit.fSetRating) AS RatingAVG'
' FROM oknardia_merchantoffice'
' INNER JOIN oknardia_ouruser'
' ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id'
' INNER JOIN oknardia_setkit'
' ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id'
' GROUP BY oknardia_merchantoffice.id,'
' oknardia_merchantoffice.kMerchantName_id) AS Q,'
' oknardia_ouruser'
' INNER JOIN oknardia_merchantoffice'
' ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id'
' INNER JOIN oknardia_priceoffer'
' ON oknardia_priceoffer.kOfferFromUser_id = oknardia_ouruser.id'
' INNER JOIN oknardia_merchantbrand'
' ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id'
' WHERE Q_ID = oknardia_merchantoffice.kMerchantName_id '
'GROUP BY oknardia_merchantoffice.kMerchantName_id '
'ORDER BY Q.RatingAVG DESC;')
list_company = list(q_company)
for i in list_company:
i.STARS = get_rating_set_for_stars(i.RatingAVG)
i.NumSets = pytils.numeral.get_plural(i.NumSets, u"оконный набор, оконных набора, оконных наборов")
i.NumOffers = pytils.numeral.get_plural(i.NumOffers, u"вариант, варианта, вариантов")
i.lastUpdate = pytils.dt.distance_of_time_in_words(int(django.utils.dateformat.format(i.lastUpdate, 'U')))
i.sMerchantMainURL = pytils.translit.slugify(i.sMerchantName)
# print("NAME:", i.sMerchantName, "\tNumSets:", i.NumSets, "\tNumOffers:", i.NumOffers,
# "\t:AverageRating:", i.RatingAVG, "\tAveragePrice:", i.PriceAVG, "\tSTARS:", i.STARS)
to_template.update({
'COMPANIES': list_company,
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "catalog/catalog_company.html", to_template)
def catalog_company_detail(request: HttpRequest, company_id: str, company_name_slug: str) -> HttpResponse:
time_start = time.perf_counter()
to_template = {} # словарь, для передачи шаблону
company_id = int(company_id)
q_by_id = MerchantBrand.objects.get(id=company_id)
if pytils.translit.slugify(q_by_id.sMerchantName) != company_name_slug:
return redirect('/catalog/company/%d-%s' % (company_id, pytils.translit.slugify(q_by_id.sMerchantName)))
to_template.update({'COMPANY': q_by_id.sMerchantName})
to_template.update({'COMPANY_ID': company_id})
to_template.update({'COMPANY_T': company_name_slug})
list_not = [u"нет", u"", ""]
to_template.update({'LIST_NOT': list_not})
q_sets = MerchantBrand.objects.raw(f"SELECT"
f" COUNT(oknardia_priceoffer.id) AS NumOffers,"
f" AVG(oknardia_priceoffer.fOfferPrice) AS priceAVG,"
f" MAX(oknardia_priceoffer.dOfferModify) AS lastUpdate,"
f" MIN(oknardia_priceoffer.dOfferCreate) AS earlyCreation,"
f" oknardia_merchantbrand.*,"
f" oknardia_merchantoffice.*,"
f" oknardia_merchantoffice.id AS idMERCH,"
f" oknardia_setkit.*,"
f" oknardia_setkit.id AS idSET,"
f" oknardia_pvcprofiles.*,"
f" oknardia_pvcprofiles.id AS idPVC,"
f" oknardia_glazing.*, "
f" oknardia_glazing.id AS idGLAZ "
f"FROM oknardia_ouruser"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_priceoffer"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id "
f"WHERE oknardia_merchantbrand.id = {company_id} "
f"AND oknardia_priceoffer.sOfferActive = TRUE "
f"GROUP BY oknardia_merchantoffice.id,"
f" oknardia_setkit.id,"
f" oknardia_setkit.fSetRating "
f"ORDER BY oknardia_setkit.fSetRating DESC;")
list_sets = list(q_sets)
for i in list_sets:
i.sMerchantMainURL = {"URL": i.sMerchantMainURL,
"URL_VIEW": re.sub(r"(?:^http://|^https://|/$|www\.)", "", i.sMerchantMainURL)}
k = random.randint(1, int(len(i.sOfficeEmails)/2) - 1)
i.sOfficeEmails = [i.sOfficeEmails[0:k], i.sOfficeEmails[k:-k], i.sOfficeEmails[-k:]]
to_template.update({'IMG_FOR_BLOG': i.pMerchantLogo})
i.fSetRating = {"RATING": i.fSetRating,
"STARS": get_rating_set_for_stars(i.fSetRating)}
i.lastUpdate = pytils.dt.distance_of_time_in_words(int(django.utils.dateformat.format(i.lastUpdate, 'U')))
i.earlyCreation = pytils.dt.distance_of_time_in_words(int(django.utils.dateformat.format(i.earlyCreation, 'U')))
i.sProfileName = {"NAME": i.sProfileName,
"NAME_T": pytils.translit.slugify(i.sProfileName)}
i.sProfileManufacturer = {"NAME": i.sProfileManufacturer,
"NAME_T": pytils.translit.slugify(i.sProfileManufacturer)}
i.fProfileSeals = pytils.numeral.sum_string(i.fProfileSeals, pytils.numeral.MALE, u"контур, контура, контуров")
if i.sSetImplementCatch.lower() in list_not:
i.sSetImplementCatch = ""
if i.sSetClimateControl.lower() in list_not:
i.sSetClimateControl = ""
if len(i.sProfileReinforcement) > 0:
i.sProfileReinforcement = i.sProfileReinforcement[0].lower()+i.sProfileReinforcement[1:]
if len(i.sSetSill) > 0:
i.sSetSill = i.sSetSill[0].lower()+i.sSetSill[1:]
if len(i.sSetPanes) > 0:
i.sSetPanes = i.sSetPanes[0].lower()+i.sSetPanes[1:]
if len(i.sSetSlope) > 0:
i.sSetSlope = i.sSetSlope[0].lower()+i.sSetSlope[1:]
if len(i.sSetUninstallInstall) > 0:
i.sSetUninstallInstall = i.sSetUninstallInstall[0].lower()+i.sSetUninstallInstall[1:]
if len(i.sSetDelivery) > 0:
i.sSetDelivery = i.sSetDelivery[0].lower()+i.sSetDelivery[1:]
if len(i.sSetOtherConditions) > 0:
i.sSetOtherConditions = i.sSetOtherConditions[0].lower()+i.sSetOtherConditions[1:]
to_template.update({
'SETS': list_sets,
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "catalog/catalog_company_detail.html", to_template)
+82
View File
@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.http import HttpRequest, HttpResponse
from oknardia.models import (
Seria_Info,
Win_MountDim,
)
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import get_flaps_for_mini_pictures
import time
import pytils
def standard_opening(request: HttpRequest) -> HttpResponse:
time_start = time.perf_counter()
to_template = {} # словарь, для передачи шаблону
q_seria = Seria_Info.objects.raw('SELECT oknardia_seria_info.id, oknardia_seria_info.sName '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
to_template.update({'SERIAS': list(q_seria)})
q_win_opening = Win_MountDim.objects.raw(
'SELECT oknardia_win_mountdim.*,'
' oknardia_seria_info.sName,'
' oknardia_seria_info.id AS ID_Seria '
'FROM oknardia_win_mountdim'
' INNER JOIN oknardia_mountdim2apartment'
' ON oknardia_win_mountdim.id = oknardia_mountdim2apartment.kMountDim_id'
' RIGHT OUTER JOIN oknardia_apartment_type'
' ON oknardia_apartment_type.id = oknardia_mountdim2apartment.kApartment_id'
' RIGHT OUTER JOIN oknardia_seria_info'
' ON oknardia_apartment_type.kSeria_id = oknardia_seria_info.id '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'GROUP BY oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,'
' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.bIsNearDoor,'
' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.id,'
' oknardia_seria_info.sName, oknardia_seria_info.id '
'ORDER BY oknardia_win_mountdim.iWinWidth DESC,'
' oknardia_win_mountdim.iWinHight DESC,'
' oknardia_win_mountdim.bIsNearDoor,'
' oknardia_win_mountdim.bIsDoor,'
' oknardia_win_mountdim.id,'
' oknardia_seria_info.sName;')
list_windows_opening = []
tmp_id = 0
for i in q_win_opening:
if tmp_id != i.id:
tmp_id = i.id
image_file_name = get_flaps_for_mini_pictures(i.sFlapConfig)
list_windows_opening.append({
"ID": i.id,
"INCLUDING_IN_SERIA": [{
"ID": i.ID_Seria,
"NAME_T": pytils.translit.slugify(i.sName),
"NAME": i.sName
}],
"INCLUDING_IN_SERIA_ID": [],
"URL2IMG": image_file_name,
"FLAP_CONFIG": i.sFlapConfig,
"DESCRIPTION": i.sDescripion.split(" для")[0].split(" (")[0],
"DESCRIPTION_L": i.sDescripion,
"IS_DOOR": i.bIsDoor,
"IS_NEAR_DOOR": i.bIsNearDoor,
"H": i.iWinHight * 10,
"W": i.iWinWidth * 10
})
else:
list_windows_opening[-1]["INCLUDING_IN_SERIA"].append({
"ID": i.ID_Seria,
"NAME_T": pytils.translit.slugify(i.sName),
"NAME": i.sName
})
to_template.update({
'LIST_WIN_OPENING': list_windows_opening,
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "catalog/catalog_standard_opening.html", to_template)
+356
View File
@@ -0,0 +1,356 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Count
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from oknardia.settings import *
from oknardia.models import Catalog2Profile, PVCprofiles, PriceOffer
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import normalize, get_rating_set_for_stars
import time
import json
import re
import pytils
# ---------------------------------------------------------------------------
# Модульные хелперы, общие для всех вьюх этого файла
# ---------------------------------------------------------------------------
def make_slug(value: str) -> str:
"""Транслитерирует строку в slug (pytils)."""
return pytils.translit.slugify(value).lower()
def _merchant_row_to_dict(row: dict) -> dict:
"""Преобразует ORM-строку с данными партнёра в словарь для шаблона."""
merchant_name = row["kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__sMerchantName"]
return {
"MERCHANT_ID": row["kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__id"],
"MERCHANT_NAME": merchant_name,
"MERCHANT_NAME_T": make_slug(merchant_name),
"MERCHANT_LOGO_URL": row["kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__pMerchantLogo"],
"MERCHANT_OFFERS": row["offers_by_merchant"],
}
def _profile_row_to_dict(profile: dict) -> dict:
"""Преобразует ORM-строку профиля в словарь для шаблона."""
return {
"PROFILE_NAME": profile["sProfileBriefDescription"],
"PROFILE_ID": profile["id"],
"PROFILE_URL": make_slug(profile["sProfileName"]),
"PROFILE_RATING": profile["fProfileRating"],
"PROFILE_RATING_STARS": get_rating_set_for_stars(profile["fProfileRating"]),
}
def _append_visit_context(to_template: dict, request: HttpRequest, time_start: float) -> None:
"""Дописывает в контекст стандартный хвост: визиты и время выполнения."""
to_template.update({
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start),
})
# ---------------------------------------------------------------------------
def catalog_profile(request: HttpRequest) -> HttpResponse:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница со списком производителей и моделей (марками) профилей
:param request: HttpRequest -- входящий http-запрос
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
# Берём только те поля, которые реально нужны для построения страницы каталога.
# Это позволяет не тащить лишние данные из БД и сразу работать с простыми словарями.
profile_rows = list(
PVCprofiles.objects.values(
"id",
"sProfileName",
"sProfileBriefDescription",
"sProfileManufacturer",
).order_by("sProfileManufacturer", "sProfileBriefDescription")
)
profile_count = len(profile_rows)
# В этом контексте смешанные типы значений (str/int/list/float), поэтому задаём общий тип явно.
to_template: dict[str, object] = {
'CATALOG_PROFILE_NUM': pytils.numeral.get_plural(profile_count, "профиль,профиля,профилей")
}
list_profile_manufactures = []
tmp_profile_manufacture = ""
for profile in profile_rows:
if profile["sProfileManufacturer"] == "":
# Пустой производитель в каталоге только мешает: не создаём для него отдельную группу.
continue
if tmp_profile_manufacture != profile["sProfileManufacturer"]:
# Новый производитель — открываем новую группу карточек.
tmp_profile_manufacture = profile["sProfileManufacturer"]
list_profile_manufactures.append({
"PROF_MAN_ID": profile["id"],
"PROF_MAN": profile["sProfileManufacturer"],
"PROF_MAN_T": make_slug(profile["sProfileManufacturer"]),
"PROF_MAN_LIST": [{
"PROF_NAME_ID": profile["id"],
"PROF_NAME": profile["sProfileBriefDescription"],
"PROF_NAME_T": make_slug(profile["sProfileName"]),
}]
})
else:
# Если производитель уже встречался, просто дописываем новую модель в его список.
list_profile_manufactures[-1]["PROF_MAN_LIST"].append({
"PROF_NAME_ID": profile["id"],
"PROF_NAME": profile["sProfileBriefDescription"],
"PROF_NAME_T": make_slug(profile["sProfileName"]),
})
to_template.update({
'CATALOG_PROFILE_MAN1_NAME2': list_profile_manufactures,
'CATALOG_MANUFACT_NUM': len(list_profile_manufactures),
'CATALOG_MANUFACT_NUM_W':
pytils.numeral.sum_string(len(list_profile_manufactures), pytils.numeral.MALE, ("производитель",
"производителя",
"производителей")),
})
_append_visit_context(to_template, request, time_start)
return render(request, "catalog/catalog_of_profiles.html", to_template)
def catalog_profile_model(request: HttpRequest, manufacture_id: int, manufacture_name: str,
model_id: int, model_name: str) -> HttpResponse:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница с описанием марки профиля
:param request: HttpRequest -- входящий http-запрос
:param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription
:param manufacture_name: название производителя (транслитерированное pytils.translit.slugify())
:param model_id: id модели (марки) профиля
:param model_name: модель (марка) профиля (транслитерированное pytils.translit.slugify(sProfileName))
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
manufacture_id = int(manufacture_id)
model_id = int(model_id)
q_pvc_by_id = PVCprofiles.objects.get(id=model_id)
manufacturer_slug = pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)
model_slug = pytils.translit.slugify(q_pvc_by_id.sProfileName)
if manufacturer_slug != manufacture_name \
or model_slug != model_name \
or manufacture_id != model_id:
return redirect(f"/catalog/profile/{model_id}-{manufacturer_slug}/"
f"{model_id}-{model_slug}")
# Локальные помощники держат вьюху короче и не размазывают однотипную логику по коду.
def build_other_list(value: str) -> list[str]:
# Убираем пустые куски, чтобы не плодить «пустые» характеристики в шаблоне.
result = []
for chunk in (part.strip() for part in value.split(";")):
if not chunk:
continue
if ":" in chunk:
head, tail = chunk.split(":", 1)
result.append(f"<b>{head.strip()}:</b>{tail.strip()}")
else:
result.append(f"<b>{chunk}</b>")
return result
def update_pub_dat(current_pub_dat: datetime | None, candidate_pub_dat: datetime | None) -> datetime | None:
# На странице оставляем дату публикации/обновления только если она реально новее карточки профиля.
if candidate_pub_dat is None:
return current_pub_dat
if current_pub_dat is None or candidate_pub_dat.replace(tzinfo=None) > current_pub_dat.replace(tzinfo=None):
return candidate_pub_dat
return current_pub_dat
def apply_rating_colors(rating: dict, rating_pairs: tuple[tuple[str, str], ...], multiplier: int,
gray: bool = False) -> None:
# Один маленький helper вместо россыпи почти одинаковых строк: меняется только множитель и формат RGB.
for rating_key, template_key in rating_pairs:
color = int(255 - rating[rating_key] * multiplier)
if gray:
to_template[template_key] = f"{color},{color},{color}"
else:
to_template[template_key] = f"{color},255,{color}"
to_template: dict[str, object] = {"CATALOG_MODEL": q_pvc_by_id,
"CATALOG_MAN2URL": manufacture_name,
"CATALOG_URL": f"{manufacture_id}-{manufacture_name}",
"CATALOG_URL2": f"{manufacture_id}-{manufacture_name}/{model_id}-{model_name}",
"PROFILE_RATING_STARS": get_rating_set_for_stars(q_pvc_by_id.fProfileRating)}
try:
got_json = json.loads(q_pvc_by_id.sProfileDescription)
# раскрашиваем кружочки рейтинга напротив характеристик профиля
rating_pairs = (
(RANK_PVCP_CAMERAS_NUM_NAME, "RANK_PVCP_CAMERAS_COLOR"),
(RANK_PVCP_SEALS_NAME, "RANK_PVCP_SEALS_COLOR"),
(RANK_PVCP_THICKNESS_NAME, "RANK_PVCP_THICKNESS_COLOR"),
(RANK_PVCP_G_THICKNESS_NAME, "RANK_PVCP_G_THICKNESS_COLOR"),
(RANK_PVCP_RABBET_NAME, "RANK_PVCP_RABBET_COLOR"),
(RANK_PVCP_HEAT_TRANSFER_NAME, "RANK_PVCP_HEAT_TRANSFER_COLOR"),
(RANK_PVCP_SOUNDPROOFING_NAME, "RANK_PVCP_SOUNDPROOFING_COLOR"),
(RANK_PVCP_HEIGHT_NAME, "RANK_PVCP_HEIGHT_COLOR"),
)
if KEY_RATING in got_json:
# кружочки зелёные
apply_rating_colors(got_json[KEY_RATING], rating_pairs, 255)
elif KEY_RATING_VIRTUAL in got_json:
# кружочки серые
apply_rating_colors(got_json[KEY_RATING_VIRTUAL], rating_pairs, 64, gray=True)
else:
pass
if KEY_HTML in got_json:
to_template.update({"EXTRA_INFO": got_json[KEY_HTML]})
except (TypeError, ValueError, KeyError):
pass
to_template.update({"LIST_OTHER": build_other_list(q_pvc_by_id.sProfileOther)})
# Партнёров считаем через ORM: так код проще читать и легче переносить между СУБД.
q_merchant = (
PriceOffer.objects.filter(
kOffer2SetKit__kSet2PVCprofiles_id=model_id,
sOfferActive=True,
)
.values(
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__id",
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__sMerchantName",
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__pMerchantLogo",
)
.annotate(offers_by_merchant=Count("id"))
.order_by("-offers_by_merchant", "kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__sMerchantName")
)
to_template.update({'MERCHANTS': [_merchant_row_to_dict(row) for row in q_merchant]})
# Близкие профили этого же производителя нужны для быстрых переходов по карточкам.
q_profiles = (
PVCprofiles.objects.filter(sProfileManufacturer=q_pvc_by_id.sProfileManufacturer)
.exclude(id=model_id)
.values("id", "fProfileRating", "sProfileBriefDescription", "sProfileName")
.order_by("fProfileRating")
)
to_template.update({'PROFILES': [_profile_row_to_dict(profile) for profile in q_profiles]})
# Описание профиля берём через связку каталог -> блог: это один ORM-запрос вместо сырого SQL.
q_profiles_detail = (
Catalog2Profile.objects.filter(
kProfile_id=model_id,
sCatalogCardType=CATALOG_RECORD_FOR_PROFILE_MODEL,
kBlogCatalog__isnull=False,
)
.select_related("kBlogCatalog")
.order_by("kBlogCatalog__iCatalogSort")
)
profile_blog_posts = [row.kBlogCatalog for row in q_profiles_detail if row.kBlogCatalog is not None]
to_template.update({'PROFILE_DETAIL': profile_blog_posts})
# Картинка и дата публикации для meta-тегов берутся из связанного блога, если он есть.
if profile_blog_posts:
for blog_post in profile_blog_posts:
if blog_post.sImgForBlogSocial:
to_template['IMG_FOR_BLOG'] = blog_post.sImgForBlogSocial
break
pub_dat: datetime = q_pvc_by_id.dProfileModify
if profile_blog_posts:
profile_blog_dat: datetime | None = max((post.dPostDataModify for post in profile_blog_posts), default=pub_dat)
pub_dat = update_pub_dat(pub_dat, profile_blog_dat) or pub_dat
to_template['PUB_DAT'] = pub_dat
_append_visit_context(to_template, request, time_start)
return render(request, "catalog/catalog_of_profiles_model.html", to_template)
def catalog_profile_manufacture(request: HttpRequest, manufacture_id: int, manufacture_name: str) -> HttpResponse:
"""
КАТАЛОГ ПРОФИЛЕЙ: страница с описанием производителя профилей и списком марки производимых им профилей
:param request: HttpRequest -- входящий http-запрос
:param manufacture_id: id профиля. Предполагается, что это первый id при сортировке по sProfileBriefDescription
:param manufacture_name: название производителя (транслитерированное pytils.translit.slugify())
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
manufacture_id = int(manufacture_id)
q_pvc_by_id = PVCprofiles.objects.get(id=manufacture_id)
if pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer) != manufacture_name:
return redirect(f'/catalog/profile/{manufacture_id}-'
f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}')
else:
q_pvc_by_id = PVCprofiles.objects.order_by('id') \
.filter(sProfileManufacturer=q_pvc_by_id.sProfileManufacturer).first()
if q_pvc_by_id.id != manufacture_id:
return redirect(f'/catalog/profile/{q_pvc_by_id.id}-'
f'{pytils.translit.slugify(q_pvc_by_id.sProfileManufacturer)}')
to_template: dict[str, object] = {'CATALOG_MANUFACT': q_pvc_by_id.sProfileManufacturer,
'CATALOG_MAN2URL': manufacture_name,
'CATALOG_URL': f"{manufacture_id}-{manufacture_name}"}
try:
# Получаем статью-описание производителя через Catalog2Profile → BlogPosts.
# GROUP BY из оригинального SQL здесь не нужен: нас устраивает любая первая запись.
catalog_entry = (
Catalog2Profile.objects.filter(
kProfile__sProfileManufacturer=q_pvc_by_id.sProfileManufacturer,
sCatalogCardType=CATALOG_RECORD_FOR_PROFILE_MANUFACTURER,
kBlogCatalog__bCatalog=True,
)
.select_related("kBlogCatalog")
.first()
)
if catalog_entry is None or catalog_entry.kBlogCatalog is None:
raise ObjectDoesNotExist
manufacture_description = catalog_entry.kBlogCatalog
to_template.update({'PUB_DAT': manufacture_description.dPostDataModify})
if PATH_FOR_IMG_BLOG in (manufacture_description.sImgForBlogSocial or ""):
to_template.update({'IMG_FOR_BLOG': manufacture_description.sImgForBlogSocial})
content = re.sub(r'<cut[\s\S]*>', '', manufacture_description.sPostContent, 0, re.IGNORECASE)
to_template.update({'HEADER': manufacture_description.sPostHeader, 'CONTENT': content})
to_template.update({'TIZER': re.sub(
r'<script[\s\S]*?</script>|<style[\s\S]*?</style>|<iframe[\s\S]*?</iframe>',
'', content, 0, re.IGNORECASE,
)})
except (ObjectDoesNotExist, IndexError, TypeError, KeyError):
pass
# Список всех профилей этого производителя для навигации по карточкам.
q_profiles = (
PVCprofiles.objects.filter(sProfileManufacturer=q_pvc_by_id.sProfileManufacturer)
.values("id", "fProfileRating", "sProfileBriefDescription", "sProfileName")
.order_by("fProfileRating")
)
to_template.update({'PROFILES': [_profile_row_to_dict(p) for p in q_profiles]})
try:
# Доля предложений этого производителя относительно всех предложений в базе.
offers_by_manufacture = PriceOffer.objects.filter(
kOffer2SetKit__kSet2PVCprofiles__sProfileManufacturer=q_pvc_by_id.sProfileManufacturer,
).count()
total_offers = PriceOffer.objects.count()
offers_other = total_offers - offers_by_manufacture
to_template.update({
'OFFERS_BY_MAUFACTURE': offers_by_manufacture,
'OFFERS_OTHER': offers_other,
'OFFERS_ANGLE': 90 + 180 * normalize(offers_by_manufacture, total_offers),
})
if offers_by_manufacture > 0:
# Партнёры, у которых есть предложения с профилями этого производителя.
q_merchant = (
PriceOffer.objects.filter(
kOffer2SetKit__kSet2PVCprofiles__sProfileManufacturer=q_pvc_by_id.sProfileManufacturer,
)
.values(
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__id",
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__sMerchantName",
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__pMerchantLogo",
)
.annotate(offers_by_merchant=Count("id"))
.order_by(
"-offers_by_merchant",
"kOffer2SetKit__kSet2User__kMerchantOffice__kMerchantName__sMerchantName",
)
)
to_template.update({'MERCHANTS': [_merchant_row_to_dict(row) for row in q_merchant]})
except (ObjectDoesNotExist, IndexError, TypeError):
pass
_append_visit_context(to_template, request, time_start)
return render(request, "catalog/catalog_of_profiles_manufacture.html", to_template)
+404
View File
@@ -0,0 +1,404 @@
# -*- coding: utf-8 -*-
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from django.template.loader import render_to_string
from oknardia.settings import *
from oknardia.models import (
Seria_Info,
Win_MountDim,
Building_Info,
)
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import get_flaps_for_big_pictures, touch_reload_wsgi
import time
import os
import math
import pytils
# Каталог типовых серий зданий (пока переадресация)
def catalog_seria(request: HttpRequest) -> HttpResponse:
"""
КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница со всеми сериями зданий в базе окнардии
:param request: HttpRequest -- входящий http-запрос
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
try:
q_seria = Seria_Info.objects.raw('SELECT'
' oknardia_seria_info.id,'
' oknardia_seria_info.sURL2IMG,'
' oknardia_seria_info.sName '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
list_seria = []
for i in q_seria:
list_seria.append({
"ID": i.id,
"URL": i.sURL2IMG,
"NAME": i.sName,
"NAME_T": pytils.translit.slugify(i.sName)
})
to_template = {'SERIAS': list_seria}
except (ObjectDoesNotExist,):
to_template = {}
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "catalog/catalog_seria.html", to_template)
def catalog_seria_info(request: HttpRequest, seria_name_translit: None, seria_id: int = 843) -> HttpResponse:
"""
КАТАЛОГ ТИПОВЫЙ СЕРИЙ: страница детальной информацией по серии зданий
:param request: HttpRequest -- входящий http-запрос
:param seria_name_translit: str -- имя серии здания (транслитерированное pytils.translit.slugify())
:param seria_id: int -- id серии
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
msg = ""
try:
seria_id = int(seria_id)
q_seria = Seria_Info.objects.get(id=seria_id)
if q_seria.id != q_seria.kRoot_id or seria_name_translit != pytils.translit.slugify(q_seria.sName):
return redirect(f"/catalog/seria/{pytils.translit.slugify(q_seria.sName)}/all{seria_id}")
except(ObjectDoesNotExist, ValueError,):
return redirect("/catalog/")
# если есть "облегченный" шаблон с частичным пре-рендером, то используем его.
light_template = f"{PATH_FOR_SERIA_INFO_HTML_INCLUDE}{str(seria_id)}_id.html"
light_template_w_path = f"{TEMPLATES[0]['DIRS'][0]}/{light_template}"
# print(f"{TEMPLATES[0]['DIRS'][0]}/{light_template}")
# print(light_template_w_path)
# print(light_template_w_path)
if os.path.isfile(light_template_w_path):
is_hard_template = False
else:
is_hard_template = True
to_template = {}
# получаем проемы использующиеся в данной серии домов
q_windows_in_seria = Win_MountDim.objects.raw(
f"SELECT DISTINCT"
f" oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,"
f" oknardia_win_mountdim.sDescripion, oknardia_win_mountdim.bIsDoor,"
f" oknardia_win_mountdim.bIsNearDoor, oknardia_win_mountdim.sFlapConfig,"
f" oknardia_win_mountdim.iWinDepth, oknardia_win_mountdim.id,"
f" 1 AS iQuantity "
f"FROM oknardia_mountdim2apartment"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_apartment_type"
f" ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id "
f"WHERE oknardia_apartment_type.kSeria_id = {seria_id}"
f" ORDER BY oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC;")
if is_hard_template:
# Получаем данные для отрисовки больших картинок с проёмами и передаём в "тяжёлый" шаблон
to_template.update(get_flaps_for_big_pictures(q_windows_in_seria))
# формируем строку для включения в SQL-запрос вида "(2,8,16,46,1)"
str_for_sql_in = "("
for count in q_windows_in_seria:
str_for_sql_in += str(count.id) + ","
str_for_sql_in = str_for_sql_in[:-1] + ")"
# print StringForSqlIN
# Получаем данные для таблички Окон по типам квартирах в серии дома
# " IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity," \
# tStart2 = time.perf_counter() # замер времени
q_win_in_apartment_in_seria = Win_MountDim.objects.raw(
f"SELECT"
f" oknardia_win_mountdim.id,"
f" oknardia_apartment_type.sNameApartment,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight,"
f" oknardia_apartment_type.id AS id_apart,"
f" IFNULL(oknardia_mountdim2apartment.iQuantity, 0) AS iQuantity,"
f" COUNT(oknardia_priceoffer.id) AS NumOffers "
f"FROM oknardia_apartment_type"
f" INNER JOIN oknardia_win_mountdim"
f" LEFT OUTER JOIN oknardia_mountdim2apartment"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" AND oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id"
f" LEFT OUTER JOIN oknardia_priceoffer"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" LEFT OUTER JOIN oknardia_ouruser"
f" ON oknardia_ouruser.id = oknardia_priceoffer.kOfferFromUser_id "
f"WHERE oknardia_apartment_type.kSeria_id = {seria_id} "
f"AND oknardia_win_mountdim.id IN {str_for_sql_in} "
f"GROUP BY oknardia_apartment_type.id,"
f" oknardia_apartment_type.sNameApartment,"
f" oknardia_win_mountdim.id,"
f" oknardia_mountdim2apartment.iQuantity "
f"ORDER BY oknardia_apartment_type.iSort,"
f" oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC;")
list_win_in_seria = list(q_windows_in_seria)
total_column = len(list_win_in_seria) - 1
count_column = 0
min_offer_in_row = 1000000000
table_of_win_in_seria_by_apartmment = []
row_for_table = []
offer_and_merchant_per_win = [
{
"WIN_OFFER": 0,
"WIN_MERCHANT": 0,
"WIN_W": list_win_in_seria[i].iWinWidth,
"WIN_H": list_win_in_seria[i].iWinHight,
"WIN_ID": list_win_in_seria[i].id
} for i in range(total_column + 1)]
for count in q_win_in_apartment_in_seria:
if count.iQuantity != 0:
row_for_table.append({
"WIN_NUM": [chr(65 + count_column)],
"WIN_Q": count.iQuantity,
"WIN_ID": count.id,
"WIN_WIDTH": list_win_in_seria[count_column].iWinWidth,
"WIN_HEIGHT": list_win_in_seria[count_column].iWinHight,
"WIN_DESCRIPTION": list_win_in_seria[count_column].sDescripion,
"WIN_FLAPCFG": list_win_in_seria[count_column].sFlapConfig
})
if min_offer_in_row > count.NumOffers:
min_offer_in_row = count.NumOffers
if offer_and_merchant_per_win[count_column]["WIN_OFFER"] < count.NumOffers:
offer_and_merchant_per_win[count_column]["WIN_OFFER"] = count.NumOffers
else:
row_for_table.append({"WIN_NUM": ""})
if count_column < total_column:
count_column += 1
else:
# print row_for_table
table_of_win_in_seria_by_apartmment.append({"WIN_IN_APART": row_for_table,
"APART_NAME": count.sNameApartment,
"APART_ID": count.id_apart,
"NUM_OFFERS": min_offer_in_row})
count_column = 0
min_offer_in_row = 10000
row_for_table = []
# print(table_of_win_in_seria_by_apartmment)
# print(f"==============>{float(time.perf_counter()-tStart2)}<==============")
# print NumOffersPerColumn, NumMerchantPerColumn
to_template.update({"WIN_OFFER_AND_MERCHANT": offer_and_merchant_per_win,
"TABLE_OF_WINDOWS": table_of_win_in_seria_by_apartmment})
# для "тяжелого шаблона" получаем навигацию страницы, данные для карты и графика ввода в эксплуатацию
if is_hard_template:
# если вызывается "тяжелый" шаблон, то нужно подготовить тяжелые данные для построения навигации
seria_id, for_seria_nav = seria_nav(seria_id)
to_template.update(for_seria_nav) # данные для навигации по сериям
to_template.update(seria_info_year(seria_id)) # данные для графика ввода зданий серии в эксплуатацию
to_template.update(seria_info_geo_code(seria_id)) # данные для карты
# т.к. обрабатывается "тяжелый шаблон" надо создать "легкий шаблон"
# для его использования в будущем.
string_prerender = render_to_string("seria_info/all_seria_info_pre_light.html", to_template)
file = open(light_template_w_path, 'w')
# file.write(AA.encode('utf-8'))
file.write(string_prerender)
file.close()
touch_reload_wsgi(light_template_w_path)
else:
seria_name = Seria_Info.objects.get(id=seria_id).sName
to_template.update({'THIS_SERIA_NAME': seria_name})
# to_template.update({'LOG_VISIT': GetLastAllUserVisitSeriaList(SeriaName),
# 'ticks': float(time.perf_counter()-time_start)})
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, light_template, to_template)
def seria_nav(seria_id: int = 12) -> (int, dict):
"""
Возвращает корректный seria_id и кортеж для построения навигации по сериям дома
:param seria_id: id серии
:return:
"""
q_seria = Seria_Info.objects.raw(
'SELECT oknardia_seria_info.id,'
' oknardia_seria_info.sName,'
' oknardia_seria_info.sSeriaDescription,'
' oknardia_seria_info.kRoot_id,'
' oknardia_seria_info.kParent_id '
'FROM oknardia_seria_info '
'WHERE oknardia_seria_info.id = oknardia_seria_info.kRoot_id '
'ORDER BY oknardia_seria_info.sName;')
error_seria = True
for count_seria in q_seria:
if count_seria.id == int(seria_id):
error_seria = False
break
if error_seria:
# Ошибочный seria_id. Такой базовой серии нет и надо ее найти.
try:
query = Seria_Info.objects.get(id=int(seria_id))
if query.kRoot_id is not None:
# базовая серия прописана в kRoot_id
seria_id = query.kRoot_id
else:
# == корневой нет
# == ищем методом наименьших расстояний"
min_min = 100000000
min_id = seria_id
for count_seria in q_seria:
if math.fabs(int(seria_id) - count_seria.id) < min_min:
min_min = math.fabs(int(seria_id) - count_seria.id)
min_id = count_seria.id
seria_id = min_id
except ObjectDoesNotExist:
seria_id = q_seria[0].id
# print(f"-->{seria_id}<--")
return all_seria_nav(seria_id, q_seria)
def all_seria_nav(seria_id: int, q_seria) -> (int, dict):
seria_nav_dim = []
this_return = {}
for count_seria in q_seria:
one_seria = {}
one_seria.update({"SERIA_R": count_seria.sName, "ID2URL": count_seria.id})
if count_seria.id == seria_id:
this_return.update({"THIS_SERIA_NAME": count_seria.sName,
"THIS_SERIA_DESCRIPTION": count_seria.sSeriaDescription})
# one_seria.update({"SERIA_L": ""})
one_seria.update({"SERIA_L": pytils.translit.slugify(count_seria.sName)})
else:
one_seria.update({"SERIA_L": pytils.translit.slugify(count_seria.sName)})
seria_nav_dim.append(one_seria)
this_return.update({"SERIA_NAV_DIM": seria_nav_dim})
return seria_id, this_return
def seria_info_year(seria_id: int = 12) -> dict:
""" Возвращает данные для графика распределения сдачи серии в эксплуатацию
:param seria_id: int -- id серии для которой нужно получить данные
:return: dict -- данные для графика распределения сдачи серии в эксплуатацию типа:
{"DATA4GRAPH": [{'YEAR': 1997, 'NUMS': 1, 'CLRS': '99'},
{'YEAR': 1998, 'NUMS': 15, 'CLRS': 'сс'},
{'YEAR': 1998, 'NUMS': 10, 'CLRS': 'a9'}
]
}
"""
seria_in_years = []
query = Seria_Info.objects.raw(
f"SELECT oknardia_building_info.iCommissioning_year as id,"
f" COUNT(oknardia_building_info.iCommissioning_year) AS NumInYear "
f"FROM oknardia_building_info"
f" INNER JOIN oknardia_seria_info"
f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id "
f"WHERE oknardia_seria_info.kRoot_id = {seria_id} "
f"GROUP BY oknardia_building_info.iCommissioning_year;"
)
max_per_year = 0
graph_color_light = 0xCC # самый светлый цвет на графике (максимальное значение)
graph_color_dark = 0x99 # самый темный цвет на графике (минимальное значение)
for YearCount in query:
if int(YearCount.NumInYear) > max_per_year:
max_per_year = int(YearCount.NumInYear)
# print("max", MaxPerYear)
for YearCount in query:
data_of_year = {}
try:
data_of_year.update({
"YEAR": int(YearCount.id),
"NUMS": YearCount.NumInYear,
"CLRS": str(hex(int(graph_color_dark + YearCount.NumInYear * (
graph_color_light - graph_color_dark) / max_per_year)))[2:]
})
except ValueError:
continue
seria_in_years.append(data_of_year)
# print(seria_in_years)
return {"DATA4GRAPH": seria_in_years}
def seria_info_geo_code(seria_id: str = '12') -> dict:
""" Возвращает массив геокоординат зданий одной серии
:param seria_id: str -- id серии для которой нужно получить данные
:return: dict -- массив геокоординат зданий серии
"""
data_return = {}
seria_to_geo = []
municipal_m2 = 0 # муниципальный фонд (кв.м)
residential_m2 = 0 # жилой фонд (кв.м)
government_m2 = 0 # государственные учреждения занимают (кв.м.)
residents = 0 # количество жильцов
apartments = 0 # число квартиры
accounts = 0 # количество лицевых счетов
condition_max = 0 # максимальное значение показателя состояния здания
condition_min = 1000000 # минимальное значение показателя состояния здания
query = Building_Info.objects.raw(
f"SELECT"
f" oknardia_building_info.id,"
f" oknardia_seria_info.kRoot_id as SerId,"
f" oknardia_building_info.sAddress,"
f" oknardia_building_info.fResidential_Area,"
f" oknardia_building_info.fMunicipal_Area,"
f" oknardia_building_info.fGovernment_Area,"
f" oknardia_building_info.iNum_Residents,"
f" oknardia_building_info.iNum_Apartments,"
f" oknardia_building_info.iNum_Accounts,"
f" oknardia_building_info.fCondition_House,"
f" oknardia_building_info.fGeoCode_Latitude,"
f" oknardia_building_info.fGeoCode_Longitude "
f"FROM oknardia_building_info"
f" INNER JOIN oknardia_seria_info"
f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id "
f"WHERE oknardia_seria_info.kRoot_id IN ({seria_id});"
)
for count in query:
if int(count.fGeoCode_Latitude) != 0 and int(count.fGeoCode_Longitude) != 0:
seria_to_geo.append({"LATITUDE": count.fGeoCode_Latitude,
"LONGITUDE": count.fGeoCode_Longitude,
"ADDR_ID": count.id,
"ADDR_LAT": pytils.translit.slugify(count.sAddress),
"ADDR_RUS": count.sAddress,
"SER_ID": count.SerId
})
if count.fMunicipal_Area > 0:
municipal_m2 += count.fMunicipal_Area
if count.fResidential_Area > 0:
residential_m2 += count.fResidential_Area
if count.fGovernment_Area > 0:
government_m2 += count.fGovernment_Area
if count.iNum_Residents > 0:
residents += count.iNum_Residents
if count.iNum_Residents > 0:
residents += count.iNum_Residents
if count.iNum_Apartments > 0:
apartments += count.iNum_Apartments
if count.iNum_Accounts > 0:
accounts += count.iNum_Accounts
if count.fCondition_House > 0:
if count.fCondition_House > condition_max:
condition_max = count.fCondition_House
if count.fCondition_House < condition_min:
condition_min = count.fCondition_House
data_return.update({"DATA4GEO": seria_to_geo,
"MUNICIPAL_M2": municipal_m2,
"RESIDENTIAL_M2": residential_m2,
"GOVERNMENT_M2": government_m2,
"RESIDENTS": residents,
"APARTMENTS": apartments,
"ACCOUNTS": accounts,
"CONDITION_MAX": condition_max,
"CONDITION_MIN": condition_min})
# print(seria_to_geo)
return data_return
View File
+2 -2
View File
@@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
from time import time
from oknardia.settings import *
from oknardia.models import Seria_Info
from web.catalog_series import all_seria_nav
# from oknardia.catalog import all_seria_nav
import math
import os
@@ -60,7 +61,6 @@ def statistic_menu(request: HttpRequest) -> HttpResponse:
:return: HttpResponse -- исходящий http-ответ
"""
time_start = time()
template = "seria_info/all_stat.html"
to_template = {}
seria_id, for_seria_nav = seria_nav(0)
to_template.update(for_seria_nav)
@@ -93,4 +93,4 @@ def statistic_menu(request: HttpRequest) -> HttpResponse:
# print(data2pie)
to_template.update({'DATA2PIE': data2pie})
to_template.update({'ticks': float(time()-time_start)})
return render(request, template, to_template)
return render(request, "seria_info/all_stat.html", to_template)
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
@@ -0,0 +1,612 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
"""
Команда генерации sitemap-файлов проекта.
Почему реализовано именно так:
- Генерация выполняется оффлайн (через management command), чтобы не нагружать веб-запросы.
- На выходе всегда создаются статические XML-файлы, которые потом отдает Nginx/прокси.
- URL-источники описаны через Django Sitemap API (классы Sitemap), но рендер XML
контролируем самостоятельно для точного управления лимитами размера/количества.
"""
from collections import defaultdict
from dataclasses import dataclass
from datetime import date, datetime
from itertools import combinations
from pathlib import Path
from typing import Iterable
from xml.etree import ElementTree as ET
from django.conf import settings
from django.contrib.sitemaps import Sitemap
from django.core.management.base import BaseCommand, CommandError
from django.db.models import Count, F, Max, Min
from django.utils import timezone
from oknardia.models import (
Apartment_Type,
BlogPosts,
Building_Info,
MerchantBrand,
PriceOffer,
PVCprofiles,
Seria_Info,
SetKit,
Win_MountDim,
)
import pytils
# Namespace схемы sitemap.xml по стандарту sitemaps.org.
SITEMAP_XMLNS = "http://www.sitemaps.org/schemas/sitemap/0.9"
@dataclass(slots=True)
class SitemapBuildResult:
"""Итог генерации sitemap для удобного вывода в CLI и web-обертках."""
# Общее число URL, записанных во все sitemap-файлы.
total_urls: int
# Количество созданных файлов (1 = только sitemap.xml, >1 = sitemapindex + sitemapNNNN.xml).
files_count: int
# Время выполнения генерации в секундах.
elapsed_seconds: float
# Физический каталог, куда записаны файлы.
output_dir: Path
def _as_sitemap_date(value: date | datetime | None) -> str:
"""
Приводит дату/время к формату `YYYY-MM-DD`.
Для sitemap нам не нужна точность до секунд: поисковикам достаточно даты.
Если значение не передано, используем текущую локальную дату.
"""
if value is None:
return timezone.localdate().isoformat()
if isinstance(value, datetime):
return value.date().isoformat()
return value.isoformat()
class SingleWindowSitemap(Sitemap):
"""Источник URL для страниц цен одного проёма (/tsena-odnogo-okna/...)."""
changefreq = "weekly"
priority = 0.5
def __init__(self, lastmod_value: datetime):
# Один timestamp на весь прогон: так проще сравнивать выпуски sitemap.
self.lastmod_value = lastmod_value
def items(self):
# Берем только те монтажные размеры, где есть реальные офферы.
# Сортировка по числу офферов повторяет историческую логику из raw SQL.
mount_ids = (
PriceOffer.objects.values("kOffer2MountDim_id")
.annotate(num_offer=Count("id"))
.order_by("num_offer", "kOffer2MountDim_id")
.values_list("kOffer2MountDim_id", flat=True)
)
# Возвращаем сами объекты Win_MountDim, чтобы location() строил URL без доп. запросов.
return Win_MountDim.objects.filter(id__in=mount_ids).only("id", "iWinWidth", "iWinHight")
def location(self, item: Win_MountDim) -> str:
# В БД размеры в см (Decimal с 1 знаком). В URL исторически используются мм,
# поэтому умножаем на 10 и приводим к int.
width_mm = int(float(item.iWinWidth) * 10)
height_mm = int(float(item.iWinHight) * 10)
return f"/tsena-odnogo-okna/{width_mm}x{height_mm}mm/tip{item.id}"
def lastmod(self, item: Win_MountDim) -> datetime:
return self.lastmod_value
class BuildingOffersSitemap(Sitemap):
"""Источник URL для страниц ценовой выдачи по адресам (/{build_id}/{apart_id}/{slug})."""
changefreq = "weekly"
priority = 0.5
def __init__(self, lastmod_value: datetime):
self.lastmod_value = lastmod_value
def items(self):
# Получаем здания только с валидной привязкой к корневой серии.
buildings = list(
Building_Info.objects.filter(kSeria_Link__kRoot__isnull=False)
.select_related("kSeria_Link__kRoot")
.only("id", "sAddress", "kSeria_Link__kRoot")
.order_by("id")
)
# Для каждой корневой серии нужен список типов квартир, чтобы собрать итоговые URL.
root_ids = {
building.kSeria_Link.kRoot_id
for building in buildings
if building.kSeria_Link_id and building.kSeria_Link.kRoot_id
}
apartments_by_root: dict[int, list[int]] = defaultdict(list)
for root_id, apart_id in Apartment_Type.objects.filter(kSeria_id__in=root_ids).values_list("kSeria_id", "id"):
apartments_by_root[root_id].append(apart_id)
# Генерируем декартово произведение: здание x квартиры его корневой серии.
for building in buildings:
root_id = building.kSeria_Link.kRoot_id if building.kSeria_Link_id else None
if not root_id:
continue
for apart_id in apartments_by_root.get(root_id, []):
yield (building.id, apart_id, pytils.translit.slugify(building.sAddress))
def location(self, item: tuple[int, int, str]) -> str:
build_id, apart_id, slug = item
return f"/{build_id}/{apart_id}/{slug}"
def lastmod(self, item: tuple[int, int, str]) -> datetime:
return self.lastmod_value
class CompareOffersSitemap(Sitemap):
"""Источник URL для страниц сравнения наборов (/compare_offers/1,2,3...)."""
# Для compare-страниц изменения редки, поэтому просим роботов не дергать их часто.
changefreq = "monthly"
priority = 0.35
def __init__(self, lastmod_value: datetime, min_depth: int = 2, max_depth: int = 4):
self.lastmod_value = lastmod_value
# Жестко ограничиваем глубину до 2..4, чтобы не получить комбинаторный взрыв.
self.min_depth = max(2, min_depth)
self.max_depth = min(4, max_depth)
def items(self):
# Берем только активные наборы и строим combinations без повторов/перестановок.
set_ids = list(SetKit.objects.filter(sSetActive=True).order_by("id").values_list("id", flat=True))
for depth in range(self.min_depth, self.max_depth + 1):
for combo in combinations(set_ids, depth):
# Формат URL-параметра должен остаться историческим: "1,2,3".
yield ",".join(str(item) for item in combo)
def location(self, item: str) -> str:
return f"/compare_offers/{item}"
def lastmod(self, item: str) -> datetime:
return self.lastmod_value
class StaticPagesSitemap(Sitemap):
"""Набор важных статических/обзорных страниц, которые не требуют отдельной модели."""
def __init__(self, items: list[dict]):
self._items = items
def items(self):
return self._items
def location(self, item: dict) -> str:
return item["loc"]
def lastmod(self, item: dict) -> date | datetime | None:
return item.get("lastmod")
def changefreq(self, item: dict) -> str:
return item.get("changefreq", "weekly")
def priority(self, item: dict) -> float:
return float(item.get("priority", 0.5))
class BlogListSitemap(Sitemap):
"""Страницы пагинации блога: /blog/P0, /blog/P1, ..."""
changefreq = "weekly"
priority = 0.82
def __init__(self, lastmod_value: date | datetime | None):
self.lastmod_value = lastmod_value
def items(self):
posts_qs = BlogPosts.objects.filter(
dPostDataBegin__lte=timezone.now(),
bPublished=True,
bArchive=False,
)
total_posts = posts_qs.count()
if total_posts == 0:
return []
pages_total = (total_posts - 1) // settings.NUM_BLOG_TIZER_IN_PAGE + 1
return list(range(pages_total))
def location(self, item: int) -> str:
return f"/blog/P{item}"
def lastmod(self, item: int) -> date | datetime | None:
return self.lastmod_value
class BlogPostSitemap(Sitemap):
"""Публичные посты блога в каноническом URL без page_back."""
changefreq = "monthly"
priority = 0.90
def items(self):
return BlogPosts.objects.filter(
dPostDataBegin__lte=timezone.now(),
bPublished=True,
bArchive=False,
).only("id", "sPostHeader", "dPostDataModify")
def location(self, item: BlogPosts) -> str:
return f"/blogpost/{item.id}/{pytils.translit.slugify(item.sPostHeader).lower()}"
def lastmod(self, item: BlogPosts) -> date | datetime | None:
return item.dPostDataModify
class ProfileManufactureSitemap(Sitemap):
"""Страницы производителей профилей: /catalog/profile/{id}-{manufacturer}."""
changefreq = "monthly"
priority = 0.92
def items(self):
return list(
PVCprofiles.objects.values("sProfileManufacturer")
.annotate(first_id=Min("id"), lastmod=Max("dProfileModify"))
.order_by("sProfileManufacturer")
)
def location(self, item: dict) -> str:
manufacturer_slug = pytils.translit.slugify(item["sProfileManufacturer"]).lower()
return f"/catalog/profile/{item['first_id']}-{manufacturer_slug}"
def lastmod(self, item: dict) -> date | datetime | None:
return item.get("lastmod")
class ProfileModelSitemap(Sitemap):
"""Карточки конкретных профильных систем."""
changefreq = "monthly"
priority = 0.94
def items(self):
return PVCprofiles.objects.only("id", "sProfileManufacturer", "sProfileName", "dProfileModify")
def location(self, item: PVCprofiles) -> str:
manufacturer_slug = pytils.translit.slugify(item.sProfileManufacturer).lower()
model_slug = pytils.translit.slugify(item.sProfileName).lower()
# Исторически канонический URL использует id модели и в сегменте manufacturer_id, и в segment model_id.
return f"/catalog/profile/{item.id}-{manufacturer_slug}/{item.id}-{model_slug}"
def lastmod(self, item: PVCprofiles) -> date | datetime | None:
return item.dProfileModify
class SeriaDetailSitemap(Sitemap):
"""Страницы типовых серий домов — это одни из самых важных SEO-страниц проекта."""
changefreq = "monthly"
priority = 0.97
def items(self):
return Seria_Info.objects.filter(id__isnull=False, kRoot_id__isnull=False, id=F("kRoot_id")).only(
"id", "sName", "dSeriaInfoModify"
)
def location(self, item: Seria_Info) -> str:
return f"/catalog/seria/{pytils.translit.slugify(item.sName).lower()}/all{item.id}"
def lastmod(self, item: Seria_Info) -> date | datetime | None:
return item.dSeriaInfoModify
class CompanyDetailSitemap(Sitemap):
"""Страницы брендов/производителей оконных компаний."""
changefreq = "monthly"
priority = 0.91
def items(self):
return list(
MerchantBrand.objects.annotate(
last_offer_modify=Max("merchantoffice__ouruser__setkit__priceoffer__dOfferModify"),
last_office_modify=Max("merchantoffice__dOfficeDataModify"),
).only("id", "sMerchantName")
)
def location(self, item: MerchantBrand) -> str:
return f"/catalog/company/{item.id}-{pytils.translit.slugify(item.sMerchantName).lower()}"
def lastmod(self, item: MerchantBrand) -> date | datetime | None:
return getattr(item, "last_offer_modify", None) or getattr(item, "last_office_modify", None)
class SitemapXmlWriter:
"""
Низкоуровневый писатель XML.
Делит URL на несколько файлов по двум условиям:
- число URL в файле;
- приблизительный размер файла в байтах.
Если chunk-файлов больше одного, создается sitemapindex (sitemap.xml),
который перечисляет sitemap0000.xml, sitemap0001.xml и т.д.
"""
def __init__(
self,
output_dir: Path,
public_base_url: str,
max_items: int,
max_file_size: int,
max_files_qty: int,
):
self.output_dir = output_dir
# Публичный URL-префикс для ссылок в sitemapindex.
self.public_base_url = public_base_url.rstrip("/")
self.max_items = max_items
self.max_file_size = max_file_size
self.max_files_qty = max_files_qty
self.total_urls = 0
self.chunk_files: list[str] = []
self.current_urls: list[ET.Element] = []
# Небольшой стартовый запас размера на корневые XML-теги.
self.current_size = 128
def cleanup_old(self) -> None:
# Перед генерацией удаляем старые sitemap*.xml, чтобы не оставить устаревшие куски.
self.output_dir.mkdir(parents=True, exist_ok=True)
for file_path in self.output_dir.glob("sitemap*.xml"):
file_path.unlink(missing_ok=True)
def add_url(self, loc: str, lastmod: datetime, changefreq: str, priority: float) -> None:
# Собираем XML-элемент URL и оцениваем его вклад в размер файла.
url_element = self._build_url_element(loc=loc, lastmod=lastmod, changefreq=changefreq, priority=priority)
url_size = len(ET.tostring(url_element, encoding="utf-8"))
need_flush = False
if self.current_urls:
# Лимиты применяем только если файл уже что-то содержит:
# так мы гарантируем, что хотя бы один URL всегда будет записан.
if len(self.current_urls) >= self.max_items:
need_flush = True
elif self.current_size + url_size > self.max_file_size:
need_flush = True
if need_flush:
self._flush_chunk()
self.current_urls.append(url_element)
self.current_size += url_size
self.total_urls += 1
def finalize(self, generated_at: datetime) -> int:
# Если уже были chunk-файлы, значит итог должен быть в формате sitemapindex.
if self.chunk_files:
self._flush_chunk()
self._write_sitemap_index(generated_at)
return len(self.chunk_files)
# Иначе пишем единый sitemap.xml с URLSet.
self._write_single_sitemap()
return 1
def _flush_chunk(self) -> None:
if not self.current_urls:
return
chunk_idx = len(self.chunk_files)
if chunk_idx >= self.max_files_qty:
raise RuntimeError(
"Превышено максимальное количество sitemap-файлов. "
f"Текущий лимит: {self.max_files_qty}."
)
file_name = f"sitemap{chunk_idx:04d}.xml"
self._write_urlset(self.output_dir / file_name, self.current_urls)
self.chunk_files.append(file_name)
# Сбрасываем буфер для следующего chunk-файла.
self.current_urls = []
self.current_size = 128
def _write_single_sitemap(self) -> None:
self._write_urlset(self.output_dir / "sitemap.xml", self.current_urls)
self.current_urls = []
self.current_size = 128
def _write_sitemap_index(self, generated_at: datetime) -> None:
root = ET.Element("sitemapindex", xmlns=SITEMAP_XMLNS)
for file_name in self.chunk_files:
sitemap_element = ET.SubElement(root, "sitemap")
ET.SubElement(sitemap_element, "loc").text = f"{self.public_base_url}/{file_name}"
ET.SubElement(sitemap_element, "lastmod").text = _as_sitemap_date(generated_at)
xml_bytes = ET.tostring(root, encoding="utf-8", xml_declaration=True)
(self.output_dir / "sitemap.xml").write_bytes(xml_bytes)
@staticmethod
def _write_urlset(file_path: Path, urls: Iterable[ET.Element]) -> None:
root = ET.Element("urlset", xmlns=SITEMAP_XMLNS)
for url in urls:
root.append(url)
xml_bytes = ET.tostring(root, encoding="utf-8", xml_declaration=True)
file_path.write_bytes(xml_bytes)
@staticmethod
def _build_url_element(loc: str, lastmod: datetime, changefreq: str, priority: float) -> ET.Element:
element = ET.Element("url")
ET.SubElement(element, "loc").text = loc
ET.SubElement(element, "lastmod").text = _as_sitemap_date(lastmod)
ET.SubElement(element, "changefreq").text = changefreq
ET.SubElement(element, "priority").text = f"{priority:.2f}"
return element
def build_sitemaps(
output_dir: Path,
site_base_url: str,
sitemap_url_prefix: str,
max_items: int,
max_file_size: int,
max_files_qty: int,
compare_min_depth: int = 2,
compare_max_depth: int = 4,
) -> SitemapBuildResult:
"""Оркестратор полного прогона сборки sitemap-файлов."""
time_start = timezone.now()
generated_at = timezone.now()
compare_lastmod = generated_at.date().replace(day=1)
latest_blog_modify = BlogPosts.objects.filter(
dPostDataBegin__lte=timezone.now(),
bPublished=True,
bArchive=False,
).aggregate(lastmod=Max("dPostDataModify"))["lastmod"]
latest_profile_modify = PVCprofiles.objects.aggregate(lastmod=Max("dProfileModify"))["lastmod"]
latest_seria_modify = Seria_Info.objects.aggregate(lastmod=Max("dSeriaInfoModify"))["lastmod"]
latest_company_modify = MerchantBrand.objects.annotate(
last_offer_modify=Max("merchantoffice__ouruser__setkit__priceoffer__dOfferModify"),
last_office_modify=Max("merchantoffice__dOfficeDataModify"),
).aggregate(lastmod=Max("last_offer_modify"), lastmod_office=Max("last_office_modify"))
latest_company_date = latest_company_modify.get("lastmod") or latest_company_modify.get("lastmod_office")
base_url = site_base_url.rstrip("/")
url_prefix = sitemap_url_prefix.strip("/")
public_sitemap_base = f"{base_url}/{url_prefix}" if url_prefix else base_url
writer = SitemapXmlWriter(
output_dir=output_dir,
public_base_url=public_sitemap_base,
max_items=max_items,
max_file_size=max_file_size,
max_files_qty=max_files_qty,
)
writer.cleanup_old()
# Источники URL. Порядок можно менять, если нужно управлять наполнением chunk-файлов.
sitemaps = [
StaticPagesSitemap(
items=[
{"loc": "/", "lastmod": generated_at, "changefreq": "weekly", "priority": 1.00},
{"loc": "/catalog", "lastmod": generated_at, "changefreq": "weekly", "priority": 0.88},
{"loc": "/catalog/profile", "lastmod": latest_profile_modify, "changefreq": "weekly", "priority": 0.92},
{"loc": "/catalog/seria", "lastmod": latest_seria_modify, "changefreq": "weekly", "priority": 0.95},
{"loc": "/catalog/standard_opening", "lastmod": latest_seria_modify, "changefreq": "monthly", "priority": 0.86},
{"loc": "/catalog/company", "lastmod": latest_company_date, "changefreq": "weekly", "priority": 0.90},
{"loc": "/stat/rating/profiles_rank", "lastmod": latest_profile_modify, "changefreq": "monthly", "priority": 0.76},
]
),
BlogListSitemap(lastmod_value=latest_blog_modify),
BlogPostSitemap(),
ProfileManufactureSitemap(),
ProfileModelSitemap(),
SeriaDetailSitemap(),
CompanyDetailSitemap(),
SingleWindowSitemap(lastmod_value=generated_at),
BuildingOffersSitemap(lastmod_value=generated_at),
CompareOffersSitemap(
lastmod_value=compare_lastmod,
min_depth=compare_min_depth,
max_depth=compare_max_depth,
),
]
for sitemap in sitemaps:
for item in sitemap.items():
location = sitemap.location(item)
lastmod = sitemap.lastmod(item)
if not location.startswith("/"):
location = f"/{location}"
sitemap_changefreq = sitemap.changefreq(item) if callable(getattr(sitemap, "changefreq", None)) else str(sitemap.changefreq)
sitemap_priority = sitemap.priority(item) if callable(getattr(sitemap, "priority", None)) else float(sitemap.priority)
writer.add_url(
loc=f"{base_url}{location}",
lastmod=lastmod,
changefreq=sitemap_changefreq,
priority=sitemap_priority,
)
files_count = writer.finalize(generated_at=generated_at)
elapsed = (timezone.now() - time_start).total_seconds()
return SitemapBuildResult(
total_urls=writer.total_urls,
files_count=files_count,
elapsed_seconds=elapsed,
output_dir=output_dir,
)
class Command(BaseCommand):
help = "Генерирует sitemap.xml и sitemapNNNN.xml в файловый кэш."
def add_arguments(self, parser):
parser.add_argument(
"--compare-min-depth",
type=int,
default=2,
help="Минимальная глубина комбинаций compare_offers (по умолчанию 2).",
)
parser.add_argument(
"--compare-max-depth",
type=int,
default=4,
help="Максимальная глубина комбинаций compare_offers (по умолчанию 4).",
)
parser.add_argument(
"--max-items",
type=int,
default=40000,
help="Максимум URL в одном sitemap-файле (по умолчанию 40000).",
)
parser.add_argument(
"--max-file-size",
type=int,
default=5242880,
help="Максимальный размер sitemap-файла в байтах (по умолчанию 5242880).",
)
parser.add_argument(
"--max-files-qty",
type=int,
default=998,
help="Максимум вложенных sitemap-файлов (по умолчанию 998).",
)
def handle(self, *args, **options):
# Валидация глубины compare перед запуском тяжелой части генерации.
compare_min_depth = options["compare_min_depth"]
compare_max_depth = options["compare_max_depth"]
if compare_min_depth > compare_max_depth:
raise CommandError("--compare-min-depth не может быть больше --compare-max-depth")
result = build_sitemaps(
output_dir=Path(settings.SITEMAP_ROOT),
site_base_url=settings.SITE_BASE_URL,
sitemap_url_prefix=settings.SITEMAP_URL_PREFIX,
max_items=options["max_items"],
max_file_size=options["max_file_size"],
max_files_qty=options["max_files_qty"],
compare_min_depth=compare_min_depth,
compare_max_depth=compare_max_depth,
)
# Человекочитаемый отчет для логов CI/CD и контейнерных entrypoint-скриптов.
if result.files_count == 1:
self.stdout.write(
self.style.SUCCESS(
f"Создан единственный sitemap.xml. URL-ов: {result.total_urls}. "
f"Время: {result.elapsed_seconds:.2f} сек."
)
)
else:
self.stdout.write(
self.style.SUCCESS(
f"Создан каскад sitemap. Файлов: {result.files_count}. URL-ов: {result.total_urls}. "
f"Время: {result.elapsed_seconds:.2f} сек."
)
)
+715
View File
@@ -0,0 +1,715 @@
# -*- coding: utf-8 -*-
from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from oknardia.models import Win_MountDim, PriceOffer, Apartment_Type, Seria_Info, LogVisitPriceReport
from oknardia.settings import *
from web.report1 import get_last_all_user_visit_list, get_last_user_visit_cookies, get_last_user_visit_list
from web.add_func import normalize, get_rating_set_for_stars, get_flaps_for_big_pictures, get_flaps_for_mini_pictures, \
get_geo_distance
import django.utils.dateformat
import time
import os
import re
import json
import pytils
def report_price_frame(apartment_id: int, mount_dim_per_offer: int, address_longitude: float, address_latitude: float,
frame_begin_n: int = 0, brand_id: int = 0, win_id: int = 0) -> dict:
""" Формируем выдачу цен для фрейма
:param apartment_id: int -- ID типа квартиры, для которой получаем ценовые предложения
:param mount_dim_per_offer: int -- число различных оконых проемов в этой квартире (чтобы отсеять предложения,
в которых не представлены все проемы)
:param address_longitude: float -- долгота адреса (геокоордината), чтобы рассчитать удаленность компании
предоставившей коммерческие предложения
:param address_latitude: float -- широта адреса (геокоордината), чтобы рассчитать удаленность компании
предоставившей коммерческие предложения
:param frame_begin_n: int -- Номер записи с которой начинается фрейм с ценами (с какого предложения начинать)
:param brand_id: int -- ID бренда, если выбран бренд, то отображаем только предложения этого бренда
(нужно для виджета, где отображаются предложения только от одной компании)
если 0, то отображаем все предложения
:param win_id: int -- ID окна, если выбрано окно, то отображаем только предложения этого окна
:return: dict -- словарь данных для отображения в фрейме (цены предложений и их характеристики)
"""
# ценовая выдача
time_for_meta = 0 # время для мета-данных в HTML-кода
apartment_id = int(apartment_id)
mount_dim_per_offer = int(mount_dim_per_offer)
address_longitude = float(address_longitude)
address_latitude = float(address_latitude)
frame_begin_n = int(frame_begin_n)
brand_id = int(brand_id)
win_id = int(win_id)
add_to_sql_for_widget = ""
offer_per_frame = OFFER_PER_FRAME
if brand_id != 0:
# Это вывод для выджета. Нужны цены только по определенному поставщику
add_to_sql_for_widget = f" AND oknardia_merchantbrand.id = {brand_id} "
offer_per_frame = 1000 # Фреймовый вывод не нужен... фигачим сразу целую 1000 предложений.
if int(apartment_id) == 0 and int(win_id) != 0:
# если выводим цены только для одного проема
offer_per_frame = OFFER_PER_FRAME_FOR_ONE_FLAP
q_price_offer = PriceOffer.objects.raw(
f"SELECT"
f" oknardia_priceoffer.id, oknardia_priceoffer.iOfferImpressions,"
f" oknardia_priceoffer.fOfferPrice, oknardia_priceoffer.dOfferModify,"
f" oknardia_priceoffer.fOfferRating, oknardia_priceoffer.sOfferFlapConfig,"
f" oknardia_priceoffer.iOfferViews, oknardia_priceoffer.sOfferActive,"
f" oknardia_win_mountdim.sDescripion, oknardia_win_mountdim.id AS mID, "
f" oknardia_win_mountdim.bIsNearDoor, oknardia_win_mountdim.bIsDoor,"
f" oknardia_win_mountdim.iWinWidth, oknardia_win_mountdim.iWinHight,"
f" oknardia_setkit.id AS setID,"
f" oknardia_setkit.sSetName, oknardia_setkit.dSetModify,"
f" oknardia_setkit.sSetClimateControl, oknardia_setkit.sSetSill,"
f" oknardia_setkit.sSetImplementAll, oknardia_setkit.sSetImplementHandles,"
f" oknardia_setkit.sSetImplementHinges, oknardia_setkit.sSetImplementLatch,"
f" oknardia_setkit.sSetImplementLimiter, oknardia_setkit.sSetImplementCatch,"
f" oknardia_setkit.sSetPanes, oknardia_setkit.sSetSlope,"
f" oknardia_setkit.sSetOtherConditions, oknardia_setkit.sSetActive,"
f" oknardia_setkit.bSetDelivery, oknardia_setkit.sSetDelivery,"
f" oknardia_setkit.sSetUninstallInstall, oknardia_setkit.bSetUninstallInstall,"
f" oknardia_setkit.fSetRating, oknardia_setkit.iSetNumEval,"
f" oknardia_setkit.iSetImpressions, oknardia_setkit.iSetViews,"
f" (oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial,"
f" oknardia_merchantoffice.sOfficePhones, "
f" oknardia_merchantoffice.sOfficeDiscountMetaFormula,"
f" oknardia_merchantoffice.sOfficeName, oknardia_merchantoffice.sOfficeAddress,"
f" oknardia_glazing.fGlazingRating,"
f" oknardia_glazing.sGlazingName, oknardia_glazing.sGlazingBriefDescription,"
f" oknardia_glazing.sGlazingMark, oknardia_glazing.sGlazingToning,"
f" oknardia_pvcprofiles.sProfileBriefDescription, oknardia_pvcprofiles.id AS pwc_id,"
f" oknardia_pvcprofiles.sProfileReinforcement, oknardia_pvcprofiles.sProfileSealDescription,"
f" oknardia_pvcprofiles.sProfileName, oknardia_pvcprofiles.sProfileColor,"
f" oknardia_pvcprofiles.fProfileRating, oknardia_pvcprofiles.sProfileManufacturer,"
f" oknardia_merchantbrand.sMerchantName, oknardia_merchantbrand.pMerchantLogo,"
f" oknardia_merchantbrand.sMerchantMainURL, oknardia_merchantbrand.id AS brand_id,"
f" 1 AS iQuantity, 0 AS fOfficeGeoCode_Longitude, 0 AS fOfficeGeoCode_Latitude "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_priceoffer.sOfferActive IS TRUE"
f" AND oknardia_setkit.sSetActive IS TRUE "
f" AND oknardia_win_mountdim.id = {int(win_id)}"
f" {add_to_sql_for_widget} "
f"ORDER BY"
f" oknardia_priceoffer.dOfferModify DESC "
f"LIMIT {int(frame_begin_n)}, 10000;")
else:
# если выводим цены для типовой квартиры
# print("Нужно несколько окон для квартиры")
q_price_offer = PriceOffer.objects.raw(
f"SELECT"
f" oknardia_priceoffer.*,"
f" oknardia_win_mountdim.*,"
f" oknardia_setkit.*,"
f" oknardia_merchantoffice.*,"
f" oknardia_glazing.*,"
f" oknardia_pvcprofiles.*,"
f" oknardia_merchantbrand.*,"
f" oknardia_mountdim2apartment.iQuantity,"
f" oknardia_win_mountdim.id AS mID, "
f" oknardia_setkit.id AS setID,"
f" (oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial,"
f" oknardia_pvcprofiles.id AS pwc_id,"
f" oknardia_merchantbrand.id AS brand_id "
f"FROM oknardia_priceoffer"
f" INNER JOIN oknardia_win_mountdim"
f" ON oknardia_priceoffer.kOffer2MountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_mountdim2apartment"
f" ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_priceoffer.sOfferActive IS TRUE"
f" AND oknardia_mountdim2apartment.kApartment_id = {int(apartment_id)}"
f" AND oknardia_setkit.sSetActive IS TRUE {add_to_sql_for_widget} "
f"ORDER BY"
f" oknardia_setkit.dSetCreate DESC, " # Сейчас окна в наборе собираются через это
f" oknardia_win_mountdim.bIsNearDoor DESC,"
f" oknardia_win_mountdim.bIsDoor DESC,"
f" oknardia_win_mountdim.iWinWidth,"
f" oknardia_win_mountdim.iWinHight DESC "
f"LIMIT {int(frame_begin_n)} , 10000;")
# print list(qPO)
price_frame = []
count_mount_dim_in_offer = 0
dim_in_offer = []
total = 0
cur_bullet = 0
previous_set_id = 0
count_mount_dim_in_frame_page = 0
# Так как получен QuerySet начиная с frame_begin_n, то для того чтобы получить frame_begin_n следующего фрйма
# считаем не от нуля, а от старого frame_begin_n
n_begin = int(frame_begin_n)
# Проверяем есть ли папка для хранения мини-картинки конфигурации схемы открывания.
if not os.path.exists(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_IMGFLAPCONFIG}"):
# создаем такую папку если её нет
os.makedirs(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_IMGFLAPCONFIG}")
# print(">>>>>>>>>>>>>", apartment_id)
for i2 in q_price_offer:
n_begin += 1
count_mount_dim_in_frame_page += 1
# Случается, что в том или ином наборе поставщиком просчитаны не все проёмы.
# Чтобы не происходило формирование предложения (офера) из окон разных наборов делаем проверку
# является ли текущий проём в предложении из того же набора, что и предыдущий.
# Если он из другого набора, то удаляем предыдущий проём из предложения и начинаем
# формирование предложения сначала.
if count_mount_dim_in_offer == 0:
previous_set_id = i2.setID
else:
if previous_set_id != i2.setID:
# print("Сбой в наборе. Обнуляем набор")
previous_set_id = i2.setID
count_mount_dim_in_offer = 0
total = 0
cur_bullet = 0
dim_in_offer.pop()
dim_in_offer = []
# print("mID:", i2.mID, " || pID:", i2.id, " || price:", i2.fOfferPrice, " || N:", i2.iQuantity,
# " || set:", i2.sSetName, " || merchant:", i2.sOfficeName)
total += i2.fOfferPrice * i2.iQuantity
image_file = get_flaps_for_mini_pictures(i2.sOfferFlapConfig)
dim_in_offer.append({
'PRICE': i2.fOfferPrice,
'FLAP': i2.sOfferFlapConfig,
'DESCRIPTION': i2.sDescripion,
'WIDTH': i2.iWinWidth,
'HIGHT': i2.iWinHight,
'ID': i2.id,
'IMG_MINI': image_file,
'QUANTITY': i2.iQuantity,
'BULLET': [chr(65 + cur_bullet + i) for i in range(i2.iQuantity)],
# 'BULLET': range(CurBullet, CurBullet+i2.iQuantity),
'SUBTOTAL': i2.fOfferPrice * i2.iQuantity,
})
cur_bullet += i2.iQuantity
count_mount_dim_in_offer += 1
if count_mount_dim_in_offer == mount_dim_per_offer:
# print("-----------------")
# узнаем скидку через разбор формулы на метаязыке
discount = 0
try:
meta_keys = eval(i2.sOfficeDiscountMetaFormula)
if KEY_DICSOUNT in meta_keys:
# скидки рассчитываются исходя из общей суммы
for CountVal in sorted(meta_keys[KEY_DICSOUNT]):
# print(CountVal, "::", meta_keys[KEY_DICSOUNT][CountVal])
if float(total) > float(CountVal):
discount = meta_keys[KEY_DICSOUNT][CountVal]
# # DiscountTXT += u"!!%d!!" % Discount
# print("Значит DISCOUNT: ", Discount)
except (ValueError, TypeError):
pass
fin_price = total * (100 - discount) / 100
# уточняем, есть ли в принципе геокоординаты?
if int(i2.fOfficeGeoCode_Longitude) != 0 and int(i2.fOfficeGeoCode_Latitude) != 0 and \
int(address_longitude) != 0 and int(address_latitude) != 0:
# рассчитываем дистанцию между адресом дома и офиса.
distance = get_geo_distance(i2.fOfficeGeoCode_Longitude, i2.fOfficeGeoCode_Latitude, address_longitude,
address_latitude)
# т.к. из-за изменений в api яндекс карт поменялась местами широта-долгота и вообще, то
# порядок переменных строчной выше... На самом деле должно быть как в закоментированной
# строке ниже
# distance = get_geo_distance(i2.fOfficeGeoCode_Longitude, i2.fOfficeGeoCode_Latitude,
# address_longitude, address_latitude)
else:
distance = -1
# print(discount)
if discount > 99 or discount < 0.1:
discount_color1 = ""
discount_color2 = ""
else:
color_ratio = (discount + 0.) / 100
discount_color1 = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
discount_color2 = f"#{255 - int(color_ratio * 255):02x}ff{255 - int(color_ratio * 255):02x}"
# print(discount_color1, discount_color2)
price_frame.append({
'DISTANCE': distance,
'DIM': dim_in_offer,
'TOTAL': total,
'DISCOUNT': discount,
'DISCOUNT_COLOR1': discount_color1,
'DISCOUNT_COLOR2': discount_color2,
'FIN_PRICE': fin_price,
'OFFICE_NAME': i2.sOfficeName,
'OFFICE_ADDRESS': i2.sOfficeAddress,
'OFFICE_PHONES': i2.sOfficePhones,
'MERCHANT': i2.sMerchantName,
'MERCHANT_LOGO': i2.pMerchantLogo,
'MERCHANT_URL': i2.sMerchantMainURL,
'MERCHANT_URL_SHOT': re.sub(r"(?:^http://|^https://|/$|www\.)", "", i2.sMerchantMainURL),
'SETS_NAME': i2.sSetName,
'GLAZING_NAME_B': i2.sGlazingBriefDescription,
'GLAZING_MARK': i2.sGlazingMark,
'GLAZING_TONING': i2.sGlazingToning,
'PVC_ID': i2.pwc_id,
'PVC_NAME': i2.sProfileName,
'PVC_NAME_T': pytils.translit.slugify(i2.sProfileName).lower(),
'PVC_MANUFACTURER': i2.sProfileManufacturer,
'PVC_MANUFACTURER_T': pytils.translit.slugify(i2.sProfileManufacturer).lower(),
'PVC_SEAL': i2.sProfileSealDescription,
'SETS_CLIMATE_CONTROL': i2.sSetClimateControl,
'SETS_SILL': i2.sSetSill,
'SETS_IMPLEMENT': i2.sSetImplementAll,
'SETS_IMPLEMENT_R': i2.sSetImplementHandles,
'SETS_IMPLEMENT_P': i2.sSetImplementHinges,
'SETS_IMPLEMENT_Z': i2.sSetImplementLatch,
'SETS_IMPLEMENT_O': i2.sSetImplementLimiter,
'SETS_IMPLEMENT_F': i2.sSetImplementCatch,
'SETS_PANES': i2.sSetPanes,
'SETS_SLOPE': i2.sSetSlope,
'SETS_DELIVERY': i2.sSetDelivery,
'SETS_DELIVERY_B': i2.bSetDelivery,
'SETS_OTHER': i2.sSetOtherConditions,
'SETS_ID': i2.setID,
'SETS_UNINSTALL_INSTALL': i2.sSetUninstallInstall,
'SETS_UNINSTALL_INSTALL_B': i2.bSetUninstallInstall,
'SETS_RATING': i2.fSetRating,
'SETS_RATING_STARTS': get_rating_set_for_stars(i2.fSetRating),
'SETS_DATA_MODIFY': i2.dOfferModify,
'IS_COMMERCIAL': i2.bCommercial,
})
if len(price_frame) == offer_per_frame:
break
count_mount_dim_in_offer = 0
dim_in_offer = []
total = 0
cur_bullet = 0
# узнаем дату-время самого свежего ценового предложения для размещения в META-тега
if time_for_meta == 0 or django.utils.dateformat.format(time_for_meta, 'U') < \
django.utils.dateformat.format(i2.dOfferModify, 'U'):
time_for_meta = i2.dOfferModify
if time_for_meta == 0 or django.utils.dateformat.format(time_for_meta, 'U') < \
django.utils.dateformat.format(i2.dSetModify, 'U'):
time_for_meta = i2.dSetModify
# массив ценовых предложений (что бы предложения на одной дистанции были в случайном порядке)
# random.shuffle(PriceFrame)
# сортируем по удаленности
price_frame = sorted(price_frame, key=lambda item: item['DISTANCE'])
if len(price_frame) < offer_per_frame:
n_begin = '-1'
return {'META_DATA_PUBLISH': time_for_meta, 'PRICE_FRAME': price_frame, 'N': n_begin}
def report_one_win_price(request: HttpRequest, win_width_mm: str = '670', win_height_mm: str = '2160',
win_id: str = '16') -> HttpResponse:
""" Формируем выдачу цен для единичного ТИПОВОГО окна (т.е. проема из серийного дома).
:param request: HttpRequest -- входящий http-запрос
:param win_width_mm: str -- Ширина проема в миллиметрах (это SEO-параметр, в реальности он будет получен из базы)
:param win_height_mm: str -- Высота проема в миллиметрах (это SEO-параметр, в реальности он будет получен из базы)
:param win_id: str -- ID проема (см. таблицу oknardia_win_mountdim)
:return response: HttpResponse -- исходящий http-ответ
"""
time_start = time.perf_counter()
to_template = {}
try:
# т.к. для вызова GetFlapDim4BigPictures нужно иметь внутри queryset поле iQuantity нельзя использовать
# простой запрос (см. следующую строку).
# qWinInfo = Win_MountDim.objects.filter(id=int(win_id))
# Придется сделать запрос немного сложнее:
q_win_info = Win_MountDim.objects.raw(
f'SELECT oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
f' oknardia_win_mountdim.id, 0 as iQuantity '
f'FROM oknardia_win_mountdim '
f'WHERE oknardia_win_mountdim.id = {int(win_id)};'
)
list_win_info = list(q_win_info)
# Если размеры типового проема не совпадают с размерами из базы, то подменяем
# на правильные и перевызываем страницу
if (list_win_info[0].iWinWidth * 10 != int(win_width_mm)) or \
(list_win_info[0].iWinHight * 10 != int(win_height_mm)):
return redirect(f"/tsena-odnogo-okna/{list_win_info[0].iWinWidth * 10}x{list_win_info[0].iWinHight * 10}"
f"mm/tip{win_id}")
except (ObjectDoesNotExist, ValueError, IndexError, TypeError):
return redirect("/tsena-odnogo-okna/670x2160mm/tip16")
# все хорошо, засылаем картинку в шаблон
to_template.update(get_flaps_for_big_pictures(list_win_info))
# получаем варианты схемы открывания (для графиков)
q_offer_flap_variation = PriceOffer.objects.raw(
f'SELECT'
f' COUNT(oknardia_priceoffer.sOfferFlapConfig) AS id,'
f' "" AS IMG_MINI,'
f' "" AS STR_NUM,'
f' oknardia_priceoffer.sOfferFlapConfig '
f'FROM oknardia_priceoffer '
f'WHERE oknardia_priceoffer.sOfferActive <> 0'
f' AND oknardia_priceoffer.kOffer2MountDim_id = {int(win_id)} '
f'GROUP BY oknardia_priceoffer.sOfferFlapConfig,'
f' oknardia_priceoffer.sOfferActive,'
f' oknardia_priceoffer.kOffer2MountDim_id '
f'ORDER BY id DESC;'
)
list_offer_flap_variation = list(q_offer_flap_variation)
for i in range(0, len(list_offer_flap_variation)):
if i < 3:
list_offer_flap_variation[i].STR_NUM = "вариант " + pytils.numeral.in_words(i + 1)
elif i == 3:
list_offer_flap_variation[i].STR_NUM = "остальные варианты"
continue
else:
list_offer_flap_variation[3].id += list_offer_flap_variation[i].id
continue
list_offer_flap_variation[i].IMG_MINI = get_flaps_for_mini_pictures(
list_offer_flap_variation[i].sOfferFlapConfig
)
to_template.update({'LIST_FLAP_VARIATION': list_offer_flap_variation[:4]})
to_template.update({'NUM_FLAP_VARIATION_IN_WORD': pytils.numeral.sum_string(len(list_offer_flap_variation),
pytils.numeral.MALE,
("вариант схемы",
"варианта схем",
"вариантов схем"))})
#
q = PriceOffer.objects.raw(f'SELECT'
f' COUNT(oknardia_priceoffer.kOfferFromUser_id) AS id,'
f' oknardia_priceoffer.kOfferFromUser_id,'
f' oknardia_priceoffer.kOffer2MountDim_id '
f'FROM oknardia_priceoffer '
f'WHERE oknardia_priceoffer.kOffer2MountDim_id = {int(win_id)} '
f'GROUP BY oknardia_priceoffer.kOffer2MountDim_id,'
f' oknardia_priceoffer.kOfferFromUser_id;')
to_template.update({'NUM_TOTAL_FIRM_N_WORD': pytils.numeral.get_plural(len(list(q)),
("компании", "компаний", "компаний"))})
q = PriceOffer.objects.filter(kOffer2MountDim_id=int(win_id))
to_template.update({'NUM_TOTAL_OFFER_N_WORD': pytils.numeral.get_plural(q.count(),
("готовый расчёт", "готовых расчёта",
"готовых расчётов"))})
to_template.update({'NUM_ARCHIVE_OFFER': q.filter(sOfferActive=0).count()})
#
q_seria_for_win = PriceOffer.objects.raw(
f'SELECT'
f' oknardia_seria_info.sName, oknardia_seria_info.id AS id,'
f' "" AS sNameLat,'
f' COUNT(oknardia_mountdim2apartment.id) AS num_variation_of_apartment '
f'FROM oknardia_apartment_type'
f' INNER JOIN oknardia_mountdim2apartment'
f' ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id'
f' INNER JOIN oknardia_win_mountdim'
f' ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id'
f' INNER JOIN oknardia_seria_info'
f' ON oknardia_apartment_type.kSeria_id = oknardia_seria_info.id '
f'WHERE oknardia_win_mountdim.id = {int(win_id)} '
f'GROUP BY oknardia_win_mountdim.id,'
f' oknardia_seria_info.sName,'
f' oknardia_seria_info.id '
f'ORDER BY oknardia_seria_info.sName;'
)
list_seria_for_win = list(q_seria_for_win)
for i in list_seria_for_win:
i.sNameLat = pytils.translit.slugify(i.sName)
i.num_variation_of_apartment = pytils.numeral.sum_string(i.num_variation_of_apartment,
pytils.numeral.MALE,
("типовую планировку квартиры",
"типовые планировки квартир",
"типовых планировок квартир"))
to_template.update(report_price_frame(0, 1, 0, 0, 0, 0, int(win_id)))
to_template.update({
'SERIA_FOR_WIN': list_seria_for_win,
'WIN_ID': int(win_id),
'MOUNT_DIM_PER_OFFER': 1,
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "price/price_offers_for_one_window.html", to_template)
def next_one_win_price(request: HttpRequest, win_id='16', frame_begin_n="0"):
""" Возвращает очередной фреймом ценовых предложений для выдачи с одиночным окном.
:param request: HttpRequest -- входящий http-запрос
:param win_id: str -- id типового окна
:param frame_begin_n: str -- Номер записи с которой начинается фрейм с ценами
:return: HttpResponse --
"""
time_start = time.perf_counter()
to_template = report_price_frame(0, 1, 0, 0, int(frame_begin_n), 0, int(win_id))
to_template.update({'MOUNT_DIM_PER_OFFER': 1,
'WIN_ID': int(win_id),
'ticks': float(time.perf_counter() - time_start)})
return render(request, "price/price_offers_for_one_window_frame.html", to_template)
def report_price(request: HttpRequest, build_id: str = "22427", apart_id: str = "61",
slug: str = "g-moskva-ul-novorossijskaya-d-16") -> HttpResponse:
""" Страница с расчетом стоимости окон
:param request: HttpRequest -- входящий http-запрос
:param build_id: str - id здания (адрес в таблице oknardia_building_info.id)
:param apart_id: str - id типовой планировки квартиры (в таблице oknardia_apartment_type.id)
:param slug: str - slug адреса здания
:return: response: HttpResponse
"""
time_start = time.perf_counter()
msg = ""
to_template = {}
try:
build_id = int(build_id)
apart_id = int(apart_id)
except ValueError:
return redirect("/")
try:
# получаем все типы квартир для данного адреса (а заодно и попутную информацию о площади дома и пр.)
q_apart = Apartment_Type.objects.raw(
f'SELECT'
f' oknardia_apartment_type.sNameApartment, oknardia_apartment_type.id,'
f' oknardia_apartment_type.iSort, oknardia_seria_info.kRoot_id,'
f' oknardia_building_info.kSeria_Link_id, oknardia_building_info.sAddress,'
f' oknardia_building_info.fGeoCode_Latitude, oknardia_building_info.fGeoCode_Longitude,'
f' oknardia_building_info.fTotal_Area, oknardia_building_info.sCadastre_Num_Area,'
f' oknardia_building_info.fLand_Area, oknardia_building_info.sInventory_Num,'
f' oknardia_building_info.iNum_Apartments, oknardia_building_info.sType,'
f' oknardia_building_info.iStoreys, oknardia_building_info.fCommon_Area,'
f' oknardia_building_info.sEnergy_Efficiency, oknardia_building_info.iEntrances_Porchs,'
f' oknardia_building_info.fUninhabited_Area, oknardia_building_info.sManagement_Co,'
f' oknardia_building_info.iElevators, oknardia_building_info.fResidential_Area,'
f' oknardia_building_info.iNum_Residents, oknardia_building_info.fPrivate_Area,'
f' oknardia_building_info.iNum_Accounts, oknardia_building_info.iCommissioning_year,'
f' oknardia_building_info.fGovernment_Area, oknardia_building_info.fCondition_House,'
f' oknardia_building_info.fCondition_Foundation, oknardia_building_info.fCondition_Walls,'
f' oknardia_building_info.fCondition_Overlap, oknardia_building_info.fMunicipal_Area,'
f' oknardia_building_info.sSerias_Project '
f'FROM oknardia_seria_info '
f'INNER JOIN oknardia_apartment_type'
f' ON oknardia_seria_info.kRoot_id = oknardia_apartment_type.kSeria_id '
f' INNER JOIN oknardia_building_info'
f' ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id '
f'WHERE oknardia_building_info.id = {build_id} '
f'ORDER BY oknardia_apartment_type.iSort;')
list_apart = list(q_apart)
# если кто-то нахимичит ID квартиры не для этого дома, то сделаем так, что он будет от этого дома!
apart_inside = False
for i in q_apart:
if i.id == apart_id:
apart_inside = True
break
if not apart_inside or slug != pytils.translit.slugify(list_apart[0].sAddress):
# Переадресация 302, если с apart_id (ID-квартиры нахимичили) или slug-ом.
# Нужно для склейки парных URL в поисковиках
# При переходе с карты apart_id выставляем в 0. Из-за этого тоже нужно 302-переадресация.
return redirect(f"/{build_id}/{list_apart[0].id}/{pytils.translit.slugify(list_apart[0].sAddress)}")
address_latitude = list_apart[0].fGeoCode_Latitude
address_longitude = list_apart[0].fGeoCode_Longitude
to_template.update({'BUILD_ID': build_id})
to_template.update({'APPARTMENT_ID': apart_id})
to_template.update({'ADDRESS_LAT': address_latitude})
to_template.update({'ADDRESS_LON': address_longitude})
to_template.update({'ADDRESS': list_apart[0].sAddress})
to_template.update({'ADDRESS_T': pytils.translit.slugify(list_apart[0].sAddress)})
to_template.update({'SERIA': list_apart[0].sSerias_Project})
# данные нужные для отображения информации о доме (метраж, число подъездов и пр.)
to_template.update({'CADASTRE_NUM': list_apart[0].sCadastre_Num_Area})
to_template.update({'INVENTORY_NUM': list_apart[0].sInventory_Num})
to_template.update({'TYPE_BUILDING': list_apart[0].sType})
to_template.update({'ENERGY_EFFICIENCY': list_apart[0].sEnergy_Efficiency})
if list_apart[0].fTotal_Area != -1.0:
to_template.update({'TOTAL_AREA': f"{list_apart[0].fTotal_Area:.1f}"})
if list_apart[0].fLand_Area != -1.0:
to_template.update({'LAND': f"{list_apart[0].fLand_Area:.1f}"})
if list_apart[0].iNum_Apartments != -1:
to_template.update({'NUM_APARTMENTS': list_apart[0].iNum_Apartments})
if list_apart[0].iStoreys != -1:
to_template.update({'STOREYS': list_apart[0].iStoreys})
if list_apart[0].fCommon_Area != -1.0:
to_template.update({'COMMON_AREA': f"{list_apart[0].fCommon_Area:.1f}"})
if list_apart[0].iEntrances_Porchs != -1:
to_template.update({'NUM_ENTERANCES': list_apart[0].iEntrances_Porchs})
if list_apart[0].fUninhabited_Area != -1.0:
to_template.update({'UNINHABITED_AREA': f"{list_apart[0].fUninhabited_Area:.1f}"})
if list_apart[0].sManagement_Co != u"N/A":
to_template.update({'MANAGEMENT_CO': list_apart[0].sManagement_Co})
if list_apart[0].iElevators != -1:
to_template.update({'NUM_ELEVATORS': list_apart[0].iElevators})
if list_apart[0].fResidential_Area != -1.0:
to_template.update({'RESIDENTIAL_AREA': f"{list_apart[0].fResidential_Area:.1f}"})
if list_apart[0].iNum_Residents != -1:
to_template.update({'NUM_RESIDENTS': list_apart[0].iNum_Residents})
if list_apart[0].fPrivate_Area != -1.0:
to_template.update({'PRIVATE_AREA': f"{list_apart[0].fPrivate_Area:.1f}"})
if list_apart[0].iNum_Accounts != -1:
to_template.update({'NUM_ACCOUNTS': list_apart[0].iNum_Accounts})
if list_apart[0].iCommissioning_year != "N/A":
to_template.update({'COMMISSIONING_YEAR': list_apart[0].iCommissioning_year})
if list_apart[0].fGovernment_Area != -1.0:
to_template.update({'GOVERNMENT_AREA': f"{list_apart[0].fGovernment_Area:.1f}"})
if list_apart[0].fCondition_House != -1.0:
to_template.update({'CONDITION_HOUSE': f"{list_apart[0].fCondition_House:.0f}%"})
if list_apart[0].fCondition_Foundation != -1.0:
to_template.update({'CONDITION_FOUNDATION': f"{list_apart[0].fCondition_Foundation:.0f}%"})
if list_apart[0].fCondition_Walls != -1.0:
to_template.update({'CONDITION_WALL': f"{list_apart[0].fCondition_Walls:.0f}%"})
if list_apart[0].fCondition_Overlap != -1.0:
to_template.update({'CONDITION_OVERLAP': f"{list_apart[0].fCondition_Overlap:.0f}%"})
if list_apart[0].fMunicipal_Area != -1.0:
to_template.update({'MUNICIPAL_AREA': f"{list_apart[0].fMunicipal_Area:.1f}"})
# заполняем массив квартир для отправки в шаблон
apart_in_building = []
for apartment_count in q_apart:
apartment_in = {}
if apartment_count.id != apart_id:
apartment_in.update({'APT_ID': apartment_count.id})
else:
apartment_in.update({'APT_ID': "!"})
apartment_in.update({'APT_NAME': apartment_count.sNameApartment})
apart_in_building.append(apartment_in)
to_template.update({'APARTMENT_IN_BUILDING': apart_in_building})
# узнаем базовую серию дома
q_base_seria = Seria_Info.objects.get(id=list_apart[0].kRoot_id)
base_seria_slug = pytils.translit.slugify(q_base_seria.sName)
to_template.update({'BASE_SERIA': q_base_seria.sName,
'BASE_SERIA_LAT': base_seria_slug,
'BASE_SERIA_ID': q_base_seria.id})
# except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
except ObjectDoesNotExist:
return redirect("/")
###############################################
# получаем массив окон для данной квартиры...
try:
q_md = Win_MountDim.objects.raw(
f'SELECT'
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
f'FROM oknardia_mountdim2apartment '
f'INNER JOIN oknardia_apartment_type'
f' ON oknardia_mountdim2apartment.kApartment_id = oknardia_apartment_type.id'
f' INNER JOIN oknardia_win_mountdim'
f' ON oknardia_mountdim2apartment.kMountDim_id = oknardia_win_mountdim.id '
f'WHERE oknardia_mountdim2apartment.kApartment_id = {apart_id} '
f'GROUP BY'
f' oknardia_apartment_type.sNameApartment, oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight, oknardia_win_mountdim.iWinDepth,'
f' oknardia_win_mountdim.sFlapConfig, oknardia_win_mountdim.bIsNearDoor,'
f' oknardia_win_mountdim.bIsDoor, oknardia_win_mountdim.sDescripion,'
f' oknardia_apartment_type.bApartmentCheck, oknardia_win_mountdim.dMountXYZModify,'
f' oknardia_apartment_type.dApartmentModify, oknardia_win_mountdim.iWinLimit,'
f' oknardia_win_mountdim.id, oknardia_mountdim2apartment.iQuantity '
f'ORDER BY'
f' oknardia_win_mountdim.bIsNearDoor DESC,'
f' oknardia_win_mountdim.bIsDoor DESC,'
f' oknardia_win_mountdim.iWinWidth,'
f' oknardia_win_mountdim.iWinHight DESC;')
list_mount_dim_per_offer = list(q_md)
mount_dim_per_offer = len(list_mount_dim_per_offer)
to_template.update({'APART': list_mount_dim_per_offer[0].sNameApartment})
# получаем данные для отрисовки больших картинок с проемами.
to_template.update(get_flaps_for_big_pictures(q_md))
# <---
except (ValueError, IndexError, TypeError, ObjectDoesNotExist):
return redirect("/")
# получаем данные для фрейма ценовых предложений
price_frame = report_price_frame(apart_id, mount_dim_per_offer, address_longitude, address_latitude)
to_template.update(price_frame)
# print u"строк в querySet:", CountMountDimInFramePage
# dimension_to_template.update({'DISCOUNT_TXT': DiscountTXT})
to_template.update({'MOUNT_DIM_PER_OFFER': mount_dim_per_offer,
'META_DESCRIPTION': "Окнардия ",
'META_KEYWORDS': "Окнардия+ ",
'MSG': msg})
# получаем последние визиты всех посетителей из базы
log_visit = get_last_all_user_visit_list()
if log_visit[0]['id'] is not None:
id_last_visit_log = log_visit[0]['id'] + 1
else:
id_last_visit_log = 1
# print("id_last_visit_log:", id_last_visit_log)
to_template.update({'LOG_VISIT': log_visit})
if id_last_visit_log > MAX_LEN_RING_LOG_BUFFER: # максимальный размер циклического буфера
id_last_visit_log = 1 # ставим в начало буфера
try:
log_entry = LogVisitPriceReport.objects.get(id=id_last_visit_log)
log_entry.sLogAddress = to_template["ADDRESS"]
log_entry.sLogNameApartment = to_template["APART"]
log_entry.sLogURL = f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}"
log_entry.dLogVisitTime = time.perf_counter()
log_entry.save() # UPDATE
except ObjectDoesNotExist:
log_entry = LogVisitPriceReport(
sLogAddress=to_template["ADDRESS"],
sLogNameApartment=to_template["APART"],
sLogURL=f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
dLogVisitTime=time.perf_counter()
)
log_entry.save() # INSERT
# получаем последние визиты клиента через куки
last_visit = get_last_user_visit_cookies(request)
to_template.update({'LAST_VISIT': get_last_user_visit_list(last_visit)})
# подготавливаем данные о текущем посещении для помещения в cookie
Item = {
"LastURL": f"/{build_id}/{apart_id}/{to_template['ADDRESS_T']}",
"LastAddress": to_template["ADDRESS"],
"LastApart": to_template["APART"],
"Time": time.perf_counter()}
last_visit.insert(0, Item) # Добавляем текущий Item в начало
last_visit = json.dumps(last_visit[:3]) # упаковываем json без пробелов (три записи)
# print u"сейчас запишем вот эту куку:", LastVisit
to_template.update({'ticks': float(time.perf_counter() - time_start)})
response = render(request, "price/price_list.html", to_template)
response.set_cookie("LastVisit", last_visit, max_age=7862400) # ставим или перезаписываем куки (91 день)
return response
def next_price_frame(request: HttpRequest, apart_id: str = "1", mount_dim_per_offer: str = "1",
address_longitude: str = "0.", address_latitude: str = "0.",
frame_begin_n: str = "0") -> HttpResponse:
""" Возвращает очередным фреймом ценовых предложений.
:param request: HttpRequest -- входящий HTTP-запрос
:param apart_id: str -- ID типовой квартиры, для которой получаем ценовые предложения
:param mount_dim_per_offer: str -- число различных оконных проемов в этой квартире (чтобы отсеять предложения,
в которых не представлены все проемы)
:param address_longitude: str -- долгота адреса (геокоордината), для которого получаем ценовые предложения, чтобы
рассчитать удаленность компании предоставившей коммерческие предложения
:param address_latitude: str -- широта адреса (геокоордината), для которого получаем ценовые предложения, чтобы
рассчитать удаленность компании предоставившей коммерческие предложения
:param frame_begin_n: str -- Номер записи с которой начинается фрейм с ценами
:return: HttpResponse -- HTTP-ответ
"""
time_start = time.perf_counter()
# получаем данные для фрейма ценовых предложений
price_frame = report_price_frame(int(apart_id), int(mount_dim_per_offer), float(address_longitude),
float(address_latitude), int(frame_begin_n))
to_template = price_frame
to_template.update({'APPARTMENT_ID': apart_id,
'MOUNT_DIM_PER_OFFER': mount_dim_per_offer,
'ADDRESS_LAT': address_latitude,
'ADDRESS_LON': address_longitude,
'ticks': float(time.perf_counter() - time_start)})
return render(request, "price/price_list_frame.html", to_template)
+541 -9
View File
@@ -1,12 +1,16 @@
# -*- coding: utf-8 -*-
# from django.shortcuts import render, redirect
from django.http import HttpRequest # , HttpResponse
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from django.utils.dateformat import format
from oknardia.models import LogVisitPriceReport
# from oknardia.settings import *
# from web.add_func import normalize, get_rating_set_for_stars
from oknardia.models import LogVisitPriceReport, SetKit
from oknardia.settings import *
from web.add_func import normalize, get_rating_set_for_stars, sum_through
# from time import time
import django.utils.dateformat
import time
import json
import re
import pytils
@@ -50,19 +54,547 @@ def get_last_all_user_visit_list() -> list:
:return: list -- список четырех последних посещений ценовых предложений всеми пользователями
"""
result_list_visit = []
id_fourth_visit = 0 # id четвертого посещения??? Зачем??? Не помню хоть убей!!!
# id_last_visit = 0 # id четвертого посещения??? Зачем??? Не помню хоть убей!!!
try:
q_log_visit = LogVisitPriceReport.objects.all().order_by('-dLogVisitTime')[:4]
for i in q_log_visit:
if id_fourth_visit == 0:
id_fourth_visit = i.id
# if id_last_visit == 0:
# id_last_visit = i.id
result_list_visit.append({
"Time": pytils.dt.distance_of_time_in_words(int(format(i.dLogVisitTime, 'U'))),
"id": i.id,
"Time": pytils.dt.distance_of_time_in_words(int(django.utils.dateformat.format(i.dLogVisitTime, 'U'))),
"LogURL": i.sLogURL,
"LogAddress": i.sLogAddress,
"LogApart": i.sLogNameApartment
})
except LogVisitPriceReport.DoesNotExist:
pass
# return id_fourth_visit+1, list_visit
# return id_last_visit+1, list_visit
return result_list_visit
def compare_offers(request: HttpRequest, to_compare: str = "1,2") -> HttpResponse:
""" Сравнение нескольких коммерческих предложений (оконных набора).
:param request: HttpRequest -- входящий http-запрос
:param to_compare: str -- список ,через запятую, id оконных наборов (Set) для сравнения
:return: HttpResponse --
"""
time_start = time.perf_counter()
to_template = {}
try:
# Этот блок нужен для 302-переадресации, когда разные URL отдают одинаковые страницы.
# Например, такое происходит для страницы: /compare_offers/1,2 и /compare_offers/2,1
# т.е. сравнивают одни и те же наборы, но они указаны в строке сравнения в разном порядке
# ----------------------------------------------------------------------------------------------
# получил строку: to_compare
# превращаем в список
list_input = to_compare.split(",")
list_fin = []
# убираем мусор и создаем список только из целых чисел (listResult)
for i in list_input:
try:
list_fin.append(int(i))
except ValueError:
continue
if len(list_fin) < 2:
return redirect("/compare_offers/1,2")
# Сортируем этот список (list_fin)
list_fin.sort()
# Превращаем список list_fin в строку list_fine (разделитель -- запятая)
list_fine = ','.join(map(str, list_fin))
# Сравниваем входной порядок параметров и отсоветованный. Если не совпадает, то переадресация-302
if to_compare != list_fine:
return redirect(f"/compare_offers/{list_fine}")
try:
q_set_kit = SetKit.objects.raw(
f"SELECT "
f"oknardia_setkit.id, oknardia_setkit.sSetName, oknardia_setkit.sSetDescription,"
f"oknardia_setkit.sSetClimateControl, oknardia_setkit.sSetSill, oknardia_setkit.sSetImplementAll,"
f"oknardia_setkit.sSetImplementHandles, oknardia_setkit.sSetImplementHinges,"
f"oknardia_setkit.sSetImplementLatch, oknardia_setkit.sSetImplementLimiter,"
f"oknardia_setkit.sSetImplementCatch, oknardia_setkit.sSetPanes, oknardia_setkit.sSetSlope,"
f"oknardia_setkit.sSetDelivery, oknardia_setkit.bSetDelivery, oknardia_setkit.sSetUninstallInstall,"
f"oknardia_setkit.bSetUninstallInstall, oknardia_setkit.sSetOtherConditions,"
f"oknardia_setkit.fSetRating, oknardia_setkit.iSetNumEval, oknardia_setkit.iSetImpressions,"
f"oknardia_setkit.iSetViews, oknardia_setkit.sSetActive, oknardia_setkit.dSetModify,"
f"(oknardia_setkit.dSetCommercialUntil > NOW()) AS bCommercial,"
f"oknardia_glazing.sGlazingReflectionAndAbsorptionOfHeat, oknardia_glazing.sGlazingBriefDescription,"
f"oknardia_glazing.sGlazingDescription, oknardia_glazing.fGlazingSoundproofing,"
f"oknardia_glazing.fGlazingRating, oknardia_glazing.sGlazingMark,"
f"oknardia_glazing.fGlazingHeatTransfer, oknardia_glazing.fGlazingLightTransmission,"
f"oknardia_glazing.fGlazingPassingSun, oknardia_glazing.sGlazingLightReflectance,"
f"oknardia_glazing.sGlazingManufacturer, oknardia_glazing.iGlazingCamerasN,"
f"oknardia_glazing.sGlazingToning, oknardia_glazing.iGlazingThickness,"
f"oknardia_merchantoffice.dOfficeDataCreate, oknardia_merchantoffice.sOfficeName,"
f"oknardia_merchantoffice.sOfficeStatus, oknardia_merchantoffice.sOfficePhones,"
f"oknardia_merchantoffice.sOfficeEmails, oknardia_merchantoffice.sOfficeDescription,"
f"oknardia_merchantoffice.sOfficeDiscountMetaFormula, oknardia_merchantoffice.fOfficeGeoCode_Latitude,"
f"oknardia_merchantoffice.fOfficeGeoCode_Longitude, oknardia_merchantoffice.sOfficeAddress,"
f"oknardia_ouruser.sUserAvatarImg, oknardia_ouruser.sUserJobTitle, oknardia_ouruser.bUserSubscribe,"
f"oknardia_ouruser.sUserPhone, oknardia_ouruser.sUserStatus, oknardia_merchantbrand.id AS MERCHANT_ID,"
f"oknardia_merchantbrand.sMerchantMainURL, oknardia_merchantbrand.sMerchantName,"
f"oknardia_merchantbrand.pMerchantLogo, oknardia_pvcprofiles.id AS PROFILE_ID,"
f"oknardia_pvcprofiles.sProfileName, oknardia_pvcprofiles.sProfileBriefDescription,"
f"oknardia_pvcprofiles.sProfileReinforcement, oknardia_pvcprofiles.sProfileDescription,"
f"oknardia_pvcprofiles.fProfileHeatTransf, oknardia_pvcprofiles.sProfileSealDescription,"
f"oknardia_pvcprofiles.fProfileSeals, oknardia_pvcprofiles.fProfileSoundproofing,"
f"oknardia_pvcprofiles.iProfileCameras, oknardia_pvcprofiles.iProfileGlazingThickness,"
f"oknardia_pvcprofiles.iProfileHeight, oknardia_pvcprofiles.iProfileRabbet,"
f"oknardia_pvcprofiles.iProfileThickness, oknardia_pvcprofiles.sProfileColor,"
f"oknardia_pvcprofiles.sProfileFillet, oknardia_pvcprofiles.sProfileManufacturer,"
f"oknardia_pvcprofiles.sProfileOther, oknardia_pvcprofiles.fProfileRating "
f"FROM oknardia_setkit"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_ouruser"
f" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantoffice.kMerchantName_id = oknardia_merchantbrand.id "
f"WHERE oknardia_setkit.id IN ({to_compare})")
except SetKit.DoesNotExist:
return redirect("/compare_offers/1,2")
list_set_kit = list(q_set_kit)
if len(list_set_kit) == 0:
return redirect("/compare_offers/1,2")
if len(list_set_kit) == 1:
return redirect(f"/specification_set/{list_set_kit[0].id}")
except (ValueError, TypeError):
return render("/compare_offers/1,2")
# ПРЕДВАРИТЕЛЬНЫЙ "ПРОГОН"
# Для того, чтобы "покрасить" ячейки таблицы сравнения в цвета, нужно для некоторых полей найти min и max...
ini_max = -100000
ini_min = 1000000
max_i_profile_cameras = max_f_profile_seals = max_i_profile_thickness = max_i_profile_glazing_thickness = \
max_f_profile_heat_transf = max_f_profile_soundproofing = max_i_profile_rabbet = max_i_profile_height = \
max_i_glazing_cameras_n = max_i_glazing_thickness = max_f_glazing_heat_transfer = max_rating_set = \
max_f_glazing_soundproofing = max_f_glazing_light_transmission = max_f_glazing_passing_sun = ini_max
min_i_profile_cameras = min_f_profile_seals = min_i_profile_thickness = min_i_profile_glazing_thickness = \
min_f_profile_heat_transf = min_f_profile_soundproofing = min_i_profile_rabbet = min_i_profile_height = \
min_i_glazing_cameras_n = min_i_glazing_thickness = min_f_glazing_heat_transfer = min_rating_set = \
min_f_glazing_soundproofing = min_f_glazing_light_transmission = min_f_glazing_passing_sun = ini_min
list_of_merchant_name = []
list_of_profile_name = []
list_of_glazing_brief_description = []
for i in list_set_kit:
if i.sMerchantName not in list_of_merchant_name:
list_of_merchant_name.append(i.sMerchantName)
if i.sProfileName not in list_of_profile_name:
list_of_profile_name.append(i.sProfileName)
if i.sGlazingMark not in list_of_glazing_brief_description:
list_of_glazing_brief_description.append(i.sGlazingMark)
profile_num_cameras = sum_through(i.iProfileCameras)
if profile_num_cameras > 0: # Общее число камер профиля (рама+створка)
if profile_num_cameras > max_i_profile_cameras:
max_i_profile_cameras = profile_num_cameras
if profile_num_cameras < min_i_profile_cameras:
min_i_profile_cameras = profile_num_cameras
if i.iProfileThickness > 0: # Контуров уплотнения
if i.fProfileSeals > max_f_profile_seals:
max_f_profile_seals = i.fProfileSeals
if i.fProfileSeals < min_f_profile_seals:
min_f_profile_seals = i.fProfileSeals
if i.iProfileThickness > 10: # Монтажная ширина профиля
if i.iProfileThickness > max_i_profile_thickness:
max_i_profile_thickness = i.iProfileThickness
if i.iProfileThickness < min_i_profile_thickness:
min_i_profile_thickness = i.iProfileThickness
if i.iProfileGlazingThickness > 4: # Максимальная толщина стеклопакета
if i.iProfileGlazingThickness > max_i_profile_glazing_thickness:
max_i_profile_glazing_thickness = i.iProfileGlazingThickness
if i.iProfileGlazingThickness < min_i_profile_glazing_thickness:
min_i_profile_glazing_thickness = i.iProfileGlazingThickness
if i.fProfileHeatTransf > 0: # Сопротивление теплопередаче
if i.fProfileHeatTransf > max_f_profile_heat_transf:
max_f_profile_heat_transf = i.fProfileHeatTransf
if i.fProfileHeatTransf < min_f_profile_heat_transf:
min_f_profile_heat_transf = i.fProfileHeatTransf
if i.fProfileSoundproofing > 0: # Коэффициент звукоизоляции
if i.fProfileSoundproofing > max_f_profile_soundproofing:
max_f_profile_soundproofing = i.fProfileSoundproofing
if i.fProfileSoundproofing < min_f_profile_soundproofing:
min_f_profile_soundproofing = i.fProfileSoundproofing
if i.iProfileRabbet > 1: # Фальц
if i.iProfileRabbet > max_i_profile_rabbet:
max_i_profile_rabbet = i.iProfileRabbet
if i.iProfileRabbet < min_i_profile_rabbet:
min_i_profile_rabbet = i.iProfileRabbet
if i.iProfileHeight > 12: # Высота в световом проеме
if i.iProfileHeight > max_i_profile_height:
max_i_profile_height = i.iProfileHeight
if i.iProfileHeight < min_i_profile_height:
min_i_profile_height = i.iProfileHeight
if i.iGlazingCamerasN > 0: # Камер стеклопакета
if i.iGlazingCamerasN > max_i_glazing_cameras_n:
max_i_glazing_cameras_n = i.iGlazingCamerasN
if i.iGlazingCamerasN < min_i_glazing_cameras_n:
min_i_glazing_cameras_n = i.iGlazingCamerasN
if i.iGlazingThickness > 4: # Толщина стеклопакета
if i.iGlazingThickness > max_i_glazing_thickness:
max_i_glazing_thickness = i.iGlazingThickness
if i.iGlazingThickness < min_i_glazing_thickness:
min_i_glazing_thickness = i.iGlazingThickness
if i.fGlazingHeatTransfer > 0.05: # Сопротивление теплопередаче стеклопакета Ro (м²×°C/Вт)
if i.fGlazingHeatTransfer > max_f_glazing_heat_transfer:
max_f_glazing_heat_transfer = i.fGlazingHeatTransfer
if i.fGlazingHeatTransfer < min_f_glazing_heat_transfer:
min_f_glazing_heat_transfer = i.fGlazingHeatTransfer
if i.fGlazingSoundproofing > 5: # Коэффициент звукоизоляции стеклопакета
if i.fGlazingSoundproofing > max_f_glazing_soundproofing:
max_f_glazing_soundproofing = i.fGlazingSoundproofing
if i.fGlazingSoundproofing < min_f_glazing_soundproofing:
min_f_glazing_soundproofing = i.fGlazingSoundproofing
if i.fGlazingLightTransmission > 5: # Коэффициент светопропускания стеклопакета
if i.fGlazingLightTransmission > max_f_glazing_light_transmission:
max_f_glazing_light_transmission = i.fGlazingLightTransmission
if i.fGlazingLightTransmission < min_f_glazing_light_transmission:
min_f_glazing_light_transmission = i.fGlazingLightTransmission
if i.fGlazingPassingSun > 5: # Коэффициент солнцепропускания стеклопакета
if i.fGlazingPassingSun > max_f_glazing_passing_sun:
max_f_glazing_passing_sun = i.fGlazingPassingSun
if i.fGlazingPassingSun < min_f_glazing_passing_sun:
min_f_glazing_passing_sun = i.fGlazingPassingSun
if i.fSetRating > 0.05: # Рейтинг НАБОРА!
if i.fSetRating > max_rating_set:
max_rating_set = i.fSetRating
if i.fSetRating < min_rating_set:
min_rating_set = i.fSetRating
# ОКОНЧАТЕЛЬНЫЙ ПРОГОН
# Передаём данные из SQL-запроса шаблон. Иногда надо вычислять цвета и прочее.
# Много макаронного стиля кодинга, из-за того что иначе придется передавать в функции большие массивы QuerySet.
# А это жрет много памяти.
dim = []
for i in list_set_kit:
# построим массив "цветов" для рейтинга "Общее число камер профиля (рама+створка)" (чем больше, тем лучше)
profile_num_cameras = sum_through(i.iProfileCameras)
if max_i_profile_cameras == ini_max or min_i_profile_cameras == ini_min or profile_num_cameras <= 1 \
or profile_num_cameras == min_i_profile_cameras or max_i_profile_cameras - min_i_profile_cameras < 0.001:
profile_num_cameras_color = None
else:
color_ratio = (profile_num_cameras - min_i_profile_cameras) / (
max_i_profile_cameras - min_i_profile_cameras)
profile_num_cameras_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Контуров уплотнения" (чем больше, тем лучше)
if max_f_profile_seals == ini_max or min_f_profile_seals == ini_min or i.fProfileSeals <= 0 \
or i.fProfileSeals == min_f_profile_seals or max_f_profile_seals - min_f_profile_seals < 0.001:
profile_seals_color = None
else:
color_ratio = (i.fProfileSeals - min_f_profile_seals) / (max_f_profile_seals - min_f_profile_seals)
profile_seals_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Монтажная ширина профиля" (чем больше, тем лучше)
if max_i_profile_thickness == ini_max or min_i_profile_thickness == ini_min or i.iProfileThickness <= 10 \
or i.iProfileThickness == min_i_profile_thickness \
or max_i_profile_thickness - min_i_profile_thickness < 0.001:
profile_thickness_color = None
else:
color_ratio = (i.iProfileThickness - min_i_profile_thickness) / (max_i_profile_thickness
- min_i_profile_thickness)
profile_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Максимальная толщина стеклопакета" (чем больше, тем лучше)
if max_i_profile_glazing_thickness == ini_max or min_i_profile_glazing_thickness == ini_min \
or i.iProfileGlazingThickness <= 4 or i.iProfileGlazingThickness == min_i_profile_glazing_thickness \
or max_i_profile_glazing_thickness - min_i_profile_glazing_thickness < 0.001:
profile_glazing_thickness_color = None
else:
color_ratio = (i.iProfileGlazingThickness
- min_i_profile_glazing_thickness) / (max_i_profile_glazing_thickness
- min_i_profile_glazing_thickness)
profile_glazing_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Сопротивление теплопередаче" (чем больше, тем лучше)
if max_f_profile_heat_transf == ini_max or min_f_profile_heat_transf == ini_min \
or i.fProfileHeatTransf == min_f_profile_heat_transf \
or max_f_profile_heat_transf - min_f_profile_heat_transf < 0.001:
profile_heat_transf_color = None
else:
color_ratio = (i.fProfileHeatTransf - min_f_profile_heat_transf) / (max_f_profile_heat_transf
- min_f_profile_heat_transf)
profile_heat_transf_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент звукоизоляции" (чем больше, тем лучше)
if max_f_profile_soundproofing == ini_max or min_f_profile_soundproofing == ini_min \
or i.fProfileSoundproofing == min_f_profile_soundproofing \
or max_f_profile_soundproofing - min_f_profile_soundproofing < 0.001:
profile_soundproofing_color = None
else:
color_ratio = (i.fProfileSoundproofing - min_f_profile_soundproofing) / (max_f_profile_soundproofing
- min_f_profile_soundproofing)
profile_soundproofing_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Фальц" (чем больше, тем лучше)
if max_i_profile_rabbet == ini_max or min_i_profile_rabbet == ini_min or i.iProfileRabbet <= 1 \
or i.iProfileRabbet == min_i_profile_rabbet or max_i_profile_rabbet - min_i_profile_rabbet < 0.001:
profile_rabbet_color = None
else:
color_ratio = (i.iProfileRabbet - min_i_profile_rabbet) / (max_i_profile_rabbet - min_i_profile_rabbet)
profile_rabbet_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Высота в световом проеме" (чем меньше, тем лучше)
if max_i_profile_rabbet == ini_max or min_i_profile_height == ini_min or i.iProfileHeight <= 12 \
or i.iProfileHeight == max_i_profile_height or max_i_profile_height - min_i_profile_height < 0.01:
profile_height_color = None
else:
color_ratio = (i.iProfileHeight - min_i_profile_height) / (max_i_profile_height - min_i_profile_height)
profile_height_color = f"#{127 + int(color_ratio * 128):02x}ff{127 + int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Камер стеклопакета" (чем больше, тем лучше)
if max_i_glazing_cameras_n == ini_max or min_i_profile_height == ini_min \
or i.iGlazingCamerasN == min_i_glazing_cameras_n \
or max_i_glazing_cameras_n - min_i_glazing_cameras_n < 0.001:
glazing_cameras_n_color = None
else:
color_ratio = (i.iGlazingCamerasN - min_i_glazing_cameras_n) / (max_i_glazing_cameras_n
- min_i_glazing_cameras_n)
glazing_cameras_n_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Толщина стеклопакета" (чем больше, тем лучше)
if max_i_glazing_thickness == ini_max or min_i_glazing_thickness == ini_min or i.iGlazingThickness <= 3 \
or i.iGlazingThickness == min_i_glazing_thickness \
or max_i_glazing_thickness - min_i_glazing_thickness < 0.001:
glazing_thickness_color = None
else:
color_ratio = (i.iGlazingThickness - min_i_glazing_thickness) / (max_i_glazing_thickness
- min_i_glazing_thickness)
glazing_thickness_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Сопротивление теплопередаче стеклопакета" (чем больше, тем лучше)
if max_f_glazing_heat_transfer == ini_max or min_f_glazing_heat_transfer == ini_min \
or i.fGlazingHeatTransfer <= 0.05 or i.fGlazingHeatTransfer == min_f_glazing_heat_transfer \
or max_f_glazing_heat_transfer - min_f_glazing_heat_transfer < 0.001:
glazing_heat_transfer_color = None
else:
color_ratio = (i.fGlazingHeatTransfer - min_f_glazing_heat_transfer) / (max_f_glazing_heat_transfer
- min_f_glazing_heat_transfer)
glazing_heat_transfer_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент звукоизоляции стеклопакета" (чем больше, тем лучше)
if max_f_glazing_soundproofing == ini_max or min_f_glazing_soundproofing == ini_min \
or i.fGlazingSoundproofing <= 5 or i.fGlazingSoundproofing == min_f_glazing_heat_transfer \
or max_f_glazing_soundproofing - min_f_glazing_soundproofing < 0.001:
glazing_soundproofing_color = None
else:
color_ratio = (i.fGlazingSoundproofing - min_f_glazing_soundproofing) / (max_f_glazing_soundproofing
- min_f_glazing_soundproofing)
glazing_soundproofing_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент светопропускания стеклопакета" (чем больше, тем лучше)
if max_f_glazing_light_transmission == ini_max or min_f_glazing_light_transmission == ini_min \
or i.fGlazingLightTransmission <= 5 or i.fGlazingLightTransmission == min_f_glazing_light_transmission \
or max_f_glazing_light_transmission - min_f_glazing_light_transmission < 0.002:
glazing_light_transmission_color = None
else:
color_ratio = (i.fGlazingLightTransmission
- min_f_glazing_light_transmission) / (max_f_glazing_light_transmission
- min_f_glazing_light_transmission)
glazing_light_transmission_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
# построим массив "цветов" для рейтинга "Коэффициент солнцепропускания стеклопакета" (чем меньше, тем лучше)
if max_f_glazing_passing_sun == ini_max or min_f_glazing_passing_sun == ini_min or i.fGlazingPassingSun <= 5 \
or i.fGlazingPassingSun == max_f_glazing_passing_sun \
or max_f_glazing_passing_sun - min_f_glazing_passing_sun < 0.0001:
glazing_passing_sun_color = None
else:
color_ratio = (i.fGlazingPassingSun - min_f_glazing_passing_sun) / (max_f_glazing_passing_sun
- min_f_glazing_passing_sun)
glazing_passing_sun_color = f"#{127 + int(color_ratio * 128):02x}ff{127 + int(color_ratio * 128):02x}"
########################################################################
# построим массив цветов "звездочек" для рейтинга наборов
if i.fSetRating > RARING_SET_MAX:
rating_set_n = RARING_SET_MAX
rating_set_color = "#80ff80"
elif i.fSetRating < RARING_SET_MIN + 0.05 or max_rating_set - min_rating_set < 0.001:
rating_set_n = RARING_SET_MIN
rating_set_color = ""
else:
try:
rating_set_n = i.fSetRating * (RARING_SET_MAX - RARING_SET_MIN) / RARING_STAR
color_ratio = (i.fSetRating - min_rating_set) / (max_rating_set - min_rating_set)
rating_set_color = f"#{255 - int(color_ratio * 128):02x}ff{255 - int(color_ratio * 128):02x}"
except (ZeroDivisionError, TypeError):
rating_set_color = None
rating_set_n = RARING_SET_MIN
# print RatingSet
list2_del = f",{to_compare},"
dim.append({
"MERCHANT": i.sMerchantName,
"MERCHANT_ID": i.MERCHANT_ID,
"IS_COMMERCIAL": i.bCommercial,
"MERCHANT_T": pytils.translit.slugify(i.sMerchantName),
'MERCHANT_URL': i.sMerchantMainURL,
'MERCHANT_URL_SHOT': re.sub("(?:^http://|^https://|/$|www\.)", "", i.sMerchantMainURL),
"SET_NAME": i.sSetName,
"MERCHANT_LOGO": i.pMerchantLogo,
"RATING_SET": get_rating_set_for_stars(i.fSetRating),
"RATING_SET_N": rating_set_n,
"RATING_SET_COLOR": rating_set_color,
"PROFILE_ID": i.PROFILE_ID,
"PROFILE_NAME": i.sProfileName,
"PROFILE_NAME_T": pytils.translit.slugify(i.sProfileName),
"PROFILE_MANUFACTURER": i.sProfileManufacturer,
"PROFILE_MANUFACTURER_T": pytils.translit.slugify(i.sProfileManufacturer),
"PROFILE_NUM_COLOR": i.sProfileColor,
"PROFILE_NUM_CAMERAS": i.iProfileCameras, # Число камер рамы/створки
"PROFILE_NUM_CAMERAS_COLOR": profile_num_cameras_color, # Число камер рамы/створки ЦВЕТА
"PROFILE_THICKNESS": i.iProfileThickness, # Монтажная ширина профиля
"PROFILE_THICKNESS_COLOR": profile_thickness_color, # Окраска Монтажная ширина профиля ЦВЕТА
"PROFILE_GLAZING_THICKNESS": i.iProfileGlazingThickness, # Максимальная толщина стеклопакета
"PROFILE_GLAZING_THICKNESS_COLOR": profile_glazing_thickness_color, # Макс-толщина стеклопакета ЦВЕТА
"PROFILE_HEAT_TRANSFER": i.fProfileHeatTransf, # Сопротивление теплопередаче
"PROFILE_HEAT_TRANSFER_COLOR": profile_heat_transf_color, # Сопротивление теплопередаче ЦВЕТА
"PROFILE_NUM_SEALS": i.fProfileSeals, # Контуров уплотнения
"PROFILE_NUM_SEALS_COLOR": profile_seals_color, # Контуров уплотнения ЦВЕТА
"PROFILE_SEAL_DESCRIPTION": i.sProfileSealDescription,
"PROFILE_SOUND_PROOFING": i.fProfileSoundproofing, # Коэффициент звукоизоляции
"PROFILE_SOUND_PROOFING_COLOR": profile_soundproofing_color, # Коэффициент звукоизоляции ЦВЕТА
"PROFILE_HEIGHT": i.iProfileHeight, # Высота в световом проеме
"PROFILE_HEIGHT_COLOR": profile_height_color, # Высота в световом проеме ЦВЕТА
"PROFILE_RABBET": i.iProfileRabbet, # Фальц
"PROFILE_RABBET_COLOR": profile_rabbet_color, # Фальц ЦВЕТА
"PROFILE_FILLET": i.sProfileFillet, # Штапик
"PROFILE_REINFORCEMENT": i.sProfileReinforcement, # Армирование профиля
"PROFILE_OTHER": i.sProfileOther,
"SET_ID": i.id, # id-набора
"SET_CLIMATE_CONTROL": i.sSetClimateControl, # климат контроль
"SET_STILL": i.sSetSill, # Подоконник
"SET_IMPLEMENTS_ALL": i.sSetImplementAll, # Фурнитура
"SET_IMPLEMENTS_HANDLES": i.sSetImplementHandles, # Фурнитура: Ручки
"SET_IMPLEMENTS_HINGES": i.sSetImplementHinges, # Фурнитура: Петли
"SET_IMPLEMENTS_LATCH": i.sSetImplementLatch, # Фурнитура: механизма запирания (запор)
"SET_IMPLEMENTS_LIMITER": i.sSetImplementLimiter, # Фурнитура: Ограничитель
"SET_IMPLEMENTS_CATCH": i.sSetImplementCatch, # Фурнитура: Фиксаторы открывания
"SET_PANES": i.sSetPanes, # Водоотлив
"SET_SLOPE": i.sSetSlope, # Откос
"SET_DELIVERY": i.sSetDelivery, # Доставка (условия
"SET_DELIVERY_B": i.bSetDelivery, # Доставка (да/нет)
"SET_UNINSTALL_INSTALL": i.sSetUninstallInstall, # Монтаж/демонтаж (условия)
"SET_UNINSTALL_INSTALL_B": i.bSetUninstallInstall, # Монтаж/демонтаж (да/нет)
"SET_OTHER_CONDITIONS": i.sSetOtherConditions, # Прочие условия
"GLAZING_CAMERAS_NUM": i.iGlazingCamerasN, # Камер стеклопакета
"GLAZING_CAMERAS_COLOR": glazing_cameras_n_color, # Камер стеклопакета ЦВЕТА
"GLAZING_THICKNESS": i.iGlazingThickness, # Толщина стеклопакета
"GLAZING_THICKNESS_COLOR": glazing_thickness_color, # Толщина стеклопакета
"GLAZING_BRIEF_DESCRIPTION": re.sub(u",[\s\d]+мм", "", i.sGlazingBriefDescription), # Кратко о стеклопакете
"GLAZING_MARK": i.sGlazingMark, # Схема, марка, маркировка, модель стеклопакета
"GLAZING_MANUFACTURER": i.sGlazingManufacturer, # Производитель стеклопакета
"GLAZING_HEAT_TRANSFER": i.fGlazingHeatTransfer, # Сопротивление теплопередаче стеклопакета Ro (м²×°C/Вт)
"GLAZING_HEAT_TRANSFER_COLOR": glazing_heat_transfer_color, # Сопротивление теплопередаче стеклопакета ЦВЕТ
"GLAZING_SOUNDPROOFING": i.fGlazingSoundproofing, # Коэффициент звукоизоляции стеклопакета
"GLAZING_SOUNDPROOFING_COLOR": glazing_soundproofing_color, # Коэффициент звукоизоляции стеклопакета ЦВЕТА
"GLAZING_LIGHT_TRANSMISSION": i.fGlazingLightTransmission, # Коэффициент светопропускания стеклопакета
"GLAZING_LIGHT_TRANSMISSION_COLOR": glazing_light_transmission_color, # Коэффициент светопропускания ЦВЕТА
"GLAZING_LIGHT_REFLECTION": i.sGlazingLightReflectance, # Коэффициент светоотражения внешний/внутренний
"GLAZING_PASSING_SUN": i.fGlazingPassingSun, # Коэффициент солнцепропускания стеклопакета
"GLAZING_PASSING_SUN_COLOR": glazing_passing_sun_color, # Коэффициент солнцепропускания ЦВЕТ
"GLAZING_REFLECTION_AND_ABSORPTION": i.sGlazingReflectionAndAbsorptionOfHeat,
# Коэффициент теплоотражения/теплопоглощения стеклопакета
"GLAZING_TONING": i.sGlazingToning, # Тонирование стеклопакета
"URL_W_DEL": list2_del.replace(f",{i.id},", ",")[1:-1] # Тонирование стеклопакета
})
to_template.update({'SET_LIST': dim,
'LIST_MERCHANT': list_of_merchant_name,
'LIST_PROFILE': list_of_profile_name,
'LIST_GLAZING': list_of_glazing_brief_description})
# Предложения для добавления в сравнения:
if len(list_set_kit) < 7:
try:
q_set_kit = SetKit.objects.raw(
f"SELECT "
f" oknardia_setkit.id, oknardia_setkit.sSetName,"
f" oknardia_setkit.dSetModify, oknardia_setkit.fSetRating,"
f" oknardia_merchantbrand.sMerchantName,"
f" MAX(oknardia_priceoffer.dOfferModify) AS dLastData,"
f" TO_DAYS(NOW()) - TO_DAYS(MAX(oknardia_priceoffer.dOfferModify)) AS deltaData "
f"FROM oknardia_ouruser"
f" INNER JOIN oknardia_setkit"
f" ON oknardia_ouruser.id = oknardia_setkit.kSet2User_id"
f" INNER JOIN oknardia_merchantoffice"
f" ON oknardia_merchantoffice.id = oknardia_ouruser.kMerchantOffice_id"
f" INNER JOIN oknardia_merchantbrand"
f" ON oknardia_merchantbrand.id = oknardia_merchantoffice.kMerchantName_id"
f" INNER JOIN oknardia_priceoffer"
f" ON oknardia_setkit.id = oknardia_priceoffer.kOffer2SetKit_id "
f"WHERE oknardia_setkit.id NOT IN (%s) "
f"GROUP BY oknardia_setkit.id,"
f" oknardia_setkit.sSetName,"
f" oknardia_merchantbrand.sMerchantName,"
f" oknardia_setkit.fSetRating "
f"ORDER BY dLastData DESC "
f"LIMIT 25;" % to_compare)
dim = []
for i in q_set_kit:
if i.deltaData < 100:
early_data = pytils.dt.distance_of_time_in_words(
int(django.utils.dateformat.format(i.dLastData, 'U')), accuracy=2
)
else:
early_data = ""
dim.append({
"ID_LIST": "%s,%d" % (to_compare, i.id),
"SET_NAME": i.sSetName,
"MERCHANT": i.sMerchantName,
"DATA_MODIFY": early_data,
"R": i.fSetRating,
"R_STAR": get_rating_set_for_stars(i.fSetRating),
})
to_template.update({'LIST_TO_ADD': dim})
except SetKit.DoesNotExist:
pass
to_template.update({
# получаем последние визиты клиента через куки
'LAST_VISIT': get_last_user_visit_list(get_last_user_visit_cookies(request)[:3]),
# получаем последние визиты всех посетителей из базы
# id2log, log_visit = get_last_all_user_visit_list()
'LOG_VISIT': get_last_all_user_visit_list(),
'ticks': float(time.perf_counter() - time_start)
})
return render(request, "report/report_compare_set.html", to_template)
def show_rating_components(request: HttpRequest, win_set: str = "1") -> HttpResponse:
""" Показать состав рейтинга оконного предложения (компоненты рейтинга)
:param request: HttpRequest -- входящий http-запрос
:param win_set: str -- id оконного набора, для которого показать состав рейтинга
:return: HttpResponse --
"""
time_start = time.perf_counter()
to_template = {}
try:
win_set = int(win_set)
except ValueError:
win_set = 1
q = SetKit.objects.raw(
f"SELECT oknardia_pvcprofiles.fProfileRating, oknardia_glazing.fGlazingRating,"
f" oknardia_setkit.fSetRating, oknardia_setkit.id, MAX(oknardia_priceoffer.dOfferModify) AS dPriceModify,"
f" COUNT(oknardia_priceoffer.id) AS NumOffer, AVG(oknardia_priceoffer.fOfferRating) AS fOfferRatingAvg "
f"FROM oknardia_setkit"
f" INNER JOIN oknardia_glazing"
f" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
f" INNER JOIN oknardia_pvcprofiles"
f" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id"
f" INNER JOIN oknardia_priceoffer"
f" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id "
f"WHERE oknardia_setkit.id = {win_set} "
f"GROUP BY oknardia_pvcprofiles.fProfileRating,"
f" oknardia_glazing.fGlazingRating,"
f" oknardia_setkit.fSetRating,"
f" oknardia_setkit.id;")
raring_list = list(q)
f_rating_service = raring_list[0].fSetRating - RARING_WEIGHT_PVC_PROFILE_IN_SET * normalize(
raring_list[0].fProfileRating, val_max=RARING_PVC_PROFILE_MAX
)
f_rating_service -= RARING_WEIGHT_GLAZING_IN_SET * normalize(raring_list[0].fGlazingRating,
val_max=RARING_GLAZING_MAX)
f_rating_service = normalize(f_rating_service,
val_max=RARING_SET_MAX-RARING_WEIGHT_PVC_PROFILE_IN_SET-RARING_WEIGHT_GLAZING_IN_SET)
f_rating_service *= RARING_SET_MAX
to_template.update({'RATING_SERVIZ': f_rating_service,
'RATING_SERVIZ_STARS': get_rating_set_for_stars(f_rating_service),
'RATING_GLAZ': raring_list[0].fGlazingRating,
'RATING_GLAZ_STARS': get_rating_set_for_stars(raring_list[0].fGlazingRating),
'RATING_PVC': raring_list[0].fProfileRating,
'RATING_PVC_STARS': get_rating_set_for_stars(raring_list[0].fProfileRating),
'RATING_OFFER': raring_list[0].fOfferRatingAvg,
'RATING_OFFER_STARS': get_rating_set_for_stars(raring_list[0].fOfferRatingAvg),
'DATA_OFFER_UPDATE': pytils.dt.distance_of_time_in_words(
int(django.utils.dateformat.format(raring_list[0].dPriceModify, 'U')), accuracy=2),
'NUM_OFFERS': pytils.numeral.get_plural(raring_list[0].NumOffer,
"коммерческое предложение, коммерческих предложения,"
" коммерческих предложений"),
'TEST': win_set,
'ticks': float(time.perf_counter() - time_start)})
return render(request, "report/show_rating_components.html", to_template)
+368
View File
@@ -0,0 +1,368 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from oknardia.models import PVCprofiles, Seria_Info, Win_MountDim, Building_Info, SetKit
from datetime import datetime, timezone
import django.utils.dateformat
import django.utils.timezone
from oknardia.settings import *
import time
# Главная страница для вызова служебных процедур.
def service(request: HttpRequest) -> HttpResponse:
""" Страница для вызова служебных процедур
:param request: HttpRequest
:return: HttpResponse
"""
time_start = time.perf_counter()
# проверка на аутентификацию
# print(request.user.is_authenticated)
if not request.user.is_authenticated:
return redirect("/service/not-denice")
return render(request, "service/index.html", {'ticks': float(time.perf_counter()-time_start)})
# страничка, на которую переадресует служебный интерфейс, если нет аутентификации.
def not_denice(request):
time_start = time.perf_counter()
return render(request, "service/not_denice.html", {'ticks': float(time.perf_counter()-time_start)})
def tmp(request: HttpRequest) -> HttpResponse:
""" Страница для тестирования верстки текста в блоге
:param request:
:return:
"""
t_start = time.perf_counter()
return render(request, "service/tmp.html", {'TAU': float(time.perf_counter()-t_start)})
def make_rating(request: HttpRequest) -> HttpResponse:
"""
Вычисляем (каждый раз заново) рейтинги оконных профилей, стеклопакетов и оконных наборов.
Вычисление базируется на ренкинге. В базовом ренкинге участвуют только стеклопакеты и профиля
присутствующие в коммерческих предложениях размещенных в ОКНАРДИИ.
Ренкинг профилей: Для получения ранка вся совокупность профилей из коммерческих предложений сортируется
по тому или иному признаку (характеристике). Каждому профилю присваивается ранк, который вычисляется как
весу той или иной характеристики и порядковому номеру профиля в сортированному по этому признаку
(характеристике) в списке.
ВНИМАНИЕ ТЕХНИЧЕСКИЙ ДОЛГ:
Система ренкинга разрабатывалась когда в базе было уже достаточно предложений. Возможно, если
объектов ренкинга будет мало что-то не сработает. И выдаст ошибку.
:param request: HttpRequest -- запрос
:return: HttpResponse -- ответ
"""
time_start = time.perf_counter()
msg = ""
# ВЫЧИСЛЯЕМ РЕЙТИНГ ПРОФИЛЕЙ
# устанавливаем рейтинг всех профилей в базе в ноль
profile_all_num = PVCprofiles.objects.all().update(fProfileRating=0.0)
to_template = {'NUM_PROFILE_TOTAL': profile_all_num} # засовываем данные в шаблон
q = PVCprofiles.objects.raw("SELECT"
" oknardia_pvcprofiles.*,"
" COUNT(oknardia_priceoffer.id) AS NumOffer "
"FROM oknardia_setkit"
" INNER JOIN oknardia_priceoffer"
" ON oknardia_setkit.id = oknardia_priceoffer.kOffer2SetKit_id"
" RIGHT OUTER JOIN oknardia_pvcprofiles"
" ON oknardia_setkit.kSet2PVCprofiles_id = oknardia_pvcprofiles.id "
"GROUP BY oknardia_pvcprofiles.id;")
profile_use_list = list(q)
# получаем словарь из RawQuerySet
PVC_Dictionary = Prepare_PVC_Dictionary(profile_use_list)
# получаем рейтинги
dim, PVC_Dictionary = RankingPVC(PVC_Dictionary)
to_template.update(dim) # засовываем данные в шаблон
# сортируем по полученному рейтингу
PVC_Dictionary = sorted(PVC_Dictionary, key=lambda item: item["TmpRating"])
# print u"РЕЙТИНГИ ПРОФИЛЕЙ IN USE"
# найдем минимальный и максимальный ранкинг для последующей нормализации
NumMaxRank = 0
NumMinRank = -1
j = 0
for i in PVC_Dictionary:
if i["NumOffer"] != 0:
NumMaxRank = j
if NumMinRank == -1:
NumMinRank = j
j += 1
j = 0
for i in PVC_Dictionary:
obj = PVCprofiles.objects.get(id=i["id"])
try:
GettedJSON = json.loads(obj.sProfileDescription)
except:
GettedJSON = {}
if i["NumOffer"] != 0:
try: del GettedJSON[KEY_RATING_VIRTUAL]
except: pass
GettedJSON[KEY_RATING] = i["RatingConsist"]
# GettedJSON.update({KEY_RATING:i["RatingConsist"]})
else:
try: del GettedJSON[KEY_RATING]
except: pass
GettedJSON[KEY_RATING_VIRTUAL] = i["RatingConsist"]
# GettedJSON.update({KEY_RATING_VIRTUAL:i["RatingConsist"]})
obj.sProfileDescription = json.dumps(GettedJSON,
separators=(",",":"),
sort_keys=True,
encoding="utf-8",
ensure_ascii=False)
if j <= NumMaxRank:
obj.fProfileRating = Normalize(i["TmpRating"],PVC_Dictionary[NumMaxRank]["TmpRating"]) * (RARING_PVC_PROFILE_MAX-RARING_PVC_PROFILE_MIN) + RARING_PVC_PROFILE_MIN
else:
obj.fProfileRating = 5.0
# print "id_PVC:", i["id"], u"\tΣ:", obj.fProfileRating, u"\tСостав:",
# print json.dumps(i["RatingConsist"], separators=(",",":"), encoding="utf-8", ensure_ascii=False)
obj.save()
j += 1
# вычисляем рейтинги стеклопакетоа
# ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░
# устанавливаем рейтинг всех стеклопакетоа в базе в ноль
GlazingAllNum = Glazing.objects.all().update(fGlazingRating=0.0)
to_template.update({'NUM_GLAZING_TOTAL':GlazingAllNum}) # засовываем данные в шаблон
q = Glazing.objects.raw("SELECT"
" oknardia_glazing.*,"
" COUNT(oknardia_priceoffer.id) AS NumOffer "
"FROM oknardia_setkit"
" INNER JOIN oknardia_priceoffer"
" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
" INNER JOIN oknardia_glazing"
" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id "
"GROUP BY oknardia_glazing.id;")
GlazingUseList = list(q)
# получаем словарь из RawQuerySet
GLAZ_Dictionary = Prepare_GLAZ_Dictionary(GlazingUseList)
# получаем рейтинги
dim, GLAZ_Dictionary = RankingGlazing(GLAZ_Dictionary)
to_template.update(dim) # засовываем данные в шаблон
# сортируем по полученному рейтингу
GLAZ_Dictionary = sorted(GLAZ_Dictionary, key=lambda item: item["TmpRating"])
# print u"РЕЙТИНГИ СТЕКЛОПАКЕТОВ IN USE"
for i in GLAZ_Dictionary:
obj = Glazing.objects.get(id=i["id"])
obj.fGlazingRating = Normalize(i["TmpRating"], ValMax=GLAZ_Dictionary[-1]["TmpRating"]) * (RARING_GLAZING_MAX-RARING_GLAZING_MIN) + RARING_GLAZING_MIN
try:
GettedJSON = json.loads(obj.sGlazingDescription)
except:
GettedJSON = {}
try: del GettedJSON[KEY_RATING_VIRTUAL]
except: pass
GettedJSON.update({KEY_RATING:i["RatingConsist"]})
obj.sGlazingDescription = json.dumps(GettedJSON,
separators=(",",":"),
sort_keys=True,
encoding="utf-8",
ensure_ascii=False)
# print u"id:",i["id"], u"\tRank:", i["TmpRating"], u"\rate:", obj.fGlazingRating, u"\tGLAZ:", i["sGlazingMark"]
obj.save()
# получаем все стеклопакеты, чтобы забацать рейтинг и для тех, которые есть в каталоге но нет в КП
q = Glazing.objects.raw("SELECT oknardia_glazing.* "
"FROM oknardia_glazing;")
GlazingAllList = list(q)
# получаем словарь из RawQuerySet
GLAZ_Dictionary = Prepare_GLAZ_Dictionary(GlazingAllList)
# получаем рейтинги
dim, GLAZ_Dictionary = RankingGlazing(GLAZ_Dictionary)
GLAZ_Dictionary = sorted(GLAZ_Dictionary, key=lambda item: item["TmpRating"])
if GlazingAllNum > len(GlazingUseList):
CutStartIndex = -1
CutStartRatingValue = 0.
CutEndIndex = -1
CutEndRatingValue = 0.
for i in range(0, GlazingAllNum):
# print i, GLAZ_Dictionary[i]["id"], u"\trank --> ", GLAZ_Dictionary[i]["TmpRating"], "\t(",
# print GLAZ_Dictionary[i]["fGlazingRating"], ")\tFormulaGLAZING:", GLAZ_Dictionary[i]["sGlazingMark"]
if GLAZ_Dictionary[i]["fGlazingRating"] != 0.:
# нашли конец следующего отрезка, нужно отрезок переопределить
CutStartRatingValue = CutEndRatingValue
CutStartIndex = CutEndIndex
CutEndRatingValue = GLAZ_Dictionary[i]["fGlazingRating"]
CutEndIndex = i
if CutEndIndex == 0:
continue
else:
# надо перебрать все объекты внутри отрезка
for j in range(CutStartIndex+1, CutEndIndex):
# и пересчитать рейтинги внутри этого, нового отрезка
GLAZ_Dictionary[j]["fGlazingRating"] = CutStartRatingValue + (GLAZ_Dictionary[j]["TmpRating"]-GLAZ_Dictionary[CutStartIndex]["TmpRating"])*((CutEndRatingValue-CutStartRatingValue)/(GLAZ_Dictionary[CutEndIndex]["TmpRating"]-GLAZ_Dictionary[CutStartIndex]["TmpRating"]))
# print j, GLAZ_Dictionary[j]["id"], u"\trank >>> ", GLAZ_Dictionary[j]["TmpRating"], "\t(",
# print GLAZ_Dictionary[j]["fGlazingRating"], ")\tFormulaGLAZING:", GLAZ_Dictionary[j]["sGlazingMark"]
# и записать этот рейтинг в базу
obj = Glazing.objects.get(id=GLAZ_Dictionary[j]["id"])
obj.fGlazingRating = GLAZ_Dictionary[j]["fGlazingRating"]
try:
GettedJSON = json.loads(obj.sGlazingDescription)
except:
GettedJSON = {}
try: del GettedJSON[KEY_RATING]
except: pass
GettedJSON.update({KEY_RATING_VIRTUAL:GLAZ_Dictionary[j]["RatingConsist"]})
obj.sGlazingDescription = json.dumps(GettedJSON,
separators=(",",":"),
sort_keys=True,
encoding="utf-8",
ensure_ascii=False)
obj.save()
for j in range(CutEndIndex+1, GlazingAllNum):
# пересчитать рейтинги хвоста (для отрезка после последнего отрейтингованного)
# внимание это код не для работы со словарями. при ревизии переделать GlazingAllList[j].fGlazingRating = CutStartRatingValue + (GlazingAllList[j].TmpRating-GlazingAllList[CutStartIndex].TmpRating)*((CutEndRatingValue-CutStartRatingValue)/(GlazingAllList[CutEndIndex].TmpRating-GlazingAllList[CutStartIndex].TmpRating))
GLAZ_Dictionary[j]["fGlazingRating"] = RARING_GLAZING_MAX # т.к. для виртуальный рейтинг иногда снижается, то ставим 5*
# и записать этот рейтинг в базу
obj = Glazing.objects.get(id=GLAZ_Dictionary[j]["id"])
obj.fGlazingRating = GLAZ_Dictionary[j]["fGlazingRating"]
try:
GettedJSON = json.loads(obj.sGlazingDescription)
except:
GettedJSON = {}
try: del GettedJSON[KEY_RATING]
except: pass
GettedJSON.update({KEY_RATING_VIRTUAL:GLAZ_Dictionary[j]["RatingConsist"]})
obj.sGlazingDescription = json.dumps(GettedJSON,
separators=(",",":"),
sort_keys=True,
encoding="utf-8",
ensure_ascii=False)
obj.save()
# вычисляем рейтинги наборов (стеклопакет + профиль + сопутсвующие услуги т.п.
# ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░
# устанавливаем рейтинг всех наборов в базе в ноль
SetAllNum = SetKit.objects.all().update(fSetRating=0.0)
to_template.update({'NUM_SET_TOTAL':SetAllNum}) # засовываем данные в шаблон
q = SetKit.objects.raw("SELECT"
" COUNT(oknardia_priceoffer.id) AS NumOffer,"
" MAX(oknardia_priceoffer.dOfferModify) AS dModify,"
" oknardia_pvcprofiles.fProfileRating,"
" oknardia_glazing.fGlazingRating,"
" oknardia_setkit.*,"
" oknardia_merchantoffice.sOfficeDiscountMetaFormula "
"FROM oknardia_setkit"
" INNER JOIN oknardia_priceoffer"
" ON oknardia_priceoffer.kOffer2SetKit_id = oknardia_setkit.id"
" INNER JOIN oknardia_glazing"
" ON oknardia_setkit.kSet2Glazing_id = oknardia_glazing.id"
" INNER JOIN oknardia_pvcprofiles"
" ON oknardia_pvcprofiles.id = oknardia_setkit.kSet2PVCprofiles_id "
" INNER JOIN oknardia_ouruser"
" ON oknardia_setkit.kSet2User_id = oknardia_ouruser.id"
" INNER JOIN oknardia_merchantoffice"
" ON oknardia_ouruser.kMerchantOffice_id = oknardia_merchantoffice.id "
"WHERE oknardia_setkit.sSetActive = TRUE "
"GROUP BY oknardia_pvcprofiles.fProfileRating,"
" oknardia_glazing.fGlazingRating,"
" oknardia_merchantoffice.sOfficeDiscountMetaFormula,"
" oknardia_setkit.sSetActive, oknardia_setkit.id "
"ORDER BY MAX(oknardia_priceoffer.dOfferModify);")
# q = SetKit.objects.order_by("dModify")
SetUseList = list(q)
to_template.update({'NUM_SET': len(SetUseList) })
SetDictionary = []
# Превратим RawQuerySet в массив словарей (почти JSON). Так получится избежать "макаронного кода".
# Заодно переопределяем для правильного ранжирования некоторые параметры из строк в цифры.
for i in range(0,len(SetUseList)):
SetDictionary.append(q[i].__dict__)
if SetDictionary[i]["sSetSill"].lower() in [u"нет",u"-",u"",""," "]:
SetDictionary[i]["sSetSill"] = 0 # Подоконника нет
else: SetDictionary[i]["sSetSill"] = 1 # Подоконник есть
if SetDictionary[i]["sSetPanes"].lower() in [u"нет",u"-",u"",""," "]:
SetDictionary[i]["sSetPanes"] = 0 # Водоотлив нет
else: SetDictionary[i]["sSetPanes"] = 1 # Водоотлив есть
if SetDictionary[i]["sSetSlope"].lower() in [u"нет",u"-",u"",""," "]:
SetDictionary[i]["sSetSlope"] = 0 # Откос нет
else: SetDictionary[i]["sSetSlope"] = 1 # Откос есть
if SetDictionary[i]["sSetClimateControl"].lower() in [u"нет",u"-",u"",""," "]:
SetDictionary[i]["sSetClimateControl"] = 0 # Климат-контроль нет
else: SetDictionary[i]["sSetClimateControl"] = 1 # Климат-контроль есть
try:
# print eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].keys()
# print max(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].values())
SetDictionary[i].update({"DiscountMax": max(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].values())})
SetDictionary[i]["sOfficeDiscountMetaFormula"] = len(eval(SetDictionary[i]["sOfficeDiscountMetaFormula"])[KEY_DICSOUNT].keys())
except:
SetDictionary[i].update({"DiscountMax": 0})
SetDictionary[i]["sOfficeDiscountMetaFormula"] = 0
# Отранжируем наборы по параметру "дата последнего обновления цены" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "dModify", key_weight=RANK_STEP_SET_MODIFY,
rank_name=u"Актуальность", revers=False)
to_template.update({'S_Modify_Step': RANK_STEP_SET_MODIFY })
to_template.update({'S_Modify_MaxRank': MaxRank })
# Отранжируем наборы по параметру "доставка включена в стоимость" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "bSetDelivery", key_weight=RANK_STEP_SET_DELIVERY,
rank_name=u"Доставка", revers=False)
to_template.update({'S_Delivery_Step': RANK_STEP_SET_DELIVERY })
to_template.update({'S_Delivery_MaxRank': MaxRank })
# Отранжируем наборы по параметру Демонтаж/Монтаж" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "bSetUninstallInstall", key_weight=RANK_STEP_SET_UNINSTALL_INSTALL,
rank_name=u"Монтаж")
to_template.update({'S_UninstallInstall_Step': RANK_STEP_SET_UNINSTALL_INSTALL })
to_template.update({'S_UninstallInstall_MaxRank': MaxRank })
# Отранжируем наборы по параметру Подоконник" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "sSetSill", key_weight=RANK_STEP_SET_SILL,
rank_name=u"Подоконник")
to_template.update({'S_Sill_Step': RANK_STEP_SET_SILL })
to_template.update({'S_Sill_MaxRank': MaxRank })
# Отранжируем наборы по параметру Водоотлив" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "sSetPanes", key_weight=RANK_STEP_SET_PANES,
rank_name=u"Водоотлив")
to_template.update({'S_Panes_Step': RANK_STEP_SET_PANES })
to_template.update({'S_Panes_MaxRank': MaxRank })
# Отранжируем наборы по параметру Откос" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "sSetSlope", key_weight=RANK_STEP_SET_SLOPE,
rank_name=u"Откос")
to_template.update({'S_Slope_Step': RANK_STEP_SET_SLOPE })
to_template.update({'S_Slope_MaxRank': MaxRank })
# Отранжируем наборы по параметру Климат-контроль" -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "sSetClimateControl", key_weight=RANK_STEP_SET_CLIMATE_CONTROL,
rank_name=u"Климат-контроль")
to_template.update({'S_ClimateControl_Step': RANK_STEP_SET_CLIMATE_CONTROL })
to_template.update({'S_ClimateControl_MaxRank': MaxRank })
# Отранжируем наборы по параметру Число предложений -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "NumOffer", key_weight=RANK_STEP_SET_NUM_OFFER,
rank_name=u"Число предложений")
to_template.update({'S_NumOffer_Step': RANK_STEP_SET_NUM_OFFER })
to_template.update({'S_NumOffer_MaxRank': MaxRank })
# Отранжируем наборы по параметру Гибкие скидки -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "sOfficeDiscountMetaFormula", key_weight=RANK_STEP_DISCOUNT_FLEX,
rank_name=u"Гибкость скидок")
to_template.update({'S_DiscountFlex_Step': RANK_STEP_DISCOUNT_FLEX })
to_template.update({'S_DiscountFlex_MaxRank': MaxRank })
# Отранжируем наборы по параметру Гибкие скидки -- ПО ВОЗРАСТАНИЮ
SetDictionary, MaxRank = GetRank(SetDictionary, "DiscountMax", key_weight=RANK_STEP_DISCOUNT_MAX,
rank_name=u"Размеры скидок")
to_template.update({'S_DiscountMax_Step': RANK_STEP_DISCOUNT_MAX })
to_template.update({'S_DiscountMax_MaxRank': MaxRank })
# расчитываем обзий рейтинг наборов и записываем в базу
SetDictionary = sorted(SetDictionary, key=lambda item: item["TmpRating"])
# print u"РЕЙТИНГИ НАБОРОВ"
for i in SetDictionary:
obj = SetKit.objects.get(id=i["id"])
try:
GettedJSON = json.loads(obj.sSetDescription)
except:
GettedJSON = {}
# нормализованный рейтинг сета
# print GettedJSON
k1 = Normalize(i["TmpRating"], SetDictionary[-1]["TmpRating"] )*(RARING_SET_MAX-RARING_WEIGHT_PVC_PROFILE_IN_SET-RARING_WEIGHT_GLAZING_IN_SET-RARING_SET_MIN)
k2 = Normalize(i["fGlazingRating"], RARING_GLAZING_MAX) * RARING_WEIGHT_GLAZING_IN_SET
k3 = Normalize(i["fProfileRating"], RARING_PVC_PROFILE_MAX) * RARING_WEIGHT_PVC_PROFILE_IN_SET
# print "id:", i["id"], u"\tk1:", k1, u"\tk2", k2, u"\tk3", k3, u"\tΣ:", k1+k2+k3
obj.fSetRating = k1+k2+k3
# print str(i["RatingConsist"])
try: del GettedJSON[KEY_RATING_VIRTUAL]
except: pass
GettedJSON.update({KEY_RATING:i["RatingConsist"]})
obj.sSetDescription = json.dumps(GettedJSON, separators=(",",":"), encoding="utf-8", ensure_ascii=False)
# print obj.sSetDescription
obj.save()
# print u"id:",i["id"], u"\tRank:", i["TmpRating"], u"\tRate:", obj.fSetRating, u"\tSet:", i["sSetName"], i["fProfileRating"], i["fGlazingRating"]
to_template.update({'msg': msg})
to_template.update({'ticks': float(time.perf_counter()-time_start)})
return render(request, "service/make_rating.html", to_template)
+292 -2
View File
@@ -1,3 +1,293 @@
from django.test import TestCase
from datetime import timedelta
from decimal import Decimal
import json
from unittest.mock import patch
from django.contrib.auth.models import User
from django.db import connection
from django.http import HttpResponse
from django.test import RequestFactory, TestCase
from django.utils import timezone
from oknardia.settings import CATALOG_RECORD_FOR_PROFILE_MODEL
from web.catalog import catalog_profile_model
from oknardia.models import (
BlogPosts,
Catalog2Profile,
Glazing,
MerchantBrand,
MerchantOffice,
OurUser,
PVCprofiles,
PriceOffer,
SetKit,
)
class CatalogProfileViewTests(TestCase):
"""Регрессионные тесты для вьюхи каталога профилей."""
def setUp(self) -> None:
# Базовый пользователь нужен, потому что профиль ссылается на OurUser.
django_user = User.objects.create_user(username="tester", password="secret")
self.our_user = OurUser.objects.create(kDjangoUser=django_user)
self.factory = RequestFactory()
def _get_context(self, response):
"""Достаёт итоговый контекст из ответа тестового клиента."""
context = response.context
if isinstance(context, list):
return context[-1]
return context
def _create_profile(self, *, name: str, brief: str, manufacturer: str, days_ago: int) -> PVCprofiles:
"""Создаёт профиль с нужными полями и фиксирует дату изменения вручную."""
profile = PVCprofiles.objects.create(
sProfileName=name,
sProfileBriefDescription=brief,
sProfileManufacturer=manufacturer,
kProfile2User=self.our_user,
fProfileRating=3.5,
)
# В модели стоит auto_now=True, поэтому после создания дату правим отдельным update.
modified_at = timezone.now() - timedelta(days=days_ago)
PVCprofiles.objects.filter(pk=profile.pk).update(dProfileModify=modified_at)
profile.refresh_from_db()
return profile
def _create_catalog_profile_model_fixture(self, *, manufacturer: str = "Альфа"):
"""Собирает минимальный набор данных для карточки профиля."""
profile = PVCprofiles.objects.create(
sProfileName="Alpha Basic",
sProfileBriefDescription="Альфа База",
sProfileManufacturer=manufacturer,
kProfile2User=self.our_user,
fProfileRating=4.25,
sProfileDescription=json.dumps({"html": "<p>Дополнительная информация о профиле.</p>"}),
sProfileOther="Контур: 2; Цвет: Белый",
)
PVCprofiles.objects.filter(pk=profile.pk).update(dProfileModify=timezone.now() - timedelta(days=10))
profile.refresh_from_db()
sibling = PVCprofiles.objects.create(
sProfileName="Alpha Plus",
sProfileBriefDescription="Альфа Плюс",
sProfileManufacturer=manufacturer,
kProfile2User=self.our_user,
fProfileRating=3.75,
)
brand = MerchantBrand.objects.create(
sMerchantName="Окно-Мир",
sMerchantMainURL="https://example.com",
)
office = MerchantOffice.objects.create(
sOfficeName="Окно-Мир Москва",
kMerchantName=brand,
sOfficeEmails="info@example.com",
sOfficePhones="+7(495)000-00-00",
)
self.our_user.kMerchantOffice = office
self.our_user.save(update_fields=["kMerchantOffice"])
glazing = Glazing.objects.create(
sGlazingName="Тёплый пакет",
sGlazingBriefDescription="Теплый двухкамерный стеклопакет",
kGlazing2User=self.our_user,
)
setkit = SetKit.objects.create(
sSetName="Набор-Альфа",
kSet2User=self.our_user,
kSet2PVCprofiles=profile,
kSet2Glazing=glazing,
sSetDescription="Комплект для теста",
sSetClimateControl="Климат",
sSetSill="Подоконник",
sSetImplementAll="Фурнитура",
sSetImplementHandles="Ручки",
sSetImplementHinges="Петли",
sSetImplementLatch="Запоры",
sSetImplementLimiter="Ограничитель",
sSetImplementCatch="Фиксатор",
sSetPanes="Водоотлив",
sSetSlope="Откос",
sSetDelivery="Доставка",
bSetDelivery=True,
sSetUninstallInstall="Монтаж",
bSetUninstallInstall=True,
sSetOtherConditions="Прочее",
fSetRating=4.1,
dSetCommercialUntil=timezone.now(),
)
# В текущей схеме таблицы поле открывания называется flap_config, а не sFlapConfig.
win_flap_column = "flap_" + "config"
with connection.cursor() as cursor:
cursor.execute(
f"INSERT INTO oknardia_win_mountdim "
f"(iWinWidth, iWinHight, iWinDepth, {win_flap_column}, sDescripion, bIsDoor, bIsNearDoor, iWinLimit, dMountXYZDataCreate, dMountXYZModify) "
f"VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
[Decimal("120.0"), Decimal("140.0"), Decimal("15.0"), "[>][<]", "Окно тестовое", 0, 0, Decimal("5.0")],
)
win_id = cursor.lastrowid
PriceOffer.objects.create(
kOffer2MountDim_id=win_id,
kOfferFromUser=self.our_user,
kOffer2SetKit=setkit,
sOfferFlapConfig="[>][<]",
fOfferPrice=Decimal("12345.00"),
)
blog = BlogPosts.objects.create(
sPostHeader="Описание профиля",
kBlogAuthorUser=self.our_user,
sPostContent="<p>Основной текст</p><cut><p>Скрыто</p>",
sImgForBlogSocial="img/catalog-profile.jpg",
bCatalog=True,
iCatalogSort=1,
dPostDataBegin=timezone.now(),
)
BlogPosts.objects.filter(pk=blog.pk).update(dPostDataModify=timezone.now() - timedelta(days=1))
blog.refresh_from_db()
Catalog2Profile.objects.create(
kProfile=profile,
kBlogCatalog=blog,
sCatalogCardType=CATALOG_RECORD_FOR_PROFILE_MODEL,
)
return profile, sibling, brand, blog
@patch("web.catalog.get_last_all_user_visit_list", return_value=["all-visits"])
@patch("web.catalog.get_last_user_visit_list", return_value=["last-visits"])
@patch("web.catalog.get_last_user_visit_cookies", return_value=["cookie-1", "cookie-2", "cookie-3"])
def test_catalog_profile_handles_empty_catalog(
self,
mocked_cookies,
mocked_last_visits,
mocked_all_visits,
):
"""Пустой каталог не должен падать и должен отдавать ожидаемый контекст."""
with self.assertNumQueries(1):
response = self.client.get("/catalog/profile/")
context = self._get_context(response)
self.assertEqual(response.status_code, 200)
self.assertEqual(context["CATALOG_PROFILE_NUM"], "0 профилей")
self.assertEqual(context["CATALOG_MANUFACT_NUM"], 0)
self.assertEqual(context["CATALOG_PROFILE_MAN1_NAME2"], [])
self.assertEqual(context["LAST_VISIT"], ["last-visits"])
self.assertEqual(context["LOG_VISIT"], ["all-visits"])
self.assertTrue(mocked_cookies.called)
self.assertTrue(mocked_last_visits.called)
self.assertTrue(mocked_all_visits.called)
@patch("web.catalog.get_last_all_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_cookies", return_value=[])
def test_catalog_profile_groups_and_sorts_profiles(
self,
mocked_cookies,
mocked_last_visits,
mocked_all_visits,
):
"""Каталог должен группировать профили по производителю и сохранять сортировку."""
self._create_profile(name="Alpha Basic", brief="Альфа База", manufacturer="Альфа", days_ago=5)
self._create_profile(name="Alpha Plus", brief="Альфа Плюс", manufacturer="Альфа", days_ago=2)
self._create_profile(name="Beta Light", brief="Бета Лайт", manufacturer="Бета", days_ago=1)
self._create_profile(name="Hidden", brief="Скрытый", manufacturer="", days_ago=7)
with self.assertNumQueries(1):
response = self.client.get("/catalog/profile/")
context = self._get_context(response)
self.assertEqual(response.status_code, 200)
# Пустой производитель не должен превращаться в отдельную группу.
groups = context["CATALOG_PROFILE_MAN1_NAME2"]
self.assertEqual(len(groups), 2)
self.assertEqual([group["PROF_MAN"] for group in groups], ["Альфа", "Бета"])
alpha_group = groups[0]
self.assertEqual(alpha_group["PROF_MAN_T"], "alfa")
self.assertEqual(
[item["PROF_NAME"] for item in alpha_group["PROF_MAN_LIST"]],
["Альфа База", "Альфа Плюс"],
)
self.assertEqual(
[item["PROF_NAME_T"] for item in alpha_group["PROF_MAN_LIST"]],
["alpha-basic", "alpha-plus"],
)
beta_group = groups[1]
self.assertEqual(beta_group["PROF_MAN_T"], "beta")
self.assertEqual([item["PROF_NAME"] for item in beta_group["PROF_MAN_LIST"]], ["Бета Лайт"])
# Проверяем итоговые счетчики и структуру контекста.
self.assertEqual(context["CATALOG_MANUFACT_NUM"], 2)
self.assertEqual(context["CATALOG_PROFILE_NUM"], "4 профиля")
self.assertEqual(context["LAST_VISIT"], [])
self.assertEqual(context["LOG_VISIT"], [])
self.assertTrue(mocked_cookies.called)
self.assertTrue(mocked_last_visits.called)
self.assertTrue(mocked_all_visits.called)
@patch("web.catalog.get_last_all_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_cookies", return_value=[])
def test_catalog_profile_model_redirects_to_canonical_url(
self,
mocked_cookies,
mocked_last_visits,
mocked_all_visits,
):
"""При неверных slug страница должна отправлять на канонический URL."""
profile = self._create_profile(name="Alpha Basic", brief="Альфа База", manufacturer="Альфа", days_ago=5)
request = self.factory.get(f"/catalog/profile/{profile.id}-wrong/{profile.id}-wrong/")
response = catalog_profile_model(request, profile.id, "wrong", profile.id, "wrong")
self.assertEqual(response.status_code, 302)
self.assertEqual(response["Location"], f"/catalog/profile/{profile.id}-alfa/{profile.id}-alpha-basic")
@patch("web.catalog.get_last_all_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_list", return_value=[])
@patch("web.catalog.get_last_user_visit_cookies", return_value=[])
def test_catalog_profile_model_renders_related_data(
self,
mocked_cookies,
mocked_last_visits,
mocked_all_visits,
):
"""Карточка профиля должна собираться через ORM и отдавать все ключевые блоки."""
profile, sibling, brand, blog = self._create_catalog_profile_model_fixture()
request = self.factory.get(f"/catalog/profile/{profile.id}-alfa/{profile.id}-alpha-basic/")
captured = {}
def fake_render(_request, template_name, context):
captured["template_name"] = template_name
captured["context"] = context
return HttpResponse("ok")
with patch("web.catalog.render", side_effect=fake_render):
with self.assertNumQueries(4):
response = catalog_profile_model(request, profile.id, "alfa", profile.id, "alpha-basic")
context = captured["context"]
self.assertEqual(response.status_code, 200)
self.assertEqual(captured["template_name"], "catalog/catalog_of_profiles_model.html")
self.assertEqual(context["CATALOG_MODEL"].id, profile.id)
self.assertEqual(context["CATALOG_URL"], f"{profile.id}-alfa")
self.assertEqual(context["CATALOG_URL2"], f"{profile.id}-alfa/{profile.id}-alpha-basic")
self.assertEqual(len(context["MERCHANTS"]), 1)
self.assertEqual(context["MERCHANTS"][0]["MERCHANT_NAME"], brand.sMerchantName)
self.assertEqual(context["MERCHANTS"][0]["MERCHANT_OFFERS"], 1)
self.assertEqual(len(context["PROFILES"]), 1)
self.assertEqual(context["PROFILES"][0]["PROFILE_ID"], sibling.id)
self.assertEqual(len(context["PROFILE_DETAIL"]), 1)
self.assertEqual(context["PROFILE_DETAIL"][0].sPostContent, blog.sPostContent)
self.assertEqual(context["IMG_FOR_BLOG"], blog.sImgForBlogSocial)
self.assertEqual(context["PUB_DAT"].date(), blog.dPostDataModify.date())
self.assertEqual(context["LIST_OTHER"], ["<b>Контур:</b>2", "<b>Цвет:</b>Белый"])
self.assertTrue(mocked_cookies.called)
self.assertTrue(mocked_last_visits.called)
self.assertTrue(mocked_all_visits.called)
# Create your tests here.
+198 -5
View File
@@ -1,10 +1,14 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.shortcuts import render, redirect
from django.http import HttpRequest, HttpResponse
from django.core.mail import send_mail
from smtplib import SMTPException
from oknardia.models import Seria_Info, Building_Info, Apartment_Type
from web.add_func import get_yandex_geocode_by_address, get_geo_distance
import json
import datetime
import time
import pytils
# from django.core.context_processors import csrf
@@ -17,7 +21,6 @@ def main_init(request: HttpRequest) -> HttpResponse:
"""
to_template = {} # словарь, для передачи шаблону
num_viz = 0 # как будто первый визит
template = "index.html" # шаблон
# проверяем куки числа визита
if "NumVisit" in request.COOKIES:
# стоят куки, и это не первый визит
@@ -41,7 +44,7 @@ def main_init(request: HttpRequest) -> HttpResponse:
to_template.update({'META_DOCUMENT_STATE': u"Static"}) # Эта страничка статичная (в шаблон)
to_template.update({'NV': num_viz})
# to_template.update(csrf(request)) # токен, для метода POST и GET
response = render(request, template, to_template)
response = render(request, "index.html", to_template)
response.set_cookie("NumVisit", num_viz, max_age=604800) # ставим или перезаписываем куки (неделя)
return response
@@ -53,7 +56,6 @@ def tariff(request: HttpRequest) -> HttpResponse:
:return response: исходящий http-ответ
"""
to_template = {} # для передачи в шаблон
template = "tariff.html" # шаблон
if request.method == 'POST':
# print request.POST
if 'tariff' in request.POST and 'email_' in request.POST \
@@ -91,7 +93,7 @@ def tariff(request: HttpRequest) -> HttpResponse:
# Что-то пошло не так и почта не отправилась. Надо подумать что в этим делать
to_template.update({'SENDER': "Error!"})
pass
return render(request, template, to_template)
return render(request, "tariff.html", to_template)
def contact(request: HttpRequest) -> HttpResponse:
@@ -101,3 +103,194 @@ def contact(request: HttpRequest) -> HttpResponse:
:return response: исходящий http-ответ
"""
return render(request, "contact.html", {})
def get_address(request: HttpRequest) -> HttpResponse:
""" Вызывается после ввода пользователем адреса. Получает строку с адресом методом POST
ВНИМАНИЕ ТЕХНИЧЕСКИЙ ДОЛГ: Заменить GET на POST
:param request: request
:return: response
"""
time_start = time.perf_counter()
if request.method != 'POST':
return redirect("/")
if 'address' not in request.POST:
return redirect("/")
addr = request.POST['address']
to_template = {}
try:
q = Building_Info.objects.get(sAddress=addr)
# Если QuerySet не содержит GeoCode (такое бывает, что в Яндекс-Картах не было каких-то данных),
# то пробуем получить GeoCode повторно (вдруг, у Яндекс-Карт расширилась база адресов)
if int(q.fGeoCode_Longitude) != 0 and int(q.fGeoCode_Latitude != 0):
# print("координаты не ноль")
to_template.update({'LATITUDE': str(q.fGeoCode_Latitude).replace(",", "."),
'LONGITUDE': str(q.fGeoCode_Longitude).replace(",", ".")})
geocode = [q.fGeoCode_Latitude, q.fGeoCode_Longitude]
else:
# print("координаты ноль")
geocode = get_yandex_geocode_by_address(addr)
# print("получен геокод", geocode)
to_template.update({'LATITUDE': str(geocode[0]).replace(",", "."),
'LONGITUDE': str(geocode[1]).replace(",", ".")})
except:
# print("тут")
geocode = get_yandex_geocode_by_address(addr)
# print(geocode)
to_template.update({'LATITUDE': str(geocode[0]).replace(",", ".")})
to_template.update({'LONGITUDE': str(geocode[1]).replace(",", ".")})
q = Building_Info.objects.raw(
f"SELECT oknardia_building_info.*, "
f"ABS({geocode[0]} - oknardia_building_info.fGeoCode_Latitude) + "
f"ABS({geocode[1]} - oknardia_building_info.fGeoCode_Longitude) AS R2 "
f"FROM oknardia_building_info "
f"ORDER BY R2 "
f"LIMIT 1;")[0]
if q.R2 > 0.67: # Если расстояние между точками больше 670 метров, то не показываем результат
to_template.update({'ticks': float(time.perf_counter()-time_start)})
to_template.update({'addr': addr})
return render(request, "popup/popup_incorrect_address.html", to_template)
addr = q.sAddress
# print("addr", addr)
to_template.update({'ADDRESS_ID': q.id,
'SERIA': q.sSerias_Project})
if q.fTotal_Area < 0:
to_template.update({'TOTAL_AREA': "Нет данных"})
else:
to_template.update({'TOTAL_AREA': f"{q.fTotal_Area: .1f}"})
to_template.update({'CADASTRE_NUM': q.sCadastre_Num_Area})
if q.fLand_Area < 0:
to_template.update({'LAND': "Нет данных"})
else:
to_template.update({'LAND': f"{q.fLand_Area: .1f}"})
to_template.update({'INVENTORY_NUM': q.sInventory_Num})
if q.iNum_Apartments < 0:
to_template.update({'NUM_APARTMENTS': "Нет данных"})
else:
to_template.update({'NUM_APARTMENTS': q.iNum_Apartments})
to_template.update({'TYPE_BUILDING': q.sType})
if q.iNum_Apartments < 0:
to_template.update({'STOREYS': "Нет данных"})
else:
to_template.update({'STOREYS': q.iStoreys})
if q.fCommon_Area < 0:
to_template.update({'COMMON_AREA': "Нет данных"})
else:
to_template.update({'COMMON_AREA': f"{q.fCommon_Area: .1f}"})
to_template.update({'ENERGY_EFFICIENCY': q.sEnergy_Efficiency})
if q.iEntrances_Porchs < 0:
to_template.update({'NUM_ENTERANCES': "Нет"})
else:
to_template.update({'NUM_ENTERANCES': q.iEntrances_Porchs})
if q.fUninhabited_Area < 0:
to_template.update({'UNINHABITED_AREA': "Нет данных"})
else:
to_template.update({'UNINHABITED_AREA': f"{q.fUninhabited_Area: .1f}"})
if q.sManagement_Co == u"N/A":
to_template.update({'MANAGEMENT_CO': "Нет данных"})
else:
to_template.update({'MANAGEMENT_CO': q.sManagement_Co})
if q.iElevators < 0:
to_template.update({'NUM_ELEVATORS': "Нет данных"})
else:
to_template.update({'NUM_ELEVATORS': q.iElevators})
if q.fResidential_Area < 0:
to_template.update({'RESIDENTIAL_AREA': "Нет данных"})
else:
to_template.update({'RESIDENTIAL_AREA': f"{q.fResidential_Area: .1f}"})
if q.iNum_Residents < 0:
to_template.update({'NUM_RESIDENTS': "Нет данных"})
else:
to_template.update({'NUM_RESIDENTS': q.iNum_Residents})
if q.fPrivate_Area < 0:
to_template.update({'PRIVATE_AREA': "Нет данных"})
else:
to_template.update({'PRIVATE_AREA': f"{q.fPrivate_Area:.1f}"})
if q.iNum_Accounts < 0:
to_template.update({'NUM_ACCOUNTS': "Нет данных"})
else:
to_template.update({'NUM_ACCOUNTS': q.iNum_Accounts})
if q.iCommissioning_year == "N/A":
to_template.update({'COMMISSIONING_YEAR': "Нет данных"})
else:
to_template.update({'COMMISSIONING_YEAR': q.iCommissioning_year})
if q.fGovernment_Area < 0:
to_template.update({'GOVERNMENT_AREA': "Нет данных"})
else:
to_template.update({'GOVERNMENT_AREA': f"{q.fGovernment_Area: .1f}"})
if q.fCondition_House < 0:
to_template.update({'CONDITION_HOUSE': "Нет данных"})
else:
to_template.update({'CONDITION_HOUSE': f"{q.fCondition_House: .0f}%"})
if q.fCondition_Foundation < 0:
to_template.update({'CONDITION_FOUNDATION': "Нет данных"})
else:
to_template.update({'CONDITION_FOUNDATION': f"{q.fCondition_Foundation: .0f}%"})
if q.fCondition_Walls < 0:
to_template.update({'CONDITION_WALL': u"Нет данных"})
else:
to_template.update({'CONDITION_WALL': f"{q.fCondition_Walls: .0f}%"})
if q.fCondition_Overlap < 0:
to_template.update({'CONDITION_OVERLAP': "Нет данных"})
else:
to_template.update({'CONDITION_OVERLAP': f"{q.fCondition_Overlap: .0f}%"})
if q.fMunicipal_Area < 0:
to_template.update({'MUNICIPAL_AREA': "Нет данных"})
else:
to_template.update({'MUNICIPAL_AREA': f"{q.fMunicipal_Area: .1f}"})
to_template.update({'URL2REFOEMAGKH': q.sURL})
# Пробуем получить базовую серию дома. Для этого рекурсивно раскручиваем записи в таблице Seria_Info
idd = q.kSeria_Link_id
all_apartment_in_seria = False
while idd is not None:
# рекурсивно движемся по дерву потомок→предок серий домов.
q1 = Seria_Info.objects.get(id=idd)
# получаем список типовых квартир для серии дома с id == idd
all_apartment_in_seria = Apartment_Type.objects.filter(kSeria_id=idd).order_by("iSort")
# проверяем есть-ли что-то в списке типовых квартир.
if bool(all_apartment_in_seria):
# список типовых квартир не нулевой
to_template.update({'LIST_APART': all_apartment_in_seria})
break
idd = q1.kParent_id
# проверяем, был ли получен список квартир
if not bool(all_apartment_in_seria):
# Если списка квартир нет, нужно получить список ближайших адресов, для которых есть цены.
q = Building_Info.objects.raw(
f"SELECT"
f" oknardia_building_info.sAddress, oknardia_building_info.id,"
f" oknardia_building_info.fGeoCode_Longitude, oknardia_building_info.fGeoCode_Latitude,"
f" oknardia_seria_info.kRoot_id, oknardia_seria_info.sName,"
f" COUNT(oknardia_apartment_type.sNameApartment) AS NumApart,"
f" ABS({geocode[0]} - oknardia_building_info.fGeoCode_Latitude)"
f" + ABS({geocode[1]} - oknardia_building_info.fGeoCode_Longitude) AS R2 "
f"FROM oknardia_building_info"
f" INNER JOIN oknardia_seria_info"
f" ON oknardia_building_info.kSeria_Link_id = oknardia_seria_info.id"
f" INNER JOIN oknardia_apartment_type"
f" ON oknardia_seria_info.kRoot_id = oknardia_apartment_type.kSeria_id "
f"WHERE oknardia_building_info.fGeoCode_Longitude <> 0.0"
f" AND oknardia_building_info.fGeoCode_Latitude <> 0.0 "
f"GROUP BY oknardia_seria_info.sName,"
f" oknardia_seria_info.kRoot_id,"
f" oknardia_building_info.id,"
f" oknardia_building_info.sAddress,"
f" oknardia_building_info.fGeoCode_Longitude,"
f" oknardia_building_info.fGeoCode_Latitude "
f"ORDER BY R2 "
f"LIMIT 5;")
q = list(q)
for i in q:
i.R2 = get_geo_distance(i.fGeoCode_Longitude, i.fGeoCode_Latitude, geocode[0], geocode[1])
# print i.id, i.sAddress, i.sName, i.R2
# сортируем список по R2 (дистанция от текущего адреса, до домов по которым данные известны)
sorted(q, key=lambda item: item.R2)
to_template.update({'NEAR_KNOWN_ADDRESS': q})
# print q
to_template.update({'SERIA_BASE': q1.sName,
'addr': addr,
'addr_T': pytils.translit.slugify(addr),
'ticks': float(time.perf_counter()-time_start)})
return render(request, "popup/popup_show_apartment_variants.html", to_template)
Generated
+433
View File
@@ -0,0 +1,433 @@
# This file is automatically @generated by Poetry 1.8.0 and should not be changed by hand.
[[package]]
name = "asgiref"
version = "3.11.1"
description = "ASGI specs, helper code, and adapters"
optional = false
python-versions = ">=3.9"
files = [
{file = "asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133"},
{file = "asgiref-3.11.1.tar.gz", hash = "sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce"},
]
[package.extras]
tests = ["mypy (>=1.14.0)", "pytest", "pytest-asyncio"]
[[package]]
name = "certifi"
version = "2026.2.25"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.7"
files = [
{file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"},
{file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"},
]
[[package]]
name = "charset-normalizer"
version = "3.4.7"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7"
files = [
{file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"},
{file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"},
{file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"},
{file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"},
{file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"},
{file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"},
{file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"},
{file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"},
{file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"},
{file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"},
{file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"},
{file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"},
{file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"},
{file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"},
{file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"},
{file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"},
{file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"},
{file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"},
{file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"},
{file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"},
{file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"},
{file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"},
{file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"},
{file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"},
{file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"},
{file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"},
{file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"},
{file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"},
{file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"},
{file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"},
{file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"},
{file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"},
{file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"},
{file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"},
{file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"},
{file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"},
{file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"},
{file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"},
{file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"},
{file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"},
{file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"},
{file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"},
{file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"},
{file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"},
]
[[package]]
name = "django"
version = "5.2.13"
description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
optional = false
python-versions = ">=3.10"
files = [
{file = "django-5.2.13-py3-none-any.whl", hash = "sha256:5788fce61da23788a8ce6f02583765ab060d396720924789f97fa42119d37f7a"},
{file = "django-5.2.13.tar.gz", hash = "sha256:a31589db5188d074c63f0945c3888fad104627dfcc236fb2b97f71f89da33bc4"},
]
[package.dependencies]
asgiref = ">=3.8.1"
sqlparse = ">=0.3.1"
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
argon2 = ["argon2-cffi (>=19.1.0)"]
bcrypt = ["bcrypt"]
[[package]]
name = "django-debug-toolbar"
version = "6.3.0"
description = "A configurable set of panels that display various debug information about the current request/response."
optional = false
python-versions = ">=3.10"
files = [
{file = "django_debug_toolbar-6.3.0-py3-none-any.whl", hash = "sha256:a199ce3d0f884739a9096835ad417479fede05f3b3c4824bc8b354721ba8f629"},
{file = "django_debug_toolbar-6.3.0.tar.gz", hash = "sha256:f830a86fe02e17f625a22cfbed24a5bd1500762e201ec959c50efb0f9327282b"},
]
[package.dependencies]
django = ">=4.2.9"
sqlparse = ">=0.2"
[[package]]
name = "django-environ"
version = "0.11.2"
description = "A package that allows you to utilize 12factor inspired environment variables to configure your Django application."
optional = false
python-versions = ">=3.6,<4"
files = [
{file = "django-environ-0.11.2.tar.gz", hash = "sha256:f32a87aa0899894c27d4e1776fa6b477e8164ed7f6b3e410a62a6d72caaf64be"},
{file = "django_environ-0.11.2-py2.py3-none-any.whl", hash = "sha256:0ff95ab4344bfeff693836aa978e6840abef2e2f1145adff7735892711590c05"},
]
[package.extras]
develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "pytest (>=4.6.11)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"]
testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"]
[[package]]
name = "idna"
version = "3.11"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.8"
files = [
{file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"},
{file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"},
]
[package.extras]
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
[[package]]
name = "pillow"
version = "11.3.0"
description = "Python Imaging Library (Fork)"
optional = false
python-versions = ">=3.9"
files = [
{file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
{file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"},
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"},
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"},
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"},
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"},
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"},
{file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"},
{file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"},
{file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"},
{file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"},
{file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"},
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"},
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"},
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"},
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"},
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"},
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"},
{file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"},
{file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"},
{file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"},
{file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"},
{file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"},
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"},
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"},
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"},
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"},
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"},
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"},
{file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"},
{file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"},
{file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"},
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"},
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"},
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"},
{file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"},
{file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"},
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"},
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"},
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"},
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"},
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"},
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"},
{file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"},
{file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"},
{file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"},
{file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"},
{file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"},
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"},
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"},
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"},
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"},
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"},
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"},
{file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"},
{file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"},
{file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"},
{file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"},
{file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"},
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"},
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"},
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"},
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"},
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"},
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"},
{file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"},
{file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"},
{file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"},
{file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"},
{file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"},
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"},
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"},
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"},
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"},
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"},
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"},
{file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"},
{file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"},
{file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"},
{file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"},
{file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"},
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"},
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"},
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"},
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"},
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"},
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"},
{file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"},
{file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"},
{file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"},
{file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"},
{file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"},
{file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"},
]
[package.extras]
docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
fpx = ["olefile"]
mic = ["olefile"]
test-arrow = ["pyarrow"]
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
typing = ["typing-extensions"]
xmp = ["defusedxml"]
[[package]]
name = "pytils"
version = "0.4.4"
description = "Russian-specific string utils"
optional = false
python-versions = "*"
files = [
{file = "pytils-0.4.4-py3-none-any.whl", hash = "sha256:e54c16465a5fdb65d414e2da8045e6cc6de79889acda6143dcef2e1e86a1a840"},
{file = "pytils-0.4.4.tar.gz", hash = "sha256:9992a96caad57daa211584df1da4fd825f11e836d3ed93011785f1d02ab6f0ca"},
]
[[package]]
name = "requests"
version = "2.33.1"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.10"
files = [
{file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"},
{file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"},
]
[package.dependencies]
certifi = ">=2023.5.7"
charset_normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.26,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"]
[[package]]
name = "sqlparse"
version = "0.5.5"
description = "A non-validating SQL parser."
optional = false
python-versions = ">=3.8"
files = [
{file = "sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba"},
{file = "sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"},
]
[package.extras]
dev = ["build"]
doc = ["sphinx"]
[[package]]
name = "tzdata"
version = "2026.1"
description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
files = [
{file = "tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9"},
{file = "tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98"},
]
[[package]]
name = "urllib3"
version = "2.6.3"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.9"
files = [
{file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"},
{file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"},
]
[package.extras]
brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["backports-zstd (>=1.0.0)"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.12,<3.13"
content-hash = "ccd7fbf755beccde5eef4e5edf52cb82b47341a485c3addf6c0245f5d3c4f66e"
+1
View File
@@ -0,0 +1 @@
e8819d2fd6d3
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<users>
<user>027F51EEB3278BF010983153FDB6F9A8</user>
</users>
+8
View File
@@ -0,0 +1,8 @@
АВТОРЫ
ДИЗАЙН: Сергей Еремин
КОД HTML: Сергей Еремин
КОД CSS: Сергей Еремин
КОД SVG: Сергей Еремин
КОД JavaScript: Сергей Еремин
ФОТОРГАФИИ:
ГРАФИКА:
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="120" viewBox="0 0 5.81 5.81" shape-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd"><path d="M2.25 4.2h-.02H0V1.69h2.25v.98h3.54V4.2z" fill="#393185"/><g fill="#fefefe" class="E"><path d="M1.45 3.55h.16l-.08-.3-.08.3zm.27.43l-.05-.21h-.28l-.06.21h-.26l.32-1.03h.33l.33 1.03h-.33z"/><path d="M1.07 2.95v1.03H.76v-.4H.52v.4H.2V2.95h.32v.38h.24v-.38zm.98 0H1.7l-.18-.39-.1.15v.24h-.3V1.92h.3v.43l.28-.43h.28l-.26.38z"/><path d="M.63 2.74c.06 0 .09-.02.12-.07.02-.04.03-.13.03-.25 0-.18-.05-.27-.14-.27-.11 0-.16.1-.16.31 0 .19.05.28.15.28zm0 .23c-.14 0-.26-.04-.35-.14-.09-.09-.14-.22-.14-.38a.58.58 0 0 1 .13-.38c.09-.1.21-.15.37-.15.14 0 .26.04.35.14.09.09.13.22.13.38s-.04.29-.14.39c-.09.1-.2.14-.35.14z"/></g><g fill="#d2cde7" class="E"><path d="M5.22 3.17H5.1c-.06 0-.1.01-.12.03-.01.02-.02.05-.02.07 0 .04.01.06.03.08.03.01.07.02.12.02h.11v-.2zm0 .42h-.14l-.17.39h-.29l.22-.43c-.14-.05-.21-.15-.21-.28 0-.1.03-.18.1-.24.07-.05.16-.08.27-.08h.54v1.03h-.32v-.39z"/><path d="M4.04 3.87v.11h-.3V2.95h.3v.42.19c.03-.08.07-.15.11-.22l.16-.28v-.11h.31v1.03h-.31v-.41c0-.05 0-.12.01-.19-.03.07-.07.14-.11.22l-.17.27z"/><path d="M3.04 3.76h.28L3.2 3.2h-.02l-.14.56zm-.25 0l.23-.8h.38l.23.8h.11v.44h-.2l-.02-.21H2.9l-.02.21h-.2v-.44h.11z"/><path d="M2.36 3.38h.11c.09 0 .13-.03.13-.1s-.04-.1-.12-.1h-.12v.2zm.01.22v.38h-.32V2.95h.43c.11 0 .2.01.25.04.06.02.1.06.14.11.03.05.05.11.05.18 0 .09-.04.17-.1.23a.41.41 0 0 1-.28.09h-.17z"/></g><path d="M3.09 1.9c0 .13-.05.2-.14.2a.11.11 0 0 1-.1-.05c-.03-.04-.04-.09-.04-.15 0-.13.05-.2.14-.2a.11.11 0 0 1 .1.05c.03.03.04.08.04.15zM3 1.9c0-.05 0-.09-.01-.11-.01-.01-.02-.02-.04-.02s-.03.01-.04.03c-.01.01-.01.05-.01.1s0 .08.01.1.02.03.04.03.03-.01.04-.03C3 1.99 3 1.95 3 1.9zm.25-.19h.09v.16l.09-.16h.09l-.1.14.1.24h-.08l-.07-.18-.03.05v.13h-.09v-.38zm.66.19c0 .13-.04.2-.14.2-.04 0-.08-.02-.1-.05-.02-.04-.04-.09-.04-.15 0-.13.05-.2.14-.2.05 0 .08.02.11.05.02.03.03.08.03.15zm-.09 0c0-.05 0-.09-.01-.11-.01-.01-.02-.02-.04-.02-.01 0-.03.01-.03.03-.01.01-.02.05-.02.1s.01.08.01.1c.01.02.03.03.04.03.02 0 .03-.01.04-.03.01-.01.01-.05.01-.1zm.26-.19h.08v.15h.09v-.15h.09v.38h-.09v-.16h-.09v.16h-.08v-.38zm.43 0h.09v.15h.09v-.15h.08v.38h-.08v-.16H4.6v.16h-.09v-.38zm.44.38v-.38h.08v.14h.03c.06 0 .09.01.11.03.03.02.04.05.04.09 0 .03-.01.06-.03.08-.01.02-.02.03-.04.03-.02.01-.05.01-.08.01h-.11zm.08-.06h.03c.01 0 .02 0 .03-.01.01 0 .01 0 .02-.01 0-.01.01-.02.01-.04s-.01-.03-.01-.04c-.01-.01-.03-.02-.05-.02h-.03v.12zm.22-.32h.08v.38h-.08v-.38zm.34.34v.04h-.08v-.38h.08v.21l.01-.02.09-.15v-.04h.08v.38h-.08v-.2-.01l-.01.02-.09.15zm-.04-.45h.05c0 .02.02.03.04.03.03 0 .04-.01.05-.03h.05c-.02.05-.05.07-.1.07-.04 0-.08-.02-.09-.07zm-3 .58h.09l.11.39h-.09l-.02-.08h-.11l-.02.08h-.07l.11-.39zm.07.24l-.03-.16-.04.16h.07zm.5-.24v.07h-.15v.32h-.09v-.39h.24zm.14 0h.11c.03 0 .06 0 .07.01.02.01.04.02.05.04s.02.04.02.07-.01.05-.02.07-.02.03-.04.04-.04.01-.08.01h-.03v.15h-.08v-.39zm.08.06v.12h.03c.02 0 .03-.01.04-.02s.01-.02.01-.04c0-.01 0-.03-.01-.03 0-.01-.01-.02-.01-.02-.01 0-.02-.01-.03-.01h-.03zm.31-.06h.24v.07h-.15v.09h.11v.06h-.11v.1h.15v.07h-.24v-.39zm.62 0v.07h-.15v.32h-.09v-.39h.24zm.2 0h.09l.11.39h-.09l-.02-.08h-.11l-.01.08h-.08l.11-.39zm.08.24l-.04-.16-.04.16h.08zm.2-.24h.24v.07h-.08v.32h-.09v-.32h-.07v-.07zm.64.19c0 .14-.05.2-.14.2-.05 0-.08-.01-.1-.05-.03-.03-.04-.08-.04-.15 0-.13.05-.19.14-.19.04 0 .08.01.1.05.03.03.04.08.04.14zm-.09 0c0-.05 0-.08-.01-.1s-.02-.03-.04-.03-.03.01-.04.03-.01.05-.01.1 0 .09.01.11c.01.01.02.02.04.02s.03 0 .04-.02.01-.05.01-.11zm.25-.19h.11c.04 0 .06 0 .08.01s.03.02.05.04c.01.02.02.04.02.07s-.01.05-.02.07-.02.03-.04.04-.05.01-.08.01h-.03v.15h-.09v-.39zm.09.06v.12h.02c.03 0 .04-.01.05-.02 0-.01.01-.02.01-.04 0-.01-.01-.03-.01-.03-.01-.01-.01-.02-.02-.02s-.02-.01-.03-.01h-.02z" fill="#7e71b1" class="E"/></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

+1
View File
@@ -0,0 +1 @@
google-site-verification: googleacb673eb0c31969f.html
+1
View File
@@ -0,0 +1 @@
google-site-verification: googleea5d443319529114.html
+1
View File
@@ -0,0 +1 @@
mailru-domain: T2hJTKvdCl8xIbEm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Some files were not shown because too many files have changed in this diff Show More