ya-aliya-soprovozhdayu-dogov-2/index.html

435 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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()">&times;</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>