mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 16:44:46 +00:00
feat: production blocks 1-3 — invite links, server-side checkpoints, CRM↔client binding
This commit is contained in:
parent
dfad10bbff
commit
ade80274ff
@ -227,7 +227,10 @@ body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);displ
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
const API="https://claude-83-172-150-111.sslip.io/elena";
|
const API="https://claude-83-172-150-111.sslip.io/elena";
|
||||||
let token=localStorage.getItem("cab_token"), state=null, cur=1;
|
// Доступ: токен из ссылки-приглашения (?t=) имеет приоритет
|
||||||
|
const urlToken=new URLSearchParams(location.search).get("t");
|
||||||
|
if(urlToken)localStorage.setItem("cab_token",urlToken);
|
||||||
|
let token=urlToken||localStorage.getItem("cab_token"), state=null, cur=1;
|
||||||
const chat=document.getElementById("chat"), inp=document.getElementById("inp");
|
const chat=document.getElementById("chat"), inp=document.getElementById("inp");
|
||||||
const PCTS={1:20,2:40,3:60,4:80,5:100};
|
const PCTS={1:20,2:40,3:60,4:80,5:100};
|
||||||
function esc(s){return (s||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}
|
function esc(s){return (s||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}
|
||||||
|
|||||||
@ -188,9 +188,19 @@ const TABS=[
|
|||||||
{id:"idef0",name:"Функции",icon:"🔧"},
|
{id:"idef0",name:"Функции",icon:"🔧"},
|
||||||
{id:"spec",name:"ТЗ",icon:"📋"}
|
{id:"spec",name:"ТЗ",icon:"📋"}
|
||||||
];
|
];
|
||||||
function approved(stage){return localStorage.getItem(`appr_${current}_${stage}`)==="1"}
|
function approved(stage){return state.approvals && state.approvals[stage]}
|
||||||
function approve(stage){localStorage.setItem(`appr_${current}_${stage}`,"1");renderMain()}
|
async function approve(stage){
|
||||||
function unapprove(stage){localStorage.removeItem(`appr_${current}_${stage}`);renderMain()}
|
await fetch(`${API}/api/project/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,stage,approved:true})});
|
||||||
|
state.approvals=state.approvals||{};state.approvals[stage]=new Date().toISOString();renderMain();
|
||||||
|
}
|
||||||
|
async function unapprove(stage){
|
||||||
|
await fetch(`${API}/api/project/approve`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:current,stage,approved:false})});
|
||||||
|
if(state.approvals)delete state.approvals[stage];renderMain();
|
||||||
|
}
|
||||||
|
function inviteLink(){
|
||||||
|
const url=`${location.origin}${location.pathname.replace('crm.html','cabinet.html')}?t=${current}`;
|
||||||
|
navigator.clipboard.writeText(url).then(()=>alert("Ссылка для клиента скопирована:\n\n"+url)).catch(()=>prompt("Ссылка для клиента:",url));
|
||||||
|
}
|
||||||
|
|
||||||
function renderMain(){
|
function renderMain(){
|
||||||
const p=projects.find(x=>x.token===current);
|
const p=projects.find(x=>x.token===current);
|
||||||
@ -198,6 +208,7 @@ function renderMain(){
|
|||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<div class="tb-av">${esc((state.client_name||'?')[0])}</div>
|
<div class="tb-av">${esc((state.client_name||'?')[0])}</div>
|
||||||
<div><div class="tb-name">${esc(state.client_name||'Без имени')}</div><div class="tb-meta">${esc(state.niche||'')} · ${state.messages.length} сообщений</div></div>
|
<div><div class="tb-name">${esc(state.client_name||'Без имени')}</div><div class="tb-meta">${esc(state.niche||'')} · ${state.messages.length} сообщений</div></div>
|
||||||
|
<button class="cp-btn cp-redo" style="margin-left:auto" onclick="inviteLink()">🔗 Ссылка клиенту</button>
|
||||||
<div class="tb-status">${esc(statusLabel(state.status))}</div>
|
<div class="tb-status">${esc(statusLabel(state.status))}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs">${TABS.map(t=>`<div class="tab ${t.id===activeTab?'active':''} ${approved(t.id)?'done':''}" onclick="setTab('${t.id}')">${t.icon} ${t.name}<span class="tab-check">✓</span></div>`).join("")}</div>
|
<div class="tabs">${TABS.map(t=>`<div class="tab ${t.id===activeTab?'active':''} ${approved(t.id)?'done':''}" onclick="setTab('${t.id}')">${t.icon} ${t.name}<span class="tab-check">✓</span></div>`).join("")}</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user