/
shool
/
lessons
Обзор
Документация
Войти
/
shool
/
lessons
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
index.html
1 281 строка
47 KB
shool
Create: index.html
29 июл 2026, 13:46
Верифицирован
29 июл 2026, 13:46
29381ac
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Проектирование ГеоПарка</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, sans-serif; background: linear-gradient(135deg, #e8f5e9 0%, #e3f2fd 100%); color: #1a3a3a; min-height: 100vh; padding: 20px; line-height: 1.5; } .container { max-width: 1000px; margin: 0 auto; background: #fff; border-radius: 16px; box-shadow: 0 10px 40px rgba(0,0,0,0.08); overflow: hidden; } /* ===== Первый экран: суть занятия ===== */ .hero { background: linear-gradient(135deg, #0d47a1 0%, #1b5e20 50%, #00695c 100%); color: #fff; padding: 40px; position: relative; overflow: hidden; } .hero::before { content: ""; position: absolute; inset: 0; background-image: radial-gradient(circle at 20% 30%, rgba(255,255,255,0.08) 0%, transparent 40%), radial-gradient(circle at 80% 70%, rgba(255,255,255,0.06) 0%, transparent 40%); pointer-events: none; } .hero-badge { display: inline-block; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 6px 14px; border-radius: 20px; font-size: 0.8rem; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 14px; backdrop-filter: blur(4px); } .hero h2 { font-size: 2rem; margin-bottom: 10px; line-height: 1.2; } .hero .subtitle { font-size: 1.1rem; opacity: 0.9; margin-bottom: 24px; } .hero-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 20px; position: relative; z-index: 1; } .hero-card { background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); border-radius: 12px; padding: 18px 20px; backdrop-filter: blur(6px); } .hero-card .label { font-size: 0.75rem; letter-spacing: 1.5px; text-transform: uppercase; opacity: 0.75; margin-bottom: 8px; display: flex; align-items: center; gap: 6px; } .hero-card .label.problem { color: #ffcc80; } .hero-card .label.product { color: #a5d6a7; } .hero-card .text { font-size: 1rem; line-height: 1.5; font-weight: 500; } /* ===== Инфо-карточки занятия ===== */ .hero-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; margin-top: 20px; position: relative; z-index: 1; } .info-chip { background: rgba(255,255,255,0.12); border: 1px solid rgba(255,255,255,0.25); border-radius: 10px; padding: 14px 16px; backdrop-filter: blur(6px); display: flex; gap: 12px; align-items: flex-start; transition: transform 0.2s, background 0.2s; } .info-chip:hover { transform: translateY(-2px); background: rgba(255,255,255,0.18); } .info-chip .ic-icon { font-size: 1.5rem; flex-shrink: 0; line-height: 1; } .info-chip .ic-body { flex: 1; min-width: 0; } .info-chip .ic-label { font-size: 0.7rem; letter-spacing: 1.2px; text-transform: uppercase; opacity: 0.7; margin-bottom: 4px; } .info-chip .ic-value { font-size: 0.92rem; font-weight: 500; line-height: 1.4; } .info-chip .ic-sub { font-size: 0.8rem; opacity: 0.8; margin-top: 2px; line-height: 1.35; } .status-bar { display: flex; justify-content: space-between; align-items: center; padding: 12px 40px; background: #f1f8e9; border-bottom: 1px solid #c5e1a5; font-size: 0.9rem; color: #33691e; } .status-bar .saved { color: #2e7d32; font-weight: 600; } main { padding: 30px 40px 40px; } section { margin-bottom: 35px; padding: 22px 26px; background: #fafbfc; border-left: 5px solid #2e7d32; border-radius: 8px; } section.blue { border-left-color: #1565c0; } section.orange { border-left-color: #ef6c00; } section.purple { border-left-color: #6a1b9a; } section.teal { border-left-color: #00695c; } section.indigo { border-left-color: #283593; } section.amber { border-left-color: #ff8f00; } section h2 { font-size: 1.2rem; color: #2e7d32; margin-bottom: 14px; display: flex; align-items: center; gap: 10px; } section.blue h2 { color: #1565c0; } section.orange h2 { color: #ef6c00; } section.purple h2 { color: #6a1b9a; } section.teal h2 { color: #00695c; } section.indigo h2 { color: #283593; } section.amber h2 { color: #ff8f00; } .num { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: #2e7d32; color: #fff; font-size: 0.9rem; font-weight: 700; } section.blue .num { background: #1565c0; } section.orange .num { background: #ef6c00; } section.purple .num { background: #6a1b9a; } section.teal .num { background: #00695c; } section.indigo .num { background: #283593; } section.amber .num { background: #ff8f00; } /* ===== Этапы занятия ===== */ .stages { list-style: none; counter-reset: stage; display: flex; flex-direction: column; gap: 10px; } .stages li { counter-increment: stage; display: grid; grid-template-columns: auto 1fr auto; gap: 14px; align-items: center; padding: 12px 16px; background: #fff; border-radius: 8px; border: 1px solid #e0e0e0; transition: transform 0.15s, box-shadow 0.15s; } .stages li:hover { transform: translateX(4px); box-shadow: 0 3px 10px rgba(0,0,0,0.06); border-color: #00695c; } .stages li::before { content: counter(stage); display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(135deg, #00695c, #2e7d32); color: #fff; font-weight: 700; font-size: 0.95rem; } .stage-body .stage-title { font-weight: 600; color: #1a3a3a; margin-bottom: 2px; } .stage-body .stage-desc { font-size: 0.88rem; color: #546e7a; } .stage-time { background: #e0f2f1; color: #00695c; padding: 5px 12px; border-radius: 14px; font-size: 0.82rem; font-weight: 700; white-space: nowrap; } /* ===== Предмет результата ===== */ .results-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; } .result-item { background: #fff; border: 1px solid #c5cae9; border-radius: 10px; padding: 14px 16px; display: flex; gap: 12px; align-items: flex-start; transition: transform 0.15s, box-shadow 0.15s; } .result-item:hover { transform: translateY(-2px); box-shadow: 0 6px 14px rgba(40,53,147,0.12); border-color: #283593; } .result-icon { font-size: 1.6rem; flex-shrink: 0; } .result-text { font-size: 0.92rem; color: #1a3a3a; } .result-text strong { display: block; color: #283593; margin-bottom: 2px; font-size: 0.95rem; } /* ===== Материалы ===== */ .materials-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; } .material-card { background: #fff; border-radius: 10px; padding: 14px 16px; border-left: 4px solid #ff8f00; box-shadow: 0 2px 6px rgba(0,0,0,0.04); display: flex; gap: 12px; align-items: flex-start; } .material-card .mat-icon { font-size: 1.6rem; } .material-card .mat-title { font-weight: 700; color: #e65100; font-size: 0.95rem; margin-bottom: 3px; } .material-card .mat-desc { font-size: 0.85rem; color: #546e7a; } .row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; margin-bottom: 10px; } label { display: block; font-size: 0.85rem; color: #546e7a; margin-bottom: 5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; } input[type="text"], input[type="number"], textarea, select { width: 100%; padding: 10px 12px; border: 1.5px solid #cfd8dc; border-radius: 6px; font-size: 0.95rem; font-family: inherit; transition: border 0.2s, box-shadow 0.2s; background: #fff; } input:focus, textarea:focus, select:focus { outline: none; border-color: #2e7d32; box-shadow: 0 0 0 3px rgba(46,125,50,0.15); } textarea { resize: vertical; min-height: 80px; } table { width: 100%; border-collapse: collapse; margin-top: 10px; background: #fff; border-radius: 6px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,0.05); } th { background: #e8f5e9; color: #1b5e20; padding: 10px; text-align: left; font-size: 0.85rem; font-weight: 700; text-transform: uppercase; } td { padding: 4px; border-bottom: 1px solid #eceff1; } td input { border: none; padding: 8px; background: transparent; width: 100%; } td input:focus { background: #f1f8e9; } .btn { padding: 8px 14px; border: none; border-radius: 6px; cursor: pointer; font-size: 0.85rem; font-weight: 600; transition: transform 0.15s, box-shadow 0.15s; margin-right: 6px; margin-top: 8px; }.btn:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(0,0,0,0.1); } .btn-add { background: #66bb6a; color: #fff; } .btn-del { background: #ef5350; color: #fff; padding: 6px 10px; font-size: 0.8rem; } .formula-box { background: #fff; border: 2px dashed #1565c0; border-radius: 8px; padding: 16px; margin: 10px 0; } .formula-box code { display: block; font-family: 'Consolas', monospace; color: #0d47a1; margin: 6px 0; font-size: 0.95rem; } .grid-canvas { width: 100%; height: 320px; border: 2px solid #1565c0; border-radius: 8px; background: #fff; background-image: linear-gradient(#e3f2fd 1px, transparent 1px), linear-gradient(90deg, #e3f2fd 1px, transparent 1px); background-size: 20px 20px; cursor: crosshair; display: block; } .toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; } .toolbar button { padding: 6px 12px; border: 1px solid #1565c0; background: #fff; color: #1565c0; border-radius: 5px; cursor: pointer; font-size: 0.85rem; } .toolbar button.active { background: #1565c0; color: #fff; } .actions { display: flex; flex-wrap: wrap; gap: 10px; padding: 25px 40px; background: #eceff1; border-top: 1px solid #cfd8dc; justify-content: center; } .actions button { padding: 12px 22px; border: none; border-radius: 8px; cursor: pointer; font-size: 0.95rem; font-weight: 600; transition: all 0.2s; display: flex; align-items: center; gap: 8px; } .actions button:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,0.15); } .save { background: #2e7d32; color: #fff; } .load { background: #1565c0; color: #fff; } .print { background: #ef6c00; color: #fff; } .clear { background: #c62828; color: #fff; } .toast { position: fixed; bottom: 30px; right: 30px; background: #2e7d32; color: #fff; padding: 14px 22px; border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,0.2); opacity: 0; transform: translateY(20px); transition: all 0.3s; z-index: 1000; } .toast.show { opacity: 1; transform: translateY(0); } .hint { font-size: 0.85rem; color: #78909c; font-style: italic; margin-top: 6px; } @media print { body { background: #fff; padding: 0; } .actions, .toolbar, .btn-add, .btn-del, .status-bar { display: none !important; } .container { box-shadow: none; } section { break-inside: avoid; } } @media (max-width: 600px) { main, .actions, .hero { padding-left: 20px; padding-right: 20px; } .hero h2 { font-size: 1.4rem; } .hero-grid { grid-template-columns: 1fr; } .hero-info { grid-template-columns: 1fr; } .stages li { grid-template-columns: auto 1fr; } .stage-time { grid-column: 2; justify-self: start; } } </style> </head> <body> <div class="container"> <!-- ====== ПЕРВЫЙ ЭКРАН: СУТЬ ЗАНЯТИЯ ====== --> <div class="hero"> <span class="hero-badge">📘 Методическая карта занятия</span> <h2>«Школьный кампус»</h2> <p class="subtitle">Интерактивная карта школьного двора для расчета зоны отдыха</p> <!-- Информационные карточки занятия --> <div class="hero-info"> <div class="info-chip"> <div class="ic-icon">📚</div> <div class="ic-body"> <div class="ic-label">Предметы</div> <div class="ic-value">Информатика + геометрия</div> <div class="ic-sub">Инструмент моделирования реального пространства и расчета площадей</div> </div> </div> <div class="info-chip"> <div class="ic-icon">💻</div> <div class="ic-body"> <div class="ic-label">Информатика</div> <div class="ic-value">Визуализация данных</div> <div class="ic-sub">Работа с графическими редакторами</div> </div> </div> <div class="info-chip"> <div class="ic-icon">🎓</div> <div class="ic-body"> <div class="ic-label">Класс</div> <div class="ic-value">8–9 класс</div> <div class="ic-sub">13–14 лет</div> </div> </div> <div class="info-chip"> <div class="ic-icon">🌳</div> <div class="ic-body"> <div class="ic-label">Сбор данных</div> <div class="ic-value">Территория школьного двора</div> <div class="ic-sub">Полевые замеры объектов</div> </div> </div> <div class="info-chip"> <div class="ic-icon">🖥️</div> <div class="ic-body"> <div class="ic-label">Обработка</div> <div class="ic-value">Кабинет информатики</div> <div class="ic-sub">Расчёты и построение чертежа</div> </div> </div> <div class="info-chip"> <div class="ic-icon">⏱️</div> <div class="ic-body"> <div class="ic-label">Формат</div> <div class="ic-value">Серия из 2 занятий</div> <div class="ic-sub">По 40 минут каждое</div> </div> </div> </div> <div class="hero-grid"> <div class="hero-card"> <div class="label problem">⚠️ Проблема</div> <div class="text">Как спроектировать зону отдыха на территории школы/парка так, чтобы она была удобной, безопасной, соответствовала нормам СанПиН и вписывалась в существующий ландшафт?</div> </div> <div class="hero-card"> <div class="label product">✅ Продукт</div> <div class="text">Командный проект: чертёж-схема зоны отдыха в масштабе с расчётом площади, обоснованием формы и протоколом проверки расчётов с помощью ИИ.</div> </div> </div> </div> <div class="status-bar"> <span id="statusText">⚪ Данные не сохранены</span> <span id="lastSaved"></span> </div> <main> <!-- ====== ЭТАПЫ ЗАНЯТИЯ ====== --> <section class="teal"> <h2><span class="num">⏱</span>Этапы занятия</h2> <p class="hint" style="margin-bottom:14px;">Общая продолжительность — 70 минут (2 академических часа). Допустимо делить на два урока по 35 минут.</p> <ol class="stages"> <li> <div class="stage-body"> <div class="stage-title">Мотивация и постановка проблемы</div> <div class="stage-desc">Обсуждение: что такое ГеоПарк? Зачем нужны зоны отдыха? Знакомство с нормативами СанПиН.</div> </div> <div class="stage-time">5 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Формирование команд и распределение ролей</div> <div class="stage-desc">Координатор, инженер-геодезист, аналитик-математик, картограф/дизайнер.</div> </div> <div class="stage-time">3 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Полевые замеры территории</div> <div class="stage-desc">Выход на участок, измерение рулеткой/шагами длин, widths, радиусов объектов. Запись в протокол.</div> </div> <div class="stage-time">15 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Перевод в масштаб чертежа</div> <div class="stage-desc">Выбор масштаба (1:50 / 1:100). Расчёт размеров в сантиметрах по формуле.</div> </div> <div class="stage-time">10 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Построение чертежа-схемы</div> <div class="stage-desc">Нанесение существующих объектов и проектируемой зоны отдыха на миллиметровку / canvas.</div> </div> <div class="stage-time">15 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Геометрический расчёт площади</div> <div class="stage-desc">Разбиение сложной фигуры на простые (прямоугольник, треугольник, круг, трапеция). Суммирование.</div> </div> <div class="stage-time">10 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Обоснование решения и проверка ИИ</div> <div class="stage-desc">Запрос к ИИ-ассистенту для проверки расчётов. Сравнение результатов. Запись выводов.</div> </div> <div class="stage-time">8 мин</div> </li> <li> <div class="stage-body"> <div class="stage-title">Презентация и рефлексия</div> <div class="stage-desc">Команды представляют проекты. Самооценка. Обсуждение трудностей и находок.</div> </div> <div class="stage-time">4 мин</div> </li> </ol> </section> <!-- ====== ПРЕДМЕТ РЕЗУЛЬТАТА ====== --> <section class="indigo"> <h2><span class="num">🎯</span>Предмет результата: что создают ученики</h2> <p class="hint" style="margin-bottom:14px;">По итогам занятия каждая команда предъявляет следующие артефакты:</p> <div class="results-grid"> <div class="result-item"> <div class="result-icon">📋</div> <div class="result-text"> <strong>Протокол полевых замеров</strong> Таблица с измерениями реальных объектов территории в метрах. </div> </div> <div class="result-item"> <div class="result-icon">📐</div> <div class="result-text"> <strong>Расчёт масштаба</strong> Обоснованный выбор масштаба и таблица пересчёта размеров. </div> </div> <div class="result-item"> <div class="result-icon">🗺️</div> <div class="result-text"> <strong>Чертёж-схема участка</strong> Графический план территории с обозначением существующих и проектируемых объектов. </div> </div> <div class="result-item"> <div class="result-icon">🧮</div> <div class="result-text"> <strong>Расчёт площади</strong> Разбиение фигуры на простые, применение формул, итоговая площадь зоны отдыха. </div> </div> <div class="result-item"> <div class="result-icon">📊</div> <div class="result-text"> <strong>Проверка по норме СанПиН</strong> Сравнение площади на 1 человека с нормативом (≥ 2 м²). </div> </div> <div class="result-item"> <div class="result-icon">🤖</div> <div class="result-text"> <strong>Протокол работы с ИИ</strong> Запрос к ИИ-ассистенту, ответ ИИ, вывод о совпадении результатов. </div> </div> <div class="result-item"> <div class="result-icon">💬</div> <div class="result-text"> <strong>Обоснование проекта</strong> Текстовое описание: почему выбрана такая форма и место. </div> </div> <div class="result-item"> <div class="result-icon">🪞</div> <div class="result-text"> <strong>Рефлексия команды</strong> Самооценка вклада, сложности, открытия. </div> </div> </div> </section> <!-- ====== МАТЕРИАЛЫ ====== --> <section class="amber"> <h2><span class="num">🧰</span>Материалы к занятию</h2> <p class="hint" style="margin-bottom:14px;">Что необходимо подготовить учителю и ученикам:</p> <div class="materials-list"> <div class="material-card"> <div class="mat-icon">📄</div> <div> <div class="mat-title">Рабочий лист учащегося</div> <div class="mat-desc">Интерактивная HTML-форма (этот документ) или распечатанный вариант А4.</div> </div> </div> <div class="material-card"> <div class="mat-icon">📝</div> <div> <div class="mat-title">Протокол полевых замеров</div> <div class="mat-desc">Планшет с таблицей для записи измерений на улице (ручка, твёрдая подложка).</div> </div> </div> <div class="material-card"> <div class="mat-icon">📏</div> <div> <div class="mat-title">Шаблон чертежа (миллиметровка)</div> <div class="mat-desc">Лист А3 в клетку 5×5 мм или распечатанная сетка масштаба 1:50 / 1:100.</div> </div> </div> <div class="material-card"> <div class="mat-icon">📐</div> <div> <div class="mat-title">Измерительные инструменты</div> <div class="mat-desc">Рулетка (5–10 м), мерная лента, угольник, линейка, карандаш, ластик.</div> </div> </div> <div class="material-card"> <div class="mat-icon">🧾</div> <div> <div class="mat-title">Карточка с формулами</div> <div class="mat-desc">Справочник: площадь прямоугольника, треугольника, трапеции, круга.</div> </div> </div> <div class="material-card"> <div class="mat-icon">📚</div> <div> <div class="mat-title">Выписка из СанПиН</div> <div class="mat-desc">Норматив: не менее 2 м² площади зоны отдыха на 1 человека.</div> </div> </div> <div class="material-card"> <div class="mat-icon">🤖</div> <div> <div class="mat-title">Доступ к ИИ-ассистенту</div> <div class="mat-desc">Смартфон/планшет/компьютер с доступом в интернет для проверки расчётов.</div> </div> </div> <div class="material-card"> <div class="mat-icon">🎨</div> <div> <div class="mat-title">Шаблоны карточек</div> <div class="mat-desc">Карточки с описанием заданий, вопросов для рефлексии и этапов работы команды.</div> </div> </div> </div> </section> <!-- Раздел 1. О себе --> <section> <h2><span class="num">1</span>Обо мне и моей команде</h2> <div class="row"> <div> <label>Фамилия Имя Отчество</label> <input type="text" id="fio" placeholder="Иванов Иван"> </div> <div> <label>Класс</label> <input type="text" id="klass" placeholder="8 «А»"> </div> <div> <label>Дата</label> <input type="text" id="date" placeholder="28.07.2026"> </div> </div> <div class="row"> <div> <label>Название команды</label> <input type="text" id="team" placeholder="Архитекторы"> </div> <div> <label>Моя роль в команде</label> <select id="role"> <option value="">— выберите —</option> <option>Координатор</option><option>Инженер-геодезист</option> <option>Аналитик-математик</option> <option>Картограф / Дизайнер</option> </select> </div> </div> </section> <!-- Раздел 2. Замеры --> <section class="blue"> <h2><span class="num">2</span>Полевые замеры территории</h2> <p class="hint">Запишите все измерения в метрах. Укажите объекты: бордюры, деревья, дорожки, столбы, площадка.</p> <table id="measureTable"> <thead> <tr> <th style="width:30%">Объект</th> <th>Длина, м</th> <th>Ширина / радиус, м</th> <th>Примечание</th> <th style="width:40px"></th> </tr> </thead> <tbody id="measureBody"></tbody> </table> <button class="btn btn-add" onclick="addMeasureRow()">+ Добавить объект</button> </section> <!-- Раздел 3. Масштаб --> <section class="blue"> <h2><span class="num">3</span>Перевод в масштаб чертежа</h2> <div class="row"> <div> <label>Масштаб (1 : N)</label> <input type="number" id="scale" placeholder="50" value="50"> </div> <div> <label>Реальный размер (м)</label> <input type="number" id="realSize" placeholder="10" step="0.1"> </div> <div> <label>Размер на чертеже (см)</label> <input type="number" id="drawSize" placeholder="авто" readonly> </div> </div> <p class="hint">Формула: размер_на_чертеже (см) = реальный_размер (м) × 100 ÷ N</p> </section> <!-- Раздел 4. Чертёж --> <section class="blue"> <h2><span class="num">4</span>Чертёж-схема участка</h2> <p class="hint">Нарисуйте существующие объекты (чёрным) и проектируемую зону отдыха (зелёным). Используйте кнопки ниже.</p> <div class="toolbar"> <button id="toolLine" class="active" onclick="setTool('line')">📏 Линия</button> <button id="toolRect" onclick="setTool('rect')">▭ Прямоугольник</button> <button id="toolCircle" onclick="setTool('circle')">◯ Круг</button> <button id="toolZone" onclick="setTool('zone')">🌳 Зона отдыха</button> <button onclick="clearCanvas()">🗑️ Очистить</button> </div> <canvas id="grid" class="grid-canvas"></canvas> </section> <!-- Раздел 5. Расчёт площади --> <section class="orange"> <h2><span class="num">5</span>Геометрический расчёт площади</h2> <div class="formula-box"> <strong>Формулы:</strong> <code>• Прямоугольник: S = a × b</code> <code>• Треугольник: S = ½ × a × h</code> <code>• Трапеция: S = (a + b) / 2 × h</code> <code>• Круг: S = π × r²</code> </div> <div class="row"> <div> <label>Часть 1 (описание фигуры)</label> <input type="text" id="part1name" placeholder="Прямоугольник"> </div> <div> <label>Площадь части 1, м²</label> <input type="number" id="part1area" step="0.01" placeholder="0"> </div> </div> <div class="row"> <div> <label>Часть 2 (описание фигуры)</label> <input type="text" id="part2name" placeholder="Полукруг"> </div> <div> <label>Площадь части 2, м²</label> <input type="number" id="part2area" step="0.01" placeholder="0"> </div> </div> <div class="row"> <div> <label>Часть 3 (описание фигуры)</label> <input type="text" id="part3name" placeholder="Трапеция"> </div> <div> <label>Площадь части 3, м²</label> <input type="number" id="part3area" step="0.01" placeholder="0"> </div> </div> <div class="row"> <div> <label>Вычитаемая площадь (дерево и т.п.), м²</label> <input type="number" id="subtractArea" step="0.01" placeholder="0"> </div> <div><label>ИТОГО площадь зоны отдыха, м²</label> <input type="number" id="totalArea" readonly style="background:#fff9c4;font-weight:700;"> </div> </div> <div class="row"> <div> <label>Количество человек, на которых рассчитана зона</label> <input type="number" id="peopleCount" placeholder="10"> </div> <div> <label>Площадь на 1 человека, м²</label> <input type="number" id="perPerson" readonly style="background:#fff9c4;font-weight:700;"> </div> </div> <p class="hint">Норма СанПиН: не менее 2 м² на человека. Сравните ваш результат с нормой.</p> </section> <!-- Раздел 6. Обоснование --> <section class="purple"> <h2><span class="num">6</span>Обоснование решения</h2> <label>Почему мы выбрали именно эту форму и место для зоны отдыха?</label> <textarea id="justification" placeholder="Наша зона имеет форму..., потому что... Она не пересекается с..., соответствует норме..."></textarea> <label style="margin-top:14px;">Какие трудности возникли и как мы их решили?</label> <textarea id="difficulties" placeholder="Например: не могли точно измерить диагональ..."></textarea> <label style="margin-top:14px;">Запрос к ИИ-ассистенту (для проверки расчётов)</label> <textarea id="aiQuery" placeholder="Посчитай площадь трапеции по формуле (a+b)/2*h, где a=..., b=..., h=..."></textarea> <label style="margin-top:14px;">Ручная проверка: совпал ли результат ИИ с моим?</label> <select id="aiCheck"> <option value="">— выберите —</option> <option>Да, совпал полностью</option> <option>Совпал с небольшой погрешностью</option> <option>Не совпал — наш ответ верный</option> <option>Не совпал — исправили свою ошибку</option> </select> </section> <!-- Раздел 7. Самооценка --> <section> <h2><span class="num">7</span>Самооценка и рефлексия</h2> <div class="row"> <div> <label>Мой вклад в работу команды (1–5)</label> <select id="selfContrib"> <option value="">—</option> <option>1 — минимальный</option> <option>2</option> <option>3 — средний</option> <option>4</option> <option>5 — максимальный</option> </select> </div> <div> <label>Что нового я узнал на занятии?</label> <input type="text" id="learned" placeholder="..."> </div> </div> </section> </main> <div class="actions"> <button class="save" onclick="saveData()">💾 Сохранить локально</button> <button class="load" onclick="loadData()">📂 Загрузить сохранённое</button> <button class="print" onclick="window.print()">🖨️ Печать</button> <button class="clear" onclick="clearAll()">🗑️ Очистить всё</button> </div> </div> <div id="toast" class="toast"></div> <script> // ========== Динамическая таблица замеров ========== function addMeasureRow(obj='', len='', w='', note='') { const tbody = document.getElementById('measureBody'); const tr = document.createElement('tr'); tr.innerHTML = ` <td><input type="text" value="${obj}" placeholder="Дерево, бордюр..."></td> <td><input type="number" step="0.1" value="${len}" placeholder="0"></td> <td><input type="number" step="0.1" value="${w}" placeholder="0"></td> <td><input type="text" value="${note}" placeholder="охранная зона и т.п."></td> <td><button class="btn btn-del" onclick="this.closest('tr').remove()">✕</button></td> `; tbody.appendChild(tr); } // начальные строки for (let i = 0; i < 4; i++) addMeasureRow(); // ========== Автоматический расчёт масштаба ========== document.getElementById('realSize').addEventListener('input', calcScale); document.getElementById('scale').addEventListener('input', calcScale); function calcScale() { const r = parseFloat(document.getElementById('realSize').value); const s = parseFloat(document.getElementById('scale').value); if (!isNaN(r) && !isNaN(s) && s > 0) { document.getElementById('drawSize').value = (r * 100 / s).toFixed(2); } else { document.getElementById('drawSize').value = ''; } } // ========== Автоматический расчёт площади ========== ['part1area','part2area','part3area','subtractArea'].forEach(id => { document.getElementById(id).addEventListener('input', calcArea); }); document.getElementById('totalArea').addEventListener('input', calcPerPerson); document.getElementById('peopleCount').addEventListener('input', calcPerPerson); function calcArea() { const p1 = parseFloat(document.getElementById('part1area').value) || 0; const p2 = parseFloat(document.getElementById('part2area').value) || 0; const p3 = parseFloat(document.getElementById('part3area').value) || 0; const sub = parseFloat(document.getElementById('subtractArea').value) || 0; const total = p1 + p2 + p3 - sub; document.getElementById('totalArea').value = total.toFixed(2); calcPerPerson(); } function calcPerPerson() { const t = parseFloat(document.getElementById('totalArea').value) || 0; const p = parseFloat(document.getElementById('peopleCount').value); if (!isNaN(p) && p > 0) { document.getElementById('perPerson').value = (t / p).toFixed(2); } else { document.getElementById('perPerson').value = ''; } } // ========== Чертёж на canvas ========== const canvas = document.getElementById('grid'); const ctx = canvas.getContext('2d'); let currentTool = 'line'; let drawing = false; let startX, startY; let shapes = []; function resizeCanvas() { const ratio = window.devicePixelRatio || 1; const rect = canvas.getBoundingClientRect(); canvas.width = rect.width * ratio; canvas.height = rect.height * ratio; ctx.setTransform(ratio, 0, 0, ratio, 0, 0); redraw(); } window.addEventListener('resize', resizeCanvas); setTimeout(resizeCanvas, 50); function setTool(t) { currentTool = t; document.querySelectorAll('.toolbar button').forEach(b => b.classList.remove('active')); const btn = document.getElementById('tool' + t.charAt(0).toUpperCase() + t.slice(1)); if (btn) btn.classList.add('active'); } function getPos(e) { const rect = canvas.getBoundingClientRect(); const x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left; const y = (e.touches ? e.touches[0].clientY : e.clientY) - rect.top; return {x, y}; } canvas.addEventListener('mousedown', startDraw); canvas.addEventListener('touchstart', startDraw); function startDraw(e) { e.preventDefault(); const p = getPos(e); startX = p.x; startY = p.y; drawing = true; } canvas.addEventListener('mousemove', moveDraw); canvas.addEventListener('touchmove', moveDraw); function moveDraw(e) { if (!drawing) return; e.preventDefault(); const p = getPos(e); redraw(); drawShape(startX, startY, p.x, p.y, currentTool, true); } canvas.addEventListener('mouseup', endDraw); canvas.addEventListener('touchend', endDraw); function endDraw(e) { if (!drawing) return; drawing = false; const p = getPos(e) || {x: startX, y: startY}; shapes.push({type: currentTool, x1: startX, y1: startY, x2: p.x, y2: p.y}); redraw(); } function drawShape(x1, y1, x2, y2, type, preview) { ctx.save(); if (preview) ctx.setLineDash([5, 5]); ctx.lineWidth = 2; if (type === 'zone') { ctx.strokeStyle = '#2e7d32'; ctx.fillStyle = 'rgba(46,125,50,0.2)'; } else { ctx.strokeStyle = '#263238'; ctx.fillStyle = 'rgba(38,50,56,0.1)'; } ctx.beginPath(); if (type === 'line') { ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); } else if (type === 'rect' || type === 'zone') { ctx.fillRect(Math.min(x1,x2), Math.min(y1,y2), Math.abs(x2-x1), Math.abs(y2-y1)); ctx.strokeRect(Math.min(x1,x2), Math.min(y1,y2), Math.abs(x2-x1), Math.abs(y2-y1)); } else if (type === 'circle') { const r = Math.hypot(x2-x1, y2-y1); ctx.arc(x1, y1, r, 0, Math.PI*2); ctx.fill(); ctx.stroke(); } ctx.restore(); } function redraw() { const rect = canvas.getBoundingClientRect(); ctx.clearRect(0, 0, rect.width, rect.height); shapes.forEach(s => drawShape(s.x1, s.y1, s.x2, s.y2, s.type, false)); } function clearCanvas() { if (confirm('Очистить чертёж?')) { shapes = []; redraw(); } } // ========== Сохранение / загрузка ========== const STORAGE_KEY = 'geopark_worksheet_v1'; function collectData() { const data = { fio: document.getElementById('fio').value, klass: document.getElementById('klass').value, date: document.getElementById('date').value, team: document.getElementById('team').value, role: document.getElementById('role').value, measures: [], scale: document.getElementById('scale').value, part1name: document.getElementById('part1name').value, part1area: document.getElementById('part1area').value, part2name: document.getElementById('part2name').value, part2area: document.getElementById('part2area').value, part3name: document.getElementById('part3name').value, part3area: document.getElementById('part3area').value, subtractArea: document.getElementById('subtractArea').value, peopleCount: document.getElementById('peopleCount').value, justification: document.getElementById('justification').value, difficulties: document.getElementById('difficulties').value, aiQuery: document.getElementById('aiQuery').value, aiCheck: document.getElementById('aiCheck').value, selfContrib: document.getElementById('selfContrib').value, learned: document.getElementById('learned').value, shapes: shapes, savedAt: new Date().toISOString() }; document.querySelectorAll('#measureBody tr').forEach(tr => { const inputs = tr.querySelectorAll('input'); data.measures.push({ obj: inputs[0].value, len: inputs[1].value, w: inputs[2].value, note: inputs[3].value }); }); return data; } function applyData(data) { if (!data) return; ['fio','klass','date','team','role','scale', 'part1name','part1area','part2name','part2area', 'part3name','part3area','subtractArea','peopleCount', 'justification','difficulties','aiQuery','aiCheck', 'selfContrib','learned'].forEach(id => { if (data[id] !== undefined) document.getElementById(id).value = data[id]; }); const tbody = document.getElementById('measureBody'); tbody.innerHTML = ''; if (data.measures && data.measures.length) { data.measures.forEach(m => addMeasureRow(m.obj, m.len, m.w, m.note)); } else { for (let i = 0; i < 4; i++) addMeasureRow(); } if (data.shapes) { shapes = data.shapes; redraw(); } calcScale(); calcArea(); } function saveData() { const data = collectData(); localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); const now = new Date().toLocaleString('ru-RU'); document.getElementById('lastSaved').textContent = 'Сохранено: ' + now; document.getElementById('statusText').innerHTML = '🟢 <span class="saved">Сохранено локально</span>'; showToast('✅ Данные сохранены в браузере'); // авто-скачивание JSON const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); const safeName = (data.fio || 'ученик').replace(/\s+/g, '_'); a.href = url; a.download = `ГеоПарк_${safeName}_${data.klass || ''}.json`; a.click(); URL.revokeObjectURL(url); } function loadData() { const raw = localStorage.getItem(STORAGE_KEY); if (!raw) { showToast('⚠️ Нет сохранённых данных'); return; } try { applyData(JSON.parse(raw)); showToast('📂 Данные загружены'); document.getElementById('statusText').innerHTML = '🟢 <span class="saved">Загружено из памяти</span>'; } catch(e) { showToast('❌ Ошибка загрузки'); } } function clearAll() { if (!confirm('Удалить все введённые данные?')) return; localStorage.removeItem(STORAGE_KEY); document.querySelectorAll('input, textarea, select').forEach(el => { if (el.type !== 'button') el.value = ''; }); document.getElementById('measureBody').innerHTML = ''; for (let i = 0; i < 4; i++) addMeasureRow(); shapes = []; redraw(); document.getElementById('statusText').textContent = '⚪ Данные не сохранены'; document.getElementById('lastSaved').textContent = ''; showToast('🗑️ Все данные очищены'); } function showToast(msg) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 2500); } // автосохранение черновика каждые 30 секунд setInterval(() => { const hasInput = Array.from(document.querySelectorAll('input, textarea')).some(el => el.value.trim()); if (hasInput) { localStorage.setItem(STORAGE_KEY + '_draft', JSON.stringify(collectData())); } }, 30000); // загрузка черновика при старте window.addEventListener('load', () => { const draft = localStorage.getItem(STORAGE_KEY + '_draft'); if (draft) { try { applyData(JSON.parse(draft)); document.getElementById('statusText').innerHTML = '🟡 <span style="color:#ef6c00;font-weight:600;">Восстановлен черновик</span>'; } catch(e) {} } }); </script> </body> </html>