// procurement-criteria.jsx — бібліотека шаблонів критеріїв оцінки закупівель // (PIN/Екоклуб). Багаторазові шаблони: ваги (сума 100%), методи (бали/формула/ // pass-fail), рубрики балів. Зберігаються на бекенді (resource procurement-criteria). // Відкривається як повноекранна панель із вкладки «План закупівель». (function () { const KINDS = [ { key: "Services", uk: "Послуги" }, { key: "Works", uk: "Роботи" }, { key: "Goods", uk: "Товари / Матеріали" }, { key: "", uk: "Будь-який тип" }, ]; const kindUk = (k) => (KINDS.find(x => x.key === k) || {}).uk || "Будь-який тип"; const METHODS = [ { key: "points", uk: "Бали (рубрика)" }, { key: "formula", uk: "Формула (ціна)" }, { key: "passfail", uk: "Pass / Fail" }, ]; const methodUk = (m) => (METHODS.find(x => x.key === m) || {}).uk || m; const rnd = () => Math.random().toString(36).slice(2, 7); const blankRubric = (score) => ({ score, desc: "" }); const blankCriterion = () => ({ id: "cr-" + rnd(), name: "", weight: 0, method: "points", maxScore: 5, formula: "", rubric: [] }); const sumWeight = (cs) => (cs || []).reduce((a, c) => a + (Number(c.weight) || 0), 0); // ── друк одного шаблону в окреме вікно ── function printTemplate(t) { const esc = (s) => String(s == null ? "" : s).replace(/[&<>]/g, ch => ({ "&": "&", "<": "<", ">": ">" }[ch])); const rows = (t.criteria || []).map((c, i) => { let body = ""; if (c.method === "points") { body = "" + (c.rubric || []).map(r => ``).join("") + "
${esc(r.score)}${esc(r.desc)}
"; } else if (c.method === "formula") { body = `
${esc(c.formula)}
`; } else { body = "
Pass / Fail
"; } return `${i + 1}${esc(c.name)}${c.method === "points" && c.maxScore ? `
макс. ${esc(c.maxScore)} балів
` : ""}${esc(c.weight)}%${body}`; }).join(""); const html = `Критерії оцінки — ${esc(t.name)}

Критерії оцінки пропозицій

${esc(t.name)} · ${esc(kindUk(t.kind))}${t.note ? " · " + esc(t.note) : ""}
${rows}
КритерійВагаШкала / метод оцінки
Сумарна вага: ${sumWeight(t.criteria)}%