Skip to content

Commit 1cfd2d7

Browse files
feat: adicionar página de documentos com funcionalidades de upload e listagem
1 parent 8ca08e6 commit 1cfd2d7

7 files changed

Lines changed: 356 additions & 24 deletions

File tree

src/app/app.routes.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,30 @@ export const routes: Routes = [
55
{
66
path: '',
77
redirectTo: 'dashboard',
8-
pathMatch: 'full'
8+
pathMatch: 'full',
99
},
1010
{
1111
path: 'dashboard',
12-
loadComponent: () => import('./pages/dashboard').then(m => m.DashboardComponent)
12+
loadComponent: () => import('./pages/dashboard').then((m) => m.DashboardComponent),
1313
},
1414
{
1515
path: 'chat',
1616
canActivate: [authGuard],
17+
loadComponent: () => import('./pages/chat/chat').then((m) => m.ChatComponent),
18+
},
19+
{
20+
path: 'documents',
21+
canActivate: [authGuard],
1722
loadComponent: () =>
18-
import('./pages/chat/chat').then(m => m.ChatComponent)
23+
import('./pages/documents/documents').then((m) => m.DocumentsComponent),
1924
},
2025
{
2126
path: 'upload',
2227
canActivate: [authGuard],
23-
loadComponent: () =>
24-
import('./pages/upload/upload').then(m => m.UploadComponent)
28+
loadComponent: () => import('./pages/upload/upload').then((m) => m.UploadComponent),
2529
},
2630
{
2731
path: '**',
28-
redirectTo: 'chat'
29-
}
30-
];
32+
redirectTo: 'chat',
33+
},
34+
];

src/app/layout/header/header.html

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
1-
<nav class="navbar navbar-expand-lg navbar-dark bg-dark px-4" role="navigation" aria-label="Navegação principal">
1+
<nav
2+
class="navbar navbar-expand-lg navbar-dark bg-dark px-4"
3+
role="navigation"
4+
aria-label="Navegação principal"
5+
>
26
<a class="navbar-brand" routerLink="/chat" aria-label="Início - Assistente IA">
37
<i class="fas fa-robot me-2" aria-hidden="true"></i>
48
<span class="brand-text">Assistente IA</span>
59
</a>
610

7-
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
11+
<button
12+
class="navbar-toggler"
13+
type="button"
14+
data-bs-toggle="collapse"
15+
data-bs-target="#navbarNav"
16+
>
817
<span class="navbar-toggler-icon"></span>
918
</button>
1019

1120
<div class="collapse navbar-collapse" id="navbarNav">
1221
<ul class="navbar-nav ms-auto">
1322
<li class="nav-item">
14-
<a class="nav-link nav-btn nav-btn-primary" routerLink="/chat" routerLinkActive="active" aria-label="Abrir chat">
23+
<a class="nav-link" routerLink="/dashboard" routerLinkActive="active" aria-label="Ir para dashboard">
24+
<i class="fas fa-tachometer-alt me-1" aria-hidden="true"></i>Dashboard
25+
</a>
26+
</li>
27+
<li class="nav-item">
28+
<a class="nav-link" routerLink="/chat" routerLinkActive="active" aria-label="Abrir chat">
1529
<i class="fas fa-comments me-1" aria-hidden="true"></i>
1630
<span>Chat</span>
1731
</a>
1832
</li>
1933
<li class="nav-item">
20-
<a class="nav-link nav-btn nav-btn-secondary" routerLink="/upload" routerLinkActive="active" aria-label="Ver documentos">
34+
<a class="nav-link" routerLink="/documents" routerLinkActive="active">
35+
<i class="fas fa-database me-1"></i>Base de Conhecimento
36+
</a>
37+
</li>
38+
<li class="nav-item">
39+
<a
40+
class="nav-link nav-btn nav-btn-secondary"
41+
routerLink="/upload"
42+
routerLinkActive="active"
43+
aria-label="Ver documentos"
44+
>
2145
<i class="fas fa-upload me-1" aria-hidden="true"></i>
2246
<span>Documentos</span>
2347
</a>
2448
</li>
2549
</ul>
2650
</div>
27-
</nav>
51+
</nav>

