From 0a335d0075349688d59ddf2f24ff2e08857de83d Mon Sep 17 00:00:00 2001 From: wasrusgen Date: Wed, 3 Jun 2026 18:39:08 +0300 Subject: [PATCH] =?UTF-8?q?brand:=20=D1=83=D0=B1=D1=80=D0=B0=D0=BD=D1=8B?= =?UTF-8?q?=20=D0=92=D0=A1=D0=95=20=D1=8D=D0=BC=D0=BE=D0=B4=D0=B7=D0=B8=20?= =?UTF-8?q?->=20Lucide-=D0=B8=D0=BA=D0=BE=D0=BD=D0=BA=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=B1=D1=80=D0=B5=D0=BD=D0=B4=D0=B1=D1=83=D0=BA=D1=83=20(?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81-=D0=B1=D0=B5=D0=B9=D0=B4?= =?UTF-8?q?=D0=B6=D0=B8,=20=D1=87=D0=B8=D0=BF=D1=8B,=20=D0=BA=D0=BD=D0=BE?= =?UTF-8?q?=D0=BF=D0=BA=D0=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/cabinet.html | 43 +++++++++-------- docs/crm.html | 116 +++++++++++++++++++++++++--------------------- 2 files changed, 88 insertions(+), 71 deletions(-) diff --git a/docs/cabinet.html b/docs/cabinet.html index e07e5d0..e8ee7b1 100644 --- a/docs/cabinet.html +++ b/docs/cabinet.html @@ -298,7 +298,7 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
-
+
@@ -406,7 +406,12 @@ const ICONS={ receipt:'', search:'', target:'', - send:'' + send:'', + close:'', + checkCircle:'', + sparkle:'', + gift:'', + dot:'' }; function ic(n,s,sw){s=s||20;return ''+(ICONS[n]||'')+'';} @@ -494,7 +499,7 @@ async function opPollOnce(){try{const r=await fetch(`${API}/api/operator-chat?to function startOpPoll(){stopOpPoll();opPollOnce();opPollTimer=setInterval(opPollOnce,15000);} function stopOpPoll(){if(opPollTimer){clearInterval(opPollTimer);opPollTimer=null;}} /* ── Предложения клиента ── */ -const SUG_ST={new:['🆕 Новое','#EFF6FF','#2563EB'],discussion:['💬 На обсуждении','#FEF3C7','#92400E'],accepted:['✅ Принято','#D1FAE5','#047857'],rejected:['❌ Отклонено','#FEE2E2','#B91C1C']}; +const SUG_ST={new:[ic('dot',12)+' Новое','#EFF6FF','#2563EB'],discussion:[ic('message',12)+' На обсуждении','#FEF3C7','#92400E'],accepted:[ic('checkCircle',12)+' Принято','#D1FAE5','#047857'],rejected:[ic('close',12)+' Отклонено','#FEE2E2','#B91C1C']}; function openIdeas(){ const sgs=state.suggestions||[]; const list=sgs.length?sgs.map(s=>{const st=SUG_ST[s.status]||SUG_ST.new;return `
${esc(s.text)}
${st[0]}${s.decision?`— ${esc(s.decision)}`:''}
`}).join(''):'
Пока нет. Предложите первую идею — мы рассмотрим её.
'; @@ -522,7 +527,7 @@ function toggleAsk(){document.getElementById("askDock").classList.toggle("open") function addAsk(role,text,dev){ const t=document.getElementById("askThread");if(!t)return; const m=document.createElement("div");m.className="am "+(role==="user"?"u":"e"); - m.innerHTML=`
${role==="user"?"Я":"Е"}
${fmt(text)}${dev?'
⚠ Ваше пожелание зафиксировано — учтём при внедрении
':''}
`; + m.innerHTML=`
${role==="user"?"Я":"Е"}
${fmt(text)}${dev?'
'+ic('alert',12)+' Ваше пожелание зафиксировано — учтём при внедрении
':''}
`; t.appendChild(m);t.scrollTop=t.scrollHeight; } function renderAskThread(){ @@ -532,14 +537,14 @@ function renderAskThread(){ async function askAttach(files){ document.getElementById("askDock").classList.add("open"); for(const f of files){ - addAsk("user","📎 "+f.name); + addAsk("user","Файл: "+f.name); try{ const b64=await new Promise((res,rej)=>{const r=new FileReader();r.onload=()=>res(r.result);r.onerror=rej;r.readAsDataURL(f)}); const r=await fetch(`${API}/api/upload`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token,filename:f.name,content:b64})}); const d=await r.json(); if(d.error){addAsk("elena","Не удалось загрузить «"+f.name+"»: "+d.error);continue;} state.documents=state.documents||[];state.documents.push({filename:d.filename,size:d.size}); - addAsk("elena","📎 «"+f.name+"» приложен — учту его в ответах по проекту. Спрашивайте."); + addAsk("elena","Документ «"+f.name+"» приложен — учту его в ответах по проекту. Спрашивайте."); }catch(e){addAsk("elena","Ошибка загрузки: "+e.message);} } document.getElementById("askFile").value=""; @@ -598,9 +603,9 @@ async function handleFiles(files){ const b64=await new Promise((res,rej)=>{const r=new FileReader();r.onload=()=>res(r.result);r.onerror=rej;r.readAsDataURL(f)}); const r=await fetch(`${API}/api/upload`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token,filename:f.name,content:b64})}); const d=await r.json(); - if(d.error){tmp.innerHTML=`❌ ${esc(f.name)}: ${d.error}`;continue} + if(d.error){tmp.innerHTML=`${ic('alert',13)} ${esc(f.name)}: ${d.error}`;continue} state.documents=state.documents||[];state.documents.push({filename:d.filename,size:d.size}); - }catch(e){tmp.innerHTML=`❌ ${esc(f.name)}: ${e.message}`;continue} + }catch(e){tmp.innerHTML=`${ic('alert',13)} ${esc(f.name)}: ${e.message}`;continue} } renderDocs(); } @@ -657,7 +662,7 @@ async function signConfirm(){ state.signed=true; document.getElementById("signModal").classList.remove("show"); document.getElementById("signStep1").style.display="block";document.getElementById("signStep2").style.display="none"; - alert("✓ Договор подписан\nПодписант: "+d.identifier); + alert("Договор подписан.\nПодписант: "+d.identifier); document.getElementById("payModal").classList.add("show"); // сразу к оплате }catch(e){alert("Ошибка: "+e.message)} } @@ -668,7 +673,7 @@ async function payVia(method){ const r=await fetch(`${API}/api/payment/create`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token,amount,method,return_url:location.href})}); const d=await r.json(); if(d.error){alert("Ошибка: "+d.error);return} - if(method==="cash"){alert("💵 "+d.instructions);return} + if(method==="cash"){alert(d.instructions);return} if(d.demo){alert("ДЕМО-режим: ЮKassa ещё не подключена.\n\n"+d.note);return} if(d.qr){alert("СБП: отсканируйте QR в приложении банка\n\n"+(d.qr||""));return} if(d.confirmation_url){location.href=d.confirmation_url;return} @@ -733,7 +738,7 @@ function renderOrgChart(o){ ${u.reports_to&&u.reports_to!=='—'?`↑ ${esc(u.reports_to)}`:'руководство'} ${(u.owns_functions&&u.owns_functions.length)?`
Отвечает: ${u.owns_functions.map(f=>`${esc(f)}`).join('')}
`:''} - ${u.note?`
⚠ ${esc(u.note)}
`:''} + ${u.note?`
${ic('alert',12)} ${esc(u.note)}
`:''} `).join(''); return h; } @@ -745,7 +750,7 @@ function renderJobs(j){ ${(r.responsibilities&&r.responsibilities.length)?`
Зоны ответственности
    ${r.responsibilities.map(x=>`
  • ${esc(x)}
  • `).join('')}
`:''} ${(r.kpis&&r.kpis.length)?`
KPI
${r.kpis.map(k=>`${esc(k)}`).join('')}
`:''} ${(r.authority&&r.authority.length)?`
Полномочия: ${r.authority.map(a=>esc(a)).join(' · ')}
`:''} - ${r.deviation_note?`
⚠ Учтено пожелание клиента: ${esc(r.deviation_note)}
`:''} + ${r.deviation_note?`
${ic('alert',12)} Учтено пожелание клиента: ${esc(r.deviation_note)}
`:''} `).join(''); } function renderSpecPane(){ @@ -789,10 +794,10 @@ function renderEstimateCard(){ const dd=due[s.key]||''; let tag=''; if(isFree)tag='бесплатно'; - else if(isPaid)tag='✓ оплачено'; + else if(isPaid)tag=''+ic('check',11)+' оплачено'; else if(done)tag='к оплате'; else tag='в работе'; - const dueChip=(dd&&!isPaid&&!isFree)?`📅 до ${fmtD(dd)}`:''; + const dueChip=(dd&&!isPaid&&!isFree)?`${ic('calendar',11)} до ${fmtD(dd)}`:''; return `
${s.icon}
${s.name} ${tag} ${dueChip}
${s.desc}
@@ -808,7 +813,7 @@ function renderEstimateCard(){ } function renderExportBar(){ if(state.unlocked){ - return renderEstimateCard()+`
📦 Готовые документы
+ return renderEstimateCard()+`
${ic('crm',17)} Готовые документы
Долг закрыт — документы и ТЗ доступны для печати и выгрузки.
@@ -829,8 +834,8 @@ function buildTZmd(s){ (s.roles||[]).forEach(r=>m+=`- **${r.name}** — ${r.does} (доступ: ${r.access})\n`); m+=`\n## B. Модули\n`;(s.modules||[]).forEach(x=>{m+=`### ${x.name} [${x.source_node}]\n${x.purpose}\nЭкраны: ${(x.screens||[]).join(', ')}\nДанные: вход — ${x.inputs_data}; выход — ${x.outputs_data}\n`;(x.rules||[]).forEach(r=>m+=`- правило: ${r}\n`);m+=`\n`}); m+=`## C. Модель данных\n`;(s.entities||[]).forEach(e=>{m+=`### ${e.name}\n`;(e.fields||[]).forEach(f=>m+=`- ${f.field}: ${f.type}\n`);if((e.relations||[]).length)m+=`Связи: ${e.relations.join(' · ')}\n`;m+=`Пример: ${e.example}\n\n`}); - if(state.orgchart&&(state.orgchart.units||[]).length){m+=`\n## D. Оргструктура\n${state.orgchart.insight||''}\n`;state.orgchart.units.forEach(u=>{m+=`- **${u.role}** (${(+u.headcount||1)} чел.)${u.reports_to&&u.reports_to!=='—'?` ↑ ${u.reports_to}`:''}${(u.owns_functions||[]).length?` — отвечает: ${u.owns_functions.join(', ')}`:''}${u.note?` ⚠ ${u.note}`:''}\n`})} - if(state.jobs&&(state.jobs.roles||[]).length){m+=`\n## E. Должностные инструкции\n`;state.jobs.roles.forEach(r=>{m+=`### ${r.role}\n${r.purpose||''}${r.reports_to?` (подчинение: ${r.reports_to})`:''}\n`;(r.responsibilities||[]).forEach(x=>m+=`- ${x}\n`);if((r.kpis||[]).length)m+=`KPI: ${r.kpis.join(' · ')}\n`;if((r.authority||[]).length)m+=`Полномочия: ${r.authority.join(' · ')}\n`;if(r.deviation_note)m+=`⚠ Учтено пожелание клиента: ${r.deviation_note}\n`;m+=`\n`})} + if(state.orgchart&&(state.orgchart.units||[]).length){m+=`\n## D. Оргструктура\n${state.orgchart.insight||''}\n`;state.orgchart.units.forEach(u=>{m+=`- **${u.role}** (${(+u.headcount||1)} чел.)${u.reports_to&&u.reports_to!=='—'?` ↑ ${u.reports_to}`:''}${(u.owns_functions||[]).length?` — отвечает: ${u.owns_functions.join(', ')}`:''}${u.note?` (внимание: ${u.note})`:''}\n`})} + if(state.jobs&&(state.jobs.roles||[]).length){m+=`\n## E. Должностные инструкции\n`;state.jobs.roles.forEach(r=>{m+=`### ${r.role}\n${r.purpose||''}${r.reports_to?` (подчинение: ${r.reports_to})`:''}\n`;(r.responsibilities||[]).forEach(x=>m+=`- ${x}\n`);if((r.kpis||[]).length)m+=`KPI: ${r.kpis.join(' · ')}\n`;if((r.authority||[]).length)m+=`Полномочия: ${r.authority.join(' · ')}\n`;if(r.deviation_note)m+=`Внимание — учтено пожелание клиента: ${r.deviation_note}\n`;m+=`\n`})} if((s.open_questions||[]).length){m+=`## Уточнить перед разработкой\n`;s.open_questions.forEach(q=>m+=`- ${q}\n`)} return m; } @@ -864,8 +869,8 @@ function renderIdef(m){const box=(fn,ct,ins,outs,me,id,pct)=>{const C=(ct&&ct.le return h} function renderSpec(s){let h=`
AОбзор
${esc(s.overview)}
`; h+=`
AРоли (${s.roles.length})
`;s.roles.forEach(r=>h+=`
${esc(r.name)} — ${esc(r.does)}
Доступ: ${esc(r.access)}
`); - h+=`
BМодули (${s.modules.length})
`;s.modules.forEach(m=>h+=`
${esc(m.source_node)}${esc(m.name)}
${esc(m.purpose)}
${m.screens.map(s=>`${esc(s)}`).join("")}
📥 ${esc(m.inputs_data)} · 📤 ${esc(m.outputs_data)}
${m.rules.length?`
${m.rules.map(r=>`
${esc(r)}
`).join("")}
`:''}
`); - h+=`
CМодель данных (${s.entities.length} таблиц)
`;s.entities.forEach(e=>h+=`
◆ ${esc(e.name)}
${e.fields.map(f=>`
${esc(f.field)} ${esc(f.type)}
`).join("")}
${e.relations.length?`
🔗 ${e.relations.map(esc).join(" · ")}
`:''}
${esc(e.example)}
`); + h+=`
BМодули (${s.modules.length})
`;s.modules.forEach(m=>h+=`
${esc(m.source_node)}${esc(m.name)}
${esc(m.purpose)}
${m.screens.map(s=>`${esc(s)}`).join("")}
Вход: ${esc(m.inputs_data)} · Выход: ${esc(m.outputs_data)}
${m.rules.length?`
${m.rules.map(r=>`
${esc(r)}
`).join("")}
`:''}
`); + h+=`
CМодель данных (${s.entities.length} таблиц)
`;s.entities.forEach(e=>h+=`
◆ ${esc(e.name)}
${e.fields.map(f=>`
${esc(f.field)} ${esc(f.type)}
`).join("")}
${e.relations.length?`
Связи: ${e.relations.map(esc).join(" · ")}
`:''}
${esc(e.example)}
`); if(s.open_questions&&s.open_questions.length){h+=`
Уточнить перед разработкой
${s.open_questions.map(q=>`
${esc(q)}
`).join("")}
`} return h} diff --git a/docs/crm.html b/docs/crm.html index bfdc8d6..af20ae6 100644 --- a/docs/crm.html +++ b/docs/crm.html @@ -163,7 +163,7 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
@wasrusgen1КОНСАЛТИНГ
CRM
Руслан
- +
- ${paid>0?`
💵 Наличные ${money(cash)}🏦 Безнал ${money(noncash)}
`:''} + ${paid>0?`
${ic('cash',12)} Наличные ${money(cash)}${ic('card',12)} Безнал ${money(noncash)}
`:''} ${pays.map((p,i)=>i===editPayIdx ?`
@@ -1075,7 +1087,7 @@ function renderPayments(){
` - :`
${esc(p.date||'')}${METHOD_ICON[p.method||'bank']||'🏦'}${esc(p.note||'Платёж')}${p.stage?` · этап`:''}${money(p.amount)}
`).join("")||'
Платежей нет
'} + :`
${esc(p.date||'')}${METHOD_ICON[p.method||'bank']||ic('card',13)}${esc(p.note||'Платёж')}${p.stage?` · этап`:''}${money(p.amount)}
`).join("")||'
Платежей нет
'}
@@ -1154,7 +1166,7 @@ function renderTasks(){ box.innerHTML=`
${ic('pin',16)} Задачи по клиенту
${tasks.map((t,i)=>`
${esc(t.text)}${t.due?`${t.due===today?'сегодня':fmtDate(t.due)}`:''}
`).join("")||'
Задач нет
'} -
${micBtn('newTask',34)}
+
${micBtn('newTask',34)}
`; } function fmtDate(d){const[y,m,dd]=d.split("-");return `${dd}.${m}`} @@ -1190,9 +1202,9 @@ function exportSpecPDF(){ body+=H("Модули системы");s.modules.forEach(m=>{body+=`
${esc(m.source_node)} ${esc(m.name)}
${esc(m.purpose)}
Экраны: ${m.screens.map(esc).join(", ")}
Вход: ${esc(m.inputs_data)}
Выход: ${esc(m.outputs_data)}
${m.rules.length?`
Бизнес-правила:
    ${m.rules.map(r=>`
  • ${esc(r)}
  • `).join("")}
`:''}
`}); body+=H("Модель данных");s.entities.forEach(e=>{body+=`
◆ ${esc(e.name)}${e.fields.map(f=>``).join("")}
ПолеТип
${esc(f.field)}${esc(f.type)}
${e.relations.length?`
Связи: ${e.relations.map(esc).join("; ")}
`:''}
${esc(e.example)}
`}); // Оргструктура - if(state.orgchart&&(state.orgchart.units||[]).length){body+=H("Оргструктура");body+=`
${esc(state.orgchart.insight||'')}
`;state.orgchart.units.forEach(u=>{body+=`
${esc(u.role)} ${(+u.headcount||1)} чел.${u.reports_to&&u.reports_to!=='—'?` ↑ ${esc(u.reports_to)}`:''}${(u.owns_functions&&u.owns_functions.length)?`
Отвечает: ${u.owns_functions.map(esc).join(", ")}
`:''}${u.note?`
⚠ ${esc(u.note)}
`:''}
`});} + if(state.orgchart&&(state.orgchart.units||[]).length){body+=H("Оргструктура");body+=`
${esc(state.orgchart.insight||'')}
`;state.orgchart.units.forEach(u=>{body+=`
${esc(u.role)} ${(+u.headcount||1)} чел.${u.reports_to&&u.reports_to!=='—'?` ↑ ${esc(u.reports_to)}`:''}${(u.owns_functions&&u.owns_functions.length)?`
Отвечает: ${u.owns_functions.map(esc).join(", ")}
`:''}${u.note?`
${ic('alert',12)} ${esc(u.note)}
`:''}
`});} // Должностные инструкции - if(state.jobs&&(state.jobs.roles||[]).length){body+=H("Должностные инструкции");state.jobs.roles.forEach(r=>{body+=`
${esc(r.role)}
${esc(r.purpose||'')}${r.reports_to?` · ↑ ${esc(r.reports_to)}`:''}
${(r.responsibilities&&r.responsibilities.length)?`
Ответственность:
    ${r.responsibilities.map(x=>`
  • ${esc(x)}
  • `).join("")}
`:''}${(r.kpis&&r.kpis.length)?`
KPI: ${r.kpis.map(esc).join(" · ")}
`:''}${(r.authority&&r.authority.length)?`
Полномочия: ${r.authority.map(esc).join(" · ")}
`:''}${r.deviation_note?`
⚠ Учтено пожелание клиента: ${esc(r.deviation_note)}
`:''}
`});} + if(state.jobs&&(state.jobs.roles||[]).length){body+=H("Должностные инструкции");state.jobs.roles.forEach(r=>{body+=`
${esc(r.role)}
${esc(r.purpose||'')}${r.reports_to?` · ↑ ${esc(r.reports_to)}`:''}
${(r.responsibilities&&r.responsibilities.length)?`
Ответственность:
    ${r.responsibilities.map(x=>`
  • ${esc(x)}
  • `).join("")}
`:''}${(r.kpis&&r.kpis.length)?`
KPI: ${r.kpis.map(esc).join(" · ")}
`:''}${(r.authority&&r.authority.length)?`
Полномочия: ${r.authority.map(esc).join(" · ")}
`:''}${r.deviation_note?`
${ic('alert',12)} Учтено пожелание клиента: ${esc(r.deviation_note)}
`:''}
`});} if(s.open_questions&&s.open_questions.length){body+=H("Уточнить перед разработкой")+`
    ${s.open_questions.map(q=>`
  • ${esc(q)}
  • `).join("")}
`} w.document.write(`ТЗ — ${cn}