Initial commit: site monorepo with API, web, and infra.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
влад
2026-07-16 10:11:54 +03:00
co-authored by Cursor
commit 016910ffb7
447 changed files with 73972 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>стандарты чистоты</title>
<script src="/static/js/wesp-theme-boot.js"></script>
<script>document.documentElement.classList.add('wesp-page-enter-pending');</script>
<script src="/static/js/wesp-page-enter.js?v=2"></script>
<script src="/static/js/wesp-nav-logo-shimmer.js?v=2"></script>
<script src="/static/js/wesp-lab-access.js?v=1"></script>
<script src="/static/js/wesp-zootech-nav.js?v=5"></script>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/wesp-zootech-shell.css" rel="stylesheet">
<link href="/static/css/wesp-zootech-layout.css?v=16" rel="stylesheet">
<link href="/static/css/wesp-zootech-components.css?v=8" rel="stylesheet">
<link href="/static/css/wesp-lab-sandbox.css?v=10" rel="stylesheet">
<link href="/static/css/wesp-lab-profiles.css?v=4" rel="stylesheet">
<link href="/static/css/font-awesome.min.css" rel="stylesheet">
<script src="/static/js/wesp-zootech-notification-messages.js?v=1"></script>
<script src="/static/js/wesp-user-messages.js?v=1"></script>
<script src="/static/js/wesp-zootech-notify.js?v=6"></script>
<script src="/static/js/bootstrap.bundle.min.js"></script>
<link href="/static/css/wesp-zootech-theme-organic.css?v=6" rel="stylesheet">
</head>
<body class="zootech-app-body lab-sandbox-page lab-profiles-page lab-heisenberg-prime">
<div id="wespZootechNavMount" data-active-page="lab"></div>
<div class="page-content wesp-page-main">
<div class="container py-3">
<div class="lab-sandbox-header lab-profiles-header" data-wesp-enter>
<p class="lab-heisenberg-prime-kicker mb-2"><span class="lab-heisenberg-prime-tag">PRIME</span> Heisenberg</p>
<h1><i class="fas fa-sliders-h text-primary me-2"></i>Стандарты чистоты</h1>
<p class="mb-0">Я не бизнесмен — я специалист. <a href="/lab">лаборатория</a></p>
</div>
<div class="lab-profiles-layout" data-wesp-enter>
<aside class="lab-sandbox-panel">
<div class="lab-sandbox-panel__title">Реестр стандартов</div>
<div class="mb-2">
<select id="labProfilesType" class="form-select form-select-sm">
<option value="">Все линейки</option>
<option value="DAIRY">Молоко</option>
<option value="BEEF">Говядина</option>
</select>
</div>
<input id="labProfilesSearch" class="form-control form-control-sm mb-2" type="search" placeholder="Это не мет">
<div id="labProfilesList" class="lab-profiles-list">
<div class="lab-sandbox-empty">Готовим список…</div>
</div>
<button type="button" class="btn btn-sm btn-outline-primary w-100 mt-2" id="labProfilesNew">+ Новый стандарт</button>
</aside>
<section class="lab-sandbox-panel lab-profiles-editor">
<div id="labProfilesEmpty" class="lab-sandbox-empty">Выбери стандарт</div>
<div id="labProfilesForm" hidden>
<div class="d-flex justify-content-between align-items-start flex-wrap gap-2 mb-2">
<div class="lab-sandbox-panel__title mb-0">Настройка формулы</div>
<div class="lab-profiles-toolbar mt-0">
<button type="button" class="btn btn-sm btn-outline-danger" id="labProfilesDelete" hidden>Никаких полумер</button>
<button type="button" class="btn btn-sm btn-primary" id="labProfilesSave">Запомни это</button>
</div>
</div>
<div class="lab-profiles-meta">
<div>
<label class="form-label small">Код</label>
<input id="labProfileKey" class="form-control form-control-sm" type="text" placeholder="Это не мет">
</div>
<div>
<label class="form-label small">Название</label>
<input id="labProfileLabel" class="form-control form-control-sm" type="text" placeholder="Синий — значит чистый">
</div>
<div>
<label class="form-label small">Линейка</label>
<select id="labProfileType" class="form-select form-select-sm">
<option value="DAIRY">Молоко</option>
<option value="BEEF">Говядина</option>
</select>
</div>
<div>
<label class="form-label small">Масса, кг</label>
<input id="labProfileMass" class="form-control form-control-sm" type="number" step="0.1">
</div>
<div>
<label class="form-label small">Удой, кг/сут</label>
<input id="labProfileMilk" class="form-control form-control-sm" type="number" step="0.1" title="Для динамической нормы уСП по GfE — наука о переменах">
</div>
<div>
<label class="form-label small">№ в справочнике</label>
<input id="labProfileExternal" class="form-control form-control-sm" type="number" step="1">
</div>
<div>
<label class="form-label small" for="labProfileNormsMethod">Методика норм</label>
<select id="labProfileNormsMethod" class="form-select form-select-sm">
<option value="wesp">WESP / GfE</option>
<option value="racion_moscow">RACION Москва</option>
<option value="racion_piter">RACION Петербург</option>
</select>
</div>
</div>
<div id="labProfileRacionFields" class="lab-profiles-meta d-none mb-2">
<div>
<label class="form-label small" for="labProfileFat">Жирность молока, %</label>
<input id="labProfileFat" class="form-control form-control-sm" type="number" step="0.1" value="4">
</div>
<div>
<label class="form-label small" for="labProfileLactation">Лактация №</label>
<input id="labProfileLactation" class="form-control form-control-sm" type="number" step="1" value="2" min="1" max="3">
</div>
<div class="lab-profile-piter-only d-none">
<label class="form-label small" for="labProfileKonc">ОЭ/СВ, МДж/кг СВ</label>
<input id="labProfileKonc" class="form-control form-control-sm" type="number" step="0.1" value="10.3">
</div>
</div>
<div id="labProfilesSeedPanel" class="lab-profiles-seed alert alert-light py-2 px-3 small mb-2" hidden>
<div class="d-flex flex-wrap align-items-end gap-2">
<div class="flex-grow-1" style="min-width: 12rem;">
<label class="form-label small mb-0" for="labProfilesSeedSearch">Справочник zootech</label>
<input id="labProfilesSeedSearch" class="form-control form-control-sm mb-1" type="search" placeholder="Фильтр по названию или №">
<select id="labProfilesSeedSelect" class="form-select form-select-sm" size="1">
<option value="">— выбери строку —</option>
</select>
</div>
<button type="button" class="btn btn-sm btn-outline-primary" id="labProfilesSeedApply" disabled>Загрузить нормы</button>
</div>
<p class="mb-0 mt-1 text-muted">Справочник zootech (БД). Пустой список — <code>python3 scripts/import_seed.py --norms</code>. Подставляет min/max; сохранение — «Запомни это».</p>
</div>
<div id="labProfilesGfePanel" class="lab-profiles-gfe alert alert-secondary py-2 px-3 small mb-2" hidden>
<div class="d-flex flex-wrap align-items-center gap-2 mb-1">
<strong>GfE 2001</strong>
<span id="labProfilesGfeValues" class="text-muted"></span>
<button type="button" class="btn btn-sm btn-outline-primary ms-auto" id="labProfilesGfeApplyUsp" disabled>Нижняя уСП</button>
<button type="button" class="btn btn-sm btn-outline-primary" id="labProfilesGfeApplyNel" disabled>Нижняя ЧЭЛ</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="labProfilesGfeApplyAll" disabled>Обе нижние</button>
</div>
<p class="mb-0 text-muted">Считаются только <strong>уСП</strong> и <strong>ЧЭЛ</strong> из массы и удоя. Остальные границы — из справочника или вручную (СВ, минералы, клетчатка, RNB).</p>
</div>
<div id="labProfilesNormsSummary" class="lab-profiles-norms-summary alert alert-light py-2 px-3 small mb-2" hidden>
<div class="d-flex flex-wrap align-items-center gap-2">
<strong>Источники норм</strong>
<span id="labProfilesNormsSummaryText" class="text-muted"></span>
<button type="button" class="btn btn-sm btn-outline-secondary ms-auto" id="labProfilesNormsRefresh">Обновить разбор</button>
</div>
<p class="mb-0 mt-1 text-muted">В БД — сохранённые границы профиля. RACION — расчёт по Москва/Петербург. WESP — из справочника zootech (fallback).</p>
</div>
<div class="lab-profiles-toolbar">
<label class="small mb-0"><input type="checkbox" id="labProfilesOnlyFilled" checked> Только с границами</label>
<label class="small mb-0"><input type="checkbox" id="labProfilesOnlyCalc"> Только в расчёте</label>
<label class="small mb-0" for="labProfilesSourceFilter">Источник</label>
<select id="labProfilesSourceFilter" class="form-select form-select-sm" style="width: auto; min-width: 10rem;">
<option value="all">Все</option>
<option value="in_db">В БД</option>
<option value="seed">Справочник WESP</option>
<option value="racion" data-racion-only>RACION (всё)</option>
<option value="racion_only" data-racion-only>RACION NPitV</option>
<option value="derived" data-racion-only>Производные</option>
<option value="new_racion" data-racion-only>Только RACION (не WESP)</option>
</select>
<input id="labProfilesNormSearch" class="form-control form-control-sm" type="search" placeholder="Поиск показателя" style="max-width: 12rem;">
<span id="labProfilesNormCount" class="small text-muted ms-auto"></span>
</div>
<div class="lab-profiles-table-wrap">
<table class="table table-sm mb-0">
<thead>
<tr>
<th>Показатель</th>
<th>Источник</th>
<th>нижняя</th>
<th>верхняя</th>
</tr>
</thead>
<tbody id="labProfilesNormsBody"></tbody>
</table>
</div>
</div>
</section>
</div>
</div>
</div>
<script src="/static/js/pages/lab-profiles.js?v=10"></script>
</body>
</html>