mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 14:24:47 +00:00
ui: правка существующих платежей в реестре (дата/сумма/назначение) + sync со сметой
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b0d0af277
commit
a621f301ce
@ -149,7 +149,7 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
|
||||
|
||||
<script>
|
||||
const API=location.hostname.indexOf("wasrusgen1.ru")>=0?"/consulting":"https://claude-83-172-150-111.sslip.io/elena";
|
||||
let projects=[], current=null, state=null, view="dashboard", activeTab="interview", mainTab="deal";
|
||||
let projects=[], current=null, state=null, view="dashboard", activeTab="interview", mainTab="deal", editPayIdx=-1;
|
||||
const PIPE=[["lead","Лид","#9ca3af"],["qualified","Квалификация","#3B82F6"],["proposal","Предложение","#8B5CF6"],["active","В работе","#047857"],["done","Завершён","#10B981"]];
|
||||
const pipeMap=Object.fromEntries(PIPE.map(p=>[p[0],p]));
|
||||
function esc(s){return (s||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}
|
||||
@ -194,7 +194,7 @@ async function newClient(){
|
||||
}
|
||||
function setView(v){view=v;current=null;document.getElementById("nav-dash").classList.toggle("active",v==="dashboard");document.getElementById("nav-pipe").classList.toggle("active",v==="pipeline");renderClientList();render();}
|
||||
async function openClient(token){
|
||||
current=token;view="client";mainTab="deal";document.querySelectorAll(".nav-item").forEach(n=>n.classList.remove("active"));
|
||||
current=token;view="client";mainTab="deal";editPayIdx=-1;document.querySelectorAll(".nav-item").forEach(n=>n.classList.remove("active"));
|
||||
const r=await fetch(`${API}/api/project/${token}`);state=await r.json();renderClientList();render();
|
||||
}
|
||||
function render(){
|
||||
@ -347,7 +347,7 @@ function renderClient(){
|
||||
<div id="mainPanel"></div>`;
|
||||
renderMainPanel();
|
||||
}
|
||||
function setMainTab(t){mainTab=t;renderMainPanel();document.querySelectorAll('.mtab').forEach((b,i)=>b.classList.toggle('active',MAINTABS[i].id===mainTab));}
|
||||
function setMainTab(t){mainTab=t;editPayIdx=-1;renderMainPanel();document.querySelectorAll('.mtab').forEach((b,i)=>b.classList.toggle('active',MAINTABS[i].id===mainTab));}
|
||||
function renderMainPanel(){
|
||||
const p=document.getElementById("mainPanel");if(!p)return;
|
||||
const crm=state.crm||{pipeline:"lead",deal_amount:0,source:""};
|
||||
@ -628,7 +628,16 @@ function renderPayments(){
|
||||
${deal>0?`<span style="margin-left:auto;font-size:12px;color:var(--muted)">Сделка ${money(deal)} · Получено ${money(paid)} · <b style="color:${left>0?'#DC2626':'#047857'}">Остаток ${money(left)}</b></span>`:'<span style="margin-left:auto"></span>'}
|
||||
${left>0?`<button class="cp-btn cp-r" style="padding:5px 10px" onclick="remindBalance(${left})">⏰ Задача на остаток</button>`:''}
|
||||
${pays.length?`<button class="cp-btn cp-r" style="padding:5px 10px" onclick="exportPayments()">⬇ CSV</button>`:''}</div>
|
||||
${pays.map((p,i)=>`<div style="display:flex;align-items:center;gap:10px;padding:7px 0;border-top:1px solid var(--bg)"><span style="font-size:12px;color:var(--muted);min-width:70px">${esc(p.date||'')}</span><span style="flex:1;font-size:13px">${esc(p.note||'Платёж')}</span><span style="font-size:13px;font-weight:700;color:#047857">${money(p.amount)}</span><button onclick="delPayment(${i})" style="border:none;background:none;cursor:pointer;color:#cbd5e1;font-size:14px">✕</button></div>`).join("")||'<div style="font-size:12px;color:#cbd5e1;padding:4px">Платежей нет</div>'}
|
||||
${pays.map((p,i)=>i===editPayIdx
|
||||
?`<div style="display:flex;align-items:center;gap:8px;padding:9px 10px;border-top:1px solid var(--bg);flex-wrap:wrap;background:var(--bg);border-radius:8px;margin-top:4px">
|
||||
<input type="date" id="epd-${i}" value="${esc(p.date||'')}" style="border:1.5px solid var(--border);border-radius:8px;padding:6px 8px;font-size:13px;font-family:Inter">
|
||||
<input type="number" id="epa-${i}" value="${p.amount||''}" style="width:100px;border:1.5px solid var(--border);border-radius:8px;padding:6px 9px;font-size:13px;font-family:Inter">
|
||||
<input id="epn-${i}" value="${esc(p.note||'')}" placeholder="Назначение" style="flex:1;min-width:120px;border:1.5px solid var(--border);border-radius:8px;padding:6px 9px;font-size:13px;font-family:Inter">
|
||||
${p.stage?`<span style="font-size:10px;color:#9CA3AF;white-space:nowrap">этап: ${esc((CLIENT_STAGES.find(s=>s.key===p.stage)||{}).name||p.stage)}</span>`:''}
|
||||
<button class="cp-btn cp-a" style="padding:6px 12px" onclick="confirmEditPayment(${i})">Сохранить</button>
|
||||
<button class="cp-btn cp-r" style="padding:6px 10px" onclick="cancelEditPayment()">✕</button>
|
||||
</div>`
|
||||
:`<div style="display:flex;align-items:center;gap:10px;padding:7px 0;border-top:1px solid var(--bg)"><span style="font-size:12px;color:var(--muted);min-width:70px">${esc(p.date||'')}</span><span style="flex:1;font-size:13px">${esc(p.note||'Платёж')}${p.stage?` <span style="font-size:10px;color:#9CA3AF">· этап</span>`:''}</span><span style="font-size:13px;font-weight:700;color:#047857">${money(p.amount)}</span><span onclick="editPayment(${i})" title="Изменить" style="cursor:pointer;color:#9CA3AF;font-size:13px">✎</span><button onclick="delPayment(${i})" title="Удалить" style="border:none;background:none;cursor:pointer;color:#cbd5e1;font-size:14px">✕</button></div>`).join("")||'<div style="font-size:12px;color:#cbd5e1;padding:4px">Платежей нет</div>'}
|
||||
<div style="display:flex;gap:8px;margin-top:10px;flex-wrap:wrap;align-items:center">
|
||||
<input id="payDate" type="date" value="${new Date().toISOString().slice(0,10)}" style="border:1.5px solid var(--border);border-radius:8px;padding:8px;font-size:13px;font-family:Inter">
|
||||
<input id="payAmt" type="number" placeholder="Сумма ₽" style="width:110px;border:1.5px solid var(--border);border-radius:8px;padding:8px 11px;font-size:13px;font-family:Inter" onkeydown="if(event.key==='Enter')addPayment()">
|
||||
@ -645,6 +654,21 @@ async function savePayments(){
|
||||
await fetch(`${API}/api/project/crm`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,payments:state.crm.payments,stage_payments:state.crm.stage_payments||{}})});
|
||||
await loadProjects();
|
||||
}
|
||||
function editPayment(i){editPayIdx=i;renderClient();}
|
||||
function cancelEditPayment(){editPayIdx=-1;renderClient();}
|
||||
function confirmEditPayment(i){
|
||||
const p=state.crm.payments[i];if(!p)return;
|
||||
const amt=+document.getElementById('epa-'+i).value;
|
||||
if(!amt){alert('Укажите сумму');return;}
|
||||
const date=document.getElementById('epd-'+i).value||p.date;
|
||||
const note=document.getElementById('epn-'+i).value;
|
||||
p.amount=amt;p.date=date;p.note=note||'Платёж';
|
||||
if(p.stage&&state.crm.stage_payments&&state.crm.stage_payments[p.stage]){
|
||||
state.crm.stage_payments[p.stage]={amount:amt,date};
|
||||
}
|
||||
editPayIdx=-1;
|
||||
savePayments();renderClient();
|
||||
}
|
||||
function addPayment(){
|
||||
const amt=+document.getElementById("payAmt").value;if(!amt){alert("Укажите сумму");return;}
|
||||
const date=document.getElementById("payDate").value;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user