Aplicação Funcionando
This commit is contained in:
parent
99807d78f7
commit
5f7b4e19e8
|
|
@ -2,11 +2,11 @@ import { Component, EventEmitter, Output, Input } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cta-button',
|
selector: 'app-cta-button',
|
||||||
|
standalone: true,
|
||||||
templateUrl: './cta-button.html',
|
templateUrl: './cta-button.html',
|
||||||
styleUrls: ['./cta-button.scss']
|
styleUrls: ['./cta-button.scss']
|
||||||
})
|
})
|
||||||
export class CtaButtonComponent {
|
export class CtaButtonComponent {
|
||||||
|
|
||||||
@Input() label: string = 'COMEÇAR AGORA';
|
@Input() label: string = 'COMEÇAR AGORA';
|
||||||
|
|
||||||
@Input() width: string = '250px';
|
@Input() width: string = '250px';
|
||||||
|
|
|
||||||
|
|
@ -102,14 +102,14 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Pesquisar..."
|
placeholder="Pesquisar..."
|
||||||
[(ngModel)]="macrophonySearch"
|
[value]="macrophonySearch"
|
||||||
(ngModelChange)="onMacrophonySearch()" />
|
(input)="onMacrophonySearch($any($event.target).value)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tools-right">
|
<div class="tools-right">
|
||||||
<label class="select-label">
|
<label class="select-label">
|
||||||
Exibir
|
Exibir
|
||||||
<select [(ngModel)]="macrophonyPageSize" (ngModelChange)="onMacrophonyPageSizeChange()">
|
<select [value]="macrophonyPageSize" (change)="onMacrophonyPageSizeChange($any($event.target).value)">
|
||||||
<option *ngFor="let size of macrophonyPageOptions" [value]="size">{{ size }}</option>
|
<option *ngFor="let size of macrophonyPageOptions" [value]="size">{{ size }}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
|
@ -120,7 +120,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button class="btn-icon-text" type="button" (click)="exportMacrophonyCsv()">
|
<button class="btn-icon-text" type="button" (click)="exportMacrophonyCsv()">
|
||||||
<i class="bi bi-download"></i>
|
<i class="bi bi-download"></i>
|
||||||
<span class="hide-mobile">CSV</span>
|
<span class="hide-mobile">Exportar</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -428,8 +428,8 @@
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Pesquisar..."
|
placeholder="Pesquisar..."
|
||||||
[(ngModel)]="group.search"
|
[value]="group.search"
|
||||||
(ngModelChange)="onGroupedSearch(group)" />
|
(input)="onGroupedSearch(group, $any($event.target).value)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tools-right">
|
<div class="tools-right">
|
||||||
|
|
@ -439,7 +439,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button class="btn-icon-text" type="button" (click)="exportGroupedCsv(group, file)">
|
<button class="btn-icon-text" type="button" (click)="exportGroupedCsv(group, file)">
|
||||||
<i class="bi bi-download"></i>
|
<i class="bi bi-download"></i>
|
||||||
<span class="hide-mobile">CSV</span>
|
<span class="hide-mobile">Exportar</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import {
|
||||||
HostBinding
|
HostBinding
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
||||||
import { FormsModule } from '@angular/forms';
|
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import Chart from 'chart.js/auto';
|
import Chart from 'chart.js/auto';
|
||||||
import type { ChartConfiguration, ChartData, ScriptableContext, TooltipItem } from 'chart.js';
|
import type { ChartConfiguration, ChartData, ScriptableContext, TooltipItem } from 'chart.js';
|
||||||
|
|
@ -70,7 +69,7 @@ type GroupedTableState<T> = { key: string; label: string; table: TableState<T>;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, FormsModule],
|
imports: [CommonModule],
|
||||||
templateUrl: './resumo.html',
|
templateUrl: './resumo.html',
|
||||||
styleUrls: ['./resumo.scss']
|
styleUrls: ['./resumo.scss']
|
||||||
})
|
})
|
||||||
|
|
@ -500,15 +499,32 @@ export class Resumo implements OnInit, AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
// Métodos obrigatórios para o template funcionar
|
// Métodos obrigatórios para o template funcionar
|
||||||
toggleMacrophonyCompact() { this.macrophonyCompact = !this.macrophonyCompact; }
|
toggleMacrophonyCompact() { this.macrophonyCompact = !this.macrophonyCompact; }
|
||||||
onMacrophonySearch() { this.macrophonyPage = 1; this.updateMacrophonyView(); }
|
onMacrophonySearch(value?: string) {
|
||||||
onMacrophonyPageSizeChange() { this.macrophonyPage = 1; this.updateMacrophonyView(); }
|
if (typeof value === 'string') this.macrophonySearch = value;
|
||||||
|
this.macrophonyPage = 1;
|
||||||
|
this.updateMacrophonyView();
|
||||||
|
}
|
||||||
|
onMacrophonyPageSizeChange(value?: number | string) {
|
||||||
|
if (value !== undefined && value !== null) {
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (Number.isFinite(parsed) && parsed > 0) {
|
||||||
|
this.macrophonyPageSize = parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.macrophonyPage = 1;
|
||||||
|
this.updateMacrophonyView();
|
||||||
|
}
|
||||||
isMacrophonyOpen(key: string) { return this.macrophonyOpen.has(key); }
|
isMacrophonyOpen(key: string) { return this.macrophonyOpen.has(key); }
|
||||||
toggleMacrophonyGroup(key: string) { if (this.macrophonyOpen.has(key)) this.macrophonyOpen.delete(key); else this.macrophonyOpen.add(key); }
|
toggleMacrophonyGroup(key: string) { if (this.macrophonyOpen.has(key)) this.macrophonyOpen.delete(key); else this.macrophonyOpen.add(key); }
|
||||||
openMacrophonyDetail(g: MacrophonyGroup) { this.macrophonyDetailGroup = g; this.macrophonyDetailOpen = true; }
|
openMacrophonyDetail(g: MacrophonyGroup) { this.macrophonyDetailGroup = g; this.macrophonyDetailOpen = true; }
|
||||||
closeMacrophonyDetail() { this.macrophonyDetailOpen = false; this.macrophonyDetailGroup = null; }
|
closeMacrophonyDetail() { this.macrophonyDetailOpen = false; this.macrophonyDetailGroup = null; }
|
||||||
goToMacrophonyPage(p: number) { this.macrophonyPage = p; this.updateMacrophonyView(); }
|
goToMacrophonyPage(p: number) { this.macrophonyPage = p; this.updateMacrophonyView(); }
|
||||||
|
|
||||||
onGroupedSearch<T>(g: GroupedTableState<T>) { g.page = 1; this.updateGroupView(g); }
|
onGroupedSearch<T>(g: GroupedTableState<T>, value?: string) {
|
||||||
|
if (typeof value === 'string') g.search = value;
|
||||||
|
g.page = 1;
|
||||||
|
this.updateGroupView(g);
|
||||||
|
}
|
||||||
toggleGroupedCompact<T>(g: GroupedTableState<T>) { g.compact = !g.compact; }
|
toggleGroupedCompact<T>(g: GroupedTableState<T>) { g.compact = !g.compact; }
|
||||||
exportGroupedCsv<T>(g: GroupedTableState<T>, file: string) { this.exportCsv(g.table, file); }
|
exportGroupedCsv<T>(g: GroupedTableState<T>, file: string) { this.exportCsv(g.table, file); }
|
||||||
isGroupedOpen<T>(g: GroupedTableState<T>, key: string) { return g.open.has(key); }
|
isGroupedOpen<T>(g: GroupedTableState<T>, key: string) { return g.open.has(key); }
|
||||||
|
|
@ -1037,21 +1053,72 @@ export class Resumo implements OnInit, AfterViewInit, OnDestroy {
|
||||||
if (!isPlatformBrowser(this.platformId)) return;
|
if (!isPlatformBrowser(this.platformId)) return;
|
||||||
const rows = table.data ?? [];
|
const rows = table.data ?? [];
|
||||||
const columns = table.columns ?? [];
|
const columns = table.columns ?? [];
|
||||||
const header = columns.map((c) => c.label);
|
const generatedAt = new Date().toLocaleString('pt-BR');
|
||||||
const body = rows.map((row) =>
|
const escapeHtml = (value: string) =>
|
||||||
columns.map((column) => {
|
value
|
||||||
const value = this.formatCell(column, row);
|
.replace(/&/g, '&')
|
||||||
const escaped = String(value).replace(/"/g, '""');
|
.replace(/</g, '<')
|
||||||
return `"${escaped}"`;
|
.replace(/>/g, '>')
|
||||||
})
|
.replace(/"/g, '"')
|
||||||
);
|
.replace(/'/g, ''');
|
||||||
|
|
||||||
const csv = [header.join(';'), ...body.map((line) => line.join(';'))].join('\n');
|
const headerHtml = columns
|
||||||
const blob = new Blob([`\uFEFF${csv}`], { type: 'text/csv;charset=utf-8;' });
|
.map((column) => `<th class="${column.align === 'right' ? 'text-right' : column.align === 'center' ? 'text-center' : ''}">${escapeHtml(column.label)}</th>`)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
const bodyHtml = rows
|
||||||
|
.map((row, index) => {
|
||||||
|
const cells = columns
|
||||||
|
.map((column) => {
|
||||||
|
const value = this.formatCell(column, row);
|
||||||
|
const toneClass = column.tone ? this.getToneClass(column.value(row)) : '';
|
||||||
|
const alignClass = column.align === 'right' ? 'text-right' : column.align === 'center' ? 'text-center' : '';
|
||||||
|
const classes = [alignClass, toneClass].filter(Boolean).join(' ');
|
||||||
|
return `<td class="${classes}">${escapeHtml(String(value))}</td>`;
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
return `<tr class="${index % 2 === 0 ? 'even' : 'odd'}">${cells}</tr>`;
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
const html = `<!DOCTYPE html>
|
||||||
|
<html lang="pt-BR">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<style>
|
||||||
|
body { font-family: Segoe UI, Arial, sans-serif; margin: 20px; color: #0f172a; }
|
||||||
|
.sheet-title { font-size: 18px; font-weight: 700; margin-bottom: 4px; }
|
||||||
|
.sheet-subtitle { font-size: 12px; color: #64748b; margin-bottom: 14px; }
|
||||||
|
table { border-collapse: collapse; width: 100%; table-layout: auto; }
|
||||||
|
th, td { border: 1px solid #dbe2ef; padding: 8px 10px; font-size: 12px; }
|
||||||
|
th { background: #e8eefc; color: #1e3a8a; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px; }
|
||||||
|
tr.even td { background: #ffffff; }
|
||||||
|
tr.odd td { background: #f8fafc; }
|
||||||
|
.text-right { text-align: right; }
|
||||||
|
.text-center { text-align: center; }
|
||||||
|
.text-success { color: #047857; font-weight: 700; }
|
||||||
|
.text-danger { color: #b91c1c; font-weight: 700; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="sheet-title">${escapeHtml(table.label || 'Resumo')}</div>
|
||||||
|
<div class="sheet-subtitle">Exportado em ${escapeHtml(generatedAt)} | Total de linhas: ${rows.length}</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>${headerHtml}</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${bodyHtml}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
const blob = new Blob([`\uFEFF${html}`], { type: 'application/vnd.ms-excel;charset=utf-8;' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = `${filename}.csv`;
|
a.download = `${filename}.xls`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { join } from 'node:path';
|
||||||
import { Readable } from 'node:stream';
|
import { Readable } from 'node:stream';
|
||||||
|
|
||||||
const browserDistFolder = join(import.meta.dirname, '../browser');
|
const browserDistFolder = join(import.meta.dirname, '../browser');
|
||||||
const apiBaseUrl = (process.env['API_BASE_URL'] || 'http://backend:8080').replace(/\/+$/, '');
|
const apiBaseUrl = (process.env['API_BASE_URL'] || 'http://localhost:5298').replace(/\/+$/, '');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const angularApp = new AngularNodeAppEngine();
|
const angularApp = new AngularNodeAppEngine();
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: var(--bg-body);
|
min-height: 100vh;
|
||||||
|
background:
|
||||||
|
radial-gradient(900px 420px at 20% 10%, rgba(227, 61, 207, 0.1), transparent 60%),
|
||||||
|
radial-gradient(820px 380px at 80% 30%, rgba(227, 61, 207, 0.06), transparent 60%),
|
||||||
|
linear-gradient(180deg, #ffffff 0%, #f5f5f7 70%);
|
||||||
|
background-attachment: fixed;
|
||||||
|
background-repeat: no-repeat;
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
font-family: var(--font-sans);
|
font-family: var(--font-sans);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
|
@ -84,31 +90,20 @@ select.form-control-sm {
|
||||||
/* Empurra o conteúdo pra baixo do header fixo */
|
/* Empurra o conteúdo pra baixo do header fixo */
|
||||||
.app-main.has-header {
|
.app-main.has-header {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-top: 84px; /* altura segura p/ header (mobile/desktop) */
|
padding-top: 76px; /* evita vão visual entre o header fixo e o conteúdo */
|
||||||
background:
|
background: transparent;
|
||||||
radial-gradient(900px 420px at 20% 10%, rgba(227, 61, 207, 0.1), transparent 60%),
|
|
||||||
radial-gradient(820px 380px at 80% 30%, rgba(227, 61, 207, 0.06), transparent 60%),
|
|
||||||
linear-gradient(180deg, #ffffff 0%, #f5f5f7 70%);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
.app-main.has-header {
|
.app-main.has-header {
|
||||||
padding-top: 96px;
|
padding-top: 88px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ajuste para monitores grandes: elimina o "vão" visual entre header e corpo. */
|
/* Ajuste para monitores grandes: elimina o "vão" visual entre header e corpo. */
|
||||||
@media (min-width: 1400px) {
|
@media (min-width: 1400px) {
|
||||||
.app-main.has-header {
|
.app-main.has-header {
|
||||||
padding-top: 72px;
|
padding-top: 76px;
|
||||||
}
|
|
||||||
|
|
||||||
.container-geral,
|
|
||||||
.container-geral-responsive,
|
|
||||||
.container-fat,
|
|
||||||
.container-mureg,
|
|
||||||
.container-troca {
|
|
||||||
margin-top: 14px !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,4 +321,3 @@ app-header .modal-card .btn-secondary:hover {
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue