referencias añadidas reparada forma de topologia
This commit is contained in:
@@ -1,965 +0,0 @@
|
|||||||
import 'package:cbluna_crm_lu/helpers/globals.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/content_manager/widget/edit_video_popup_neo.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/widgets/pluto_grid/pluto_grid_header.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:pluto_grid/pluto_grid.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/content_manager/widget/edit_video_popup.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/content_manager/widget/popup_detalle_video.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/content_manager/widget/popup_eliminar_video.dart';
|
|
||||||
import 'package:cbluna_crm_lu/pages/widgets/animated_hover_button.dart';
|
|
||||||
|
|
||||||
import '../../../providers/videos_provider.dart';
|
|
||||||
import '../../../theme/theme.dart';
|
|
||||||
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
import 'package:toggle_switch/toggle_switch.dart';
|
|
||||||
|
|
||||||
class AllVideoTable extends StatelessWidget {
|
|
||||||
const AllVideoTable({
|
|
||||||
Key? key,
|
|
||||||
required this.providerAd,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final VideosProvider providerAd;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Flexible(
|
|
||||||
child: PlutoGrid(
|
|
||||||
key: UniqueKey(),
|
|
||||||
configuration: PlutoGridConfiguration(
|
|
||||||
enableMoveDownAfterSelecting: true,
|
|
||||||
enableMoveHorizontalInEditing: true,
|
|
||||||
localeText: const PlutoGridLocaleText.spanish(),
|
|
||||||
scrollbar: plutoGridScrollbarConfig(context),
|
|
||||||
style: plutoGridStyleConfigContentManager(context, rowHeight: 150),
|
|
||||||
columnFilter: const PlutoGridColumnFilterConfig(
|
|
||||||
filters: [
|
|
||||||
...FilterHelper.defaultFilters,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
columns: [
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.numbers,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'ID',
|
|
||||||
),
|
|
||||||
title: 'ID',
|
|
||||||
field: 'video_id',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 100,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
cellPadding: const EdgeInsets.all(0),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return rendererContext.cell.row.cells['categories']!.value
|
|
||||||
.toString()
|
|
||||||
.replaceAll(RegExp(r'^\[|\]$'), '')
|
|
||||||
.replaceAll('", "', ', ')
|
|
||||||
.replaceAll('null', '')
|
|
||||||
.isEmpty
|
|
||||||
? Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
color: Colors.yellowAccent[400],
|
|
||||||
child: Center(
|
|
||||||
child: //icono warning
|
|
||||||
Icon(
|
|
||||||
Icons.warning,
|
|
||||||
color: AppTheme.of(context).tertiaryText,
|
|
||||||
size: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: Colors.yellowAccent[400],
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
rendererContext.cell.value.toString(),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
rendererContext.cell.value.toString(),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.play_arrow,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Video',
|
|
||||||
),
|
|
||||||
title: 'Video',
|
|
||||||
field: 'video_url',
|
|
||||||
width: 225,
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
try {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 250,
|
|
||||||
width: 100,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(20)),
|
|
||||||
child: Image.network(
|
|
||||||
rendererContext.row.cells['poster_path']!.value,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
)),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
),
|
|
||||||
child: AnimatedHoverButton(
|
|
||||||
icon: Icons.play_arrow,
|
|
||||||
tooltip: 'Iniciar',
|
|
||||||
size: 48,
|
|
||||||
primaryColor: AppTheme.of(context).primaryBackground,
|
|
||||||
secondaryColor: AppTheme.of(context).secondaryColor,
|
|
||||||
onTap: () async {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
content: PopupDetallesVideo(
|
|
||||||
tituloEncabezado: "Video actual",
|
|
||||||
url: rendererContext.cell.value.toString(),
|
|
||||||
titulo:
|
|
||||||
rendererContext.row.cells['title']!.value,
|
|
||||||
video: rendererContext.row.cells,
|
|
||||||
),
|
|
||||||
// Widget personalizado
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
return Container(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: const Text("--", textAlign: TextAlign.center));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.calendar_month,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Fecha de creación',
|
|
||||||
),
|
|
||||||
title: 'Created at',
|
|
||||||
field: 'created_at',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 150,
|
|
||||||
type: PlutoColumnType.date(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
enableAutoEditing: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
// Obtiene el valor de la fecha
|
|
||||||
String? fecha = rendererContext.row.cells['created_at']?.value;
|
|
||||||
|
|
||||||
// Uso de operador ternario para verificar si hay fecha y formatearla
|
|
||||||
String fechaFormateada = (fecha != null && fecha.isNotEmpty)
|
|
||||||
? DateFormat("dd 'de' MMMM 'de' yyyy", 'es_ES')
|
|
||||||
.format(DateTime.parse(fecha))
|
|
||||||
: '--';
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
width: 250,
|
|
||||||
child: Text(
|
|
||||||
fechaFormateada,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
maxLines: 3,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.check_circle,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Estado',
|
|
||||||
),
|
|
||||||
title: 'Estado',
|
|
||||||
field: 'video_status',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 200,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
//usa el tooltip para mostrar el estado del video
|
|
||||||
return MouseRegion(
|
|
||||||
cursor: SystemMouseCursors.click,
|
|
||||||
child: ToggleSwitch(
|
|
||||||
centerText: true,
|
|
||||||
minWidth: 90.0,
|
|
||||||
cornerRadius: 20.0,
|
|
||||||
fontSize: 14,
|
|
||||||
activeBgColor: [AppTheme.of(context).primaryColor],
|
|
||||||
activeFgColor: Colors.white,
|
|
||||||
inactiveBgColor:
|
|
||||||
AppTheme.of(context).primaryText.withOpacity(0.7),
|
|
||||||
inactiveFgColor: Colors.white,
|
|
||||||
activeBgColors: [
|
|
||||||
[AppTheme.of(context).primaryColor],
|
|
||||||
const [Colors.red]
|
|
||||||
],
|
|
||||||
borderWidth: 2.0,
|
|
||||||
borderColor: [
|
|
||||||
AppTheme.of(context).tertiaryText.withOpacity(0.7)
|
|
||||||
],
|
|
||||||
labels: const ['Activo', 'Inactivo'],
|
|
||||||
initialLabelIndex:
|
|
||||||
rendererContext.cell.value == true ? 0 : 1,
|
|
||||||
onToggle: (index) {
|
|
||||||
rendererContext.cell.row.cells['video_status']!.value =
|
|
||||||
index == 0
|
|
||||||
? true
|
|
||||||
: false; //cambia el valor en la celda
|
|
||||||
providerAd.cambiarEstadoVideo(
|
|
||||||
rendererContext.cell.row.cells['video_id']!.value,
|
|
||||||
index == 0 ? true : false);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.star,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Prioridad',
|
|
||||||
),
|
|
||||||
title: 'Priority',
|
|
||||||
field: 'priority',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 125,
|
|
||||||
type: PlutoColumnType.number(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return Container(
|
|
||||||
width: 100,
|
|
||||||
padding: const EdgeInsets.all(5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
color: rendererContext.row.cells['priority']!.value == 4
|
|
||||||
? const Color(0xFFD90D56).withOpacity(0.5)
|
|
||||||
: rendererContext.row.cells['priority']!.value == 3
|
|
||||||
? const Color(0xFFFFC700).withOpacity(0.5)
|
|
||||||
: rendererContext.row.cells['priority']!.value ==
|
|
||||||
2
|
|
||||||
? const Color(0xFF517EF2).withOpacity(0.5)
|
|
||||||
: const Color(0x5A0E2152)),
|
|
||||||
child: Text(
|
|
||||||
rendererContext.row.cells['priority']!.value == 4
|
|
||||||
? 'alta'
|
|
||||||
: rendererContext.row.cells['priority']!.value == 3
|
|
||||||
? 'media'
|
|
||||||
: rendererContext.row.cells['priority']!.value == 2
|
|
||||||
? 'baja'
|
|
||||||
: 'neutra',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.title,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Titulo',
|
|
||||||
),
|
|
||||||
title: 'Title',
|
|
||||||
field: 'title',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 325,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
enableAutoEditing: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return SizedBox(
|
|
||||||
width: 150,
|
|
||||||
child: Text(
|
|
||||||
rendererContext.row.cells['title']!.value ?? '--',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
maxLines: 3,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.description,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Descripción',
|
|
||||||
),
|
|
||||||
title: 'Descripción',
|
|
||||||
field: 'overview',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 350,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
enableAutoEditing: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return providerAd.showWarningsOnTable == true
|
|
||||||
? Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: rendererContext.cell.value.isEmpty
|
|
||||||
? Colors.yellowAccent[400]
|
|
||||||
: Colors.transparent,
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
rendererContext.cell.value.isEmpty
|
|
||||||
? 'NO DESCRIPTION'
|
|
||||||
: rendererContext.cell.value,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: rendererContext.cell.value.isEmpty
|
|
||||||
? AppTheme.of(context).tertiaryText
|
|
||||||
: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: rendererContext.cell.value.isEmpty
|
|
||||||
? 18
|
|
||||||
: 14,
|
|
||||||
fontWeight: rendererContext.cell.value.isEmpty
|
|
||||||
? FontWeight.w800
|
|
||||||
: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: Text(
|
|
||||||
rendererContext.row.cells['overview']!.value,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
maxLines: 4,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.qr_code_2_rounded,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'QRs generados',
|
|
||||||
),
|
|
||||||
title: 'QRs generados',
|
|
||||||
field: 'qr_codes',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 150,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
final qrCodes = rendererContext.row.cells['qr_codes']?.value;
|
|
||||||
|
|
||||||
// Verifica que qrCodes no esté vacío antes de mostrar el botón
|
|
||||||
if (qrCodes != null && qrCodes.isNotEmpty) {
|
|
||||||
return Center(
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
icon: Icon(Icons.list_alt_rounded, size: 18),
|
|
||||||
label: Text(
|
|
||||||
'Ver QRs',
|
|
||||||
style: TextStyle(fontSize: 13),
|
|
||||||
),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12, vertical: 6),
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => AlertDialog(
|
|
||||||
backgroundColor:
|
|
||||||
AppTheme.of(context).primaryBackground,
|
|
||||||
title: const Text('Lista de QRs'),
|
|
||||||
content: SizedBox(
|
|
||||||
width: 400,
|
|
||||||
height: 300,
|
|
||||||
child: ListView.builder(
|
|
||||||
itemCount: qrCodes
|
|
||||||
.split('\n')
|
|
||||||
.length, // Divide los QR Codes concatenados
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
try {
|
|
||||||
final qrData = qrCodes.split(
|
|
||||||
'\n')[index]; // Obtiene el QR individual
|
|
||||||
return Padding(
|
|
||||||
padding:
|
|
||||||
const EdgeInsets.symmetric(vertical: 4),
|
|
||||||
child: Text(
|
|
||||||
qrData,
|
|
||||||
style: const TextStyle(fontSize: 14),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
return Text(
|
|
||||||
'Error al leer QR: $e',
|
|
||||||
style: const TextStyle(color: Colors.red),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('Cerrar'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return Center(
|
|
||||||
child: Text(
|
|
||||||
'GLOBAL',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w900,
|
|
||||||
),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.link,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Enlace',
|
|
||||||
),
|
|
||||||
title: 'OutLink',
|
|
||||||
field: 'url_ad',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 100,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
String? url = rendererContext.row.cells['url_ad']?.value;
|
|
||||||
bool isValidUrl = url != null && url != 'null' && url.isNotEmpty;
|
|
||||||
return providerAd.showWarningsOnTable == true
|
|
||||||
? Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
color: isValidUrl
|
|
||||||
? Colors.transparent
|
|
||||||
: Colors.yellowAccent[400],
|
|
||||||
child: IconButton(
|
|
||||||
onPressed: () async {
|
|
||||||
if (isValidUrl) {
|
|
||||||
String finalUrl =
|
|
||||||
url!.startsWith(RegExp(r'http://|https://'))
|
|
||||||
? url
|
|
||||||
: 'http://$url';
|
|
||||||
if (await canLaunchUrl(Uri.parse(finalUrl))) {
|
|
||||||
await launchUrl(Uri.parse(finalUrl));
|
|
||||||
} else {
|
|
||||||
print('No se puede abrir el enlace');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print('No se puede abrir el enlace');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
isValidUrl ? Icons.link : Icons.link_off,
|
|
||||||
color: isValidUrl
|
|
||||||
? AppTheme.of(context).primaryColor
|
|
||||||
: AppTheme.of(context).tertiaryText,
|
|
||||||
semanticLabel:
|
|
||||||
isValidUrl ? 'Open link' : 'No link',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!isValidUrl)
|
|
||||||
const Text('No link added',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16, fontWeight: FontWeight.w800)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: IconButton(
|
|
||||||
onPressed: () async {
|
|
||||||
if (isValidUrl) {
|
|
||||||
// Asegurarse de que 'url' comience con 'http://' o 'https://'
|
|
||||||
String finalUrl =
|
|
||||||
url!.startsWith(RegExp(r'http://|https://'))
|
|
||||||
? url
|
|
||||||
: 'http://$url';
|
|
||||||
if (await canLaunchUrl(Uri.parse(finalUrl))) {
|
|
||||||
await launchUrl(Uri.parse(finalUrl));
|
|
||||||
} else {
|
|
||||||
print('No se puede abrir el enlace');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print('No se puede abrir el enlace');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
// Usar 'isValidUrl' para determinar el ícono a mostrar.
|
|
||||||
isValidUrl ? Icons.link : Icons.link_off,
|
|
||||||
color: AppTheme.of(context).primaryColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.category,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Categoría de video',
|
|
||||||
),
|
|
||||||
title: 'Categoría',
|
|
||||||
field: 'categories',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 200,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
var textoLimpio = rendererContext.cell.value
|
|
||||||
.toString()
|
|
||||||
.replaceAll(RegExp(r'^\[|\]$'), '')
|
|
||||||
.replaceAll('", "', ', ')
|
|
||||||
.replaceAll('null', '');
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: textoLimpio.isEmpty
|
|
||||||
? Colors.yellowAccent[400]
|
|
||||||
: Colors.transparent,
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
textoLimpio.isEmpty ? 'NO CATEGORIES' : textoLimpio,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: textoLimpio.isEmpty
|
|
||||||
? AppTheme.of(context).tertiaryText
|
|
||||||
: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: textoLimpio.isEmpty ? 18 : 16,
|
|
||||||
fontWeight: textoLimpio.isEmpty
|
|
||||||
? FontWeight.w800
|
|
||||||
: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.person,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Patrocinador',
|
|
||||||
),
|
|
||||||
title: 'Partner',
|
|
||||||
field: 'partner',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 150,
|
|
||||||
type: PlutoColumnType.text(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return providerAd.showWarningsOnTable == true
|
|
||||||
? Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
color: rendererContext.cell.value.isEmpty
|
|
||||||
? Colors.yellowAccent[400]
|
|
||||||
: Colors.transparent,
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
rendererContext.cell.value.isEmpty
|
|
||||||
? 'NO PARTNER'
|
|
||||||
: rendererContext.cell.value,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: rendererContext.cell.value.isEmpty
|
|
||||||
? AppTheme.of(context).tertiaryText
|
|
||||||
: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: rendererContext.cell.value.isEmpty
|
|
||||||
? 18
|
|
||||||
: 16,
|
|
||||||
fontWeight: rendererContext.cell.value.isEmpty
|
|
||||||
? FontWeight.w800
|
|
||||||
: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: SizedBox(
|
|
||||||
width: 200,
|
|
||||||
child: Text(
|
|
||||||
rendererContext.row.cells['partner']!.value ?? '--',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
maxLines: 4,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
/* PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.calendar_today,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Fecha expiración',
|
|
||||||
),
|
|
||||||
title: 'Exp. date',
|
|
||||||
field: 'expirationDate',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 180,
|
|
||||||
type: PlutoColumnType.date(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
), */
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.timelapse,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Duración',
|
|
||||||
),
|
|
||||||
title: 'Duration',
|
|
||||||
field: 'duration_video',
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
width: 130,
|
|
||||||
type: PlutoColumnType.number(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
int durationInSeconds = rendererContext.cell.value;
|
|
||||||
String minutes =
|
|
||||||
(durationInSeconds ~/ 60).toString().padLeft(2, '0');
|
|
||||||
String seconds =
|
|
||||||
(durationInSeconds % 60).toString().padLeft(2, '0');
|
|
||||||
return Text(
|
|
||||||
'$minutes:$seconds',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryText,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.edit,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Editar',
|
|
||||||
),
|
|
||||||
title: 'Edit',
|
|
||||||
field: 'editar',
|
|
||||||
width: 100,
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
type: PlutoColumnType.number(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: AnimatedHoverButton(
|
|
||||||
icon: Icons.edit,
|
|
||||||
tooltip: 'Edit',
|
|
||||||
primaryColor: AppTheme.of(context).primaryBackground,
|
|
||||||
secondaryColor: AppTheme.of(context).primaryColor,
|
|
||||||
onTap: () async {
|
|
||||||
providerAd.resetAllvideoData();
|
|
||||||
final List<String> qrsAsociados =
|
|
||||||
await providerAd.getQrsByVideoId(rendererContext
|
|
||||||
.cell.row.cells['video_id']!.value);
|
|
||||||
|
|
||||||
providerAd.listaQrsSeleccionados = qrsAsociados;
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
providerAd.selectedVideoId = rendererContext
|
|
||||||
.cell.row.cells['video_id']!.value;
|
|
||||||
|
|
||||||
providerAd.tituloVideo = rendererContext
|
|
||||||
.cell.row.cells['title']!.value;
|
|
||||||
|
|
||||||
providerAd.videoPoints = rendererContext
|
|
||||||
.cell.row.cells['points']!.value;
|
|
||||||
|
|
||||||
providerAd.videoName = rendererContext
|
|
||||||
.cell.row.cells['title']!.value;
|
|
||||||
|
|
||||||
providerAd.videoPatner = rendererContext
|
|
||||||
.cell.row.cells['partner']!.value;
|
|
||||||
|
|
||||||
providerAd.descripcionVideo = rendererContext
|
|
||||||
.cell.row.cells['overview']!.value;
|
|
||||||
|
|
||||||
providerAd.videoOutlink = rendererContext
|
|
||||||
.cell.row.cells['url_ad']!.value;
|
|
||||||
//video_poster_file
|
|
||||||
providerAd.videoCoverFile = rendererContext
|
|
||||||
.cell.row.cells['poster_file_name']!.value;
|
|
||||||
|
|
||||||
providerAd.videoCoverFileNameNoModif =
|
|
||||||
rendererContext.cell.row
|
|
||||||
.cells['poster_file_name']!.value;
|
|
||||||
|
|
||||||
providerAd.selectePriority = rendererContext
|
|
||||||
.row.cells['priority']!.value ==
|
|
||||||
4
|
|
||||||
? 'alta'
|
|
||||||
: rendererContext
|
|
||||||
.row.cells['priority']!.value ==
|
|
||||||
3
|
|
||||||
? 'media'
|
|
||||||
: rendererContext.row.cells['priority']!
|
|
||||||
.value ==
|
|
||||||
2
|
|
||||||
? 'baja'
|
|
||||||
: 'neutra';
|
|
||||||
|
|
||||||
providerAd.videoPath = rendererContext
|
|
||||||
.cell.row.cells['video_url']!.value;
|
|
||||||
|
|
||||||
providerAd.videoPosterPath = rendererContext
|
|
||||||
.cell.row.cells['poster_path']!.value;
|
|
||||||
|
|
||||||
return AlertDialog(
|
|
||||||
backgroundColor:
|
|
||||||
AppTheme.of(context).primaryBackground,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(50),
|
|
||||||
),
|
|
||||||
content: PopupEditVideoNeo(
|
|
||||||
provider: providerAd,
|
|
||||||
editMode: true,
|
|
||||||
currentCategories: rendererContext
|
|
||||||
.cell.row.cells['categories']!.value,
|
|
||||||
));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
PlutoColumn(
|
|
||||||
titleSpan: plutoGridHeader(
|
|
||||||
context: context,
|
|
||||||
icono: Icons.delete,
|
|
||||||
color: AppTheme.of(context).primaryBackground,
|
|
||||||
texto: 'Eliminar',
|
|
||||||
),
|
|
||||||
title: 'Delete',
|
|
||||||
field: 'eliminar',
|
|
||||||
width: 100,
|
|
||||||
titleTextAlign: PlutoColumnTextAlign.center,
|
|
||||||
textAlign: PlutoColumnTextAlign.center,
|
|
||||||
type: PlutoColumnType.number(),
|
|
||||||
enableEditingMode: false,
|
|
||||||
backgroundColor: AppTheme.of(context).primaryColor,
|
|
||||||
enableContextMenu: false,
|
|
||||||
enableDropToResize: false,
|
|
||||||
renderer: (rendererContext) {
|
|
||||||
return Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: AnimatedHoverButton(
|
|
||||||
icon: Icons.delete,
|
|
||||||
tooltip: 'Delete this video',
|
|
||||||
primaryColor: AppTheme.of(context).primaryBackground,
|
|
||||||
secondaryColor: Colors.redAccent,
|
|
||||||
onTap: () async {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return EliminarVideoPopup(
|
|
||||||
idVideo: rendererContext
|
|
||||||
.cell.row.cells['video_id']!.value,
|
|
||||||
nombreVideo: rendererContext
|
|
||||||
.cell.row.cells['title']!.value,
|
|
||||||
videoFileName: rendererContext
|
|
||||||
.cell.row.cells['video_file_name']!.value,
|
|
||||||
posterFileName: rendererContext
|
|
||||||
.cell.row.cells['poster_file_name']!.value,
|
|
||||||
videoUrl: rendererContext
|
|
||||||
.cell.row.cells['video_url']!.value,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
rows: providerAd.allVideoRows,
|
|
||||||
onLoaded: (event) async {
|
|
||||||
providerAd.listStateManager.add(event.stateManager);
|
|
||||||
},
|
|
||||||
createFooter: (stateManager) {
|
|
||||||
stateManager.setPageSize(10, notify: false); // default 40
|
|
||||||
|
|
||||||
return PlutoPagination(stateManager);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BIN
assets/referencia/categoria_componente.png
Normal file
BIN
assets/referencia/categoria_componente.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
92
assets/referencia/fn_topologia_por_negocio.txt
Normal file
92
assets/referencia/fn_topologia_por_negocio.txt
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION nethive.fn_topologia_por_negocio(p_negocio_id uuid)
|
||||||
|
RETURNS jsonb
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN (
|
||||||
|
SELECT jsonb_build_object(
|
||||||
|
'componentes', (
|
||||||
|
SELECT jsonb_agg(row_to_json(c))
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
comp.id,
|
||||||
|
comp.nombre,
|
||||||
|
comp.categoria_id,
|
||||||
|
cat.nombre AS categoria,
|
||||||
|
comp.rol_logico_id,
|
||||||
|
r.nombre AS rol_logico,
|
||||||
|
comp.descripcion,
|
||||||
|
comp.ubicacion,
|
||||||
|
comp.imagen_url,
|
||||||
|
comp.en_uso,
|
||||||
|
comp.activo,
|
||||||
|
comp.fecha_registro,
|
||||||
|
comp.distribucion_id,
|
||||||
|
td.nombre AS tipo_distribucion,
|
||||||
|
d.nombre AS nombre_distribucion
|
||||||
|
FROM nethive.componente comp
|
||||||
|
LEFT JOIN nethive.categoria_componente cat ON comp.categoria_id = cat.id
|
||||||
|
LEFT JOIN nethive.rol_logico_componente r ON comp.rol_logico_id = r.id
|
||||||
|
LEFT JOIN nethive.distribucion d ON comp.distribucion_id = d.id
|
||||||
|
LEFT JOIN nethive.tipo_distribucion td ON d.tipo_id = td.id
|
||||||
|
WHERE comp.negocio_id = p_negocio_id
|
||||||
|
) AS c
|
||||||
|
),
|
||||||
|
|
||||||
|
'conexiones_datos', (
|
||||||
|
SELECT jsonb_agg(row_to_json(cd))
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
cc.id,
|
||||||
|
cc.componente_origen_id,
|
||||||
|
co.nombre AS nombre_origen,
|
||||||
|
ro.id AS rol_logico_origen_id,
|
||||||
|
ro.nombre AS rol_logico_origen,
|
||||||
|
cc.componente_destino_id,
|
||||||
|
cd.nombre AS nombre_destino,
|
||||||
|
rd.id AS rol_logico_destino_id,
|
||||||
|
rd.nombre AS rol_logico_destino,
|
||||||
|
cc.cable_id,
|
||||||
|
cb.nombre AS nombre_cable,
|
||||||
|
cc.descripcion,
|
||||||
|
cc.activo
|
||||||
|
FROM nethive.conexion_componente cc
|
||||||
|
LEFT JOIN nethive.componente co ON cc.componente_origen_id = co.id
|
||||||
|
LEFT JOIN nethive.rol_logico_componente ro ON co.rol_logico_id = ro.id
|
||||||
|
LEFT JOIN nethive.componente cd ON cc.componente_destino_id = cd.id
|
||||||
|
LEFT JOIN nethive.rol_logico_componente rd ON cd.rol_logico_id = rd.id
|
||||||
|
LEFT JOIN nethive.componente cb ON cc.cable_id = cb.id
|
||||||
|
WHERE co.negocio_id = p_negocio_id OR cd.negocio_id = p_negocio_id
|
||||||
|
) AS cd
|
||||||
|
),
|
||||||
|
|
||||||
|
'conexiones_energia', (
|
||||||
|
SELECT jsonb_agg(row_to_json(ce))
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
ca.id,
|
||||||
|
ca.origen_id,
|
||||||
|
co.nombre AS nombre_origen,
|
||||||
|
ro.id AS rol_logico_origen_id,
|
||||||
|
ro.nombre AS rol_logico_origen,
|
||||||
|
ca.destino_id,
|
||||||
|
cd.nombre AS nombre_destino,
|
||||||
|
rd.id AS rol_logico_destino_id,
|
||||||
|
rd.nombre AS rol_logico_destino,
|
||||||
|
ca.cable_id,
|
||||||
|
cb.nombre AS nombre_cable,
|
||||||
|
ca.descripcion,
|
||||||
|
ca.activo
|
||||||
|
FROM nethive.conexion_alimentacion ca
|
||||||
|
LEFT JOIN nethive.componente co ON ca.origen_id = co.id
|
||||||
|
LEFT JOIN nethive.rol_logico_componente ro ON co.rol_logico_id = ro.id
|
||||||
|
LEFT JOIN nethive.componente cd ON ca.destino_id = cd.id
|
||||||
|
LEFT JOIN nethive.rol_logico_componente rd ON cd.rol_logico_id = rd.id
|
||||||
|
LEFT JOIN nethive.componente cb ON ca.cable_id = cb.id
|
||||||
|
WHERE co.negocio_id = p_negocio_id OR cd.negocio_id = p_negocio_id
|
||||||
|
) AS ce
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
|
|
||||||
# 📘 Estructura de Base de Datos — NETHIVE (Esquema: `nethive`)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏢 `empresa`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|-----------------|----------------|-----------------------------------|
|
|
||||||
| id | UUID | PRIMARY KEY |
|
|
||||||
| nombre | TEXT | Nombre de la empresa |
|
|
||||||
| rfc | TEXT | Registro fiscal |
|
|
||||||
| direccion | TEXT | Dirección |
|
|
||||||
| telefono | TEXT | Teléfono de contacto |
|
|
||||||
| email | TEXT | Correo electrónico |
|
|
||||||
| fecha_creacion | TIMESTAMP | Fecha de creación (default: now) |
|
|
||||||
| logo_url | TEXT | URL del logo |
|
|
||||||
| imagen_url | TEXT | URL de imagen principal |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏪 `negocio`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|-----------------|----------------|-----------------------------------|
|
|
||||||
| id | UUID | PRIMARY KEY |
|
|
||||||
| empresa_id | UUID | FK → empresa.id |
|
|
||||||
| nombre | TEXT | Nombre del negocio |
|
|
||||||
| direccion | TEXT | Dirección |
|
|
||||||
| latitud | DECIMAL(9,6) | Latitud geográfica |
|
|
||||||
| longitud | DECIMAL(9,6) | Longitud geográfica |
|
|
||||||
| tipo_local | TEXT | Tipo de local (Sucursal, etc.) |
|
|
||||||
| fecha_creacion | TIMESTAMP | Default: now() |
|
|
||||||
| logo_url | TEXT | Logo del negocio |
|
|
||||||
| imagen_url | TEXT | Imagen del negocio |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧾 `categoria_componente`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|---------|--------------|--------------------------|
|
|
||||||
| id | SERIAL | PRIMARY KEY |
|
|
||||||
| nombre | TEXT | Nombre único de categoría|
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📦 `componente`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|-----------------|----------------|------------------------------------|
|
|
||||||
| id | UUID | PRIMARY KEY |
|
|
||||||
| negocio_id | UUID | FK → negocio.id |
|
|
||||||
| categoria_id | INT | FK → categoria_componente.id |
|
|
||||||
| nombre | TEXT | Nombre del componente |
|
|
||||||
| descripcion | TEXT | Descripción general |
|
|
||||||
| en_uso | BOOLEAN | Si está en uso |
|
|
||||||
| activo | BOOLEAN | Si está activo |
|
|
||||||
| ubicacion | TEXT | Ubicación física (rack, bandeja) |
|
|
||||||
| imagen_url | TEXT | URL de imagen |
|
|
||||||
| fecha_registro | TIMESTAMP | Default: now() |
|
|
||||||
| distribucion_id | UUID | FK → distribucion.id |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔌 `detalle_cable`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|----------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo_cable | TEXT |
|
|
||||||
| color | TEXT |
|
|
||||||
| tamaño | DECIMAL(5,2) |
|
|
||||||
| tipo_conector | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📶 `detalle_switch`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|----------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| marca | TEXT |
|
|
||||||
| modelo | TEXT |
|
|
||||||
| numero_serie | TEXT |
|
|
||||||
| administrable | BOOLEAN |
|
|
||||||
| poe | BOOLEAN |
|
|
||||||
| cantidad_puertos | INT |
|
|
||||||
| velocidad_puertos | TEXT |
|
|
||||||
| tipo_puertos | TEXT |
|
|
||||||
| ubicacion_en_rack | TEXT |
|
|
||||||
| direccion_ip | TEXT |
|
|
||||||
| firmware | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧱 `detalle_patch_panel`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|---------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo_conector | TEXT |
|
|
||||||
| numero_puertos | INT |
|
|
||||||
| categoria | TEXT |
|
|
||||||
| tipo_montaje | TEXT |
|
|
||||||
| numeracion_frontal | BOOLEAN |
|
|
||||||
| panel_ciego | BOOLEAN |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🗄 `detalle_rack`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|------------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo | TEXT |
|
|
||||||
| altura_u | INT |
|
|
||||||
| profundidad_cm | INT |
|
|
||||||
| ancho_cm | INT |
|
|
||||||
| ventilacion_integrada | BOOLEAN |
|
|
||||||
| puertas_con_llave | BOOLEAN |
|
|
||||||
| ruedas | BOOLEAN |
|
|
||||||
| color | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧰 `detalle_organizador`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|--------------|----------------|
|
|
||||||
| componente_id| UUID (PK, FK) |
|
|
||||||
| tipo | TEXT |
|
|
||||||
| material | TEXT |
|
|
||||||
| tamaño | TEXT |
|
|
||||||
| color | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚡ `detalle_ups`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|--------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo | TEXT |
|
|
||||||
| marca | TEXT |
|
|
||||||
| modelo | TEXT |
|
|
||||||
| voltaje_entrada | TEXT |
|
|
||||||
| voltaje_salida | TEXT |
|
|
||||||
| capacidad_va | INT |
|
|
||||||
| autonomia_minutos | INT |
|
|
||||||
| cantidad_tomas | INT |
|
|
||||||
| rackeable | BOOLEAN |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔐 `detalle_router_firewall`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|--------------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo | TEXT |
|
|
||||||
| marca | TEXT |
|
|
||||||
| modelo | TEXT |
|
|
||||||
| numero_serie | TEXT |
|
|
||||||
| interfaces | TEXT |
|
|
||||||
| capacidad_routing_gbps | DECIMAL(5,2) |
|
|
||||||
| direccion_ip | TEXT |
|
|
||||||
| firmware | TEXT |
|
|
||||||
| licencias | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧿 `detalle_equipo_activo`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato |
|
|
||||||
|-------------------|----------------|
|
|
||||||
| componente_id | UUID (PK, FK) |
|
|
||||||
| tipo | TEXT |
|
|
||||||
| marca | TEXT |
|
|
||||||
| modelo | TEXT |
|
|
||||||
| numero_serie | TEXT |
|
|
||||||
| especificaciones | TEXT |
|
|
||||||
| direccion_ip | TEXT |
|
|
||||||
| firmware | TEXT |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧭 `distribucion`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|--------------|----------------|--------------------------------------|
|
|
||||||
| id | UUID | PRIMARY KEY |
|
|
||||||
| negocio_id | UUID | FK → negocio.id |
|
|
||||||
| tipo | TEXT | 'MDF' o 'IDF' |
|
|
||||||
| nombre | TEXT | Nombre de la ubicación lógica |
|
|
||||||
| descripcion | TEXT | Detalles adicionales (opcional) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔗 `conexion_componente`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|-----------------------|----------------|------------------------------------------|
|
|
||||||
| id | UUID | PRIMARY KEY |
|
|
||||||
| componente_origen_id | UUID | FK → componente.id |
|
|
||||||
| componente_destino_id | UUID | FK → componente.id |
|
|
||||||
| descripcion | TEXT | Descripción de la conexión (opcional) |
|
|
||||||
| activo | BOOLEAN | Si la conexión está activa |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 👁️ `vista_negocios_con_coordenadas`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|--------------------|--------------|--------------------------------------------|
|
|
||||||
| negocio_id | UUID | ID del negocio |
|
|
||||||
| nombre_negocio | TEXT | Nombre del negocio |
|
|
||||||
| latitud | DECIMAL | Latitud del negocio |
|
|
||||||
| longitud | DECIMAL | Longitud del negocio |
|
|
||||||
| logo_negocio | TEXT | URL del logo del negocio |
|
|
||||||
| imagen_negocio | TEXT | URL de la imagen del negocio |
|
|
||||||
| empresa_id | UUID | ID de la empresa |
|
|
||||||
| nombre_empresa | TEXT | Nombre de la empresa |
|
|
||||||
| logo_empresa | TEXT | URL del logo de la empresa |
|
|
||||||
| imagen_empresa | TEXT | URL de la imagen de la empresa |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 `vista_inventario_por_negocio`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|--------------------|--------------|---------------------------------------------|
|
|
||||||
| componente_id | UUID | ID del componente |
|
|
||||||
| nombre_componente | TEXT | Nombre del componente |
|
|
||||||
| categoria | TEXT | Categoría del componente |
|
|
||||||
| en_uso | BOOLEAN | Si está en uso |
|
|
||||||
| activo | BOOLEAN | Si está activo |
|
|
||||||
| ubicacion | TEXT | Ubicación física del componente |
|
|
||||||
| imagen_componente | TEXT | Imagen asociada al componente |
|
|
||||||
| negocio_id | UUID | ID del negocio |
|
|
||||||
| nombre_negocio | TEXT | Nombre del negocio |
|
|
||||||
| logo_negocio | TEXT | Logo del negocio |
|
|
||||||
| imagen_negocio | TEXT | Imagen del negocio |
|
|
||||||
| empresa_id | UUID | ID de la empresa |
|
|
||||||
| nombre_empresa | TEXT | Nombre de la empresa |
|
|
||||||
| logo_empresa | TEXT | Logo de la empresa |
|
|
||||||
| imagen_empresa | TEXT | Imagen de la empresa |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧵 `vista_detalle_cables`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|--------------------|--------------|--------------------------------------------|
|
|
||||||
| componente_id | UUID | ID del componente |
|
|
||||||
| nombre | TEXT | Nombre del cable |
|
|
||||||
| tipo_cable | TEXT | Tipo de cable (UTP, fibra, etc.) |
|
|
||||||
| color | TEXT | Color del cable |
|
|
||||||
| tamaño | DECIMAL | Longitud del cable |
|
|
||||||
| tipo_conector | TEXT | Tipo de conector (RJ45, LC, etc.) |
|
|
||||||
| en_uso | BOOLEAN | Si está en uso |
|
|
||||||
| activo | BOOLEAN | Si está activo |
|
|
||||||
| ubicacion | TEXT | Ubicación física |
|
|
||||||
| imagen_componente | TEXT | Imagen del cable |
|
|
||||||
| nombre_negocio | TEXT | Nombre del negocio |
|
|
||||||
| logo_negocio | TEXT | Logo del negocio |
|
|
||||||
| nombre_empresa | TEXT | Nombre de la empresa |
|
|
||||||
| logo_empresa | TEXT | Logo de la empresa |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 `vista_resumen_componentes_activos`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|------------------|--------------|----------------------------------------------|
|
|
||||||
| nombre_empresa | TEXT | Nombre de la empresa |
|
|
||||||
| nombre_negocio | TEXT | Nombre del negocio |
|
|
||||||
| categoria | TEXT | Categoría del componente |
|
|
||||||
| cantidad_activos | INTEGER | Cantidad total de componentes activos |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔌 `vista_conexiones_por_negocio`
|
|
||||||
|
|
||||||
| Columna | Tipo de dato | Descripción |
|
|
||||||
|-----------------------|--------------|------------------------------------------|
|
|
||||||
| id | UUID | ID de la conexión |
|
|
||||||
| componente_origen_id | UUID | Componente origen |
|
|
||||||
| componente_destino_id | UUID | Componente destino |
|
|
||||||
| descripcion | TEXT | Descripción de la conexión |
|
|
||||||
| activo | BOOLEAN | Si la conexión está activa |
|
|
||||||
"""
|
|
||||||
BIN
assets/referencia/rol_logico_componente.png
Normal file
BIN
assets/referencia/rol_logico_componente.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
@@ -161,6 +161,25 @@ tipo (text),
|
|||||||
nombre (text),
|
nombre (text),
|
||||||
descripcion (text),
|
descripcion (text),
|
||||||
|
|
||||||
|
-- conexion_alimentacion --
|
||||||
|
|
||||||
|
id (uuid) (PK),
|
||||||
|
origen_id (uuid) (FK de nethive.componente.id),
|
||||||
|
destino_id (uuid) (FK de nethive.componente.id),
|
||||||
|
cable_id (uuid) (FK de nethive.componente.id, opcional),
|
||||||
|
descripcion (text),
|
||||||
|
activo (bool)
|
||||||
|
|
||||||
|
-- rol_logico_componente --
|
||||||
|
|
||||||
|
id (serial) (PK),
|
||||||
|
nombre (text),
|
||||||
|
descripcion (text)
|
||||||
|
|
||||||
|
|
||||||
|
-- tipo_distribucion --
|
||||||
|
id (serial) (PK),
|
||||||
|
nombre (text)
|
||||||
|
|
||||||
******* VISTAS: *******
|
******* VISTAS: *******
|
||||||
|
|
||||||
@@ -174,7 +193,7 @@ tamaño (numeric),
|
|||||||
tipo_conector (text),
|
tipo_conector (text),
|
||||||
conexion_id (uuid),
|
conexion_id (uuid),
|
||||||
|
|
||||||
-- vista_conexiones_por_cables --
|
-- vista_conexiones_con_cables --
|
||||||
|
|
||||||
conexion_id (uuid),
|
conexion_id (uuid),
|
||||||
descripcion (text),
|
descripcion (text),
|
||||||
@@ -275,3 +294,21 @@ ubicacion (text),
|
|||||||
imagen_url (text),
|
imagen_url (text),
|
||||||
fecha_registro (timestamp),
|
fecha_registro (timestamp),
|
||||||
|
|
||||||
|
-- vista_alimentacion_componentes --
|
||||||
|
|
||||||
|
id (uuid),
|
||||||
|
origen_id (uuid),
|
||||||
|
nombre_origen (text),
|
||||||
|
categoria_origen (int4),
|
||||||
|
|
||||||
|
destino_id (uuid),
|
||||||
|
nombre_destino (text),
|
||||||
|
categoria_destino (int4),
|
||||||
|
|
||||||
|
cable_id (uuid),
|
||||||
|
nombre_cable (text),
|
||||||
|
categoria_cable (int4),
|
||||||
|
|
||||||
|
descripcion (text),
|
||||||
|
activo (bool)
|
||||||
|
|
||||||
|
|||||||
BIN
assets/referencia/tipo_distribucion.png
Normal file
BIN
assets/referencia/tipo_distribucion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,8 @@ class Componente {
|
|||||||
final String? ubicacion;
|
final String? ubicacion;
|
||||||
final String? imagenUrl;
|
final String? imagenUrl;
|
||||||
final DateTime fechaRegistro;
|
final DateTime fechaRegistro;
|
||||||
|
final String? distribucionId; // ← Nuevo (si lo usas)
|
||||||
|
final String? rolLogicoId; // ← NUEVO
|
||||||
|
|
||||||
Componente({
|
Componente({
|
||||||
required this.id,
|
required this.id,
|
||||||
@@ -23,7 +25,8 @@ class Componente {
|
|||||||
this.ubicacion,
|
this.ubicacion,
|
||||||
this.imagenUrl,
|
this.imagenUrl,
|
||||||
required this.fechaRegistro,
|
required this.fechaRegistro,
|
||||||
String? distribucionId,
|
this.distribucionId,
|
||||||
|
this.rolLogicoId,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Componente.fromMap(Map<String, dynamic> map) {
|
factory Componente.fromMap(Map<String, dynamic> map) {
|
||||||
@@ -38,6 +41,8 @@ class Componente {
|
|||||||
ubicacion: map['ubicacion'],
|
ubicacion: map['ubicacion'],
|
||||||
imagenUrl: map['imagen_url'],
|
imagenUrl: map['imagen_url'],
|
||||||
fechaRegistro: DateTime.parse(map['fecha_registro']),
|
fechaRegistro: DateTime.parse(map['fecha_registro']),
|
||||||
|
distribucionId: map['distribucion_id'],
|
||||||
|
rolLogicoId: map['rol_logico_id'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,10 +58,13 @@ class Componente {
|
|||||||
'ubicacion': ubicacion,
|
'ubicacion': ubicacion,
|
||||||
'imagen_url': imagenUrl,
|
'imagen_url': imagenUrl,
|
||||||
'fecha_registro': fechaRegistro.toIso8601String(),
|
'fecha_registro': fechaRegistro.toIso8601String(),
|
||||||
|
'distribucion_id': distribucionId,
|
||||||
|
'rol_logico_id': rolLogicoId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
factory Componente.fromJson(String source) =>
|
factory Componente.fromJson(String source) =>
|
||||||
Componente.fromMap(json.decode(source));
|
Componente.fromMap(json.decode(source));
|
||||||
|
|
||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
}
|
}
|
||||||
|
|||||||
39
lib/models/nethive/conexion_alimentacion_model.dart
Normal file
39
lib/models/nethive/conexion_alimentacion_model.dart
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
class ConexionAlimentacion {
|
||||||
|
final String id;
|
||||||
|
final String origenId;
|
||||||
|
final String destinoId;
|
||||||
|
final String? cableId;
|
||||||
|
final String? descripcion;
|
||||||
|
final bool activo;
|
||||||
|
|
||||||
|
ConexionAlimentacion({
|
||||||
|
required this.id,
|
||||||
|
required this.origenId,
|
||||||
|
required this.destinoId,
|
||||||
|
this.cableId,
|
||||||
|
this.descripcion,
|
||||||
|
required this.activo,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ConexionAlimentacion.fromMap(Map<String, dynamic> map) {
|
||||||
|
return ConexionAlimentacion(
|
||||||
|
id: map['id'] ?? '',
|
||||||
|
origenId: map['origen_id'] ?? '',
|
||||||
|
destinoId: map['destino_id'] ?? '',
|
||||||
|
cableId: map['cable_id'],
|
||||||
|
descripcion: map['descripcion'],
|
||||||
|
activo: map['activo'] ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'origen_id': origenId,
|
||||||
|
'destino_id': destinoId,
|
||||||
|
'cable_id': cableId,
|
||||||
|
'descripcion': descripcion,
|
||||||
|
'activo': activo,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
58
lib/models/nethive/rol_logico_componente_model.dart
Normal file
58
lib/models/nethive/rol_logico_componente_model.dart
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
class RolLogicoComponente {
|
||||||
|
final int id;
|
||||||
|
final String nombre;
|
||||||
|
final String? descripcion;
|
||||||
|
|
||||||
|
RolLogicoComponente({
|
||||||
|
required this.id,
|
||||||
|
required this.nombre,
|
||||||
|
this.descripcion,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory RolLogicoComponente.fromMap(Map<String, dynamic> map) {
|
||||||
|
return RolLogicoComponente(
|
||||||
|
id: map['id'] ?? 0,
|
||||||
|
nombre: map['nombre'] ?? '',
|
||||||
|
descripcion: map['descripcion'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'nombre': nombre,
|
||||||
|
'descripcion': descripcion,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
RolLogicoComponente copyWith({
|
||||||
|
int? id,
|
||||||
|
String? nombre,
|
||||||
|
String? descripcion,
|
||||||
|
}) {
|
||||||
|
return RolLogicoComponente(
|
||||||
|
id: id ?? this.id,
|
||||||
|
nombre: nombre ?? this.nombre,
|
||||||
|
descripcion: descripcion ?? this.descripcion,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'RolLogicoComponente(id: $id, nombre: $nombre, descripcion: $descripcion)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return other is RolLogicoComponente &&
|
||||||
|
other.id == id &&
|
||||||
|
other.nombre == nombre &&
|
||||||
|
other.descripcion == descripcion;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return id.hashCode ^ nombre.hashCode ^ descripcion.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
lib/models/nethive/tipo_distribucion_model.dart
Normal file
51
lib/models/nethive/tipo_distribucion_model.dart
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
class TipoDistribucion {
|
||||||
|
final int id;
|
||||||
|
final String nombre;
|
||||||
|
|
||||||
|
TipoDistribucion({
|
||||||
|
required this.id,
|
||||||
|
required this.nombre,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TipoDistribucion.fromMap(Map<String, dynamic> map) {
|
||||||
|
return TipoDistribucion(
|
||||||
|
id: map['id'] ?? 0,
|
||||||
|
nombre: map['nombre'] ?? '',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
'id': id,
|
||||||
|
'nombre': nombre,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
TipoDistribucion copyWith({
|
||||||
|
int? id,
|
||||||
|
String? nombre,
|
||||||
|
}) {
|
||||||
|
return TipoDistribucion(
|
||||||
|
id: id ?? this.id,
|
||||||
|
nombre: nombre ?? this.nombre,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TipoDistribucion(id: $id, nombre: $nombre)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return other is TipoDistribucion &&
|
||||||
|
other.id == id &&
|
||||||
|
other.nombre == nombre;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return id.hashCode ^ nombre.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
199
lib/models/nethive/topologia_completa_model.dart
Normal file
199
lib/models/nethive/topologia_completa_model.dart
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import 'package:nethive_neo/models/nethive/componente_model.dart';
|
||||||
|
import 'package:nethive_neo/models/nethive/conexion_componente_model.dart';
|
||||||
|
import 'package:nethive_neo/models/nethive/conexion_alimentacion_model.dart';
|
||||||
|
|
||||||
|
class TopologiaCompleta {
|
||||||
|
final List<ComponenteTopologia> componentes;
|
||||||
|
final List<ConexionDatos> conexionesDatos;
|
||||||
|
final List<ConexionEnergia> conexionesEnergia;
|
||||||
|
|
||||||
|
TopologiaCompleta({
|
||||||
|
required this.componentes,
|
||||||
|
required this.conexionesDatos,
|
||||||
|
required this.conexionesEnergia,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TopologiaCompleta.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TopologiaCompleta(
|
||||||
|
componentes: (json['componentes'] as List<dynamic>? ?? [])
|
||||||
|
.map((c) => ComponenteTopologia.fromMap(c))
|
||||||
|
.toList(),
|
||||||
|
conexionesDatos: (json['conexiones_datos'] as List<dynamic>? ?? [])
|
||||||
|
.map((cd) => ConexionDatos.fromMap(cd))
|
||||||
|
.toList(),
|
||||||
|
conexionesEnergia: (json['conexiones_energia'] as List<dynamic>? ?? [])
|
||||||
|
.map((ce) => ConexionEnergia.fromMap(ce))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ComponenteTopologia {
|
||||||
|
final String id;
|
||||||
|
final String nombre;
|
||||||
|
final int categoriaId;
|
||||||
|
final String categoria;
|
||||||
|
final String? descripcion;
|
||||||
|
final String? ubicacion;
|
||||||
|
final String? imagenUrl;
|
||||||
|
final bool enUso;
|
||||||
|
final bool activo;
|
||||||
|
final DateTime fechaRegistro;
|
||||||
|
final String? distribucionId;
|
||||||
|
final String? tipoDistribucion;
|
||||||
|
final String? nombreDistribucion;
|
||||||
|
|
||||||
|
ComponenteTopologia({
|
||||||
|
required this.id,
|
||||||
|
required this.nombre,
|
||||||
|
required this.categoriaId,
|
||||||
|
required this.categoria,
|
||||||
|
this.descripcion,
|
||||||
|
this.ubicacion,
|
||||||
|
this.imagenUrl,
|
||||||
|
required this.enUso,
|
||||||
|
required this.activo,
|
||||||
|
required this.fechaRegistro,
|
||||||
|
this.distribucionId,
|
||||||
|
this.tipoDistribucion,
|
||||||
|
this.nombreDistribucion,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ComponenteTopologia.fromMap(Map<String, dynamic> map) {
|
||||||
|
return ComponenteTopologia(
|
||||||
|
id: map['id'] ?? '',
|
||||||
|
nombre: map['nombre'] ?? '',
|
||||||
|
categoriaId: map['categoria_id'] ?? 0,
|
||||||
|
categoria: map['categoria'] ?? '',
|
||||||
|
descripcion: map['descripcion'],
|
||||||
|
ubicacion: map['ubicacion'],
|
||||||
|
imagenUrl: map['imagen_url'],
|
||||||
|
enUso: map['en_uso'] ?? false,
|
||||||
|
activo: map['activo'] ?? false,
|
||||||
|
fechaRegistro:
|
||||||
|
DateTime.tryParse(map['fecha_registro']?.toString() ?? '') ??
|
||||||
|
DateTime.now(),
|
||||||
|
distribucionId: map['distribucion_id'],
|
||||||
|
tipoDistribucion: map['tipo_distribucion'],
|
||||||
|
nombreDistribucion: map['nombre_distribucion'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Métodos de utilidad para topología
|
||||||
|
bool get esMDF =>
|
||||||
|
tipoDistribucion?.toLowerCase() == 'mdf' ||
|
||||||
|
ubicacion?.toLowerCase().contains('mdf') == true ||
|
||||||
|
categoria.toLowerCase().contains('mdf');
|
||||||
|
|
||||||
|
bool get esIDF =>
|
||||||
|
tipoDistribucion?.toLowerCase() == 'idf' ||
|
||||||
|
ubicacion?.toLowerCase().contains('idf') == true ||
|
||||||
|
categoria.toLowerCase().contains('idf');
|
||||||
|
|
||||||
|
bool get esSwitch => categoria.toLowerCase().contains('switch');
|
||||||
|
|
||||||
|
bool get esRouter =>
|
||||||
|
categoria.toLowerCase().contains('router') ||
|
||||||
|
categoria.toLowerCase().contains('firewall');
|
||||||
|
|
||||||
|
bool get esServidor =>
|
||||||
|
categoria.toLowerCase().contains('servidor') ||
|
||||||
|
categoria.toLowerCase().contains('server');
|
||||||
|
|
||||||
|
bool get esUPS => categoria.toLowerCase().contains('ups');
|
||||||
|
|
||||||
|
bool get esRack => categoria.toLowerCase().contains('rack');
|
||||||
|
|
||||||
|
bool get esPatchPanel =>
|
||||||
|
categoria.toLowerCase().contains('patch') ||
|
||||||
|
categoria.toLowerCase().contains('panel');
|
||||||
|
|
||||||
|
// Prioridad para ordenamiento en topología
|
||||||
|
int get prioridadTopologia {
|
||||||
|
if (esMDF) return 1;
|
||||||
|
if (esIDF) return 2;
|
||||||
|
if (esSwitch) return 3;
|
||||||
|
if (esRouter) return 4;
|
||||||
|
if (esServidor) return 5;
|
||||||
|
if (esUPS) return 6;
|
||||||
|
if (esRack) return 7;
|
||||||
|
if (esPatchPanel) return 8;
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConexionDatos {
|
||||||
|
final String id;
|
||||||
|
final String componenteOrigenId;
|
||||||
|
final String nombreOrigen;
|
||||||
|
final String componenteDestinoId;
|
||||||
|
final String nombreDestino;
|
||||||
|
final String? cableId;
|
||||||
|
final String? nombreCable;
|
||||||
|
final String? descripcion;
|
||||||
|
final bool activo;
|
||||||
|
|
||||||
|
ConexionDatos({
|
||||||
|
required this.id,
|
||||||
|
required this.componenteOrigenId,
|
||||||
|
required this.nombreOrigen,
|
||||||
|
required this.componenteDestinoId,
|
||||||
|
required this.nombreDestino,
|
||||||
|
this.cableId,
|
||||||
|
this.nombreCable,
|
||||||
|
this.descripcion,
|
||||||
|
required this.activo,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ConexionDatos.fromMap(Map<String, dynamic> map) {
|
||||||
|
return ConexionDatos(
|
||||||
|
id: map['id'] ?? '',
|
||||||
|
componenteOrigenId: map['componente_origen_id'] ?? '',
|
||||||
|
nombreOrigen: map['nombre_origen'] ?? '',
|
||||||
|
componenteDestinoId: map['componente_destino_id'] ?? '',
|
||||||
|
nombreDestino: map['nombre_destino'] ?? '',
|
||||||
|
cableId: map['cable_id'],
|
||||||
|
nombreCable: map['nombre_cable'],
|
||||||
|
descripcion: map['descripcion'],
|
||||||
|
activo: map['activo'] ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConexionEnergia {
|
||||||
|
final String id;
|
||||||
|
final String origenId;
|
||||||
|
final String nombreOrigen;
|
||||||
|
final String destinoId;
|
||||||
|
final String nombreDestino;
|
||||||
|
final String? cableId;
|
||||||
|
final String? nombreCable;
|
||||||
|
final String? descripcion;
|
||||||
|
final bool activo;
|
||||||
|
|
||||||
|
ConexionEnergia({
|
||||||
|
required this.id,
|
||||||
|
required this.origenId,
|
||||||
|
required this.nombreOrigen,
|
||||||
|
required this.destinoId,
|
||||||
|
required this.nombreDestino,
|
||||||
|
this.cableId,
|
||||||
|
this.nombreCable,
|
||||||
|
this.descripcion,
|
||||||
|
required this.activo,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ConexionEnergia.fromMap(Map<String, dynamic> map) {
|
||||||
|
return ConexionEnergia(
|
||||||
|
id: map['id'] ?? '',
|
||||||
|
origenId: map['origen_id'] ?? '',
|
||||||
|
nombreOrigen: map['nombre_origen'] ?? '',
|
||||||
|
destinoId: map['destino_id'] ?? '',
|
||||||
|
nombreDestino: map['nombre_destino'] ?? '',
|
||||||
|
cableId: map['cable_id'],
|
||||||
|
nombreCable: map['nombre_cable'],
|
||||||
|
descripcion: map['descripcion'],
|
||||||
|
activo: map['activo'] ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ class VistaTopologiaPorNegocio {
|
|||||||
final String componenteNombre;
|
final String componenteNombre;
|
||||||
final String? descripcion;
|
final String? descripcion;
|
||||||
final String categoriaComponente;
|
final String categoriaComponente;
|
||||||
|
final int? rolLogicoId;
|
||||||
|
final String? rolLogico;
|
||||||
final bool enUso;
|
final bool enUso;
|
||||||
final bool activo;
|
final bool activo;
|
||||||
final String? ubicacion;
|
final String? ubicacion;
|
||||||
@@ -26,6 +28,8 @@ class VistaTopologiaPorNegocio {
|
|||||||
required this.componenteNombre,
|
required this.componenteNombre,
|
||||||
this.descripcion,
|
this.descripcion,
|
||||||
required this.categoriaComponente,
|
required this.categoriaComponente,
|
||||||
|
this.rolLogicoId,
|
||||||
|
this.rolLogico,
|
||||||
required this.enUso,
|
required this.enUso,
|
||||||
required this.activo,
|
required this.activo,
|
||||||
this.ubicacion,
|
this.ubicacion,
|
||||||
@@ -35,29 +39,30 @@ class VistaTopologiaPorNegocio {
|
|||||||
|
|
||||||
factory VistaTopologiaPorNegocio.fromMap(Map<String, dynamic> map) {
|
factory VistaTopologiaPorNegocio.fromMap(Map<String, dynamic> map) {
|
||||||
return VistaTopologiaPorNegocio(
|
return VistaTopologiaPorNegocio(
|
||||||
negocioId: map['negocio_id']?.toString() ?? '',
|
negocioId: map['negocio_id'] ?? '',
|
||||||
nombreNegocio: map['nombre_negocio']?.toString() ?? '',
|
nombreNegocio: map['negocio_nombre'] ?? '',
|
||||||
distribucionId: map['distribucion_id']?.toString(),
|
distribucionId: map['distribucion_id'],
|
||||||
tipoDistribucion: map['tipo_distribucion']?.toString(),
|
tipoDistribucion: map['tipo_distribucion'],
|
||||||
distribucionNombre: map['distribucion_nombre']?.toString(),
|
distribucionNombre: map['distribucion_nombre'],
|
||||||
componenteId: map['componente_id']?.toString() ?? '',
|
componenteId: map['componente_id'] ?? '',
|
||||||
componenteNombre: map['componente_nombre']?.toString() ?? '',
|
componenteNombre: map['componente_nombre'] ?? '',
|
||||||
descripcion: map['descripcion']?.toString(),
|
descripcion: map['descripcion'],
|
||||||
categoriaComponente: map['categoria_componente']?.toString() ?? '',
|
categoriaComponente: map['categoria_componente'] ?? '',
|
||||||
|
rolLogicoId: map['rol_logico_id'],
|
||||||
|
rolLogico: map['rol_logico'],
|
||||||
enUso: map['en_uso'] == true,
|
enUso: map['en_uso'] == true,
|
||||||
activo: map['activo'] == true,
|
activo: map['activo'] == true,
|
||||||
ubicacion: map['ubicacion']?.toString(),
|
ubicacion: map['ubicacion'],
|
||||||
imagenUrl: map['imagen_url']?.toString(),
|
imagenUrl: map['imagen_url'],
|
||||||
fechaRegistro:
|
fechaRegistro:
|
||||||
DateTime.tryParse(map['fecha_registro']?.toString() ?? '') ??
|
DateTime.tryParse(map['fecha_registro'] ?? '') ?? DateTime.now(),
|
||||||
DateTime.now(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return {
|
||||||
'negocio_id': negocioId,
|
'negocio_id': negocioId,
|
||||||
'nombre_negocio': nombreNegocio,
|
'negocio_nombre': nombreNegocio,
|
||||||
'distribucion_id': distribucionId,
|
'distribucion_id': distribucionId,
|
||||||
'tipo_distribucion': tipoDistribucion,
|
'tipo_distribucion': tipoDistribucion,
|
||||||
'distribucion_nombre': distribucionNombre,
|
'distribucion_nombre': distribucionNombre,
|
||||||
@@ -65,6 +70,8 @@ class VistaTopologiaPorNegocio {
|
|||||||
'componente_nombre': componenteNombre,
|
'componente_nombre': componenteNombre,
|
||||||
'descripcion': descripcion,
|
'descripcion': descripcion,
|
||||||
'categoria_componente': categoriaComponente,
|
'categoria_componente': categoriaComponente,
|
||||||
|
'rol_logico_id': rolLogicoId,
|
||||||
|
'rol_logico': rolLogico,
|
||||||
'en_uso': enUso,
|
'en_uso': enUso,
|
||||||
'activo': activo,
|
'activo': activo,
|
||||||
'ubicacion': ubicacion,
|
'ubicacion': ubicacion,
|
||||||
@@ -78,20 +85,36 @@ class VistaTopologiaPorNegocio {
|
|||||||
|
|
||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
|
|
||||||
// Método para obtener el tipo de componente principal basado en IDs
|
bool get esMDF => tipoDistribucion?.toUpperCase() == 'MDF';
|
||||||
|
bool get esIDF => tipoDistribucion?.toUpperCase() == 'IDF';
|
||||||
|
|
||||||
String get tipoComponentePrincipal {
|
String get tipoComponentePrincipal {
|
||||||
final categoria = categoriaComponente.toLowerCase();
|
final categoria = categoriaComponente.toLowerCase();
|
||||||
|
final nombre = componenteNombre.toLowerCase();
|
||||||
|
final desc = descripcion?.toLowerCase() ?? '';
|
||||||
|
|
||||||
// Clasificación basada en los nombres de categorías exactos
|
if (nombre.contains('switch') || desc.contains('switch')) return 'switch';
|
||||||
|
if (nombre.contains('router') ||
|
||||||
|
desc.contains('router') ||
|
||||||
|
nombre.contains('firewall') ||
|
||||||
|
desc.contains('firewall') ||
|
||||||
|
nombre.contains('fortigate') ||
|
||||||
|
(nombre.contains('cisco') &&
|
||||||
|
(nombre.contains('asa') || nombre.contains('pix')))) {
|
||||||
|
return 'router';
|
||||||
|
}
|
||||||
|
if (nombre.contains('servidor') ||
|
||||||
|
nombre.contains('server') ||
|
||||||
|
desc.contains('servidor') ||
|
||||||
|
desc.contains('server')) {
|
||||||
|
return 'servidor';
|
||||||
|
}
|
||||||
if (categoria == 'cable') return 'cable';
|
if (categoria == 'cable') return 'cable';
|
||||||
if (categoria == 'switch') return 'switch';
|
|
||||||
if (categoria == 'patch panel') return 'patch_panel';
|
if (categoria == 'patch panel') return 'patch_panel';
|
||||||
if (categoria == 'rack') return 'rack';
|
if (categoria == 'rack') return 'rack';
|
||||||
if (categoria == 'ups') return 'ups';
|
if (categoria == 'ups') return 'ups';
|
||||||
if (categoria == 'mdf') return 'mdf';
|
if (categoria.contains('organizador')) return 'organizador';
|
||||||
if (categoria == 'idf') return 'idf';
|
|
||||||
|
|
||||||
// Clasificación por contenido para compatibilidad
|
|
||||||
if (categoria.contains('switch')) return 'switch';
|
if (categoria.contains('switch')) return 'switch';
|
||||||
if (categoria.contains('router') || categoria.contains('firewall'))
|
if (categoria.contains('router') || categoria.contains('firewall'))
|
||||||
return 'router';
|
return 'router';
|
||||||
@@ -102,32 +125,13 @@ class VistaTopologiaPorNegocio {
|
|||||||
return 'patch_panel';
|
return 'patch_panel';
|
||||||
if (categoria.contains('rack')) return 'rack';
|
if (categoria.contains('rack')) return 'rack';
|
||||||
if (categoria.contains('ups')) return 'ups';
|
if (categoria.contains('ups')) return 'ups';
|
||||||
if (categoria.contains('organizador')) return 'organizador';
|
|
||||||
|
|
||||||
return 'otro';
|
return 'otro';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Método mejorado para determinar si es MDF
|
|
||||||
bool get esMDF {
|
|
||||||
final categoria = categoriaComponente.toLowerCase();
|
|
||||||
return categoria == 'mdf' ||
|
|
||||||
tipoDistribucion?.toUpperCase() == 'MDF' ||
|
|
||||||
ubicacion?.toLowerCase().contains('mdf') == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Método mejorado para determinar si es IDF
|
|
||||||
bool get esIDF {
|
|
||||||
final categoria = categoriaComponente.toLowerCase();
|
|
||||||
return categoria == 'idf' ||
|
|
||||||
tipoDistribucion?.toUpperCase() == 'IDF' ||
|
|
||||||
ubicacion?.toLowerCase().contains('idf') == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Método para obtener el nivel de prioridad del componente (para ordenamiento en topología)
|
|
||||||
int get prioridadTopologia {
|
int get prioridadTopologia {
|
||||||
if (esMDF) return 1; // Máxima prioridad para MDF
|
if (esMDF) return 1;
|
||||||
if (esIDF) return 2; // Segunda prioridad para IDF
|
if (esIDF) return 2;
|
||||||
|
|
||||||
switch (tipoComponentePrincipal) {
|
switch (tipoComponentePrincipal) {
|
||||||
case 'router':
|
case 'router':
|
||||||
return 3;
|
return 3;
|
||||||
@@ -150,32 +154,26 @@ class VistaTopologiaPorNegocio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Método para determinar el color del componente en el diagrama
|
|
||||||
String getColorForDiagram() {
|
String getColorForDiagram() {
|
||||||
if (esMDF) return '#2196F3'; // Azul para MDF
|
if (esMDF) return '#2196F3';
|
||||||
if (esIDF) {
|
if (esIDF) return enUso ? '#4CAF50' : '#FF9800';
|
||||||
return enUso
|
|
||||||
? '#4CAF50'
|
|
||||||
: '#FF9800'; // Verde si está en uso, naranja si no
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (tipoComponentePrincipal) {
|
switch (tipoComponentePrincipal) {
|
||||||
case 'router':
|
case 'router':
|
||||||
return '#FF5722'; // Naranja rojizo
|
return '#FF5722';
|
||||||
case 'switch':
|
case 'switch':
|
||||||
return '#9C27B0'; // Morado
|
return '#9C27B0';
|
||||||
case 'servidor':
|
case 'servidor':
|
||||||
return '#E91E63'; // Rosa
|
return '#E91E63';
|
||||||
case 'patch_panel':
|
case 'patch_panel':
|
||||||
return '#607D8B'; // Azul gris
|
return '#607D8B';
|
||||||
case 'rack':
|
case 'rack':
|
||||||
return '#795548'; // Marrón
|
return '#795548';
|
||||||
case 'ups':
|
case 'ups':
|
||||||
return '#FFC107'; // Ámbar
|
return '#FFC107';
|
||||||
case 'cable':
|
case 'cable':
|
||||||
return '#4CAF50'; // Verde
|
return '#4CAF50';
|
||||||
case 'organizador':
|
case 'organizador':
|
||||||
return '#9E9E9E'; // Gris
|
return '#9E9E9E';
|
||||||
default:
|
default:
|
||||||
return activo ? '#2196F3' : '#757575';
|
return activo ? '#2196F3' : '#757575';
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user