diff --git a/miniapp/assets/clients.js b/miniapp/assets/clients.js index 4e1b706..8861230 100644 --- a/miniapp/assets/clients.js +++ b/miniapp/assets/clients.js @@ -419,13 +419,52 @@ const Clients = (function () { // Управление карточкой — кнопки прямо под шапкой root.appendChild(renderClientManagement(client)); - // Быстрые действия для менеджера + // Быстрые действия для менеджера — кастомные SVG-иконки в орехе + const QA_ICON_PODBOR = ` + `; + const QA_ICON_RULER = ` + `; + const QA_ICON_WRENCH = ` + `; + const QA_ICON_COPY = ` + `; const actionsRow = el(`
- - - - + + + +
`); actionsRow.querySelectorAll(".qa-btn").forEach(btn => { @@ -1233,13 +1272,11 @@ const Clients = (function () { } let rec = null; let recording = false; - let baseText = ""; // текст до начала записи — чтобы не перетирать + let baseText = ""; // что было в textarea ДО старта записи + let confirmedFinal = ""; // финальная фраза текущей сессии записи micBtn.addEventListener("click", () => { - if (recording) { - rec?.stop(); - return; - } + if (recording) { rec?.stop(); return; } try { rec = new SR(); rec.lang = "ru-RU"; @@ -1251,7 +1288,7 @@ const Clients = (function () { return; } baseText = (textarea.value || "").trim(); - const sep = baseText ? "\n" : ""; + confirmedFinal = ""; rec.onstart = () => { recording = true; @@ -1261,20 +1298,21 @@ const Clients = (function () { status.className = "note-status"; haptic && haptic("impact"); }; + // Защита от дублей: пересчитываем ВСЕ финальные и interim с нуля + // на каждом событии. Не полагаемся на ev.resultIndex (в Chrome он + // ведёт себя нестабильно при паузах — отсюда дублирование слов). rec.onresult = (ev) => { - let interim = ""; - let final = ""; - for (let i = ev.resultIndex; i < ev.results.length; i++) { + let finalAll = "", interim = ""; + for (let i = 0; i < ev.results.length; i++) { const t = ev.results[i][0].transcript; - if (ev.results[i].isFinal) final += t; + if (ev.results[i].isFinal) finalAll += t; else interim += t; } - if (final) { - baseText = (baseText + sep + final).trim(); - textarea.value = baseText; - } else if (interim) { - textarea.value = baseText + sep + interim; - } + confirmedFinal = finalAll.trim(); + const sep = baseText ? " " : ""; + const fp = confirmedFinal ? sep + confirmedFinal : ""; + const ip = interim.trim() ? ((baseText || confirmedFinal) ? " " : "") + interim.trim() : ""; + textarea.value = baseText + fp + ip; }; rec.onerror = (ev) => { status.textContent = "Ошибка распознавания: " + (ev.error || "неизвестно"); @@ -1288,6 +1326,11 @@ const Clients = (function () { micBtn.classList.remove("rec"); micBtn.textContent = "🎤 Диктовать"; if (status.textContent === "Слушаю...") status.textContent = ""; + // Фиксируем подтверждённый текст в baseText на случай повторного запуска + if (confirmedFinal) { + baseText = (baseText + (baseText ? " " : "") + confirmedFinal).trim(); + textarea.value = baseText; + } haptic && haptic("impact"); }; try { rec.start(); } diff --git a/miniapp/assets/podbor.css b/miniapp/assets/podbor.css index 73d7b7d..82d7340 100644 --- a/miniapp/assets/podbor.css +++ b/miniapp/assets/podbor.css @@ -2134,34 +2134,74 @@ } .client-call-btn:active { transform: scale(0.95); } +/* ===== Быстрые действия — 2×2 объёмные кнопки-карточки ===== */ .client-quick-actions { display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 8px; + grid-template-columns: 1fr 1fr; + gap: 10px; margin: 14px 0 18px; } -.client-quick-actions .qa-btn { + +.qa-btn { + position: relative; display: flex; flex-direction: column; align-items: center; - gap: 4px; - padding: 12px 6px; - background: var(--card, #fff); - border: 1px solid rgba(107, 74, 43, 0.18); - border-radius: 12px; + gap: 9px; + padding: 15px 10px 13px; + background: + linear-gradient(160deg, + rgba(255, 255, 255, 0.80) 0%, + rgba(245, 237, 220, 0.62) 100%); + border: 1px solid rgba(107, 74, 43, 0.16); + border-radius: 14px; cursor: pointer; font-family: inherit; - font-size: 19px; - line-height: 1; + box-shadow: + 0 2px 0 rgba(107, 74, 43, 0.20), + 0 1px 5px rgba(0, 0, 0, 0.07), + inset 0 1px 0 rgba(255, 255, 255, 0.90); + transition: transform 0.10s ease, box-shadow 0.10s ease; + -webkit-tap-highlight-color: transparent; } -.client-quick-actions .qa-btn:active { background: var(--paper-2, #F5EDDC); } -.client-quick-actions .qa-btn span { - font-size: 11px; - font-weight: 500; + +.qa-btn:active { + transform: translateY(2px); + box-shadow: + 0 0px 0 rgba(107, 74, 43, 0.20), + inset 0 1px 4px rgba(0, 0, 0, 0.14), + inset 0 0 0 1px rgba(107, 74, 43, 0.10); +} + +/* Круглый орехово-коричневый чип с иконкой */ +.qa-icon { + display: flex; + align-items: center; + justify-content: center; + width: 46px; + height: 46px; + border-radius: 50%; + background: linear-gradient(145deg, #845A2E 0%, #5C3A1C 100%); + box-shadow: + 0 2px 0 rgba(0, 0, 0, 0.24), + inset 0 1px 0 rgba(255, 255, 255, 0.18); + color: #F5DAAA; + flex-shrink: 0; +} + +.qa-icon svg { + width: 22px; + height: 22px; +} + +/* Подпись под иконкой */ +.qa-label { + font-size: 11.5px; + font-weight: 600; color: var(--ink, #1F1A14); - margin-top: 4px; - line-height: 1.2; + line-height: 1.25; text-align: center; + letter-spacing: 0.01em; } /* ===== Хронология клиента ===== */ diff --git a/miniapp/index.html b/miniapp/index.html index ddef96d..2c962da 100644 --- a/miniapp/index.html +++ b/miniapp/index.html @@ -12,14 +12,14 @@ - - + +
- +
- - - - - - - - - - + + + + + + + + + +