diff --git a/docs/crm.html b/docs/crm.html index c7a3311..5667ec3 100644 --- a/docs/crm.html +++ b/docs/crm.html @@ -180,10 +180,20 @@ function renderDashboard(){
${money(revenue)}
Выручка (оплачено)
${conv}%
Конверсия в сделку
${done} завершено
+ ${renderUpcomingTasks()}
Все клиенты · ${total}
${projects.map(p=>{const pc=pipeMap[(p.crm&&p.crm.pipeline)||"lead"];return `
${esc((p.client_name||'?')[0])}
${esc(p.client_name)}
${esc(p.niche)} · ${p.msg_count} сообщений
${pc[1]}${money((p.crm&&p.crm.deal_amount)||0)}
`}).join("")||'
Создайте первого клиента
'}`; } +function renderUpcomingTasks(){ + const today=new Date().toISOString().slice(0,10); + const all=[]; + projects.forEach(p=>(p.tasks||[]).forEach(t=>{if(!t.done)all.push({...t,client:p.client_name,token:p.token})})); + all.sort((a,b)=>(a.due||"9999")<(b.due||"9999")?-1:1); + const top=all.slice(0,6); + if(!top.length)return""; + return `
📌 Ближайшие задачи · ${all.length}
${top.map(t=>`
${esc(t.text)}${esc(t.client)}${t.due?`${t.due===today?'сегодня':t.due`:''}
`).join("")}`; +} function renderPipeline(){ document.getElementById("view").innerHTML=`
Воронка продаж
${PIPE.map(([k,name,col])=>{ const items=projects.filter(p=>((p.crm&&p.crm.pipeline)||"lead")===k); @@ -202,10 +212,27 @@ function renderClient(){
Источник
👁 Открыть кабинет
+
${TABS.map(t=>`
${t.icon} ${t.name}
`).join("")}
`; + renderTasks(); renderTab(); } +function renderTasks(){ + const box=document.getElementById("tasksBox");if(!box)return; + const tasks=state.tasks||[]; + const today=new Date().toISOString().slice(0,10); + box.innerHTML=`
+
📌 Задачи по клиенту
+ ${tasks.map((t,i)=>`
${esc(t.text)}${t.due?`${t.due===today?'сегодня':fmtDate(t.due)}`:''}
`).join("")||'
Задач нет
'} +
+
`; +} +function fmtDate(d){const[y,m,dd]=d.split("-");return `${dd}.${m}`} +async function saveTasks(){await fetch(`${API}/api/project/tasks`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,tasks:state.tasks})});await loadProjects();} +function addTask(){const t=document.getElementById("newTask").value.trim();if(!t)return;const due=document.getElementById("newTaskDue").value;state.tasks=state.tasks||[];state.tasks.push({text:t,due,done:false});renderTasks();saveTasks();} +function toggleTask(i){state.tasks[i].done=!state.tasks[i].done;renderTasks();saveTasks();} +function delTask(i){state.tasks.splice(i,1);renderTasks();saveTasks();} async function saveCrm(){ const crm={pipeline:document.getElementById("cpPipe").value,deal_amount:+document.getElementById("cpDeal").value||0,paid_amount:+document.getElementById("cpPaid").value||0,source:document.getElementById("cpSrc").value}; state.crm={...state.crm,...crm};