@ddiazr/generic-table-drag-and-drop 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Generic Table Drag and Drop
|
|
2
|
+
|
|
3
|
+
Tabla Dinamica con Drag and Drop Angular 21+
|
|
4
|
+
|
|
5
|
+
## Instalación
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ddiazr/generic-table-drag-and-drop
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Peer Dependencies
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ng add @angular/cdk
|
|
15
|
+
npm i bootstrap @fortawesome/fontawesome-free
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## ColumnConfig && TableAction
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
interface TableAction<T> {
|
|
22
|
+
label: string;
|
|
23
|
+
icon: string;
|
|
24
|
+
class: string;
|
|
25
|
+
callback: (row: T) => void;
|
|
26
|
+
showIf?: (row: T) => boolean; // Tu validación dinámica
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface ColumnConfig {
|
|
30
|
+
key: string;
|
|
31
|
+
label: string;
|
|
32
|
+
type?: 'text' | 'number' | 'currency' | 'date';
|
|
33
|
+
bold?: boolean;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Campos
|
|
38
|
+
|
|
39
|
+
| Propiedad | Tipo | Obligatorio | Descripción |
|
|
40
|
+
| --------------- | ---------------- | ----------- | ----------------------------------------------------- |
|
|
41
|
+
| `data` | `any[]` | ✅ Sí | Datos de entrada segun el jsonen la tabla |
|
|
42
|
+
| `columnsConfig` | `ColumnConfig[]` | ✅ Sí | Datos de las columnas que quieras que tenga la tabla |
|
|
43
|
+
| `pageSize` | `number` | ❌ No | Valor por defecto tiene 25 para la paginación |
|
|
44
|
+
| `exportExcel` | `boolean` | ❌ No | Valor por defecto false, exportacion a excel |
|
|
45
|
+
| `exportPdf` | `boolean` | ❌ No | Valor por defecto false, exportacion a pdf |
|
|
46
|
+
| `nameExport` | `string` | ❌ No | Nombre que se le dara a las exportaciones |
|
|
47
|
+
| `actions` | `TableAction<T>[]` | ❌ No | Funcion que devuelve la accion segun el columnsConfig |
|
|
48
|
+
|
|
49
|
+
## Uso básico
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { GenericTableDragAndDrop } from '@ddiazr/generic-table-drag-and-drop';
|
|
53
|
+
|
|
54
|
+
interface ColumnConfig {
|
|
55
|
+
key: string;
|
|
56
|
+
label: string;
|
|
57
|
+
type?: 'text' | 'number' | 'currency' | 'date';
|
|
58
|
+
bold?: boolean;
|
|
59
|
+
}
|
|
60
|
+
interface TableAction<T> {
|
|
61
|
+
label: string;
|
|
62
|
+
icon: string;
|
|
63
|
+
class: string;
|
|
64
|
+
callback: (row: T) => void;
|
|
65
|
+
showIf?: (row: T) => boolean; // Tu validación dinámica
|
|
66
|
+
}
|
|
67
|
+
@Component({
|
|
68
|
+
imports: [GenericTableDragAndDrop],
|
|
69
|
+
template: `
|
|
70
|
+
<tbl-generic-drag-and-drop
|
|
71
|
+
[data]="data()"
|
|
72
|
+
[columnsConfig]="columns()"
|
|
73
|
+
[pageSize]="pageSize()"
|
|
74
|
+
[exportExcel]="exportExcel"
|
|
75
|
+
[exportPdf]="exportPdf"
|
|
76
|
+
nameExport="Reporte pruebas"
|
|
77
|
+
[actions]="actions()"
|
|
78
|
+
/>
|
|
79
|
+
`,
|
|
80
|
+
})
|
|
81
|
+
export class AppComponent {
|
|
82
|
+
// SI NO QUEREMOS EL DEFECTO SE LO PODEMOS MANDAR INDICANDO EL VALOR
|
|
83
|
+
pageSize = signal<number>(10);
|
|
84
|
+
// SI NECESITAMOS EXPORTAR LO QUE LA TABLA PRESENTA EN EXCEL
|
|
85
|
+
exportExcel = signal<boolean>(true);
|
|
86
|
+
// SI NECESITAMOS EXPORTAR LO QUE LA TABLA PRESENTA EN PDF
|
|
87
|
+
exportPdf = signal<boolean>(true);
|
|
88
|
+
// AQUI SE LE ASIGNA LOS VALORES QUE SE MOSTRARAN EN LA TABLA
|
|
89
|
+
data = signal<any[]>([
|
|
90
|
+
{
|
|
91
|
+
id: 1,
|
|
92
|
+
nombre: 'Juan Perez',
|
|
93
|
+
edad: 36,
|
|
94
|
+
salario: 1000,
|
|
95
|
+
fechanac: '21/07/1700',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 2,
|
|
99
|
+
nombre: 'Juana Perez',
|
|
100
|
+
edad: 14,
|
|
101
|
+
salario: 2000,
|
|
102
|
+
fechanac: '21/07/1700',
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
//DECALRAMOS LAS COLUMNAS QUE VA A CONTENER LA TABLA
|
|
106
|
+
columns = signal<ColumnConfig[]>([
|
|
107
|
+
{
|
|
108
|
+
key: 'id',
|
|
109
|
+
label: 'ID',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
key: 'nombre',
|
|
113
|
+
label: 'NOMBRE',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
key: 'edad',
|
|
117
|
+
label: 'EDAD',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
key: 'salario',
|
|
121
|
+
label: 'SALARIO',
|
|
122
|
+
type: 'currency',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
key: 'fechanac',
|
|
126
|
+
label: 'FECHA NACIMIENTO',
|
|
127
|
+
type: 'date',
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
// SI SE NECESITA QUE LA TABLA TENGA BOTONES PARA N ACCIONES
|
|
132
|
+
// SE MUESTRA ESTE EJEMPLO QUE TIENE DOS ACCIONES
|
|
133
|
+
// 1. MUESTRA EL BOTON EDIT SI LA EDAD ES > 18
|
|
134
|
+
// 2. MUESTRA EL BOTON SIN RESTRICCION
|
|
135
|
+
actions = signal<TableAction<any>[]>([
|
|
136
|
+
{
|
|
137
|
+
label: 'Edit',
|
|
138
|
+
icon: 'fa fa-edit',
|
|
139
|
+
class: 'btn btn-warning',
|
|
140
|
+
showIf: (row) => row.edad > 18,
|
|
141
|
+
callback: (row) => this.edit(row),
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
label: 'VER',
|
|
145
|
+
icon: 'fa fa-edit',
|
|
146
|
+
class: 'btn btn-warning',
|
|
147
|
+
callback: (row) => this.ver(row.id),
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Configuración de estilos
|
|
154
|
+
|
|
155
|
+
En tu `angular.json`:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
"styles": [
|
|
159
|
+
"node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
160
|
+
"node_modules/@fortawesome/fontawesome-free/css/all.min.css"
|
|
161
|
+
]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Licencia
|
|
165
|
+
|
|
166
|
+
MIT
|
|
167
|
+
|
|
168
|
+
# Source files
|
|
169
|
+
|
|
170
|
+
src/
|
|
171
|
+
_.ts
|
|
172
|
+
!_.d.ts
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common';
|
|
2
|
+
import * as i1 from '@angular/cdk/drag-drop';
|
|
3
|
+
import { moveItemInArray, transferArrayItem, DragDropModule, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { Pipe, input, signal, effect, computed, Component } from '@angular/core';
|
|
6
|
+
import * as XLSX from 'xlsx';
|
|
7
|
+
import jsPDF from 'jspdf';
|
|
8
|
+
import autoTable from 'jspdf-autotable';
|
|
9
|
+
import { ModalGeneric } from 'modal-generic';
|
|
10
|
+
|
|
11
|
+
class SafeDatePipe {
|
|
12
|
+
transform(value) {
|
|
13
|
+
if (!value)
|
|
14
|
+
return "";
|
|
15
|
+
const date = new Date(value);
|
|
16
|
+
if (isNaN(date.getTime()))
|
|
17
|
+
return value;
|
|
18
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
19
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
20
|
+
const year = date.getFullYear();
|
|
21
|
+
return `${day}/${month}/${year}`;
|
|
22
|
+
}
|
|
23
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeDatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
24
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: SafeDatePipe, isStandalone: true, name: "safeDate" });
|
|
25
|
+
}
|
|
26
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeDatePipe, decorators: [{
|
|
27
|
+
type: Pipe,
|
|
28
|
+
args: [{
|
|
29
|
+
name: "safeDate",
|
|
30
|
+
standalone: true,
|
|
31
|
+
pure: true, // ✅ Muy importante para performance
|
|
32
|
+
}]
|
|
33
|
+
}] });
|
|
34
|
+
|
|
35
|
+
class SafeCurrencyPipe {
|
|
36
|
+
transform(value) {
|
|
37
|
+
if (value == null || value === '')
|
|
38
|
+
return '';
|
|
39
|
+
const num = Number(value);
|
|
40
|
+
if (isNaN(num))
|
|
41
|
+
return value;
|
|
42
|
+
return 'Q' + num.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
43
|
+
}
|
|
44
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeCurrencyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
45
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: SafeCurrencyPipe, isStandalone: true, name: "safeCurrency" });
|
|
46
|
+
}
|
|
47
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeCurrencyPipe, decorators: [{
|
|
48
|
+
type: Pipe,
|
|
49
|
+
args: [{
|
|
50
|
+
name: 'safeCurrency',
|
|
51
|
+
standalone: true,
|
|
52
|
+
pure: true
|
|
53
|
+
}]
|
|
54
|
+
}] });
|
|
55
|
+
|
|
56
|
+
class SafeNumberPipe {
|
|
57
|
+
transform(value) {
|
|
58
|
+
if (value == null || value === "")
|
|
59
|
+
return "";
|
|
60
|
+
const num = Number(value);
|
|
61
|
+
if (isNaN(num))
|
|
62
|
+
return value;
|
|
63
|
+
return num.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
64
|
+
}
|
|
65
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeNumberPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
66
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: SafeNumberPipe, isStandalone: true, name: "safeNumber" });
|
|
67
|
+
}
|
|
68
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SafeNumberPipe, decorators: [{
|
|
69
|
+
type: Pipe,
|
|
70
|
+
args: [{
|
|
71
|
+
name: "safeNumber",
|
|
72
|
+
standalone: true,
|
|
73
|
+
pure: true,
|
|
74
|
+
}]
|
|
75
|
+
}] });
|
|
76
|
+
|
|
77
|
+
class GenericTableDragAndDrop {
|
|
78
|
+
// Inputs
|
|
79
|
+
data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
80
|
+
columnsConfig = input([], ...(ngDevMode ? [{ debugName: "columnsConfig" }] : []));
|
|
81
|
+
footData = input({}, ...(ngDevMode ? [{ debugName: "footData" }] : []));
|
|
82
|
+
actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : []));
|
|
83
|
+
exportExcel = input(false, ...(ngDevMode ? [{ debugName: "exportExcel" }] : []));
|
|
84
|
+
exportPdf = input(false, ...(ngDevMode ? [{ debugName: "exportPdf" }] : []));
|
|
85
|
+
nameExport = input('reporte', ...(ngDevMode ? [{ debugName: "nameExport" }] : []));
|
|
86
|
+
pageSize = input(25, ...(ngDevMode ? [{ debugName: "pageSize" }] : []));
|
|
87
|
+
// Estado
|
|
88
|
+
displayedColumns = signal([], ...(ngDevMode ? [{ debugName: "displayedColumns" }] : []));
|
|
89
|
+
availableColumns = signal([], ...(ngDevMode ? [{ debugName: "availableColumns" }] : []));
|
|
90
|
+
globalFilter = signal('', ...(ngDevMode ? [{ debugName: "globalFilter" }] : []));
|
|
91
|
+
filters = signal({}, ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
92
|
+
sortConfig = signal({
|
|
93
|
+
column: '',
|
|
94
|
+
direction: null,
|
|
95
|
+
}, ...(ngDevMode ? [{ debugName: "sortConfig" }] : []));
|
|
96
|
+
activeFilterColumn = signal('', ...(ngDevMode ? [{ debugName: "activeFilterColumn" }] : []));
|
|
97
|
+
showModal = signal(false, ...(ngDevMode ? [{ debugName: "showModal" }] : []));
|
|
98
|
+
currentPage = signal(1, ...(ngDevMode ? [{ debugName: "currentPage" }] : []));
|
|
99
|
+
constructor() {
|
|
100
|
+
effect(() => {
|
|
101
|
+
const d = this.data();
|
|
102
|
+
if (d?.length) {
|
|
103
|
+
this.currentPage.set(1);
|
|
104
|
+
}
|
|
105
|
+
}, { allowSignalWrites: true });
|
|
106
|
+
// Inicialización de columnas
|
|
107
|
+
effect(() => {
|
|
108
|
+
const config = this.columnsConfig();
|
|
109
|
+
if (config.length > 0 && this.displayedColumns().length === 0) {
|
|
110
|
+
this.displayedColumns.set(config.map((c) => c.key));
|
|
111
|
+
}
|
|
112
|
+
}, { allowSignalWrites: true });
|
|
113
|
+
// RESET de página al filtrar: Muy importante
|
|
114
|
+
effect(() => {
|
|
115
|
+
this.globalFilter();
|
|
116
|
+
this.filters();
|
|
117
|
+
this.currentPage.set(1);
|
|
118
|
+
}, { allowSignalWrites: true });
|
|
119
|
+
}
|
|
120
|
+
// Lógica de filtrado
|
|
121
|
+
filteredData = computed(() => {
|
|
122
|
+
let result = [...this.data()];
|
|
123
|
+
const search = this.globalFilter().toLowerCase();
|
|
124
|
+
const activeFilters = this.filters();
|
|
125
|
+
const sort = this.sortConfig();
|
|
126
|
+
if (search) {
|
|
127
|
+
result = result.filter((row) => Object.values(row).some((val) => String(val).toLowerCase().includes(search)));
|
|
128
|
+
}
|
|
129
|
+
Object.keys(activeFilters).forEach((col) => {
|
|
130
|
+
const values = activeFilters[col];
|
|
131
|
+
if (values?.length > 0) {
|
|
132
|
+
result = result.filter((row) => values.includes(String(row[col])));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
if (sort.column && sort.direction) {
|
|
136
|
+
result.sort((a, b) => {
|
|
137
|
+
const valA = String(a[sort.column]).toLowerCase();
|
|
138
|
+
const valB = String(b[sort.column]).toLowerCase();
|
|
139
|
+
const res = valA.localeCompare(valB, undefined, { numeric: true });
|
|
140
|
+
return sort.direction === 'asc' ? res : -res;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}, ...(ngDevMode ? [{ debugName: "filteredData" }] : []));
|
|
145
|
+
uniqueValuesMap = computed(() => {
|
|
146
|
+
const baseData = this.data();
|
|
147
|
+
const activeFilters = this.filters();
|
|
148
|
+
const allCols = [...this.availableColumns(), ...this.displayedColumns()];
|
|
149
|
+
const map = {};
|
|
150
|
+
allCols.forEach((col) => {
|
|
151
|
+
// FILTRADO DINÁMICO:
|
|
152
|
+
// Para la lista de la columna "X", filtramos la data base
|
|
153
|
+
// usando los criterios de TODAS las columnas MENOS la columna "X".
|
|
154
|
+
const dataFilteredByOthers = baseData.filter((row) => {
|
|
155
|
+
return Object.keys(activeFilters).every((filterCol) => {
|
|
156
|
+
// Si es la misma columna que estamos calculando, ignoramos su filtro
|
|
157
|
+
if (filterCol === col)
|
|
158
|
+
return true;
|
|
159
|
+
const values = activeFilters[filterCol];
|
|
160
|
+
if (!values || values.length === 0)
|
|
161
|
+
return true;
|
|
162
|
+
return values.includes(String(row[filterCol]));
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
// Extraemos los valores únicos de esa data filtrada por los demás
|
|
166
|
+
map[col] = [
|
|
167
|
+
...new Set(dataFilteredByOthers.map((item) => String(item[col]))),
|
|
168
|
+
].sort();
|
|
169
|
+
});
|
|
170
|
+
return map;
|
|
171
|
+
}, ...(ngDevMode ? [{ debugName: "uniqueValuesMap" }] : []));
|
|
172
|
+
// Data que realmente se renderiza (muy ligera)
|
|
173
|
+
pagedData = computed(() => {
|
|
174
|
+
const start = (this.currentPage() - 1) * this.pageSize();
|
|
175
|
+
return this.filteredData().slice(start, start + this.pageSize());
|
|
176
|
+
}, ...(ngDevMode ? [{ debugName: "pagedData" }] : []));
|
|
177
|
+
totalPages = computed(() => Math.ceil(this.filteredData().length / this.pageSize()) || 1, ...(ngDevMode ? [{ debugName: "totalPages" }] : []));
|
|
178
|
+
// Genera el array de números para los botones (ej: [1, 2, 3...])
|
|
179
|
+
pagesArray = computed(() => {
|
|
180
|
+
const current = this.currentPage();
|
|
181
|
+
const total = this.totalPages();
|
|
182
|
+
const pages = []; // Especificamos el tipo aquí
|
|
183
|
+
for (let i = 1; i <= total; i++) {
|
|
184
|
+
// Lógica para mostrar: primera, última, y 2 alrededor de la actual
|
|
185
|
+
if (i === 1 || i === total || (i >= current - 2 && i <= current + 2)) {
|
|
186
|
+
pages.push(i);
|
|
187
|
+
}
|
|
188
|
+
else if (pages[pages.length - 1] !== '...') {
|
|
189
|
+
pages.push('...');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return pages;
|
|
193
|
+
}, ...(ngDevMode ? [{ debugName: "pagesArray" }] : []));
|
|
194
|
+
//SI TRAE FOOT
|
|
195
|
+
hasFootData = computed(() => Object.keys(this.footData()).length > 0, ...(ngDevMode ? [{ debugName: "hasFootData" }] : []));
|
|
196
|
+
getConfig(key) {
|
|
197
|
+
return this.columnsConfig().find((c) => c.key === key);
|
|
198
|
+
}
|
|
199
|
+
// Métodos de UI (Drop, Sort, Filter) simplificados
|
|
200
|
+
drop(event) {
|
|
201
|
+
console.log('Envent:::', event);
|
|
202
|
+
const prev = event.previousContainer.data;
|
|
203
|
+
const curr = event.container.data;
|
|
204
|
+
if (event.previousContainer === event.container) {
|
|
205
|
+
moveItemInArray(curr, event.previousIndex, event.currentIndex);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
transferArrayItem(prev, curr, event.previousIndex, event.currentIndex);
|
|
209
|
+
}
|
|
210
|
+
// Sincronizar con los modelos
|
|
211
|
+
if (event.container.id === 'active-list')
|
|
212
|
+
this.displayedColumns.set([...curr]);
|
|
213
|
+
else
|
|
214
|
+
this.availableColumns.set([...curr]);
|
|
215
|
+
}
|
|
216
|
+
toggleSort(col) {
|
|
217
|
+
const cur = this.sortConfig();
|
|
218
|
+
const dir = cur.column === col
|
|
219
|
+
? cur.direction === 'asc'
|
|
220
|
+
? 'desc'
|
|
221
|
+
: cur.direction === 'desc'
|
|
222
|
+
? null
|
|
223
|
+
: 'asc'
|
|
224
|
+
: 'asc';
|
|
225
|
+
this.sortConfig.set({ column: dir ? col : '', direction: dir });
|
|
226
|
+
}
|
|
227
|
+
toggleFilter(column, value) {
|
|
228
|
+
this.filters.update((prev) => {
|
|
229
|
+
const currentList = prev[column] || [];
|
|
230
|
+
const newList = currentList.includes(value)
|
|
231
|
+
? currentList.filter((v) => v !== value) // Quitar si ya está
|
|
232
|
+
: [...currentList, value]; // Agregar si no está
|
|
233
|
+
return { ...prev, [column]: newList };
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
isAllSelected(column) {
|
|
237
|
+
if (!column)
|
|
238
|
+
return false;
|
|
239
|
+
const uniqueValues = this.uniqueValuesMap()[column] || [];
|
|
240
|
+
const currentFilters = this.filters()[column] || [];
|
|
241
|
+
// Si no hay filtros, por defecto todo está "seleccionado" visualmente
|
|
242
|
+
if (currentFilters.length === 0)
|
|
243
|
+
return true;
|
|
244
|
+
return uniqueValues.length === currentFilters.length;
|
|
245
|
+
}
|
|
246
|
+
toggleAll(column) {
|
|
247
|
+
const uniqueValues = this.uniqueValuesMap()[column] || [];
|
|
248
|
+
const currentFilters = this.filters()[column] || [];
|
|
249
|
+
this.filters.update((prev) => {
|
|
250
|
+
// Si ya están todos, limpiamos para mostrar todo de nuevo
|
|
251
|
+
if (currentFilters.length === 0 || currentFilters.length === uniqueValues.length) {
|
|
252
|
+
return { ...prev, [column]: [] };
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// Si no, seleccionamos todos los valores únicos
|
|
256
|
+
return { ...prev, [column]: [...uniqueValues] };
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
exportToExcel() {
|
|
261
|
+
const data = this.filteredData();
|
|
262
|
+
const columns = this.displayedColumns();
|
|
263
|
+
const foot = this.footData(); // El input que viene del padre
|
|
264
|
+
// 1. Mapear los datos del cuerpo
|
|
265
|
+
const dataToExport = data.map((row) => {
|
|
266
|
+
const filteredRow = {};
|
|
267
|
+
columns.forEach((col) => {
|
|
268
|
+
const headerName = this.getConfig(col)?.label || col;
|
|
269
|
+
filteredRow[headerName] = row[col];
|
|
270
|
+
});
|
|
271
|
+
return filteredRow;
|
|
272
|
+
});
|
|
273
|
+
// 2. Crear la fila del pie de página
|
|
274
|
+
const footerRow = {};
|
|
275
|
+
columns.forEach((col) => {
|
|
276
|
+
const headerName = this.getConfig(col)?.label || col;
|
|
277
|
+
// Buscamos si existe un valor en footData para esta key
|
|
278
|
+
footerRow[headerName] = foot[col] ?? '';
|
|
279
|
+
});
|
|
280
|
+
// 3. Insertar al final
|
|
281
|
+
dataToExport.push(footerRow);
|
|
282
|
+
const worksheet = XLSX.utils.json_to_sheet(dataToExport);
|
|
283
|
+
const workbook = XLSX.utils.book_new();
|
|
284
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, 'Reporte');
|
|
285
|
+
XLSX.writeFile(workbook, `${this.nameExport()}_${new Date().getTime()}.xlsx`);
|
|
286
|
+
}
|
|
287
|
+
exportToPDF() {
|
|
288
|
+
const doc = new jsPDF('l', 'mm', 'a4');
|
|
289
|
+
const data = this.filteredData();
|
|
290
|
+
const columns = this.displayedColumns();
|
|
291
|
+
const foot = this.footData();
|
|
292
|
+
const headers = columns.map((col) => this.getConfig(col)?.label || col);
|
|
293
|
+
// Datos del cuerpo
|
|
294
|
+
const rows = data.map((row) => columns.map((col) => row[col]));
|
|
295
|
+
// Fila del pie de página mapeada según el orden de las columnas visibles
|
|
296
|
+
const footerRow = columns.map((col) => foot[col] ?? '');
|
|
297
|
+
autoTable(doc, {
|
|
298
|
+
head: [headers],
|
|
299
|
+
body: rows,
|
|
300
|
+
foot: [footerRow], // Pasamos el pie aquí
|
|
301
|
+
theme: 'grid',
|
|
302
|
+
headStyles: { fillColor: [13, 110, 253] }, // Azul
|
|
303
|
+
footStyles: {
|
|
304
|
+
fillColor: [240, 240, 240], // Gris claro para resaltar
|
|
305
|
+
textColor: [0, 0, 0],
|
|
306
|
+
fontStyle: 'bold',
|
|
307
|
+
},
|
|
308
|
+
styles: { fontSize: 8, cellPadding: 2 },
|
|
309
|
+
});
|
|
310
|
+
doc.save(`${this.nameExport()}_${new Date().getTime()}.pdf`);
|
|
311
|
+
}
|
|
312
|
+
resetAllFilters() {
|
|
313
|
+
// 1. Limpiamos el objeto de filtros de columnas (vuelve a {})
|
|
314
|
+
this.filters.set({});
|
|
315
|
+
// 2. Limpiamos el buscador global
|
|
316
|
+
this.globalFilter.set('');
|
|
317
|
+
// 3. (Opcional) Si quieres que las columnas vuelvan a su orden original:
|
|
318
|
+
const config = this.columnsConfig();
|
|
319
|
+
this.displayedColumns.set(config.map((c) => c.key));
|
|
320
|
+
// Available inicia vacío por defecto como pediste
|
|
321
|
+
this.availableColumns.set([]);
|
|
322
|
+
}
|
|
323
|
+
goToPage(page) {
|
|
324
|
+
if (typeof page === 'number' && page > 0 && page <= this.totalPages()) {
|
|
325
|
+
this.currentPage.set(page);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: GenericTableDragAndDrop, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
329
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: GenericTableDragAndDrop, isStandalone: true, selector: "tbl-generic-drag-and-drop", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columnsConfig: { classPropertyName: "columnsConfig", publicName: "columnsConfig", isSignal: true, isRequired: false, transformFunction: null }, footData: { classPropertyName: "footData", publicName: "footData", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, exportExcel: { classPropertyName: "exportExcel", publicName: "exportExcel", isSignal: true, isRequired: false, transformFunction: null }, exportPdf: { classPropertyName: "exportPdf", publicName: "exportPdf", isSignal: true, isRequired: false, transformFunction: null }, nameExport: { classPropertyName: "nameExport", publicName: "nameExport", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"row g-3 mb-1 align-items-end\">\r\n <div class=\"col-12\">\r\n <div class=\"table-toolbar-container\">\r\n <div class=\"btn-group shadow-sm h-100\">\r\n <button\r\n class=\"btn btn-outline-warning btn-sm d-flex align-items-center\"\r\n (click)=\"resetAllFilters()\"\r\n title=\"Limpiar todos los filtros\"\r\n >\r\n <i class=\"fa fa-sync-alt me-1\"></i> Restablecer\r\n </button>\r\n @if (exportExcel()) {\r\n <button class=\"btn btn-outline-success border-end-0\" (click)=\"exportToExcel()\">\r\n <i class=\"fa fa-file-excel me-1\"></i>\r\n </button>\r\n }\r\n @if (exportPdf()) {\r\n <button class=\"btn btn-outline-danger border-end-0\" (click)=\"exportToPDF()\">\r\n <i class=\"fa fa-file-pdf me-1\"></i>\r\n </button>\r\n }\r\n <ng-content select=\"[buttonsexport]\"></ng-content>\r\n </div>\r\n\r\n <div class=\"input-group custom-search-input shadow-sm flex-grow-1 h-100\">\r\n <span class=\"input-group-text\"><i class=\"fa fa-search\"></i></span>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n placeholder=\"Buscar en el reporte actual...\"\r\n [value]=\"globalFilter()\"\r\n (input)=\"globalFilter.set($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 mb-3\">\r\n <div\r\n cdkDropList\r\n #availableList=\"cdkDropList\"\r\n id=\"available-list\"\r\n [cdkDropListData]=\"availableColumns()\"\r\n [cdkDropListConnectedTo]=\"[activeList]\"\r\n orientation=\"horizontal\"\r\n class=\"available-cols-box d-flex gap-2 flex-wrap justify-content-center align-items-center p-2 border rounded bg-light\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n >\r\n @for (col of availableColumns(); track col) {\r\n <div class=\"column-tag shadow-sm badge rounded-pill bg-danger p-2\" cdkDrag>\r\n <i class=\"fa fa-eye-slash me-1\"></i> {{ col }}\r\n </div>\r\n } @empty {\r\n <small class=\"text-muted opacity-50\">Arrastre aqu\u00ED las columnas que desea ocultar</small>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"table-responsive shadow-sm border rounded mb-2\" (scroll)=\"(0)\">\r\n <!-- <div class=\"table-container-scroll shadow-sm\"> -->\r\n <table class=\"table table-hover mb-0 table-sm\">\r\n <thead class=\"bg-dark text-white\">\r\n <tr\r\n cdkDropList\r\n #activeList=\"cdkDropList\"\r\n id=\"active-list\"\r\n [cdkDropListData]=\"displayedColumns()\"\r\n [cdkDropListConnectedTo]=\"[availableList]\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n cdkDropListOrientation=\"horizontal\"\r\n orientation=\"horizontal\"\r\n >\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <th cdkDrag class=\"bg-primary text-white border-end nowrap\">\r\n <div class=\"d-flex align-items-center justify-content-between h-100\">\r\n <span (click)=\"toggleSort(col)\" style=\"cursor: pointer\">\r\n <i class=\"fa fa-grip-vertical me-2 opacity-50\"></i>{{ config?.label || col }}\r\n @if (sortConfig().column === col) {\r\n <i\r\n class=\"fa ms-1\"\r\n [class.fa-sort-up]=\"sortConfig().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortConfig().direction === 'desc'\"\r\n ></i>\r\n }\r\n </span>\r\n <button\r\n class=\"btn btn-sm text-white p-0\"\r\n (click)=\"activeFilterColumn.set(col); showModal.set(true)\"\r\n >\r\n <i\r\n class=\"fa fa-filter\"\r\n [class.text-warning]=\"(filters()[col]?.length ?? 0) > 0\"\r\n ></i>\r\n </button>\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of pagedData(); track row.id) {\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <!-- <td>{{ $any(row)[col] }}</td> -->\r\n\r\n <td class=\"py-2 px-3 border-end\">\r\n <div [class.fw-bold]=\"config?.bold\" class=\"text-dark\">\r\n @switch (config?.type) {\r\n @case ('date') {\r\n {{ $any(row)[col] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col] }}\r\n }\r\n }\r\n </div>\r\n <!-- {{ $any(row)[col] }} -->\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.showIf || action.showIf(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.class\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n @if (hasFootData()) {\r\n <tfoot class=\"bg-light fw-bold border-top\">\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col); @let footValue = footData()[col];\r\n\r\n <td class=\"py-2 px-3 border-end text-dark\">\r\n @if (footValue !== undefined && footValue !== null) {\r\n @switch (config?.type) {\r\n @case ('currency') {\r\n {{ footValue | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ footValue | safeNumber }}\r\n }\r\n @default {\r\n {{ footValue }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"bg-light\"></td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n </table>\r\n <!-- </div> -->\r\n</div>\r\n<nav>\r\n <ul class=\"pagination pagination-sm mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\">Anterior</button>\r\n </li>\r\n\r\n @for (p of pagesArray(); track $index) {\r\n @if (p === '...') {\r\n <li class=\"page-item disabled\"><span class=\"page-link\">...</span></li>\r\n } @else {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === p\">\r\n <button class=\"page-link\" (click)=\"goToPage(p)\">{{ p }}</button>\r\n </li>\r\n }\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">Siguiente</button>\r\n </li>\r\n </ul>\r\n</nav>\r\n@if (showModal()) {\r\n <mdl-modal-generic\r\n [textTitle]=\"'Filtrar: ' + activeFilterColumn()\"\r\n [showFooter]=\"false\"\r\n modalSize=\"md\"\r\n >\r\n <ng-container buttonclose>\r\n <button type=\"button\" class=\"btn-close py-0\" (click)=\"showModal.set(false)\"></button>\r\n </ng-container>\r\n\r\n <ng-container body>\r\n <div class=\"px-2\">\r\n <div class=\"form-check mb-3\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n id=\"all-modal\"\r\n [checked]=\"isAllSelected(activeFilterColumn())\"\r\n (change)=\"toggleAll(activeFilterColumn())\"\r\n />\r\n <label class=\"form-check-label fw-bold\" for=\"all-modal\">(Seleccionar todo)</label>\r\n </div>\r\n <hr />\r\n <div style=\"max-height: 300px; overflow-y: auto\" class=\"custom-scroll\">\r\n @for (val of uniqueValuesMap()[activeFilterColumn()]; track val) {\r\n <div class=\"form-check py-1\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [id]=\"'check-' + val\"\r\n [checked]=\"filters()[activeFilterColumn()]?.includes(val)\"\r\n (change)=\"toggleFilter(activeFilterColumn(), val)\"\r\n />\r\n <label class=\"form-check-label\" [for]=\"'check-' + val\">{{ val }}</label>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </ng-container>\r\n </mdl-modal-generic>\r\n}\r\n", styles: ["@charset \"UTF-8\";tfoot{position:sticky;bottom:0;z-index:10;background-color:#f8f9fa;box-shadow:0 -2px 5px #0000001a}.table-toolbar-container{display:flex;align-items:center;gap:10px;height:40px}.custom-search-input{border-radius:6px!important;border:1px solid #ced4da;height:100%}.custom-search-input .input-group-text{background-color:#fff;border-right:none;color:#adb5bd;padding-left:12px;padding-right:8px}.custom-search-input .form-control{border-left:none;font-size:.9rem;box-shadow:none!important}.custom-search-input:focus-within{border-color:#0d6efd;box-shadow:0 0 0 .25rem #0d6efd1a}.available-cols-box{background-color:#d3d3d4;border-radius:8px;padding:8px 12px;min-height:50px}.column-tag{background-color:#ff6b52!important;color:#fff;padding:6px 14px;font-size:.85rem;font-weight:600;border-radius:20px;cursor:grab;transition:all .2s}.column-tag:hover{transform:translateY(-2px);filter:brightness(1.1)}th,td{overflow:hidden;white-space:nowrap}tfoot{position:sticky;bottom:0;z-index:5;background-color:#f8f9fa}tfoot td{border-top:2px solid #dee2e6!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: ModalGeneric, selector: "mdl-modal-generic", inputs: ["textTitle", "modalSize", "showFooter", "FullScreen"] }, { kind: "pipe", type: SafeDatePipe, name: "safeDate" }, { kind: "pipe", type: SafeCurrencyPipe, name: "safeCurrency" }, { kind: "pipe", type: SafeNumberPipe, name: "safeNumber" }] });
|
|
330
|
+
}
|
|
331
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: GenericTableDragAndDrop, decorators: [{
|
|
332
|
+
type: Component,
|
|
333
|
+
args: [{ selector: 'tbl-generic-drag-and-drop', imports: [
|
|
334
|
+
CommonModule,
|
|
335
|
+
DragDropModule,
|
|
336
|
+
ModalGeneric,
|
|
337
|
+
CdkDropList,
|
|
338
|
+
CdkDrag,
|
|
339
|
+
SafeDatePipe,
|
|
340
|
+
SafeCurrencyPipe,
|
|
341
|
+
SafeNumberPipe,
|
|
342
|
+
], template: "<div class=\"row g-3 mb-1 align-items-end\">\r\n <div class=\"col-12\">\r\n <div class=\"table-toolbar-container\">\r\n <div class=\"btn-group shadow-sm h-100\">\r\n <button\r\n class=\"btn btn-outline-warning btn-sm d-flex align-items-center\"\r\n (click)=\"resetAllFilters()\"\r\n title=\"Limpiar todos los filtros\"\r\n >\r\n <i class=\"fa fa-sync-alt me-1\"></i> Restablecer\r\n </button>\r\n @if (exportExcel()) {\r\n <button class=\"btn btn-outline-success border-end-0\" (click)=\"exportToExcel()\">\r\n <i class=\"fa fa-file-excel me-1\"></i>\r\n </button>\r\n }\r\n @if (exportPdf()) {\r\n <button class=\"btn btn-outline-danger border-end-0\" (click)=\"exportToPDF()\">\r\n <i class=\"fa fa-file-pdf me-1\"></i>\r\n </button>\r\n }\r\n <ng-content select=\"[buttonsexport]\"></ng-content>\r\n </div>\r\n\r\n <div class=\"input-group custom-search-input shadow-sm flex-grow-1 h-100\">\r\n <span class=\"input-group-text\"><i class=\"fa fa-search\"></i></span>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n placeholder=\"Buscar en el reporte actual...\"\r\n [value]=\"globalFilter()\"\r\n (input)=\"globalFilter.set($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 mb-3\">\r\n <div\r\n cdkDropList\r\n #availableList=\"cdkDropList\"\r\n id=\"available-list\"\r\n [cdkDropListData]=\"availableColumns()\"\r\n [cdkDropListConnectedTo]=\"[activeList]\"\r\n orientation=\"horizontal\"\r\n class=\"available-cols-box d-flex gap-2 flex-wrap justify-content-center align-items-center p-2 border rounded bg-light\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n >\r\n @for (col of availableColumns(); track col) {\r\n <div class=\"column-tag shadow-sm badge rounded-pill bg-danger p-2\" cdkDrag>\r\n <i class=\"fa fa-eye-slash me-1\"></i> {{ col }}\r\n </div>\r\n } @empty {\r\n <small class=\"text-muted opacity-50\">Arrastre aqu\u00ED las columnas que desea ocultar</small>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"table-responsive shadow-sm border rounded mb-2\" (scroll)=\"(0)\">\r\n <!-- <div class=\"table-container-scroll shadow-sm\"> -->\r\n <table class=\"table table-hover mb-0 table-sm\">\r\n <thead class=\"bg-dark text-white\">\r\n <tr\r\n cdkDropList\r\n #activeList=\"cdkDropList\"\r\n id=\"active-list\"\r\n [cdkDropListData]=\"displayedColumns()\"\r\n [cdkDropListConnectedTo]=\"[availableList]\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n cdkDropListOrientation=\"horizontal\"\r\n orientation=\"horizontal\"\r\n >\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <th cdkDrag class=\"bg-primary text-white border-end nowrap\">\r\n <div class=\"d-flex align-items-center justify-content-between h-100\">\r\n <span (click)=\"toggleSort(col)\" style=\"cursor: pointer\">\r\n <i class=\"fa fa-grip-vertical me-2 opacity-50\"></i>{{ config?.label || col }}\r\n @if (sortConfig().column === col) {\r\n <i\r\n class=\"fa ms-1\"\r\n [class.fa-sort-up]=\"sortConfig().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortConfig().direction === 'desc'\"\r\n ></i>\r\n }\r\n </span>\r\n <button\r\n class=\"btn btn-sm text-white p-0\"\r\n (click)=\"activeFilterColumn.set(col); showModal.set(true)\"\r\n >\r\n <i\r\n class=\"fa fa-filter\"\r\n [class.text-warning]=\"(filters()[col]?.length ?? 0) > 0\"\r\n ></i>\r\n </button>\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of pagedData(); track row.id) {\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <!-- <td>{{ $any(row)[col] }}</td> -->\r\n\r\n <td class=\"py-2 px-3 border-end\">\r\n <div [class.fw-bold]=\"config?.bold\" class=\"text-dark\">\r\n @switch (config?.type) {\r\n @case ('date') {\r\n {{ $any(row)[col] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col] }}\r\n }\r\n }\r\n </div>\r\n <!-- {{ $any(row)[col] }} -->\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.showIf || action.showIf(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.class\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n @if (hasFootData()) {\r\n <tfoot class=\"bg-light fw-bold border-top\">\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col); @let footValue = footData()[col];\r\n\r\n <td class=\"py-2 px-3 border-end text-dark\">\r\n @if (footValue !== undefined && footValue !== null) {\r\n @switch (config?.type) {\r\n @case ('currency') {\r\n {{ footValue | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ footValue | safeNumber }}\r\n }\r\n @default {\r\n {{ footValue }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"bg-light\"></td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n </table>\r\n <!-- </div> -->\r\n</div>\r\n<nav>\r\n <ul class=\"pagination pagination-sm mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\">Anterior</button>\r\n </li>\r\n\r\n @for (p of pagesArray(); track $index) {\r\n @if (p === '...') {\r\n <li class=\"page-item disabled\"><span class=\"page-link\">...</span></li>\r\n } @else {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === p\">\r\n <button class=\"page-link\" (click)=\"goToPage(p)\">{{ p }}</button>\r\n </li>\r\n }\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">Siguiente</button>\r\n </li>\r\n </ul>\r\n</nav>\r\n@if (showModal()) {\r\n <mdl-modal-generic\r\n [textTitle]=\"'Filtrar: ' + activeFilterColumn()\"\r\n [showFooter]=\"false\"\r\n modalSize=\"md\"\r\n >\r\n <ng-container buttonclose>\r\n <button type=\"button\" class=\"btn-close py-0\" (click)=\"showModal.set(false)\"></button>\r\n </ng-container>\r\n\r\n <ng-container body>\r\n <div class=\"px-2\">\r\n <div class=\"form-check mb-3\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n id=\"all-modal\"\r\n [checked]=\"isAllSelected(activeFilterColumn())\"\r\n (change)=\"toggleAll(activeFilterColumn())\"\r\n />\r\n <label class=\"form-check-label fw-bold\" for=\"all-modal\">(Seleccionar todo)</label>\r\n </div>\r\n <hr />\r\n <div style=\"max-height: 300px; overflow-y: auto\" class=\"custom-scroll\">\r\n @for (val of uniqueValuesMap()[activeFilterColumn()]; track val) {\r\n <div class=\"form-check py-1\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [id]=\"'check-' + val\"\r\n [checked]=\"filters()[activeFilterColumn()]?.includes(val)\"\r\n (change)=\"toggleFilter(activeFilterColumn(), val)\"\r\n />\r\n <label class=\"form-check-label\" [for]=\"'check-' + val\">{{ val }}</label>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </ng-container>\r\n </mdl-modal-generic>\r\n}\r\n", styles: ["@charset \"UTF-8\";tfoot{position:sticky;bottom:0;z-index:10;background-color:#f8f9fa;box-shadow:0 -2px 5px #0000001a}.table-toolbar-container{display:flex;align-items:center;gap:10px;height:40px}.custom-search-input{border-radius:6px!important;border:1px solid #ced4da;height:100%}.custom-search-input .input-group-text{background-color:#fff;border-right:none;color:#adb5bd;padding-left:12px;padding-right:8px}.custom-search-input .form-control{border-left:none;font-size:.9rem;box-shadow:none!important}.custom-search-input:focus-within{border-color:#0d6efd;box-shadow:0 0 0 .25rem #0d6efd1a}.available-cols-box{background-color:#d3d3d4;border-radius:8px;padding:8px 12px;min-height:50px}.column-tag{background-color:#ff6b52!important;color:#fff;padding:6px 14px;font-size:.85rem;font-weight:600;border-radius:20px;cursor:grab;transition:all .2s}.column-tag:hover{transform:translateY(-2px);filter:brightness(1.1)}th,td{overflow:hidden;white-space:nowrap}tfoot{position:sticky;bottom:0;z-index:5;background-color:#f8f9fa}tfoot td{border-top:2px solid #dee2e6!important}\n"] }]
|
|
343
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columnsConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnsConfig", required: false }] }], footData: [{ type: i0.Input, args: [{ isSignal: true, alias: "footData", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], exportExcel: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportExcel", required: false }] }], exportPdf: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportPdf", required: false }] }], nameExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "nameExport", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }] } });
|
|
344
|
+
|
|
345
|
+
/*
|
|
346
|
+
* Public API Surface of generic-table-drag-and-drop
|
|
347
|
+
*/
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Generated bundle index. Do not edit.
|
|
351
|
+
*/
|
|
352
|
+
|
|
353
|
+
export { GenericTableDragAndDrop };
|
|
354
|
+
//# sourceMappingURL=ddiazr-generic-table-drag-and-drop.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ddiazr-generic-table-drag-and-drop.mjs","sources":["../../../projects/generic-table-drag-and-drop/src/lib/pipes/safe-date.pipe.ts","../../../projects/generic-table-drag-and-drop/src/lib/pipes/safe-currency.pipe.ts","../../../projects/generic-table-drag-and-drop/src/lib/pipes/safe-number.pipe.ts","../../../projects/generic-table-drag-and-drop/src/lib/generic-table-drag-and-drop.ts","../../../projects/generic-table-drag-and-drop/src/lib/generic-table-drag-and-drop.html","../../../projects/generic-table-drag-and-drop/src/public-api.ts","../../../projects/generic-table-drag-and-drop/src/ddiazr-generic-table-drag-and-drop.ts"],"sourcesContent":["import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeDate\",\r\n standalone: true,\r\n pure: true, // ✅ Muy importante para performance\r\n})\r\nexport class SafeDatePipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (!value) return \"\";\r\n const date = new Date(value);\r\n if (isNaN(date.getTime())) return value;\r\n\r\n const day = String(date.getDate()).padStart(2, \"0\");\r\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\r\n const year = date.getFullYear();\r\n\r\n return `${day}/${month}/${year}`;\r\n }\r\n}\r\n","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: 'safeCurrency',\r\n standalone: true,\r\n pure: true\r\n})\r\nexport class SafeCurrencyPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === '') return '';\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n \r\n return 'Q' + num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\r\n }\r\n}","import { Pipe, PipeTransform } from \"@angular/core\";\r\n\r\n@Pipe({\r\n name: \"safeNumber\",\r\n standalone: true,\r\n pure: true,\r\n})\r\nexport class SafeNumberPipe implements PipeTransform {\r\n transform(value: any): string {\r\n if (value == null || value === \"\") return \"\";\r\n const num = Number(value);\r\n if (isNaN(num)) return value;\r\n\r\n return num.toFixed(2).replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\");\r\n }\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport {\r\n CdkDrag,\r\n CdkDragDrop,\r\n CdkDropList,\r\n DragDropModule,\r\n moveItemInArray,\r\n transferArrayItem,\r\n} from '@angular/cdk/drag-drop';\r\nimport { Component, computed, effect, input, signal } from '@angular/core';\r\nimport * as XLSX from 'xlsx';\r\nimport jsPDF from 'jspdf';\r\nimport autoTable from 'jspdf-autotable';\r\nimport { ColumnConfig, TableAction } from './models/table.interfaces';\r\nimport { SafeDatePipe } from './pipes/safe-date.pipe';\r\nimport { SafeCurrencyPipe } from './pipes/safe-currency.pipe';\r\nimport { SafeNumberPipe } from './pipes/safe-number.pipe';\r\nimport { ModalGeneric } from 'modal-generic'\r\n\r\n@Component({\r\n selector: 'tbl-generic-drag-and-drop',\r\n imports: [\r\n CommonModule,\r\n DragDropModule,\r\n ModalGeneric,\r\n CdkDropList,\r\n CdkDrag,\r\n SafeDatePipe,\r\n SafeCurrencyPipe,\r\n SafeNumberPipe,\r\n ],\r\n templateUrl: './generic-table-drag-and-drop.html',\r\n styleUrl: './generic-table-drag-and-drop.scss',\r\n})\r\nexport class GenericTableDragAndDrop<T extends { id: any }> {\r\n // Inputs\r\n data = input.required<T[]>();\r\n columnsConfig = input<ColumnConfig[]>([]);\r\n footData = input<Record<string, any>>({});\r\n actions = input<TableAction<T>[]>([]);\r\n exportExcel = input<boolean>(false);\r\n exportPdf = input<boolean>(false);\r\n nameExport = input<string>('reporte');\r\n pageSize = input<number>(25);\r\n\r\n // Estado\r\n displayedColumns = signal<string[]>([]);\r\n availableColumns = signal<string[]>([]);\r\n globalFilter = signal<string>('');\r\n filters = signal<Record<string, string[]>>({});\r\n sortConfig = signal<{ column: string; direction: 'asc' | 'desc' | null }>({\r\n column: '',\r\n direction: null,\r\n });\r\n activeFilterColumn = signal<string>('');\r\n showModal = signal<boolean>(false);\r\n currentPage = signal(1);\r\n\r\n constructor() {\r\n effect(\r\n () => {\r\n const d = this.data();\r\n if (d?.length) {\r\n this.currentPage.set(1);\r\n }\r\n },\r\n { allowSignalWrites: true },\r\n );\r\n\r\n // Inicialización de columnas\r\n effect(\r\n () => {\r\n const config = this.columnsConfig();\r\n if (config.length > 0 && this.displayedColumns().length === 0) {\r\n this.displayedColumns.set(config.map((c) => c.key));\r\n }\r\n },\r\n { allowSignalWrites: true },\r\n );\r\n\r\n // RESET de página al filtrar: Muy importante\r\n effect(\r\n () => {\r\n this.globalFilter();\r\n this.filters();\r\n this.currentPage.set(1);\r\n },\r\n { allowSignalWrites: true },\r\n );\r\n }\r\n\r\n // Lógica de filtrado\r\n filteredData = computed(() => {\r\n let result = [...this.data()];\r\n const search = this.globalFilter().toLowerCase();\r\n const activeFilters = this.filters();\r\n const sort = this.sortConfig();\r\n\r\n if (search) {\r\n result = result.filter((row) =>\r\n Object.values(row).some((val) => String(val).toLowerCase().includes(search)),\r\n );\r\n }\r\n\r\n Object.keys(activeFilters).forEach((col) => {\r\n const values = activeFilters[col];\r\n if (values?.length > 0) {\r\n result = result.filter((row) => values.includes(String((row as any)[col])));\r\n }\r\n });\r\n\r\n if (sort.column && sort.direction) {\r\n result.sort((a, b) => {\r\n const valA = String((a as any)[sort.column]).toLowerCase();\r\n const valB = String((b as any)[sort.column]).toLowerCase();\r\n const res = valA.localeCompare(valB, undefined, { numeric: true });\r\n return sort.direction === 'asc' ? res : -res;\r\n });\r\n }\r\n return result;\r\n });\r\n\r\n uniqueValuesMap = computed(() => {\r\n const baseData = this.data();\r\n const activeFilters = this.filters();\r\n const allCols = [...this.availableColumns(), ...this.displayedColumns()];\r\n const map: Record<string, string[]> = {};\r\n\r\n allCols.forEach((col) => {\r\n // FILTRADO DINÁMICO:\r\n // Para la lista de la columna \"X\", filtramos la data base\r\n // usando los criterios de TODAS las columnas MENOS la columna \"X\".\r\n const dataFilteredByOthers = baseData.filter((row) => {\r\n return Object.keys(activeFilters).every((filterCol) => {\r\n // Si es la misma columna que estamos calculando, ignoramos su filtro\r\n if (filterCol === col) return true;\r\n\r\n const values = activeFilters[filterCol];\r\n if (!values || values.length === 0) return true;\r\n\r\n return values.includes(String((row as any)[filterCol]));\r\n });\r\n });\r\n\r\n // Extraemos los valores únicos de esa data filtrada por los demás\r\n map[col] = [\r\n ...new Set(dataFilteredByOthers.map((item) => String((item as any)[col]))),\r\n ].sort();\r\n });\r\n\r\n return map;\r\n });\r\n\r\n // Data que realmente se renderiza (muy ligera)\r\n pagedData = computed(() => {\r\n const start = (this.currentPage() - 1) * this.pageSize();\r\n return this.filteredData().slice(start, start + this.pageSize());\r\n });\r\n\r\n totalPages = computed(() => Math.ceil(this.filteredData().length / this.pageSize()) || 1);\r\n\r\n // Genera el array de números para los botones (ej: [1, 2, 3...])\r\n pagesArray = computed<(number | string)[]>(() => {\r\n const current = this.currentPage();\r\n const total = this.totalPages();\r\n const pages: (number | string)[] = []; // Especificamos el tipo aquí\r\n\r\n for (let i = 1; i <= total; i++) {\r\n // Lógica para mostrar: primera, última, y 2 alrededor de la actual\r\n if (i === 1 || i === total || (i >= current - 2 && i <= current + 2)) {\r\n pages.push(i);\r\n } else if (pages[pages.length - 1] !== '...') {\r\n pages.push('...');\r\n }\r\n }\r\n return pages;\r\n });\r\n\r\n //SI TRAE FOOT\r\n hasFootData = computed(() => Object.keys(this.footData()).length > 0);\r\n\r\n getConfig(key: string): ColumnConfig | undefined {\r\n return this.columnsConfig().find((c) => c.key === key);\r\n }\r\n // Métodos de UI (Drop, Sort, Filter) simplificados\r\n drop(event: CdkDragDrop<string[]>) {\r\n console.log('Envent:::', event);\r\n const prev = event.previousContainer.data;\r\n const curr = event.container.data;\r\n if (event.previousContainer === event.container) {\r\n moveItemInArray(curr, event.previousIndex, event.currentIndex);\r\n } else {\r\n transferArrayItem(prev, curr, event.previousIndex, event.currentIndex);\r\n }\r\n // Sincronizar con los modelos\r\n if (event.container.id === 'active-list') this.displayedColumns.set([...curr]);\r\n else this.availableColumns.set([...curr]);\r\n }\r\n\r\n toggleSort(col: string) {\r\n const cur = this.sortConfig();\r\n const dir =\r\n cur.column === col\r\n ? cur.direction === 'asc'\r\n ? 'desc'\r\n : cur.direction === 'desc'\r\n ? null\r\n : 'asc'\r\n : 'asc';\r\n this.sortConfig.set({ column: dir ? col : '', direction: dir });\r\n }\r\n\r\n toggleFilter(column: string, value: string) {\r\n this.filters.update((prev) => {\r\n const currentList = prev[column] || [];\r\n const newList = currentList.includes(value)\r\n ? currentList.filter((v) => v !== value) // Quitar si ya está\r\n : [...currentList, value]; // Agregar si no está\r\n\r\n return { ...prev, [column]: newList };\r\n });\r\n }\r\n\r\n isAllSelected(column: string): boolean {\r\n if (!column) return false;\r\n const uniqueValues = this.uniqueValuesMap()[column] || [];\r\n const currentFilters = this.filters()[column] || [];\r\n\r\n // Si no hay filtros, por defecto todo está \"seleccionado\" visualmente\r\n if (currentFilters.length === 0) return true;\r\n return uniqueValues.length === currentFilters.length;\r\n }\r\n\r\n toggleAll(column: string) {\r\n const uniqueValues = this.uniqueValuesMap()[column] || [];\r\n const currentFilters = this.filters()[column] || [];\r\n\r\n this.filters.update((prev) => {\r\n // Si ya están todos, limpiamos para mostrar todo de nuevo\r\n if (currentFilters.length === 0 || currentFilters.length === uniqueValues.length) {\r\n return { ...prev, [column]: [] };\r\n } else {\r\n // Si no, seleccionamos todos los valores únicos\r\n return { ...prev, [column]: [...uniqueValues] };\r\n }\r\n });\r\n }\r\n\r\n exportToExcel() {\r\n const data = this.filteredData();\r\n const columns = this.displayedColumns();\r\n const foot = this.footData(); // El input que viene del padre\r\n\r\n // 1. Mapear los datos del cuerpo\r\n const dataToExport = data.map((row) => {\r\n const filteredRow: any = {};\r\n columns.forEach((col) => {\r\n const headerName = this.getConfig(col)?.label || col;\r\n filteredRow[headerName] = (row as any)[col];\r\n });\r\n return filteredRow;\r\n });\r\n\r\n // 2. Crear la fila del pie de página\r\n const footerRow: any = {};\r\n columns.forEach((col) => {\r\n const headerName = this.getConfig(col)?.label || col;\r\n // Buscamos si existe un valor en footData para esta key\r\n footerRow[headerName] = foot[col] ?? '';\r\n });\r\n\r\n // 3. Insertar al final\r\n dataToExport.push(footerRow);\r\n\r\n const worksheet = XLSX.utils.json_to_sheet(dataToExport);\r\n const workbook = XLSX.utils.book_new();\r\n XLSX.utils.book_append_sheet(workbook, worksheet, 'Reporte');\r\n\r\n XLSX.writeFile(workbook, `${this.nameExport()}_${new Date().getTime()}.xlsx`);\r\n }\r\n\r\n exportToPDF() {\r\n const doc = new jsPDF('l', 'mm', 'a4');\r\n const data = this.filteredData();\r\n const columns = this.displayedColumns();\r\n const foot = this.footData();\r\n\r\n const headers = columns.map((col) => this.getConfig(col)?.label || col);\r\n\r\n // Datos del cuerpo\r\n const rows = data.map((row) => columns.map((col) => (row as any)[col]));\r\n\r\n // Fila del pie de página mapeada según el orden de las columnas visibles\r\n const footerRow = columns.map((col) => foot[col] ?? '');\r\n\r\n autoTable(doc, {\r\n head: [headers],\r\n body: rows,\r\n foot: [footerRow], // Pasamos el pie aquí\r\n theme: 'grid',\r\n headStyles: { fillColor: [13, 110, 253] }, // Azul\r\n footStyles: {\r\n fillColor: [240, 240, 240], // Gris claro para resaltar\r\n textColor: [0, 0, 0],\r\n fontStyle: 'bold',\r\n },\r\n styles: { fontSize: 8, cellPadding: 2 },\r\n });\r\n\r\n doc.save(`${this.nameExport()}_${new Date().getTime()}.pdf`);\r\n }\r\n\r\n resetAllFilters() {\r\n // 1. Limpiamos el objeto de filtros de columnas (vuelve a {})\r\n this.filters.set({});\r\n\r\n // 2. Limpiamos el buscador global\r\n this.globalFilter.set('');\r\n\r\n // 3. (Opcional) Si quieres que las columnas vuelvan a su orden original:\r\n const config = this.columnsConfig();\r\n this.displayedColumns.set(config.map((c) => c.key));\r\n // Available inicia vacío por defecto como pediste\r\n this.availableColumns.set([]);\r\n }\r\n\r\n goToPage(page: number | string) {\r\n if (typeof page === 'number' && page > 0 && page <= this.totalPages()) {\r\n this.currentPage.set(page);\r\n }\r\n }\r\n}\r\n","<div class=\"row g-3 mb-1 align-items-end\">\r\n <div class=\"col-12\">\r\n <div class=\"table-toolbar-container\">\r\n <div class=\"btn-group shadow-sm h-100\">\r\n <button\r\n class=\"btn btn-outline-warning btn-sm d-flex align-items-center\"\r\n (click)=\"resetAllFilters()\"\r\n title=\"Limpiar todos los filtros\"\r\n >\r\n <i class=\"fa fa-sync-alt me-1\"></i> Restablecer\r\n </button>\r\n @if (exportExcel()) {\r\n <button class=\"btn btn-outline-success border-end-0\" (click)=\"exportToExcel()\">\r\n <i class=\"fa fa-file-excel me-1\"></i>\r\n </button>\r\n }\r\n @if (exportPdf()) {\r\n <button class=\"btn btn-outline-danger border-end-0\" (click)=\"exportToPDF()\">\r\n <i class=\"fa fa-file-pdf me-1\"></i>\r\n </button>\r\n }\r\n <ng-content select=\"[buttonsexport]\"></ng-content>\r\n </div>\r\n\r\n <div class=\"input-group custom-search-input shadow-sm flex-grow-1 h-100\">\r\n <span class=\"input-group-text\"><i class=\"fa fa-search\"></i></span>\r\n <input\r\n type=\"text\"\r\n class=\"form-control\"\r\n placeholder=\"Buscar en el reporte actual...\"\r\n [value]=\"globalFilter()\"\r\n (input)=\"globalFilter.set($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"col-12 mb-3\">\r\n <div\r\n cdkDropList\r\n #availableList=\"cdkDropList\"\r\n id=\"available-list\"\r\n [cdkDropListData]=\"availableColumns()\"\r\n [cdkDropListConnectedTo]=\"[activeList]\"\r\n orientation=\"horizontal\"\r\n class=\"available-cols-box d-flex gap-2 flex-wrap justify-content-center align-items-center p-2 border rounded bg-light\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n >\r\n @for (col of availableColumns(); track col) {\r\n <div class=\"column-tag shadow-sm badge rounded-pill bg-danger p-2\" cdkDrag>\r\n <i class=\"fa fa-eye-slash me-1\"></i> {{ col }}\r\n </div>\r\n } @empty {\r\n <small class=\"text-muted opacity-50\">Arrastre aquí las columnas que desea ocultar</small>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div class=\"table-responsive shadow-sm border rounded mb-2\" (scroll)=\"(0)\">\r\n <!-- <div class=\"table-container-scroll shadow-sm\"> -->\r\n <table class=\"table table-hover mb-0 table-sm\">\r\n <thead class=\"bg-dark text-white\">\r\n <tr\r\n cdkDropList\r\n #activeList=\"cdkDropList\"\r\n id=\"active-list\"\r\n [cdkDropListData]=\"displayedColumns()\"\r\n [cdkDropListConnectedTo]=\"[availableList]\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n cdkDropListOrientation=\"horizontal\"\r\n orientation=\"horizontal\"\r\n >\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <th cdkDrag class=\"bg-primary text-white border-end nowrap\">\r\n <div class=\"d-flex align-items-center justify-content-between h-100\">\r\n <span (click)=\"toggleSort(col)\" style=\"cursor: pointer\">\r\n <i class=\"fa fa-grip-vertical me-2 opacity-50\"></i>{{ config?.label || col }}\r\n @if (sortConfig().column === col) {\r\n <i\r\n class=\"fa ms-1\"\r\n [class.fa-sort-up]=\"sortConfig().direction === 'asc'\"\r\n [class.fa-sort-down]=\"sortConfig().direction === 'desc'\"\r\n ></i>\r\n }\r\n </span>\r\n <button\r\n class=\"btn btn-sm text-white p-0\"\r\n (click)=\"activeFilterColumn.set(col); showModal.set(true)\"\r\n >\r\n <i\r\n class=\"fa fa-filter\"\r\n [class.text-warning]=\"(filters()[col]?.length ?? 0) > 0\"\r\n ></i>\r\n </button>\r\n </div>\r\n </th>\r\n }\r\n @if (actions().length > 0) {\r\n <th class=\"bg-dark text-center\">Acciones</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of pagedData(); track row.id) {\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col);\r\n <!-- <td>{{ $any(row)[col] }}</td> -->\r\n\r\n <td class=\"py-2 px-3 border-end\">\r\n <div [class.fw-bold]=\"config?.bold\" class=\"text-dark\">\r\n @switch (config?.type) {\r\n @case ('date') {\r\n {{ $any(row)[col] | safeDate }}\r\n }\r\n @case ('currency') {\r\n {{ $any(row)[col] | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ $any(row)[col] | safeNumber }}\r\n }\r\n @default {\r\n {{ $any(row)[col] }}\r\n }\r\n }\r\n </div>\r\n <!-- {{ $any(row)[col] }} -->\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"text-center\">\r\n @for (action of actions(); track action.label) {\r\n @if (!action.showIf || action.showIf(row)) {\r\n <button\r\n [class]=\"'btn btn-sm mx-1 ' + action.class\"\r\n (click)=\"action.callback(row)\"\r\n >\r\n <i [class]=\"action.icon\"></i>\r\n </button>\r\n }\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n @if (hasFootData()) {\r\n <tfoot class=\"bg-light fw-bold border-top\">\r\n <tr>\r\n @for (col of displayedColumns(); track col) {\r\n @let config = getConfig(col); @let footValue = footData()[col];\r\n\r\n <td class=\"py-2 px-3 border-end text-dark\">\r\n @if (footValue !== undefined && footValue !== null) {\r\n @switch (config?.type) {\r\n @case ('currency') {\r\n {{ footValue | safeCurrency }}\r\n }\r\n @case ('number') {\r\n {{ footValue | safeNumber }}\r\n }\r\n @default {\r\n {{ footValue }}\r\n }\r\n }\r\n }\r\n </td>\r\n }\r\n @if (actions().length > 0) {\r\n <td class=\"bg-light\"></td>\r\n }\r\n </tr>\r\n </tfoot>\r\n }\r\n </table>\r\n <!-- </div> -->\r\n</div>\r\n<nav>\r\n <ul class=\"pagination pagination-sm mb-0\">\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === 1\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() - 1)\">Anterior</button>\r\n </li>\r\n\r\n @for (p of pagesArray(); track $index) {\r\n @if (p === '...') {\r\n <li class=\"page-item disabled\"><span class=\"page-link\">...</span></li>\r\n } @else {\r\n <li class=\"page-item\" [class.active]=\"currentPage() === p\">\r\n <button class=\"page-link\" (click)=\"goToPage(p)\">{{ p }}</button>\r\n </li>\r\n }\r\n }\r\n\r\n <li class=\"page-item\" [class.disabled]=\"currentPage() === totalPages()\">\r\n <button class=\"page-link\" (click)=\"goToPage(currentPage() + 1)\">Siguiente</button>\r\n </li>\r\n </ul>\r\n</nav>\r\n@if (showModal()) {\r\n <mdl-modal-generic\r\n [textTitle]=\"'Filtrar: ' + activeFilterColumn()\"\r\n [showFooter]=\"false\"\r\n modalSize=\"md\"\r\n >\r\n <ng-container buttonclose>\r\n <button type=\"button\" class=\"btn-close py-0\" (click)=\"showModal.set(false)\"></button>\r\n </ng-container>\r\n\r\n <ng-container body>\r\n <div class=\"px-2\">\r\n <div class=\"form-check mb-3\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n id=\"all-modal\"\r\n [checked]=\"isAllSelected(activeFilterColumn())\"\r\n (change)=\"toggleAll(activeFilterColumn())\"\r\n />\r\n <label class=\"form-check-label fw-bold\" for=\"all-modal\">(Seleccionar todo)</label>\r\n </div>\r\n <hr />\r\n <div style=\"max-height: 300px; overflow-y: auto\" class=\"custom-scroll\">\r\n @for (val of uniqueValuesMap()[activeFilterColumn()]; track val) {\r\n <div class=\"form-check py-1\">\r\n <input\r\n class=\"form-check-input\"\r\n type=\"checkbox\"\r\n [id]=\"'check-' + val\"\r\n [checked]=\"filters()[activeFilterColumn()]?.includes(val)\"\r\n (change)=\"toggleFilter(activeFilterColumn(), val)\"\r\n />\r\n <label class=\"form-check-label\" [for]=\"'check-' + val\">{{ val }}</label>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </ng-container>\r\n </mdl-modal-generic>\r\n}\r\n","/*\r\n * Public API Surface of generic-table-drag-and-drop\r\n */\r\n\r\nexport * from './lib/generic-table-drag-and-drop';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddiazr/generic-table-drag-and-drop",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Tabla generica que puede hacer drag and drop, acciones, export PDF,EXCEl",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Dany Díaz",
|
|
7
|
+
"email": "danylen1@hotmail.com"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"peerDependencies": {
|
|
11
|
+
"@angular/common": "^21.1.0",
|
|
12
|
+
"@angular/core": "^21.1.0",
|
|
13
|
+
"@angular/cdk": "^21.1.2",
|
|
14
|
+
"bootstrap": "^5.3.8",
|
|
15
|
+
"@fortawesome/fontawesome-free": "^7.1.0",
|
|
16
|
+
"jspdf": "^4.0.0",
|
|
17
|
+
"jspdf-autotable": "^5.0.7",
|
|
18
|
+
"xlsx": "^0.18.5"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"tslib": "^2.3.0"
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"module": "fesm2022/ddiazr-generic-table-drag-and-drop.mjs",
|
|
25
|
+
"typings": "types/ddiazr-generic-table-drag-and-drop.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
"./package.json": {
|
|
28
|
+
"default": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./types/ddiazr-generic-table-drag-and-drop.d.ts",
|
|
32
|
+
"default": "./fesm2022/ddiazr-generic-table-drag-and-drop.mjs"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
|
3
|
+
|
|
4
|
+
interface TableAction<T> {
|
|
5
|
+
label: string;
|
|
6
|
+
icon: string;
|
|
7
|
+
class: string;
|
|
8
|
+
callback: (row: T) => void;
|
|
9
|
+
showIf?: (row: T) => boolean;
|
|
10
|
+
}
|
|
11
|
+
interface ColumnConfig {
|
|
12
|
+
key: string;
|
|
13
|
+
label: string;
|
|
14
|
+
type?: 'text' | 'number' | 'currency' | 'date';
|
|
15
|
+
bold?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare class GenericTableDragAndDrop<T extends {
|
|
19
|
+
id: any;
|
|
20
|
+
}> {
|
|
21
|
+
data: _angular_core.InputSignal<T[]>;
|
|
22
|
+
columnsConfig: _angular_core.InputSignal<ColumnConfig[]>;
|
|
23
|
+
footData: _angular_core.InputSignal<Record<string, any>>;
|
|
24
|
+
actions: _angular_core.InputSignal<TableAction<T>[]>;
|
|
25
|
+
exportExcel: _angular_core.InputSignal<boolean>;
|
|
26
|
+
exportPdf: _angular_core.InputSignal<boolean>;
|
|
27
|
+
nameExport: _angular_core.InputSignal<string>;
|
|
28
|
+
pageSize: _angular_core.InputSignal<number>;
|
|
29
|
+
displayedColumns: _angular_core.WritableSignal<string[]>;
|
|
30
|
+
availableColumns: _angular_core.WritableSignal<string[]>;
|
|
31
|
+
globalFilter: _angular_core.WritableSignal<string>;
|
|
32
|
+
filters: _angular_core.WritableSignal<Record<string, string[]>>;
|
|
33
|
+
sortConfig: _angular_core.WritableSignal<{
|
|
34
|
+
column: string;
|
|
35
|
+
direction: "asc" | "desc" | null;
|
|
36
|
+
}>;
|
|
37
|
+
activeFilterColumn: _angular_core.WritableSignal<string>;
|
|
38
|
+
showModal: _angular_core.WritableSignal<boolean>;
|
|
39
|
+
currentPage: _angular_core.WritableSignal<number>;
|
|
40
|
+
constructor();
|
|
41
|
+
filteredData: _angular_core.Signal<T[]>;
|
|
42
|
+
uniqueValuesMap: _angular_core.Signal<Record<string, string[]>>;
|
|
43
|
+
pagedData: _angular_core.Signal<T[]>;
|
|
44
|
+
totalPages: _angular_core.Signal<number>;
|
|
45
|
+
pagesArray: _angular_core.Signal<(string | number)[]>;
|
|
46
|
+
hasFootData: _angular_core.Signal<boolean>;
|
|
47
|
+
getConfig(key: string): ColumnConfig | undefined;
|
|
48
|
+
drop(event: CdkDragDrop<string[]>): void;
|
|
49
|
+
toggleSort(col: string): void;
|
|
50
|
+
toggleFilter(column: string, value: string): void;
|
|
51
|
+
isAllSelected(column: string): boolean;
|
|
52
|
+
toggleAll(column: string): void;
|
|
53
|
+
exportToExcel(): void;
|
|
54
|
+
exportToPDF(): void;
|
|
55
|
+
resetAllFilters(): void;
|
|
56
|
+
goToPage(page: number | string): void;
|
|
57
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<GenericTableDragAndDrop<any>, never>;
|
|
58
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<GenericTableDragAndDrop<any>, "tbl-generic-drag-and-drop", never, { "data": { "alias": "data"; "required": true; "isSignal": true; }; "columnsConfig": { "alias": "columnsConfig"; "required": false; "isSignal": true; }; "footData": { "alias": "footData"; "required": false; "isSignal": true; }; "actions": { "alias": "actions"; "required": false; "isSignal": true; }; "exportExcel": { "alias": "exportExcel"; "required": false; "isSignal": true; }; "exportPdf": { "alias": "exportPdf"; "required": false; "isSignal": true; }; "nameExport": { "alias": "nameExport"; "required": false; "isSignal": true; }; "pageSize": { "alias": "pageSize"; "required": false; "isSignal": true; }; }, {}, never, ["[buttonsexport]"], true, never>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { GenericTableDragAndDrop };
|