mirror of
https://github.com/wasrusgen/zov-tech.git
synced 2026-06-03 21:44:48 +00:00
feat: поиск клиентов на главном экране (фильтр по ФИО / телефону / договору)
- clients.js: renderList — поле поиска над списком, renderFiltered() фильтрует без API-запроса - фильтрация: имя (подстрока), телефон (только цифры), номер договора - счётчик обновляется: «Найдено N из M» при поиске, полная статистика без запроса - podbor.css: .client-search-wrap, .client-search, .client-search-meta - index.html: cache bump → v=20260514n Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
bfd661575c
commit
715ac96de8
@ -408,6 +408,15 @@ const Clients = (function () {
|
|||||||
});
|
});
|
||||||
root.appendChild(addBtn);
|
root.appendChild(addBtn);
|
||||||
|
|
||||||
|
// Поиск (рендерится сразу, до загрузки)
|
||||||
|
const searchWrap = el(`
|
||||||
|
<div class="client-search-wrap">
|
||||||
|
<input class="client-search" type="search" placeholder="🔍 Поиск по имени, телефону, договору…" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
root.appendChild(searchWrap);
|
||||||
|
const searchInput = searchWrap.querySelector(".client-search");
|
||||||
|
|
||||||
const loading = el(`<div class="loader-inline"><div class="spinner"></div></div>`);
|
const loading = el(`<div class="loader-inline"><div class="spinner"></div></div>`);
|
||||||
root.appendChild(loading);
|
root.appendChild(loading);
|
||||||
|
|
||||||
@ -434,18 +443,42 @@ const Clients = (function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = el(`
|
const metaEl = el(`<div class="kicker client-search-meta" style="margin-bottom:8px;"></div>`);
|
||||||
<div class="kicker" style="margin-bottom:8px;">
|
root.appendChild(metaEl);
|
||||||
${data.count} ${pluralize(data.count, "клиент", "клиента", "клиентов")} · ${countLeads(data.clients)} ${pluralize(countLeads(data.clients), "подбор", "подбора", "подборов")}
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
root.appendChild(meta);
|
|
||||||
|
|
||||||
const list = el(`<div class="client-list"></div>`);
|
const list = el(`<div class="client-list"></div>`);
|
||||||
for (const c of data.clients) {
|
root.appendChild(list);
|
||||||
|
|
||||||
|
function renderFiltered(q) {
|
||||||
|
q = (q || "").trim().toLowerCase();
|
||||||
|
const qDigits = q.replace(/\D/g, "");
|
||||||
|
const filtered = q
|
||||||
|
? data.clients.filter(c => {
|
||||||
|
const nameMatch = (c.client_name || "").toLowerCase().includes(q);
|
||||||
|
const phoneMatch = qDigits && (c.client_phone || "").replace(/\D/g, "").includes(qDigits);
|
||||||
|
const contractMatch = (c.contract_no || "").toLowerCase().includes(q);
|
||||||
|
return nameMatch || phoneMatch || contractMatch;
|
||||||
|
})
|
||||||
|
: data.clients;
|
||||||
|
|
||||||
|
const n = filtered.length;
|
||||||
|
const total = data.clients.length;
|
||||||
|
metaEl.textContent = q
|
||||||
|
? `Найдено: ${n} из ${total}`
|
||||||
|
: `${total} ${pluralize(total, "клиент", "клиента", "клиентов")} · ${countLeads(data.clients)} ${pluralize(countLeads(data.clients), "подбор", "подбора", "подборов")}`;
|
||||||
|
|
||||||
|
list.innerHTML = "";
|
||||||
|
if (!filtered.length) {
|
||||||
|
list.innerHTML = `<div class="picker-empty-state" style="padding:32px 0;text-align:center;color:var(--muted);">Ничего не найдено</div>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const c of filtered) {
|
||||||
list.appendChild(renderClientCard(c));
|
list.appendChild(renderClientCard(c));
|
||||||
}
|
}
|
||||||
root.appendChild(list);
|
}
|
||||||
|
|
||||||
|
searchInput.addEventListener("input", () => renderFiltered(searchInput.value));
|
||||||
|
renderFiltered("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderClientCard(c) {
|
function renderClientCard(c) {
|
||||||
|
|||||||
@ -3358,6 +3358,30 @@
|
|||||||
border-top: 1px dashed var(--line);
|
border-top: 1px dashed var(--line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== Поиск по списку клиентов ===== */
|
||||||
|
.client-search-wrap {
|
||||||
|
padding: 0 0 10px;
|
||||||
|
}
|
||||||
|
.client-search {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: var(--paper, #FBF7F0);
|
||||||
|
border: 1.5px solid rgba(107,74,43,0.18);
|
||||||
|
border-radius: 10px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--ink, #1F1A14);
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
.client-search:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--walnut, #6B4A2B);
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
.client-search::placeholder { color: var(--muted, #998877); }
|
||||||
|
.client-search-meta { transition: color 0.15s; }
|
||||||
|
|
||||||
/* ===== Поля адреса (addr-grid) ===== */
|
/* ===== Поля адреса (addr-grid) ===== */
|
||||||
.addr-grid {
|
.addr-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@ -12,14 +12,14 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap">
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap">
|
||||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||||
<link rel="stylesheet" href="assets/styles.css?v=20260514m">
|
<link rel="stylesheet" href="assets/styles.css?v=20260514n">
|
||||||
<link rel="stylesheet" href="assets/podbor.css?v=20260514m">
|
<link rel="stylesheet" href="assets/podbor.css?v=20260514n">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Splash — лого @wasrusgen1 + опилки (16) + вращающийся диск -->
|
<!-- Splash — лого @wasrusgen1 + опилки (16) + вращающийся диск -->
|
||||||
<div class="loader splash" id="splash">
|
<div class="loader splash" id="splash">
|
||||||
<div class="brand-logo-wrap">
|
<div class="brand-logo-wrap">
|
||||||
<img class="brand-logo" src="assets/wasrusgen-logo.svg?v=20260514m" alt="@wasrusgen1">
|
<img class="brand-logo" src="assets/wasrusgen-logo.svg?v=20260514n" alt="@wasrusgen1">
|
||||||
<div class="splash-dust" aria-hidden="true">
|
<div class="splash-dust" aria-hidden="true">
|
||||||
<span class="dust d1"></span> <span class="dust d2"></span>
|
<span class="dust d1"></span> <span class="dust d2"></span>
|
||||||
<span class="dust d3"></span> <span class="dust d4"></span>
|
<span class="dust d3"></span> <span class="dust d4"></span>
|
||||||
@ -35,15 +35,15 @@
|
|||||||
<div class="brand-tagline-gold">CRM</div>
|
<div class="brand-tagline-gold">CRM</div>
|
||||||
</div>
|
</div>
|
||||||
<main id="app"></main>
|
<main id="app"></main>
|
||||||
<script src="assets/icons.js?v=20260514m"></script>
|
<script src="assets/icons.js?v=20260514n"></script>
|
||||||
<script src="assets/podbor.config.js?v=20260514m"></script>
|
<script src="assets/podbor.config.js?v=20260514n"></script>
|
||||||
<script src="assets/podbor.picts.js?v=20260514m"></script>
|
<script src="assets/podbor.picts.js?v=20260514n"></script>
|
||||||
<script src="assets/podbor.js?v=20260514m"></script>
|
<script src="assets/podbor.js?v=20260514n"></script>
|
||||||
<script src="assets/clients.js?v=20260514m"></script>
|
<script src="assets/clients.js?v=20260514n"></script>
|
||||||
<script src="assets/zamer-picts.js?v=20260514m"></script>
|
<script src="assets/zamer-picts.js?v=20260514n"></script>
|
||||||
<script src="assets/measurements.js?v=20260514m"></script>
|
<script src="assets/measurements.js?v=20260514n"></script>
|
||||||
<script src="assets/request.js?v=20260514m"></script>
|
<script src="assets/request.js?v=20260514n"></script>
|
||||||
<script src="assets/assembly.js?v=20260514m"></script>
|
<script src="assets/assembly.js?v=20260514n"></script>
|
||||||
<script src="assets/app.js?v=20260514m"></script>
|
<script src="assets/app.js?v=20260514n"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user