Files
wevads-platform/scripts/ia-knowledge.php
2026-02-26 04:53:11 +01:00

755 lines
37 KiB
PHP
Executable File

<?php
session_start();
error_reporting(E_ALL);
ini_set('display_errors', 1);
try {
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $e) {
die("DB Error: " . $e->getMessage());
}
$message = '';
$messageType = '';
$debug = '';
// Actions POST
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
// Debug
$debug = "Action: $action | POST: " . json_encode($_POST);
try {
if ($action === 'add') {
$type = $_POST['type'] ?? 'qa';
$category = trim($_POST['category'] ?? 'Général');
$priority = intval($_POST['priority'] ?? 5);
if ($type === 'qa') {
$question = trim($_POST['question'] ?? '');
$answer = trim($_POST['answer'] ?? '');
$keywords = trim($_POST['keywords'] ?? '');
if (empty($question)) {
throw new Exception("Question requise");
}
if (empty($answer)) {
throw new Exception("Réponse requise");
}
$keywordsArray = null;
if ($keywords) {
$kw = array_map('trim', explode(',', $keywords));
$keywordsArray = '{' . implode(',', $kw) . '}';
}
$sql = "INSERT INTO admin.commonia_knowledge (type, category, question, answer, keywords, priority, created_at) VALUES (:type, :cat, :q, :a, :kw, :prio, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':type' => 'qa',
':cat' => $category,
':q' => $question,
':a' => $answer,
':kw' => $keywordsArray,
':prio' => $priority
]);
} else {
// DOC
$title = trim($_POST['title'] ?? '');
$content = trim($_POST['content'] ?? '');
$author = trim($_POST['author'] ?? 'Admin');
if (empty($title)) {
throw new Exception("Titre requis");
}
$sql = "INSERT INTO admin.commonia_knowledge (type, category, title, content, question, answer, author, priority, created_at) VALUES (:type, :cat, :title, :content, :q, :a, :author, :prio, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':type' => 'doc',
':cat' => $category,
':title' => $title,
':content' => $content,
':q' => $title,
':a' => $content,
':author' => $author,
':prio' => $priority
]);
}
$message = "✅ Entrée ajoutée avec succès! (ID: " . $pdo->lastInsertId() . ")";
$messageType = 'success';
// Redirect pour éviter resoumission
header("Location: ia-knowledge.php?tab=" . ($_GET['tab'] ?? 'all') . "&msg=added");
exit;
}
if ($action === 'update') {
$id = intval($_POST['id'] ?? 0);
$type = $_POST['type'] ?? 'qa';
$category = trim($_POST['category'] ?? 'Général');
$priority = intval($_POST['priority'] ?? 5);
if ($id <= 0) {
throw new Exception("ID invalide");
}
if ($type === 'qa') {
$question = trim($_POST['question'] ?? '');
$answer = trim($_POST['answer'] ?? '');
$keywords = trim($_POST['keywords'] ?? '');
$keywordsArray = null;
if ($keywords) {
$kw = array_map('trim', explode(',', $keywords));
$keywordsArray = '{' . implode(',', $kw) . '}';
}
$sql = "UPDATE admin.commonia_knowledge SET category = :cat, question = :q, answer = :a, keywords = :kw, priority = :prio, updated_at = NOW() WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':cat' => $category,
':q' => $question,
':a' => $answer,
':kw' => $keywordsArray,
':prio' => $priority,
':id' => $id
]);
} else {
$title = trim($_POST['title'] ?? '');
$content = trim($_POST['content'] ?? '');
$author = trim($_POST['author'] ?? 'Admin');
$sql = "UPDATE admin.commonia_knowledge SET category = :cat, title = :title, content = :content, question = :q, answer = :a, author = :author, priority = :prio, updated_at = NOW() WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':cat' => $category,
':title' => $title,
':content' => $content,
':q' => $title,
':a' => $content,
':author' => $author,
':prio' => $priority,
':id' => $id
]);
}
$message = "✅ Entrée #$id modifiée!";
$messageType = 'success';
header("Location: ia-knowledge.php?tab=" . ($_GET['tab'] ?? 'all') . "&msg=updated");
exit;
}
if ($action === 'delete') {
$id = intval($_POST['id'] ?? 0);
if ($id > 0) {
$stmt = $pdo->prepare("DELETE FROM admin.commonia_knowledge WHERE id = ?");
$stmt->execute([$id]);
header("Location: ia-knowledge.php?tab=" . ($_GET['tab'] ?? 'all') . "&msg=deleted");
exit;
}
}
} catch (Exception $e) {
$message = "❌ Erreur: " . $e->getMessage();
$messageType = 'error';
$debug .= " | Exception: " . $e->getMessage();
}
}
// Messages de redirection
if (isset($_GET['msg'])) {
$msgs = [
'added' => '✅ Entrée ajoutée avec succès!',
'updated' => '✅ Entrée modifiée avec succès!',
'deleted' => '✅ Entrée supprimée!'
];
$message = $msgs[$_GET['msg']] ?? '';
$messageType = 'success';
}
// API pour récupérer une entrée (AJAX)
if (isset($_GET['api']) && $_GET['api'] === 'get') {
header('Content-Type: application/json');
$id = intval($_GET['id'] ?? 0);
$stmt = $pdo->prepare("SELECT * FROM admin.commonia_knowledge WHERE id = ?");
$stmt->execute([$id]);
$entry = $stmt->fetch(PDO::FETCH_ASSOC);
echo json_encode($entry ?: ['error' => 'Not found']);
exit;
}
// Stats
$stats = [
'total' => $pdo->query("SELECT COUNT(*) FROM admin.commonia_knowledge")->fetchColumn(),
'qa' => $pdo->query("SELECT COUNT(*) FROM admin.commonia_knowledge WHERE type = 'qa'")->fetchColumn(),
'doc' => $pdo->query("SELECT COUNT(*) FROM admin.commonia_knowledge WHERE type = 'doc'")->fetchColumn(),
'pending' => $pdo->query("SELECT COUNT(*) FROM admin.chatbot_pending_knowledge")->fetchColumn(),
'discussions' => $pdo->query("SELECT COUNT(*) FROM admin.chatbot_conversations_history")->fetchColumn(),
'articles' => $pdo->query("SELECT COUNT(*) FROM admin.knowledge_base")->fetchColumn()
];
// Filtres
$tab = $_GET['tab'] ?? 'all';
$search = $_GET['search'] ?? '';
$catFilter = $_GET['category'] ?? '';
// Query
$where = [];
$params = [];
if ($tab === 'qa') { $where[] = "type = 'qa'"; }
elseif ($tab === 'doc') { $where[] = "type = 'doc'"; }
elseif ($tab === 'discussions') {
$specialTab = true;
$entries = $pdo->query("SELECT id, title as question, summary as answer, category, 'discussion' as type, 5 as priority, created_at FROM admin.chatbot_conversations_history ORDER BY id DESC LIMIT 100")->fetchAll(PDO::FETCH_ASSOC);
}
elseif ($tab === 'articles') {
$specialTab = true;
$entries = $pdo->query("SELECT id, title as question, content as answer, category, 'article' as type, 5 as priority, created_at FROM admin.knowledge_base ORDER BY id DESC LIMIT 100")->fetchAll(PDO::FETCH_ASSOC);
}
if ($search) {
$where[] = "(question ILIKE ? OR answer ILIKE ? OR title ILIKE ? OR content ILIKE ?)";
$params = array_merge($params, ["%$search%", "%$search%", "%$search%", "%$search%"]);
}
if ($catFilter) {
$where[] = "category = ?";
$params[] = $catFilter;
}
if (!isset($specialTab)) {
$whereSQL = $where ? 'WHERE ' . implode(' AND ', $where) : '';
$sql = "SELECT * FROM admin.commonia_knowledge $whereSQL ORDER BY id DESC LIMIT 100";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$entries = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// Pending
$pending = $pdo->query("SELECT * FROM admin.chatbot_pending_knowledge ORDER BY created_at DESC")->fetchAll(PDO::FETCH_ASSOC);
// Categories
$categories = $pdo->query("SELECT DISTINCT category FROM admin.commonia_knowledge WHERE category IS NOT NULL AND category != '' ORDER BY category")->fetchAll(PDO::FETCH_COLUMN);
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Knowledge Base - WEVAL IA</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
:root { --primary: #06b6d4; --bg: #f8fafc; --card: #ffffff; --text: #1e293b; --muted: #64748b; --border: #e2e8f0; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: var(--bg); color: var(--text); }
.container { max-width: 1400px; margin: 0 auto; padding: 1.5rem; }
.back-link { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--muted); text-decoration: none; margin-bottom: 1rem; font-size: 0.9rem; }
.back-link:hover { color: var(--primary); }
.header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; gap: 1rem; }
.header-left { display: flex; align-items: center; gap: 1rem; }
.header-icon { width: 44px; height: 44px; background: linear-gradient(135deg, var(--primary), #3b82f6); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.1rem; }
.header h1 { font-size: 1.5rem; font-weight: 700; }
.header p { color: var(--muted); font-size: 0.85rem; }
.header-actions { display: flex; gap: 0.5rem; }
.btn { padding: 0.5rem 1rem; border-radius: 8px; font-size: 0.85rem; font-weight: 500; cursor: pointer; display: inline-flex; align-items: center; gap: 0.4rem; border: 1px solid var(--border); background: white; color: var(--text); text-decoration: none; transition: all 0.15s; }
.btn:hover { background: var(--bg); }
.btn-primary { background: linear-gradient(135deg, var(--primary), #3b82f6); color: white; border: none; }
.btn-danger { background: #ef4444; color: white; border: none; }
.btn-success { background: #22c55e; color: white; border: none; }
.btn-warning { background: #f59e0b; color: white; border: none; }
.btn-info { background: #3b82f6; color: white; border: none; }
.btn-sm { padding: 0.3rem 0.5rem; font-size: 0.75rem; }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
.stat-card { background: var(--card); border-radius: 10px; padding: 1rem; text-align: center; border: 1px solid var(--border); }
.stat-card .label { font-size: 0.7rem; color: var(--muted); text-transform: uppercase; }
.stat-card .value { font-size: 1.75rem; font-weight: 700; }
.stat-card .value.cyan { color: var(--primary); }
.stat-card .value.purple { color: #8b5cf6; }
.stat-card .value.orange { color: #f59e0b; }
.tabs { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
.tab { padding: 0.4rem 0.8rem; border-radius: 6px; background: white; border: 1px solid var(--border); color: var(--muted); text-decoration: none; font-size: 0.8rem; }
.tab:hover { border-color: var(--primary); }
.tab.active { background: var(--primary); color: white; border-color: var(--primary); }
.tab .count { background: rgba(0,0,0,0.1); padding: 0.1rem 0.35rem; border-radius: 6px; font-size: 0.65rem; margin-left: 0.3rem; }
.tab.active .count { background: rgba(255,255,255,0.3); }
.filters { display: flex; gap: 0.75rem; margin-bottom: 1rem; }
.search-box { flex: 1; position: relative; }
.search-box input { width: 100%; padding: 0.6rem 0.8rem 0.6rem 2.2rem; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; }
.search-box i { position: absolute; left: 0.75rem; top: 50%; transform: translateY(-50%); color: var(--muted); font-size: 0.85rem; }
.filter-select { padding: 0.6rem; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; }
.table-container { background: var(--card); border-radius: 10px; border: 1px solid var(--border); overflow-x: auto; }
table { width: 100%; border-collapse: collapse; }
th { background: var(--bg); padding: 0.6rem; text-align: left; font-size: 0.7rem; font-weight: 600; color: var(--muted); text-transform: uppercase; }
td { padding: 0.6rem; border-top: 1px solid var(--border); font-size: 0.8rem; }
tr:hover { background: #fafafa; }
.badge { display: inline-block; padding: 0.15rem 0.4rem; border-radius: 8px; font-size: 0.65rem; font-weight: 500; }
.badge-qa { background: #e0f2fe; color: #0369a1; }
.badge-doc { background: #f3e8ff; color: #7c3aed; }
.badge-cat { background: #f1f5f9; color: #475569; }
.badge-prio { background: #fef3c7; color: #92400e; }
.text-truncate { max-width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }
.actions-cell { display: flex; gap: 0.25rem; }
.alert { padding: 0.75rem 1rem; border-radius: 8px; margin-bottom: 1rem; font-size: 0.9rem; }
.alert-success { background: #dcfce7; color: #166534; }
.alert-error { background: #fee2e2; color: #991b1b; }
.debug { background: #fef3c7; color: #92400e; padding: 0.5rem; font-size: 0.75rem; margin-bottom: 1rem; border-radius: 6px; font-family: monospace; }
.empty-state { text-align: center; padding: 2rem; color: var(--muted); }
/* Modal */
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 9999; align-items: center; justify-content: center; padding: 1rem; }
.modal-overlay.show { display: flex; }
.modal { background: white; border-radius: 12px; width: 100%; max-width: 700px; max-height: 95vh; display: flex; flex-direction: column; }
.modal-header { padding: 1rem 1.25rem; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; flex-shrink: 0; }
.modal-header h2 { font-size: 1rem; display: flex; align-items: center; gap: 0.5rem; }
.modal-close { background: none; border: none; font-size: 1.5rem; cursor: pointer; color: var(--muted); }
.modal-body { padding: 1.25rem; overflow-y: auto; flex: 1; }
.modal-footer { padding: 1rem 1.25rem; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 0.5rem; flex-shrink: 0; }
.form-group { margin-bottom: 0.875rem; }
.form-group label { display: block; margin-bottom: 0.3rem; font-weight: 500; font-size: 0.8rem; }
.form-group input, .form-group select { width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: 6px; font-size: 0.9rem; }
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: 6px;
font-size: 0.9rem;
font-family: inherit;
line-height: 1.5;
resize: vertical;
min-height: 150px;
}
.form-group textarea.large { min-height: 250px; }
.form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(6,182,212,0.15); }
.type-selector { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 1rem; }
.type-option { padding: 0.75rem; border: 2px solid var(--border); border-radius: 8px; cursor: pointer; text-align: center; transition: all 0.15s; }
.type-option:hover { border-color: #a5f3fc; }
.type-option.active { border-color: var(--primary); background: #ecfeff; }
.type-option i { font-size: 1.1rem; display: block; margin-bottom: 0.25rem; color: var(--muted); }
.type-option.active i { color: var(--primary); }
.type-option strong { font-size: 0.85rem; }
.type-option small { font-size: 0.7rem; color: var(--muted); }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; }
.view-content { background: #f8fafc; border-radius: 6px; padding: 1rem; max-height: 300px; overflow-y: auto; white-space: pre-wrap; font-size: 0.85rem; line-height: 1.6; border: 1px solid var(--border); }
.view-label { font-weight: 600; color: var(--muted); font-size: 0.7rem; text-transform: uppercase; margin-bottom: 0.25rem; }
.view-section { margin-bottom: 1rem; }
.view-meta { display: flex; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1rem; }
.view-meta-item { background: #f1f5f9; padding: 0.3rem 0.6rem; border-radius: 4px; font-size: 0.75rem; }
@media (max-width: 768px) {
.stats-grid { grid-template-columns: repeat(2, 1fr); }
.form-row { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="container">
<a href="/ia-index.php" class="back-link"><i class="fas fa-arrow-left"></i> Retour</a>
<div class="header">
<div class="header-left">
<div class="header-icon"><i class="fas fa-brain"></i></div>
<div>
<h1>Knowledge Base</h1>
<p>commonia_knowledge</p>
</div>
</div>
<div class="header-actions">
<a href="/hamid-fullscreen.php" class="btn"><i class="fas fa-comments"></i> Chat</a>
<button type="button" class="btn btn-primary" onclick="openAddModal()"><i class="fas fa-plus"></i> Ajouter</button>
</div>
</div>
<?php if ($debug && isset($_POST['action'])): ?>
<div class="debug">DEBUG: <?= htmlspecialchars($debug) ?></div>
<?php endif; ?>
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?>"><?= htmlspecialchars($message) ?></div>
<?php endif; ?>
<div class="stats-grid">
<div class="stat-card"><div class="label">Total</div><div class="value"><?= $stats['total'] ?></div></div>
<div class="stat-card"><div class="label">Q&A</div><div class="value cyan"><?= $stats['qa'] ?></div></div>
<div class="stat-card"><div class="label">Docs</div><div class="value purple"><?= $stats['doc'] ?></div></div>
<div class="stat-card"><div class="label">Attente</div><div class="value orange"><?= $stats['pending'] ?></div></div>
<div class="stat-card"><div class="label">Discussions</div><div class="value green"><?= $stats['discussions'] ?? 0 ?></div></div>
<div class="stat-card"><div class="label">Articles</div><div class="value blue"><?= $stats['articles'] ?? 0 ?></div></div>
</div>
<div class="tabs">
<a href="?tab=all" class="tab <?= $tab === 'all' ? 'active' : '' ?>">Tout<span class="count"><?= $stats['total'] ?></span></a>
<a href="?tab=qa" class="tab <?= $tab === 'qa' ? 'active' : '' ?>">Q&A<span class="count"><?= $stats['qa'] ?></span></a>
<a href="?tab=doc" class="tab <?= $tab === 'doc' ? 'active' : '' ?>">Docs<span class="count"><?= $stats['doc'] ?></span></a>
<a href="?tab=pending" class="tab <?= $tab === 'pending' ? 'active' : '' ?>">Attente<span class="count"><?= $stats['pending'] ?></span></a>
<a href="?tab=discussions" class="tab <?= $tab === 'discussions' ? 'active' : '' ?>">Discussions<span class="count"><?= $stats['discussions'] ?? 0 ?></span></a>
<a href="?tab=articles" class="tab <?= $tab === 'articles' ? 'active' : '' ?>">Articles<span class="count"><?= $stats['articles'] ?? 0 ?></span></a>
</div>
<?php if ($tab !== 'pending'): ?>
<form class="filters" method="GET">
<input type="hidden" name="tab" value="<?= htmlspecialchars($tab) ?>">
<div class="search-box">
<i class="fas fa-search"></i>
<input type="text" name="search" placeholder="Rechercher..." value="<?= htmlspecialchars($search) ?>">
</div>
<select name="category" class="filter-select" onchange="this.form.submit()">
<option value="">Toutes</option>
<?php foreach ($categories as $cat): ?>
<option value="<?= htmlspecialchars($cat) ?>" <?= $catFilter === $cat ? 'selected' : '' ?>><?= htmlspecialchars($cat) ?></option>
<?php endforeach; ?>
</select>
</form>
<div class="table-container">
<table>
<thead>
<tr><th>ID</th><th>Type</th><th>Cat.</th><th>Question/Titre</th><th>Réponse/Contenu</th><th>Prio</th><th>Date</th><th>Actions</th></tr>
</thead>
<tbody>
<?php if (empty($entries)): ?>
<tr><td colspan="7"><div class="empty-state"><i class="fas fa-inbox"></i> Aucune entrée</div></td></tr>
<?php else: ?>
<?php foreach ($entries as $e): ?>
<tr>
<td><?= $e['id'] ?></td>
<td><span class="badge badge-<?= $e['type'] ?>"><?= $e['type'] ?></span></td>
<td><span class="badge badge-cat"><?= htmlspecialchars($e['category'] ?? '-') ?></span></td>
<td><span class="text-truncate"><?= htmlspecialchars($e['type'] === 'doc' ? ($e['title'] ?: $e['question']) : $e['question']) ?></span></td>
<td><span class="text-truncate"><?= htmlspecialchars(mb_substr($e['type'] === 'doc' ? ($e['content'] ?: $e['answer']) : $e['answer'], 0, 50)) ?></span></td>
<td><span class="badge badge-prio"><?= $e['priority'] ?? 5 ?></span></td>
<td><span class="text-muted small"><?= date("d/m/Y", strtotime($e['created_at'])) ?></span></td>
<td>
<div class="actions-cell">
<button type="button" class="btn btn-info btn-sm" onclick="viewEntry(<?= $e['id'] ?>)"><i class="fas fa-eye"></i></button>
<button type="button" class="btn btn-warning btn-sm" onclick="editEntry(<?= $e['id'] ?>)"><i class="fas fa-edit"></i></button>
<form method="POST" style="display:inline" onsubmit="return confirm('Supprimer?')">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $e['id'] ?>">
<button type="submit" class="btn btn-danger btn-sm"><i class="fas fa-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="table-container">
<table>
<thead><tr><th>ID</th><th>Question</th><th>Réponse</th><th>Actions</th></tr></thead>
<tbody>
<?php if (empty($pending)): ?>
<tr><td colspan="4"><div class="empty-state">Aucune question en attente</div></td></tr>
<?php else: ?>
<?php foreach ($pending as $p): ?>
<tr>
<td><?= $p['id'] ?></td>
<td><?= htmlspecialchars($p['question']) ?></td>
<td><span class="text-truncate"><?= htmlspecialchars(mb_substr($p['suggested_answer'] ?? '', 0, 60)) ?></span></td>
<td>
<form method="POST" style="display:inline-flex;gap:0.25rem;">
<input type="hidden" name="action" value="approve">
<input type="hidden" name="pending_id" value="<?= $p['id'] ?>">
<select name="approve_category" style="padding:0.25rem;font-size:0.75rem;">
<option>Général</option><option>PowerMTA</option><option>Office365</option>
</select>
<button type="submit" class="btn btn-success btn-sm"><i class="fas fa-check"></i></button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<!-- Modal Ajouter -->
<div class="modal-overlay" id="addModal">
<div class="modal">
<form method="POST" id="addForm" action="ia-knowledge.php?tab=<?= htmlspecialchars($tab) ?>">
<input type="hidden" name="action" value="add">
<input type="hidden" name="type" id="addType" value="qa">
<div class="modal-header">
<h2><i class="fas fa-plus-circle" style="color:var(--primary)"></i> Ajouter</h2>
<button type="button" class="modal-close" onclick="closeModal('addModal')">&times;</button>
</div>
<div class="modal-body">
<div class="type-selector">
<div class="type-option active" onclick="selectAddType('qa', this)">
<i class="fas fa-question-circle"></i>
<strong>Q&A</strong><br><small>Pour l'IA</small>
</div>
<div class="type-option" onclick="selectAddType('doc', this)">
<i class="fas fa-file-alt"></i>
<strong>Doc</strong><br><small>Articles</small>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Catégorie</label>
<select name="category">
<option>Général</option><option>PowerMTA</option><option>Office365</option><option>Serveur</option><option>Email</option><option>DNS</option><option>Cloud</option><option>Infrastructure</option><option>Email Marketing</option><option>Technical</option><option>Deliverability</option>
</select>
</div>
<div class="form-group">
<label>Priorité</label>
<input type="number" name="priority" value="5" min="1" max="10">
</div>
</div>
<div id="addQaFields">
<div class="form-group">
<label>Question *</label>
<input type="text" name="question" placeholder="Comment faire...?" required>
</div>
<div class="form-group">
<label>Réponse *</label>
<textarea name="answer" class="large" placeholder="Entrez la réponse complète ici... (saisie illimitée)" required></textarea>
</div>
<div class="form-group">
<label>Mots-clés</label>
<input type="text" name="keywords" placeholder="mot1, mot2, mot3">
</div>
</div>
<div id="addDocFields" style="display:none;">
<div class="form-group">
<label>Titre *</label>
<input type="text" name="title" placeholder="Titre du document">
</div>
<div class="form-group">
<label>Contenu</label>
<textarea name="content" class="large" placeholder="Entrez le contenu complet ici... (saisie illimitée)" style="min-height: 300px;"></textarea>
</div>
<div class="form-group">
<label>Auteur</label>
<input type="text" name="author" value="Admin">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn" onclick="closeModal('addModal')">Annuler</button>
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Enregistrer</button>
</div>
</form>
</div>
</div>
<!-- Modal Voir -->
<div class="modal-overlay" id="viewModal">
<div class="modal">
<div class="modal-header">
<h2><i class="fas fa-eye" style="color:#3b82f6"></i> <span id="viewTitle">Détails</span></h2>
<button type="button" class="modal-close" onclick="closeModal('viewModal')">&times;</button>
</div>
<div class="modal-body">
<div class="view-meta" id="viewMeta"></div>
<div class="view-section">
<div class="view-label" id="viewQuestionLabel">Question</div>
<div class="view-content" id="viewQuestion"></div>
</div>
<div class="view-section">
<div class="view-label" id="viewAnswerLabel">Réponse</div>
<div class="view-content" id="viewAnswer" style="max-height:400px;"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn" onclick="closeModal('viewModal')">Fermer</button>
<button type="button" class="btn btn-warning" onclick="editFromView()"><i class="fas fa-edit"></i> Modifier</button>
</div>
</div>
</div>
<!-- Modal Modifier -->
<div class="modal-overlay" id="editModal">
<div class="modal">
<form method="POST" id="editForm" action="ia-knowledge.php?tab=<?= htmlspecialchars($tab) ?>">
<input type="hidden" name="action" value="update">
<input type="hidden" name="id" id="editId">
<input type="hidden" name="type" id="editType">
<div class="modal-header">
<h2><i class="fas fa-edit" style="color:#f59e0b"></i> Modifier</h2>
<button type="button" class="modal-close" onclick="closeModal('editModal')">&times;</button>
</div>
<div class="modal-body">
<div class="form-row">
<div class="form-group">
<label>Catégorie</label>
<select name="category" id="editCategory">
<option>Général</option><option>PowerMTA</option><option>Office365</option><option>Serveur</option><option>Email</option><option>DNS</option><option>Cloud</option><option>Infrastructure</option><option>Email Marketing</option><option>Technical</option><option>Deliverability</option>
</select>
</div>
<div class="form-group">
<label>Priorité</label>
<input type="number" name="priority" id="editPriority" min="1" max="10">
</div>
</div>
<div id="editQaFields">
<div class="form-group">
<label>Question</label>
<input type="text" name="question" id="editQuestion">
</div>
<div class="form-group">
<label>Réponse</label>
<textarea name="answer" id="editAnswer" class="large" style="min-height:250px;"></textarea>
</div>
<div class="form-group">
<label>Mots-clés</label>
<input type="text" name="keywords" id="editKeywords">
</div>
</div>
<div id="editDocFields" style="display:none;">
<div class="form-group">
<label>Titre</label>
<input type="text" name="title" id="editTitle">
</div>
<div class="form-group">
<label>Contenu</label>
<textarea name="content" id="editContent" class="large" style="min-height:350px;"></textarea>
</div>
<div class="form-group">
<label>Auteur</label>
<input type="text" name="author" id="editAuthor">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn" onclick="closeModal('editModal')">Annuler</button>
<button type="submit" class="btn btn-success"><i class="fas fa-save"></i> Sauvegarder</button>
</div>
</form>
</div>
</div>
<script>
let currentEntry = null;
function openModal(id) {
document.getElementById(id).classList.add('show');
document.body.style.overflow = 'hidden';
}
function closeModal(id) {
document.getElementById(id).classList.remove('show');
document.body.style.overflow = '';
}
function openAddModal() { openModal('addModal'); }
function selectAddType(type, el) {
document.getElementById('addType').value = type;
document.querySelectorAll('#addModal .type-option').forEach(o => o.classList.remove('active'));
el.classList.add('active');
document.getElementById('addQaFields').style.display = type === 'qa' ? 'block' : 'none';
document.getElementById('addDocFields').style.display = type === 'doc' ? 'block' : 'none';
}
async function viewEntry(id) {
try {
const res = await fetch('?api=get&id=' + id);
const data = await res.json();
currentEntry = data;
if (data.error) { alert('Non trouvé'); return; }
const isDoc = data.type === 'doc';
document.getElementById('viewTitle').textContent = isDoc ? (data.title || 'Doc') : 'Q&A #' + id;
document.getElementById('viewMeta').innerHTML = `
<div class="view-meta-item"><b>ID:</b> ${data.id}</div>
<div class="view-meta-item"><b>Type:</b> ${data.type}</div>
<div class="view-meta-item"><b>Cat:</b> ${data.category || '-'}</div>
<div class="view-meta-item"><b>Prio:</b> ${data.priority || 5}</div>
`;
document.getElementById('viewQuestionLabel').textContent = isDoc ? 'Titre' : 'Question';
document.getElementById('viewQuestion').textContent = isDoc ? (data.title || data.question) : data.question;
document.getElementById('viewAnswerLabel').textContent = isDoc ? 'Contenu' : 'Réponse';
document.getElementById('viewAnswer').textContent = isDoc ? (data.content || data.answer) : data.answer;
openModal('viewModal');
} catch (e) { alert('Erreur: ' + e.message); }
}
function editFromView() {
closeModal('viewModal');
if (currentEntry) { populateEdit(currentEntry); openModal('editModal'); }
}
async function editEntry(id) {
try {
const res = await fetch('?api=get&id=' + id);
const data = await res.json();
if (data.error) { alert('Non trouvé'); return; }
populateEdit(data);
openModal('editModal');
} catch (e) { alert('Erreur: ' + e.message); }
}
function populateEdit(data) {
document.getElementById('editId').value = data.id;
document.getElementById('editType').value = data.type;
document.getElementById('editCategory').value = data.category || 'Général';
document.getElementById('editPriority').value = data.priority || 5;
const isDoc = data.type === 'doc';
document.getElementById('editQaFields').style.display = isDoc ? 'none' : 'block';
document.getElementById('editDocFields').style.display = isDoc ? 'block' : 'none';
if (isDoc) {
document.getElementById('editTitle').value = data.title || data.question || '';
document.getElementById('editContent').value = data.content || data.answer || '';
document.getElementById('editAuthor').value = data.author || 'Admin';
} else {
document.getElementById('editQuestion').value = data.question || '';
document.getElementById('editAnswer').value = data.answer || '';
let kw = data.keywords || '';
if (typeof kw === 'string') kw = kw.replace(/[{}]/g, '');
document.getElementById('editKeywords').value = kw;
}
}
// Close on overlay/Escape
document.querySelectorAll('.modal-overlay').forEach(m => {
m.addEventListener('click', e => { if (e.target === m) closeModal(m.id); });
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') document.querySelectorAll('.modal-overlay.show').forEach(m => closeModal(m.id));
});
</script>
</body>
</html>