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};