435 lines
21 KiB
HTML
435 lines
21 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">
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📄</text></svg>">
|
||
<style>
|
||
a.kt-ai-btn { text-decoration: none; }
|
||
.kt-ai-app { min-height: 100vh; display: flex; flex-direction: column; }
|
||
.search-section { padding: var(--kt-ai-space-10) 0; }
|
||
.search-box { max-width: 720px; margin: 0 auto; }
|
||
.search-input-wrap { display: flex; gap: var(--kt-ai-space-3); }
|
||
.search-input-wrap .kt-ai-input { flex: 1; font-size: var(--kt-ai-text-lg); padding: var(--kt-ai-space-4); }
|
||
.categories-wrap { display: flex; gap: var(--kt-ai-space-2); flex-wrap: wrap; margin-top: var(--kt-ai-space-5); }
|
||
.result-card { margin-top: var(--kt-ai-space-8); }
|
||
.steps-list { counter-reset: step; list-style: none; padding: 0; margin: var(--kt-ai-space-4) 0; }
|
||
.steps-list li { position: relative; padding-left: var(--kt-ai-space-7); margin-bottom: var(--kt-ai-space-3); }
|
||
.steps-list li::before { counter-increment: step; content: counter(step); position: absolute; left: 0; top: 0; width: 24px; height: 24px; background: var(--kt-ai-primary); color: var(--kt-ai-bg); border-radius: var(--kt-ai-radius-md); display: flex; align-items: center; justify-content: center; font-size: var(--kt-ai-text-sm); font-weight: var(--kt-ai-weight-semibold); }
|
||
.history-section { margin-top: var(--kt-ai-space-8); }
|
||
.history-list { display: flex; flex-direction: column; gap: var(--kt-ai-space-2); }
|
||
.history-item { display: flex; align-items: center; gap: var(--kt-ai-space-3); padding: var(--kt-ai-space-3); border-radius: var(--kt-ai-radius-lg); background: var(--kt-ai-bg-soft); cursor: pointer; transition: background 0.2s; }
|
||
.history-item:hover { background: var(--kt-ai-card-bg); }
|
||
.empty-state { text-align: center; padding: var(--kt-ai-space-10) var(--kt-ai-space-4); color: var(--kt-ai-fg-muted); }
|
||
.kb-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--kt-ai-space-4); margin-top: var(--kt-ai-space-6); }
|
||
.kb-card { cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; }
|
||
.kb-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||
.kb-category { font-size: var(--kt-ai-text-xs); color: var(--kt-ai-fg-muted); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: var(--kt-ai-space-2); }
|
||
.instruction-link { display: inline-flex; align-items: center; gap: var(--kt-ai-space-2); margin-top: var(--kt-ai-space-4); color: var(--kt-ai-link); }
|
||
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: none; align-items: center; justify-content: center; z-index: 1000; }
|
||
.modal-overlay.active { display: flex; }
|
||
.modal-content { background: var(--kt-ai-bg); border-radius: var(--kt-ai-radius-2xl); padding: var(--kt-ai-space-6); max-width: 640px; width: 90%; max-height: 80vh; overflow-y: auto; }
|
||
.modal-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: var(--kt-ai-space-4); }
|
||
.modal-close { background: none; border: none; font-size: 24px; cursor: pointer; color: var(--kt-ai-fg-muted); }
|
||
</style>
|
||
</head>
|
||
<body class="kt-ai-app" data-kt-data-mode="demo">
|
||
|
||
<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">
|
||
<strong>Помощник по договорам</strong>
|
||
</div>
|
||
<span class="kt-ai-spacer"></span>
|
||
<span class="kt-ai-chip" data-tone="orange">Демо-данные</span>
|
||
</div>
|
||
</header>
|
||
|
||
<main style="flex:1">
|
||
|
||
<section class="search-section">
|
||
<div class="kt-ai-wrap">
|
||
<div class="search-box">
|
||
<h1 style="text-align:center;margin-bottom:var(--kt-ai-space-3)">Как работать в портале договоров</h1>
|
||
<p class="kt-ai-hero-sub" style="text-align:center;margin-bottom:var(--kt-ai-space-6)">Задайте вопрос — получите пошаговую инструкцию</p>
|
||
|
||
<div class="search-input-wrap">
|
||
<input type="text" id="searchInput" class="kt-ai-input" placeholder="Например: как создать договор?" autofocus>
|
||
<button class="kt-ai-btn" data-variant="primary" data-size="lg" onclick="performSearch()">Найти ответ</button>
|
||
</div>
|
||
|
||
<div class="categories-wrap" id="categoriesWrap">
|
||
<button class="kt-ai-btn" data-variant="ghost" onclick="filterByCategory('all')">Все</button>
|
||
<button class="kt-ai-btn" data-variant="ghost" onclick="filterByCategory('Создание')">Создание</button>
|
||
<button class="kt-ai-btn" data-variant="ghost" onclick="filterByCategory('Согласование')">Согласование</button>
|
||
<button class="kt-ai-btn" data-variant="ghost" onclick="filterByCategory('Подписание')">Подписание</button>
|
||
<button class="kt-ai-btn" data-variant="ghost" onclick="filterByCategory('Архив')">Архив</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="kt-ai-section">
|
||
<div class="kt-ai-wrap">
|
||
|
||
<div id="resultBlock" class="result-card" style="display:none">
|
||
<div class="kt-ai-card" style="border-left: 4px solid var(--kt-ai-primary)">
|
||
<h2 id="resultTitle" style="margin-bottom:var(--kt-ai-space-3)"></h2>
|
||
<div id="resultCategory" class="kb-category" style="margin-bottom:var(--kt-ai-space-4)"></div>
|
||
<div id="resultContent"></div>
|
||
<a id="resultLink" class="instruction-link kt-ai-link" href="#" target="_blank" style="display:none">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||
Открыть полную инструкцию
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="emptyState" class="empty-state" style="display:none">
|
||
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="var(--kt-ai-fg-faint)" stroke-width="1.5" style="margin-bottom:var(--kt-ai-space-4)">
|
||
<circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
|
||
<path d="M11 8v6"/><path d="M11 18h.01"/>
|
||
</svg>
|
||
<h3 style="margin-bottom:var(--kt-ai-space-2)">Ответ не найден</h3>
|
||
<p>В документах не найдено точного ответа на ваш вопрос.<br>Попробуйте переформулировать или выберите тему из справочника ниже.</p>
|
||
</div>
|
||
|
||
<div id="kbSection">
|
||
<h2 style="margin-bottom:var(--kt-ai-space-2)">Справочник вопросов</h2>
|
||
<p style="color:var(--kt-ai-fg-muted);margin-bottom:var(--kt-ai-space-4)">Выберите готовый вопрос, чтобы увидеть ответ</p>
|
||
<div class="kb-grid" id="kbGrid"></div>
|
||
</div>
|
||
|
||
<div class="history-section" id="historySection" style="display:none">
|
||
<h3 style="margin-bottom:var(--kt-ai-space-3)">Последние запросы</h3>
|
||
<div class="history-list" id="historyList"></div>
|
||
<button class="kt-ai-btn" data-variant="ghost" style="margin-top:var(--kt-ai-space-3)" onclick="clearHistory()">Очистить историю</button>
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
<footer class="kt-ai-wrap kt-ai-pagefoot">
|
||
<span>© 2026 Казахтелеком</span>
|
||
<span class="kt-ai-spacer"></span>
|
||
<span class="kt-ai-fg-faint">Помощник по договорам v1.0</span>
|
||
</footer>
|
||
|
||
<div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2 id="modalTitle" style="margin:0"></h2>
|
||
<button class="modal-close" onclick="closeModal()">×</button>
|
||
</div>
|
||
<div id="modalBody"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const KNOWLEDGE_BASE = [
|
||
{
|
||
id: 1,
|
||
question: "Как создать новый договор?",
|
||
category: "Создание",
|
||
keywords: ["создать", "новый", "договор", "регистрация"],
|
||
steps: [
|
||
"Откройте раздел «Договоры» → «Создать договор»",
|
||
"Заполните обязательные поля: контрагент, предмет, сумма, срок действия",
|
||
"Прикрепите скан-копию договора в формате PDF",
|
||
"Нажмите «Сохранить и отправить на согласование»"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Все обязательные поля отмечены звёздочкой (*)"
|
||
},
|
||
{
|
||
id: 2,
|
||
question: "Как изменить существующий договор?",
|
||
category: "Создание",
|
||
keywords: ["изменить", "редактировать", "обновить", "дополнительное"],
|
||
steps: [
|
||
"Найдите договор в реестре через поиск или фильтры",
|
||
"Откройте карточку договора",
|
||
"Нажмите кнопку «Редактировать» или «Создать дополнительное соглашение»",
|
||
"Внесите изменения, сохраните и отправьте на согласование"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Изменения вступают в силу после подписания обеими сторонами"
|
||
},
|
||
{
|
||
id: 3,
|
||
question: "Как отправить договор на согласование?",
|
||
category: "Согласование",
|
||
keywords: ["отправить", "согласование", "маршрут", "визировать"],
|
||
steps: [
|
||
"Откройте черновик договора",
|
||
"Проверьте заполненность всех обязательных полей",
|
||
"Нажмите «Отправить на согласование»",
|
||
"Выберите маршрут согласования или используйте стандартный",
|
||
"Подтвердите отправку — договор уйдёт первому согласующему"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Статус изменится на «На согласовании», вы увидите текущий этап"
|
||
},
|
||
{
|
||
id: 4,
|
||
question: "Как отозвать договор с согласования?",
|
||
category: "Согласование",
|
||
keywords: ["отозвать", "вернуть", "отменить", "согласование"],
|
||
steps: [
|
||
"Откройте договор со статусом «На согласовании»",
|
||
"Нажмите кнопку «Отозвать» (доступна, если договор ещё не подписан)",
|
||
"Укажите причину отзыва в комментарии",
|
||
"Договор вернётся в статус «Черновик»"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Отозвать можно только до момента финального подписания"
|
||
},
|
||
{
|
||
id: 5,
|
||
question: "Как подписать договор электронной подписью?",
|
||
category: "Подписание",
|
||
keywords: ["подписать", "эцп", "подпись", "нцр"],
|
||
steps: [
|
||
"Откройте договор со статусом «Готов к подписанию»",
|
||
"Нажмите «Подписать ЭЦП»",
|
||
"Выберите сертификат подписи из списка",
|
||
"Введите пароль от токена/ключа",
|
||
"Дождитесь подтверждения — статус сменится на «Подписан»"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Требуется установленный плагин ЭЦП и действующий сертификат"
|
||
},
|
||
{
|
||
id: 6,
|
||
question: "Как посмотреть статус договора?",
|
||
category: "Создание",
|
||
keywords: ["статус", "этап", "где находится", "отследить"],
|
||
steps: [
|
||
"Откройте реестр договоров",
|
||
"Найдите нужный договор (поиск/фильтры)",
|
||
"Статус отображается в отдельной колонке цветом",
|
||
"Кликните на статус для детальной информации по этапам"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Зелёный — подписан, жёлтый — на согласовании, серый — черновик"
|
||
},
|
||
{
|
||
id: 7,
|
||
question: "Как получить архивную копию договора?",
|
||
category: "Архив",
|
||
keywords: ["архив", "копия", "выгрузить", "скачать", "экспорт"],
|
||
steps: [
|
||
"Откройте исполненный договор (статус «Архив»)",
|
||
"Нажмите кнопку «Скачать» или «Выгрузить»",
|
||
"Выберите формат: PDF с подписями или XML",
|
||
"Файл загрузится на устройство"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Архивные договоры хранятся 5 лет после исполнения"
|
||
},
|
||
{
|
||
id: 8,
|
||
question: "Как переместить договор в архив?",
|
||
category: "Архив",
|
||
keywords: ["архив", "переместить", "исполнен", "закрыть"],
|
||
steps: [
|
||
"Убедитесь, что договор полностью исполнен (все обязательства закрыты)",
|
||
"Откройте карточку договора",
|
||
"Нажмите «Закрыть договор» или «Переместить в архив»",
|
||
"Подтвердите действие — статус сменится на «Архив»"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Архивный договор нельзя редактировать, только просматривать"
|
||
},
|
||
{
|
||
id: 9,
|
||
question: "Как назначить ответственного за договор?",
|
||
category: "Создание",
|
||
keywords: ["ответственный", "назначить", "владелец", "куратор"],
|
||
steps: [
|
||
"Откройте договор в режиме редактирования",
|
||
"В поле «Ответственный» начните вводить ФИО сотрудника",
|
||
"Выберите сотрудника из выпадающего списка",
|
||
"Сохраните изменения"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Ответственный получает уведомления об этапах договора"
|
||
},
|
||
{
|
||
id: 10,
|
||
question: "Как найти договор по контрагенту?",
|
||
category: "Создание",
|
||
keywords: ["найти", "поиск", "контрагент", "поставщик", "заказчик"],
|
||
steps: [
|
||
"Откройте реестр договоров",
|
||
"В фильтре «Контрагент» введите название компании или БИН",
|
||
"Нажмите «Применить» или Enter",
|
||
"Система покажет все договоры с этим контрагентом"
|
||
],
|
||
instructionUrl: "#",
|
||
tip: "Можно искать по части названия — система подскажет варианты"
|
||
}
|
||
];
|
||
|
||
let currentCategory = 'all';
|
||
|
||
function init() {
|
||
renderKB();
|
||
renderHistory();
|
||
|
||
document.getElementById('searchInput').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') performSearch();
|
||
});
|
||
}
|
||
|
||
function renderKB() {
|
||
const grid = document.getElementById('kbGrid');
|
||
const filtered = currentCategory === 'all'
|
||
? KNOWLEDGE_BASE
|
||
: KNOWLEDGE_BASE.filter(kb => kb.category === currentCategory);
|
||
|
||
grid.innerHTML = filtered.map(kb => `
|
||
<article class="kt-ai-card kb-card" onclick="showKBDetail(${kb.id})">
|
||
<div class="kb-category">${kb.category}</div>
|
||
<h3 style="margin:0 0 var(--kt-ai-space-2) 0">${kb.question}</h3>
|
||
<p style="color:var(--kt-ai-fg-muted);font-size:var(--kt-ai-text-sm);margin:0">
|
||
${kb.steps.length} шагов • ${kb.tip}
|
||
</p>
|
||
</article>
|
||
`).join('');
|
||
}
|
||
|
||
function filterByCategory(cat) {
|
||
currentCategory = cat;
|
||
renderKB();
|
||
|
||
document.querySelectorAll('#categoriesWrap .kt-ai-btn').forEach(btn => {
|
||
btn.dataset.variant = btn.textContent.trim() === (cat === 'all' ? 'Все' : cat) ? 'primary' : 'ghost';
|
||
});
|
||
}
|
||
|
||
function performSearch() {
|
||
const query = document.getElementById('searchInput').value.trim().toLowerCase();
|
||
if (!query) return;
|
||
|
||
addToHistory(query);
|
||
|
||
const result = KNOWLEDGE_BASE.find(kb => {
|
||
const qMatch = kb.question.toLowerCase().includes(query);
|
||
const kMatch = kb.keywords.some(k => k.includes(query) || query.includes(k));
|
||
const cMatch = currentCategory === 'all' || kb.category === currentCategory;
|
||
return (qMatch || kMatch) && cMatch;
|
||
});
|
||
|
||
const resultBlock = document.getElementById('resultBlock');
|
||
const emptyState = document.getElementById('emptyState');
|
||
|
||
if (result) {
|
||
document.getElementById('resultTitle').textContent = result.question;
|
||
document.getElementById('resultCategory').textContent = result.category;
|
||
document.getElementById('resultContent').innerHTML = `
|
||
<ol class="steps-list">
|
||
${result.steps.map(s => `<li>${s}</li>`).join('')}
|
||
</ol>
|
||
<p style="color:var(--kt-ai-fg-muted);font-size:var(--kt-ai-text-sm);margin-top:var(--kt-ai-space-4)">
|
||
💡 ${result.tip}
|
||
</p>
|
||
`;
|
||
const linkEl = document.getElementById('resultLink');
|
||
if (result.instructionUrl && result.instructionUrl !== '#') {
|
||
linkEl.href = result.instructionUrl;
|
||
linkEl.style.display = 'inline-flex';
|
||
} else {
|
||
linkEl.style.display = 'none';
|
||
}
|
||
resultBlock.style.display = 'block';
|
||
emptyState.style.display = 'none';
|
||
} else {
|
||
resultBlock.style.display = 'none';
|
||
emptyState.style.display = 'block';
|
||
}
|
||
}
|
||
|
||
function showKBDetail(id) {
|
||
const kb = KNOWLEDGE_BASE.find(k => k.id === id);
|
||
if (!kb) return;
|
||
|
||
document.getElementById('modalTitle').textContent = kb.question;
|
||
document.getElementById('modalBody').innerHTML = `
|
||
<div class="kb-category" style="margin-bottom:var(--kt-ai-space-4)">${kb.category}</div>
|
||
<ol class="steps-list">
|
||
${kb.steps.map(s => `<li>${s}</li>`).join('')}
|
||
</ol>
|
||
<div class="kt-ai-card" style="background:var(--kt-ai-bg-soft);margin-top:var(--kt-ai-space-5)">
|
||
<strong>💡 Совет:</strong>
|
||
<p style="margin:var(--kt-ai-space-2) 0 0 0;color:var(--kt-ai-fg-muted)">${kb.tip}</p>
|
||
</div>
|
||
${kb.instructionUrl && kb.instructionUrl !== '#' ? `
|
||
<a href="${kb.instructionUrl}" class="kt-ai-btn" data-variant="primary" style="margin-top:var(--kt-ai-space-5);width:100%" target="_blank">
|
||
Открыть полную инструкцию
|
||
</a>
|
||
` : ''}
|
||
`;
|
||
|
||
document.getElementById('modalOverlay').classList.add('active');
|
||
}
|
||
|
||
function closeModal(event) {
|
||
if (!event || event.target === document.getElementById('modalOverlay')) {
|
||
document.getElementById('modalOverlay').classList.remove('active');
|
||
}
|
||
}
|
||
|
||
function addToHistory(query) {
|
||
let history = JSON.parse(localStorage.getItem('searchHistory') || '[]');
|
||
history = history.filter(h => h !== query);
|
||
history.unshift(query);
|
||
if (history.length > 5) history.pop();
|
||
localStorage.setItem('searchHistory', JSON.stringify(history));
|
||
renderHistory();
|
||
}
|
||
|
||
function renderHistory() {
|
||
const history = JSON.parse(localStorage.getItem('searchHistory') || '[]');
|
||
const section = document.getElementById('historySection');
|
||
const list = document.getElementById('historyList');
|
||
|
||
if (history.length === 0) {
|
||
section.style.display = 'none';
|
||
return;
|
||
}
|
||
|
||
section.style.display = 'block';
|
||
list.innerHTML = history.map(q => `
|
||
<div class="history-item" onclick="searchFromHistory('${q.replace(/'/g, "\\'")}')">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--kt-ai-fg-muted)" stroke-width="2">
|
||
<path d="M12 8v4l3 3"/><circle cx="12" cy="12" r="9"/>
|
||
</svg>
|
||
<span>${q}</span>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
function searchFromHistory(query) {
|
||
document.getElementById('searchInput').value = query;
|
||
performSearch();
|
||
}
|
||
|
||
function clearHistory() {
|
||
localStorage.removeItem('searchHistory');
|
||
renderHistory();
|
||
}
|
||
|
||
init();
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|