mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 17:44:46 +00:00
feat: Клиенты — список с фильтрами (Все/Лиды/Активные/Закрытые) и поиском, карточка открывается из списка
This commit is contained in:
parent
6f0e54c0bd
commit
297fcf90e6
@ -1844,7 +1844,8 @@ function renderScreen(id) {
|
|||||||
if (id==='manager_schedule') return screenSchedule();
|
if (id==='manager_schedule') return screenSchedule();
|
||||||
if (id==='manager_calc') return screenCalc();
|
if (id==='manager_calc') return screenCalc();
|
||||||
if (id==='manager_salary') return screenSalary();
|
if (id==='manager_salary') return screenSalary();
|
||||||
if (id==='manager_client') return screenClient();
|
if (id==='manager_client') return screenClientsList();
|
||||||
|
if (id==='manager_client_card') return screenClient();
|
||||||
if (id==='manager_own_tech') return screenOwnTech();
|
if (id==='manager_own_tech') return screenOwnTech();
|
||||||
if (id==='manager_tech_client') return screenTechClient();
|
if (id==='manager_tech_client') return screenTechClient();
|
||||||
if (id==='manager_kb') return screenKB();
|
if (id==='manager_kb') return screenKB();
|
||||||
@ -3633,7 +3634,118 @@ function _renderSendPreview(msg, sel){
|
|||||||
+'</div></div>';
|
+'</div></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── CLIENT ────────────────────────────────────────────────────────────────────
|
// ── CLIENTS LIST ─────────────────────────────────────────────────────────────
|
||||||
|
window._clientFilter = window._clientFilter || 'all';
|
||||||
|
window._clientSearch = window._clientSearch || '';
|
||||||
|
|
||||||
|
function screenClientsList() {
|
||||||
|
var all = window._managerOrders || [];
|
||||||
|
var filter = window._clientFilter;
|
||||||
|
var search = (window._clientSearch || '').toLowerCase();
|
||||||
|
|
||||||
|
// Фильтрация
|
||||||
|
var filtered = all.filter(function(o) {
|
||||||
|
var matchFilter =
|
||||||
|
filter === 'all' ? true :
|
||||||
|
filter === 'leads' ? !!o.isLead :
|
||||||
|
filter === 'active' ? (!o.isLead && o.stage < 7) :
|
||||||
|
filter === 'done' ? (!o.isLead && o.stage >= 7) : true;
|
||||||
|
var matchSearch = !search || o.client.toLowerCase().indexOf(search) >= 0
|
||||||
|
|| (o.contract||'').toLowerCase().indexOf(search) >= 0
|
||||||
|
|| (o.label||'').toLowerCase().indexOf(search) >= 0;
|
||||||
|
return matchFilter && matchSearch;
|
||||||
|
});
|
||||||
|
|
||||||
|
var counts = {
|
||||||
|
all: all.length,
|
||||||
|
leads: all.filter(function(o){ return !!o.isLead; }).length,
|
||||||
|
active: all.filter(function(o){ return !o.isLead && o.stage < 7; }).length,
|
||||||
|
done: all.filter(function(o){ return !o.isLead && o.stage >= 7; }).length,
|
||||||
|
};
|
||||||
|
|
||||||
|
var stageLabel = ['','Замер','Проект','Техника','Технолог','Производство','Сборка','Закрыт'];
|
||||||
|
var stageColor = ['','#3B82F6','#8B5CF6','#F59E0B','#EF4444','#10B981','#0891B2','#6B7280'];
|
||||||
|
var leadStageLabel = {new:'Новый',meeting:'Замер',kp:'КП',thinking:'Думает',done:'Договор'};
|
||||||
|
var typeIcon = {kitchen:'🍳', wardrobe:'🚪', other:'📦'};
|
||||||
|
|
||||||
|
// Фильтр-таб
|
||||||
|
var tabs = [
|
||||||
|
{key:'all', label:'Все', cnt:counts.all},
|
||||||
|
{key:'leads', label:'Лиды', cnt:counts.leads},
|
||||||
|
{key:'active', label:'Активные', cnt:counts.active},
|
||||||
|
{key:'done', label:'Закрытые', cnt:counts.done},
|
||||||
|
];
|
||||||
|
var tabHtml = '<div style="display:flex;gap:6px;padding:10px 16px;overflow-x:auto;scrollbar-width:none">'
|
||||||
|
+ tabs.map(function(t) {
|
||||||
|
var active = filter === t.key;
|
||||||
|
return '<div onclick="window._clientFilter=\''+t.key+'\';_nav(\'manager_client\')" '
|
||||||
|
+'style="padding:6px 13px;border-radius:20px;font-size:12px;font-weight:700;cursor:pointer;white-space:nowrap;flex-shrink:0;'
|
||||||
|
+(active ? 'background:var(--accent);color:#fff;' : 'background:var(--card);color:var(--muted);border:1.5px solid rgba(0,0,0,.08);')
|
||||||
|
+'">'+t.label+(t.cnt > 0 ? ' <span style="opacity:.7">'+t.cnt+'</span>' : '')+'</div>';
|
||||||
|
}).join('')
|
||||||
|
+ '</div>';
|
||||||
|
|
||||||
|
// Поиск
|
||||||
|
var searchHtml = '<div style="padding:0 16px 10px">'
|
||||||
|
+'<div style="background:var(--card);border-radius:12px;border:1.5px solid rgba(0,0,0,.07);display:flex;align-items:center;padding:0 12px;gap:8px">'
|
||||||
|
+'<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="flex-shrink:0;color:var(--muted)"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>'
|
||||||
|
+'<input id="clientSearch" type="text" placeholder="Поиск по имени, договору…" value="'+window._clientSearch+'" '
|
||||||
|
+'oninput="window._clientSearch=this.value;_nav(\'manager_client\')" '
|
||||||
|
+'style="flex:1;border:none;outline:none;font-size:13px;color:var(--ink);background:transparent;padding:10px 0">'
|
||||||
|
+(window._clientSearch ? '<button onclick="window._clientSearch=\'\';_nav(\'manager_client\')" style="border:none;background:none;color:var(--muted);cursor:pointer;font-size:16px;padding:0">×</button>' : '')
|
||||||
|
+'</div></div>';
|
||||||
|
|
||||||
|
// Список карточек
|
||||||
|
var listHtml = filtered.length === 0
|
||||||
|
? '<div style="padding:40px 16px;text-align:center;color:var(--muted);font-size:14px">Клиентов не найдено</div>'
|
||||||
|
: filtered.map(function(o, i) {
|
||||||
|
var idx = all.indexOf(o);
|
||||||
|
var initials = o.client.split(' ').slice(0,2).map(function(w){ return w[0]; }).join('');
|
||||||
|
var avatarColor = o.isLead ? '#F59E0B' : stageColor[o.stage] || '#3B82F6';
|
||||||
|
var stageText = o.isLead
|
||||||
|
? (leadStageLabel[o.leadStage] || 'Лид')
|
||||||
|
: (stageLabel[o.stage] || '');
|
||||||
|
var stageCol = o.isLead ? '#F59E0B'
|
||||||
|
: (o.stage >= 7 ? '#6B7280' : stageColor[o.stage] || '#3B82F6');
|
||||||
|
var icon = typeIcon[o.type] || '📦';
|
||||||
|
var hasBlocker = !!o.blocker;
|
||||||
|
|
||||||
|
return '<div onclick="window._activeOrder='+idx+';_nav(\'manager_client_card\')" '
|
||||||
|
+'style="display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1px solid rgba(0,0,0,.05);cursor:pointer;active:background:var(--bg)">'
|
||||||
|
// Аватар
|
||||||
|
+'<div style="width:40px;height:40px;border-radius:50%;background:'+avatarColor+';display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;color:#fff;flex-shrink:0">'+initials+'</div>'
|
||||||
|
// Инфо
|
||||||
|
+'<div style="flex:1;min-width:0">'
|
||||||
|
+'<div style="display:flex;align-items:center;gap:6px;margin-bottom:2px">'
|
||||||
|
+'<div style="font-size:14px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">'+o.client+'</div>'
|
||||||
|
+(hasBlocker ? '<div style="width:6px;height:6px;border-radius:50%;background:var(--danger);flex-shrink:0"></div>' : '')
|
||||||
|
+'</div>'
|
||||||
|
+'<div style="font-size:11px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">'
|
||||||
|
+icon+' '+(o.label || o.type)+(o.contract ? ' · '+o.contract : '')
|
||||||
|
+'</div>'
|
||||||
|
+'</div>'
|
||||||
|
// Статус + сумма
|
||||||
|
+'<div style="text-align:right;flex-shrink:0">'
|
||||||
|
+'<div style="font-size:11px;font-weight:700;color:'+stageCol+';margin-bottom:3px">'+stageText+'</div>'
|
||||||
|
+(o.amount ? '<div style="font-size:12px;font-weight:800;color:var(--ink)">'+Math.round(o.amount/1000)+' тыс ₽</div>' : '')
|
||||||
|
+'</div>'
|
||||||
|
+'</div>';
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
return '<div class="page">'
|
||||||
|
+'<div style="padding:14px 16px 10px;background:var(--card);border-bottom:1px solid rgba(0,0,0,.06)">'
|
||||||
|
+'<div style="font-size:18px;font-weight:800;color:var(--ink)">Клиенты</div>'
|
||||||
|
+'<div style="font-size:12px;color:var(--muted);margin-top:1px">'+all.length+' всего · '+counts.active+' активных</div>'
|
||||||
|
+'</div>'
|
||||||
|
+ tabHtml
|
||||||
|
+ searchHtml
|
||||||
|
+'<div style="background:var(--card);margin:0 16px;border-radius:14px;box-shadow:0 2px 8px rgba(0,0,0,.06);overflow:hidden">'
|
||||||
|
+ listHtml
|
||||||
|
+'</div>'
|
||||||
|
+'</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── CLIENT CARD ───────────────────────────────────────────────────────────────
|
||||||
function screenClient() {
|
function screenClient() {
|
||||||
var o=window._managerOrders[window._activeOrder]||window._managerOrders[0];
|
var o=window._managerOrders[window._activeOrder]||window._managerOrders[0];
|
||||||
var init=o.client.split(' ').slice(0,2).map(function(w){return w[0];}).join('');
|
var init=o.client.split(' ').slice(0,2).map(function(w){return w[0];}).join('');
|
||||||
@ -3710,7 +3822,7 @@ function screenClient() {
|
|||||||
{label:'Телефон', val: o.phone},
|
{label:'Телефон', val: o.phone},
|
||||||
{label:'Источник', val: 'Зал'},
|
{label:'Источник', val: 'Зал'},
|
||||||
{label:'Первый контакт', val: '03.05.2025'},
|
{label:'Первый контакт', val: '03.05.2025'},
|
||||||
{label:'Ответственный', val: 'Анна Соколова'},
|
{label:'Ответственный', val: _MGR_IDENTITY.name},
|
||||||
];
|
];
|
||||||
var infoHtml = '<div style="background:var(--card);border-radius:16px;margin:0 16px 12px;overflow:hidden">'
|
var infoHtml = '<div style="background:var(--card);border-radius:16px;margin:0 16px 12px;overflow:hidden">'
|
||||||
+infoRows.map(function(r,i){
|
+infoRows.map(function(r,i){
|
||||||
@ -3746,7 +3858,7 @@ function screenClient() {
|
|||||||
+'</div>';
|
+'</div>';
|
||||||
|
|
||||||
return '<div class="page">'
|
return '<div class="page">'
|
||||||
+'<div class="page-header"><button class="back-btn" onclick="document.getElementById(\'screen\').innerHTML=renderScreen(\'manager_order\')">'+bk+'</button><h2>Клиент</h2></div>'
|
+'<div class="page-header"><button class="back-btn" onclick="_nav(\'manager_client\')">'+bk+'</button><h2>'+o.client.split(' ')[0]+'</h2></div>'
|
||||||
// Hero
|
// Hero
|
||||||
+'<div style="display:flex;flex-direction:column;align-items:center;padding:20px 16px 16px;gap:6px">'
|
+'<div style="display:flex;flex-direction:column;align-items:center;padding:20px 16px 16px;gap:6px">'
|
||||||
+'<div style="width:72px;height:72px;border-radius:50%;background:linear-gradient(135deg,var(--accent),#1E6BB8);display:flex;align-items:center;justify-content:center;color:#fff;font-size:24px;font-weight:700;box-shadow:0 4px 16px rgba(0,62,126,.3)">'+init+'</div>'
|
+'<div style="width:72px;height:72px;border-radius:50%;background:linear-gradient(135deg,var(--accent),#1E6BB8);display:flex;align-items:center;justify-content:center;color:#fff;font-size:24px;font-weight:700;box-shadow:0 4px 16px rgba(0,62,126,.3)">'+init+'</div>'
|
||||||
@ -3962,7 +4074,7 @@ function _renderAIContract(r){
|
|||||||
function navBar() {
|
function navBar() {
|
||||||
var s=window._currentScreen||'manager_home';
|
var s=window._currentScreen||'manager_home';
|
||||||
var isHome = s==='manager_home'||s==='manager_order'||s==='manager_tech'||s==='manager_wizard'||s==='manager_result';
|
var isHome = s==='manager_home'||s==='manager_order'||s==='manager_tech'||s==='manager_wizard'||s==='manager_result';
|
||||||
var isClients = s==='manager_client'||s==='manager_lead';
|
var isClients = s==='manager_client'||s==='manager_client_card'||s==='manager_lead';
|
||||||
var isSched = s==='manager_schedule';
|
var isSched = s==='manager_schedule';
|
||||||
var isCalc = s==='manager_salary'||s==='manager_calc';
|
var isCalc = s==='manager_salary'||s==='manager_calc';
|
||||||
var isKB = s==='manager_kb';
|
var isKB = s==='manager_kb';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user