mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 15:04:47 +00:00
feat(воронка): drag-and-drop смены этапа, суммы по колонкам, степпер+бейдж на картах, моб.скролл
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0a9d924d58
commit
30160a0999
@ -66,6 +66,10 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
|
|||||||
.kcard-n{font-size:13px;font-weight:700;margin-bottom:3px}
|
.kcard-n{font-size:13px;font-weight:700;margin-bottom:3px}
|
||||||
.kcard-m{font-size:11px;color:var(--muted)}
|
.kcard-m{font-size:11px;color:var(--muted)}
|
||||||
.kcard-amt{font-size:12px;font-weight:700;color:var(--primary);margin-top:6px}
|
.kcard-amt{font-size:12px;font-weight:700;color:var(--primary);margin-top:6px}
|
||||||
|
.kcol-sum{font-size:11px;font-weight:700;color:var(--primary);padding:0 8px 4px}
|
||||||
|
.kcard[draggable=true]{cursor:grab}
|
||||||
|
.kcard.dragging{opacity:.45;cursor:grabbing}
|
||||||
|
.kcol.drop-hot{background:#ECFDF5;outline:2px dashed var(--mid);outline-offset:-2px}
|
||||||
/* Client card */
|
/* Client card */
|
||||||
.cc-top{display:flex;align-items:center;gap:14px;margin-bottom:18px}
|
.cc-top{display:flex;align-items:center;gap:14px;margin-bottom:18px}
|
||||||
.cc-av{width:48px;height:48px;border-radius:12px;background:#6366F1;display:flex;align-items:center;justify-content:center;font-weight:700;color:#fff;font-size:20px}
|
.cc-av{width:48px;height:48px;border-radius:12px;background:#6366F1;display:flex;align-items:center;justify-content:center;font-weight:700;color:#fff;font-size:20px}
|
||||||
@ -152,6 +156,7 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
|
|||||||
.cc-top{flex-wrap:wrap}
|
.cc-top{flex-wrap:wrap}
|
||||||
.cc-name{font-size:17px}
|
.cc-name{font-size:17px}
|
||||||
.sec-h{font-size:14px}
|
.sec-h{font-size:14px}
|
||||||
|
.kcol{min-width:168px}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@ -369,10 +374,44 @@ function renderUpcomingTasks(){
|
|||||||
return head+`<div class="tbl">${top.map(t=>`<div class="tbl-row" onclick="openClient('${t.token}')"><span style="font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(t.text)}</span><span style="font-size:12px;color:var(--muted);white-space:nowrap">${esc(t.client)}</span>${t.due?`<span style="font-size:11px;font-weight:700;padding:3px 9px;border-radius:6px;white-space:nowrap;${t.due<today?'background:#FEF2F2;color:#DC2626':t.due===today?'background:#FEF3C7;color:#92400E':'background:#F1F5F9;color:#6B7280'}">${t.due===today?'сегодня':t.due<today?'просрочено':fmtDate(t.due)}</span>`:''}</div>`).join("")}</div>`;
|
return head+`<div class="tbl">${top.map(t=>`<div class="tbl-row" onclick="openClient('${t.token}')"><span style="font-size:13px;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(t.text)}</span><span style="font-size:12px;color:var(--muted);white-space:nowrap">${esc(t.client)}</span>${t.due?`<span style="font-size:11px;font-weight:700;padding:3px 9px;border-radius:6px;white-space:nowrap;${t.due<today?'background:#FEF2F2;color:#DC2626':t.due===today?'background:#FEF3C7;color:#92400E':'background:#F1F5F9;color:#6B7280'}">${t.due===today?'сегодня':t.due<today?'просрочено':fmtDate(t.due)}</span>`:''}</div>`).join("")}</div>`;
|
||||||
}
|
}
|
||||||
function renderPipeline(){
|
function renderPipeline(){
|
||||||
document.getElementById("view").innerHTML=`<div class="sec-h">Воронка продаж</div><div class="kanban">${PIPE.map(([k,name,col])=>{
|
document.getElementById("view").innerHTML=`<div class="sec-h">Воронка продаж</div>
|
||||||
const items=projects.filter(p=>((p.crm&&p.crm.pipeline)||"lead")===k);
|
<div style="font-size:12px;color:var(--muted);margin:-3px 0 10px">Перетащите карточку между колонками, чтобы сменить этап сделки</div>
|
||||||
return `<div class="kcol"><div class="kcol-h"><span style="color:${col}">${name}</span><span class="kcol-c">${items.length}</span></div>${items.map(p=>`<div class="kcard" onclick="openClient('${p.token}')"><div class="kcard-n">${esc(p.client_name)}</div><div class="kcard-m">${esc(p.niche)}</div>${(p.crm&&p.crm.deal_amount)?`<div class="kcard-amt">${money(p.crm.deal_amount)}</div>`:''}</div>`).join("")}</div>`;
|
<div class="kanban">${PIPE.map(([k,name,col])=>{
|
||||||
}).join("")}</div>`;
|
const items=projects.filter(p=>((p.crm&&p.crm.pipeline)||"lead")===k);
|
||||||
|
const sum=items.reduce((s,p)=>s+((p.crm&&p.crm.deal_amount)||0),0);
|
||||||
|
return `<div class="kcol" data-pipe="${k}" ondragover="kDragOver(event)" ondragleave="kDragLeave(event)" ondrop="kDrop(event,'${k}')">
|
||||||
|
<div class="kcol-h"><span style="color:${col}">${name}</span><span class="kcol-c">${items.length}</span></div>
|
||||||
|
${sum>0?`<div class="kcol-sum">${money(sum)}</div>`:''}
|
||||||
|
${items.map(p=>kCard(p)).join("")||'<div style="font-size:11px;color:#cbd5e1;text-align:center;padding:16px 4px">пусто</div>'}
|
||||||
|
</div>`;
|
||||||
|
}).join("")}</div>`;
|
||||||
|
}
|
||||||
|
function kCard(p){
|
||||||
|
const billing=(p.crm&&p.crm.billing_type)||"paid";
|
||||||
|
const bch=billing==='free'?'<span class="mini-chip" style="color:#6366F1;background:#EEF2FF">🎁</span>':'<span class="mini-chip" style="color:#047857;background:#ECFDF5">💰</span>';
|
||||||
|
const st=clientStages(p);
|
||||||
|
let dots="";STAGE_DEFS.forEach((s,i)=>{const d=st.done[i],c=!st.all&&i===st.cur;dots+=`<span title="${s.name}" style="width:7px;height:7px;border-radius:50%;background:${d?'#047857':c?'#10B981':'#E5E7EB'};display:inline-block"></span>`;});
|
||||||
|
return `<div class="kcard" draggable="true" ondragstart="kDragStart(event,'${p.token}')" ondragend="kDragEnd(event)" onclick="openClient('${p.token}')">
|
||||||
|
<div style="display:flex;align-items:center;gap:6px;margin-bottom:3px"><span class="kcard-n" style="flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(p.client_name)}</span>${bch}</div>
|
||||||
|
<div class="kcard-m">${esc(p.niche)}</div>
|
||||||
|
<div style="display:flex;align-items:center;gap:3px;margin-top:7px">${dots}<span style="font-size:10px;color:#9ca3af;margin-left:4px">${st.cnt}/5</span></div>
|
||||||
|
${(p.crm&&p.crm.deal_amount)?`<div class="kcard-amt">${money(p.crm.deal_amount)}</div>`:''}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
let kDragToken=null;
|
||||||
|
function kDragStart(e,token){kDragToken=token;e.currentTarget.classList.add('dragging');try{e.dataTransfer.effectAllowed='move';e.dataTransfer.setData('text/plain',token);}catch(_){}}
|
||||||
|
function kDragEnd(e){e.currentTarget.classList.remove('dragging');document.querySelectorAll('.kcol').forEach(c=>c.classList.remove('drop-hot'));}
|
||||||
|
function kDragOver(e){e.preventDefault();e.currentTarget.classList.add('drop-hot');try{e.dataTransfer.dropEffect='move';}catch(_){}}
|
||||||
|
function kDragLeave(e){e.currentTarget.classList.remove('drop-hot');}
|
||||||
|
async function kDrop(e,pipe){
|
||||||
|
e.preventDefault();e.currentTarget.classList.remove('drop-hot');
|
||||||
|
const tok=kDragToken||(e.dataTransfer&&e.dataTransfer.getData('text/plain'));kDragToken=null;
|
||||||
|
if(!tok)return;
|
||||||
|
const p=projects.find(x=>x.token===tok);if(!p)return;
|
||||||
|
if(((p.crm&&p.crm.pipeline)||'lead')===pipe){renderPipeline();return;}
|
||||||
|
p.crm=p.crm||{};p.crm.pipeline=pipe;
|
||||||
|
await fetch(`${API}/api/project/crm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:tok,pipeline:pipe})});
|
||||||
|
await loadProjects();renderPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAINTABS=[{id:"deal",name:"Сделка",icon:"📇"},{id:"pricing",name:"Ценообразование",icon:"💰"},{id:"payments",name:"Платежи",icon:"💳"},{id:"tasks",name:"Задачи",icon:"📌"},{id:"analysis",name:"Анализ",icon:"📊"}];
|
const MAINTABS=[{id:"deal",name:"Сделка",icon:"📇"},{id:"pricing",name:"Ценообразование",icon:"💰"},{id:"payments",name:"Платежи",icon:"💳"},{id:"tasks",name:"Задачи",icon:"📌"},{id:"analysis",name:"Анализ",icon:"📊"}];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user