refactor(ui): passe les pages en pleine largeur
Chaque page plafonnait sa largeur differemment (max-w-4xl pour Config, 5xl pour IA, 6xl pour l'accueil et les documents, 7xl pour les revenus et les depenses) : sur un ecran large, les donnees se tassaient au centre. Les pages n'ont plus de plafond, le contenu occupe l'ecran avec une marge laterale fixe. Pour tirer parti de la place gagnee : Config affiche ses deux sections cote a cote, et le split apercu PDF / donnees passe de 50-50 a 40-60 en faveur des donnees. Pendant le tagging, le bouton « Annuler » de l'en-tete d'edition est masque : il faisait doublon avec celui du bandeau de tagging, qui a un sens different (retour a l'edition, et non abandon). La sortie vers la liste reste le fil d'Ariane. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
<div class="max-w-5xl mx-auto space-y-6">
|
||||
<div class="page">
|
||||
<div class="page-content">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold text-white">Assistant IA</h1>
|
||||
<p class="text-gray-400 text-sm mt-1">Posez des questions sur vos données en langage naturel</p>
|
||||
<h1 class="page-title">Assistant IA</h1>
|
||||
<p class="page-subtitle">Posez des questions sur vos données en langage naturel</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span
|
||||
@@ -19,19 +19,19 @@
|
||||
</div>
|
||||
|
||||
<!-- Formulaire -->
|
||||
<div class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<div class="card card-body">
|
||||
<div class="flex gap-3">
|
||||
<input
|
||||
v-model="question"
|
||||
type="text"
|
||||
placeholder="Posez votre question..."
|
||||
class="flex-1 bg-gray-900 border border-gray-700 rounded-lg px-4 py-2.5 text-white placeholder-gray-500 focus:outline-none focus:border-blue-500 transition-colors"
|
||||
class="input"
|
||||
@keydown.enter="askQuestion"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<select
|
||||
v-model="chartType"
|
||||
class="bg-gray-900 border border-gray-700 rounded-lg px-3 py-2.5 text-white focus:outline-none focus:border-blue-500 transition-colors"
|
||||
class="input w-auto"
|
||||
:disabled="loading"
|
||||
>
|
||||
<option value="auto">Auto</option>
|
||||
@@ -43,7 +43,7 @@
|
||||
<button
|
||||
@click="askQuestion"
|
||||
:disabled="!question.trim() || loading"
|
||||
class="px-5 py-2.5 bg-blue-600 text-white rounded-lg font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed hover:bg-blue-700"
|
||||
class="btn btn-primary whitespace-nowrap"
|
||||
>
|
||||
{{ loading ? 'Analyse...' : 'Demander' }}
|
||||
</button>
|
||||
@@ -51,14 +51,14 @@
|
||||
</div>
|
||||
|
||||
<!-- Exemples de questions -->
|
||||
<div v-if="!result && !loading && !error" class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<div v-if="!result && !loading && !error" class="card card-body">
|
||||
<p class="text-gray-400 text-sm mb-3">Exemples de questions :</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<button
|
||||
v-for="example in examples"
|
||||
:key="example"
|
||||
@click="question = example; askQuestion()"
|
||||
class="px-3 py-1.5 text-sm bg-gray-900 border border-gray-700 rounded-lg text-gray-300 hover:border-blue-500 hover:text-white transition-colors"
|
||||
class="btn btn-secondary"
|
||||
>
|
||||
{{ example }}
|
||||
</button>
|
||||
@@ -66,8 +66,8 @@
|
||||
</div>
|
||||
|
||||
<!-- Spinner -->
|
||||
<div v-if="loading" class="bg-gray-800 rounded-lg border border-gray-700 p-8 text-center">
|
||||
<div class="inline-block w-8 h-8 border-2 border-gray-600 border-t-blue-500 rounded-full animate-spin mb-3"></div>
|
||||
<div v-if="loading" class="card empty-state">
|
||||
<div class="spinner w-8 h-8 mb-3"></div>
|
||||
<p class="text-gray-400">{{ loadingMessage }}</p>
|
||||
</div>
|
||||
|
||||
@@ -77,23 +77,33 @@
|
||||
</div>
|
||||
|
||||
<!-- Résultat -->
|
||||
<div v-if="result" class="space-y-4">
|
||||
<div v-if="result" class="space-y-6">
|
||||
<!-- Réponse texte -->
|
||||
<div class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<h2 class="text-sm font-medium text-gray-400 mb-2">Réponse</h2>
|
||||
<p class="text-white whitespace-pre-wrap">{{ result.answer }}</p>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Réponse</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-white whitespace-pre-wrap">{{ result.answer }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Requête SQL -->
|
||||
<div v-if="result.sql_query" class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<h2 class="text-sm font-medium text-gray-400 mb-2">Requête SQL exécutée</h2>
|
||||
<pre class="text-xs text-gray-300 font-mono bg-gray-900 rounded p-3 overflow-x-auto">{{ result.sql_query }}</pre>
|
||||
<div v-if="result.sql_query" class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Requête SQL exécutée</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="text-xs text-gray-300 font-mono bg-gray-950 border border-gray-700 rounded p-3 overflow-x-auto">{{ result.sql_query }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Graphique -->
|
||||
<div v-if="result.chart_config && chartComponent" class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<h2 class="text-sm font-medium text-gray-400 mb-3">Graphique</h2>
|
||||
<div class="bg-gray-900 rounded-lg p-4">
|
||||
<div v-if="result.chart_config && chartComponent" class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">Graphique</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<component
|
||||
:is="chartComponent"
|
||||
:data="result.chart_config.data"
|
||||
@@ -103,34 +113,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Tableau de données -->
|
||||
<div v-if="result.data && result.data.columns && result.data.rows && result.data.rows.length > 0" class="bg-gray-800 rounded-lg border border-gray-700 p-4">
|
||||
<h2 class="text-sm font-medium text-gray-400 mb-3">
|
||||
Données ({{ result.data.row_count }} ligne{{ result.data.row_count > 1 ? 's' : '' }})
|
||||
</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<div v-if="result.data && result.data.columns && result.data.rows && result.data.rows.length > 0" class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="card-title">
|
||||
Données ({{ result.data.row_count }} ligne{{ result.data.row_count > 1 ? 's' : '' }})
|
||||
</h2>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-700">
|
||||
<th
|
||||
v-for="col in result.data.columns"
|
||||
:key="col"
|
||||
class="text-left px-3 py-2 text-gray-400 font-medium"
|
||||
>
|
||||
{{ col }}
|
||||
</th>
|
||||
<tr>
|
||||
<th v-for="col in result.data.columns" :key="col">{{ col }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(row, idx) in result.data.rows"
|
||||
:key="idx"
|
||||
class="border-b border-gray-700/50 hover:bg-gray-700/30"
|
||||
>
|
||||
<td
|
||||
v-for="(cell, cidx) in row"
|
||||
:key="cidx"
|
||||
class="px-3 py-2 text-gray-300"
|
||||
>
|
||||
<tr v-for="(row, idx) in result.data.rows" :key="idx">
|
||||
<td v-for="(cell, cidx) in row" :key="cidx">
|
||||
{{ formatCell(cell) }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user