Compare commits
No commits in common. "319f7234c500f0753b692c0b30bb04329de39c3c" and "4ee5a99cb117ddde35b392346599467dd58d8b4d" have entirely different histories.
319f7234c5
...
4ee5a99cb1
3
.gitignore
vendored
3
.gitignore
vendored
@ -420,6 +420,3 @@ FodyWeavers.xsd
|
|||||||
*.tar
|
*.tar
|
||||||
/Core/obj/Core.csproj.nuget.g.props
|
/Core/obj/Core.csproj.nuget.g.props
|
||||||
/Domain/obj/Domain.csproj.nuget.dgspec.json
|
/Domain/obj/Domain.csproj.nuget.dgspec.json
|
||||||
/Domain/obj/Domain.csproj.nuget.g.props
|
|
||||||
/Models/obj/Models.csproj.nuget.g.props
|
|
||||||
/phronCare.API/obj/Debug/net8.0/ApiEndpoints.json
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace Core.Interfaces
|
|||||||
Task<byte[]> ExportFilteredInstitutionsToExcelAsync(InstitutionSearchParams searchParams);
|
Task<byte[]> ExportFilteredInstitutionsToExcelAsync(InstitutionSearchParams searchParams);
|
||||||
Task<PagedResult<EInstitution>> GetAllAsync(int page = 1, int pageSize = 50);
|
Task<PagedResult<EInstitution>> GetAllAsync(int page = 1, int pageSize = 50);
|
||||||
Task<EInstitution?> GetByIdAsync(int id);
|
Task<EInstitution?> GetByIdAsync(int id);
|
||||||
Task<PagedResult<EInstitution>> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50);
|
Task<PagedResult<EInstitution>> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50);
|
||||||
Task<bool> UpdateAsync(EInstitution entity);
|
Task<bool> UpdateAsync(EInstitution entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,11 +66,11 @@ namespace Core.Services
|
|||||||
throw new ArgumentException("Debe seleccionar un tipo de institución.");
|
throw new ArgumentException("Debe seleccionar un tipo de institución.");
|
||||||
return await _repository.UpdateAsync(entity);
|
return await _repository.UpdateAsync(entity);
|
||||||
}
|
}
|
||||||
public async Task<PagedResult<EInstitution>> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50)
|
public async Task<PagedResult<EInstitution>> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _repository.SearchAsync(name, type, province, page, pageSize);
|
return await _repository.SearchAsync(name, city, province, page, pageSize);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -88,7 +88,7 @@ namespace Core.Services
|
|||||||
{
|
{
|
||||||
var searchResult = await SearchAsync(
|
var searchResult = await SearchAsync(
|
||||||
searchParams.Name,
|
searchParams.Name,
|
||||||
searchParams.Type,
|
searchParams.City,
|
||||||
searchParams.Province,
|
searchParams.Province,
|
||||||
searchParams.Page,
|
searchParams.Page,
|
||||||
searchParams.PageSize
|
searchParams.PageSize
|
||||||
|
|||||||
@ -1,25 +1,20 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
namespace Domain.Entities
|
||||||
|
|
||||||
namespace Domain.Entities
|
|
||||||
{
|
{
|
||||||
public partial class EInstitution
|
public partial class EInstitution
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
[Required(ErrorMessage = "El nombre de la institucion es obligatorio.")]
|
|
||||||
public string Name { get; set; } = null!;
|
public string Name { get; set; } = null!;
|
||||||
[Required(ErrorMessage = "El tipo de institucion es obligatorio.")]
|
|
||||||
public string Type { get; set; } = null!;
|
public string Type { get; set; } = null!;
|
||||||
public string? Streetaddress { get; set; }
|
public string? Streetaddress { get; set; }
|
||||||
public string? City { get; set; }
|
public string? City { get; set; }
|
||||||
[Required(ErrorMessage = "La provincia es obligatoria.")]
|
public string? Province { get; set; }
|
||||||
public string? Province { get; set; } = string.Empty;
|
|
||||||
public string? Phone { get; set; }
|
public string? Phone { get; set; }
|
||||||
public string? Email { get; set; }
|
public string? Email { get; set; }
|
||||||
public string? Operatingroominfo { get; set; }
|
public string? Operatingroominfo { get; set; }
|
||||||
public DateTime Createdat { get; set; }
|
public DateTime Createdat { get; set; }
|
||||||
public bool Isactive { get; set; }
|
public bool Isactive { get; set; }
|
||||||
public double? Latitude { get; set; } = 0;
|
public double? Latitude { get; set; }
|
||||||
public double? Longitude { get; set; } = 0;
|
public double? Longitude { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
public class InstitutionSearchParams :PagedRequest
|
public class InstitutionSearchParams :PagedRequest
|
||||||
{
|
{
|
||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public string? Type { get; set; }
|
public string? City { get; set; }
|
||||||
public string? Province { get; set; }
|
public string? Province { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace Models.Interfaces
|
|||||||
Task<EInstitution?> GetByIdAsync(int id);
|
Task<EInstitution?> GetByIdAsync(int id);
|
||||||
Task<PagedResult<EInstitution>> SearchAsync(
|
Task<PagedResult<EInstitution>> SearchAsync(
|
||||||
string? name,
|
string? name,
|
||||||
string? type,
|
string? city,
|
||||||
string? province,
|
string? province,
|
||||||
int page = 1,
|
int page = 1,
|
||||||
int pageSize = 50);
|
int pageSize = 50);
|
||||||
|
|||||||
@ -33,7 +33,7 @@ namespace Models.Repositories
|
|||||||
var entity = await _context.PhSInstitutions.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
|
var entity = await _context.PhSInstitutions.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id);
|
||||||
return entity == null ? null : EntityMapper.MapEntity<PhSInstitution, EInstitution>(entity);
|
return entity == null ? null : EntityMapper.MapEntity<PhSInstitution, EInstitution>(entity);
|
||||||
}
|
}
|
||||||
public async Task<PagedResult<EInstitution>> SearchAsync(string? name, string? type, string? province, int page = 1, int pageSize = 50)
|
public async Task<PagedResult<EInstitution>> SearchAsync(string? name, string? city, string? province, int page = 1, int pageSize = 50)
|
||||||
{
|
{
|
||||||
var query = _context.PhSInstitutions.AsQueryable();
|
var query = _context.PhSInstitutions.AsQueryable();
|
||||||
|
|
||||||
@ -43,10 +43,10 @@ namespace Models.Repositories
|
|||||||
query = query.Where(i => i.Name.ToLower().Contains(lowered));
|
query = query.Where(i => i.Name.ToLower().Contains(lowered));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(type))
|
if (!string.IsNullOrWhiteSpace(city))
|
||||||
{
|
{
|
||||||
var lowered = type.ToLower();
|
var lowered = city.ToLower();
|
||||||
query = query.Where(i => i.Type != null && i.Type.ToLower().Contains(lowered));
|
query = query.Where(i => i.City != null && i.City.ToLower().Contains(lowered));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(province))
|
if (!string.IsNullOrWhiteSpace(province))
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
|
||||||
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\maski\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
|
||||||
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
|
||||||
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.2</NuGetToolVersion>
|
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.13.1</NuGetToolVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
|
||||||
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
<SourceRoot Include="C:\Users\maski\.nuget\packages\" />
|
||||||
|
|||||||
@ -33,14 +33,14 @@ namespace phronCare.API.Controllers.Sales
|
|||||||
[HttpGet("search")]
|
[HttpGet("search")]
|
||||||
public async Task<IActionResult> Search(
|
public async Task<IActionResult> Search(
|
||||||
[FromQuery] string? name,
|
[FromQuery] string? name,
|
||||||
[FromQuery] string? type,
|
[FromQuery] string? city,
|
||||||
[FromQuery] string? province,
|
[FromQuery] string? province,
|
||||||
[FromQuery] int page = 1,
|
[FromQuery] int page = 1,
|
||||||
[FromQuery] int pageSize = 50)
|
[FromQuery] int pageSize = 50)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _institutionService.SearchAsync(name, type, province, page, pageSize);
|
var result = await _institutionService.SearchAsync(name, city, province, page, pageSize);
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@ -664,7 +664,7 @@
|
|||||||
"IsRequired": false
|
"IsRequired": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "type",
|
"Name": "city",
|
||||||
"Type": "System.String",
|
"Type": "System.String",
|
||||||
"IsRequired": false
|
"IsRequired": false
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,195 +0,0 @@
|
|||||||
@page "/sales/institutionform"
|
|
||||||
@page "/sales/institutionform/{InstitutionId:int?}"
|
|
||||||
@using System.ComponentModel.DataAnnotations
|
|
||||||
@using phronCare.UIBlazor.Services.Sales
|
|
||||||
@using phronCare.UIBlazor.Pages.Shared.Modals
|
|
||||||
|
|
||||||
@inject InstitutionService institutionService
|
|
||||||
@inject IToastService ToastService
|
|
||||||
@inject NavigationManager Navigation
|
|
||||||
@inject IModalService Modal
|
|
||||||
|
|
||||||
<div class="card" style="zoom:80%">
|
|
||||||
<div class="card-header d-flex justify-content-center align-items-center">
|
|
||||||
<h3 class="card-title m-0">@((InstitutionId.HasValue ? "Editar institución" : "Nueva institución"))</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<EditForm Model="_model">
|
|
||||||
<DataAnnotationsValidator />
|
|
||||||
<ValidationSummary />
|
|
||||||
|
|
||||||
<!-- Fila 1: Nombre de la institución -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<label for="Name">Nombre:</label>
|
|
||||||
<InputText id="Name" @bind-Value="_model.Name" class="form-control" />
|
|
||||||
<ValidationMessage For="@(() => _model.Name)" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label for="Type">Tipo de institución:</label>
|
|
||||||
<InputSelect id="Type" @bind-Value="_model.Type" class="form-control">
|
|
||||||
<option value="">--- Seleccionar ---</option>
|
|
||||||
<option value="Sanatorio">Sanatorio</option>
|
|
||||||
<option value="Clínica">Clínica</option>
|
|
||||||
<option value="Hospital">Hospital</option>
|
|
||||||
</InputSelect>
|
|
||||||
<ValidationMessage For="@(() => _model.Type)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Fila 3: Dirección -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<label for="Streetaddress">Dirección:</label>
|
|
||||||
<InputText id="Streetaddress" @bind-Value="_model.Streetaddress" class="form-control" />
|
|
||||||
<ValidationMessage For="@(() => _model.Streetaddress)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Fila 4: Ciudad, Provincia, Teléfono -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label for="City">Ciudad:</label>
|
|
||||||
<InputText id="City" @bind-Value="_model.City" class="form-control" />
|
|
||||||
<ValidationMessage For="@(() => _model.City)" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label for="Province">Provincia:</label>
|
|
||||||
<InputSelect id="Province" @bind-Value="_model.Province" class="form-control">
|
|
||||||
<option value="">--- Seleccionar ---</option>
|
|
||||||
@foreach (var province in provinces)
|
|
||||||
{
|
|
||||||
<option value="@province">@province</option>
|
|
||||||
}
|
|
||||||
</InputSelect>
|
|
||||||
<ValidationMessage For="@(() => _model.Province)" />
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<label for="Phone">Teléfono:</label>
|
|
||||||
<InputText id="Phone" @bind-Value="_model.Phone" class="form-control" />
|
|
||||||
<ValidationMessage For="@(() => _model.Phone)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Fila 7: Mapas - Ubicación -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="row">
|
|
||||||
<!-- Columna izquierda: campos Latitud y Longitud -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="Email">Email:</label>
|
|
||||||
<InputText id="Email" @bind-Value="_model.Email" class="form-control" />
|
|
||||||
<ValidationMessage For="@(() => _model.Email)" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="Operatingroominfo">Información sobre quirófanos:</label>
|
|
||||||
<InputTextArea id="Operatingroominfo" @bind-Value="_model.Operatingroominfo" class="form-control" rows="3" />
|
|
||||||
<ValidationMessage For="@(() => _model.Operatingroominfo)" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="Latitude" class="form-label">Latitud</label>
|
|
||||||
<InputNumber @bind-Value="_model.Latitude" class="form-control" id="Latitude" />
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="Longitude" class="form-label">Longitud</label>
|
|
||||||
<InputNumber @bind-Value="_model.Longitude" class="form-control" id="Longitude" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Columna derecha: mapa -->
|
|
||||||
<div class="col-md-6" style="zoom:80%">
|
|
||||||
@if (_model.Latitude.HasValue && _model.Longitude.HasValue)
|
|
||||||
{
|
|
||||||
<PhMap Latitude="@_model.Latitude.Value"
|
|
||||||
Longitude="@_model.Longitude.Value"
|
|
||||||
Zoom="13"
|
|
||||||
OnLocationChanged="HandleLocationChanged" />
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<div class="text-muted">Ingrese coordenadas para visualizar el mapa</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</EditForm>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
<div class="d-flex justify-content-end align-items-center py-3">
|
|
||||||
<button class="btn btn-primary me-2" type="button" @onclick="HandleValidSubmit" disabled="@isSaving"> @(isSaving ? "Guardando..." : "Guardar institución") </button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="NavigateBack">Cancelar</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
[Parameter] public int? InstitutionId { get; set; }
|
|
||||||
[Parameter] public string? returnUrl { get; set; } = "/sales/institutions";
|
|
||||||
private string searchQuery = string.Empty;
|
|
||||||
|
|
||||||
private EInstitution _model = new();
|
|
||||||
private bool isSaving = false;
|
|
||||||
private List<string> provinces = new()
|
|
||||||
{
|
|
||||||
"Buenos Aires", "CABA", "Catamarca", "Chaco", "Chubut", "Córdoba", "Corrientes",
|
|
||||||
"Entre Ríos", "Formosa", "Jujuy", "La Pampa", "La Rioja", "Mendoza", "Misiones",
|
|
||||||
"Neuquén", "Río Negro", "Salta", "San Juan", "San Luis", "Santa Cruz",
|
|
||||||
"Santa Fe", "Santiago del Estero", "Tierra del Fuego", "Tucumán"
|
|
||||||
};
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
if (InstitutionId.HasValue)
|
|
||||||
{
|
|
||||||
_model = await institutionService.GetByIdAsync(InstitutionId.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleLocationChanged((double lat, double lng) location)
|
|
||||||
{
|
|
||||||
_model.Latitude = location.lat;
|
|
||||||
_model.Longitude = location.lng;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleValidSubmit()
|
|
||||||
{
|
|
||||||
var parameters = new ModalParameters();
|
|
||||||
parameters.Add("Message", "¿Desea guardar los cambios de la institución?");
|
|
||||||
var modal = Modal.Show<ConfirmModal>("Confirmación", parameters);
|
|
||||||
var result = await modal.Result;
|
|
||||||
|
|
||||||
if (result.Cancelled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpResponseMessage response;
|
|
||||||
|
|
||||||
if (_model.Id == 0)
|
|
||||||
response = await institutionService.CreateAsync(_model);
|
|
||||||
else
|
|
||||||
response = await institutionService.UpdateAsync(_model);
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
ToastService.ShowSuccess("Institución guardada correctamente.");
|
|
||||||
NavigateBack();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var error = await response.Content.ReadAsStringAsync();
|
|
||||||
ToastService.ShowError($"Error: {error}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ToastService.ShowError($"Error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NavigateBack()
|
|
||||||
{
|
|
||||||
Navigation.NavigateTo(returnUrl ?? "/sales/institutions");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,190 +0,0 @@
|
|||||||
@page "/sales/institutions"
|
|
||||||
@using phronCare.UIBlazor.Services.Sales
|
|
||||||
@using phronCare.UIBlazor.Data
|
|
||||||
@using Domain.Entities
|
|
||||||
@using Domain.Generics
|
|
||||||
@using Domain.SearchParams
|
|
||||||
@inject IToastService toastService
|
|
||||||
@inject NavigationManager Navigation
|
|
||||||
@inject InstitutionService institutionService
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header d-flex justify-content-center align-items-center" style="zoom:80%;">
|
|
||||||
<h3 class="card-title m-0">Búsqueda de instituciones</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body" style="zoom:80%;">
|
|
||||||
<div class="mb-4 space-y-2">
|
|
||||||
<input @bind="SearchParams.Name" placeholder="Nombre de la institución" class="border rounded p-1 w-full" />
|
|
||||||
<input @bind="SearchParams.Type" placeholder="Tipo (Hospital, Clínica...)" class="border rounded p-1 w-full" />
|
|
||||||
<input @bind="SearchParams.Province" placeholder="Provincia de la institución" class="border rounded p-1 w-full" />
|
|
||||||
<button class="btn btn-primary rounded-pill" @onclick="BuscarInstituciones">
|
|
||||||
<i class="fas fa-binoculars me-1"></i> Buscar
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-success rounded-pill" @onclick="NuevaInstitucion">
|
|
||||||
<i class="fas fa-plus me-1"></i> Nueva
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-success rounded-pill" @onclick="ExportarExcel">
|
|
||||||
<i class="fas fa-file-excel me-1"></i> Excel
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary rounded-pill" @onclick="Volver">
|
|
||||||
<i class="fas fa-arrow-left me-1"></i> Volver
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div>
|
|
||||||
@if (TablaInstituciones != null && TablaInstituciones.Any())
|
|
||||||
{
|
|
||||||
<PhTable Columns="TableColumns"
|
|
||||||
Data="TablaInstituciones"
|
|
||||||
SelectionField="Id"
|
|
||||||
RowsPerPage=SearchParams.PageSize
|
|
||||||
RenderButtons="true" Buttons="botones"
|
|
||||||
ShowPageButtons="false"
|
|
||||||
ShowQuickSearch="false"
|
|
||||||
RenderSelect="false" />
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<p>No hay resultados.</p>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer d-flex justify-content-center align-items-center" style="zoom:80%;">
|
|
||||||
<div class="d-flex align-items-center gap-3">
|
|
||||||
<button class="btn btn-secondary rounded-pill" @onclick="PrimeraPagina" disabled="@(SearchParams.Page == 1)">
|
|
||||||
<i class="fas fa-angle-double-left me-1"></i> Primera
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary rounded-pill" @onclick="AnteriorPagina" disabled="@(!PuedeRetroceder)">
|
|
||||||
<i class="fas fa-chevron-left me-1"></i> Anterior
|
|
||||||
</button>
|
|
||||||
<span class="mx-2">
|
|
||||||
Página <strong>@SearchParams.Page</strong> de <strong>@TotalPaginas</strong>
|
|
||||||
</span>
|
|
||||||
<button class="btn btn-secondary rounded-pill" @onclick="SiguientePagina" disabled="@(!PuedeAvanzar)">
|
|
||||||
Siguiente <i class="fas fa-chevron-right ms-1"></i>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-secondary rounded-pill" @onclick="UltimaPagina" disabled="@(SearchParams.Page == TotalPaginas)">
|
|
||||||
Última <i class="fas fa-angle-double-right ms-1"></i>
|
|
||||||
</button>
|
|
||||||
<div class="d-flex align-items-center ms-3">
|
|
||||||
<input type="number" class="form-control form-control-sm rounded" style="width: 80px;" min="1" max="@TotalPaginas" @bind="PaginaDeseada" />
|
|
||||||
<button class="btn btn-outline-primary btn-sm ms-2 rounded-pill" @onclick="IrAPagina">
|
|
||||||
<i class="fas fa-arrow-right-to-bracket me-1"></i> Ir
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private InstitutionSearchParams SearchParams = new();
|
|
||||||
private PagedResult<EInstitution>? PagedResult;
|
|
||||||
private List<Dictionary<string, object>> TablaInstituciones = new();
|
|
||||||
private List<string> TableColumns = new()
|
|
||||||
{
|
|
||||||
"Id", "Nombre", "Tipo", "Dirección", "Ciudad", "Provincia", "Teléfono", "Email", "Activo"
|
|
||||||
};
|
|
||||||
private int PaginaDeseada = 1;
|
|
||||||
|
|
||||||
private List<PhTable.ButtonOptions> botones;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
botones = new List<PhTable.ButtonOptions>
|
|
||||||
{
|
|
||||||
new PhTable.ButtonOptions
|
|
||||||
{
|
|
||||||
Caption = "Editar",
|
|
||||||
ElementClass = "btn btn-primary btn-sm",
|
|
||||||
UrlAction = "/sales/institutionform/",
|
|
||||||
OnClickAction = async (id) =>
|
|
||||||
{
|
|
||||||
if (int.TryParse(id, out var instId))
|
|
||||||
{
|
|
||||||
Navigation.NavigateTo($"/sales/institutionform/{instId}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task BuscarInstituciones() => await CargarInstituciones();
|
|
||||||
|
|
||||||
private async Task CargarInstituciones()
|
|
||||||
{
|
|
||||||
PagedResult = await institutionService.SearchInstitutionsAsync(SearchParams);
|
|
||||||
if (PagedResult?.Items is not null)
|
|
||||||
{
|
|
||||||
TablaInstituciones = PagedResult.Items.Select(i => new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "Id", i.Id },
|
|
||||||
{ "Nombre", i.Name ?? string.Empty },
|
|
||||||
{ "Tipo", i.Type ?? string.Empty },
|
|
||||||
{ "Dirección", i.Streetaddress ?? string.Empty },
|
|
||||||
{ "Ciudad", i.City ?? string.Empty },
|
|
||||||
{ "Provincia", i.Province ?? string.Empty },
|
|
||||||
{ "Teléfono", i.Phone ?? string.Empty },
|
|
||||||
{ "Email", i.Email ?? string.Empty },
|
|
||||||
{ "Activo", i.Isactive ? "Sí" : "No" }
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PrimeraPagina() { SearchParams.Page = 1; await BuscarInstituciones(); }
|
|
||||||
private async Task UltimaPagina() { SearchParams.Page = TotalPaginas; await BuscarInstituciones(); }
|
|
||||||
private async Task SiguientePagina() => await CambiarPagina(1);
|
|
||||||
private async Task AnteriorPagina() => await CambiarPagina(-1);
|
|
||||||
|
|
||||||
private async Task CambiarPagina(int delta)
|
|
||||||
{
|
|
||||||
var nuevaPagina = SearchParams.Page + delta;
|
|
||||||
if (nuevaPagina >= 1 && nuevaPagina <= TotalPaginas)
|
|
||||||
{
|
|
||||||
SearchParams.Page = nuevaPagina;
|
|
||||||
await BuscarInstituciones();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task IrAPagina()
|
|
||||||
{
|
|
||||||
if (PaginaDeseada >= 1 && PaginaDeseada <= TotalPaginas)
|
|
||||||
{
|
|
||||||
SearchParams.Page = PaginaDeseada;
|
|
||||||
await BuscarInstituciones();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toastService.ShowWarning("Número de página fuera de rango.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ExportarExcel()
|
|
||||||
{
|
|
||||||
var exportParams = new InstitutionSearchParams
|
|
||||||
{
|
|
||||||
Name = SearchParams.Name,
|
|
||||||
Type = SearchParams.Type,
|
|
||||||
Province = SearchParams.Province,
|
|
||||||
Page = 1,
|
|
||||||
PageSize = int.MaxValue
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await institutionService.ExportFilteredAsync(exportParams);
|
|
||||||
toastService.ShowSuccess("Exportación completada exitosamente.");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
toastService.ShowError($"{ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NuevaInstitucion() => Navigation.NavigateTo("/sales/institutionform/");
|
|
||||||
private void Volver() => Navigation.NavigateTo("/DashboardPanel");
|
|
||||||
|
|
||||||
private bool PuedeRetroceder => PagedResult != null && SearchParams.Page > 1;
|
|
||||||
private bool PuedeAvanzar => PagedResult != null && SearchParams.Page < TotalPaginas;
|
|
||||||
private int TotalPaginas => PagedResult is null ? 1 :
|
|
||||||
(int)Math.Ceiling((double)(PagedResult.TotalItems) / SearchParams.PageSize);
|
|
||||||
}
|
|
||||||
@ -44,7 +44,6 @@ builder.Services.AddScoped<TaxConditionService>();
|
|||||||
builder.Services.AddScoped<AccountTypeService>();
|
builder.Services.AddScoped<AccountTypeService>();
|
||||||
builder.Services.AddScoped<PatientService>();
|
builder.Services.AddScoped<PatientService>();
|
||||||
builder.Services.AddScoped<DocumentTypeService>();
|
builder.Services.AddScoped<DocumentTypeService>();
|
||||||
builder.Services.AddScoped<InstitutionService>();
|
|
||||||
builder.Services.AddScoped<ProductService>();
|
builder.Services.AddScoped<ProductService>();
|
||||||
builder.Services.AddScoped<BusinessUnitService>();
|
builder.Services.AddScoped<BusinessUnitService>();
|
||||||
builder.Services.AddScoped<ProductCategoryService>();
|
builder.Services.AddScoped<ProductCategoryService>();
|
||||||
|
|||||||
@ -1,88 +0,0 @@
|
|||||||
using Domain.Entities;
|
|
||||||
using Domain.Generics;
|
|
||||||
using System.Net.Http.Json;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.JSInterop;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace phronCare.UIBlazor.Services.Sales
|
|
||||||
{
|
|
||||||
public class InstitutionService
|
|
||||||
{
|
|
||||||
private readonly HttpClient _http;
|
|
||||||
private readonly IJSRuntime _js;
|
|
||||||
|
|
||||||
public InstitutionService(HttpClient http, IJSRuntime js)
|
|
||||||
{
|
|
||||||
_http = http;
|
|
||||||
_js = js;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener todas las instituciones
|
|
||||||
public async Task<List<EInstitution>> GetAllAsync()
|
|
||||||
{
|
|
||||||
var result = await _http.GetFromJsonAsync<List<EInstitution>>("/api/Institution/all");
|
|
||||||
return result ?? new List<EInstitution>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener institución por ID
|
|
||||||
public async Task<EInstitution> GetByIdAsync(int id)
|
|
||||||
{
|
|
||||||
var result = await _http.GetFromJsonAsync<EInstitution>($"/api/Institution/{id}");
|
|
||||||
return result ?? new EInstitution();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crear una nueva institución
|
|
||||||
public async Task<HttpResponseMessage> CreateAsync(EInstitution institution)
|
|
||||||
{
|
|
||||||
return await _http.PostAsJsonAsync("/api/Institution/create", institution);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actualizar una institución existente
|
|
||||||
public async Task<HttpResponseMessage> UpdateAsync(EInstitution institution)
|
|
||||||
{
|
|
||||||
return await _http.PutAsJsonAsync("/api/Institution/update", institution);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buscar instituciones con parámetros de búsqueda (paginación)
|
|
||||||
public async Task<PagedResult<EInstitution>?> SearchInstitutionsAsync(InstitutionSearchParams searchParams)
|
|
||||||
{
|
|
||||||
var url = $"api/Institution/search?" +
|
|
||||||
$"name={searchParams.Name}&" +
|
|
||||||
$"type={searchParams.Type}&" +
|
|
||||||
$"province={searchParams.Province}&" +
|
|
||||||
$"page={searchParams.Page}&" +
|
|
||||||
$"pageSize={searchParams.PageSize}";
|
|
||||||
return await _http.GetFromJsonAsync<PagedResult<EInstitution>>(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exportar instituciones filtradas
|
|
||||||
public async Task ExportFilteredAsync(InstitutionSearchParams searchParams)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var content = new StringContent(JsonSerializer.Serialize(searchParams), Encoding.UTF8, "application/json");
|
|
||||||
var response = await _http.PostAsync("api/Institution/exportfiltered", content);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var errorContent = await response.Content.ReadAsStringAsync();
|
|
||||||
throw new Exception(errorContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytes = await response.Content.ReadAsByteArrayAsync();
|
|
||||||
var base64 = Convert.ToBase64String(bytes);
|
|
||||||
var timestamp = DateTime.Now.ToString("yyyyMMddHHmm");
|
|
||||||
var fileName = $"{timestamp}_instituciones.xlsx";
|
|
||||||
await _js.InvokeVoidAsync("saveAsFile", fileName, base64);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var methodName = MethodBase.GetCurrentMethod()?.Name ?? "UnknownMethod";
|
|
||||||
var message = ex.Message ?? "No message provided";
|
|
||||||
throw new Exception($"{message}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,14 +2,13 @@
|
|||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
@* <div class="row">
|
<div class="row">
|
||||||
@foreach (var item in Items)
|
@foreach (var item in Items)
|
||||||
{
|
{
|
||||||
<div class=@DashboardClass>
|
<div class=@DashboardClass>
|
||||||
<div class="circle-tile">
|
<div class="circle-tile">
|
||||||
<p>
|
<p>
|
||||||
<div class="circle-tile-heading @item.MainColor">
|
<div class="circle-tile-heading @item.MainColor"><br />
|
||||||
<br />
|
|
||||||
<i class="@item.Icon"></i>
|
<i class="@item.Icon"></i>
|
||||||
</div>
|
</div>
|
||||||
</p>
|
</p>
|
||||||
@ -21,6 +20,9 @@
|
|||||||
<div class="circle-tile-number text-faded" style="color: @item.ValueColor;">
|
<div class="circle-tile-number text-faded" style="color: @item.ValueColor;">
|
||||||
@item.Value
|
@item.Value
|
||||||
</div>
|
</div>
|
||||||
|
@* <!-- Utiliza el método NavigateToUrl para manejar la navegación -->
|
||||||
|
<a class="circle-tile-footer" @onclick="() => NavigateToUrl(item.Url)">More Info <i class="fa fa-chevron-circle-right"></i></a>
|
||||||
|
*@ <!-- RENDERIZAR FOOTER TIPO ONCLICK-->
|
||||||
@if (item.OnClickAction is not null)
|
@if (item.OnClickAction is not null)
|
||||||
{
|
{
|
||||||
<a class="circle-tile-footer" @onclick="async () => await item.OnClickAction(item.OnClickParam)">More Info <i class="fa fa-chevron-circle-right"></i></a>
|
<a class="circle-tile-footer" @onclick="async () => await item.OnClickAction(item.OnClickParam)">More Info <i class="fa fa-chevron-circle-right"></i></a>
|
||||||
@ -34,26 +36,14 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
*@
|
</div>
|
||||||
<!-- MAPA DE EJEMPLO -->
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col-12">
|
|
||||||
<div class="card shadow rounded-3">
|
|
||||||
<div class="card-header bg-light">
|
|
||||||
<strong>Ubicación de ejemplo</strong>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<PhMap Latitude="-34.618998"
|
|
||||||
Longitude="-58.501015" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter] public List<DashboardItem> Items { get; set; } = new List<DashboardItem>();
|
[Parameter] public List<DashboardItem> Items { get; set; } = new List<DashboardItem>();
|
||||||
[Parameter] public string DashboardClass { get; set; } = string.Empty;
|
[Parameter]
|
||||||
|
public string DashboardClass { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
private string cUrlAction = string.Empty;
|
||||||
|
|
||||||
public class DashboardItem
|
public class DashboardItem
|
||||||
{
|
{
|
||||||
@ -64,15 +54,9 @@
|
|||||||
public string MainColor { get; set; } = string.Empty;
|
public string MainColor { get; set; } = string.Empty;
|
||||||
public string ValueColor { get; set; } = string.Empty;
|
public string ValueColor { get; set; } = string.Empty;
|
||||||
public string Url { get; set; } = string.Empty;
|
public string Url { get; set; } = string.Empty;
|
||||||
public Func<string?, Task>? OnClickAction { get; set; }
|
public Func<string?,Task>? OnClickAction { get; set; }
|
||||||
public string? OnClickParam { get; set; }
|
public string? OnClickParam { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NavigateToUrl(string url) => Navigation.NavigateTo(url);
|
private void NavigateToUrl(string url) => Navigation.NavigateTo(url);
|
||||||
|
|
||||||
private void OnMapChanged((double Lat, double Lng) loc)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Nueva ubicación desde el mapa: {loc.Lat}, {loc.Lng}");
|
|
||||||
// Aquí podrías guardar en una variable, mostrar en UI, o integrarlo con lógica posterior
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
@using phronCare.UIBlazor.Shared.Services
|
|
||||||
@inject IJSRuntime JS
|
|
||||||
|
|
||||||
|
|
||||||
<div class="card mt-2">
|
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
|
||||||
<span><i class="fas fa-map-marker-alt me-2"></i>Mapa de Ubicación</span>
|
|
||||||
<div class="d-flex gap-2">
|
|
||||||
@if (EnableAddressSearch)
|
|
||||||
{
|
|
||||||
<input @bind="SearchAddress"
|
|
||||||
@bind:event="oninput"
|
|
||||||
class="form-control form-control-sm"
|
|
||||||
placeholder="Buscar dirección..."
|
|
||||||
style="width: 250px;" />
|
|
||||||
<button class="btn btn-sm btn-outline-primary" @onclick="CenterByAddress" title="Buscar">
|
|
||||||
<i class="fas fa-search-location"></i>
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
<button class="btn btn-sm btn-outline-secondary" @onclick="OpenGoogleMaps" title="Abrir en Google Maps">
|
|
||||||
<i class="fab fa-google me-1"></i>Ver en Google Maps
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body p-0" style="height: 400px;">
|
|
||||||
<div id="@MapDivId" style="height: 100%; width: 100%;"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private string MapDivId = $"map_{Guid.NewGuid()}";
|
|
||||||
public static PhMap? CurrentInstance { get; private set; }
|
|
||||||
|
|
||||||
private double _latitude = -34.6037;
|
|
||||||
private double _longitude = -58.3816;
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public double Latitude
|
|
||||||
{
|
|
||||||
get => _latitude;
|
|
||||||
set => _latitude = value;
|
|
||||||
}
|
|
||||||
[Parameter]
|
|
||||||
public double Longitude
|
|
||||||
{
|
|
||||||
get => _longitude;
|
|
||||||
set => _longitude = value;
|
|
||||||
}
|
|
||||||
[Parameter] public int Zoom { get; set; } = 13;
|
|
||||||
[Parameter] public bool EnableAddressSearch { get; set; } = true;
|
|
||||||
[Parameter] public EventCallback<(double lat, double lng)> OnLocationChanged { get; set; }
|
|
||||||
|
|
||||||
private string SearchAddress { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
if (firstRender)
|
|
||||||
{
|
|
||||||
MapInterop.RegisterInstance(this); // ✅ esto conecta con MapInterop.cs
|
|
||||||
await Task.Delay(100);
|
|
||||||
await JS.InvokeVoidAsync("phMap.initMap", MapDivId, Latitude, Longitude, Zoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private async Task CenterByAddress()
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(SearchAddress)) await JS.InvokeVoidAsync("phMap.searchAddress", MapDivId, SearchAddress);
|
|
||||||
}
|
|
||||||
private void OpenGoogleMaps()
|
|
||||||
{
|
|
||||||
var url = $"https://www.google.com/maps?q={_latitude.ToString(System.Globalization.CultureInfo.InvariantCulture)},{_longitude.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
|
|
||||||
JS.InvokeVoidAsync("window.open", url, "_blank");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -81,11 +81,6 @@
|
|||||||
<li aria-hidden="true"></li> Productos
|
<li aria-hidden="true"></li> Productos
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item px-1">
|
|
||||||
<NavLink class="nav-link" href="sales/institutions/">
|
|
||||||
<li aria-hidden="true"></li> Instituciones
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
using Microsoft.JSInterop;
|
|
||||||
using phronCare.UIBlazor.Shared.Components;
|
|
||||||
|
|
||||||
namespace phronCare.UIBlazor.Shared.Services
|
|
||||||
{
|
|
||||||
public static class MapInterop
|
|
||||||
{
|
|
||||||
private static PhMap? CurrentInstance;
|
|
||||||
public static void RegisterInstance(PhMap instance)
|
|
||||||
{
|
|
||||||
CurrentInstance = instance;
|
|
||||||
}
|
|
||||||
[JSInvokable("NotifyLocationChanged")]
|
|
||||||
public static async Task NotifyLocationChanged(double lat, double lng)
|
|
||||||
{
|
|
||||||
if (CurrentInstance is not null)
|
|
||||||
{
|
|
||||||
CurrentInstance.Latitude = lat;
|
|
||||||
CurrentInstance.Longitude = lng;
|
|
||||||
await CurrentInstance.OnLocationChanged.InvokeAsync((lat, lng));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -25,8 +25,4 @@
|
|||||||
<ProjectReference Include="..\Domain\Domain.csproj" />
|
<ProjectReference Include="..\Domain\Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Services\NewFolder\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,59 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="es">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
||||||
<title>phronCare.UIBlazor</title>
|
|
||||||
<base href="/" />
|
|
||||||
|
|
||||||
<!-- Estilos propios -->
|
|
||||||
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
|
|
||||||
<link href="css/app.css" rel="stylesheet" />
|
|
||||||
<link href="css/fontawesome-free-6.4.2-web/css/all.min.css" rel="stylesheet" />
|
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
|
||||||
<link href="phronCare.UIBlazor.styles.css" rel="stylesheet" />
|
|
||||||
<!-- Leaflet CSS -->
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
|
|
||||||
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
|
|
||||||
crossorigin="" />
|
|
||||||
|
|
||||||
<!-- Leaflet JS -->
|
|
||||||
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
|
|
||||||
integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
|
|
||||||
crossorigin=""></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="app">
|
|
||||||
<svg class="loading-progress">
|
|
||||||
<circle r="40%" cx="50%" cy="50%" />
|
|
||||||
<circle r="40%" cx="50%" cy="50%" />
|
|
||||||
</svg>
|
|
||||||
<div class="loading-progress-text"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="blazor-error-ui">
|
|
||||||
An unhandled error has occurred.
|
|
||||||
<a href="" class="reload">Reload</a>
|
|
||||||
<a class="dismiss">🗙</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Blazor y JS propios -->
|
|
||||||
<script src="_framework/blazor.webassembly.js"></script>
|
|
||||||
<script src="css/fontawesome-free-6.4.2-web/js/all.min.js"></script>
|
|
||||||
<script src="js/services.js"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Nuestro propio JS -->
|
|
||||||
<script src="js/phmap.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<!--<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
@ -87,4 +32,4 @@
|
|||||||
<script src="js/services.js"></script>
|
<script src="js/services.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>-->
|
</html>
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
window.phMap = {
|
|
||||||
initMap: function (mapId, lat, lng, zoom) {
|
|
||||||
const map = L.map(mapId).setView([lat, lng], zoom);
|
|
||||||
|
|
||||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
||||||
attribution: '© OpenStreetMap contributors'
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
const marker = L.marker([lat, lng]).addTo(map)
|
|
||||||
.bindPopup('Ubicación inicial')
|
|
||||||
.openPopup();
|
|
||||||
|
|
||||||
// Guardamos el mapa y el marcador
|
|
||||||
window._phMaps = window._phMaps || {};
|
|
||||||
window._phMaps[mapId] = { map, marker };
|
|
||||||
|
|
||||||
map.on('click', function (e) {
|
|
||||||
const newLat = e.latlng.lat;
|
|
||||||
const newLng = e.latlng.lng;
|
|
||||||
|
|
||||||
// Mover el marcador existente
|
|
||||||
window._phMaps[mapId].marker.setLatLng([newLat, newLng]);
|
|
||||||
window._phMaps[mapId].marker.getPopup().setContent('Nueva ubicación').openOn(map);
|
|
||||||
|
|
||||||
// Llamar al método en Blazor
|
|
||||||
DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', newLat, newLng);
|
|
||||||
});
|
|
||||||
|
|
||||||
},
|
|
||||||
searchAddress: async function (mapId, address) {
|
|
||||||
const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}`);
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (data.length === 0) {
|
|
||||||
alert("Dirección no encontrada.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lat = parseFloat(data[0].lat);
|
|
||||||
const lon = parseFloat(data[0].lon);
|
|
||||||
|
|
||||||
const mapData = window._phMaps[mapId];
|
|
||||||
if (!mapData) return;
|
|
||||||
|
|
||||||
mapData.map.setView([lat, lon], 15);
|
|
||||||
mapData.marker.setLatLng([lat, lon]);
|
|
||||||
mapData.marker.getPopup().setContent(address.toUpperCase()).openOn(mapData.map);
|
|
||||||
|
|
||||||
DotNet.invokeMethodAsync('phronCare.UIBlazor', 'NotifyLocationChanged', lat, lon);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Loading…
x
Reference in New Issue
Block a user