mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 15:04:47 +00:00
feat(chat): авто-обновление канала Консультант (polling 15с, GET /api/operator-chat)
This commit is contained in:
parent
865b87e664
commit
4be49a25fb
@ -406,7 +406,7 @@ function go(n){
|
||||
document.getElementById('si'+n).classList.add('active');
|
||||
if(PCTS[n]!=null){document.getElementById('pbPct').textContent=PCTS[n]+'%';document.getElementById('pbFill').style.width=PCTS[n]+'%';}
|
||||
if(n===1)requestAnimationFrame(scrollChatBottom); // sv1 уже видим — высота посчитана, прыгаем вниз без «пролёта»
|
||||
if(n===6)renderOpChat();
|
||||
if(n===6){renderOpChat();startOpPoll();}else{stopOpPoll();}
|
||||
if(n===3)renderDocs();
|
||||
if(n===4)renderAnalysis();
|
||||
if(n===5)renderSpecPane();
|
||||
@ -467,6 +467,10 @@ function renderOpChat(){const c=document.getElementById("opChat");if(!c)return;c
|
||||
async function opSend(){const inp=document.getElementById("opInp");const t=inp.value.trim();if(!t)return;inp.value="";inp.style.height="auto";opMsg("user",t);state.operator_chat=state.operator_chat||[];state.operator_chat.push({role:"user",content:t});
|
||||
try{const r=await fetch(`${API}/api/operator-chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token,message:t})});const d=await r.json();if(d.messages)state.operator_chat=d.messages;}catch(e){opMsg("elena","Не доставлено: "+e.message);}
|
||||
}
|
||||
let opPollTimer=null;
|
||||
async function opPollOnce(){try{const r=await fetch(`${API}/api/operator-chat?token=${encodeURIComponent(token)}`);const d=await r.json();if(d.messages&&d.messages.length!==(state.operator_chat||[]).length){state.operator_chat=d.messages;renderOpChat();}}catch(e){}}
|
||||
function startOpPoll(){stopOpPoll();opPollOnce();opPollTimer=setInterval(opPollOnce,15000);}
|
||||
function stopOpPoll(){if(opPollTimer){clearInterval(opPollTimer);opPollTimer=null;}}
|
||||
/* ── Спросить Елену (этапы 3-5) ── */
|
||||
const STAGE_LBL={3:"о документах",4:"о стратегии и модели",5:"о ТЗ и плане"};
|
||||
function toggleAsk(){document.getElementById("askDock").classList.toggle("open")}
|
||||
|
||||
@ -320,9 +320,9 @@ async function submitNewClient(){
|
||||
await loadProjects();openClient(d.token);toast('Клиент «'+name+'» создан','ok');
|
||||
}catch(e){toast('Ошибка: '+e.message,'err');btn.disabled=false;btn.textContent='Создать →';}
|
||||
}
|
||||
function setView(v){view=v;current=null;if(window.innerWidth<=680)closeSb();document.getElementById("nav-dash").classList.toggle("active",v==="dashboard");document.getElementById("nav-pipe").classList.toggle("active",v==="pipeline");renderClientList();render();}
|
||||
function setView(v){stopCrmChatPoll();view=v;current=null;if(window.innerWidth<=680)closeSb();document.getElementById("nav-dash").classList.toggle("active",v==="dashboard");document.getElementById("nav-pipe").classList.toggle("active",v==="pipeline");renderClientList();render();}
|
||||
async function openClient(token){
|
||||
current=token;view="client";mainTab="deal";editPayIdx=-1;if(window.innerWidth<=680)closeSb();document.querySelectorAll(".nav-item").forEach(n=>n.classList.remove("active"));
|
||||
stopCrmChatPoll();current=token;view="client";mainTab="deal";editPayIdx=-1;if(window.innerWidth<=680)closeSb();document.querySelectorAll(".nav-item").forEach(n=>n.classList.remove("active"));
|
||||
const r=await fetch(`${API}/api/project/${token}`);state=await r.json();renderClientList();render();syncPaymentReminders();
|
||||
}
|
||||
function render(){
|
||||
@ -527,7 +527,7 @@ function renderClient(){
|
||||
<div id="mainPanel"></div>`;
|
||||
renderMainPanel();
|
||||
}
|
||||
function setMainTab(t){mainTab=t;editPayIdx=-1;renderMainPanel();document.querySelectorAll('.mtab').forEach((b,i)=>b.classList.toggle('active',MAINTABS[i].id===mainTab));}
|
||||
function setMainTab(t){if(t!=='chat')stopCrmChatPoll();mainTab=t;editPayIdx=-1;renderMainPanel();document.querySelectorAll('.mtab').forEach((b,i)=>b.classList.toggle('active',MAINTABS[i].id===mainTab));}
|
||||
function renderDocsTab(){
|
||||
const docs=state.documents||[];
|
||||
let h=`<div onclick="document.getElementById('opFile').click()" ondragover="event.preventDefault();this.style.background='#ECFDF5'" ondragleave="this.style.background='#fff'" ondrop="opDropFiles(event)" style="border:2px dashed var(--border);border-radius:12px;padding:20px;text-align:center;cursor:pointer;margin-bottom:14px;background:#fff;transition:background .15s">
|
||||
@ -579,6 +579,17 @@ async function opChatSend(){
|
||||
localStorage.setItem('opseen_'+current,(state.operator_chat||[]).filter(m=>m.role==='user').length);
|
||||
}catch(e){toast('Ошибка: '+e.message,'err');}
|
||||
}
|
||||
let crmChatPoll=null;
|
||||
async function crmChatPollOnce(){
|
||||
if(!current)return;
|
||||
try{const r=await fetch(`${API}/api/operator-chat?token=${encodeURIComponent(current)}`);const d=await r.json();
|
||||
if(d.messages&&d.messages.length!==(state.operator_chat||[]).length){state.operator_chat=d.messages;
|
||||
if(mainTab==='chat'){renderOpChatTab();localStorage.setItem('opseen_'+current,d.messages.filter(m=>m.role==='user').length);}
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
function startCrmChatPoll(){stopCrmChatPoll();crmChatPoll=setInterval(crmChatPollOnce,15000);}
|
||||
function stopCrmChatPoll(){if(crmChatPoll){clearInterval(crmChatPoll);crmChatPoll=null;}}
|
||||
const DEV_STAGE={canvas:"📊 Стратегия",idef0:"🔧 Функции",spec:"📋 ТЗ",documents:"📁 Документы",methods:"🎯 Методологии",interview:"💬 Интервью"};
|
||||
function renderDeviations(){
|
||||
const dev=state.deviations||[];
|
||||
@ -661,7 +672,7 @@ function renderMainPanel(){
|
||||
else if(mainTab==="tasks"){p.innerHTML=`<div id="tasksBox"></div>`;renderTasks();}
|
||||
else if(mainTab==="analysis"){p.innerHTML=`<div class="tabs">${TABS.map(t=>`<div class="tab ${t.id===activeTab?'active':''} ${approved(t.id)?'done':''}" onclick="setTab('${t.id}')">${t.icon} ${t.name}</div>`).join("")}</div><div id="tabContent"></div>`;renderTab();}
|
||||
else if(mainTab==="docs"){p.innerHTML=renderDocsTab();}
|
||||
else if(mainTab==="chat"){p.innerHTML=`<div id="opChatBox"></div>`;renderOpChatTab();localStorage.setItem('opseen_'+current,(state.operator_chat||[]).filter(m=>m.role==='user').length);document.querySelectorAll('.mtab').forEach((b,i)=>{if(MAINTABS[i].id==='chat'){const bd=b.querySelector('.badge');if(bd)bd.remove();}});}
|
||||
else if(mainTab==="chat"){p.innerHTML=`<div id="opChatBox"></div>`;renderOpChatTab();localStorage.setItem('opseen_'+current,(state.operator_chat||[]).filter(m=>m.role==='user').length);document.querySelectorAll('.mtab').forEach((b,i)=>{if(MAINTABS[i].id==='chat'){const bd=b.querySelector('.badge');if(bd)bd.remove();}});startCrmChatPoll();}
|
||||
else if(mainTab==="deviations"){p.innerHTML=renderDeviations();}
|
||||
}
|
||||
function inviteTelegram(){const url=`https://t.me/wasrusgen1_consulting_bot?start=${current}`;navigator.clipboard.writeText(url).then(()=>alert("Ссылка для Telegram скопирована:\n\n"+url+"\n\nКлиент откроет кабинет прямо в Telegram.")).catch(()=>prompt("Ссылка для Telegram:",url));}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user