220 lines
9.4 KiB
HTML
220 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru" data-theme="light">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Помощник по закупкам</title>
|
||
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-components.css">
|
||
<link rel="stylesheet" href="design-system/kt-ai-page.css">
|
||
<style>
|
||
a.kt-ai-btn { text-decoration: none; }
|
||
.chat-container { display: flex; flex-direction: column; height: calc(100vh - 140px); margin-top: var(--kt-ai-space-6); }
|
||
.chat-messages { flex: 1; overflow-y: auto; padding: var(--kt-ai-space-4); border: 1px solid var(--kt-ai-border); border-radius: var(--kt-ai-radius-xl); background: var(--kt-ai-bg-soft); margin-bottom: var(--kt-ai-space-4); }
|
||
.chat-message { margin-bottom: var(--kt-ai-space-4); }
|
||
.chat-message.user { text-align: right; }
|
||
.chat-bubble { display: inline-block; padding: var(--kt-ai-space-3) var(--kt-ai-space-4); border-radius: var(--kt-ai-radius-xl); max-width: 70%; text-align: left; }
|
||
.chat-message.user .chat-bubble { background: var(--kt-ai-primary); color: white; }
|
||
.chat-message.assistant .chat-bubble { background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-border); }
|
||
.chat-message.system .chat-bubble { background: var(--kt-ai-bg-soft); border: 1px dashed var(--kt-ai-border); color: var(--kt-ai-fg-muted); font-size: var(--kt-ai-text-sm); }
|
||
.chat-input-area { display: flex; gap: var(--kt-ai-space-3); align-items: flex-end; }
|
||
.chat-input-area .kt-ai-field { flex: 1; margin: 0; }
|
||
.chat-input-area textarea.kt-ai-input { min-height: 48px; resize: vertical; }
|
||
.kb-status { margin-top: var(--kt-ai-space-2); font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); }
|
||
.message-time { font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-faint); margin-top: var(--kt-ai-space-1); }
|
||
.chat-message.user .message-time { color: rgba(255,255,255,0.7); }
|
||
</style>
|
||
</head>
|
||
<body class="kt-ai-app">
|
||
|
||
<header class="kt-ai-pagehead">
|
||
<div class="kt-ai-wrap kt-ai-pagehead-in">
|
||
<div style="display:flex;align-items:center;gap:var(--kt-ai-space-3)">
|
||
<img src="https://code.vibe42.kz/tore/aitu/kt-logo.svg" alt="Казахтелеком" height="28">
|
||
<div>
|
||
<strong>Помощник по закупкам</strong>
|
||
<div style="font-size:var(--kt-ai-text-xs);color:var(--kt-ai-fg-muted)">Чат по инструкциям портала</div>
|
||
</div>
|
||
</div>
|
||
<span class="kt-ai-spacer"></span>
|
||
<span class="kt-ai-chip" data-tone="orange">Демо-данные</span>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="kt-ai-wrap" data-width="wide">
|
||
<div class="chat-container">
|
||
<div id="chatMessages" class="chat-messages"></div>
|
||
|
||
<div class="chat-input-area">
|
||
<div class="kt-ai-field">
|
||
<label for="userQuestion">Ваш вопрос по договору или закупкам</label>
|
||
<textarea id="userQuestion" class="kt-ai-input" placeholder="Например: Какие документы нужны для участия в закупке?" rows="2"></textarea>
|
||
</div>
|
||
<button id="sendBtn" class="kt-ai-btn" data-variant="primary" data-size="lg">Отправить</button>
|
||
</div>
|
||
|
||
<div class="kb-status">
|
||
<span id="kbStatus">База знаний:_instructions_ не загружена. Покажу только общие ответы.</span>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<footer class="kt-ai-wrap kt-ai-pagefoot">
|
||
<span>© 2026 Казахтелеком</span>
|
||
<span class="kt-ai-spacer"></span>
|
||
<span>Внутренний помощник</span>
|
||
</footer>
|
||
|
||
<script>
|
||
// === Демо-база знаний (инструкции) ===
|
||
const knowledgeBase = {
|
||
договор: {
|
||
keywords: ['договор', 'договора', 'договору', 'договором'],
|
||
answer: 'По договору: согласно инструкции закупочного портала, договор заключается после победы в закупке. Необходимые документы: заявка, обеспечение, проект договора. Срок подписания — 10 рабочих дней.',
|
||
loaded: false
|
||
},
|
||
закупка: {
|
||
keywords: ['закупк', 'тендер', 'аукцион', 'конкурс'],
|
||
answer: 'Участие в закупке: зарегистрируйтесь на портале, подайте заявку до срока окончания, внесите обеспечение. Результаты публикуются в течение 3 рабочих дней.',
|
||
loaded: false
|
||
},
|
||
документ: {
|
||
keywords: ['документ', 'документы', 'документо'],
|
||
answer: 'Необходимые документы: устав, свидетельство о регистрации, налоговая отчётность, лицензия (если требуется). Все документы загружаются в личном кабинете.',
|
||
loaded: false
|
||
},
|
||
обеспечение: {
|
||
keywords: ['обеспечени', 'залог', 'гарантия'],
|
||
answer: 'Обеспечение заявки: 1-5% от суммы закупки. Вносится на счёт организатора или банковской гарантией. Возвращается после завершения закупки.',
|
||
loaded: false
|
||
},
|
||
срок: {
|
||
keywords: ['срок', 'сроки', 'время', 'когда'],
|
||
answer: 'Сроки проведения закупок: подача заявок — от 5 до 30 дней, рассмотрение — 3 рабочих дня, подпис договора — 10 рабочих дней.',
|
||
loaded: false
|
||
}
|
||
};
|
||
|
||
// === История чата в localStorage ===
|
||
let chatHistory = JSON.parse(localStorage.getItem('chatHistory') || '[]');
|
||
|
||
// === Инициализация ===
|
||
function init() {
|
||
renderMessages();
|
||
scrollToBottom();
|
||
|
||
document.getElementById('sendBtn').addEventListener('click', sendMessage);
|
||
document.getElementById('userQuestion').addEventListener('keydown', (e) => {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
sendMessage();
|
||
}
|
||
});
|
||
}
|
||
|
||
// === Отправка сообщения ===
|
||
function sendMessage() {
|
||
const input = document.getElementById('userQuestion');
|
||
const question = input.value.trim();
|
||
|
||
if (!question) return;
|
||
|
||
// Добавляем сообщение пользователя
|
||
const userMsg = {
|
||
role: 'user',
|
||
text: question,
|
||
time: new Date().toISOString()
|
||
};
|
||
chatHistory.push(userMsg);
|
||
|
||
// Ищем ответ в базе знаний
|
||
const response = findAnswer(question);
|
||
const assistantMsg = {
|
||
role: 'assistant',
|
||
text: response,
|
||
time: new Date().toISOString()
|
||
};
|
||
chatHistory.push(assistantMsg);
|
||
|
||
// Сохраняем и рисуем
|
||
localStorage.setItem('chatHistory', JSON.stringify(chatHistory));
|
||
input.value = '';
|
||
renderMessages();
|
||
scrollToBottom();
|
||
}
|
||
|
||
// === Поиск ответа ===
|
||
function findAnswer(question) {
|
||
const q = question.toLowerCase();
|
||
|
||
for (const key in knowledgeBase) {
|
||
const item = knowledgeBase[key];
|
||
for (const keyword of item.keywords) {
|
||
if (q.includes(keyword)) {
|
||
if (item.loaded) {
|
||
return item.answer;
|
||
} else {
|
||
return '⚠️ Инструкция по этому вопросу ещё не загружена в базу знаний. Обратитесь к администратору портала.';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return '⚠️ Инструкция не загружена. Я пока не могу ответить на этот вопрос по инструкциям портала. Попробуйте спросить про договор, закупку, документы, обеспечение или сроки.';
|
||
}
|
||
|
||
// === Отрисовка сообщений ===
|
||
function renderMessages() {
|
||
const container = document.getElementById('chatMessages');
|
||
container.innerHTML = '';
|
||
|
||
if (chatHistory.length === 0) {
|
||
container.innerHTML = `
|
||
<div class="chat-message system">
|
||
<div class="chat-bubble" style="width:100%;text-align:center">
|
||
<strong>Здравствуйте!</strong><br>
|
||
Я помощник по инструкциям закупочного портала.<br>
|
||
Спросите меня про договоры, закупки, документы или сроки.
|
||
</div>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
|
||
chatHistory.forEach(msg => {
|
||
const div = document.createElement('div');
|
||
div.className = `chat-message ${msg.role}`;
|
||
|
||
const time = new Date(msg.time).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
|
||
|
||
div.innerHTML = `
|
||
<div class="chat-bubble">${escapeHtml(msg.text)}</div>
|
||
<div class="message-time">${time}</div>
|
||
`;
|
||
container.appendChild(div);
|
||
});
|
||
}
|
||
|
||
// === Утилита: экранирование HTML ===
|
||
function escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML.replace(/\n/g, '<br>');
|
||
}
|
||
|
||
// === Скролл вниз ===
|
||
function scrollToBottom() {
|
||
const container = document.getElementById('chatMessages');
|
||
setTimeout(() => {
|
||
container.scrollTop = container.scrollHeight;
|
||
}, 50);
|
||
}
|
||
|
||
// Запуск
|
||
init();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|