src/app/pages/dashboard/dashboard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ export class DashboardComponent {
1414
features = [
1515
{ title: 'Chat assistido', desc: 'Converse com o assistente e receba respostas rápidas.', icon: 'comments', route: '/chat' },
1616
{ title: 'Upload de documentos', desc: 'Envie PDFs e outros arquivos para consulta e análise.', icon: 'file-upload', route: '/upload' },
17-
{ title: 'Relatórios simples', desc: 'Resumos e estatísticas básicas.', icon: 'chart-line', route: '' }
17+
{ title: 'Base de Conhecimento', desc: 'Busque e consulte documentos indexados.', icon: 'database', route: '/documents' }
1818
];
1919
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
.upload-wrapper { max-width: 920px; }
2+
3+
.upload-card { border-radius: 14px; overflow: hidden; display:flex; flex-direction:column }
4+
5+
.card-header {
6+
background: linear-gradient(180deg, rgba(13,27,45,0.98), rgba(2,6,23,0.98));
7+
color: #cbd5e1;
8+
border-bottom: 1px solid rgba(255,255,255,0.03);
9+
padding: 12px 16px;
10+
display:flex;
11+
justify-content:space-between;
12+
align-items:center;
13+
}
14+
15+
.header-left { display:flex; gap:12px; align-items:center }
16+
.avatar-icon { font-size:1.4rem; color:#7dd3fc; background: rgba(125,211,252,0.05); padding:8px; border-radius:8px }
17+
.upload-title { font-weight:700; color:#e6eef8 }
18+
.upload-sub { font-size:0.82rem; color:#9aa6b2 }
19+
20+
.card-body { padding:18px }
21+
22+
.drop-zone {
23+
border-radius: 12px;
24+
padding: 36px 24px;
25+
text-align: center;
26+
cursor: pointer;
27+
transition: background-color 0.15s, box-shadow 0.15s;
28+
background: linear-gradient(180deg,#f8fafc,#f6f8fb);
29+
border: 1px dashed rgba(2,6,23,0.06);
30+
}
31+
32+
.drop-zone.dragging { background: rgba(125,211,252,0.04); box-shadow: 0 8px 30px rgba(2,6,23,0.04) }
33+
.upload-icon { color: #38bdf8 }
34+
35+
.file-list { display:flex; flex-direction:column; gap:10px }
36+
37+
.file-item { display:flex; align-items:center; background:#fff; border-radius:10px; padding:10px 12px; box-shadow: 0 6px 18px rgba(2,6,23,0.04); }
38+
.file-left { width:44px; display:flex; align-items:center; justify-content:center; font-size:1.1rem }
39+
.file-info { display:flex; flex-direction:column; flex:1; min-width:0 }
40+
.file-name { font-size:0.95rem; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
41+
42+
.file-actions { display:flex; align-items:center; gap:12px }
43+
.status-message { font-size:0.82rem; color:#64748b }
44+
45+
.card-footer { background:#fff; border-top:1px solid rgba(2,6,23,0.04); padding:12px 16px }
46+
47+
.btn-send { background: linear-gradient(90deg,#7dd3fc,#38bdf8); border:none; color:#04263b }
48+
49+
@media (max-width:575px) {
50+
.upload-wrapper { padding-left:8px; padding-right:8px }
51+
}
52+
53+
/* Header action button (matches provided design) */
54+
.card-header .header-actions .header-btn {
55+
display: inline-flex;
56+
align-items: center;
57+
gap: 8px;
58+
padding: 8px 14px;
59+
border-radius: 10px;
60+
color: #e6eef8;
61+
background: transparent;
62+
border: 1px solid rgba(255,255,255,0.08);
63+
font-weight: 600;
64+
transition: background .12s ease, transform .08s ease;
65+
}
66+
67+
.card-header .header-actions .header-btn i { font-size: 16px }
68+
69+
.card-header .header-actions .header-btn:hover,
70+
.card-header .header-actions .header-btn:focus {
71+
background: rgba(255,255,255,0.03);
72+
transform: translateY(-1px);
73+
text-decoration: none;
74+
}
75+
76+
.card-header .header-actions .header-btn[disabled] {
77+
opacity: 0.6;
78+
cursor: not-allowed;
79+
transform: none;
80+
}
Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,103 @@
1-
<p>documents works!</p>
1+
<div class="upload-wrapper container py-4">
2+
<div class="upload-card card shadow-sm">
3+
4+
<!-- Cabeçalho (igual ao Upload) -->
5+
<div class="card-header d-flex justify-content-between align-items-center">
6+
<div class="header-left">
7+
<i class="fas fa-database avatar-icon" aria-hidden="true"></i>
8+
<div>
9+
<div class="upload-title">Base de Conhecimento</div>
10+
<div class="upload-sub">Documentos indexados para busca e consulta</div>
11+
</div>
12+
</div>
13+
<div class="header-actions">
14+
<button class="btn btn-sm btn-outline-secondary" (click)="loadDocuments()" [disabled]="isLoading">
15+
<i class="fas fa-rotate-right me-1" [class.fa-spin]="isLoading"></i>Atualizar
16+
</button>
17+
</div>
18+
</div>
19+
20+
<div class="card-body">
21+
22+
<!-- Mensagem de sucesso -->
23+
<div class="alert alert-success py-2" *ngIf="successMessage">
24+
<i class="fas fa-circle-check me-2"></i>{{ successMessage }}
25+
</div>
26+
27+
<!-- Mensagem de erro -->
28+
<div class="alert alert-danger py-2" *ngIf="errorMessage">
29+
<i class="fas fa-circle-exclamation me-2"></i>{{ errorMessage }}
30+
</div>
31+
32+
<!-- Loading -->
33+
<div class="text-center py-5" *ngIf="isLoading">
34+
<i class="fas fa-spinner fa-spin fa-2x text-primary"></i>
35+
<p class="mt-2 text-muted">Carregando documentos...</p>
36+
</div>
37+
38+
<!-- Sem documentos -->
39+
<div class="text-center text-muted py-5" *ngIf="!isLoading && documents.length === 0">
40+
<i class="fas fa-folder-open fa-2x mb-2"></i>
41+
<p class="mb-0">Nenhum documento na base de conhecimento.</p>
42+
<small>Faça upload de documentos na página <strong>Documentos</strong>.</small>
43+
</div>
44+
45+
<!-- Tabela de documentos (mantida) -->
46+
<div class="table-responsive" *ngIf="!isLoading && documents.length > 0">
47+
<table class="table table-hover align-middle mb-0">
48+
<thead class="table-light">
49+
<tr>
50+
<th style="width: 40px"></th>
51+
<th>Arquivo</th>
52+
<th>Importado em</th>
53+
<th style="width: 80px"></th>
54+
</tr>
55+
</thead>
56+
<tbody>
57+
<tr *ngFor="let doc of documents">
58+
59+
<!-- Ícone do tipo de arquivo -->
60+
<td>
61+
<i class="fas fa-lg" [class]="getFileIcon(doc.filename)"></i>
62+
</td>
63+
64+
<!-- Nome do arquivo -->
65+
<td>
66+
<span class="filename">{{ doc.filename }}</span>
67+
</td>
68+
69+
<!-- Data de importação -->
70+
<td>
71+
<small class="text-muted">{{ formatDate(doc.ingestedAt) }}</small>
72+
</td>
73+
74+
<!-- Botão excluir -->
75+
<td>
76+
<button
77+
class="btn btn-sm btn-outline-danger"
78+
(click)="delete(doc)"
79+
[disabled]="deletingId === doc.id"
80+
title="Excluir documento">
81+
<i class="fas"
82+
[class.fa-trash]="deletingId !== doc.id"
83+
[class.fa-spinner]="deletingId === doc.id"
84+
[class.fa-spin]="deletingId === doc.id">
85+
</i>
86+
</button>
87+
</td>
88+
89+
</tr>
90+
</tbody>
91+
</table>
92+
</div>
93+
94+
</div>
95+
96+
<!-- Rodapé com total -->
97+
<div class="card-footer d-flex justify-content-between align-items-center" *ngIf="documents.length > 0">
98+
<small class="text-muted">{{ documents.length }} documento(s) na base de conhecimento</small>
99+
<div></div>
100+
</div>
101+
102+
</div>
103+
</div>

0 commit comments

Comments
 (0)