diff --git a/docs/crm.html b/docs/crm.html index 3ca2978..41f3bac 100644 --- a/docs/crm.html +++ b/docs/crm.html @@ -165,6 +165,9 @@ function saveUi(){try{localStorage.setItem('crm_ui',JSON.stringify(ui))}catch(e) function toggleSec(k){ui.collapsed[k]=!ui.collapsed[k];saveUi();renderDashboard();} function setClientFilter(f){ui.clientFilter=f;saveUi();renderDashboard();} function setTaskFilter(f){ui.taskFilter=f;saveUi();renderDashboard();} +function setClientSearch(v){ui.clientSearch=v;renderDashboard();const el=document.getElementById('clientSearch');if(el){el.focus();const L=el.value.length;try{el.setSelectionRange(L,L);}catch(e){}}} +function setClientSort(k){if(ui.clientSort===k)ui.clientSortDir=(ui.clientSortDir||1)*-1;else{ui.clientSort=k;ui.clientSortDir=1;}saveUi();renderDashboard();} +function projStageCnt(p){return [p.msg_count>0,!!p.has_selection,!!p.has_canvas,!!p.has_idef0,!!p.has_spec].filter(Boolean).length;} function secHead(k,title,right){ const col=!!ui.collapsed[k]; return `
@@ -230,12 +233,28 @@ function renderDashboard(){ else if(cf==='active')cl=projects.filter(p=>pipeOf(p)==='active'); else if(cf==='done')cl=projects.filter(p=>pipeOf(p)==='done'); else if(cf==='free')cl=projects.filter(p=>((p.crm&&p.crm.billing_type))==='free'); + const q=(ui.clientSearch||'').toLowerCase().trim(); + if(q)cl=cl.filter(p=>(((p.client_name||'')+' '+(p.niche||'')).toLowerCase().indexOf(q)>=0)); + const sk=ui.clientSort||'name', dir=ui.clientSortDir||1; + const pipeOrder={lead:0,qualified:1,proposal:2,active:3,done:4}; + cl=cl.slice().sort((a,b)=>{let av,bv; + if(sk==='amount'){av=(a.crm&&a.crm.deal_amount)||0;bv=(b.crm&&b.crm.deal_amount)||0;} + else if(sk==='stage'){av=projStageCnt(a);bv=projStageCnt(b);} + else if(sk==='status'){av=pipeOrder[pipeOf(a)]||0;bv=pipeOrder[pipeOf(b)]||0;} + else {av=(a.client_name||'').toLowerCase();bv=(b.client_name||'').toLowerCase();} + if(avbv)return dir;return 0;}); const cChips=chips(cf,[['all','Все'],['lead','Лиды'],['active','В работе'],['done','Завершён'],['free','Бесплатные']],'setClientFilter'); const head=secHead('clients',`Все клиенты · ${cl.length}`,cChips); if(ui.collapsed.clients)return head; if(!projects.length)return head+'
Создайте первого клиента
'; - if(!cl.length)return head+'
Нет клиентов по фильтру
'; - return head+`
${cl.map(p=>renderClientRow(p)).join("")}
`; + const arrow=k=>ui.clientSort===k?(dir<0?' ↓':' ↑'):''; + const bar=`
+ + Сортировка: + ${[['name','Имя'],['amount','Сумма'],['stage','Этап'],['status','Статус']].map(([k,n])=>``).join('')} +
`; + if(!cl.length)return head+bar+'
Ничего не найдено
'; + return head+bar+`
${cl.map(p=>renderClientRow(p)).join("")}
`; })()}`; } const STAGE_DEFS=[{key:"interview",name:"Интервью"},{key:"methods",name:"Методологии"},{key:"canvas",name:"Стратегия"},{key:"idef0",name:"Функции"},{key:"spec",name:"ТЗ"}];