191 lines
9.1 KiB
HTML
191 lines
9.1 KiB
HTML
{% extends "page.html" %}
|
||
{% block page_content %}
|
||
<style>
|
||
.uq-table { width:100%; border-collapse:collapse; }
|
||
.uq-table th, .uq-table td { padding:10px 14px; text-align:left; border-bottom:1px solid var(--border); font-size:13px; }
|
||
.uq-table th { font-weight:600; color:var(--text-muted); background:var(--bg-card); }
|
||
.uq-table td { vertical-align:top; }
|
||
.badge { display:inline-block; padding:2px 8px; border-radius:4px; font-size:11px; font-weight:600; }
|
||
.badge.new { background:#fff3cd; color:#856404; }
|
||
.badge.auto_added { background:#cce5ff; color:#004085; }
|
||
.badge.reviewed { background:#d4edda; color:#155724; }
|
||
.badge.ignored { background:#f8f9fa; color:#6c757d; }
|
||
.modal-overlay { display:none; position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.4); z-index:1000; align-items:center; justify-content:center; }
|
||
.modal-overlay.open { display:flex; }
|
||
.modal-box { background:var(--bg-card); border-radius:12px; padding:30px; width:650px; max-width:90vw; max-height:85vh; overflow-y:auto; }
|
||
.modal-box h3 { margin-bottom:20px; }
|
||
.form-group { margin-bottom:14px; }
|
||
.form-group label { display:block; font-weight:600; margin-bottom:4px; font-size:13px; color:var(--text-muted); }
|
||
.form-group input, .form-group textarea, .form-group select {
|
||
width:100%; padding:8px 12px; border:1px solid var(--border); border-radius:6px; font-size:14px; }
|
||
.form-group textarea { min-height:80px; resize:vertical; }
|
||
.modal-actions { display:flex; gap:12px; margin-top:16px; }
|
||
.filter-bar { display:flex; gap:12px; margin-bottom:16px; align-items:center; }
|
||
.filter-bar select { padding:8px 12px; border:1px solid var(--border); border-radius:6px; font-size:13px; }
|
||
</style>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><h2>Неизвестные вопросы</h2></div>
|
||
<div class="filter-bar">
|
||
<select id="uq-status-filter" onchange="loadUQ()">
|
||
<option value="">Все статусы</option>
|
||
<option value="new">Новые</option>
|
||
<option value="auto_added">Авто-сгенерированные</option>
|
||
<option value="reviewed">Проверенные</option>
|
||
<option value="ignored">Игнорированные</option>
|
||
</select>
|
||
<span id="uq-count" style="font-size:13px;color:var(--text-muted);"></span>
|
||
</div>
|
||
<table class="uq-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Вопрос</th>
|
||
<th>Смысл (NLP)</th>
|
||
<th>Раз</th>
|
||
<th>Статус</th>
|
||
<th>Сгенерированный ответ</th>
|
||
<th>Дата</th>
|
||
<th>Действия</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="uq-table-body">
|
||
<tr><td colspan="7" style="text-align:center;padding:30px;color:var(--text-muted);">Загрузка...</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="modal-overlay" id="uq-modal">
|
||
<div class="modal-box">
|
||
<h3 id="uq-modal-title">Проверить вопрос</h3>
|
||
<form id="uq-form">
|
||
<input type="hidden" id="uq-edit-id">
|
||
<div class="form-group">
|
||
<label>Исходный вопрос</label>
|
||
<input type="text" id="uq-original" readonly style="background:var(--bg-secondary,#f5f5f5);">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Канонический вопрос</label>
|
||
<input type="text" id="uq-question" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Ответ</label>
|
||
<textarea id="uq-answer" required></textarea>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Ключевые слова (через запятую)</label>
|
||
<input type="text" id="uq-keywords">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Категория</label>
|
||
<select id="uq-category">
|
||
<option value="1">О компании</option>
|
||
<option value="2">Аудит безопасности</option>
|
||
<option value="3">Сервисное обслуживание (SLA)</option>
|
||
<option value="4">Реагирование на инциденты</option>
|
||
<option value="5">Технический надзор</option>
|
||
<option value="6">Документация и нормативы</option>
|
||
<option value="7">Риск-инжиниринг</option>
|
||
<option value="8">Отрасли и кейсы</option>
|
||
</select>
|
||
</div>
|
||
<div class="modal-actions">
|
||
<button type="submit" class="btn btn-primary">Опубликовать в базу знаний</button>
|
||
<button type="button" class="btn" onclick="closeModal()">Отмена</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
var allUQ = [];
|
||
|
||
function loadUQ(){
|
||
fetch('/api/bot/unknown-questions').then(function(r){ return r.json() }).then(function(data){
|
||
allUQ = data;
|
||
filterUQ();
|
||
});
|
||
}
|
||
|
||
function filterUQ(){
|
||
var status = document.getElementById('uq-status-filter').value;
|
||
var filtered = allUQ;
|
||
if(status) filtered = allUQ.filter(function(q){ return q.status === status; });
|
||
document.getElementById('uq-count').textContent = filtered.length + ' из ' + allUQ.length;
|
||
renderUQ(filtered);
|
||
}
|
||
|
||
function renderUQ(items){
|
||
var tbody = document.getElementById('uq-table-body');
|
||
if(!items.length){
|
||
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;padding:30px;color:var(--text-muted);">Нет вопросов</td></tr>';
|
||
return;
|
||
}
|
||
var html = '';
|
||
items.forEach(function(q){
|
||
var statusLabels = {new:'Новый',auto_added:'Авто',reviewed:'Проверен',ignored:'Игнор'};
|
||
html += '<tr>' +
|
||
'<td><strong>' + esc(q.question_text) + '</strong></td>' +
|
||
'<td>' + esc(q.normalized_text || '—') + '</td>' +
|
||
'<td style="text-align:center;">' + q.ask_count + '</td>' +
|
||
'<td><span class="badge ' + q.status + '">' + (statusLabels[q.status]||q.status) + '</span></td>' +
|
||
'<td style="font-size:12px;">' + esc((q.generated_answer||'').substring(0,80)) + (q.generated_answer&&q.generated_answer.length>80?'...':'') + '</td>' +
|
||
'<td style="font-size:12px;">' + (q.created_at ? q.created_at.substring(0,10) : '—') + '</td>' +
|
||
'<td>';
|
||
if(q.status === 'new' || q.status === 'auto_added'){
|
||
html += '<button class="btn btn-sm" onclick="openReview(' + q.id + ')" title="Проверить">✏️</button> ';
|
||
html += '<button class="btn btn-sm" onclick="ignoreUQ(' + q.id + ')" style="color:#dc3545;" title="Игнорировать">🗑</button>';
|
||
}
|
||
html += '</td></tr>';
|
||
});
|
||
tbody.innerHTML = html;
|
||
}
|
||
|
||
function openReview(id){
|
||
var q = allUQ.find(function(x){ return x.id === id; });
|
||
if(!q) return;
|
||
document.getElementById('uq-edit-id').value = id;
|
||
document.getElementById('uq-original').value = q.question_text;
|
||
document.getElementById('uq-question').value = q.normalized_text || q.question_text;
|
||
document.getElementById('uq-answer').value = q.generated_answer || '';
|
||
document.getElementById('uq-keywords').value = (q.generated_keywords || []).join(', ');
|
||
document.getElementById('uq-category').value = q.generated_category_id || '1';
|
||
document.getElementById('uq-modal-title').textContent = 'Проверить вопрос #' + id;
|
||
document.getElementById('uq-modal').classList.add('open');
|
||
}
|
||
|
||
function closeModal(){
|
||
document.getElementById('uq-modal').classList.remove('open');
|
||
}
|
||
|
||
document.getElementById('uq-form').addEventListener('submit', function(e){
|
||
e.preventDefault();
|
||
var id = document.getElementById('uq-edit-id').value;
|
||
var data = {
|
||
question: document.getElementById('uq-question').value,
|
||
answer: document.getElementById('uq-answer').value,
|
||
keywords: document.getElementById('uq-keywords').value.split(',').map(function(s){ return s.trim(); }).filter(Boolean),
|
||
category_id: parseInt(document.getElementById('uq-category').value),
|
||
};
|
||
fetch('/api/bot/unknown-questions/' + id + '/edit', {
|
||
method: 'PUT', headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify(data)
|
||
}).then(function(r){ return r.json() }).then(function(d){
|
||
if(d.ok){ closeModal(); loadUQ(); showNotification('Опубликовано в базу знаний', 'success'); }
|
||
else showNotification('Ошибка', 'error');
|
||
});
|
||
});
|
||
|
||
function ignoreUQ(id){
|
||
if(!confirm('Игнорировать вопрос?')) return;
|
||
fetch('/api/bot/unknown-questions/' + id + '/ignore', { method: 'PUT' })
|
||
.then(function(r){ return r.json() }).then(function(d){
|
||
if(d.ok){ loadUQ(); showNotification('Игнорировано', 'success'); }
|
||
});
|
||
}
|
||
|
||
function esc(s){ return s ? s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : ''; }
|
||
|
||
loadUQ();
|
||
</script>
|
||
{% endblock %}
|