Upgrade to version 1.4.1.1 with .NET 8.0 support
- Updated application version from 1.3.2.1 to 1.4.1.1. - Dockerfile now uses .NET 8.0 for runtime and SDK. - Added new API endpoints in HospitalController for sections by hospital ID. - Modified UniversityController to retrieve hospitals instead of sections. - Enhanced DocuMed.Api.csproj with new using directives for commands and queries. - Updated AccountService and UserService to handle hospital IDs and sections. - Introduced HospitalId and ProfileType properties in various DTOs. - Updated RestApiWrapper to include new REST API interfaces for hospitals and AI. - Enhanced MedicalHistoryTemplate components with AI interaction features. - Modified CSS files to include new styles and animations. - Introduced new classes and interfaces for AI interactions, including AiController and MetisMessage. - Updated ProfilePage to support hospital selection and related logic. - Revised API endpoints for hospitals and universities for improved data management.master
parent
ab56bf3c20
commit
3fb22c8c48
|
@ -1,9 +1,9 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
ENV ASPNETCORE_URLS=http://0.0.0.0:8010
|
||||
WORKDIR /app
|
||||
EXPOSE 8010
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["DocuMed.Api/DocuMed.Api.csproj", "DocuMed.Api/"]
|
||||
RUN dotnet restore "DocuMed.Api/DocuMed.Api.csproj"
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
namespace DocuMed.Api.Controllers;
|
||||
|
||||
public class AiController : ICarterModule
|
||||
{
|
||||
public void AddRoutes(IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.NewVersionedApi("Ai").MapGroup("api/ai");
|
||||
group.MapPost("chat", ChatAsync)
|
||||
.WithDisplayName("AiChatBot")
|
||||
.HasApiVersion(1.0);
|
||||
}
|
||||
|
||||
private async Task<IResult> ChatAsync([FromBody] MetisMessage message, [FromServices] IRestApiWrapper apiWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var messageRequest = new MetisMessageRequest
|
||||
{
|
||||
message = new MetisMessage
|
||||
{
|
||||
content = message.content
|
||||
}
|
||||
};
|
||||
var response = await apiWrapper.MetisRestApi.SendMessage("7324c5a0-5cad-4239-a8d9-38d99d490493", messageRequest, "tpsg-epC8BoLfa7uSL4ogjlocFLKiW7Un66e");
|
||||
return TypedResults.Ok(response.Content);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
using DocuMed.Domain.CommandQueries.Commands;
|
||||
using DocuMed.Domain.Entities.MedicalHistory;
|
||||
using MediatR;
|
||||
|
||||
namespace DocuMed.Api.Controllers;
|
||||
namespace DocuMed.Api.Controllers;
|
||||
|
||||
public class HospitalController : ICarterModule
|
||||
{
|
||||
|
@ -12,6 +8,9 @@ public class HospitalController : ICarterModule
|
|||
.MapGroup("api/hospital")
|
||||
.RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser());
|
||||
|
||||
group.MapGet("{id}/section", GetSectionsAsync)
|
||||
.WithDisplayName("Get All Sections")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapGet("", GetAllAsync)
|
||||
.WithDisplayName("GetAll")
|
||||
|
@ -31,37 +30,31 @@ public class HospitalController : ICarterModule
|
|||
.HasApiVersion(1.0);
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
private async Task<IResult> GetAllAsync([FromQuery] int page, IMedicalHistoryRepository repository, CancellationToken cancellationToken)
|
||||
// GET:Get All Sections
|
||||
public virtual async Task<IResult> GetSectionsAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||
{
|
||||
return TypedResults.Ok(await repository.GetMedicalHistoriesAsync(page, cancellationToken));
|
||||
return TypedResults.Ok(await repositoryWrapper.SetRepository<Section>().TableNoTracking
|
||||
.Where(s => s.HospitalId == id)
|
||||
.Select(SectionMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
private async Task<IResult> GetAllAsync([FromQuery] int page, IMediator mediator, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await mediator.Send(new GetHospitalsQuery(page), cancellationToken));
|
||||
|
||||
// GET:Get An Entity By Id
|
||||
private async Task<IResult> GetAsync(Guid id, IMedicalHistoryRepository repository, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
return TypedResults.Ok(await repository.GetMedicalHistoryAsync(id, cancellationToken));
|
||||
}
|
||||
private async Task<IResult> GetAsync(Guid id, IMediator mediator, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await mediator.Send(new GetHospitalQuery(id), cancellationToken));
|
||||
|
||||
// POST:Add New Entity
|
||||
private async Task<IResult> Post([FromBody] CreateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||
{
|
||||
return TypedResults.Ok(await service.Send(dto,cancellationToken));
|
||||
}
|
||||
=> TypedResults.Ok(await service.Send(dto, cancellationToken));
|
||||
|
||||
// PUT:Update Entity
|
||||
private async Task<IResult> Put([FromBody] UpdateHospitalCommand dto, IMediator service, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||
{
|
||||
return TypedResults.Ok(await service.Send(dto,cancellationToken));
|
||||
}
|
||||
=> TypedResults.Ok(await service.Send(dto, cancellationToken));
|
||||
|
||||
// DELETE:Delete Entity
|
||||
private async Task<IResult> Delete(Guid id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await repositoryWrapper.SetRepository<MedicalHistory>().GetByIdAsync(cancellationToken, id);
|
||||
repositoryWrapper.SetRepository<MedicalHistory>().Delete(ent);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
return TypedResults.Ok();
|
||||
}
|
||||
private async Task<IResult> Delete(Guid id, IMediator mediator, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await mediator.Send(new DeleteHospitalCommand(id), cancellationToken));
|
||||
}
|
|
@ -14,7 +14,7 @@ public class UniversityController : ICarterModule
|
|||
.WithDisplayName("Get All")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
group.MapGet("{id}/section", GetAllByUniversityAsync)
|
||||
group.MapGet("{id}/hospital", GetHospitalsAsync)
|
||||
.WithDisplayName("Get All Sections")
|
||||
.HasApiVersion(1.0);
|
||||
|
||||
|
@ -34,25 +34,25 @@ public class UniversityController : ICarterModule
|
|||
|
||||
|
||||
// GET:Get All Sections
|
||||
public virtual async Task<IResult> GetAllByUniversityAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||
private async Task<IResult> GetHospitalsAsync(Guid id, IRepositoryWrapper repositoryWrapper, ICurrentUserService currentUserService, CancellationToken cancellationToken)
|
||||
{
|
||||
return TypedResults.Ok(await repositoryWrapper.SetRepository<Section>().TableNoTracking
|
||||
.Where(s => s.HospitalId == id)
|
||||
.Select(SectionMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||
return TypedResults.Ok(await repositoryWrapper.SetRepository<Hospital>().TableNoTracking
|
||||
.Where(s => s.UniversityId == id)
|
||||
.Select(HospitalMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||
}
|
||||
|
||||
// GET:Get All Entity
|
||||
public virtual async Task<IResult> GetAllAsync([FromQuery] int page, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
private async Task<IResult> GetAllAsync([FromQuery] int page, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>()
|
||||
.TableNoTracking
|
||||
.Select(UniversityMapper.ProjectToSDto).ToListAsync(cancellationToken));
|
||||
|
||||
// GET:Get An Entity By Id
|
||||
public async Task<IResult> GetAsync(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
private async Task<IResult> GetAsync(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
=> TypedResults.Ok(await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id));
|
||||
|
||||
// POST:Add New Entity
|
||||
public virtual async Task<IResult> Post([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
private async Task<IResult> Post([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
||||
repositoryWrapper.SetRepository<University>().Add(ent);
|
||||
|
@ -61,7 +61,7 @@ public class UniversityController : ICarterModule
|
|||
}
|
||||
|
||||
// PUT:Update Entity
|
||||
public virtual async Task<IResult> Put([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
private async Task<IResult> Put([FromBody] UniversitySDto dto, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = University.Create(dto.Name,dto.Address,dto.CityId);
|
||||
ent.Id = dto.Id;
|
||||
|
@ -71,7 +71,7 @@ public class UniversityController : ICarterModule
|
|||
}
|
||||
|
||||
// DELETE:Delete Entity
|
||||
public virtual async Task<IResult> Delete(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
private async Task<IResult> Delete(int id, IRepositoryWrapper repositoryWrapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var ent = await repositoryWrapper.SetRepository<University>().GetByIdAsync(cancellationToken, id);
|
||||
repositoryWrapper.SetRepository<University>().Delete(ent);
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
<AssemblyVersion>1.3.2.1</AssemblyVersion>
|
||||
<FileVersion>1.3.2.1</FileVersion>
|
||||
<AssemblyVersion>1.4.1.1</AssemblyVersion>
|
||||
<FileVersion>1.4.1.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -74,10 +74,13 @@
|
|||
<Using Include="DocuMed.Core.EntityServices.Abstracts" />
|
||||
<Using Include="DocuMed.Core.Models.Api" />
|
||||
<Using Include="DocuMed.Domain" />
|
||||
<Using Include="DocuMed.Domain.CommandQueries.Commands" />
|
||||
<Using Include="DocuMed.Domain.CommandQueries.Queries" />
|
||||
<Using Include="DocuMed.Domain.Dtos.LargDtos" />
|
||||
<Using Include="DocuMed.Domain.Dtos.RequestDtos" />
|
||||
<Using Include="DocuMed.Domain.Dtos.SmallDtos" />
|
||||
<Using Include="DocuMed.Domain.Entities.City" />
|
||||
<Using Include="DocuMed.Domain.Entities.Hospitals" />
|
||||
<Using Include="DocuMed.Domain.Entities.MedicalHistoryTemplate" />
|
||||
<Using Include="DocuMed.Domain.Entities.User" />
|
||||
<Using Include="DocuMed.Domain.Enums.QueryFilters" />
|
||||
|
@ -85,12 +88,15 @@
|
|||
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||
<Using Include="DocuMed.Infrastructure" />
|
||||
<Using Include="DocuMed.Infrastructure.Models" />
|
||||
<Using Include="DocuMed.Infrastructure.Models.Metis" />
|
||||
<Using Include="DocuMed.Infrastructure.RestServices" />
|
||||
<Using Include="DocuMed.Repository" />
|
||||
<Using Include="DocuMed.Repository.Abstracts" />
|
||||
<Using Include="DocuMed.Repository.Extensions" />
|
||||
<Using Include="DocuMed.Repository.Models" />
|
||||
<Using Include="DocuMed.Repository.Repositories.Base.Contracts" />
|
||||
<Using Include="DocuMed.Repository.Repositories.Entities.Abstracts" />
|
||||
<Using Include="MediatR" />
|
||||
<Using Include="MediatR.Extensions.Autofac.DependencyInjection" />
|
||||
<Using Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
|
||||
<Using Include="Microsoft.AspNetCore.Identity" />
|
||||
|
|
|
@ -141,6 +141,8 @@ public class AccountService(
|
|||
if (section != null)
|
||||
{
|
||||
token.User.SectionName = section.Name;
|
||||
token.User.SectionId = section.Id;
|
||||
token.User.HospitalId = section.HospitalId;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace DocuMed.Core.EntityServices;
|
||||
using DocuMed.Domain.Entities.Staffs;
|
||||
|
||||
namespace DocuMed.Core.EntityServices;
|
||||
|
||||
|
||||
public class UserService(
|
||||
|
@ -85,6 +87,23 @@ public class UserService(
|
|||
user.BirthDate = request.BirthDate;
|
||||
user.Gender = request.Gender;
|
||||
|
||||
switch (request.ProfileType)
|
||||
{
|
||||
case ProfileType.Student:
|
||||
var student = await repositoryWrapper.SetRepository<Student>().TableNoTracking
|
||||
.FirstOrDefaultAsync(s => s.UserId == user.Id, cancellationToken);
|
||||
if (student == null)
|
||||
throw new AppException("Student not found", ApiResultStatusCode.NotFound);
|
||||
student.SetSection(request.SectionId);
|
||||
repositoryWrapper.SetRepository<Student>().Update(student);
|
||||
await repositoryWrapper.SaveChangesAsync(cancellationToken);
|
||||
break;
|
||||
case ProfileType.Patient:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
if (!result.Succeeded)
|
||||
throw new AppException(string.Join('|', result.Errors));
|
||||
|
|
|
@ -13,4 +13,6 @@ public class UserActionRequestDto
|
|||
public string RoleName { get; set; } = string.Empty;
|
||||
public Guid UniversityId { get; set; }
|
||||
public Guid SectionId { get; set; }
|
||||
public Guid HospitalId { get; set; }
|
||||
public ProfileType ProfileType { get; set; }
|
||||
}
|
|
@ -14,6 +14,8 @@ public class ApplicationUserSDto : BaseDto<ApplicationUserSDto,ApplicationUser>
|
|||
public Gender Gender { get; set; }
|
||||
public SignUpStatus SignUpStatus { get; set; }
|
||||
public Guid UniversityId { get; set; }
|
||||
public Guid HospitalId { get; set; }
|
||||
public string HospitalName { get; set; }
|
||||
public Guid SectionId { get; set; }
|
||||
public string SectionName { get; set; } = string.Empty;
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
namespace DocuMed.Domain.Enums;
|
||||
|
||||
public enum ProfileType
|
||||
{
|
||||
Student,
|
||||
Patient
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Refit" Version="7.2.1" />
|
||||
<PackageReference Include="Refit.Newtonsoft.Json" Version="7.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -27,6 +28,7 @@
|
|||
<Using Include="DocuMed.Core.Abstracts" />
|
||||
<Using Include="DocuMed.Domain.Models.Settings" />
|
||||
<Using Include="DocuMed.Infrastructure.Models" />
|
||||
<Using Include="DocuMed.Infrastructure.Models.Metis" />
|
||||
<Using Include="DocuMed.Infrastructure.Models.RestApi.KaveNegar" />
|
||||
<Using Include="DocuMed.Infrastructure.RestServices" />
|
||||
<Using Include="Microsoft.Extensions.Logging" />
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace DocuMed.Infrastructure.Models.Metis;
|
||||
|
||||
public class CreateSessionRequestDto
|
||||
{
|
||||
public string BotId { get; set; } = string.Empty;
|
||||
public MetisUser? User { get; set; }
|
||||
public MetisMessageRequest? InitializeMessage { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
namespace DocuMed.Infrastructure.Models.Metis;
|
||||
|
||||
public class MetisMessageRequest
|
||||
{
|
||||
public MetisMessage message { get; set; } = new();
|
||||
}
|
||||
|
||||
public class MetisMessage
|
||||
{
|
||||
public string content { get; set; } = string.Empty;
|
||||
public string type { get; set; } = "USER";
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace DocuMed.Infrastructure.Models.Metis;
|
||||
|
||||
public class MetisMessageResponse
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string Content { get; set; } = string.Empty;
|
||||
public object Attachments { get; set; } = string.Empty;
|
||||
public long Timestamp { get; set; }
|
||||
public string FinishReason { get; set; } = string.Empty;
|
||||
public object Citations { get; set; } = string.Empty;
|
||||
public object ToolCalls { get; set; } = string.Empty;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace DocuMed.Infrastructure.Models.Metis;
|
||||
|
||||
public class MetisUser
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Id { get; set; } = Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace DocuMed.Infrastructure.RestServices;
|
||||
|
||||
public interface IMetisRestApi
|
||||
{
|
||||
[Post("/chat/session")]
|
||||
public Task CreateSession(string sessionId, [Body] CreateSessionRequestDto request, [Header("x-api-key")] string metisToken);
|
||||
|
||||
[Post("/chat/session/{sessionId}/message")]
|
||||
public Task<MetisMessageResponse> SendMessage(string sessionId, [Body] MetisMessageRequest request, [Header("x-api-key")] string metisToken);
|
||||
|
||||
[Post("/chat/session/{sessionId}/message/stream")]
|
||||
public Task<MetisMessageResponse> SendStreamMessage(string sessionId, [Body] MetisMessageRequest request, [Header("x-api-key")] string metisToken);
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
namespace DocuMed.Infrastructure.RestServices;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DocuMed.Infrastructure.RestServices;
|
||||
|
||||
public interface IRestApiWrapper : IScopedDependency
|
||||
{
|
||||
IKaveNegarRestApi KaveNegarRestApi { get; }
|
||||
|
||||
IMetisRestApi MetisRestApi { get; }
|
||||
}
|
||||
|
||||
public class RestApiWrapper : IRestApiWrapper
|
||||
{
|
||||
private static readonly RefitSettings setting = new RefitSettings(new NewtonsoftJsonContentSerializer(new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||
|
||||
}));
|
||||
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
|
||||
public IMetisRestApi MetisRestApi => RestService.For<IMetisRestApi>("https://api.metisai.ir/api/v1", setting);
|
||||
}
|
|
@ -7,8 +7,8 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
|
||||
<AssemblyVersion>1.3.2.1</AssemblyVersion>
|
||||
<FileVersion>1.3.2.1</FileVersion>
|
||||
<AssemblyVersion>1.4.1.1</AssemblyVersion>
|
||||
<FileVersion>1.4.1.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -8,12 +8,15 @@ public static class Address
|
|||
#else
|
||||
public static string BaseAddress = "https://api.documed.ir/api";
|
||||
#endif
|
||||
|
||||
public static string AuthController = $"{BaseAddress}/auth";
|
||||
public static string CityController = $"{BaseAddress}/city";
|
||||
public static string UniversityController = $"{BaseAddress}/university";
|
||||
public static string AiController = $"{BaseAddress}/ai";
|
||||
public static string SectionController = $"{BaseAddress}/section";
|
||||
public static string UserController = $"{BaseAddress}/user";
|
||||
public static string MedicalHistoryTemplateController = $"{BaseAddress}/medicalhistory/template";
|
||||
public static string MedicalHistoryController = $"{BaseAddress}/medicalhistory";
|
||||
public static string PatientController = $"{BaseAddress}/patient";
|
||||
public static string HospitalController = $"{BaseAddress}/hospital";
|
||||
}
|
|
@ -221,7 +221,7 @@
|
|||
{
|
||||
var token = await UserUtility.GetBearerTokenAsync();
|
||||
var user = await UserUtility.GetUserAsync();
|
||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(user.UniversityId, token);
|
||||
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(user.HospitalId, token);
|
||||
|
||||
if (section.IsNullOrEmpty())
|
||||
return Sections;
|
||||
|
|
|
@ -27,17 +27,17 @@
|
|||
</MudCarouselItem>
|
||||
<MudCarouselItem>
|
||||
<div class="flex flex-col h-full p-4">
|
||||
<MedicalHistoryTemplateActionStep2 PiQuestions="@ViewModel.PiQuestions" />
|
||||
<MedicalHistoryTemplateActionStep2 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" PiQuestions="@ViewModel.PiQuestions" />
|
||||
</div>
|
||||
</MudCarouselItem>
|
||||
<MudCarouselItem>
|
||||
<div class="flex flex-col h-full p-4">
|
||||
<MedicalHistoryTemplateActionStep3 PdhQuestions="@ViewModel.PdhQuestions" PshQuestions="@ViewModel.PshQuestions" />
|
||||
<MedicalHistoryTemplateActionStep3 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" PdhQuestions="@ViewModel.PdhQuestions" PshQuestions="@ViewModel.PshQuestions" />
|
||||
</div>
|
||||
</MudCarouselItem>
|
||||
<MudCarouselItem>
|
||||
<div class="flex flex-col h-full p-4">
|
||||
<MedicalHistoryTemplateActionStep4 FamilyHistories="@ViewModel.FhQuestions" DrugHistories="@ViewModel.DhQuestions" AhMedicines="@ViewModel.AhQuestions" />
|
||||
<MedicalHistoryTemplateActionStep4 ChiefComplaint="@ViewModel.PageDto.ChiefComplaint" FamilyHistories="@ViewModel.FhQuestions" DrugHistories="@ViewModel.DhQuestions" AhMedicines="@ViewModel.AhQuestions" />
|
||||
</div>
|
||||
</MudCarouselItem>
|
||||
<MudCarouselItem>
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
{
|
||||
var token = await UserUtility.GetBearerTokenAsync();
|
||||
var user = await UserUtility.GetUserAsync();
|
||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(user.UniversityId, token);
|
||||
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(user.HospitalId, token);
|
||||
|
||||
if (section.IsNullOrEmpty())
|
||||
return Sections;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
||||
@inject IRestWrapper RestWrapper
|
||||
@inject ISnackbar Snackbar
|
||||
<MudStack class="pb-20 font-iranyekan">
|
||||
<BasePartDivider Index="2" Title="تاریخچه بیماری فعلی ( PI )" />
|
||||
|
||||
|
@ -19,24 +20,47 @@
|
|||
Variant="Variant.Outlined" />
|
||||
|
||||
@* <MudAutocomplete T="string" Label="وابستگی به سوال قبلی" Variant="Variant.Outlined" /> *@
|
||||
|
||||
<MudButton @onclick="AddQuestion" Variant="Variant.Filled" DisableElevation="true"
|
||||
class="font-extrabold text-lg right-0 rounded-md py-3 bg-[--color-medicalhistory] text-gray-800">
|
||||
class="font-extrabold text-lg right-0 rounded-md py-3 bg-[--color-medicalhistory] text-gray-800">
|
||||
+ افزودن
|
||||
</MudButton>
|
||||
|
||||
@AiResponse
|
||||
|
||||
<button @onclick="AskWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||
از هوش مصنوعی بپرس !
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@if (IsProcessing)
|
||||
{
|
||||
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||
در حال فکر کردن ....
|
||||
</p>
|
||||
}
|
||||
|
||||
</MudStack>
|
||||
|
||||
@* focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 focus:ring-offset-slate-50 *@
|
||||
|
||||
@code
|
||||
{
|
||||
private MedicalHistoryQuestionType _questionType;
|
||||
private string _questionTitle = string.Empty;
|
||||
private MedicalHistoryPart _questionPart = MedicalHistoryPart.PresentIllness;
|
||||
private bool IsProcessing { get; set; }
|
||||
private MarkupString AiResponse { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public List<MedicalHistoryQuestionSDto> PiQuestions { get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public string ChiefComplaint { get; set; } = string.Empty;
|
||||
|
||||
private void RemoveQuestion(MedicalHistoryQuestionSDto question)
|
||||
{
|
||||
PiQuestions.Remove(question);
|
||||
|
@ -44,11 +68,43 @@
|
|||
private void AddQuestion()
|
||||
{
|
||||
PiQuestions.Add(new MedicalHistoryQuestionSDto
|
||||
{
|
||||
Part = _questionPart,
|
||||
Question = _questionTitle,
|
||||
QuestionType = _questionType
|
||||
});
|
||||
{
|
||||
Part = _questionPart,
|
||||
Question = _questionTitle,
|
||||
QuestionType = _questionType
|
||||
});
|
||||
_questionTitle = string.Empty;
|
||||
}
|
||||
|
||||
private async Task AskWithAi()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
IsProcessing = true;
|
||||
var request = new
|
||||
{
|
||||
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش PI (Present Illness) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||
};
|
||||
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||
response = response.Replace("```html", null);
|
||||
response = response.Replace("```", null);
|
||||
response = response.Replace("\\n", null);
|
||||
response = response.Replace(@"""", null);
|
||||
AiResponse = (MarkupString)response;
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Snackbar.Add(e.Message, Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
||||
|
||||
@inject IRestWrapper RestWrapper
|
||||
@inject ISnackbar Snackbar
|
||||
<MudStack class="pb-20 font-iranyekan">
|
||||
<BasePartDivider Index="3" Title="تاریخچه بیماری قبلی ( PMH )" />
|
||||
|
||||
|
@ -22,6 +22,25 @@
|
|||
+ افزودن
|
||||
</MudButton>
|
||||
|
||||
@AiPMHResponse
|
||||
|
||||
<button @onclick="AskPMHWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||
از هوش مصنوعی بپرس !
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@if (IsProcessing)
|
||||
{
|
||||
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||
در حال فکر کردن ....
|
||||
</p>
|
||||
}
|
||||
|
||||
|
||||
<BasePartDivider Index="4" class="mt-9" Title="تاریخچه جراحی های قبلی ( PSH )" />
|
||||
|
||||
@foreach (var item in PshQuestions)
|
||||
|
@ -50,6 +69,23 @@
|
|||
+ افزودن
|
||||
</MudButton>
|
||||
|
||||
@AiPSHResponse
|
||||
|
||||
<button @onclick="AskPSHWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||
از هوش مصنوعی بپرس !
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@if (IsProcessing)
|
||||
{
|
||||
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||
در حال فکر کردن ....
|
||||
</p>
|
||||
}
|
||||
|
||||
</MudStack>
|
||||
|
||||
|
@ -60,11 +96,12 @@
|
|||
[Parameter]
|
||||
public List<MedicalHistoryQuestionSDto> PshQuestions { get; set; } = new();
|
||||
|
||||
|
||||
private string _pdhQuestionTitle = string.Empty;
|
||||
private MedicalHistoryQuestionType _pdhQuestionType;
|
||||
private string _pshQuestionTitle = string.Empty;
|
||||
private MedicalHistoryQuestionType _pshQuestionType;
|
||||
[Parameter]
|
||||
public string ChiefComplaint { get; set; } = string.Empty;
|
||||
|
||||
private void RemovePiQuestion(MedicalHistoryQuestionSDto question)
|
||||
{
|
||||
|
@ -96,4 +133,72 @@
|
|||
_pshQuestionTitle = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
private bool IsProcessing { get; set; }
|
||||
private MarkupString AiPMHResponse { get; set; }
|
||||
private async Task AskPMHWithAi()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
IsProcessing = true;
|
||||
var request = new
|
||||
{
|
||||
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش تاریخچه بیماری قبلی ( Past Medical History ) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||
};
|
||||
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||
response = response.Replace("```html", null);
|
||||
response = response.Replace("```", null);
|
||||
response = response.Replace("\\n", null);
|
||||
response = response.Replace(@"""", null);
|
||||
AiPMHResponse = (MarkupString)response;
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Snackbar.Add(e.Message, Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private MarkupString AiPSHResponse { get; set; }
|
||||
private async Task AskPSHWithAi()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
IsProcessing = true;
|
||||
var request = new
|
||||
{
|
||||
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش تاریخچه جراحی های قبلی ( Past Surgery History ) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||
};
|
||||
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||
response = response.Replace("```html", null);
|
||||
response = response.Replace("```", null);
|
||||
response = response.Replace("\\n", null);
|
||||
response = response.Replace(@"""", null);
|
||||
AiPSHResponse = (MarkupString)response;
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Snackbar.Add(e.Message, Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
@using DocuMed.Domain.Entities.MedicalHistoryTemplate
|
||||
@inject IRestWrapper RestWrapper
|
||||
@inject ISnackbar Snackbar
|
||||
<MudStack class="pb-20 font-iranyekan">
|
||||
<BasePartDivider Index="5" Title="تاریخچه بیماری های خانوادگی ( FH )" />
|
||||
|
||||
|
@ -22,6 +23,23 @@
|
|||
+ افزودن
|
||||
</MudButton>
|
||||
|
||||
@AiResponse
|
||||
|
||||
<button @onclick="AskWithAi" class="relative inline-flex h-12 overflow-hidden rounded-full p-[1px] ">
|
||||
<span class="absolute inset-[-1000%] animate-[spin_2s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,#E2CBFF_0%,#393BB2_50%,#E2CBFF_100%)]"></span>
|
||||
<span class="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-white px-4 py-2 text-sm font-medium text-black backdrop-blur-3xl">
|
||||
<p class="font-bold bg-gradient-to-r from-sky-600 via-violet-500 to-fuchsia-400 inline-block text-transparent bg-clip-text">
|
||||
از هوش مصنوعی بپرس !
|
||||
</p>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@if (IsProcessing)
|
||||
{
|
||||
<p class="mx-2 -mt-2 bg-gradient-to-r from-sky-600 via-blue-500 to-violet-400 inline-block text-transparent bg-clip-text">
|
||||
در حال فکر کردن ....
|
||||
</p>
|
||||
}
|
||||
|
||||
<BasePartDivider Index="6" class="mt-9" Title="داروهای مصرفی ( DH )" />
|
||||
|
||||
|
@ -66,9 +84,14 @@
|
|||
</div>
|
||||
|
||||
|
||||
|
||||
</MudStack>
|
||||
@code {
|
||||
@code
|
||||
{
|
||||
private bool IsProcessing { get; set; }
|
||||
private MarkupString AiResponse { get; set; }
|
||||
[Parameter]
|
||||
public string ChiefComplaint { get; set; } = string.Empty;
|
||||
|
||||
private string _familyHistoryQuestionTitle = string.Empty;
|
||||
private MedicalHistoryQuestionType _familyHistoryQuestionType;
|
||||
[Parameter]
|
||||
|
@ -125,4 +148,37 @@
|
|||
});
|
||||
_hhName = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
private async Task AskWithAi()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
IsProcessing = true;
|
||||
var request = new
|
||||
{
|
||||
content = $"شکایت اصلی بیمار (CC) {ChiefComplaint} است. لطفاً سوالات بخش PI (Present Illness) را در سه دسته زیر تولید کنید: سوالات توضیحی (Open-ended): سوالاتی که بیمار باید توضیح دهد. سوالات بله/خیر (Yes/No): سوالاتی که پاسخ مشخص بله یا خیر دارند. سوالات زمانی (Time-based): سوالاتی مرتبط با زمان شروع، مدت و تغییرات مشکل. لطفاً سوالات مرتبط با سردرد شامل شدت، محل، عوامل تشدیدکننده یا تسکیندهنده و علائم همراه (مثل تهوع یا تاری دید) باشد. use html concept for response and just send html and remove , head , html and body tag"
|
||||
};
|
||||
var response = await RestWrapper.AiRestApi.ChatAsync(request);
|
||||
response = response.Replace("```html", null);
|
||||
response = response.Replace("```", null);
|
||||
response = response.Replace("\\n", null);
|
||||
response = response.Replace(@"""", null);
|
||||
AiResponse = (MarkupString)response;
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Snackbar.Add(e.Message, Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsProcessing = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,25 @@
|
|||
</ItemTemplate>
|
||||
</MudAutocomplete>
|
||||
|
||||
<MudAutocomplete @bind-Value="@ViewModel.SelectedHospital"
|
||||
ToStringFunc="dto => dto.Name"
|
||||
SearchFunc="@ViewModel.SearchHospital"
|
||||
T="HospitalSDto" Label="بیمارستان" Variant="Variant.Outlined">
|
||||
<ProgressIndicatorInPopoverTemplate>
|
||||
<MudList Clickable="false">
|
||||
<MudListItem>
|
||||
<div class="flex flex-row w-full mx-auto">
|
||||
<MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
|
||||
<p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
|
||||
</div>
|
||||
</MudListItem>
|
||||
</MudList>
|
||||
</ProgressIndicatorInPopoverTemplate>
|
||||
<ItemTemplate Context="e">
|
||||
<p>@e.Name</p>
|
||||
</ItemTemplate>
|
||||
</MudAutocomplete>
|
||||
|
||||
<MudAutocomplete T="SectionSDto" Label="بخش فعلی" Variant="Variant.Outlined"
|
||||
ToStringFunc="dto => dto.Name"
|
||||
SearchFunc="@ViewModel.SearchSection"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using DocuMed.Domain.Entities.City;
|
||||
using DocuMed.Domain.Entities.Hospitals;
|
||||
using Mapster;
|
||||
|
||||
namespace DocuMed.PWA.Pages;
|
||||
|
@ -18,10 +19,12 @@ public class ProfilePageViewModel(
|
|||
|
||||
public List<CitySDto> Cities { get; private set; } = new List<CitySDto>();
|
||||
public List<UniversitySDto> Universities { get; private set; } = new List<UniversitySDto>();
|
||||
public List<HospitalSDto> Hospitals { get; private set; } = new List<HospitalSDto>();
|
||||
public List<SectionSDto> Sections { get; private set; } = new List<SectionSDto>();
|
||||
public SectionSDto? SelectedSection { get; set; }
|
||||
public CitySDto? SelectedCity { get; set; }
|
||||
public UniversitySDto? SelectedUni { get; set; }
|
||||
public HospitalSDto? SelectedHospital { get; set; }
|
||||
|
||||
public readonly string Version = Assembly.GetAssembly(typeof(Program))?.GetName()?.Version?.ToString() ?? string.Empty;
|
||||
|
||||
|
@ -37,12 +40,14 @@ public class ProfilePageViewModel(
|
|||
{
|
||||
SelectedUni = Universities.FirstOrDefault(u => u.Id == User.UniversityId);
|
||||
SelectedCity = Cities.FirstOrDefault(c => c.Id == SelectedUni?.CityId);
|
||||
if (SelectedUni != null)
|
||||
if (SelectedHospital != null)
|
||||
{
|
||||
if (User.SectionId != Guid.Empty)
|
||||
{
|
||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(SelectedUni.Id, token);
|
||||
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(SelectedHospital.Id, token);
|
||||
SelectedSection = Sections.FirstOrDefault(s => s.Id == User.SectionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await base.InitializeAsync();
|
||||
|
@ -55,6 +60,7 @@ public class ProfilePageViewModel(
|
|||
IsProcessing = true;
|
||||
var token = await UserUtility.GetBearerTokenAsync();
|
||||
var request = User.Adapt<UserActionRequestDto>();
|
||||
request.ProfileType = ProfileType.Student;
|
||||
if (SelectedUni != null)
|
||||
{
|
||||
request.UniversityId = SelectedUni.Id;
|
||||
|
@ -66,6 +72,13 @@ public class ProfilePageViewModel(
|
|||
User.SectionId = SelectedSection.Id;
|
||||
User.SectionName = SelectedSection.Name;
|
||||
}
|
||||
|
||||
if (SelectedHospital != null)
|
||||
{
|
||||
request.HospitalId = SelectedHospital.Id;
|
||||
User.HospitalId = SelectedHospital.Id;
|
||||
User.HospitalName = SelectedHospital.Name;
|
||||
}
|
||||
await RestWrapper.UserRestApi.UpdateUserAsync(request, token);
|
||||
await UserUtility.SetUserAsync(User);
|
||||
Snackbar.Add("ویرایش حساب کاربری با موفقیت انجام شد", Severity.Success);
|
||||
|
@ -92,8 +105,6 @@ public class ProfilePageViewModel(
|
|||
navigationManager.NavigateTo("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<IEnumerable<CitySDto>> SearchCity(string city)
|
||||
{
|
||||
try
|
||||
|
@ -123,10 +134,10 @@ public class ProfilePageViewModel(
|
|||
{
|
||||
try
|
||||
{
|
||||
if (SelectedUni != null)
|
||||
if (SelectedHospital != null)
|
||||
{
|
||||
var token = await UserUtility.GetBearerTokenAsync();
|
||||
Sections = await RestWrapper.SectionRestApi.GetByUniversityAsync(SelectedUni.Id, token);
|
||||
Sections = await RestWrapper.HospitalRestApi.GetSectionsAsync(SelectedHospital.Id, token);
|
||||
}
|
||||
if (section.IsNullOrEmpty())
|
||||
return Sections;
|
||||
|
@ -169,4 +180,29 @@ public class ProfilePageViewModel(
|
|||
return Universities;
|
||||
}
|
||||
}
|
||||
public async Task<IEnumerable<HospitalSDto>> SearchHospital(string hospital)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SelectedUni != null)
|
||||
{
|
||||
var token = await UserUtility.GetBearerTokenAsync();
|
||||
Hospitals = await RestWrapper.UniversityRestApi.GetHospitalsAsync(SelectedUni.Id, token);
|
||||
}
|
||||
if (hospital.IsNullOrEmpty())
|
||||
return Hospitals;
|
||||
return Hospitals.Where(c => c.Name.Contains(hospital));
|
||||
}
|
||||
catch (ApiException ex)
|
||||
{
|
||||
var exe = await ex.GetContentAsAsync<ApiResult>();
|
||||
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
|
||||
return Hospitals;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Snackbar.Add(e.Message, Severity.Error);
|
||||
return Hospitals;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace DocuMed.PWA.Services.RestServices;
|
||||
|
||||
public interface IAiRestApi
|
||||
{
|
||||
[Post("/chat")]
|
||||
public Task<string> ChatAsync([Body]object request);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace DocuMed.PWA.Services.RestServices;
|
||||
|
||||
public interface IHospitalRestApi
|
||||
{
|
||||
[Get("/{hospitalId}/section")]
|
||||
Task<List<SectionSDto>> GetSectionsAsync(Guid hospitalId, [Header("Authorization")] string authorization);
|
||||
}
|
|
@ -12,4 +12,7 @@ public interface IRestWrapper
|
|||
public IUserRestApi UserRestApi { get; }
|
||||
public IMedicalHistoryRestApi MedicalHistoryRestApi { get; }
|
||||
public IPatientRestApi PatientRestApi { get; }
|
||||
public IHospitalRestApi HospitalRestApi { get; }
|
||||
public IUniversityRestApi UniversityRestApi { get; }
|
||||
public IAiRestApi AiRestApi { get; }
|
||||
}
|
|
@ -4,6 +4,4 @@ namespace DocuMed.PWA.Services.RestServices;
|
|||
|
||||
public interface ISectionRestApi : ICrudDtoApiRest<Section,SectionSDto,Guid>
|
||||
{
|
||||
[Get("/university/{universityId}")]
|
||||
Task<List<SectionSDto>> GetByUniversityAsync(Guid universityId, [Header("Authorization")] string authorization);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace DocuMed.PWA.Services.RestServices;
|
||||
|
||||
public interface IUniversityRestApi
|
||||
{
|
||||
[Get("/{universityId}/hospital")]
|
||||
Task<List<HospitalSDto>> GetHospitalsAsync(Guid universityId, [Header("Authorization")] string authorization);
|
||||
}
|
|
@ -26,4 +26,7 @@ public class RestWrapper : IRestWrapper
|
|||
public IUserRestApi UserRestApi => RestService.For<IUserRestApi>(Address.UserController, setting);
|
||||
public IMedicalHistoryRestApi MedicalHistoryRestApi => RestService.For<IMedicalHistoryRestApi>(Address.MedicalHistoryController);
|
||||
public IPatientRestApi PatientRestApi => RestService.For<IPatientRestApi>(Address.PatientController,setting);
|
||||
public IHospitalRestApi HospitalRestApi => RestService.For<IHospitalRestApi>(Address.HospitalController, setting);
|
||||
public IUniversityRestApi UniversityRestApi => RestService.For<IUniversityRestApi>(Address.UniversityController, setting);
|
||||
public IAiRestApi AiRestApi => RestService.For<IAiRestApi>(Address.AiController, setting);
|
||||
}
|
|
@ -20,6 +20,9 @@ module.exports = {
|
|||
'6xl': '4rem',
|
||||
'7xl': '5rem'
|
||||
},
|
||||
animation: {
|
||||
'gradient': 'gradient 8s linear infinite',
|
||||
},
|
||||
fontFamily: {
|
||||
"iranyekan": ["'iranyekan'"],
|
||||
},
|
||||
|
|
|
@ -518,6 +518,15 @@ video {
|
|||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
.inset-\[-1000\%\] {
|
||||
inset: -1000%;
|
||||
}
|
||||
.bottom-0 {
|
||||
bottom: 0px;
|
||||
}
|
||||
|
@ -720,6 +729,9 @@ video {
|
|||
.mt-auto {
|
||||
margin-top: auto;
|
||||
}
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -853,6 +865,18 @@ video {
|
|||
.basis-full {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
@keyframes spin {
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.animate-\[spin_2s_linear_infinite\] {
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
.grid-cols-1 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||
}
|
||||
|
@ -989,6 +1013,35 @@ video {
|
|||
.bg-opacity-20 {
|
||||
--tw-bg-opacity: 0.2;
|
||||
}
|
||||
.bg-\[conic-gradient\(from_90deg_at_50\%_50\%\2c \#E2CBFF_0\%\2c \#393BB2_50\%\2c \#E2CBFF_100\%\)\] {
|
||||
background-image: conic-gradient(from 90deg at 50% 50%,#E2CBFF 0%,#393BB2 50%,#E2CBFF 100%);
|
||||
}
|
||||
.bg-gradient-to-r {
|
||||
background-image: linear-gradient(to right, var(--tw-gradient-stops));
|
||||
}
|
||||
.from-sky-600 {
|
||||
--tw-gradient-from: #0284c7 var(--tw-gradient-from-position);
|
||||
--tw-gradient-to: rgb(2 132 199 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to);
|
||||
}
|
||||
.via-blue-500 {
|
||||
--tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), #3b82f6 var(--tw-gradient-via-position), var(--tw-gradient-to);
|
||||
}
|
||||
.via-violet-500 {
|
||||
--tw-gradient-to: rgb(139 92 246 / 0) var(--tw-gradient-to-position);
|
||||
--tw-gradient-stops: var(--tw-gradient-from), #8b5cf6 var(--tw-gradient-via-position), var(--tw-gradient-to);
|
||||
}
|
||||
.to-fuchsia-400 {
|
||||
--tw-gradient-to: #e879f9 var(--tw-gradient-to-position);
|
||||
}
|
||||
.to-violet-400 {
|
||||
--tw-gradient-to: #a78bfa var(--tw-gradient-to-position);
|
||||
}
|
||||
.bg-clip-text {
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
}
|
||||
.p-0 {
|
||||
padding: 0px;
|
||||
}
|
||||
|
@ -1004,6 +1057,9 @@ video {
|
|||
.p-5 {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
.p-\[1px\] {
|
||||
padding: 1px;
|
||||
}
|
||||
.px-1 {
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
|
@ -1133,6 +1189,10 @@ video {
|
|||
.text-\[--color-primary\] {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.text-black {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-blue-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(59 130 246 / var(--tw-text-opacity));
|
||||
|
@ -1157,6 +1217,9 @@ video {
|
|||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||
}
|
||||
.text-transparent {
|
||||
color: transparent;
|
||||
}
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
|
@ -1173,6 +1236,11 @@ video {
|
|||
.filter {
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
.backdrop-blur-3xl {
|
||||
--tw-backdrop-blur: blur(64px);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: iranyekan;
|
||||
|
@ -1359,11 +1427,35 @@ a, .btn-link {
|
|||
border-color: rgb(20 184 166 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:outline-none:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.focus\:ring-2:focus {
|
||||
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
|
||||
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
|
||||
}
|
||||
|
||||
.focus\:ring-slate-400:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(148 163 184 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-teal-500:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: rgb(20 184 166 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-offset-2:focus {
|
||||
--tw-ring-offset-width: 2px;
|
||||
}
|
||||
|
||||
.focus\:ring-offset-slate-50:focus {
|
||||
--tw-ring-offset-color: #f8fafc;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-\[--color-primary\] {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue