mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 15:44:45 +00:00
ui: вкладка Сделка — плотный обзор клиента (прогресс+финансы+контакт+заметка)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6828ecfeb3
commit
984ead3f2f
@ -305,6 +305,11 @@ function renderMainPanel(){
|
|||||||
const p=document.getElementById("mainPanel");if(!p)return;
|
const p=document.getElementById("mainPanel");if(!p)return;
|
||||||
const crm=state.crm||{pipeline:"lead",deal_amount:0,source:""};
|
const crm=state.crm||{pipeline:"lead",deal_amount:0,source:""};
|
||||||
if(mainTab==="deal"){
|
if(mainTab==="deal"){
|
||||||
|
const deal=crm.deal_amount||0;
|
||||||
|
const pays=crm.payments||[]; const paid=pays.reduce((s,x)=>s+(x.amount||0),0); const left=Math.max(0,deal-paid);
|
||||||
|
const doneArr=CLIENT_STAGES.map(s=>stageIsDone(s.key));
|
||||||
|
const firstUndone=doneArr.findIndex(d=>!d);
|
||||||
|
const doneCnt=doneArr.filter(Boolean).length;
|
||||||
p.innerHTML=`
|
p.innerHTML=`
|
||||||
<div class="cc-grid">
|
<div class="cc-grid">
|
||||||
<div class="cc-field"><div class="cc-fl">Статус воронки</div><select class="cc-sel" id="cpPipe" onchange="saveCrm()">${PIPE.map(([k,n])=>`<option value="${k}" ${crm.pipeline===k?'selected':''}>${n}</option>`).join("")}</select></div>
|
<div class="cc-field"><div class="cc-fl">Статус воронки</div><select class="cc-sel" id="cpPipe" onchange="saveCrm()">${PIPE.map(([k,n])=>`<option value="${k}" ${crm.pipeline===k?'selected':''}>${n}</option>`).join("")}</select></div>
|
||||||
@ -312,7 +317,36 @@ function renderMainPanel(){
|
|||||||
<div class="cc-field"><div class="cc-fl">Источник</div><input class="cc-fi" id="cpSrc" value="${esc(crm.source||'')}" placeholder="откуда пришёл" onchange="saveCrm()"></div>
|
<div class="cc-field"><div class="cc-fl">Источник</div><input class="cc-fi" id="cpSrc" value="${esc(crm.source||'')}" placeholder="откуда пришёл" onchange="saveCrm()"></div>
|
||||||
<div class="cc-field" id="payStatusBox"></div>
|
<div class="cc-field" id="payStatusBox"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cc-actions"><button class="btn btn-p" onclick="inviteLink()">🔗 Ссылка клиенту</button><button class="btn btn-p" style="background:#0088cc" onclick="inviteTelegram()">✈ В Telegram</button><a class="btn btn-g" href="cabinet.html?t=${current}" target="_blank">👁 Открыть кабинет</a><button class="btn btn-g" style="margin-left:auto;border-color:#FECACA;color:#DC2626" onclick="deleteClient()">🗑 Удалить</button></div>`;
|
<div class="cc-actions"><button class="btn btn-p" onclick="inviteLink()">🔗 Ссылка клиенту</button><button class="btn btn-p" style="background:#0088cc" onclick="inviteTelegram()">✈ В Telegram</button><a class="btn btn-g" href="cabinet.html?t=${current}" target="_blank">👁 Открыть кабинет</a><button class="btn btn-g" style="margin-left:auto;border-color:#FECACA;color:#DC2626" onclick="deleteClient()">🗑 Удалить</button></div>
|
||||||
|
<div style="display:grid;grid-template-columns:1.35fr 1fr;gap:14px;align-items:start">
|
||||||
|
<div class="blk" style="margin:0">
|
||||||
|
<div style="display:flex;align-items:center;margin-bottom:6px"><b style="font-size:13px">📍 Прогресс проекта</b><span style="margin-left:auto;font-size:11px;color:var(--muted)">${doneCnt}/5 этапов</span></div>
|
||||||
|
${CLIENT_STAGES.map((s,i)=>{
|
||||||
|
const done=doneArr[i], cur=!done&&i===firstUndone;
|
||||||
|
const brd=done?'#047857':cur?'#10B981':'#E5E7EB';
|
||||||
|
const tag=done?'<span style="font-size:10px;font-weight:700;color:#047857;background:#ECFDF5;padding:1px 7px;border-radius:5px">✓ готово</span>':cur?'<span style="font-size:10px;font-weight:700;color:#92400E;background:#FEF3C7;padding:1px 7px;border-radius:5px">● в работе</span>':'<span style="font-size:10px;font-weight:700;color:#9CA3AF;background:#F3F4F6;padding:1px 7px;border-radius:5px">ожидает</span>';
|
||||||
|
return `<div style="display:flex;align-items:center;gap:10px;padding:7px 0;border-top:1px solid var(--bg)">
|
||||||
|
<span style="width:24px;height:24px;border-radius:6px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;background:${done||cur?'#ECFDF5':'#F9FAFB'};border:1.5px solid ${brd}">${s.icon}</span>
|
||||||
|
<div style="flex:1;min-width:0"><div style="font-size:12.5px;font-weight:700;color:${done||cur?'var(--text)':'#9CA3AF'}">${s.name}</div><div style="font-size:11px;color:var(--muted)">${esc(s.desc)}</div></div>
|
||||||
|
${tag}
|
||||||
|
</div>`;
|
||||||
|
}).join('')}
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;flex-direction:column;gap:14px">
|
||||||
|
<div class="blk" style="margin:0">
|
||||||
|
<div style="font-size:13px;font-weight:700;margin-bottom:8px">💰 Финансы</div>
|
||||||
|
<div style="display:flex;justify-content:space-between;padding:5px 0;font-size:13px"><span style="color:var(--muted)">Смета</span><b>${deal>0?money(deal):'—'}</b></div>
|
||||||
|
<div style="display:flex;justify-content:space-between;padding:5px 0;font-size:13px;border-top:1px solid var(--bg)"><span style="color:var(--muted)">Получено</span><b style="color:#047857">${money(paid)}</b></div>
|
||||||
|
<div style="display:flex;justify-content:space-between;padding:5px 0;font-size:13px;border-top:1px solid var(--bg)"><span style="color:var(--muted)">Остаток</span><b style="color:${left>0?'#DC2626':'#047857'}">${money(left)}</b></div>
|
||||||
|
</div>
|
||||||
|
<div class="blk" style="margin:0">
|
||||||
|
<div class="cc-fl">Контакт</div>
|
||||||
|
<input class="cc-fi" id="cpContact" value="${esc(crm.contact||'')}" placeholder="телефон / email" onchange="saveCrm()" style="margin-bottom:12px">
|
||||||
|
<div class="cc-fl">Заметка</div>
|
||||||
|
<textarea id="cpNote" onchange="saveCrm()" placeholder="заметки по клиенту..." style="width:100%;border:none;outline:none;background:transparent;font-family:Inter;font-size:13px;resize:vertical;min-height:46px;color:var(--text)">${esc(crm.note||'')}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
renderPayments();
|
renderPayments();
|
||||||
}
|
}
|
||||||
else if(mainTab==="pricing"){p.innerHTML=`<div id="pricingBox"></div>`;renderPricing();}
|
else if(mainTab==="pricing"){p.innerHTML=`<div id="pricingBox"></div>`;renderPricing();}
|
||||||
@ -598,7 +632,10 @@ function addTask(){const t=document.getElementById("newTask").value.trim();if(!t
|
|||||||
function toggleTask(i){state.tasks[i].done=!state.tasks[i].done;saveTasks();renderClient();}
|
function toggleTask(i){state.tasks[i].done=!state.tasks[i].done;saveTasks();renderClient();}
|
||||||
function delTask(i){state.tasks.splice(i,1);saveTasks();renderClient();}
|
function delTask(i){state.tasks.splice(i,1);saveTasks();renderClient();}
|
||||||
async function saveCrm(){
|
async function saveCrm(){
|
||||||
const crm={pipeline:document.getElementById("cpPipe").value,deal_amount:+document.getElementById("cpDeal").value||0,source:document.getElementById("cpSrc").value};
|
const g=id=>document.getElementById(id);
|
||||||
|
const crm={pipeline:g("cpPipe").value,deal_amount:+g("cpDeal").value||0,source:g("cpSrc").value};
|
||||||
|
if(g("cpContact"))crm.contact=g("cpContact").value;
|
||||||
|
if(g("cpNote"))crm.note=g("cpNote").value;
|
||||||
state.crm={...state.crm,...crm};
|
state.crm={...state.crm,...crm};
|
||||||
await fetch(`${API}/api/project/crm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,...crm})});
|
await fetch(`${API}/api/project/crm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,...crm})});
|
||||||
await loadProjects();
|
await loadProjects();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user