modelos y provider creados
This commit is contained in:
@@ -10,6 +10,8 @@ import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:nethive_neo/providers/user_provider.dart';
|
||||
import 'package:nethive_neo/providers/visual_state_provider.dart';
|
||||
import 'package:nethive_neo/providers/users_provider.dart';
|
||||
import 'package:nethive_neo/providers/nethive/empresas_negocios_provider.dart';
|
||||
import 'package:nethive_neo/providers/nethive/componentes_provider.dart';
|
||||
import 'package:nethive_neo/helpers/globals.dart';
|
||||
import 'package:url_strategy/url_strategy.dart';
|
||||
|
||||
@@ -42,6 +44,8 @@ void main() async {
|
||||
ChangeNotifierProvider(
|
||||
create: (context) => VisualStateProvider(context)),
|
||||
ChangeNotifierProvider(create: (_) => UsersProvider()),
|
||||
ChangeNotifierProvider(create: (_) => EmpresasNegociosProvider()),
|
||||
ChangeNotifierProvider(create: (_) => ComponentesProvider()),
|
||||
],
|
||||
child: const MyApp(),
|
||||
),
|
||||
|
||||
29
lib/models/nethive/categoria_componente_model.dart
Normal file
29
lib/models/nethive/categoria_componente_model.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class CategoriaComponente {
|
||||
final int id;
|
||||
final String nombre;
|
||||
|
||||
CategoriaComponente({
|
||||
required this.id,
|
||||
required this.nombre,
|
||||
});
|
||||
|
||||
factory CategoriaComponente.fromMap(Map<String, dynamic> map) {
|
||||
return CategoriaComponente(
|
||||
id: map['id'],
|
||||
nombre: map['nombre'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'nombre': nombre,
|
||||
};
|
||||
}
|
||||
|
||||
factory CategoriaComponente.fromJson(String source) =>
|
||||
CategoriaComponente.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
61
lib/models/nethive/componente_model.dart
Normal file
61
lib/models/nethive/componente_model.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class Componente {
|
||||
final String id;
|
||||
final String negocioId;
|
||||
final int categoriaId;
|
||||
final String nombre;
|
||||
final String? descripcion;
|
||||
final bool enUso;
|
||||
final bool activo;
|
||||
final String? ubicacion;
|
||||
final String? imagenUrl;
|
||||
final DateTime fechaRegistro;
|
||||
|
||||
Componente({
|
||||
required this.id,
|
||||
required this.negocioId,
|
||||
required this.categoriaId,
|
||||
required this.nombre,
|
||||
this.descripcion,
|
||||
required this.enUso,
|
||||
required this.activo,
|
||||
this.ubicacion,
|
||||
this.imagenUrl,
|
||||
required this.fechaRegistro,
|
||||
});
|
||||
|
||||
factory Componente.fromMap(Map<String, dynamic> map) {
|
||||
return Componente(
|
||||
id: map['id'],
|
||||
negocioId: map['negocio_id'],
|
||||
categoriaId: map['categoria_id'],
|
||||
nombre: map['nombre'],
|
||||
descripcion: map['descripcion'],
|
||||
enUso: map['en_uso'],
|
||||
activo: map['activo'],
|
||||
ubicacion: map['ubicacion'],
|
||||
imagenUrl: map['imagen_url'],
|
||||
fechaRegistro: DateTime.parse(map['fecha_registro']),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'negocio_id': negocioId,
|
||||
'categoria_id': categoriaId,
|
||||
'nombre': nombre,
|
||||
'descripcion': descripcion,
|
||||
'en_uso': enUso,
|
||||
'activo': activo,
|
||||
'ubicacion': ubicacion,
|
||||
'imagen_url': imagenUrl,
|
||||
'fecha_registro': fechaRegistro.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
factory Componente.fromJson(String source) =>
|
||||
Componente.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
41
lib/models/nethive/detalle_cable_model.dart
Normal file
41
lib/models/nethive/detalle_cable_model.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleCable {
|
||||
final String componenteId;
|
||||
final String? tipoCable;
|
||||
final String? color;
|
||||
final double? tamano;
|
||||
final String? tipoConector;
|
||||
|
||||
DetalleCable({
|
||||
required this.componenteId,
|
||||
this.tipoCable,
|
||||
this.color,
|
||||
this.tamano,
|
||||
this.tipoConector,
|
||||
});
|
||||
|
||||
factory DetalleCable.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleCable(
|
||||
componenteId: map['componente_id'],
|
||||
tipoCable: map['tipo_cable'],
|
||||
color: map['color'],
|
||||
tamano: map['tamaño']?.toDouble(),
|
||||
tipoConector: map['tipo_conector'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo_cable': tipoCable,
|
||||
'color': color,
|
||||
'tamaño': tamano,
|
||||
'tipo_conector': tipoConector,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleCable.fromJson(String source) =>
|
||||
DetalleCable.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
53
lib/models/nethive/detalle_equipo_activo_model.dart
Normal file
53
lib/models/nethive/detalle_equipo_activo_model.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleEquipoActivo {
|
||||
final String componenteId;
|
||||
final String? tipo;
|
||||
final String? marca;
|
||||
final String? modelo;
|
||||
final String? numeroSerie;
|
||||
final String? especificaciones;
|
||||
final String? direccionIp;
|
||||
final String? firmware;
|
||||
|
||||
DetalleEquipoActivo({
|
||||
required this.componenteId,
|
||||
this.tipo,
|
||||
this.marca,
|
||||
this.modelo,
|
||||
this.numeroSerie,
|
||||
this.especificaciones,
|
||||
this.direccionIp,
|
||||
this.firmware,
|
||||
});
|
||||
|
||||
factory DetalleEquipoActivo.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleEquipoActivo(
|
||||
componenteId: map['componente_id'],
|
||||
tipo: map['tipo'],
|
||||
marca: map['marca'],
|
||||
modelo: map['modelo'],
|
||||
numeroSerie: map['numero_serie'],
|
||||
especificaciones: map['especificaciones'],
|
||||
direccionIp: map['direccion_ip'],
|
||||
firmware: map['firmware'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo': tipo,
|
||||
'marca': marca,
|
||||
'modelo': modelo,
|
||||
'numero_serie': numeroSerie,
|
||||
'especificaciones': especificaciones,
|
||||
'direccion_ip': direccionIp,
|
||||
'firmware': firmware,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleEquipoActivo.fromJson(String source) =>
|
||||
DetalleEquipoActivo.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
41
lib/models/nethive/detalle_organizador_model.dart
Normal file
41
lib/models/nethive/detalle_organizador_model.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleOrganizador {
|
||||
final String componenteId;
|
||||
final String? tipo;
|
||||
final String? material;
|
||||
final String? tamano;
|
||||
final String? color;
|
||||
|
||||
DetalleOrganizador({
|
||||
required this.componenteId,
|
||||
this.tipo,
|
||||
this.material,
|
||||
this.tamano,
|
||||
this.color,
|
||||
});
|
||||
|
||||
factory DetalleOrganizador.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleOrganizador(
|
||||
componenteId: map['componente_id'],
|
||||
tipo: map['tipo'],
|
||||
material: map['material'],
|
||||
tamano: map['tamaño'],
|
||||
color: map['color'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo': tipo,
|
||||
'material': material,
|
||||
'tamaño': tamano,
|
||||
'color': color,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleOrganizador.fromJson(String source) =>
|
||||
DetalleOrganizador.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
49
lib/models/nethive/detalle_patch_panel_model.dart
Normal file
49
lib/models/nethive/detalle_patch_panel_model.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetallePatchPanel {
|
||||
final String componenteId;
|
||||
final String? tipoConector;
|
||||
final int? numeroPuertos;
|
||||
final String? categoria;
|
||||
final String? tipoMontaje;
|
||||
final bool? numeracionFrontal;
|
||||
final bool? panelCiego;
|
||||
|
||||
DetallePatchPanel({
|
||||
required this.componenteId,
|
||||
this.tipoConector,
|
||||
this.numeroPuertos,
|
||||
this.categoria,
|
||||
this.tipoMontaje,
|
||||
this.numeracionFrontal,
|
||||
this.panelCiego,
|
||||
});
|
||||
|
||||
factory DetallePatchPanel.fromMap(Map<String, dynamic> map) {
|
||||
return DetallePatchPanel(
|
||||
componenteId: map['componente_id'],
|
||||
tipoConector: map['tipo_conector'],
|
||||
numeroPuertos: map['numero_puertos'],
|
||||
categoria: map['categoria'],
|
||||
tipoMontaje: map['tipo_montaje'],
|
||||
numeracionFrontal: map['numeracion_frontal'],
|
||||
panelCiego: map['panel_ciego'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo_conector': tipoConector,
|
||||
'numero_puertos': numeroPuertos,
|
||||
'categoria': categoria,
|
||||
'tipo_montaje': tipoMontaje,
|
||||
'numeracion_frontal': numeracionFrontal,
|
||||
'panel_ciego': panelCiego,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetallePatchPanel.fromJson(String source) =>
|
||||
DetallePatchPanel.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
57
lib/models/nethive/detalle_rack_model.dart
Normal file
57
lib/models/nethive/detalle_rack_model.dart
Normal file
@@ -0,0 +1,57 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleRack {
|
||||
final String componenteId;
|
||||
final String? tipo;
|
||||
final int? alturaU;
|
||||
final int? profundidadCm;
|
||||
final int? anchoCm;
|
||||
final bool? ventilacionIntegrada;
|
||||
final bool? puertasConLlave;
|
||||
final bool? ruedas;
|
||||
final String? color;
|
||||
|
||||
DetalleRack({
|
||||
required this.componenteId,
|
||||
this.tipo,
|
||||
this.alturaU,
|
||||
this.profundidadCm,
|
||||
this.anchoCm,
|
||||
this.ventilacionIntegrada,
|
||||
this.puertasConLlave,
|
||||
this.ruedas,
|
||||
this.color,
|
||||
});
|
||||
|
||||
factory DetalleRack.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleRack(
|
||||
componenteId: map['componente_id'],
|
||||
tipo: map['tipo'],
|
||||
alturaU: map['altura_u'],
|
||||
profundidadCm: map['profundidad_cm'],
|
||||
anchoCm: map['ancho_cm'],
|
||||
ventilacionIntegrada: map['ventilacion_integrada'],
|
||||
puertasConLlave: map['puertas_con_llave'],
|
||||
ruedas: map['ruedas'],
|
||||
color: map['color'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo': tipo,
|
||||
'altura_u': alturaU,
|
||||
'profundidad_cm': profundidadCm,
|
||||
'ancho_cm': anchoCm,
|
||||
'ventilacion_integrada': ventilacionIntegrada,
|
||||
'puertas_con_llave': puertasConLlave,
|
||||
'ruedas': ruedas,
|
||||
'color': color,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleRack.fromJson(String source) =>
|
||||
DetalleRack.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
61
lib/models/nethive/detalle_router_firewall_model.dart
Normal file
61
lib/models/nethive/detalle_router_firewall_model.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleRouterFirewall {
|
||||
final String componenteId;
|
||||
final String? tipo;
|
||||
final String? marca;
|
||||
final String? modelo;
|
||||
final String? numeroSerie;
|
||||
final String? interfaces;
|
||||
final double? capacidadRoutingGbps;
|
||||
final String? direccionIp;
|
||||
final String? firmware;
|
||||
final String? licencias;
|
||||
|
||||
DetalleRouterFirewall({
|
||||
required this.componenteId,
|
||||
this.tipo,
|
||||
this.marca,
|
||||
this.modelo,
|
||||
this.numeroSerie,
|
||||
this.interfaces,
|
||||
this.capacidadRoutingGbps,
|
||||
this.direccionIp,
|
||||
this.firmware,
|
||||
this.licencias,
|
||||
});
|
||||
|
||||
factory DetalleRouterFirewall.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleRouterFirewall(
|
||||
componenteId: map['componente_id'],
|
||||
tipo: map['tipo'],
|
||||
marca: map['marca'],
|
||||
modelo: map['modelo'],
|
||||
numeroSerie: map['numero_serie'],
|
||||
interfaces: map['interfaces'],
|
||||
capacidadRoutingGbps: map['capacidad_routing_gbps']?.toDouble(),
|
||||
direccionIp: map['direccion_ip'],
|
||||
firmware: map['firmware'],
|
||||
licencias: map['licencias'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo': tipo,
|
||||
'marca': marca,
|
||||
'modelo': modelo,
|
||||
'numero_serie': numeroSerie,
|
||||
'interfaces': interfaces,
|
||||
'capacidad_routing_gbps': capacidadRoutingGbps,
|
||||
'direccion_ip': direccionIp,
|
||||
'firmware': firmware,
|
||||
'licencias': licencias,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleRouterFirewall.fromJson(String source) =>
|
||||
DetalleRouterFirewall.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
69
lib/models/nethive/detalle_switch_model.dart
Normal file
69
lib/models/nethive/detalle_switch_model.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleSwitch {
|
||||
final String componenteId;
|
||||
final String? marca;
|
||||
final String? modelo;
|
||||
final String? numeroSerie;
|
||||
final bool? administrable;
|
||||
final bool? poe;
|
||||
final int? cantidadPuertos;
|
||||
final String? velocidadPuertos;
|
||||
final String? tipoPuertos;
|
||||
final String? ubicacionEnRack;
|
||||
final String? direccionIp;
|
||||
final String? firmware;
|
||||
|
||||
DetalleSwitch({
|
||||
required this.componenteId,
|
||||
this.marca,
|
||||
this.modelo,
|
||||
this.numeroSerie,
|
||||
this.administrable,
|
||||
this.poe,
|
||||
this.cantidadPuertos,
|
||||
this.velocidadPuertos,
|
||||
this.tipoPuertos,
|
||||
this.ubicacionEnRack,
|
||||
this.direccionIp,
|
||||
this.firmware,
|
||||
});
|
||||
|
||||
factory DetalleSwitch.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleSwitch(
|
||||
componenteId: map['componente_id'],
|
||||
marca: map['marca'],
|
||||
modelo: map['modelo'],
|
||||
numeroSerie: map['numero_serie'],
|
||||
administrable: map['administrable'],
|
||||
poe: map['poe'],
|
||||
cantidadPuertos: map['cantidad_puertos'],
|
||||
velocidadPuertos: map['velocidad_puertos'],
|
||||
tipoPuertos: map['tipo_puertos'],
|
||||
ubicacionEnRack: map['ubicacion_en_rack'],
|
||||
direccionIp: map['direccion_ip'],
|
||||
firmware: map['firmware'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'marca': marca,
|
||||
'modelo': modelo,
|
||||
'numero_serie': numeroSerie,
|
||||
'administrable': administrable,
|
||||
'poe': poe,
|
||||
'cantidad_puertos': cantidadPuertos,
|
||||
'velocidad_puertos': velocidadPuertos,
|
||||
'tipo_puertos': tipoPuertos,
|
||||
'ubicacion_en_rack': ubicacionEnRack,
|
||||
'direccion_ip': direccionIp,
|
||||
'firmware': firmware,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleSwitch.fromJson(String source) =>
|
||||
DetalleSwitch.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
61
lib/models/nethive/detalle_ups_model.dart
Normal file
61
lib/models/nethive/detalle_ups_model.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class DetalleUps {
|
||||
final String componenteId;
|
||||
final String? tipo;
|
||||
final String? marca;
|
||||
final String? modelo;
|
||||
final String? voltajeEntrada;
|
||||
final String? voltajeSalida;
|
||||
final int? capacidadVa;
|
||||
final int? autonomiaMinutos;
|
||||
final int? cantidadTomas;
|
||||
final bool? rackeable;
|
||||
|
||||
DetalleUps({
|
||||
required this.componenteId,
|
||||
this.tipo,
|
||||
this.marca,
|
||||
this.modelo,
|
||||
this.voltajeEntrada,
|
||||
this.voltajeSalida,
|
||||
this.capacidadVa,
|
||||
this.autonomiaMinutos,
|
||||
this.cantidadTomas,
|
||||
this.rackeable,
|
||||
});
|
||||
|
||||
factory DetalleUps.fromMap(Map<String, dynamic> map) {
|
||||
return DetalleUps(
|
||||
componenteId: map['componente_id'],
|
||||
tipo: map['tipo'],
|
||||
marca: map['marca'],
|
||||
modelo: map['modelo'],
|
||||
voltajeEntrada: map['voltaje_entrada'],
|
||||
voltajeSalida: map['voltaje_salida'],
|
||||
capacidadVa: map['capacidad_va'],
|
||||
autonomiaMinutos: map['autonomia_minutos'],
|
||||
cantidadTomas: map['cantidad_tomas'],
|
||||
rackeable: map['rackeable'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'componente_id': componenteId,
|
||||
'tipo': tipo,
|
||||
'marca': marca,
|
||||
'modelo': modelo,
|
||||
'voltaje_entrada': voltajeEntrada,
|
||||
'voltaje_salida': voltajeSalida,
|
||||
'capacidad_va': capacidadVa,
|
||||
'autonomia_minutos': autonomiaMinutos,
|
||||
'cantidad_tomas': cantidadTomas,
|
||||
'rackeable': rackeable,
|
||||
};
|
||||
}
|
||||
|
||||
factory DetalleUps.fromJson(String source) =>
|
||||
DetalleUps.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
57
lib/models/nethive/empresa_model.dart
Normal file
57
lib/models/nethive/empresa_model.dart
Normal file
@@ -0,0 +1,57 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class Empresa {
|
||||
final String id;
|
||||
final String nombre;
|
||||
final String rfc;
|
||||
final String direccion;
|
||||
final String telefono;
|
||||
final String email;
|
||||
final DateTime fechaCreacion;
|
||||
final String? logoUrl;
|
||||
final String? imagenUrl;
|
||||
|
||||
Empresa({
|
||||
required this.id,
|
||||
required this.nombre,
|
||||
required this.rfc,
|
||||
required this.direccion,
|
||||
required this.telefono,
|
||||
required this.email,
|
||||
required this.fechaCreacion,
|
||||
this.logoUrl,
|
||||
this.imagenUrl,
|
||||
});
|
||||
|
||||
factory Empresa.fromMap(Map<String, dynamic> map) {
|
||||
return Empresa(
|
||||
id: map['id'],
|
||||
nombre: map['nombre'],
|
||||
rfc: map['rfc'],
|
||||
direccion: map['direccion'],
|
||||
telefono: map['telefono'],
|
||||
email: map['email'],
|
||||
fechaCreacion: DateTime.parse(map['fecha_creacion']),
|
||||
logoUrl: map['logo_url'],
|
||||
imagenUrl: map['imagen_url'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'nombre': nombre,
|
||||
'rfc': rfc,
|
||||
'direccion': direccion,
|
||||
'telefono': telefono,
|
||||
'email': email,
|
||||
'fecha_creacion': fechaCreacion.toIso8601String(),
|
||||
'logo_url': logoUrl,
|
||||
'imagen_url': imagenUrl,
|
||||
};
|
||||
}
|
||||
|
||||
factory Empresa.fromJson(String source) =>
|
||||
Empresa.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
61
lib/models/nethive/negocio_model.dart
Normal file
61
lib/models/nethive/negocio_model.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class Negocio {
|
||||
final String id;
|
||||
final String empresaId;
|
||||
final String nombre;
|
||||
final String direccion;
|
||||
final double latitud;
|
||||
final double longitud;
|
||||
final String tipoLocal;
|
||||
final DateTime fechaCreacion;
|
||||
final String? logoUrl;
|
||||
final String? imagenUrl;
|
||||
|
||||
Negocio({
|
||||
required this.id,
|
||||
required this.empresaId,
|
||||
required this.nombre,
|
||||
required this.direccion,
|
||||
required this.latitud,
|
||||
required this.longitud,
|
||||
required this.tipoLocal,
|
||||
required this.fechaCreacion,
|
||||
this.logoUrl,
|
||||
this.imagenUrl,
|
||||
});
|
||||
|
||||
factory Negocio.fromMap(Map<String, dynamic> map) {
|
||||
return Negocio(
|
||||
id: map['id'],
|
||||
empresaId: map['empresa_id'],
|
||||
nombre: map['nombre'],
|
||||
direccion: map['direccion'],
|
||||
latitud: map['latitud'].toDouble(),
|
||||
longitud: map['longitud'].toDouble(),
|
||||
tipoLocal: map['tipo_local'],
|
||||
fechaCreacion: DateTime.parse(map['fecha_creacion']),
|
||||
logoUrl: map['logo_url'],
|
||||
imagenUrl: map['imagen_url'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'empresa_id': empresaId,
|
||||
'nombre': nombre,
|
||||
'direccion': direccion,
|
||||
'latitud': latitud,
|
||||
'longitud': longitud,
|
||||
'tipo_local': tipoLocal,
|
||||
'fecha_creacion': fechaCreacion.toIso8601String(),
|
||||
'logo_url': logoUrl,
|
||||
'imagen_url': imagenUrl,
|
||||
};
|
||||
}
|
||||
|
||||
factory Negocio.fromJson(String source) =>
|
||||
Negocio.fromMap(json.decode(source));
|
||||
String toJson() => json.encode(toMap());
|
||||
}
|
||||
533
lib/providers/nethive/componentes_provider.dart
Normal file
533
lib/providers/nethive/componentes_provider.dart
Normal file
@@ -0,0 +1,533 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:pluto_grid/pluto_grid.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import 'package:nethive_neo/helpers/globals.dart';
|
||||
import 'package:nethive_neo/models/nethive/categoria_componente_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/componente_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_cable_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_switch_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_patch_panel_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_rack_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_organizador_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_ups_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_router_firewall_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/detalle_equipo_activo_model.dart';
|
||||
|
||||
class ComponentesProvider extends ChangeNotifier {
|
||||
// State managers
|
||||
PlutoGridStateManager? componentesStateManager;
|
||||
PlutoGridStateManager? categoriasStateManager;
|
||||
|
||||
// Controladores de búsqueda
|
||||
final busquedaComponenteController = TextEditingController();
|
||||
final busquedaCategoriaController = TextEditingController();
|
||||
|
||||
// Listas principales
|
||||
List<CategoriaComponente> categorias = [];
|
||||
List<Componente> componentes = [];
|
||||
List<PlutoRow> componentesRows = [];
|
||||
List<PlutoRow> categoriasRows = [];
|
||||
|
||||
// Variables para formularios
|
||||
String? imagenFileName;
|
||||
Uint8List? imagenToUpload;
|
||||
String? negocioSeleccionadoId;
|
||||
int? categoriaSeleccionadaId;
|
||||
bool showDetallesEspecificos = false;
|
||||
|
||||
// Detalles específicos por tipo de componente
|
||||
DetalleCable? detalleCable;
|
||||
DetalleSwitch? detalleSwitch;
|
||||
DetallePatchPanel? detallePatchPanel;
|
||||
DetalleRack? detalleRack;
|
||||
DetalleOrganizador? detalleOrganizador;
|
||||
DetalleUps? detalleUps;
|
||||
DetalleRouterFirewall? detalleRouterFirewall;
|
||||
DetalleEquipoActivo? detalleEquipoActivo;
|
||||
|
||||
ComponentesProvider() {
|
||||
getCategorias();
|
||||
}
|
||||
|
||||
// Métodos para categorías
|
||||
Future<void> getCategorias([String? busqueda]) async {
|
||||
try {
|
||||
var query = supabaseLU.from('categoria_componente').select();
|
||||
|
||||
if (busqueda != null && busqueda.isNotEmpty) {
|
||||
query = query.ilike('nombre', '%$busqueda%');
|
||||
}
|
||||
|
||||
final res = await query.order('nombre', ascending: true);
|
||||
|
||||
categorias = (res as List<dynamic>)
|
||||
.map((categoria) => CategoriaComponente.fromMap(categoria))
|
||||
.toList();
|
||||
|
||||
_buildCategoriasRows();
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error en getCategorias: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
void _buildCategoriasRows() {
|
||||
categoriasRows.clear();
|
||||
|
||||
for (CategoriaComponente categoria in categorias) {
|
||||
categoriasRows.add(PlutoRow(cells: {
|
||||
'id': PlutoCell(value: categoria.id),
|
||||
'nombre': PlutoCell(value: categoria.nombre),
|
||||
'editar': PlutoCell(value: categoria.id),
|
||||
'eliminar': PlutoCell(value: categoria.id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Métodos para componentes
|
||||
Future<void> getComponentesPorNegocio(String negocioId,
|
||||
[String? busqueda]) async {
|
||||
try {
|
||||
var query = supabaseLU.from('componente').select('''
|
||||
*,
|
||||
categoria_componente!inner(id, nombre)
|
||||
''').eq('negocio_id', negocioId);
|
||||
|
||||
if (busqueda != null && busqueda.isNotEmpty) {
|
||||
query = query.or(
|
||||
'nombre.ilike.%$busqueda%,descripcion.ilike.%$busqueda%,ubicacion.ilike.%$busqueda%');
|
||||
}
|
||||
|
||||
final res = await query.order('fecha_registro', ascending: false);
|
||||
|
||||
componentes = (res as List<dynamic>)
|
||||
.map((componente) => Componente.fromMap(componente))
|
||||
.toList();
|
||||
|
||||
_buildComponentesRows();
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error en getComponentesPorNegocio: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
void _buildComponentesRows() {
|
||||
componentesRows.clear();
|
||||
|
||||
for (Componente componente in componentes) {
|
||||
componentesRows.add(PlutoRow(cells: {
|
||||
'id': PlutoCell(value: componente.id),
|
||||
'negocio_id': PlutoCell(value: componente.negocioId),
|
||||
'categoria_id': PlutoCell(value: componente.categoriaId),
|
||||
'categoria_nombre': PlutoCell(
|
||||
value: getCategoriaById(componente.categoriaId)?.nombre ??
|
||||
'Sin categoría'),
|
||||
'nombre': PlutoCell(value: componente.nombre),
|
||||
'descripcion': PlutoCell(value: componente.descripcion ?? ''),
|
||||
'en_uso': PlutoCell(value: componente.enUso ? 'Sí' : 'No'),
|
||||
'activo': PlutoCell(value: componente.activo ? 'Sí' : 'No'),
|
||||
'ubicacion': PlutoCell(value: componente.ubicacion ?? ''),
|
||||
'fecha_registro':
|
||||
PlutoCell(value: componente.fechaRegistro.toString().split(' ')[0]),
|
||||
'imagen_url': PlutoCell(
|
||||
value: componente.imagenUrl != null
|
||||
? "${supabaseLU.supabaseUrl}/storage/v1/object/public/nethive/componentes/${componente.imagenUrl}?${DateTime.now().millisecondsSinceEpoch}"
|
||||
: '',
|
||||
),
|
||||
'editar': PlutoCell(value: componente.id),
|
||||
'eliminar': PlutoCell(value: componente.id),
|
||||
'ver_detalles': PlutoCell(value: componente.id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Métodos para subir imágenes
|
||||
Future<void> selectImagen() async {
|
||||
imagenFileName = null;
|
||||
imagenToUpload = null;
|
||||
|
||||
FilePickerResult? picker = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'jpeg'],
|
||||
);
|
||||
|
||||
if (picker != null) {
|
||||
var now = DateTime.now();
|
||||
var formatter = DateFormat('yyyyMMddHHmmss');
|
||||
var timestamp = formatter.format(now);
|
||||
|
||||
imagenFileName = 'componente-$timestamp-${picker.files.single.name}';
|
||||
imagenToUpload = picker.files.single.bytes;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<String?> uploadImagen() async {
|
||||
if (imagenToUpload != null && imagenFileName != null) {
|
||||
await supabaseLU.storage.from('nethive/componentes').uploadBinary(
|
||||
imagenFileName!,
|
||||
imagenToUpload!,
|
||||
fileOptions: const FileOptions(
|
||||
cacheControl: '3600',
|
||||
upsert: false,
|
||||
),
|
||||
);
|
||||
return imagenFileName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// CRUD Categorías
|
||||
Future<bool> crearCategoria(String nombre) async {
|
||||
try {
|
||||
final res = await supabaseLU.from('categoria_componente').insert({
|
||||
'nombre': nombre,
|
||||
}).select();
|
||||
|
||||
if (res.isNotEmpty) {
|
||||
await getCategorias();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error en crearCategoria: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> actualizarCategoria(int id, String nombre) async {
|
||||
try {
|
||||
final res = await supabaseLU
|
||||
.from('categoria_componente')
|
||||
.update({'nombre': nombre})
|
||||
.eq('id', id)
|
||||
.select();
|
||||
|
||||
if (res.isNotEmpty) {
|
||||
await getCategorias();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error en actualizarCategoria: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> eliminarCategoria(int id) async {
|
||||
try {
|
||||
await supabaseLU.from('categoria_componente').delete().eq('id', id);
|
||||
await getCategorias();
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error en eliminarCategoria: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// CRUD Componentes
|
||||
Future<bool> crearComponente({
|
||||
required String negocioId,
|
||||
required int categoriaId,
|
||||
required String nombre,
|
||||
String? descripcion,
|
||||
required bool enUso,
|
||||
required bool activo,
|
||||
String? ubicacion,
|
||||
}) async {
|
||||
try {
|
||||
final imagenUrl = await uploadImagen();
|
||||
|
||||
final res = await supabaseLU.from('componente').insert({
|
||||
'negocio_id': negocioId,
|
||||
'categoria_id': categoriaId,
|
||||
'nombre': nombre,
|
||||
'descripcion': descripcion,
|
||||
'en_uso': enUso,
|
||||
'activo': activo,
|
||||
'ubicacion': ubicacion,
|
||||
'imagen_url': imagenUrl,
|
||||
}).select();
|
||||
|
||||
if (res.isNotEmpty) {
|
||||
await getComponentesPorNegocio(negocioId);
|
||||
resetFormData();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error en crearComponente: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> eliminarComponente(String componenteId) async {
|
||||
try {
|
||||
// Eliminar todos los detalles específicos primero
|
||||
await _eliminarDetallesComponente(componenteId);
|
||||
|
||||
// Luego eliminar el componente
|
||||
await supabaseLU.from('componente').delete().eq('id', componenteId);
|
||||
|
||||
if (negocioSeleccionadoId != null) {
|
||||
await getComponentesPorNegocio(negocioSeleccionadoId!);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error en eliminarComponente: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _eliminarDetallesComponente(String componenteId) async {
|
||||
// Eliminar de todas las tablas de detalles
|
||||
await supabaseLU
|
||||
.from('detalle_cable')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_switch')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_patch_panel')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_rack')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_organizador')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_ups')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_router_firewall')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
await supabaseLU
|
||||
.from('detalle_equipo_activo')
|
||||
.delete()
|
||||
.eq('componente_id', componenteId);
|
||||
}
|
||||
|
||||
// Métodos para obtener detalles específicos
|
||||
Future<void> getDetallesComponente(
|
||||
String componenteId, int categoriaId) async {
|
||||
try {
|
||||
final categoriaNombre =
|
||||
getCategoriaById(categoriaId)?.nombre?.toLowerCase() ?? '';
|
||||
|
||||
if (categoriaNombre.contains('cable')) {
|
||||
await _getDetalleCable(componenteId);
|
||||
} else if (categoriaNombre.contains('switch')) {
|
||||
await _getDetalleSwitch(componenteId);
|
||||
} else if (categoriaNombre.contains('patch') ||
|
||||
categoriaNombre.contains('panel')) {
|
||||
await _getDetallePatchPanel(componenteId);
|
||||
} else if (categoriaNombre.contains('rack')) {
|
||||
await _getDetalleRack(componenteId);
|
||||
} else if (categoriaNombre.contains('organizador')) {
|
||||
await _getDetalleOrganizador(componenteId);
|
||||
} else if (categoriaNombre.contains('ups')) {
|
||||
await _getDetalleUps(componenteId);
|
||||
} else if (categoriaNombre.contains('router') ||
|
||||
categoriaNombre.contains('firewall')) {
|
||||
await _getDetalleRouterFirewall(componenteId);
|
||||
} else {
|
||||
await _getDetalleEquipoActivo(componenteId);
|
||||
}
|
||||
|
||||
showDetallesEspecificos = true;
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error en getDetallesComponente: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleCable(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_cable')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleCable = DetalleCable.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleSwitch(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_switch')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleSwitch = DetalleSwitch.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetallePatchPanel(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_patch_panel')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detallePatchPanel = DetallePatchPanel.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleRack(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_rack')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleRack = DetalleRack.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleOrganizador(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_organizador')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleOrganizador = DetalleOrganizador.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleUps(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_ups')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleUps = DetalleUps.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleRouterFirewall(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_router_firewall')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleRouterFirewall = DetalleRouterFirewall.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getDetalleEquipoActivo(String componenteId) async {
|
||||
final res = await supabaseLU
|
||||
.from('detalle_equipo_activo')
|
||||
.select()
|
||||
.eq('componente_id', componenteId)
|
||||
.maybeSingle();
|
||||
|
||||
if (res != null) {
|
||||
detalleEquipoActivo = DetalleEquipoActivo.fromMap(res);
|
||||
}
|
||||
}
|
||||
|
||||
// Métodos de utilidad
|
||||
void setNegocioSeleccionado(String negocioId) {
|
||||
negocioSeleccionadoId = negocioId;
|
||||
getComponentesPorNegocio(negocioId);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
CategoriaComponente? getCategoriaById(int id) {
|
||||
try {
|
||||
return categorias.firstWhere((c) => c.id == id);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void resetFormData() {
|
||||
imagenFileName = null;
|
||||
imagenToUpload = null;
|
||||
categoriaSeleccionadaId = null;
|
||||
showDetallesEspecificos = false;
|
||||
|
||||
// Limpiar detalles específicos
|
||||
detalleCable = null;
|
||||
detalleSwitch = null;
|
||||
detallePatchPanel = null;
|
||||
detalleRack = null;
|
||||
detalleOrganizador = null;
|
||||
detalleUps = null;
|
||||
detalleRouterFirewall = null;
|
||||
detalleEquipoActivo = null;
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void buscarComponentes(String busqueda) {
|
||||
if (negocioSeleccionadoId != null) {
|
||||
getComponentesPorNegocio(
|
||||
negocioSeleccionadoId!, busqueda.isEmpty ? null : busqueda);
|
||||
}
|
||||
}
|
||||
|
||||
void buscarCategorias(String busqueda) {
|
||||
getCategorias(busqueda.isEmpty ? null : busqueda);
|
||||
}
|
||||
|
||||
Widget? getImageWidget(dynamic image,
|
||||
{double height = 100, double width = 100}) {
|
||||
if (image == null || image.toString().isEmpty) {
|
||||
return Container(
|
||||
height: height,
|
||||
width: width,
|
||||
color: Colors.grey[300],
|
||||
child: const Icon(Icons.device_unknown),
|
||||
);
|
||||
} else if (image is Uint8List) {
|
||||
return Image.memory(
|
||||
image,
|
||||
height: height,
|
||||
width: width,
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
} else if (image is String) {
|
||||
return Image.network(
|
||||
image,
|
||||
height: height,
|
||||
width: width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: height,
|
||||
width: width,
|
||||
color: Colors.grey[300],
|
||||
child: const Icon(Icons.broken_image),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
371
lib/providers/nethive/empresas_negocios_provider.dart
Normal file
371
lib/providers/nethive/empresas_negocios_provider.dart
Normal file
@@ -0,0 +1,371 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:pluto_grid/pluto_grid.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import 'package:nethive_neo/helpers/globals.dart';
|
||||
import 'package:nethive_neo/models/nethive/empresa_model.dart';
|
||||
import 'package:nethive_neo/models/nethive/negocio_model.dart';
|
||||
|
||||
class EmpresasNegociosProvider extends ChangeNotifier {
|
||||
// State managers para las grillas
|
||||
PlutoGridStateManager? empresasStateManager;
|
||||
PlutoGridStateManager? negociosStateManager;
|
||||
|
||||
// Controladores de búsqueda
|
||||
final busquedaEmpresaController = TextEditingController();
|
||||
final busquedaNegocioController = TextEditingController();
|
||||
|
||||
// Listas de datos
|
||||
List<Empresa> empresas = [];
|
||||
List<Negocio> negocios = [];
|
||||
List<PlutoRow> empresasRows = [];
|
||||
List<PlutoRow> negociosRows = [];
|
||||
|
||||
// Variables para formularios
|
||||
String? logoFileName;
|
||||
String? imagenFileName;
|
||||
Uint8List? logoToUpload;
|
||||
Uint8List? imagenToUpload;
|
||||
|
||||
// Variables de selección
|
||||
String? empresaSeleccionadaId;
|
||||
Empresa? empresaSeleccionada;
|
||||
|
||||
EmpresasNegociosProvider() {
|
||||
getEmpresas();
|
||||
}
|
||||
|
||||
// Métodos para empresas
|
||||
Future<void> getEmpresas([String? busqueda]) async {
|
||||
try {
|
||||
var query = supabaseLU.from('empresa').select();
|
||||
|
||||
if (busqueda != null && busqueda.isNotEmpty) {
|
||||
query = query.or(
|
||||
'nombre.ilike.%$busqueda%,rfc.ilike.%$busqueda%,email.ilike.%$busqueda%');
|
||||
}
|
||||
|
||||
final res = await query.order('fecha_creacion', ascending: false);
|
||||
|
||||
empresas = (res as List<dynamic>)
|
||||
.map((empresa) => Empresa.fromMap(empresa))
|
||||
.toList();
|
||||
|
||||
_buildEmpresasRows();
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error en getEmpresas: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
void _buildEmpresasRows() {
|
||||
empresasRows.clear();
|
||||
|
||||
for (Empresa empresa in empresas) {
|
||||
empresasRows.add(PlutoRow(cells: {
|
||||
'id': PlutoCell(value: empresa.id),
|
||||
'nombre': PlutoCell(value: empresa.nombre),
|
||||
'rfc': PlutoCell(value: empresa.rfc),
|
||||
'direccion': PlutoCell(value: empresa.direccion),
|
||||
'telefono': PlutoCell(value: empresa.telefono),
|
||||
'email': PlutoCell(value: empresa.email),
|
||||
'fecha_creacion':
|
||||
PlutoCell(value: empresa.fechaCreacion.toString().split(' ')[0]),
|
||||
'logo_url': PlutoCell(
|
||||
value: empresa.logoUrl != null
|
||||
? "${supabaseLU.supabaseUrl}/storage/v1/object/public/nethive/logos/${empresa.logoUrl}?${DateTime.now().millisecondsSinceEpoch}"
|
||||
: '',
|
||||
),
|
||||
'imagen_url': PlutoCell(
|
||||
value: empresa.imagenUrl != null
|
||||
? "${supabaseLU.supabaseUrl}/storage/v1/object/public/nethive/imagenes/${empresa.imagenUrl}?${DateTime.now().millisecondsSinceEpoch}"
|
||||
: '',
|
||||
),
|
||||
'editar': PlutoCell(value: empresa.id),
|
||||
'eliminar': PlutoCell(value: empresa.id),
|
||||
'ver_negocios': PlutoCell(value: empresa.id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getNegociosPorEmpresa(String empresaId) async {
|
||||
try {
|
||||
final res = await supabaseLU
|
||||
.from('negocio')
|
||||
.select()
|
||||
.eq('empresa_id', empresaId)
|
||||
.order('fecha_creacion', ascending: false);
|
||||
|
||||
negocios = (res as List<dynamic>)
|
||||
.map((negocio) => Negocio.fromMap(negocio))
|
||||
.toList();
|
||||
|
||||
_buildNegociosRows();
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error en getNegociosPorEmpresa: ${e.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
void _buildNegociosRows() {
|
||||
negociosRows.clear();
|
||||
|
||||
for (Negocio negocio in negocios) {
|
||||
negociosRows.add(PlutoRow(cells: {
|
||||
'id': PlutoCell(value: negocio.id),
|
||||
'empresa_id': PlutoCell(value: negocio.empresaId),
|
||||
'nombre': PlutoCell(value: negocio.nombre),
|
||||
'direccion': PlutoCell(value: negocio.direccion),
|
||||
'latitud': PlutoCell(value: negocio.latitud.toString()),
|
||||
'longitud': PlutoCell(value: negocio.longitud.toString()),
|
||||
'tipo_local': PlutoCell(value: negocio.tipoLocal),
|
||||
'fecha_creacion':
|
||||
PlutoCell(value: negocio.fechaCreacion.toString().split(' ')[0]),
|
||||
'logo_url': PlutoCell(
|
||||
value: negocio.logoUrl != null
|
||||
? "${supabaseLU.supabaseUrl}/storage/v1/object/public/nethive/logos/${negocio.logoUrl}?${DateTime.now().millisecondsSinceEpoch}"
|
||||
: '',
|
||||
),
|
||||
'imagen_url': PlutoCell(
|
||||
value: negocio.imagenUrl != null
|
||||
? "${supabaseLU.supabaseUrl}/storage/v1/object/public/nethive/imagenes/${negocio.imagenUrl}?${DateTime.now().millisecondsSinceEpoch}"
|
||||
: '',
|
||||
),
|
||||
'editar': PlutoCell(value: negocio.id),
|
||||
'eliminar': PlutoCell(value: negocio.id),
|
||||
'ver_componentes': PlutoCell(value: negocio.id),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Métodos para subir archivos
|
||||
Future<void> selectLogo() async {
|
||||
logoFileName = null;
|
||||
logoToUpload = null;
|
||||
|
||||
FilePickerResult? picker = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'jpeg'],
|
||||
);
|
||||
|
||||
if (picker != null) {
|
||||
var now = DateTime.now();
|
||||
var formatter = DateFormat('yyyyMMddHHmmss');
|
||||
var timestamp = formatter.format(now);
|
||||
|
||||
logoFileName = 'logo-$timestamp-${picker.files.single.name}';
|
||||
logoToUpload = picker.files.single.bytes;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> selectImagen() async {
|
||||
imagenFileName = null;
|
||||
imagenToUpload = null;
|
||||
|
||||
FilePickerResult? picker = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['jpg', 'png', 'jpeg'],
|
||||
);
|
||||
|
||||
if (picker != null) {
|
||||
var now = DateTime.now();
|
||||
var formatter = DateFormat('yyyyMMddHHmmss');
|
||||
var timestamp = formatter.format(now);
|
||||
|
||||
imagenFileName = 'imagen-$timestamp-${picker.files.single.name}';
|
||||
imagenToUpload = picker.files.single.bytes;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<String?> uploadLogo() async {
|
||||
if (logoToUpload != null && logoFileName != null) {
|
||||
await supabaseLU.storage.from('nethive/logos').uploadBinary(
|
||||
logoFileName!,
|
||||
logoToUpload!,
|
||||
fileOptions: const FileOptions(
|
||||
cacheControl: '3600',
|
||||
upsert: false,
|
||||
),
|
||||
);
|
||||
return logoFileName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> uploadImagen() async {
|
||||
if (imagenToUpload != null && imagenFileName != null) {
|
||||
await supabaseLU.storage.from('nethive/imagenes').uploadBinary(
|
||||
imagenFileName!,
|
||||
imagenToUpload!,
|
||||
fileOptions: const FileOptions(
|
||||
cacheControl: '3600',
|
||||
upsert: false,
|
||||
),
|
||||
);
|
||||
return imagenFileName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// CRUD Empresas
|
||||
Future<bool> crearEmpresa({
|
||||
required String nombre,
|
||||
required String rfc,
|
||||
required String direccion,
|
||||
required String telefono,
|
||||
required String email,
|
||||
}) async {
|
||||
try {
|
||||
final logoUrl = await uploadLogo();
|
||||
final imagenUrl = await uploadImagen();
|
||||
|
||||
final res = await supabaseLU.from('empresa').insert({
|
||||
'nombre': nombre,
|
||||
'rfc': rfc,
|
||||
'direccion': direccion,
|
||||
'telefono': telefono,
|
||||
'email': email,
|
||||
'logo_url': logoUrl,
|
||||
'imagen_url': imagenUrl,
|
||||
}).select();
|
||||
|
||||
if (res.isNotEmpty) {
|
||||
await getEmpresas();
|
||||
resetFormData();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error en crearEmpresa: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> crearNegocio({
|
||||
required String empresaId,
|
||||
required String nombre,
|
||||
required String direccion,
|
||||
required double latitud,
|
||||
required double longitud,
|
||||
required String tipoLocal,
|
||||
}) async {
|
||||
try {
|
||||
final logoUrl = await uploadLogo();
|
||||
final imagenUrl = await uploadImagen();
|
||||
|
||||
final res = await supabaseLU.from('negocio').insert({
|
||||
'empresa_id': empresaId,
|
||||
'nombre': nombre,
|
||||
'direccion': direccion,
|
||||
'latitud': latitud,
|
||||
'longitud': longitud,
|
||||
'tipo_local': tipoLocal,
|
||||
'logo_url': logoUrl,
|
||||
'imagen_url': imagenUrl,
|
||||
}).select();
|
||||
|
||||
if (res.isNotEmpty) {
|
||||
await getNegociosPorEmpresa(empresaId);
|
||||
resetFormData();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('Error en crearNegocio: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> eliminarEmpresa(String empresaId) async {
|
||||
try {
|
||||
// Primero eliminar todos los negocios asociados
|
||||
await supabaseLU.from('negocio').delete().eq('empresa_id', empresaId);
|
||||
|
||||
// Luego eliminar la empresa
|
||||
await supabaseLU.from('empresa').delete().eq('id', empresaId);
|
||||
|
||||
await getEmpresas();
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error en eliminarEmpresa: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> eliminarNegocio(String negocioId) async {
|
||||
try {
|
||||
await supabaseLU.from('negocio').delete().eq('id', negocioId);
|
||||
|
||||
if (empresaSeleccionadaId != null) {
|
||||
await getNegociosPorEmpresa(empresaSeleccionadaId!);
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('Error en eliminarNegocio: ${e.toString()}');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Métodos de utilidad
|
||||
void setEmpresaSeleccionada(String empresaId) {
|
||||
empresaSeleccionadaId = empresaId;
|
||||
empresaSeleccionada = empresas.firstWhere((e) => e.id == empresaId);
|
||||
getNegociosPorEmpresa(empresaId);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void resetFormData() {
|
||||
logoFileName = null;
|
||||
imagenFileName = null;
|
||||
logoToUpload = null;
|
||||
imagenToUpload = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void buscarEmpresas(String busqueda) {
|
||||
getEmpresas(busqueda.isEmpty ? null : busqueda);
|
||||
}
|
||||
|
||||
Widget? getImageWidget(dynamic image,
|
||||
{double height = 100, double width = 100}) {
|
||||
if (image == null || image.toString().isEmpty) {
|
||||
return Container(
|
||||
height: height,
|
||||
width: width,
|
||||
color: Colors.grey[300],
|
||||
child: const Icon(Icons.image_not_supported),
|
||||
);
|
||||
} else if (image is Uint8List) {
|
||||
return Image.memory(
|
||||
image,
|
||||
height: height,
|
||||
width: width,
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
} else if (image is String) {
|
||||
return Image.network(
|
||||
image,
|
||||
height: height,
|
||||
width: width,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return Container(
|
||||
height: height,
|
||||
width: width,
|
||||
color: Colors.grey[300],
|
||||
child: const Icon(Icons.broken_image),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -65,23 +65,47 @@ abstract class AppTheme {
|
||||
abstract Color formBackground;
|
||||
|
||||
Gradient blueGradient = const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment(4, 0.8),
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFF0090FF),
|
||||
Color(0xFF0363C8),
|
||||
Color(0xFF063E9B),
|
||||
Color(0xFF0A0859),
|
||||
Color(0xFF1E40AF), // Azul profundo
|
||||
Color(0xFF3B82F6), // Azul brillante
|
||||
Color(0xFF0369A1), // Azul medio
|
||||
Color(0xFF0F172A), // Azul muy oscuro
|
||||
],
|
||||
);
|
||||
|
||||
Gradient primaryGradient = const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment(4, 0.8),
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFF6C5DD3),
|
||||
Color(0xFF090046),
|
||||
Color(0xFF05002A),
|
||||
Color(0xFF10B981), // Verde esmeralda
|
||||
Color(0xFF059669), // Verde intenso
|
||||
Color(0xFF0D9488), // Verde-azulado
|
||||
Color(0xFF0F172A), // Azul muy oscuro
|
||||
],
|
||||
);
|
||||
|
||||
// Nuevo gradiente para elementos modernos
|
||||
Gradient modernGradient = const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: <Color>[
|
||||
Color(0xFF1E40AF), // Azul profundo
|
||||
Color(0xFF3B82F6), // Azul brillante
|
||||
Color(0xFF10B981), // Verde esmeralda
|
||||
Color(0xFF7C3AED), // Púrpura
|
||||
],
|
||||
);
|
||||
|
||||
// Gradiente para backgrounds oscuros
|
||||
Gradient darkBackgroundGradient = const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: <Color>[
|
||||
Color(0xFF0F172A), // Azul muy oscuro
|
||||
Color(0xFF1E293B), // Azul oscuro
|
||||
Color(0xFF334155), // Azul gris
|
||||
],
|
||||
);
|
||||
|
||||
@@ -111,37 +135,39 @@ abstract class AppTheme {
|
||||
|
||||
class LightModeTheme extends AppTheme {
|
||||
@override
|
||||
Color primaryColor = const Color(0xFF663DD9);
|
||||
Color primaryColor = const Color(0xFF3B82F6); // Azul brillante del login
|
||||
@override
|
||||
Color secondaryColor = const Color(0xFF12142D);
|
||||
Color secondaryColor = const Color(0xFF10B981); // Verde esmeralda del login
|
||||
@override
|
||||
Color tertiaryColor = const Color(0xFF14B095);
|
||||
Color tertiaryColor = const Color(0xFF0369A1); // Azul medio del login
|
||||
@override
|
||||
Color alternate = const Color(0xFFFECE05);
|
||||
Color alternate = const Color(0xFF7C3AED); // Púrpura del login
|
||||
@override
|
||||
Color primaryBackground = const Color(0xFFFFFFFF);
|
||||
@override
|
||||
Color secondaryBackground = const Color(0xFFF9F9F9);
|
||||
Color secondaryBackground = const Color(0xFFF8FAFC); // Gris muy claro
|
||||
@override
|
||||
Color tertiaryBackground = const Color(0XFFF1F0F0);
|
||||
Color tertiaryBackground = const Color(0xFFF1F5F9); // Gris claro azulado
|
||||
@override
|
||||
Color transparentBackground = const Color(0XFF4D4D4D).withOpacity(.2);
|
||||
Color transparentBackground =
|
||||
const Color(0xFF1E293B).withOpacity(.1); // Azul oscuro transparente
|
||||
@override
|
||||
Color primaryText = const Color(0xFF12142D);
|
||||
Color primaryText = const Color(0xFF0F172A); // Azul muy oscuro del login
|
||||
@override
|
||||
Color secondaryText = const Color(0XFF000000);
|
||||
Color secondaryText = const Color(0xFF1E293B); // Azul oscuro
|
||||
@override
|
||||
Color tertiaryText = const Color(0XFF747474);
|
||||
Color tertiaryText = const Color(0xFF64748B); // Gris azulado
|
||||
@override
|
||||
Color hintText = const Color(0XFF8A88A0);
|
||||
Color hintText = const Color(0xFF94A3B8); // Gris claro
|
||||
@override
|
||||
Color error = const Color(0XFFF44A49);
|
||||
Color error = const Color(0xFFEF4444); // Rojo moderno
|
||||
@override
|
||||
Color warning = const Color(0XFFF5AB1A);
|
||||
Color warning = const Color(0xFFF59E0B); // Amarillo moderno
|
||||
@override
|
||||
Color success = const Color(0XFF3AC170);
|
||||
Color success = const Color(0xFF10B981); // Verde esmeralda del login
|
||||
@override
|
||||
Color formBackground = const Color(0xFF663DD9).withOpacity(.2);
|
||||
Color formBackground =
|
||||
const Color(0xFF3B82F6).withOpacity(.05); // Azul muy claro
|
||||
|
||||
LightModeTheme({Mode? mode}) {
|
||||
if (mode != null) {
|
||||
@@ -156,37 +182,40 @@ class LightModeTheme extends AppTheme {
|
||||
|
||||
class DarkModeTheme extends AppTheme {
|
||||
@override
|
||||
Color primaryColor = const Color(0xFF6C5DD3);
|
||||
Color primaryColor = const Color(0xFF3B82F6); // Azul brillante del login
|
||||
@override
|
||||
Color secondaryColor = const Color(0xFF098BF7);
|
||||
Color secondaryColor = const Color(0xFF10B981); // Verde esmeralda del login
|
||||
@override
|
||||
Color tertiaryColor = const Color(0xFF14B095);
|
||||
Color tertiaryColor = const Color(0xFF0369A1); // Azul medio del login
|
||||
@override
|
||||
Color alternate = const Color(0xFFFECE05);
|
||||
Color alternate = const Color(0xFF7C3AED); // Púrpura del login
|
||||
@override
|
||||
Color primaryBackground = Color(0xFF292929);
|
||||
Color primaryBackground =
|
||||
const Color(0xFF0F172A); // Azul muy oscuro del login
|
||||
@override
|
||||
Color secondaryBackground = Color(0xFF414141);
|
||||
Color secondaryBackground = const Color(0xFF1E293B); // Azul oscuro del login
|
||||
@override
|
||||
Color tertiaryBackground = Color(0xFF343434);
|
||||
Color tertiaryBackground = const Color(0xFF334155); // Azul gris
|
||||
@override
|
||||
Color transparentBackground = const Color(0XFF4D4D4D).withOpacity(.2);
|
||||
Color transparentBackground =
|
||||
const Color(0xFF1E293B).withOpacity(.3); // Azul oscuro transparente
|
||||
@override
|
||||
Color primaryText = Color(0xFFD7D7D7);
|
||||
Color primaryText = const Color(0xFFFFFFFF); // Blanco para contraste
|
||||
@override
|
||||
Color secondaryText = Color(0xFF5C63C8);
|
||||
Color secondaryText = const Color(0xFFF1F5F9); // Gris muy claro
|
||||
@override
|
||||
Color tertiaryText = const Color(0XFF747474);
|
||||
Color tertiaryText = const Color(0xFF94A3B8); // Gris azulado claro
|
||||
@override
|
||||
Color hintText = const Color(0XFF8A88A0);
|
||||
Color hintText = const Color(0xFF64748B); // Gris medio
|
||||
@override
|
||||
Color error = const Color(0XFFF44A49);
|
||||
Color error = const Color(0xFFEF4444); // Rojo moderno
|
||||
@override
|
||||
Color warning = const Color(0XFFF5AB1A);
|
||||
Color warning = const Color(0xFFF59E0B); // Amarillo moderno
|
||||
@override
|
||||
Color success = const Color(0XFF3AC170);
|
||||
Color success = const Color(0xFF10B981); // Verde esmeralda del login
|
||||
@override
|
||||
Color formBackground = const Color(0xFF663DD9).withOpacity(.2);
|
||||
Color formBackground =
|
||||
const Color(0xFF3B82F6).withOpacity(.1); // Azul transparente
|
||||
|
||||
DarkModeTheme({Mode? mode}) {
|
||||
if (mode != null) {
|
||||
|
||||
Reference in New Issue
Block a user