Files
site_aegisone/py_service/app/templates/pages/bot_unknown.html
T

191 lines
9.1 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.
{% 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,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') : ''; }
loadUQ();
</script>
{% endblock %}