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

211 lines
9.7 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; }
.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" style="max-width:650px;">
<button type="button" class="modal-close" onclick="closeModal()"></button>
<h2 id="uq-modal-title">Проверить вопрос</h2>
<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="form-actions" style="justify-content:flex-end;">
<button type="submit" class="btn btn-primary">Опубликовать в базу знаний</button>
<button type="button" class="btn" onclick="closeModal()">Отмена</button>
</div>
</form>
</div>
</div>
<div class="modal-overlay" id="confirm-ignore-uq">
<div class="modal" style="max-width:420px;">
<h2 style="font-size:16px;margin-bottom:8px;">Игнорировать вопрос?</h2>
<p style="color:var(--text-secondary);font-size:14px;margin-bottom:20px;">
Вопрос <strong id="ignore-uq-text"></strong> будет отмечен как игнорированный.
</p>
<div class="form-actions" style="justify-content:flex-end;">
<button type="button" class="btn btn-danger" onclick="confirmIgnoreUQ()">Игнорировать</button>
<button type="button" class="btn" onclick="closeConfirmIgnoreUQ()">Отмена</button>
</div>
</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-secondary btn-sm" onclick="openReview(' + q.id + ')" title="Проверить">✎</button> ';
html += '<button class="btn btn-danger btn-sm" onclick="openConfirmIgnoreUQ(' + q.id + ', \'' + esc(q.question_text).replace(/'/g, "\\'") + '\')" title="Игнорировать">✕</button>';
}
html += '</td></tr>';
});
tbody.innerHTML = html;
if(typeof sortTables === 'function') sortTables();
}
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');
});
});
var ignoreUQId = null;
function openConfirmIgnoreUQ(id, text){
ignoreUQId = id;
document.getElementById('ignore-uq-text').textContent = text || '#' + id;
document.getElementById('confirm-ignore-uq').classList.add('open');
}
function closeConfirmIgnoreUQ(){
document.getElementById('confirm-ignore-uq').classList.remove('open');
ignoreUQId = null;
}
function confirmIgnoreUQ(){
if(!ignoreUQId) return;
var id = ignoreUQId;
closeConfirmIgnoreUQ();
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 %}