v3: вернул форму вопроса, скрываю шаги если нет источника
This commit is contained in:
parent
83b4b06a6e
commit
48ded19d7e
137
index.html
137
index.html
@ -27,6 +27,10 @@
|
|||||||
.no-source { color: var(--kt-ai-fg-muted); font-style: italic; }
|
.no-source { color: var(--kt-ai-fg-muted); font-style: italic; }
|
||||||
.category-filter { display: flex; flex-wrap: wrap; gap: var(--kt-ai-space-2); justify-content: center; margin-top: var(--kt-ai-space-6); }
|
.category-filter { display: flex; flex-wrap: wrap; gap: var(--kt-ai-space-2); justify-content: center; margin-top: var(--kt-ai-space-6); }
|
||||||
.filter-chip { cursor: pointer; }
|
.filter-chip { cursor: pointer; }
|
||||||
|
.ask-form { max-width: 600px; margin: var(--kt-ai-space-8) auto; display: none; padding: var(--kt-ai-space-6); }
|
||||||
|
.ask-form[data-visible="true"] { display: block; }
|
||||||
|
.toast { position: fixed; bottom: var(--kt-ai-space-6); right: var(--kt-ai-space-6); background: var(--kt-ai-card-bg); border: 1px solid var(--kt-ai-border); padding: var(--kt-ai-space-4) var(--kt-ai-space-5); border-radius: var(--kt-ai-radius-xl); box-shadow: 0 8px 24px rgba(0,0,0,0.15); z-index: 1000; display: none; }
|
||||||
|
.toast[data-visible="true"] { display: block; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="kt-ai-app" data-kt-data-mode="demo">
|
<body class="kt-ai-app" data-kt-data-mode="demo">
|
||||||
@ -39,6 +43,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="kt-ai-spacer"></span>
|
<span class="kt-ai-spacer"></span>
|
||||||
<span class="kt-ai-chip" data-tone="orange">Демо-данные</span>
|
<span class="kt-ai-chip" data-tone="orange">Демо-данные</span>
|
||||||
|
<span class="kt-ai-spacer"></span>
|
||||||
|
<button class="kt-ai-btn" data-variant="primary" id="btnAsk">Задать вопрос</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@ -47,7 +53,7 @@
|
|||||||
<section class="kt-ai-hero" data-align="center" style="padding:0;margin-bottom:var(--kt-ai-space-8)">
|
<section class="kt-ai-hero" data-align="center" style="padding:0;margin-bottom:var(--kt-ai-space-8)">
|
||||||
<h1>Помощник по сопровождению договоров</h1>
|
<h1>Помощник по сопровождению договоров</h1>
|
||||||
<p class="kt-ai-hero-sub" style="max-width:600px;margin:0 auto">
|
<p class="kt-ai-hero-sub" style="max-width:600px;margin:0 auto">
|
||||||
Задайте вопрос о создании заявок, согласовании договоров или поиске решений — получите понятные шаги с инструкциями
|
Найдите готовый ответ или задайте свой вопрос — коллегии помогут
|
||||||
</p>
|
</p>
|
||||||
<div class="search-box" style="margin-top:var(--kt-ai-space-6)">
|
<div class="search-box" style="margin-top:var(--kt-ai-space-6)">
|
||||||
<input type="text" class="search-input" id="searchInput" placeholder="Например: как создать заявку в портале?">
|
<input type="text" class="search-input" id="searchInput" placeholder="Например: как создать заявку в портале?">
|
||||||
@ -75,10 +81,28 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<h3 style="color:var(--kt-ai-fg);margin-bottom:var(--kt-ai-space-2)">Ничего не найдено</h3>
|
<h3 style="color:var(--kt-ai-fg);margin-bottom:var(--kt-ai-space-2)">Ничего не найдено</h3>
|
||||||
<p style="color:var(--kt-ai-fg-muted)">Попробуйте изменить поисковый запрос или категорию</p>
|
<p style="color:var(--kt-ai-fg-muted)">Попробуйте изменить поисковый запрос или категорию</p>
|
||||||
|
<button class="kt-ai-btn" data-variant="primary" style="margin-top:var(--kt-ai-space-4)" onclick="showAskForm()">Задать свой вопрос</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="qa-grid" id="qaGrid"></div>
|
<div class="qa-grid" id="qaGrid"></div>
|
||||||
|
|
||||||
|
<form class="kt-ai-card ask-form" id="askForm">
|
||||||
|
<h2 style="margin-bottom:var(--kt-ai-space-4)">Новый вопрос</h2>
|
||||||
|
<p style="color:var(--kt-ai-fg-muted);margin-bottom:var(--kt-ai-space-4)">Опишите вопрос своими словами — ответ появится в базе после проверки</p>
|
||||||
|
<div class="kt-ai-field" style="margin-bottom:var(--kt-ai-space-4)">
|
||||||
|
<label for="questionTitle">Ваш вопрос</label>
|
||||||
|
<input type="text" class="kt-ai-input" id="questionTitle" required placeholder="Кратко сформулируйте вопрос">
|
||||||
|
</div>
|
||||||
|
<div class="kt-ai-field" style="margin-bottom:var(--kt-ai-space-4)">
|
||||||
|
<label for="questionDetails">Подробности</label>
|
||||||
|
<textarea class="kt-ai-textarea" id="questionDetails" rows="4" placeholder="Опишите вашу ситуацию"></textarea>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:var(--kt-ai-space-3)">
|
||||||
|
<button type="submit" class="kt-ai-btn" data-variant="primary">Отправить вопрос</button>
|
||||||
|
<button type="button" class="kt-ai-btn" data-variant="ghost" id="btnCancel">Отмена</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="kt-ai-wrap kt-ai-pagefoot">
|
<footer class="kt-ai-wrap kt-ai-pagefoot">
|
||||||
@ -87,6 +111,8 @@
|
|||||||
<span style="color:var(--kt-ai-fg-muted)">База знаний для сотрудников</span>
|
<span style="color:var(--kt-ai-fg-muted)">База знаний для сотрудников</span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<div class="toast" id="toast"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// === Демо-данные: база знаний ===
|
// === Демо-данные: база знаний ===
|
||||||
const DEMO_DATA = [
|
const DEMO_DATA = [
|
||||||
@ -94,57 +120,57 @@ const DEMO_DATA = [
|
|||||||
id: 1,
|
id: 1,
|
||||||
category: 'create',
|
category: 'create',
|
||||||
question: 'Как создать заявку в портале?',
|
question: 'Как создать заявку в портале?',
|
||||||
answer: '<ol class="step-list"><li>Войдите в портал по ссылке <a href="#" class="link-hint">portal.kazakhtelecom.kz</a></li><li>Нажмите кнопку «Создать заявку» в верхнем меню</li><li>Заполните обязательные поля: тип договора, контрагент, сумма</li><li>Прикрепите скан-копии документов</li><li>Нажмите «Отправить на согласование»</li></ol>',
|
answer: '<ol class="step-list"><li>Войдите в портал</li><li>Нажмите кнопку «Создать заявку»</li><li>Заполните поля: тип договора, контрагент, сумма</li><li>Прикрепите документы</li><li>Нажмите «Отправить на согласование»</li></ol>',
|
||||||
link: null
|
hasSource: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
category: 'create',
|
category: 'create',
|
||||||
question: 'Какие документы нужны для создания заявки?',
|
question: 'Какие документы нужны для создания заявки?',
|
||||||
answer: '<ol class="step-list"><li>Устав контрагента (действующая редакция)</li><li>Свидетельство о регистрации (ОГРН)</li><li>Приказ о назначении руководителя</li><li>Доверенность (если подписывает не руководитель)</li><li>Коммерческое предложение или счёт</li></ol>',
|
answer: '<ol class="step-list"><li>Устав контрагента</li><li>Свидетельство о регистрации (ОГРН)</li><li>Приказ о назначении руководителя</li><li>Доверенность (если подписывает не руководитель)</li><li>Коммерческое предложение или счёт</li></ol>',
|
||||||
link: null
|
hasSource: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
category: 'approve',
|
category: 'approve',
|
||||||
question: 'Кого добавить в согласование?',
|
question: 'Кого добавить в согласование?',
|
||||||
answer: '<ol class="step-list"><li>Руководитель вашего департамента (обязательно)</li><li>Юридический департамент — для договоров свыше 1 млн ₸</li><li>Финансовый департамент — если есть оплата</li><li>Департамент безопасности — для доступа к инфраструктуре</li></ol><p style="margin-top:var(--kt-ai-space-3);color:var(--kt-ai-fg-muted)">Маршрут согласования формируется автоматически по сумме и типу договора.</p>',
|
answer: '<p style="color:var(--kt-ai-fg-muted)">Инструкции пока нет. Обратитесь к руководителю департамента.</p>',
|
||||||
link: null
|
hasSource: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
category: 'approve',
|
category: 'approve',
|
||||||
question: 'Сколько времени занимает согласование?',
|
question: 'Сколько времени занимает согласование?',
|
||||||
answer: '<p>Нормативные сроки:</p><ul class="step-list"><li>До 500 тыс. ₸ — 3 рабочих дня</li><li>От 500 тыс. до 5 млн ₸ — 5 рабочих дней</li><li>Свыше 5 млн ₸ — 10 рабочих дней</li></ul>',
|
answer: '<p style="color:var(--kt-ai-fg-muted)">Инструкции пока нет. Нормативные сроки уточняйте в юридическом департаменте.</p>',
|
||||||
link: null
|
hasSource: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
category: 'find',
|
category: 'find',
|
||||||
question: 'Где найти решение по договору?',
|
question: 'Где найти решение по договору?',
|
||||||
answer: '<ol class="step-list"><li>Откройте портал в разделе «Мои заявки»</li><li>Найдите нужный договор по номеру или названию</li><li>Кликните на строку заявки</li><li>Перейдите на вкладку «Решения»</li><li>Скачайте файл с подписью и печатью</li></ol>',
|
answer: '<ol class="step-list"><li>Откройте раздел «Мои заявки»</li><li>Найдите договор по номеру</li><li>Перейдите на вкладку «Решения»</li><li>Скачайте файл</li></ol>',
|
||||||
link: null
|
hasSource: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
category: 'find',
|
category: 'find',
|
||||||
question: 'Как посмотреть историю изменений договора?',
|
question: 'Как посмотреть историю изменений договора?',
|
||||||
answer: '<ol class="step-list"><li>Откройте карточку договора</li><li>Нажмите вкладку «История» вверху</li><li>Увидите все изменения с датами и авторами</li><li>Можно скачать любую версию документа</li></ol>',
|
answer: '<p style="color:var(--kt-ai-fg-muted)">Инструкции пока нет. Попробуйте найти договор в архиве.</p>',
|
||||||
link: null
|
hasSource: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 7,
|
id: 7,
|
||||||
category: 'other',
|
category: 'other',
|
||||||
question: 'Что делать, если заявка возвращена на доработку?',
|
question: 'Что делать, если заявка возвращена на доработку?',
|
||||||
answer: '<ol class="step-list"><li>Откройте уведомление о возврате</li><li>Прочитайте комментарий согласующего</li><li>Исправьте замечания в заявке</li><li>Нажмите «Отправить повторно»</li></ol><p style="margin-top:var(--kt-ai-space-3);color:var(--kt-ai-fg-muted)">Заявка останется в том же маршруте согласования, срок обнулится.</p>',
|
answer: '<ol class="step-list"><li>Откройте уведомление</li><li>Прочитайте комментарий</li><li>Исправьте замечания</li><li>Нажмите «Отправить повторно»</li></ol>',
|
||||||
link: null
|
hasSource: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 8,
|
id: 8,
|
||||||
category: 'other',
|
category: 'other',
|
||||||
question: 'Как отозвать заявку на согласовании?',
|
question: 'Как отозвать заявку на согласовании?',
|
||||||
answer: '<ol class="step-list"><li>Найдите заявку в разделе «Мои заявки»</li><li>Убедитесь, что статус «На согласовании»</li><li>Нажмите кнопку «Отозвать»</li><li>Укажите причину отзыва (обязательно)</li><li>Подтвердите отзыв</li></ol><p style="margin-top:var(--kt-ai-space-3);color:var(--kt-ai-fg-muted)">После отзыва заявка перейдёт в статус «Черновик».</p>',
|
answer: '<p style="color:var(--kt-ai-fg-muted)">Инструкции пока нет. Свяжитесь с согласующим.</p>',
|
||||||
link: null
|
hasSource: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -155,7 +181,8 @@ const FILTERS = [
|
|||||||
|
|
||||||
let state = {
|
let state = {
|
||||||
currentCategory: 'all',
|
currentCategory: 'all',
|
||||||
searchQuery: ''
|
searchQuery: '',
|
||||||
|
userQuestions: JSON.parse(localStorage.getItem('userQuestions') || '[]')
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Инициализация ===
|
// === Инициализация ===
|
||||||
@ -169,7 +196,14 @@ function renderQA() {
|
|||||||
const grid = document.getElementById('qaGrid');
|
const grid = document.getElementById('qaGrid');
|
||||||
const emptyState = document.getElementById('emptyState');
|
const emptyState = document.getElementById('emptyState');
|
||||||
|
|
||||||
let data = DEMO_DATA;
|
let data = [...DEMO_DATA, ...state.userQuestions.map((q, i) => ({
|
||||||
|
id: 'user-' + i,
|
||||||
|
category: q.category || 'other',
|
||||||
|
question: q.title,
|
||||||
|
answer: '<p style="color:var(--kt-ai-fg-muted)">Вопрос на рассмотрении</p>',
|
||||||
|
hasSource: false,
|
||||||
|
isUser: true
|
||||||
|
}))];
|
||||||
|
|
||||||
// Фильтр по категории
|
// Фильтр по категории
|
||||||
if (state.currentCategory !== 'all') {
|
if (state.currentCategory !== 'all') {
|
||||||
@ -180,8 +214,7 @@ function renderQA() {
|
|||||||
if (state.searchQuery) {
|
if (state.searchQuery) {
|
||||||
const query = state.searchQuery.toLowerCase();
|
const query = state.searchQuery.toLowerCase();
|
||||||
data = data.filter(q =>
|
data = data.filter(q =>
|
||||||
q.question.toLowerCase().includes(query) ||
|
q.question.toLowerCase().includes(query)
|
||||||
q.answer.toLowerCase().includes(query)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,12 +226,15 @@ function renderQA() {
|
|||||||
|
|
||||||
emptyState.style.display = 'none';
|
emptyState.style.display = 'none';
|
||||||
grid.innerHTML = data.map(q => {
|
grid.innerHTML = data.map(q => {
|
||||||
const linkHtml = q.link
|
const answerHtml = q.isUser
|
||||||
? `<p class="link-hint" style="margin-top:var(--kt-ai-space-3)">📄 <a href="${q.link}" target="_blank" rel="noopener">Полная инструкция</a></p>`
|
? q.answer
|
||||||
: `<p class="no-source" style="margin-top:var(--kt-ai-space-3);font-size:var(--kt-ai-text-sm)">Источника пока нет</p>`;
|
: (q.hasSource
|
||||||
|
? q.answer + '<p class="link-hint" style="margin-top:var(--kt-ai-space-3)">📄 Инструкция проверена</p>'
|
||||||
|
: q.answer
|
||||||
|
);
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="kt-ai-card qa-card" data-id="${q.id}" data-expanded="false" onclick="toggleCard(${q.id})">
|
<div class="kt-ai-card qa-card" data-id="${q.id}" data-expanded="false" onclick="toggleCard('${q.id}')">
|
||||||
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:var(--kt-ai-space-3)">
|
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:var(--kt-ai-space-3)">
|
||||||
<h3 style="margin:0;color:var(--kt-ai-fg)">${q.question}</h3>
|
<h3 style="margin:0;color:var(--kt-ai-fg)">${q.question}</h3>
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--kt-ai-fg-muted)" stroke-width="2" style="flex-shrink:0;transition:transform 0.3s" class="chevron">
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--kt-ai-fg-muted)" stroke-width="2" style="flex-shrink:0;transition:transform 0.3s" class="chevron">
|
||||||
@ -206,8 +242,7 @@ function renderQA() {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="qa-answer">
|
<div class="qa-answer">
|
||||||
${q.answer}
|
${answerHtml}
|
||||||
${linkHtml}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`}).join('');
|
`}).join('');
|
||||||
@ -217,7 +252,7 @@ function renderQA() {
|
|||||||
function toggleCard(id) {
|
function toggleCard(id) {
|
||||||
const cards = document.querySelectorAll('.qa-card');
|
const cards = document.querySelectorAll('.qa-card');
|
||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
if (parseInt(card.dataset.id) !== id) {
|
if (card.dataset.id !== String(id)) {
|
||||||
card.dataset.expanded = 'false';
|
card.dataset.expanded = 'false';
|
||||||
} else {
|
} else {
|
||||||
card.dataset.expanded = card.dataset.expanded === 'true' ? 'false' : 'true';
|
card.dataset.expanded = card.dataset.expanded === 'true' ? 'false' : 'true';
|
||||||
@ -225,6 +260,20 @@ function toggleCard(id) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showAskForm() {
|
||||||
|
document.getElementById('askForm').dataset.visible = 'true';
|
||||||
|
document.getElementById('qaGrid').style.display = 'none';
|
||||||
|
document.getElementById('categoryFilter').style.display = 'none';
|
||||||
|
document.getElementById('emptyState').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideAskForm() {
|
||||||
|
document.getElementById('askForm').dataset.visible = 'false';
|
||||||
|
document.getElementById('qaGrid').style.display = 'grid';
|
||||||
|
document.getElementById('categoryFilter').style.display = 'flex';
|
||||||
|
renderQA();
|
||||||
|
}
|
||||||
|
|
||||||
// === Обработчики событий ===
|
// === Обработчики событий ===
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
// Поиск
|
// Поиск
|
||||||
@ -242,10 +291,40 @@ function setupEventListeners() {
|
|||||||
renderQA();
|
renderQA();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Кнопка "Задать вопрос"
|
||||||
|
document.getElementById('btnAsk').addEventListener('click', showAskForm);
|
||||||
|
|
||||||
|
// Отмена
|
||||||
|
document.getElementById('btnCancel').addEventListener('click', hideAskForm);
|
||||||
|
|
||||||
|
// Отправка формы
|
||||||
|
document.getElementById('askForm').addEventListener('submit', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const title = document.getElementById('questionTitle').value;
|
||||||
|
const details = document.getElementById('questionDetails').value;
|
||||||
|
|
||||||
|
state.userQuestions.push({ title, details, date: new Date().toISOString() });
|
||||||
|
localStorage.setItem('userQuestions', JSON.stringify(state.userQuestions));
|
||||||
|
|
||||||
|
document.getElementById('askForm').reset();
|
||||||
|
hideAskForm();
|
||||||
|
|
||||||
|
showToast('Вопрос отправлен. Коллеги ответят в чате.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showToast(message) {
|
||||||
|
const toast = document.getElementById('toast');
|
||||||
|
toast.textContent = message;
|
||||||
|
toast.dataset.visible = 'true';
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.dataset.visible = 'false';
|
||||||
|
}, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сделать функцию доступной глобально
|
|
||||||
window.toggleCard = toggleCard;
|
window.toggleCard = toggleCard;
|
||||||
|
window.showAskForm = showAskForm;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user