105 lines
4.5 KiB
JavaScript
105 lines
4.5 KiB
JavaScript
(function (global) {
|
|
"use strict";
|
|
|
|
function escapeHtml(s) {
|
|
return String(s ?? "")
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|
|
|
|
async function openLabAnimalProfilesModal() {
|
|
const resp = await fetch("/api/lab/animal-profiles");
|
|
const data = await resp.json().catch(() => ({}));
|
|
if (!resp.ok) {
|
|
global.WespZootechNotify?.createAdapter?.()?.error?.(data.message || "Ошибка загрузки профилей");
|
|
return;
|
|
}
|
|
const profiles = data.profiles || [];
|
|
const options = profiles
|
|
.map(
|
|
(p) =>
|
|
`<option value="${escapeHtml(p.id)}">${escapeHtml(p.label)} (${escapeHtml(p.rationType)})</option>`
|
|
)
|
|
.join("");
|
|
|
|
const html =
|
|
`<div class="lab-profiles-editor">` +
|
|
`<p class="small text-muted mb-2">Профили норм стада (зоотех). Выберите для просмотра или создайте новый.</p>` +
|
|
`<label class="form-label">Существующие</label>` +
|
|
`<select class="form-select mb-2" id="labProfilePick"><option value="">—</option>${options}</select>` +
|
|
`<div id="labProfileView" class="small mb-3 text-muted" hidden></div>` +
|
|
`<hr>` +
|
|
`<label class="form-label">Новый / редактирование</label>` +
|
|
`<input class="form-control form-control-sm mb-1" id="labProfileKey" placeholder="Ключ (beef_grow)">` +
|
|
`<input class="form-control form-control-sm mb-1" id="labProfileLabel" placeholder="Название">` +
|
|
`<select class="form-select form-select-sm mb-1" id="labProfileType">` +
|
|
`<option value="BEEF">Мясное</option><option value="DAIRY">Дойное</option></select>` +
|
|
`<textarea class="form-control form-control-sm" id="labProfileNorms" rows="4" placeholder='{"dry_matter":{"min":4000,"max":5000}}'></textarea>` +
|
|
`</div>`;
|
|
|
|
const ok = await global.WespDialog?.confirm?.(html, {
|
|
title: "Профили норм стада",
|
|
html: true,
|
|
confirmText: "Сохранить",
|
|
cancelText: "Закрыть",
|
|
});
|
|
if (!ok) return;
|
|
|
|
const pick = document.getElementById("labProfilePick")?.value;
|
|
const key = document.getElementById("labProfileKey")?.value?.trim();
|
|
const label = document.getElementById("labProfileLabel")?.value?.trim();
|
|
const rationType = document.getElementById("labProfileType")?.value || "BEEF";
|
|
let normsData = {};
|
|
try {
|
|
const raw = document.getElementById("labProfileNorms")?.value?.trim();
|
|
if (raw) normsData = JSON.parse(raw);
|
|
} catch (_) {
|
|
global.WespZootechNotify?.createAdapter?.()?.error?.("Некорректный JSON норм");
|
|
return;
|
|
}
|
|
if (!key || !label) {
|
|
global.WespZootechNotify?.createAdapter?.()?.error?.("Укажите ключ и название");
|
|
return;
|
|
}
|
|
|
|
const method = pick ? "PUT" : "POST";
|
|
const url = pick
|
|
? `/api/lab/animal-profiles/${encodeURIComponent(pick)}`
|
|
: "/api/lab/animal-profiles";
|
|
try {
|
|
const saveResp = await fetch(url, {
|
|
method,
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ profileKey: key, label, rationType, normsData }),
|
|
});
|
|
const saveData = await saveResp.json();
|
|
if (!saveResp.ok) throw new Error(saveData.message || "Ошибка сохранения");
|
|
global.WespZootechNotify?.createAdapter?.()?.success?.("Профиль сохранён");
|
|
} catch (e) {
|
|
global.WespZootechNotify?.createAdapter?.()?.error?.(e.message, { fallback: "Не удалось сохранить профиль" });
|
|
}
|
|
}
|
|
|
|
document.addEventListener("change", (ev) => {
|
|
if (ev.target?.id !== "labProfilePick") return;
|
|
const id = ev.target.value;
|
|
const view = document.getElementById("labProfileView");
|
|
if (!id || !view) return;
|
|
fetch(`/api/lab/animal-profiles/${encodeURIComponent(id)}`)
|
|
.then((r) => r.json())
|
|
.then((p) => {
|
|
document.getElementById("labProfileKey").value = p.profileKey || "";
|
|
document.getElementById("labProfileLabel").value = p.label || "";
|
|
document.getElementById("labProfileType").value = p.rationType || "BEEF";
|
|
document.getElementById("labProfileNorms").value = JSON.stringify(p.normsData || {}, null, 2);
|
|
view.hidden = false;
|
|
view.textContent = `${p.profileKey} · ${p.rationType}`;
|
|
})
|
|
.catch(() => {});
|
|
});
|
|
|
|
global.openLabAnimalProfilesModal = openLabAnimalProfilesModal;
|
|
})(window);
|