feat: render operational map — nodes (input/output/norms/resources) + gap patterns

This commit is contained in:
wasrusgen 2026-05-30 10:41:02 +03:00
parent 9450a95c04
commit 2abde49023

View File

@ -139,22 +139,47 @@ async function sendMsg(){
document.getElementById("sendBtn").disabled=false; document.getElementById("sendBtn").disabled=false;
} }
const COLORS={product:"#6366F1",customers:"#3B82F6",partners:"#8B5CF6",process:"#047857",team:"#EC4899",tools:"#0EA5E9",money:"#F59E0B"};
function pctColor(p){return p>=70?"#047857":p>=45?"#F59E0B":"#EF4444"} function pctColor(p){return p>=70?"#047857":p>=45?"#F59E0B":"#EF4444"}
function pctBg(p){return p>=70?"#ECFDF5":p>=45?"#FEF3C7":"#FEF2F2"} function pctBg(p){return p>=70?"#ECFDF5":p>=45?"#FEF3C7":"#FEF2F2"}
const SEV={critical:["#DC2626","#FEF2F2","КРИТИЧНО"],high:["#92400E","#FEF3C7","ВЫСОКИЙ"],medium:["#1E40AF","#EFF6FF","СРЕДНИЙ"]};
function renderModel(m){ function renderModel(m){
const col = document.getElementById("modelCol"); const col = document.getElementById("modelCol");
col.classList.add("show"); col.classList.add("show");
let html = `<div class="mc-head">Ваша бизнес-модель</div><div class="mc-sum">${esc(m.client_summary)}</div>`; let html = `<div class="mc-head">Операционная карта</div><div class="mc-sum">${esc(m.client_summary)}</div>`;
m.blocks.forEach(b=>{ if(m.business_pattern){
html += `<div style="background:#0F0F1A;color:#fff;border-radius:11px;padding:12px 14px;margin-bottom:16px;font-size:12px;line-height:1.5"><div style="font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#6EE7B7;margin-bottom:4px">Паттерн бизнеса</div>${esc(m.business_pattern)}</div>`;
}
// Узлы
html += `<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;margin-bottom:8px">Узлы бизнеса · ${m.nodes.length}</div>`;
m.nodes.forEach(n=>{
html += `<div class="blk"> html += `<div class="blk">
<div class="blk-top"><div class="blk-title">${esc(b.title)}</div> <div class="blk-top"><div class="blk-title">${esc(n.name)}</div>
<div class="blk-pct" style="color:${pctColor(b.completeness)};background:${pctBg(b.completeness)}">${b.completeness}%</div></div> <div class="blk-pct" style="color:${pctColor(n.completeness)};background:${pctBg(n.completeness)}">${n.completeness}%</div></div>
<div class="blk-row"><div class="blk-lbl">Как есть</div><div class="blk-asis">${esc(b.as_is)}</div></div>`; <div style="font-size:12px;color:#6366F1;font-weight:600;margin-bottom:8px">${esc(n.actor)}</div>
if(b.pains&&b.pains.length){html+=`<div class="blk-row"><div class="blk-lbl">Боли</div>`;b.pains.forEach(p=>html+=`<div class="blk-pain">${esc(p)}</div>`);html+=`</div>`} <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px">
html += `<div class="blk-row"><div class="blk-lbl">Как должно быть</div><div class="blk-tobe">${esc(b.to_be)}</div></div></div>`; <div style="background:#EFF6FF;border-radius:8px;padding:7px 9px"><div class="blk-lbl" style="color:#3B82F6">→ Вход</div><div style="font-size:12px;color:#374151;line-height:1.4">${esc(n.input)}</div></div>
<div style="background:#ECFDF5;border-radius:8px;padding:7px 9px"><div class="blk-lbl" style="color:#047857">Выход →</div><div style="font-size:12px;color:#374151;line-height:1.4">${esc(n.output)}</div></div>
</div>
<div class="blk-row"><div class="blk-lbl">Нормы</div><div style="font-size:12px;color:${n.norms.toLowerCase().includes('нет норм')?'#DC2626':'#374151'};line-height:1.4">${esc(n.norms)}</div></div>
<div class="blk-row"><div class="blk-lbl">Ресурсы</div><div style="font-size:12px;color:#374151;line-height:1.4">${esc(n.resources)}</div></div>`;
if(n.connections&&n.connections.length) html+=`<div class="blk-row"><div class="blk-lbl">Связи</div><div style="font-size:11px;color:#6b7280">${n.connections.map(esc).join(' · ')}</div></div>`;
if(n.issues&&n.issues.length){html+=`<div class="blk-row"><div class="blk-lbl" style="color:#92400e">Проблемы</div>`;n.issues.forEach(p=>html+=`<div class="blk-pain">${esc(p)}</div>`);html+=`</div>`}
html += `</div>`;
}); });
// Паттерны проблем
if(m.gaps&&m.gaps.length){
html += `<div style="font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;margin:18px 0 8px">Найденные разрывы · ${m.gaps.length}</div>`;
m.gaps.forEach(g=>{
const s=SEV[g.severity]||SEV.medium;
html+=`<div class="blk" style="border-left:3px solid ${s[0]}">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:5px"><span style="font-size:9px;font-weight:800;color:${s[0]};background:${s[1]};padding:2px 7px;border-radius:5px">${s[2]}</span><span class="blk-title">${esc(g.title)}</span></div>
<div style="font-size:12px;color:#6b7280;line-height:1.45">${esc(g.description)}</div></div>`;
});
}
if(m.missing_info&&m.missing_info.length){ if(m.missing_info&&m.missing_info.length){
html+=`<div class="blk" style="border-color:#FDE68A;background:#FFFBEB"><div class="blk-title" style="margin-bottom:8px">Елена уточнит ещё</div>`; html+=`<div class="blk" style="border-color:#FDE68A;background:#FFFBEB"><div class="blk-title" style="margin-bottom:8px">Елена уточнит ещё</div>`;
m.missing_info.forEach(q=>html+=`<div class="blk-pain">${esc(q)}</div>`);html+=`</div>`; m.missing_info.forEach(q=>html+=`<div class="blk-pain">${esc(q)}</div>`);html+=`</div>`;