From 8595a0ca168a967ba937545bd61d6ce62f1d2480 Mon Sep 17 00:00:00 2001 From: WASRUSGEN Date: Sat, 30 May 2026 13:02:21 +0300 Subject: [PATCH] feat: reminder system - date picker, overdue check on login, refuse flow --- mockup.html | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/mockup.html b/mockup.html index 04bef9e..100202f 100644 --- a/mockup.html +++ b/mockup.html @@ -5891,6 +5891,9 @@ function initReturnChat() { if (!msgs) return; msgs.innerHTML = ''; + // Проверяем просроченные напоминания — показываем ПОСЛЕ стандартного приветствия + if (typeof _checkRemindersOnStart === 'function') _checkRemindersOnStart(); + // ── Собираем персональные данные ── var lastOrder = JSON.parse(localStorage.getItem('zashita_last_order') || 'null'); var credits = parseInt(localStorage.getItem('zashita_credits') || '0'); @@ -8120,6 +8123,12 @@ function _handleMissingDoc(contractType, docId, variant, intent) { refused: 'Контрагент отказывается дать документ "' + doc.label + '" клиенту. Объясни права клиента и предложи официальный запрос + судебное истребование.' }; + // Для варианта "позже" — сразу показываем выбор даты напоминания + if (variant === 'later') { + setTimeout(function(){ _showReminderPicker(doc, contractType, intent); }, 300); + return; + } + setTimeout(function(){ _rcAddTyping(); _elenaApi(promptMap[variant] || promptMap.never, intent, function(apiReply, apiActions){ @@ -8135,6 +8144,190 @@ function _handleMissingDoc(contractType, docId, variant, intent) { }, 300); } +// ── НАПОМИНАНИЯ ────────────────────────────────────────────────────────────── + +var _REMINDERS_KEY = 'zashita_reminders'; + +function _saveReminder(docLabel, docId, contractType, remindAt) { + try { + var reminders = JSON.parse(localStorage.getItem(_REMINDERS_KEY) || '[]'); + // Удаляем старый если был + reminders = reminders.filter(function(r){ return !(r.docId === docId && r.contractType === contractType); }); + reminders.push({ + id: Date.now(), docId: docId, contractType: contractType, + docLabel: docLabel, remindAt: remindAt, done: false, + createdAt: new Date().toISOString() + }); + localStorage.setItem(_REMINDERS_KEY, JSON.stringify(reminders)); + } catch(e){} +} + +function _getOverdueReminders() { + try { + var reminders = JSON.parse(localStorage.getItem(_REMINDERS_KEY) || '[]'); + var now = Date.now(); + return reminders.filter(function(r){ return !r.done && new Date(r.remindAt).getTime() <= now; }); + } catch(e){ return []; } +} + +function _showReminderPicker(doc, contractType, intent) { + var msgs = document.getElementById('rchat-msgs'); + if (!msgs) return; + + var now = new Date(); + var dates = [ + { label: 'Сегодня вечером', val: _dateOffset(0, 18) }, + { label: 'Завтра утром', val: _dateOffset(1, 9) }, + { label: 'Через 3 дня', val: _dateOffset(3, 9) }, + { label: 'Через неделю', val: _dateOffset(7, 9) }, + ]; + + var div = document.createElement('div'); + div.className = 'hc-msg hc-elena'; + div.innerHTML = + '' + + '
' + + '
' + + 'Хорошо! Когда напомнить загрузить ' + doc.label + '?' + + '
' + + '
' + + dates.map(function(d){ + return ''; + }).join('') + + '
' + + '' + + '' + + '
' + + '
' + + '
'; + msgs.appendChild(div); + msgs.scrollTop = msgs.scrollHeight; +} + +function _dateOffset(days, hour) { + var d = new Date(); + d.setDate(d.getDate() + days); + d.setHours(hour, 0, 0, 0); + return d.toISOString().slice(0, 16); +} + +function _formatDate(isoStr) { + var d = new Date(isoStr); + return d.toLocaleDateString('ru-RU', {day:'numeric', month:'short', hour:'2-digit', minute:'2-digit'}); +} + +function _setReminder(docId, docLabel, contractType, remindAt, intent) { + // Убираем picker + var msgs = document.getElementById('rchat-msgs'); + var last = msgs ? msgs.lastElementChild : null; + if (last && last.className.includes('hc-elena')) last.remove(); + + _saveReminder(docLabel, docId, contractType, remindAt); + _addCaseNote('promise', docLabel + ' — напоминание установлено на ' + _formatDate(remindAt), + { docId: docId, contractType: contractType, remindAt: remindAt }); + + // Пузырь клиента + if (msgs) { + var uDiv = document.createElement('div'); + uDiv.className = 'hc-msg hc-user'; + uDiv.innerHTML = '
🔔 Напомни ' + _formatDate(remindAt) + '
'; + msgs.appendChild(uDiv); + } + + // Ответ Елены + setTimeout(function(){ + _rcAddTyping(); + var prompt = 'Клиент установил напоминание загрузить документ "' + docLabel + + '" на ' + _formatDate(remindAt) + '. Зафиксируй и скажи что будет видно при следующем входе. Продолжаем работу.'; + _elenaApi(prompt, intent, function(apiReply) { + _rcRemoveTyping(); + var reply = apiReply || 'Зафиксировала. ' + _formatDate(remindAt) + ' напомню. Продолжаем.'; + _rcAddBubble(reply, false); + _rcShowControls(); + }); + }, 300); +} + +// Проверка при старте — есть ли просроченные напоминания +function _checkRemindersOnStart() { + var overdue = _getOverdueReminders(); + if (!overdue.length) return; + + // Показываем через 1 сек после initReturnChat + setTimeout(function(){ + var msgs = document.getElementById('rchat-msgs'); + if (!msgs) return; + overdue.forEach(function(r) { + var div = document.createElement('div'); + div.className = 'hc-msg hc-elena'; + div.innerHTML = + '' + + '
' + + '
🔔 Напоминание
' + + '
' + + 'Вы обещали загрузить ' + r.docLabel + '. Удалось найти?' + + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
'; + msgs.appendChild(div); + msgs.scrollTop = msgs.scrollHeight; + }); + }, 1200); +} + +function _reminderDone(reminderId, uploaded) { + // Убираем пузырь + var msgs = document.getElementById('rchat-msgs'); + var last = msgs ? msgs.lastElementChild : null; + if (last) last.remove(); + + try { + var reminders = JSON.parse(localStorage.getItem(_REMINDERS_KEY) || '[]'); + var r = reminders.find(function(x){ return x.id == reminderId; }); + if (r) { + r.done = true; + r.outcome = uploaded ? 'uploaded' : 'refused'; + localStorage.setItem(_REMINDERS_KEY, JSON.stringify(reminders)); + + if (uploaded) { + // Отмечаем документ в чеклисте как загруженный + try { + var saved = JSON.parse(localStorage.getItem('zashita_doccheck_' + r.contractType) || '{}'); + saved[r.docId] = true; + localStorage.setItem('zashita_doccheck_' + r.contractType, JSON.stringify(saved)); + } catch(e){} + _addCaseNote('decision', r.docLabel + ' — загружен (подтверждено)', { reminderId: reminderId }); + if (msgs) { var ok = document.createElement('div'); ok.className='hc-msg hc-user'; ok.innerHTML='
✅ Загрузил
'; msgs.appendChild(ok); } + toast('✅ Зафиксировано — документ получен'); + } else { + // Конвертируем обещание в отказ + _addCaseNote('missing_doc', r.docLabel + ' — клиент решил не загружать (зафиксирован отказ)', { final: true }); + if (msgs) { var no = document.createElement('div'); no.className='hc-msg hc-user'; no.innerHTML='
❌ Не буду загружать
'; msgs.appendChild(no); } + toast('📝 Зафиксировано в карте дела как окончательный отказ'); + } + } + } catch(e){} + + _rcShowControls(); +} + function _showAuditGaps(contractType, intent) { var msgs = document.getElementById('rchat-msgs'); if (!msgs) return;