Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 19a595fb10 | |||
| 917d62cc21 | |||
| 71b5089a61 | |||
| 9e27089638 | |||
| af67b69418 | |||
| af2489f923 | |||
| 0b6536b8f4 | |||
| c930e059a0 | |||
| c0b41cd866 | |||
| b348c8fe81 | |||
| e7da2cdeb9 | |||
| d5719015b0 | |||
| bcc10de4d4 | |||
| 55f9a74231 | |||
| 49c19d9f92 | |||
| 67a8c093f5 | |||
| e0a5a5739b | |||
| 3e67d6cf71 | |||
| 917bcb42c8 | |||
| 5bdb97f5e8 | |||
| e2091b72b1 | |||
| 446cbe8c5c | |||
| bdca8dfc6a | |||
| 111dd7bd33 | |||
| 57a522f4b7 | |||
| 2b37f709a9 | |||
| f480dc3666 | |||
| 2da036e4e0 | |||
| 28620ce2a9 | |||
| 574ae84321 | |||
| 796cb89525 | |||
| 0e8839bf18 | |||
| dbd622e456 | |||
| 741dd2685e | |||
| c01873144e | |||
| 8387d36abf | |||
| 2bc0869104 | |||
| 8c7972178c | |||
| c338a17dd8 | |||
| 3cc4ae39f7 | |||
| d789b2443a | |||
| 25beecdf60 | |||
| 5eb2f304a3 | |||
| 0246c1de8c | |||
| 4196cd64d8 | |||
| 60b6582f1b | |||
| 4a91928bc7 | |||
| b322331366 | |||
| e041110059 | |||
| ae1b851db7 | |||
| 28aa35d617 | |||
| b296ad79e9 | |||
| fbea58b1c4 | |||
| 30084dd6ac | |||
| c961b64036 | |||
| ad74f0a51e | |||
| 78ec6077b6 | |||
| c68fa5be07 | |||
| ee1dd31d54 | |||
| 6066e5df29 | |||
| 8704f4125b | |||
| 2777f3fde2 | |||
| 4b9ca319f9 | |||
| 56d7af5c9d | |||
| 0368c1c34e | |||
| fbdf95b66f | |||
| 8fdaf6935e | |||
| 8272bdb25f | |||
| 6a4c315cdc | |||
| f2c89abe1c | |||
| 37a605ef09 | |||
| 28a680fdf1 | |||
| 9bcbc73602 | |||
| 8ca1f5b36e | |||
| 6c4dcd1cb7 | |||
| 5a38181cd3 | |||
| 5738ee9c9e | |||
| 9535424e6a | |||
| 4e03fead67 | |||
| 5de28c8bfb | |||
| de45931ff4 | |||
| d27d0e7173 | |||
| f3a8a65afe | |||
| 72b71c7810 | |||
| 6bd8143d83 | |||
| a970b7109b | |||
| 99b8ba80d5 | |||
| 7cc438d1c5 | |||
| 034ec20c26 | |||
| 90ddc0d88c | |||
| 6e92eca67a | |||
| 6a9c0e4568 | |||
| 265732bae8 | |||
| cded4e407e | |||
| f996dd891e | |||
| 748a1882e5 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
```
|
||||
@@ -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
|
||||
##}
|
||||
|
||||
@@ -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 ----------------
|
||||
@@ -0,0 +1,3 @@
|
||||
# Это папака для хранения базы данных SQLite, не должна быть в репозитории.
|
||||
*.*
|
||||
*
|
||||
@@ -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='Глухое')),
|
||||
|
||||
@@ -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='')
|
||||
|
||||
@@ -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)
|
||||
|
||||
# ___ ____ _ _____ _ _ _____ _
|
||||
# | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| |
|
||||
# |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| |
|
||||
# |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_|
|
||||
# |___|
|
||||
|
||||
@@ -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 %}
|
||||
{# ######################################## Нижнее меню-футер КОНЕЦ ######################################## #}
|
||||
|
||||
@@ -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>Производители и поставщики окон</li>
|
||||
</ol>
|
||||
<h1>Производители и поставщики окон</h1>
|
||||
</div>
|
||||
</div>{# <!--- Хлебные крошки: КОНЕЦ ---> #}
|
||||
<dIv class="row">
|
||||
<div class="col-md-11 col-xs-12">
|
||||
<p>Компании-партнёры «Окнардии», их средний рейтинг, число оконных наборов и вариантов расчёта цен для типовых проёмов, средняя цена окна:</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">Подробнее…</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 %}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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>часы работы:</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> — Офис предоставивший расчеты для оконного агрегатора «Окнардия».</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>Оконный набор: «{{ i.sSetName|safe }}»</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 != "—"%} Число камер рамы и створки — {{ 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> Цвет уплотнителя контуров и стеклопакета {{ i.sProfileSealDescription }}. Используется фурнитура {{ i.sSetImplementAll }}{% if i.sSetImplementHandles != "" %}, ручки {{ i.sSetImplementHandles }}{% endif %}{% if i.sSetImplementCatch != "" %}, фиксатор открывания {{ i.sSetImplementCatch }}{% endif %}. {% if i.sSetClimateControl != "" %} Каждое окно оборудовано системой климат-контроля — {{ 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 %}Подоконники, внешние водоотливы и внутренние откосы не включены в набор. Производитель «{{ COMPANY }}» предполагает, что закзчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetSill|lower in LIST_NOT and i.sSetPanes|lower in LIST_NOT %}Подоконники и внешние водоотливы не включены в набор. Производитель «{{ COMPANY }}» предполагает, что закзчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetSill|lower in LIST_NOT and i.sSetSlope|lower in LIST_NOT %}Внешние водоотливы и внутренние откосы не включены в набор. Производитель «{{ COMPANY }}» предполагает, что закзчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetPanes|lower in LIST_NOT and i.sSetSlope|lower in LIST_NOT %}Подоконники и внутренние откосы не включены в набор. Производитель «{{ COMPANY }}» предполагает, что закзчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetPanes|lower in LIST_NOT %}Внешние оконные водоотливы не включены в набор. Производитель «{{ COMPANY }}» предполагает, что заказчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetSlope|lower in LIST_NOT %}Внутренние откосы и их отделка не включены в набор. Производитель «{{ COMPANY }}» предполагает, что заказчик этого набора закупит их отдельно у него или других поставщиков.{% elif i.sSetSill|lower in LIST_NOT %}Оконные подоконники не включены в набор. Производитель «{{ COMPANY }}» предполагает, что заказчик этого набора закупит их отдельно у него или других поставщиков.{% endif %}</P>
|
||||
<P>{% if i.bSetUninstallInstall %}Установка новых и демонтаж старых оконных конструкций {{ i.sSetUninstallInstall|safe }}. {% endif %}{% if i.bSetDelivery %}Доставка {{ i.sSetDelivery|safe }}. {% endif %}{% if not i.bSetDelivery and not i.bSetUninstallInstall %}В стоимость набора не входит демонтаж и установка. Эти услуги оплачиваются отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}Примерно {{ i.sSetUninstallInstall|safe }}, или заказчик может провести все работы самостоятельно. {% endif %}Доставка тоже не входит в стоимость, осуществляется заказчиком самостоятельно или оплачивается отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}{{ i.sSetDelivery|safe|capfirst }}. {% endif %}{% elif not i.bSetDelivery %}Доставка не входит в стоимость, осуществляется заказчиком самостоятельно или оплачивается отдельно. {% if i.sSetUninstallInstall not in LIST_NOT %}{{ i.sSetDelivery|safe|capfirst }}. {% endif %}{% elif not i.bSetUninstallInstall %}В стоимость набора не входит демонтаж и установка. Эти услуги оплачиваются отдельно.{% if i.sSetUninstallInstall not in LIST_NOT %} Примерно {{ i.sSetUninstallInstall|safe }}. Или заказчик может провести все работы самостоятельно.{% endif %}{% endif %}</P>{% if i.sSetOtherConditions not in LIST_NOT %}
|
||||
<P>Прочие условия — {{ i.sSetOtherConditions|safe }}</P>{% endif %}
|
||||
{# Скидки -- {{ i.sOfficeDiscountMetaFormula }}<br>#}
|
||||
|
||||
<p style='background-color:#f0f0f0;color:silver;padding:5ex 10ex;'>Извините, графики ценового распределения для оконного набора «{{ i.sSetName|safe }}» компании «{{ i.sMerchantName }}» подготавливаются.<br /> <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>Узнать о производителях, познакомиться с детальными характеристики и описаниями оконных профилей можно кликнув по ссылкам. Сейчас в каталоге «Окнардии» представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в базе). Последнее обновление {{ CATALOG_LAST_UPDATE_W }}.</p>
|
||||
<p>Узнать о производителях, познакомиться с детальными характеристики и описаниями оконных профилей можно кликнув по ссылкам. Сейчас в каталоге «Окнардии» представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в базе).</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 %}
|
||||
|
||||
@@ -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>Стандартные оконные проёмы и балконные блоки</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">×</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>×</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 %}
|
||||
|
||||
|
||||
@@ -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" %}
|
||||
|
||||
@@ -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 />
|
||||
Если вы ошиблись при указании адреса <a href="/">попробуйте ввести адрес ещё раз</a> или
|
||||
<a href="/stat_all/#s_map">найдите его на карте типовых серий</a> жилого строительства.<br> </li>
|
||||
<li><b>Адрес <i>«{{ addr }}»</i> отсутствует в нашей базе.</b><br />
|
||||
Приносим извинения, но пока нами обработаны только типовые серии Москвы и Подмосковья, Санкт-Петербурга
|
||||
и Ленинградской области.<br />
|
||||
Свяжитесь с нами чтобы мы ускорили оцифровку и поиск партнеров в вашем регионе.</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>Узнайте стоимость установки окон в квартиру от разных поставщиков<!-- ({{ 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">Введите адрес дома (или выберите адрес из подсказки),</li>
|
||||
<li class="show_delayed">укажите тип планировки квартиры</li>
|
||||
<li class="show_delayed">и получите актуальные цены, сравнивайте характеристики предложений и условия установки.</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">×</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>К сожалению база «Окнардии» только формируется. Пока у нас нет данных по типовым квартирам для дома по этому адресу. Ближащие адреса, по которым есть информация:</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 }} км.</nobr> <a href="#" onclick="uClick({{ forloop.counter0 }})" id="a{{ forloop.counter0 }}">{{ i.sAddress }}</a>
|
||||
</li>
|
||||
{% endfor %}</ul>
|
||||
<p>С небольшой погрешностью (±6%) мы можем дать ценовые предложения под ваши требования, но потребуется самостоятельный замер проёмов.</p>
|
||||
<button type="button" class="btn btn-default" style="margin:1ex"
|
||||
accesskey="1" onclick="window.location.href='/order_by_dim'">
|
||||
Подобрать предложения по предварительным замерам <span class="glyphicon glyphicon-search"></span>
|
||||
</button>
|
||||
<p style="font-size:xx-small;width:80%"><small>Сделав замер, и сообщив его нам, вы поможете наполнению базы «Окнардии», вашим соседям и сотням людей проживающих в домах таких же серий или проектов. В благодарность за содействие мы подготовим и вышлем самые актуальные предложения по email, а также предоставим купон, предоставляющий скидку на сумму <b>500 рублей</b> при установке окон любым из наших партнёров. Если согласны <a href="/send_order_and_info">перейдите по ссылке</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" %}
|
||||
@@ -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 %} и {% else %}, {% endif %}{% endif %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. — {{ I_WIN_DIM.iQuantity }} шт.{% 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>Другие типовые квартиры в этом доме:</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">Таблица содержит цены поставщиков. Клик на название отобразит детальные спецификации каждого предложения: марку профиля рамы и створки, схему стеклопакета, тип фурнитуры, элементы отделки (отлив, подоконник, откос, клапан <nobr>климат-контроля</nobr>) и сопутствующие услуги. Предложения выводятся покадрово, получите следующий кадр кнопкой «Ещё коммерческие предложения окон» под таблицей. Просмотреть и сравнить технические характеристик стеклопакетов, профилей и детальное описание сопутствующих услуг возможно с помощью кнопки «Сравнить выбранные».</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 %}
|
||||
|
||||
@@ -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>)
|
||||
■ {{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
|
||||
■ Тонирование: {{ CurOffer.GLAZING_TONING }}
|
||||
{% if CurOffer.PVC_SEAL %}■ Уплотнитель: {{ CurOffer.PVC_SEAL }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT %}■ Фурнитура: {{ CurOffer.SETS_IMPLEMENT|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_R %}■ Ручки: {{ CurOffer.SETS_IMPLEMENT_R|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_P %}■ Петли: {{ CurOffer.SETS_IMPLEMENT_P|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_Z %}■ Запоры: {{ CurOffer.SETS_IMPLEMENT_Z|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_O %}■ Ограничители: {{ CurOffer.SETS_IMPLEMENT_O|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_F %}■ Фиксаторы: {{ 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 %}>■ Климат-контроль: {{ 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 %}>■ Подоконник: {{ 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 %}>■ Откос: {{ 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 %}>■ Водоотлив: {{ 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 %}>■ Демонтаж/монтаж: {{ 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 %}>■ Доставка: {{ CurOffer.SETS_DELIVERY|capfirst|safe }}</span>{% endif %}{% comment %} {% if CurOffer.SETS_OTHER %}■ Прочие условия: {{ 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 }} км.</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 }}» состоит из:{% else %}Рейтинг не присвоен{% endif %}"
|
||||
data-toggle="popover">рейтинг</a>: {% 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 %}−{{ 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 }} <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"> </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();">Ещё коммерческие предложения окон <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>
|
||||
@@ -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 }}×{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %} мм. </li>
|
||||
</ol>
|
||||
<h1>Стандартные оконные проёмы и балконные блоки</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 }}×{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %} мм. <small>(типовое)</small></h1>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<p>Типовой проём {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:1 }}×{{ I_WIN_DIM.iWinHight|floatformat:1 }}{% endfor %} 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">В таблице представлены только цены поставщиков из базы «Окнардия». Клик на названии набора отобразит детальную спецификацию каждого предложения: профиль рамы и створки, схему стеклопакета, фурнитуру, элементы отлива, подоконника, откоса, системы <nobr>климат-контроля</nobr>) и сопутствующие услуги. Предложения выводятся блоками. Очередной блок выводится кнопкой «Ещё коммерческие предложения окон» под таблицей. Детальные технические характеристики стеклопакетов, профилей и описание сопутствующих услуг можно посмотреть и сравнить с помощью кнопки «Сравнить выбранные».</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;">Стоимость, <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>)
|
||||
■ {{ CurOffer.GLAZING_NAME_B|safe }} <nobr>({{ CurOffer.GLAZING_MARK }})</nobr>
|
||||
■ Тонирование: {{ CurOffer.GLAZING_TONING }}
|
||||
{% if CurOffer.PVC_SEAL %}■ Уплотнитель: {{ CurOffer.PVC_SEAL }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT %}■ Фурнитура: {{ CurOffer.SETS_IMPLEMENT|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_R %}■ Ручки: {{ CurOffer.SETS_IMPLEMENT_R|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_P %}■ Петли: {{ CurOffer.SETS_IMPLEMENT_P|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_Z %}■ Запоры: {{ CurOffer.SETS_IMPLEMENT_Z|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_O %}■ Ограничители: {{ CurOffer.SETS_IMPLEMENT_O|capfirst|safe }}
|
||||
{% endif %}{% if CurOffer.SETS_IMPLEMENT_F %}■ Фиксаторы: {{ 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 %}>■ Климат-контроль: {{ 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 %}>■ Подоконник: {{ 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 %}>■ Откос: {{ 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 %}>■ Водоотлив: {{ 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 %}>■ Демонтаж/монтаж: {{ 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 %}>■ Доставка: {{ CurOffer.SETS_DELIVERY|capfirst|safe }}</span>{% endif %}{% comment %} {% if CurOffer.SETS_OTHER %}■ Прочие условия: {{ 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 }}» состоит из:{% else %}Рейтинг не присвоен{% endif %}"
|
||||
data-toggle="popover">рейтинг</a>: {% 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 %}−{{ 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 }} <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"> </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();">Ещё коммерческие предложения окон <small class="glyphicon-refresh glyphicon"></small></a>{% endif %}</td>
|
||||
</tR>
|
||||
@@ -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> </td>
|
||||
<td>Площадь участка, м²:</td>
|
||||
<td><nobr>{{ LAND|capfirst|default:"Нет данных"|price_format }}</nobr></td>
|
||||
<td> </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>
|
||||
@@ -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 %} и {% else %}, {% endif %}{% endif %}{{ Count.SET_NAME }}{% if forloop.last %}.{% endif %}{% endfor %}</h1>
|
||||
<p>Оконный набор — это комплект оконного профиля (рамы и сворки), стеклопакета, фурнитуры и уплотнителей — готовое окно в сборе для установки в проём. В набор может входить отлив, подоконник, откос, встраиваемые системы <nobr>климат-контроля</nobr>, оконная фурнитура открывания, запоры, уплотнители, москитная сетка… а также сопутствующие услуги: демонтаж старых и установка новых окон, доставка, гарантийное обслуживание, уборка, вынос и утилизация строительного мусора, защитное укрытие мебели на время монтажа и другое.</p>
|
||||
<h4>В таблицу сравнения услуг и условий, входящих в оконные наборы, добавлены следующие производители и поставщики:</h4>
|
||||
<ul>{% for MERCANT in LIST_MERCHANT %}
|
||||
<li>{{ MERCANT }}.</li>{% endfor %}
|
||||
</ul>
|
||||
<h4>В средней части таблице вы сможете сравнить характеристики оконных профилей в наборах:</h4>
|
||||
<ul>{% for PROFILE in LIST_PROFILE %}
|
||||
<li>{{ PROFILE }}.</li>{% endfor %}
|
||||
</ul>
|
||||
<h4>Нижний блок таблицы посвящен характеристикам и сравнению стеклопакетов в наборах. Формулы выбранных стеклопакетов:</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 }}/">в каталоге</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 }}» состоит из:{% 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 == "—/—" %}— / —{% 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 == "—/—" %}— / —{% 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>Помочь разобраться в комплектациях, условиях поставки, характеристиках оконных профилей и стеклопакетов поможет цвет фона ячеек таблицы. <span style="background:#83ff83;">Зеленый цвет</span> — лучшие значения, чем насыщение цвет, тем более высокие потребительская характеристика у того или иного параметра. <span style="background:#ff7f7f;">Красный цвет</span> — отсутствие отдельных элементов или услуг комплексного предложения.</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 %}
|
||||
|
||||
@@ -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;">Оконный профиль:</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;">От пользователей:</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 }}: ввод в эксплуатацию по годам</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 }} на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</small></p>
|
||||
@@ -94,22 +90,23 @@
|
||||
|
||||
<diV class="col-md-4">
|
||||
<h3 class="header">Статистика <nobr>серии {{ THIS_SERIA_NAME }}</nobr></h3>
|
||||
<p>Совокупно во всех зданиях типового проекта:</p>
|
||||
<p>Совокупно во всех зданиях типового проекта:</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> — муниципальное жильё.</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>
|
||||
</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>Информация о других, отличных от {{ THIS_SERIA_NAME }}, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</h5>
|
||||
<h5>Информация о других, отличных от {{ THIS_SERIA_NAME }}, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -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>Типовые серии домов в базе «Окнардия»</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">Распределение типовых серий в жилом фонде<sup><small style="color: darkred;">*</small></sup></h2>
|
||||
</div>
|
||||
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии ПД-4 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>16 024</strong> квартир.</li>
|
||||
<li>Проживает <strong>14 641</strong> семей <small>(<strong>69 926</strong> человек)</small>.</li>
|
||||
<li><strong>825 653.9 м²</strong> жилых помещений.</li>
|
||||
<li><strong>22 532.1 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>28 434.2 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии ПД-4 — <strong>30.00 %</strong>. Минимальный — <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>Информация о других, отличных от ПД-4, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии К-7 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>19 354</strong> квартир.</li>
|
||||
<li>Проживает <strong>16 839</strong> семей <small>(<strong>82 948</strong> человек)</small>.</li>
|
||||
<li><strong>539 518.2 м²</strong> жилых помещений.</li>
|
||||
<li><strong>93 304.8 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>27 709.9 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии К-7 — <strong>69.00 %</strong>. Минимальный — <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>Информация о других, отличных от К-7, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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–335 проектировалась Ленинградским Отделением Горстройпроекта (архитекторы Баныкин Б. Н., Артемьева И. Б. и Смирнова Л. А.) и стала одним из первых зданий «полукаркасной» схемы (неполный каркас и навесные панели). Возводилась по всей территории СССР с 1956 года. Последние здания серии сданы в эксплуатацию в 1968 году.</p>
|
||||
<p>Проект 1–335 так и не получил дальнейшей модернизации, <nobr>из-за</nobr> ряда недостатков. Так, профильные навесные бетонные панели толщиной 30 см. приводили к теплопотерям, и замена на керамзитбетонные (40 см.) для регионов с суровым климатом не спасало. Внешняя облицовка утепляющими материалами увеличивала стоимость и эксплуатационные расходы, потому 1–335 возводились только в Ленинграде, где климат мягче.</p>
|
||||
<p>Внешний вид 1–335 не сильно отличается от других панельных зданий того периода. Серию можно узнать по боковому фасаду: без балконов, две панели без окон в центре или по краям. Как и у многих «хрущёвок», серия 1–335 с железной четырёхскатной крышей (поздние модификации строились с плоской крышей без чердаков), секции без лифта (по четыре квартиры: 1-, 2- и <nobr>3-комнатные</nobr>), потолки 255 см., санузер совмещенный.</p>
|
||||
<p>Оконные проемы серии 1–335 на 10–15 см шире чем у других «хрущёвок», но максимум пять этажей подразумевают низкие ветровые нагрузки. Это означает, что при замене окон использование усиленных профилей не обязательно. Кроме того, нецелесообразно использование стеклопакетов с заполнением инертным газом и высоким сопротивлением теплопередаче — утечки тепла через панели сведут на нет их преимущество. Благодаря хорошей вытяжной вентиляции здания можно сэкономить на встраиваемых в окна клапанах <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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии 1-335 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>19 742</strong> квартир.</li>
|
||||
<li>Проживает <strong>20 521</strong> семей <small>(<strong>98 798</strong> человек)</small>.</li>
|
||||
<li><strong>904 827.7 м²</strong> жилых помещений.</li>
|
||||
<li><strong>6 470.2 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>31 829.0 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии 1-335 — <strong>70.00 %</strong>. Минимальный — <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>Информация о других, отличных от 1-335, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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> проектировался в конце 1970-х как шумозащитный. Размещение домов предполагалось вдоль больших автомагистралей или на границе промышленных зон. Возведением серии занимались в основном ДСК-4 и АО «Моспромстроиматериалов». Повышенная шумоизоляция достигалась благодаря использованию специальных трёхслойных керамзитбетонных панелей и оригинальной планировкой, благодаря которой на неблагоприятную сторону выходили главным образом нежилые помещения. Кроме того, внешний фасад имел минимальное число балконов, таким образом уменьшая проникновение пыли в жилые комнаты.</p>
|
||||
<p>Внешний фасад серии П-55 и П-55М выстраивался уступами, что значительной степени отражало шум. Сверх того, дома серии часто строили в виде Г- и П-образных конструкций и снабжали арками, что повышало защиту дворов. Но даже рядные — обычно двух- и трехсекционные блок-дома — в силу большой высотности<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>10−14 этажей) являлись достаточным препятствием для проникновения шума и пыли в дворы, в стороны которых выходили окна жилых комнат и большое число балконов.</p>
|
||||
<p>Являясь поздними<span style="margin-right:0.44em;"> </span><span style="margin-left:-0.44em;">«</span>брежневскими» серией панельного строительства, в П-55 значительное внимание уделялось удобству: в подъездах расположено по два пассажирских лифта, большинство квартир с несколькими балконами, много трёх- и четырёхкомнатных квартир. Кроме того, проект П-55 отличает более высокие чем у предыдущих серий <nobr>потолки<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>2 м 65 см)</nobr> и увеличенные размеры ванной и туалетной комнаты. Улучшенная серия П-55М ещё более комфортна: вторые санузлы в трёх- и четырёхкомнатных квартирах; входной блок подъезда и лифт адаптирован для инвалидов-колясочников.</p>
|
||||
<strong><p>В силу расположенности зданий серий П-55 вдоль шумных магистралей и промышленных зон, замена окон в них предполагает установку более качественных, дорогих, но и более защищённых конструкций<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>особенно для внешнего фасада). В первую очередь следует отдавать предпочтение предложениям с повышенной шумоизоляцией:</p>
|
||||
<ul><li>двухкамерные стеклопакеты высокой звукоизоляции<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>32 дБ и более) с несимметричными камерами или заполненные инертным газом;</li>
|
||||
<li>пятикамерные<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>и выше) профили с шумовой защитой на ниже 3-го класса<span style="margin-right:0.3em;"> </span><span style="margin-left:-0.3em;">(</span>коэффициент звукоизоляции от 35 дБ)</li>
|
||||
<li>три и более контура уплотнения.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии П-55 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>26 772</strong> квартир.</li>
|
||||
<li>Проживает <strong>31 072</strong> семей <small>(<strong>171 092</strong> человек)</small>.</li>
|
||||
<li><strong>1 724 085.9 м²</strong> жилых помещений.</li>
|
||||
<li><strong>232 384.8 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>70 828.3 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии П-55 — <strong>60.80 %</strong>. Минимальный — <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>Информация о других, отличных от П-55, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии 1Р-303 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>7 899</strong> квартир.</li>
|
||||
<li>Проживает <strong>9 247</strong> семей <small>(<strong>45 176</strong> человек)</small>.</li>
|
||||
<li><strong>345 222.8 м²</strong> жилых помещений.</li>
|
||||
<li><strong>64 146.2 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>0.0 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии 1Р-303 — <strong>60.00 %</strong>. Минимальный — <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>Информация о других, отличных от 1Р-303, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии МГ-601 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>13 011</strong> квартир.</li>
|
||||
<li>Проживает <strong>13 342</strong> семей <small>(<strong>57 998</strong> человек)</small>.</li>
|
||||
<li><strong>654 281.7 м²</strong> жилых помещений.</li>
|
||||
<li><strong>89 075.3 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>22 511.2 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии МГ-601 — <strong>42.00 %</strong>. Минимальный — <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>Информация о других, отличных от МГ-601, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии ГМС-2001 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>12 585</strong> квартир.</li>
|
||||
<li>Проживает <strong>18 198</strong> семей <small>(<strong>64 618</strong> человек)</small>.</li>
|
||||
<li><strong>862 529.2 м²</strong> жилых помещений.</li>
|
||||
<li><strong>188 963.6 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>28 750.5 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии ГМС-2001 — <strong>8.10 %</strong>. Минимальный — <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>Информация о других, отличных от ГМС-2001, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии II-66 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>4 295</strong> квартир.</li>
|
||||
<li>Проживает <strong>5 432</strong> семей <small>(<strong>28 954</strong> человек)</small>.</li>
|
||||
<li><strong>239 948.6 м²</strong> жилых помещений.</li>
|
||||
<li><strong>19 670.9 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>0.0 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии II-66 — <strong>40.00 %</strong>. Минимальный — <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>Информация о других, отличных от II-66, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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 мм.</nobr><br />
|
||||
<nobr><b>1 шт.</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');"> </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> {{ 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> {{ 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: ввод в эксплуатацию по годам</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>Для отображения гистограммы ввода в эксплуатацию зданий серии 1-515/9 нужна поддержка SVG.</p>
|
||||
<noscript>
|
||||
<p>Для визуализации отображения картографической информации с помощью 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 на карте</h2>
|
||||
</div>
|
||||
<div class="col-md-7 col-lg-offset-1">
|
||||
<p><small>Чтобы посмотреть цены на установку и замену окон от партнёров «Окнардия» в своей квартире: найдите дом на карте; кликните на него; перейдите по ссылке «Смотреть коммерческие предложения». При необходимости смените типовую планировку квартиры (на странице ценовой выдачи, справа от изображения типовых проёмов и схем открывания).</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 с помощью «Яндекс.Карт» нужно включить поддержку 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>Совокупно во всех зданиях типового проекта:</p>
|
||||
<ul>
|
||||
<li><strong>9 781</strong> квартир.</li>
|
||||
<li>Проживает <strong>18 646</strong> семей <small>(<strong>85 972</strong> человек)</small>.</li>
|
||||
<li><strong>760 689.2 м²</strong> жилых помещений.</li>
|
||||
<li><strong>68 401.4 м²</strong> — муниципальное жильё.</li>
|
||||
<li><strong>43 667.6 м²</strong> занимают государственные и городские службы, учреждения бытового обслуживания, магазины, офисы и тому подобное.</li>
|
||||
<li>Максимальный износ жилого фонда серии 1-515/9 — <strong>46.00 %</strong>. Минимальный — <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>Информация о других, отличных от 1-515/9, типовых сериях в базе «Окнардия», типовых планировках квартир и оконных проёмах в них, а также рекомендации по замене окон:</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 />по типовым сериям домов<br />в базе «Окнардия»</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&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,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>
|
||||
@@ -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> <br> <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&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>
|
||||
@@ -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> в базе «Окнардии»</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>Против некоторых позиций в тарифах «Окнардии» давно стояла метка «с 11.2017». Она появилась почти два года назад, вместе с тарифами нашего оконного агрегатора когда закончилось <nobr>бета-тестирование</nobr>. И вот этот 11.2017 наступил. А значит цены на размещение цен на размещение оконных предложений меняются. Как и было обещано.</p>
|
||||
<p><center><img src="/media/img_for_blog/tariff-changing.gif" /></center></p>
|
||||
<p>Но перед тем, как рассказать детали напомним, что было сделано за эти два года</p><cut />
|
||||
<ul>
|
||||
<li>Размещено 22 оконных набора в предложениях. Размещаются как пластиковые, так и деревянные окна.</li>
|
||||
<li>С «Окнардией» работают уже семь <nobr>оконных-компании</nobr> партнёра.</li>
|
||||
<li>— Добавлен функционал сравнения характеристик оконных предложений и отдельных компонентов этих предложений.</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>. В будущем будет каталог стеклопакетов и фурнитуры… планов много.</li>
|
||||
<li>Построен <a href="/blogpost/17/Nagljadnoe-sravnenie-harakteristik-okonnyh-profilej/">алгоритм расчёта реальных рейтингов</a> предложений, профилей, стеклопакетов и сервиса компаний. Рейтинги не на базе «общественного голосования», «опросов» или измерением <nobr>«интернет-популярности»</nobr>, а на базе физических характеристик и измеримых параметров. Таким образом — это объектовые рейтинги.</li>
|
||||
<li>Разработан <a href="https://widget.oknardia.ru/">виджет</a>, который позволяет оконной компании реализовать функционал «Окнардии» на собственном сайте.</li>
|
||||
<li>Расширены <nobr><a href="/blogpost/16/Novye-media-vozmozhnosti-uchastnikam-Oknardii-/">медиа-возможности</a></nobr> проекта: баннеры, посты в блоге, специальное выделение.</li>
|
||||
</ul>
|
||||
<h3>Теперь о том, что меняется:</h3>
|
||||
<ul>
|
||||
<li>Повысились цены на <nobr>бизнес-пакеты</nobr>. В том числе и стартовый. Эти расценки анонсировались в примечаниях к каждому пакету, так что сюрпризом эти изменения не стали. В том числе стало недоступно бесплатное размещение полных наборов — коммерческих предложений для всех типовых проёмов нашей базы.</li>
|
||||
<li>Введён новый пакет для бесплатного размещения. В его рамках возможно размещать цен только для третьи набора. Это 20–25 расчётов цен типовых проёмов. Выбравшим бесплатный, стартовый набор можно следовать двумя стратегиями: разместить цены на полный набор постепенно в течении квартала или обновлять цены только для проёмов, распространённых в вашем регионе.</li>
|
||||
</ul>
|
||||
<h3>И что не меняется:</h3>
|
||||
<ul>
|
||||
<li>Коммерческие предложения останутся в агрегаторе навсегда. А значит навсегда останутся детальные характеристики предложений, описание оконной компании и ссылки на её сайт.</li>
|
||||
<li>Тарифы на медийное размещения остались без изменений.</li>
|
||||
</ul>
|
||||
<p><a href="/tariff">Новые тарифы размещены на сайте</a>. Скачать шаблоны для платного и бесплатного размещения <a href="/blogpost/2/My_zhdem_vashi_prajs-listy%21/">можно здесь</a>.</p>
|
||||
↓ ↑ ⟶ ⟵ ↗ ↗ ↘ ↙ ↖
|
||||
|
||||
<!--- Пост в блоге :: конец --->
|
||||
</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">←</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">→</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 %}
|
||||
|
||||
@@ -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 КМ.
|
||||
@@ -109,33 +115,34 @@ def get_flaps_for_big_pictures(query_set) -> dict:
|
||||
:return: dict: dict -- словарь с размерами картинок для больших картинок
|
||||
"""
|
||||
result = {}
|
||||
mount_max_h = 0 # максимальная высота оконного проема в квартире
|
||||
door_h = 0 # высота двери
|
||||
for i in query_set: # найдём максимальную высоту проёма окна и двери
|
||||
mount_max_h = 0 # максимальная высота оконного проема в квартире
|
||||
door_h = 0 # высота двери
|
||||
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}"):
|
||||
# создаем такую папку если ее нет
|
||||
os.makedirs(f"{STATIC_BASE_PATH}/{PATH_FOR_IMG}/{PATH_FOR_BIGIMGFLAPCONFIG}")
|
||||
flaps_dim = [] # список словарей, через который будут передаваться данные в шаблон
|
||||
mount_bulk = 0 # размещение дверной перемычки
|
||||
flaps_dim = [] # список словарей, через который будут передаваться данные в шаблон
|
||||
mount_bulk = 0 # размещение дверной перемычки
|
||||
i_through = -1
|
||||
for i in query_set:
|
||||
img_file_name = "%03dx%03dH%03d" % (i.iWinWidth, i.iWinHight, mount_max_h)
|
||||
# img_file_name = f"{i.iWinWidth:03d}x{i.iWinHight:03d}H{mount_max_h:03d}"
|
||||
if i.bIsDoor:
|
||||
img_file_name += u"D" # добавляем букву D если это дверь
|
||||
img_file_name += u"D" # добавляем букву D если это дверь
|
||||
else:
|
||||
img_file_name += u"W" # добавляем букву W если это окно
|
||||
img_file_name += u"W" # добавляем букву W если это окно
|
||||
if i.bIsNearDoor:
|
||||
img_file_name += u"N" # добавляем букву N если это окно рядом с дверью
|
||||
mount_bulk = i.iWinHight # размещение дверной перемычки
|
||||
img_file_name += u"N" # добавляем букву N если это окно рядом с дверью
|
||||
mount_bulk = i.iWinHight # размещение дверной перемычки
|
||||
else:
|
||||
img_file_name += u"-" # добавляем символ отдельное окно (не рядом с дверью)
|
||||
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,10 +208,10 @@ 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)
|
||||
if is_door: # это дверь. Выравнивание по нижней кромке
|
||||
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: # это не дверь... Выравниваем по верхней кромке
|
||||
else: # это не дверь... Выравниваем по верхней кромке
|
||||
if height < height_door:
|
||||
top = bottom - (height_door * PICT_H / height_max)
|
||||
bottom = top + (height * PICT_H / height_max)
|
||||
@@ -205,21 +220,21 @@ 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)
|
||||
|
||||
############################################################
|
||||
# НАЧИНАЕМ ОТРИСОВКУ СТВОРОК ОКНА НА КРТИНКУ
|
||||
############################################################
|
||||
v_ratio_max = 0 # число всех долей (частей) для построения пропорций по вертикали
|
||||
for i in dim_flap: # цикл по рядам створок
|
||||
v_ratio_max = 0 # число всех долей (частей) для построения пропорций по вертикали
|
||||
for i in dim_flap: # цикл по рядам створок
|
||||
v_ratio_max += i["vRatio"]
|
||||
local_top = top
|
||||
local_bottom = top
|
||||
for i in dim_flap: # цикл по рядам створок
|
||||
local_bottom += i["vRatio"]*flap_h/v_ratio_max
|
||||
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||
for i in dim_flap: # цикл по рядам створок
|
||||
local_bottom += i["vRatio"] * flap_h / v_ratio_max
|
||||
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||
for j in i["row"]:
|
||||
h_ratio_max += j["hRatio"]
|
||||
local_right = 0
|
||||
@@ -227,12 +242,12 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
|
||||
for j in i["row"]:
|
||||
local_right += j["hRatio"] * right / h_ratio_max
|
||||
# отрисовка схему открывания створки
|
||||
if "M" in j["flap"] or "m" in j["flap"] or "м" in j["flap"] or "М" in j["flap"]: # москитная сетка
|
||||
if "M" in j["flap"] or "m" in j["flap"] or "м" in j["flap"] or "М" in j["flap"]: # москитная сетка
|
||||
for k in range(local_left + 3, local_right - 3, 12):
|
||||
draw.line((k, local_top + 7, k, local_bottom - 7), fill=(225, 225, 225, 255), width=2)
|
||||
for k in range(local_top + 3, local_bottom - 3, 12):
|
||||
draw.line((local_left + 7, k, local_right - 7, k), fill=(225, 225, 225), width=2)
|
||||
if is_door: # Это дверь. Выравнивание по нижней кромке
|
||||
if is_door: # Это дверь. Выравнивание по нижней кромке
|
||||
top = bottom - (height * PICT_H / height_max)
|
||||
# рисуем серединную перегородку =
|
||||
draw.line((left, top + (height_mount_bulk * PICT_H / height_max) - 8,
|
||||
@@ -242,40 +257,40 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
|
||||
right - 12, bottom - 12), fill=(125, 125, 125), width=3)
|
||||
draw.line((right - 6, top + (height_mount_bulk * PICT_H / height_max) - 4,
|
||||
left + 12, bottom - 12), fill=(125, 125, 125), width=3)
|
||||
if "|" in j["flap"]: # вертикальная перегородка |
|
||||
if "|" in j["flap"]: # вертикальная перегородка |
|
||||
for k in range(j["flap"].count("|") + 1):
|
||||
draw.line((local_left + k * (local_right - local_left) / (j["flap"].count("|") + 1), local_top,
|
||||
local_left + k * (local_right - local_left) / (j["flap"].count("|") + 1), local_bottom),
|
||||
fill=(125, 125, 125), width=4)
|
||||
if "=" in j["flap"]: # горизонтальная перегородка =
|
||||
if "=" in j["flap"]: # горизонтальная перегородка =
|
||||
for k in range(j["flap"].count("=") + 1):
|
||||
draw.line((local_left, local_top + k * (local_bottom - local_top) / (j["flap"].count("=") + 1),
|
||||
local_right, local_top + k * (local_bottom - local_top) / (j["flap"].count("=") + 1)),
|
||||
fill=(125, 125, 125), width=4)
|
||||
if "V" in j["flap"]: # откидное открывание V
|
||||
if "V" in j["flap"]: # откидное открывание V
|
||||
draw.line((local_right - 12, local_bottom - 12, (local_right + local_left) / 2, local_top + 12),
|
||||
fill=(225, 125, 125), width=1)
|
||||
draw.line((local_left + 12, local_bottom - 12, (local_right + local_left) / 2, local_top + 12),
|
||||
fill=(225, 125, 125), width=1)
|
||||
if ">" in j["flap"] or "G" in j["flap"]: # поворотное влево >
|
||||
if ">" in j["flap"] or "G" in j["flap"]: # поворотное влево >
|
||||
draw.line((local_left + 12, local_top + 12, local_right - 12, (local_bottom + local_top) / 2),
|
||||
fill=(225, 125, 125), width=1)
|
||||
draw.line((local_left + 12, local_bottom - 12, local_right - 12, (local_bottom + local_top) / 2),
|
||||
fill=(225, 125, 125), width=1)
|
||||
if "<" in j["flap"] or "L" in j["flap"]: # поворотное вправо <
|
||||
if "<" in j["flap"] or "L" in j["flap"]: # поворотное вправо <
|
||||
draw.line((local_right - 12, local_bottom - 12, local_left + 12, (local_bottom + local_top) / 2),
|
||||
fill=(225, 125, 125), width=1)
|
||||
draw.line((local_right - 12, local_top + 12, local_left + 12, (local_bottom + local_top) / 2),
|
||||
fill=(225, 125, 125), width=1)
|
||||
if "X" in j["flap"] or "x" in j["flap"] or "х" in j["flap"] or "Х" in j["flap"] or \
|
||||
"+" in j["flap"]: # глухое окно +
|
||||
"+" in j["flap"]: # глухое окно +
|
||||
draw.line(((local_right + local_left) / 2 - 11, (local_bottom + local_top) / 2,
|
||||
(local_right + local_left) / 2 + 11, (local_bottom + local_top) / 2),
|
||||
fill=(225, 125, 125), width=2)
|
||||
draw.line(((local_right + local_left) / 2, (local_bottom + local_top) / 2 - 11,
|
||||
(local_right + local_left) / 2, (local_bottom + local_top) / 2 + 11),
|
||||
fill=(225, 125, 125), width=2)
|
||||
if u"Z" in j["flap"] or "z" in j["flap"] or "S" in j["flap"] or "s" in j["flap"]: # РАСШИРИТЕЛЬ (спейсер)
|
||||
if u"Z" in j["flap"] or "z" in j["flap"] or "S" 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=4)
|
||||
@@ -296,15 +311,15 @@ 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: # цикл по рядам створок
|
||||
for i in dim_flap: # цикл по рядам створок
|
||||
local_bottom += i["vRatio"] * flap_h / v_ratio_max
|
||||
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||
h_ratio_max = 0 # число всех долей (частей) для построения пропорций по горизонтали
|
||||
for j in i["row"]:
|
||||
h_ratio_max += j["hRatio"]
|
||||
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
|
||||
@@ -317,11 +332,11 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
|
||||
fill=(255, 255, 255, 0), outline=None)
|
||||
# для окон ниже чем дверь рисуем прямоугольник над проемом
|
||||
draw.rectangle((left, 0, right - 1, top), fill=(255, 255, 255, 0), outline=None)
|
||||
if is_door: # Это дверь. Надо нарисовать сверху прямоугольник, на случай если есть очень высокое окно
|
||||
if is_door: # Это дверь. Надо нарисовать сверху прямоугольник, на случай если есть очень высокое окно
|
||||
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"}
|
||||
@@ -331,20 +346,20 @@ def make_big_img_win_flap(img_file_name_with_path: str, width: int, height: int,
|
||||
|
||||
def flap_analiz(flap_config: str) -> list:
|
||||
# анализ схем открывания.
|
||||
dim_flap = [] # массив для хранения полной схемы открывания
|
||||
dim_flap = [] # массив для хранения полной схемы открывания
|
||||
i_end = len(flap_config)
|
||||
j = -1 # счётчик горизонтальных рядов (формула, оконный блок)
|
||||
k = -1 # счётчик вертикальных рядов внутри горизонтальных (створки)
|
||||
in_flap = False # признак, где идёт разбор: внутри ли сворки или снаружи (схемы открывания или описания рядов)
|
||||
j = -1 # счётчик горизонтальных рядов (формула, оконный блок)
|
||||
k = -1 # счётчик вертикальных рядов внутри горизонтальных (створки)
|
||||
in_flap = False # признак, где идёт разбор: внутри ли сворки или снаружи (схемы открывания или описания рядов)
|
||||
# начинаем разбор
|
||||
for i in range(0, i_end):
|
||||
# посимвольный разбор строки
|
||||
if i == 0 or flap_config[i - 1] == ".":
|
||||
dim_flap.append({}) # надо создать новый ряд (фрамуги или ряд створок)
|
||||
dim_flap.append({}) # надо создать новый ряд (фрамуги или ряд створок)
|
||||
j += 1
|
||||
k = -1
|
||||
dim_flap[j].update({"row": []}) # добавляем в ряд пустой список створок
|
||||
dim_flap[j].update({"vRatio": 1}) # добавляем число характеризующее пропорцию ряда относительно других
|
||||
dim_flap[j].update({"row": []}) # добавляем в ряд пустой список створок
|
||||
dim_flap[j].update({"vRatio": 1}) # добавляем число характеризующее пропорцию ряда относительно других
|
||||
if not in_flap and (flap_config[i].isdigit() and flap_config[i - 1].isdigit()):
|
||||
dim_flap[j].update({"vRatio": dim_flap[j]["vRatio"] * 10 + int(flap_config[i])})
|
||||
continue
|
||||
@@ -364,34 +379,218 @@ def flap_analiz(flap_config: str) -> list:
|
||||
in_flap = False
|
||||
continue
|
||||
# символ увеличения пропорции
|
||||
if in_flap and (flap_config[i] == "-" or flap_config[i] == "_"): # для управления пропорциями створок
|
||||
if in_flap and (flap_config[i] == "-" or flap_config[i] == "_"): # для управления пропорциями створок
|
||||
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])})
|
||||
continue
|
||||
if in_flap and (flap_config[i] == "V" # откидное открывание
|
||||
or flap_config[i] == ">" # поворотное влево
|
||||
or flap_config[i] == "G" # ^
|
||||
or flap_config[i] == "L" # поворотное вправо
|
||||
or flap_config[i] == "<" # ^
|
||||
or flap_config[i] == "|" # вертикальная перегородка
|
||||
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] == "M" # москитная сетка
|
||||
or flap_config[i] == "m" # ^
|
||||
or flap_config[i] == "м" # ^
|
||||
or flap_config[i] == "М" # ^
|
||||
or flap_config[i] == "Z" # расширитель (спейсер)
|
||||
or flap_config[i] == "S" # ^
|
||||
or flap_config[i] == "z" # ^
|
||||
or flap_config[i] == "s"): # ^
|
||||
if in_flap and (flap_config[i] == "V" # откидное открывание
|
||||
or flap_config[i] == ">" # поворотное влево
|
||||
or flap_config[i] == "G" # ^
|
||||
or flap_config[i] == "L" # поворотное вправо
|
||||
or flap_config[i] == "<" # ^
|
||||
or flap_config[i] == "|" # вертикальная перегородка
|
||||
or flap_config[i] == "=" # горизонтальная перегородка
|
||||
or flap_config[i] == "X" # глухое окно
|
||||
or flap_config[i] == "x" # ^
|
||||
or flap_config[i] == "х" # ^
|
||||
or flap_config[i] == "Х" # ^
|
||||
or flap_config[i] == "+" # ^
|
||||
or flap_config[i] == "M" # москитная сетка
|
||||
or flap_config[i] == "m" # ^
|
||||
or flap_config[i] == "м" # ^
|
||||
or flap_config[i] == "М" # ^
|
||||
or flap_config[i] == "Z" # расширитель (спейсер)
|
||||
or flap_config[i] == "S" # ^
|
||||
or flap_config[i] == "z" # ^
|
||||
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")}')
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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} сек."
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -0,0 +1 @@
|
||||
e8819d2fd6d3
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<users>
|
||||
<user>027F51EEB3278BF010983153FDB6F9A8</user>
|
||||
</users>
|
||||
@@ -0,0 +1,8 @@
|
||||
АВТОРЫ
|
||||
ДИЗАЙН: Сергей Еремин
|
||||
КОД HTML: Сергей Еремин
|
||||
КОД CSS: Сергей Еремин
|
||||
КОД SVG: Сергей Еремин
|
||||
КОД JavaScript: Сергей Еремин
|
||||
ФОТОРГАФИИ:
|
||||
ГРАФИКА:
|
||||
|
After Width: | Height: | Size: 387 B |
|
After Width: | Height: | Size: 529 B |
|
After Width: | Height: | Size: 635 B |
@@ -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 |
@@ -0,0 +1 @@
|
||||
google-site-verification: googleacb673eb0c31969f.html
|
||||
@@ -0,0 +1 @@
|
||||
google-site-verification: googleea5d443319529114.html
|
||||
@@ -0,0 +1 @@
|
||||
mailru-domain: T2hJTKvdCl8xIbEm
|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 5.1 KiB |