diff --git a/mockup.html b/mockup.html
index 704fcc4..bd396c3 100644
--- a/mockup.html
+++ b/mockup.html
@@ -4649,18 +4649,25 @@ function _rcAddTyping() {
function _rcRemoveTyping() {
var el = document.getElementById('rc-typing'); if (el) el.remove();
}
-function _rcAddBubble(html, isUser) {
+function _rcAddBubble(content, isUser, isRawHtml) {
var msgs = document.getElementById('rchat-msgs');
if (!msgs) return;
var row = document.createElement('div');
row.className = 'hc-msg' + (isUser ? ' hc-user-msg' : '');
+ var inner = isRawHtml ? content : _rcEscape(content);
if (!isUser) {
- row.innerHTML = '
' + html + '
';
+ row.innerHTML = '
' + inner + '
';
} else {
- row.innerHTML = '' + html + '
';
+ row.innerHTML = '' + inner + '
';
}
msgs.appendChild(row); msgs.scrollTop = msgs.scrollHeight;
}
+function _rcEscape(s) {
+ return String(s)
+ .replace(/&/g,'&').replace(//g,'>')
+ .replace(/\n/g,'
');
+}
+
function _rcShowControls() {
var r = document.getElementById('rchat-replies');
var i = document.getElementById('rchat-input-row');
@@ -4732,11 +4739,24 @@ function initReturnChat() {
context += (context ? ' ' : '') + 'Подписка ' + (sNames[subPlan]||'') + ' активна.';
}
+ // Сохраняем контекст — чтобы ответить на "Что нужно сделать?"
+ if (urgentDL) {
+ _rcLastContext = {
+ type: 'deadline',
+ dl: urgentDL.dl,
+ diff: urgentDL.diff,
+ caseName: urgentDL.dl.caseName || ''
+ };
+ }
+
var callToAction = '';
if (urgentDL) {
- callToAction = '⚠️ Срочно: ' + urgentDL.dl.title + ' — через ' + urgentDL.diff
- + (urgentDL.diff === 1 ? ' день' : urgentDL.diff < 5 ? ' дня' : ' дней')
- + '. Нужно действовать.';
+ var diffLabel = urgentDL.diff < 0
+ ? 'просрочен на ' + Math.abs(urgentDL.diff) + ' дн.'
+ : urgentDL.diff === 0 ? 'сегодня'
+ : 'через ' + urgentDL.diff + (urgentDL.diff === 1 ? ' день' : urgentDL.diff < 5 ? ' дня' : ' дней');
+ callToAction = '⚠️ Срочно: ' + urgentDL.dl.title + ' — ' + diffLabel
+ + '. Напишите «что нужно сделать» — объясню конкретные шаги.';
} else if (pendingRefund) {
callToAction = 'Ваша заявка на возврат в обработке — ответим в течение 10 рабочих дней.';
} else if (!credits && !subPlan) {
@@ -4783,6 +4803,115 @@ function initReturnChat() {
}
}
+// Контекст последнего сообщения Елены в returning chat
+// { type: 'deadline', dl: {title, type, date, quote, diff}, caseName }
+var _rcLastContext = null;
+
+// Конкретные шаги по типу срока
+var _DL_ACTIONS = {
+ payment: {
+ steps: [
+ 'Проверьте реквизиты для оплаты в тексте договора',
+ 'Проведите платёж — сохраните квитанцию или выписку',
+ 'Направьте подтверждение оплаты контрагенту (скан/скриншот)',
+ 'Если уже просрочено — платите немедленно, день просрочки = начисление пени'
+ ],
+ warn: 'Просрочка оплаты — основание для начисления пени и потенциального расторжения договора.'
+ },
+ notification: {
+ steps: [
+ 'Составьте письменное уведомление (могу помочь — нажмите «Составить»)',
+ 'Отправьте заказным письмом с уведомлением о вручении — это фиксирует дату',
+ 'Продублируйте на email контрагента с запросом подтверждения получения',
+ 'Сохраните чек об отправке и трек-номер'
+ ],
+ warn: 'Устное уведомление не имеет юридической силы — только письменное с подтверждением доставки.'
+ },
+ renewal: {
+ steps: [
+ 'Решите: хотите продлить договор или нет?',
+ 'Если НЕ продлеваете — направьте уведомление об отказе от продления до истечения срока',
+ 'Если продлеваете — никаких действий не нужно, договор продлится автоматически',
+ 'Проверьте условия пролонгации: на тех же условиях или изменятся?'
+ ],
+ warn: 'Пропустить срок уведомления = автоматическое продление на тех же условиях ещё на весь период.'
+ },
+ termination: {
+ steps: [
+ 'Проверьте основание расторжения — оно должно быть в договоре или ГК РФ (ст. 450)',
+ 'Составьте уведомление о расторжении с указанием основания и даты (могу помочь)',
+ 'Направьте заказным письмом с уведомлением о вручении',
+ 'Зафиксируйте передачу имущества / возврат предоплаты актом'
+ ],
+ warn: 'Расторжение без соблюдения порядка = риск иска о возмещении убытков.'
+ },
+ penalty: {
+ steps: [
+ 'Зафиксируйте факт нарушения — скриншоты, переписка, акты',
+ 'Рассчитайте размер пени по формуле из договора',
+ 'Направьте претензию с требованием оплатить пени и основной долг',
+ 'Установите срок ответа — 10–30 дней, затем иск'
+ ],
+ warn: 'Без письменной претензии суд может снизить неустойку по ст. 333 ГК РФ.'
+ },
+ other: {
+ steps: [
+ 'Изучите конкретный пункт договора, к которому относится срок',
+ 'Определите что именно нужно сделать: подписать, оплатить, уведомить или передать',
+ 'Зафиксируйте исполнение письменно — акт, квитанция, письмо',
+ 'Сохраните все подтверждения'
+ ],
+ warn: ''
+ }
+};
+
+function _getDlActionType(dl) {
+ if (!dl) return 'other';
+ var t = (dl.type || '').toLowerCase();
+ var title = (dl.title || '').toLowerCase();
+ if (/оплат|платёж|payment/.test(t + title)) return 'payment';
+ if (/уведомл|notification/.test(t + title)) return 'notification';
+ if (/пролонг|продлен|renewal/.test(t + title)) return 'renewal';
+ if (/расторж|termination/.test(t + title)) return 'termination';
+ if (/пен|штраф|penalty/.test(t + title)) return 'penalty';
+ return 'other';
+}
+
+function _buildDlAnswer(ctx) {
+ var dl = ctx.dl;
+ var actionType = _getDlActionType(dl);
+ var actions = _DL_ACTIONS[actionType] || _DL_ACTIONS.other;
+
+ var diffText = '';
+ if (dl.diff < 0) diffText = '⚠️ Просрочен на ' + Math.abs(dl.diff) + ' дн.';
+ else if (dl.diff === 0) diffText = '🔴 Срок истекает сегодня';
+ else diffText = '🕐 Осталось ' + dl.diff + ' дн.';
+
+ var stepsHtml = actions.steps.map(function(s, i){
+ return '' +
+ '' + (i+1) + '' +
+ '' + s + '
';
+ }).join('');
+
+ var warnHtml = actions.warn
+ ? '' + actions.warn + '
'
+ : '';
+
+ var ctaHtml =
+ '' +
+ (actionType === 'notification' || actionType === 'termination'
+ ? ''
+ : '') +
+ '' +
+ '
';
+
+ return 'Елена
' +
+ '' + dl.title + ' — ' + diffText +
+ (dl.quote ? '' + dl.quote + '
' : '
') +
+ 'Что нужно сделать:' + stepsHtml + '
' +
+ warnHtml + ctaHtml;
+}
+
function retChatSend() {
var inp = document.getElementById('rchat-inp');
if (!inp) return;
@@ -4792,18 +4921,75 @@ function retChatSend() {
var i = document.getElementById('rchat-input-row');
if (r) r.style.display = 'none'; if (i) i.style.display = 'none';
_rcAddBubble(txt, true);
+
var t = txt.toLowerCase();
+
+ // ── Вопрос о действии по активному контексту срока ──
+ var isActionQ = /что (нужно|делать|сделать)|как (быть|поступить|действовать)|помоги|что значит|объясни|расскажи подробн|дальше|следующий шаг/.test(t);
+ if (isActionQ && _rcLastContext && _rcLastContext.type === 'deadline') {
+ setTimeout(function(){
+ _rcAddTyping();
+ setTimeout(function(){
+ _rcRemoveTyping();
+ var html = _buildDlAnswer(_rcLastContext);
+ _rcAddBubble(html, false, true); // true = raw html
+ _rcShowControls();
+ }, 800);
+ }, 300);
+ return;
+ }
+
+ // ── Если API доступен — спрашиваем Елену реально ──
+ var isLegalQ = !/баланс|кредит|оплат|мои дела|кабинет/.test(t);
+ if (isLegalQ && _apiAvailable) {
+ setTimeout(function(){
+ _rcAddTyping();
+ var ctx = _rcLastContext && _rcLastContext.type === 'deadline'
+ ? '\n[Контекст: клиент спрашивает о сроке «' + _rcLastContext.dl.title + '» по договору ' + (_rcLastContext.caseName || '') + ']'
+ : '';
+ fetch(API_BASE + '/api/elena', {
+ method: 'POST',
+ headers: {'Content-Type':'application/json'},
+ body: JSON.stringify({
+ text: txt + ctx,
+ intent: 'question',
+ history: _chatHistory.slice(-6),
+ deadlines: _contractDeadlines
+ })
+ })
+ .then(function(res){ return res.json(); })
+ .then(function(data){
+ _rcRemoveTyping();
+ var reply = data.reply || '...';
+ _chatHistory.push({role:'user', content: txt});
+ _chatHistory.push({role:'assistant', content: reply});
+ _rcAddBubble(reply, false);
+ _rcShowControls();
+ })
+ .catch(function(){
+ _rcRemoveTyping();
+ _rcFallbackReply(t);
+ });
+ }, 300);
+ return;
+ }
+
+ // ── Fallback — шаблонные редиректы ──
+ _rcFallbackReply(t);
+}
+
+function _rcFallbackReply(t) {
var intent = 'question';
- if (/срок|уведомл|дедлайн/.test(t)) intent = 'deadlines';
- else if (/баланс|кредит|оплат/.test(t)) intent = 'pay';
+ if (/срок|уведомл|дедлайн/.test(t)) intent = 'deadlines';
+ else if (/баланс|кредит|оплат/.test(t)) intent = 'pay';
else if (/новый|загруз|проверит|договор/.test(t)) intent = 'new';
- else if (/дела|кабинет/.test(t)) intent = 'cabinet';
+ else if (/дела|кабинет/.test(t)) intent = 'cabinet';
var replies = {
deadlines: { elena: 'Открываю ваши сроки — всё самое срочное там 📋', action: function(){ go('cabinet'); tab('sroki'); } },
- pay: { elena: 'Показываю баланс и варианты пополнения 💳', action: function(){ go('pay'); } },
- new: { elena: 'Отличное решение! Загружайте новый документ — разберём 🔍', action: function(){ go('elena'); } },
+ pay: { elena: 'Показываю варианты пополнения 💳', action: function(){ go('pay'); } },
+ new: { elena: 'Загружайте новый документ — разберём 🔍', action: function(){ go('elena'); } },
cabinet: { elena: 'Открываю ваши дела 📂', action: function(){ go('cabinet'); } },
- question: { elena: 'Хорошо! Перехожу к Елене — она ответит на любой юридический вопрос 💬', action: function(){ go('elena'); } }
+ question: { elena: 'Перехожу к полному чату — там отвечу подробнее 💬', action: function(){ go('elena'); } }
};
var resp = replies[intent] || replies.question;
setTimeout(function(){
@@ -4811,7 +4997,8 @@ function retChatSend() {
setTimeout(function(){
_rcRemoveTyping();
_rcAddBubble(resp.elena, false);
- setTimeout(resp.action, 900);
+ if (resp.action) setTimeout(resp.action, 900);
+ _rcShowControls();
}, 700);
}, 300);
}