添加项目文件。
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace IRaCIS.Application.Contracts
|
||||
{
|
||||
public class SubjectCommand
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string Code { get; set; } = String.Empty;
|
||||
|
||||
public int? Age { get; set; }
|
||||
public string Sex { get; set; } = string.Empty;
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public string MedicalNo { get; set; } = string.Empty;
|
||||
|
||||
public string ShortName { get; set; } = string.Empty;
|
||||
|
||||
public string Height { get; set; } = string.Empty;
|
||||
|
||||
public string Weight { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? BirthDate { get; set; }
|
||||
public DateTime? SignDate { get; set; }
|
||||
|
||||
public bool IsUrgent { get; set; }
|
||||
|
||||
public DateTime? FirstGiveMedicineTime { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
//public DateTime? OutEnrollmentTime { get; set; }
|
||||
//public DateTime? VisitOverTime { get; set; }
|
||||
//public SubjectStatus Status { get; set; }
|
||||
//public string Reason { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SubjectStatusChangeCommand
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public SubjectStatus Status { get; set; }
|
||||
public DateTime? OutEnrollmentTime { get; set; }
|
||||
public DateTime? VisitOverTime { get; set; }
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public Guid? FinalSubjectVisitId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class TrialSubjectConfig
|
||||
{
|
||||
public string SubjectCodeRule { get; set; } = string.Empty;
|
||||
public bool IsNoticeSubjectCodeRule { get; set; }
|
||||
public bool IsHaveFirstGiveMedicineDate { get; set; }
|
||||
public bool IsEnrollementQualificationConfirm { get; set; }
|
||||
public bool IsHaveSubjectAge { get; set; }
|
||||
public string OutEnrollmentVisitName { get; set; } = string.Empty;
|
||||
public bool VisitPlanConfirmed { get; set; }
|
||||
|
||||
public bool IsSubjectSexView { get; set; } = false;
|
||||
public bool IsSubjectExpeditedView { get; set; } = false;
|
||||
|
||||
public bool IsSubjectSecondCodeView { get; set; } = false;
|
||||
}
|
||||
|
||||
|
||||
public class SubjectQueryView: SubjectCommand
|
||||
{
|
||||
|
||||
public DateTime? OutEnrollmentTime { get; set; }
|
||||
public DateTime? VisitOverTime { get; set; }
|
||||
public SubjectStatus Status { get; set; }
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
|
||||
//public int? StudyCount { get; set; }
|
||||
//public int? VisitCount { get; set; }
|
||||
//public int? PlanVisitCount { get; set; }
|
||||
|
||||
|
||||
//public int? InPlanDicomStudyUploadCount { get; set; }
|
||||
//public int? OutPlanDicomStudyUploadCount { get; set; }
|
||||
//public int? InPlanNoneDicomStudyUploadCount { get; set; }
|
||||
//public int? OutPlanNoneDicomStudyUploadCount { get; set; }
|
||||
|
||||
public Guid? FinalSubjectVisitId { get; set; }
|
||||
|
||||
public int? TotalVisitCount => OutPlanVisitCount + InPlanVisitCount;
|
||||
public int? TotalVisitSubmmitCount => OutPlanVisitSubmmitCount + InPlanVisitSubmmitCount;
|
||||
|
||||
public int? OutPlanVisitCount { get; set; }
|
||||
public int? OutPlanVisitSubmmitCount { get; set; }
|
||||
|
||||
public int? InPlanVisitCount { get; set; }
|
||||
public int? InPlanVisitSubmmitCount { get; set; }
|
||||
|
||||
public int? MissingSubmmitCount { get; set; }
|
||||
|
||||
public int? LostVisitCount { get; set; }
|
||||
|
||||
public DateTime? CreateTime { get; set; }
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
public string SiteName { get; set; } = string.Empty;
|
||||
public string TrialSiteCode { get; set; } = string.Empty;
|
||||
|
||||
public string LatestVisitName { get; set; } = string.Empty;
|
||||
|
||||
public string LatestBlindName { get; set; } = string.Empty;
|
||||
|
||||
public bool IsMissingImages => MissingSubmmitCount > 0;
|
||||
|
||||
public Guid LatestSubmitSubjectVisitId { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class SubjectQueryParam : PageInput
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string Sex { get; set; } = string.Empty;
|
||||
|
||||
public Guid? SiteId { get; set; }
|
||||
public SubjectStatus? Status { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class SubjectSelect
|
||||
{
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public string Name => LastName + " / " + FirstName;
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
public string Sex { get; set; } = string.Empty;
|
||||
|
||||
public int? Age { get; set; }
|
||||
public SubjectStatus Status { get; set; }
|
||||
|
||||
public DateTime? FirstGiveMedicineTime { get; set; }
|
||||
|
||||
public string MRN { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Application.Contracts
|
||||
{
|
||||
public class VisitStageSelectDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
public int VisitDay { get; set; }
|
||||
|
||||
|
||||
public bool IsBaseLine { get; set; } = false;
|
||||
|
||||
public string AnonymousVisitName { get; set; } = string.Empty;
|
||||
|
||||
public int VisitWindowLeft { get; set; }
|
||||
public int VisitWindowRight { get; set; }
|
||||
}
|
||||
|
||||
public class VisitStageDTO : VisitPlanCommand
|
||||
{
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
||||
public class VisitPlanView
|
||||
{
|
||||
public List<VisitStageDTO> VisitPlanList = new List<VisitStageDTO>();
|
||||
|
||||
public decimal TimePointsPerPatient { get; set; }
|
||||
public bool VisitPlanConfirmed { get; set; }
|
||||
|
||||
public bool IsHaveFirstGiveMedicineDate { get; set; } = true;
|
||||
|
||||
//public bool SubjectHasAdded { get; set; }
|
||||
}
|
||||
|
||||
public class VisitPlanCommand
|
||||
{
|
||||
//public string BlindName => "B" + (VisitNum * 10).ToString("D3");
|
||||
|
||||
public string BlindName { get; set; } = String.Empty;
|
||||
public bool IsConfirmed { get; set; } = false;
|
||||
|
||||
public Guid? Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
public int VisitDay { get; set; }
|
||||
public string Description { get; set; } = String.Empty;
|
||||
public bool NeedGlobal { get; set; } = false;
|
||||
|
||||
public bool IsBaseLine { get; set; } = false;
|
||||
|
||||
|
||||
public string AnonymousVisitName { get; set; } = string.Empty;
|
||||
|
||||
public int VisitWindowLeft { get; set; }
|
||||
public int VisitWindowRight { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class VisitPlanQueryDTO : PageInput
|
||||
{
|
||||
public Guid TrialId { get; set; } = Guid.Empty;
|
||||
public string Keyword { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class VisitPlanInfluenceSubjectVisitStatDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
public string CreateUser { get; set; } = String.Empty;
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public int InconsistentCount { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts
|
||||
{
|
||||
public class SubjectVisitCommand
|
||||
{
|
||||
public bool IsFinalVisit { get; set; }
|
||||
|
||||
public string BlindName { get; set; } = string.Empty;
|
||||
|
||||
public Guid? Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public bool InPlan { get; set; } = true;
|
||||
public VisitExecutedEnum VisitExecuted { get; set; }
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
public int? VisitDay { get; set; }
|
||||
public string SVUPDES { get; set; } = string.Empty;
|
||||
|
||||
public bool IsBaseLine { get; set; } = false;
|
||||
public int VisitWindowLeft { get; set; }
|
||||
public int VisitWindowRight { get; set; }
|
||||
|
||||
public bool IsLostVisit { get; set; }
|
||||
public PDStateEnum? PDState { get; set; }
|
||||
|
||||
public bool? IsEnrollmentConfirm { get; set; }
|
||||
public DateTime? SubjectFirstGiveMedicineTime { get; set; }
|
||||
|
||||
//public bool IsOutEnromentVisit { get; set; }
|
||||
|
||||
public Guid? OutPlanPreviousVisitId { get; set; }
|
||||
|
||||
|
||||
|
||||
//public bool IsUrgent { get; set; }
|
||||
|
||||
|
||||
}
|
||||
public class SubjectVisitDTO : SubjectVisitCommand
|
||||
{
|
||||
public SubjectStatus SubjectStatus { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class SubjectVisitNewDTO : SubjectVisitDTO
|
||||
{
|
||||
public TrialQCProcess QCProcessEnum { get; set; }
|
||||
public CheckStateEnum CheckState { get; set; }
|
||||
public SubmitStateEnum SubmitState { get; set; }
|
||||
public AuditStateEnum AuditState { get; set; }
|
||||
|
||||
public string CurrentActionUser { get; set; } = String.Empty;
|
||||
public DateTime? CurrentActionUserExpireTime { get; set; }
|
||||
public string PreliminaryAuitUser { get; set; } = String.Empty;
|
||||
public string ReviewAuitUser { get; set; } = String.Empty;
|
||||
public DateTime? ReviewAuitTime { get; set; }
|
||||
public DateTime? PreliminaryAuditTime { get; set; }
|
||||
|
||||
|
||||
public int? StudyCount { get; set; }
|
||||
|
||||
public String TrialSiteCode { get; set; } = String.Empty;
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public string SubjectSex { get; set; } = String.Empty;
|
||||
|
||||
public int SubjectAge { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; } = String.Empty;
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public string SubjectName => LastName + " / " + FirstName;
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
public string SiteName { get; set; } = String.Empty;
|
||||
|
||||
public string SiteCode { get; set; } = String.Empty;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SubjectVisitSearchDTO : PageInput
|
||||
{
|
||||
public string SubjectInfo { get; set; } = String.Empty;
|
||||
|
||||
public string VisitPlanInfo { get; set; } = String.Empty;
|
||||
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid? SiteId { get; set; }
|
||||
}
|
||||
|
||||
public class SubjectVisitSelectItem
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
|
||||
public int VisitExecuted { get; set; }
|
||||
}
|
||||
|
||||
public class SubjectVisitSelectDTO
|
||||
{
|
||||
public Guid GuidId { get; set; } = Guid.NewGuid();
|
||||
public Guid SubjectVisitId { get; set; } = Guid.Empty;
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
|
||||
public string SVUPDES { get; set; } = string.Empty;
|
||||
|
||||
public int? VisitDay { get; set; }
|
||||
|
||||
//public Guid VisitStageId { get; set; } = Guid.Empty;
|
||||
|
||||
public DateTime? SVSTDTC { get; set; }
|
||||
|
||||
public DateTime? SVENDTC { get; set; }
|
||||
|
||||
|
||||
//public bool IsSubjectVisit { get; set; } = false;
|
||||
|
||||
public VisitExecutedEnum VisitExecuted { get; set; }
|
||||
|
||||
|
||||
|
||||
public List<SubjectVisitStudyDTO> StudyList = new List<SubjectVisitStudyDTO>();
|
||||
}
|
||||
|
||||
|
||||
public class SubjectVisitStudyDTO
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public string StudyCode { get; set; } = String.Empty;
|
||||
|
||||
public string Modalities { get; set; } = String.Empty;
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class VisitStudyDTO
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
public string StudyCode { get; set; } = String.Empty;
|
||||
public string Modalities { get; set; } = String.Empty;
|
||||
|
||||
public int SeriesCount { get; set; }
|
||||
public int InstanceCount { get; set; }
|
||||
|
||||
public List<DicomSeriesDTO> SeriesList { get; set; } = new List<DicomSeriesDTO>();
|
||||
}
|
||||
|
||||
public class ArchiveStudyCommand
|
||||
{
|
||||
|
||||
|
||||
public Guid? AbandonStudyId { get; set; }
|
||||
|
||||
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public string StudyInstanceUid { get; set; } = String.Empty;
|
||||
|
||||
//public Guid TrialId { get; set; }
|
||||
//public Guid SiteId { get; set; }
|
||||
//public Guid SubjectId { get; set; }
|
||||
//public DateTime? SVSTDTC { get; set; }
|
||||
//public DateTime? SVENDTC { get; set; }
|
||||
|
||||
//public string DTFPath { get; set; }
|
||||
//public string FileRealName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class UploadDTFCommand
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class StudyCommand
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.Empty;
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class StudyEditCommand : StudyCommand
|
||||
{
|
||||
public Guid VisitStageId { get; set; }
|
||||
public DateTime? SVSTDTC { get; set; }
|
||||
public DateTime? SVENDTC { get; set; }
|
||||
public string Comment { get; set; } = String.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class StudyStatDTO
|
||||
{
|
||||
|
||||
public int StudyCount { get; set; }
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
public int VisitDay { get; set; }
|
||||
public string Description { get; set; } = String.Empty;
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class DistributeReviewerStudyStatusDTO
|
||||
{
|
||||
public string NameCN { get; set; } = String.Empty;
|
||||
public string Name { get; set; } = String.Empty;
|
||||
public string ReviewerCode { get; set; } = String.Empty;
|
||||
public string StudyCode { get; set; } = String.Empty;
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class StudyStatusQueryDTO : PageInput
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid? ReviewerId { get; set; }
|
||||
|
||||
public int? StudyStatus { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class VerifyStudyUploadResult
|
||||
{
|
||||
public string StudyInstanceUid { get; set; } = String.Empty;
|
||||
|
||||
public VerifyStudyDto? StudyInfo { get; set; }
|
||||
|
||||
public bool AllowUpload { get; set; } = false;
|
||||
|
||||
public bool AllowReUpload { get; set; } = false;
|
||||
|
||||
public string ErrorMesseage { get; set; } = String.Empty;
|
||||
|
||||
}
|
||||
|
||||
public class VerifyUploadOrReupload
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
[NotDefault]
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
[NotDefault]
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
public List<VerifyUploadStudyBasicInfo> StudyInstanceUidList { get; set; } = new List<VerifyUploadStudyBasicInfo>();
|
||||
}
|
||||
|
||||
public class VerifyUploadStudyBasicInfo
|
||||
{
|
||||
public string StudyInstanceUid { get; set; } = String.Empty;
|
||||
|
||||
public DateTime StudyDate { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class VerifyStudyDto
|
||||
{
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string StudyCode { get; set; } = String.Empty;
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; } = String.Empty;
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
public string SubjectName => LastName + " / " + FirstName;
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
|
||||
public DateTime StudyTime { get; set; }
|
||||
}
|
||||
|
||||
public class StudyDTO
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
public decimal VisitNum { get; set; }
|
||||
public string VisitName { get; set; } = String.Empty;
|
||||
public int? VisitDay { get; set; }
|
||||
|
||||
public string SVUPDES { get; set; } = String.Empty;
|
||||
|
||||
public DateTime? SVSTDTC { get; set; }
|
||||
|
||||
public DateTime? SVENDTC { get; set; }
|
||||
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public string StudyCode { get; set; } = String.Empty;
|
||||
|
||||
|
||||
public int StudyStatus { get; set; }
|
||||
public DateTime? StudyDate { get; set; }
|
||||
public string Modalities { get; set; } = String.Empty;
|
||||
public int SeriesCount { get; set; }
|
||||
public int InstanceCount { get; set; }
|
||||
|
||||
public bool IsDoubleReview { get; set; }
|
||||
|
||||
public string StudyDescription { get; set; } = String.Empty;
|
||||
|
||||
public string BodyPartExamined { get; set; } = String.Empty;
|
||||
|
||||
public string Comment { get; set; } = String.Empty;
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public DateTime? UploadedTime { get; set; }
|
||||
|
||||
public DateTime? DeadlineTime { get; set; }
|
||||
|
||||
//public List<DistributeReviewer> DistributeReviewers { get; set; }=new List<DistributeReviewer>();
|
||||
|
||||
|
||||
public Guid SiteId { get; set; }
|
||||
public string SiteName { get; set; } = String.Empty;
|
||||
public string InstitutionName { get; set; } = String.Empty;
|
||||
public string StudyId { get; set; } = String.Empty;//这个Id是dicom文件中的Id
|
||||
public Guid SubjectId { get; set; }
|
||||
public string SubjectCode { get; set; } = String.Empty;
|
||||
|
||||
public string SubjectName => LastName + " / " + FirstName;
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
public int? SubjectAge { get; set; }
|
||||
|
||||
public SubjectStatus SubjectStatus { get; set; }
|
||||
public string SubjectSex { get; set; } = String.Empty;
|
||||
|
||||
public string SubjectMedicalNo { get; set; } = string.Empty;
|
||||
|
||||
public string PatientId { get; set; } = String.Empty;
|
||||
public string PatientName { get; set; } = String.Empty;
|
||||
public string PatientAge { get; set; } = String.Empty;
|
||||
public string PatientSex { get; set; } = String.Empty;
|
||||
public string AccessionNumber { get; set; } = string.Empty;
|
||||
public string PatientBirthDate { get; set; } = string.Empty;
|
||||
|
||||
|
||||
//public int? NeedDealMessageCount { get; set; }
|
||||
//public int? TotalMessageCount { get; set; }
|
||||
public int? DTFCount { get; set; }
|
||||
|
||||
|
||||
public string UploaderFirstName { get; set; } = String.Empty;
|
||||
public string UploaderLastName { get; set; } = String.Empty;
|
||||
}
|
||||
|
||||
public class DistributeReviewer
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
|
||||
public Guid ReviewerId { get; set; }
|
||||
public string NameCN { get; set; } = String.Empty;
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
public int Status { get; set; }
|
||||
}
|
||||
|
||||
public class StudyQueryDTO : PageInput
|
||||
{
|
||||
public Guid? SubjectId { get; set; }
|
||||
|
||||
public Guid? SiteId { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public string SubjectInfo { get; set; } = String.Empty;
|
||||
|
||||
public string VisitPlanInfo { get; set; }=String.Empty;
|
||||
|
||||
public Guid? SubjectVisitId { get; set; }
|
||||
|
||||
|
||||
public DateTime? StudyTimeBegin { get; set; }
|
||||
|
||||
public DateTime? StudyTimeEnd { get; set; }
|
||||
|
||||
public DateTime? UpdateTimeBegin { get; set; }
|
||||
|
||||
public DateTime? UpdateTimeEnd { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using IRaCIS.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IRaCIS.Application.Interfaces
|
||||
{
|
||||
public interface ISubjectService
|
||||
{
|
||||
Task<IResponseOutput> AddOrUpdateSubject([FromBody] SubjectCommand subjectCommand);
|
||||
Task<IResponseOutput> DeleteSubject(Guid id);
|
||||
Task<IResponseOutput<PageOutput<SubjectQueryView>, TrialSubjectConfig>> GetSubjectList(SubjectQueryParam param);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
|
||||
namespace IRaCIS.Core.Application.Interfaces
|
||||
{
|
||||
public interface ISubjectVisitService
|
||||
{
|
||||
Task<IResponseOutput> AddOrUpdateSV(SubjectVisitCommand svCommand);
|
||||
Task<IResponseOutput> DeleteSV(Guid id);
|
||||
Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading);
|
||||
Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IRaCIS.Application.Interfaces
|
||||
{
|
||||
public interface IVisitPlanService
|
||||
{
|
||||
Task<IResponseOutput> AddOrUpdateVisitStage(VisitPlanCommand visitPlan);
|
||||
Task<IResponseOutput> ConfirmTrialVisitPlan(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository);
|
||||
Task<IResponseOutput> DeleteVisitStage(Guid id);
|
||||
Task<IActionResult> DownloadInflunceStudyList(Guid visitPlanInfluenceStatId, [FromServices] IRepository<VisitPlanInfluenceStudy> _influnceRepository);
|
||||
Task<List<VisitPlanInfluenceSubjectVisitStatDTO>> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository);
|
||||
Task<PageOutput<VisitStageDTO>> GetTrialVisitStageList(VisitPlanQueryDTO param);
|
||||
Task<IEnumerable<VisitStageSelectDTO>> GetTrialVisitStageSelect(Guid trialId);
|
||||
Task<VisitPlanView> GetVisitStageList(Guid trialId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IRaCIS.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class SubjectService : BaseService, ISubjectService
|
||||
{
|
||||
private readonly IRepository<Subject> _subjectRepository;
|
||||
|
||||
public SubjectService(IRepository<Subject> subjectRepository)
|
||||
{
|
||||
_subjectRepository = subjectRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新受试者信息[New]
|
||||
/// </summary>
|
||||
/// <param name="subjectCommand">state:1-访视中,2-出组。0-全部</param>
|
||||
/// <returns></returns>
|
||||
|
||||
[TrialAudit(AuditType.SubjectAudit, AuditOptType.AddOrUpdateSubject)]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> AddOrUpdateSubject([FromBody] SubjectCommand subjectCommand)
|
||||
{
|
||||
|
||||
if (await _repository.AnyAsync<Trial>(t => t.Id == subjectCommand.TrialId && !t.VisitPlanConfirmed))
|
||||
{
|
||||
return ResponseOutput.NotOk("The trial visit plan has not been confirmed yet.Please contact the project manager to confirm the visit plan before adding subject.");
|
||||
}
|
||||
|
||||
var verifyExp1 = new EntityVerifyExp<Subject>()
|
||||
{
|
||||
VerifyExp = u => u.Code == subjectCommand.Code && u.TrialId == subjectCommand.TrialId,
|
||||
VerifyMsg = "A subjects with the same subject ID already existed in this trial."
|
||||
};
|
||||
|
||||
|
||||
|
||||
var mapedSubject = await _subjectRepository.InsertOrUpdateAsync(subjectCommand, false, verifyExp1/*, verifyExp2*/);
|
||||
|
||||
if (subjectCommand.Id == null) //insert
|
||||
{
|
||||
var IsEnrollementQualificationConfirm = await _repository.Where<Trial>(t => t.Id == mapedSubject.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
|
||||
//添加受试者的时候,获取访视计划列表,添加到受试者访视表。
|
||||
var visitPlan = await _repository.Where<VisitStage>(t => t.TrialId == subjectCommand.TrialId).ToListAsync();
|
||||
|
||||
var svlist = _mapper.Map<List<SubjectVisit>>(visitPlan);
|
||||
|
||||
svlist.ForEach(t =>
|
||||
{
|
||||
t.TrialId = subjectCommand.TrialId;
|
||||
t.SiteId = subjectCommand.SiteId;
|
||||
t.IsEnrollmentConfirm = t.IsBaseLine ? IsEnrollementQualificationConfirm : false;
|
||||
});
|
||||
|
||||
mapedSubject.SubjectVisitList = svlist;
|
||||
}
|
||||
else //update
|
||||
{
|
||||
//变更site
|
||||
if (mapedSubject.SiteId != subjectCommand.SiteId)
|
||||
{
|
||||
|
||||
await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == mapedSubject.Id,
|
||||
u => new SubjectVisit() { SiteId = mapedSubject.SiteId });
|
||||
|
||||
await _repository.UpdateFromQueryAsync<DicomStudy>(t => t.SubjectId == mapedSubject.Id,
|
||||
u => new DicomStudy() { SiteId = mapedSubject.SiteId });
|
||||
|
||||
|
||||
};
|
||||
////如果访视结束了 需要删除计划外未执行的访视
|
||||
//if (mapedSubject.Status == SubjectStatus.EndOfVisit)
|
||||
//{
|
||||
// await _repository.DeleteFromQueryAsync<SubjectVisit>(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == mapedSubject.Id && t.InPlan == false);
|
||||
//}
|
||||
|
||||
////如果是出组了 将受试者未执行的 设置为不可用
|
||||
//if (mapedSubject.Status == SubjectStatus.OutOfEnrollment)
|
||||
//{
|
||||
// await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == mapedSubject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok(mapedSubject.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
[HttpPut("{trialId:guid}")]
|
||||
public async Task<IResponseOutput> UpdateSubjectStatus(SubjectStatusChangeCommand subjectStatusChangeCommand)
|
||||
{
|
||||
var subject = await _subjectRepository.FirstOrDefaultAsync(t => t.Id == subjectStatusChangeCommand.SubjectId);
|
||||
|
||||
if (subject == null) return Null404NotFound(subject);
|
||||
|
||||
_mapper.Map(subjectStatusChangeCommand, subject);
|
||||
|
||||
////如果访视结束了 需要删除计划外未执行的访视
|
||||
//if (subjectStatusChangeCommand.Status == SubjectStatus.EndOfVisit)
|
||||
//{
|
||||
// await _repository.DeleteFromQueryAsync<SubjectVisit>(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == subject.Id && t.InPlan == false);
|
||||
//}
|
||||
|
||||
//如果是出组了
|
||||
if (subjectStatusChangeCommand.Status == SubjectStatus.OutOfVisit)
|
||||
{
|
||||
|
||||
if (subjectStatusChangeCommand.FinalSubjectVisitId != null)
|
||||
{
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.IsFinalVisit))
|
||||
{
|
||||
return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视");
|
||||
}
|
||||
|
||||
var sv = await _repository.FirstOrDefaultAsync<SubjectVisit>(t => t.Id == subjectStatusChangeCommand.FinalSubjectVisitId).IfNullThrowException();
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit))
|
||||
{
|
||||
return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视");
|
||||
}
|
||||
|
||||
sv.IsFinalVisit = true;
|
||||
|
||||
//末次访视后的 访视设置为不可用
|
||||
await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
|
||||
|
||||
}
|
||||
|
||||
|
||||
//将受试者未执行的 设置为不可用
|
||||
await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == subject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Obsolete]
|
||||
[HttpGet("{trialId:guid}/{subjectId:guid}/{finalSubjectVisitId:guid}")]
|
||||
public async Task<IResponseOutput> VerifySubjectFinalVisit(Guid subjectId, Guid finalSubjectVisitId)
|
||||
{
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectId && t.IsFinalVisit))
|
||||
{
|
||||
return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视");
|
||||
}
|
||||
|
||||
var sv = (await _repository.FirstOrDefaultAsync<SubjectVisit>(t => t.Id == finalSubjectVisitId)).IfNullThrowException();
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit))
|
||||
{
|
||||
return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视");
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{id:guid}/{trialId:guid}")]
|
||||
|
||||
[TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubject)]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> DeleteSubject(Guid id)
|
||||
{
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(u => u.SubjectId == id && u.VisitExecuted == VisitExecutedEnum.Executed))
|
||||
{
|
||||
return ResponseOutput.NotOk("This subject has executed a visit with uploading study images,and couldn't be deleted.");
|
||||
}
|
||||
|
||||
var isSuccess = await _subjectRepository.DeleteFromQueryAsync(u => u.Id == id);
|
||||
await _repository.DeleteFromQueryAsync<SubjectVisit>(u => u.SubjectId == id);
|
||||
return ResponseOutput.Result(isSuccess);
|
||||
}
|
||||
|
||||
/// <summary> 分页获取受试者列表[New] </summary>
|
||||
/// /// <param name="param">state:1-访视中,2-出组。0-全部</param>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput<PageOutput<SubjectQueryView>, TrialSubjectConfig>> GetSubjectList(SubjectQueryParam param)
|
||||
{
|
||||
|
||||
var subjectQuery = _subjectRepository.Where(u => u.TrialId == param.TrialId)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(param.Code), t => t.Code.Contains(param.Code))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(param.Name), t => t.ShortName.Contains(param.Name))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(param.Sex), t => t.Sex.Contains(param.Sex))
|
||||
.WhereIf(param.Status != null, t => t.Status == param.Status)
|
||||
.WhereIf(param.SiteId != null, t => t.SiteId == param.SiteId)
|
||||
// CRC 只负责他管理site的受试者
|
||||
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
|
||||
.ProjectTo<SubjectQueryView>(_mapper.ConfigurationProvider);
|
||||
|
||||
|
||||
var pageList = await subjectQuery.ToPagedListAsync(param.PageIndex, param.PageSize, param.SortField == string.Empty ? "Code" : param.SortField, param.Asc);
|
||||
|
||||
var trialConfig = await _repository.Where<Trial>(t => t.Id == param.TrialId).ProjectTo<TrialSubjectConfig>(_mapper.ConfigurationProvider).FirstOrDefaultAsync().IfNullThrowException();
|
||||
|
||||
return ResponseOutput.Ok(pageList, trialConfig);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 计划外访视 获取受试者选择下拉框列表
|
||||
/// </summary>
|
||||
[HttpGet("{siteId:guid}/{trialId:guid}")]
|
||||
public List<SubjectSelect> GetSubjectListBySiteId(Guid siteId, Guid trialId)
|
||||
{
|
||||
var query = _subjectRepository.Where(t => t.SiteId == siteId && t.TrialId == trialId && t.Status == SubjectStatus.OnVisit).Select(u => new SubjectSelect()
|
||||
{
|
||||
Code = u.Code,
|
||||
FirstName = u.FirstName,
|
||||
LastName = u.LastName,
|
||||
Sex = u.Sex,
|
||||
SubjectId = u.Id,
|
||||
Age = u.Age,
|
||||
MRN = u.MedicalNo,
|
||||
Status = u.Status,
|
||||
|
||||
FirstGiveMedicineTime = u.FirstGiveMedicineTime
|
||||
|
||||
});
|
||||
return query.ToList();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
using IRaCIS.Core.Infrastructure.ExpressionExtend;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class SubjectVisitService : BaseService, ISubjectVisitService
|
||||
{
|
||||
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
|
||||
|
||||
public SubjectVisitService(IRepository<SubjectVisit> subjectVisitRepository)
|
||||
{
|
||||
_subjectVisitRepository = subjectVisitRepository;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
[UnitOfWork]
|
||||
public async Task<IResponseOutput> AddOrUpdateSV(SubjectVisitCommand svCommand)
|
||||
{
|
||||
|
||||
var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
|
||||
{
|
||||
VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId,
|
||||
VerifyMsg = "This subject's visit plan already contains a visit with the same visitnum."
|
||||
};
|
||||
|
||||
var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
|
||||
{
|
||||
VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit,
|
||||
VerifyMsg = "该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视",
|
||||
IsVerify=svCommand.IsFinalVisit
|
||||
};
|
||||
|
||||
#region 废弃
|
||||
//var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
|
||||
//{
|
||||
// verifyType = VerifyEnum.OnlyUpdate,
|
||||
// VerifyExp = t => t.StudyList.Any(k => k.SubjectVisitId == svCommand.Id) && svCommand.SVSTDTC == null,
|
||||
// VerifyMsg = "This visit is associated with the uploaded study images, and the visit start date is not allowed to be modified."
|
||||
//};
|
||||
|
||||
//if (needDealEntity.SVSTDTC == null && needDealEntity.VisitExecuted == 1)
|
||||
//{
|
||||
// return ResponseOutput.NotOk("VisitExecuted must have Start Date ");
|
||||
//}
|
||||
|
||||
|
||||
//if (needDealEntity.IsOutEnromentVisit)
|
||||
//{
|
||||
// needDealEntity.VisitNum = _subjectVisitRepository.Where(t => t.SubjectId == svCommand.SubjectId).Max(t => t.VisitNum) + (decimal)0.1;
|
||||
//}
|
||||
|
||||
//没有EndOfVisit
|
||||
//if (svCommand.IsFinalVisit)
|
||||
//{
|
||||
// //if (svCommand.InPlan)
|
||||
// //{
|
||||
// await _repository.UpdateFromQueryAsync<Subject>(t => t.Id == svCommand.SubjectId, u => new Subject() { Status = SubjectStatus.EndOfVisit });
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // return ResponseOutput.NotOk("计划外访视不允许设置为最后一次访视");
|
||||
|
||||
// //}
|
||||
//}
|
||||
#endregion
|
||||
|
||||
|
||||
svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3");
|
||||
|
||||
var subject = (await _repository.FirstOrDefaultAsync<Subject>(t => t.Id == svCommand.SubjectId)).IfNullThrowException();
|
||||
|
||||
|
||||
//不管是否 都是执行,只是失访的时候 设置Subject状态为失去访视
|
||||
//if (svCommand.IsLostVisit)
|
||||
//{
|
||||
// svCommand.VisitExecuted = VisitExecutedEnum.Executed;
|
||||
|
||||
// subject.IsMissingImages = true;
|
||||
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// svCommand.VisitExecuted = VisitExecutedEnum.Executed;
|
||||
//}
|
||||
|
||||
svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted;
|
||||
|
||||
//设置末次评估后,不允许添加计划外访视
|
||||
if (svCommand.InPlan == false && svCommand.Id == null)
|
||||
{
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit))
|
||||
{
|
||||
return ResponseOutput.NotOk("设置末次评估后,不允许添加计划外访视");
|
||||
}
|
||||
}
|
||||
|
||||
//更新的时候,返回的是数据库此时的实体数据
|
||||
var needDealEntity = await _subjectVisitRepository.InsertOrUpdateAsync(svCommand, false, verifyExp1, verifyExp2);
|
||||
|
||||
|
||||
if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.SubmitState == SubmitStateEnum.Submitted)
|
||||
{
|
||||
return ResponseOutput.NotOk("CRC提交后,不允许修改PD确认状态");
|
||||
}
|
||||
|
||||
if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack)
|
||||
{
|
||||
return ResponseOutput.NotOk("回退的访视,不允许修改PD确认状态");
|
||||
}
|
||||
|
||||
if (svCommand.IsFinalVisit)
|
||||
{
|
||||
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit))
|
||||
{
|
||||
return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视");
|
||||
}
|
||||
|
||||
|
||||
subject.Status = SubjectStatus.OutOfVisit;
|
||||
|
||||
//末次访视后的 访视设置为不可用
|
||||
await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//回退
|
||||
subject.Status = SubjectStatus.OnVisit;
|
||||
|
||||
await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitExecuted == VisitExecutedEnum.Unavailable, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.UnExecuted });
|
||||
}
|
||||
|
||||
//更新受试者 首次给药日期 是否入组确认
|
||||
if (svCommand.SubjectFirstGiveMedicineTime != null)
|
||||
{
|
||||
|
||||
subject.FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime;
|
||||
|
||||
}
|
||||
|
||||
if (svCommand.IsEnrollmentConfirm != null)
|
||||
{
|
||||
|
||||
await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.IsBaseLine , u => new SubjectVisit() { IsEnrollmentConfirm = svCommand.IsEnrollmentConfirm.Value });
|
||||
|
||||
|
||||
//needDealEntity.IsUrgent = true;
|
||||
}
|
||||
|
||||
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
// 保存数据后,重新算下是否缺失影像 应对状态撤回
|
||||
//if (svCommand.IsLostVisit == false)
|
||||
//{
|
||||
|
||||
// var currentSubmittedVisitNum = await _repository.Where<SubjectVisit>(t => t.SubmitState == SubmitStateEnum.Submitted).MaxAsync(t => t.VisitNum);
|
||||
|
||||
// var isMissing = await _repository.AnyAsync<SubjectVisit>(t => (t.VisitNum < currentSubmittedVisitNum && t.SubmitState != SubmitStateEnum.Submitted) || t.IsLostVisit);
|
||||
|
||||
// await _repository.UpdateFromQueryAsync<Subject>(t => t.Id == svCommand.SubjectId, u => new Subject()
|
||||
// {
|
||||
// IsMissingImages = isMissing
|
||||
// });
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")]
|
||||
public async Task<IResponseOutput> SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent)
|
||||
{
|
||||
await _subjectVisitRepository.UpdateFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent });
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete, Route("{id:guid}/{trialId:guid}")]
|
||||
[TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubjectOutPlanVisit)]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> DeleteSV(Guid id)
|
||||
{
|
||||
if (await _repository.AnyAsync<DicomStudy>(t => t.SubjectVisitId == id))
|
||||
{
|
||||
return ResponseOutput.NotOk("This visit is associated with the uploaded study images and couldn't be deleted.");
|
||||
}
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan))
|
||||
{
|
||||
return ResponseOutput.NotOk("This visit is InPlan and couldn't be deleted.");
|
||||
}
|
||||
return ResponseOutput.Result(await _repository.DeleteFromQueryAsync<SubjectVisit>(s => s.Id == id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置受试者访视已执行 也就是将studyUploaded状态置为true 为了那些没有影像 人工设置准备
|
||||
/// </summary>
|
||||
/// <param name="subjectVisitId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{subjectVisitId:guid}/{trialId:guid}")]
|
||||
[TrialAudit(AuditType.SubjectAudit, AuditOptType.SetSVExecuted)]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId)
|
||||
{
|
||||
return ResponseOutput.Result(await _subjectVisitRepository.UpdateFromQueryAsync(s => s.Id == subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed }));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取访视下的Dicom 检查信息 分所有的, 阅片的 不阅片 isReading : 0 查询所有 1 查询仅仅阅片的
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <param name="sujectVisitId"></param>
|
||||
/// <param name="isReading"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading)
|
||||
{
|
||||
var studyList = await _repository.Where<DicomStudy>(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).Select(k => new VisitStudyDTO()
|
||||
{
|
||||
InstanceCount = k.InstanceCount,
|
||||
Modalities = k.Modalities,
|
||||
SeriesCount = k.SeriesCount,
|
||||
StudyCode = k.StudyCode,
|
||||
StudyId = k.Id
|
||||
}).ToListAsync();
|
||||
var studyIds = studyList.Select(t => t.StudyId).ToList();
|
||||
|
||||
var instanceList = await _repository.Where<DicomInstance>(t => studyIds.Contains(t.StudyId))
|
||||
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber }).ToListAsync();
|
||||
|
||||
foreach (var t in studyList)
|
||||
{
|
||||
t.SeriesList = await _repository.Where<DicomSeries>(s => s.StudyId == t.StudyId)
|
||||
.WhereIf(isReading == 1, s => s.IsReading).OrderBy(s => s.SeriesNumber).
|
||||
ThenBy(s => s.SeriesTime)
|
||||
.ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
|
||||
t.SeriesList.ForEach(series => series.InstanceList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => k.Id).ToList());
|
||||
|
||||
//设置为阅片与否 不更改数据库检查 的instance数量 和 SeriesCount 所以这里要实时统计
|
||||
t.SeriesCount = t.SeriesList.Count();
|
||||
t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceList).Count();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return studyList;
|
||||
|
||||
//return ResponseOutput.Ok(studyList.Where(t => t.SeriesList.Count > 0).ToList());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
using IRaCIS.Core.Infrastructure.ExpressionExtend;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
|
||||
using Magicodes.ExporterAndImporter.Core;
|
||||
using Magicodes.ExporterAndImporter.Excel;
|
||||
using Magicodes.ExporterAndImporter.Excel.AspNetCore;
|
||||
|
||||
namespace IRaCIS.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class VisitPlanService : BaseService, IVisitPlanService
|
||||
{
|
||||
private readonly IRepository<VisitStage> _visitStageRepository;
|
||||
private readonly IRepository<Trial> _trialRepository;
|
||||
|
||||
public VisitPlanService(IRepository<VisitStage> visitStageRepository,IRepository<Trial> trialRepository)
|
||||
{
|
||||
_visitStageRepository = visitStageRepository;
|
||||
_trialRepository = trialRepository;
|
||||
}
|
||||
|
||||
|
||||
///暂时不用
|
||||
/// <summary> 获取项目访视计划</summary>
|
||||
public async Task<PageOutput<VisitStageDTO>> GetTrialVisitStageList(VisitPlanQueryDTO param)
|
||||
{
|
||||
var visitStageQuery = _visitStageRepository.Where(u => u.TrialId == param.TrialId)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(param.Keyword), t => t.VisitName.Contains(param.Keyword))
|
||||
.ProjectTo<VisitStageDTO>(_mapper.ConfigurationProvider);
|
||||
|
||||
return await visitStageQuery.ToPagedListAsync(param.PageIndex, param.PageSize, "CreateTime", param.Asc);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary> 根据项目Id,获取项目访视计划(不分页)[New]</summary>
|
||||
[HttpGet("{trialId:guid}")]
|
||||
public async Task<VisitPlanView> GetVisitStageList(Guid trialId)
|
||||
{
|
||||
var query = _visitStageRepository.Where(u => u.TrialId == trialId)
|
||||
.ProjectTo<VisitStageDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
|
||||
var list = await query.ToListAsync();
|
||||
var trial = await _repository.FirstOrDefaultAsync<Trial>(t => t.Id == trialId).IfNullThrowException();
|
||||
|
||||
return new VisitPlanView()
|
||||
{
|
||||
VisitPlanList = list,
|
||||
TimePointsPerPatient = trial.TimePointsPerPatient,
|
||||
VisitPlanConfirmed = trial.VisitPlanConfirmed,
|
||||
IsHaveFirstGiveMedicineDate = trial.IsHaveFirstGiveMedicineDate,
|
||||
//SubjectHasAdded = _subjectVisitRepository.Any(t => t.TrialId == trialId)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取访视计划下拉框列表
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{trialId:guid}")]
|
||||
public async Task<IEnumerable<VisitStageSelectDTO>> GetTrialVisitStageSelect(Guid trialId)
|
||||
{
|
||||
var query = _visitStageRepository.Where(u => u.TrialId == trialId)
|
||||
.ProjectTo<VisitStageSelectDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
|
||||
var list = await query.ToListAsync();
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/// <summary> 添加或更新访视计划某项[New]</summary>
|
||||
[HttpPost]
|
||||
[UnitOfWork]
|
||||
public async Task<IResponseOutput> AddOrUpdateVisitStage(VisitPlanCommand visitPlan)
|
||||
{
|
||||
if (!await _repository.Where<Trial>(t => t.Id == visitPlan.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing))
|
||||
{
|
||||
return ResponseOutput.NotOk(" only in Initializing or Ongoing State can operate ");
|
||||
}
|
||||
|
||||
var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId)
|
||||
.Select(t => new { t.Id, t.VisitNum, t.VisitDay }).OrderBy(t => t.VisitNum).ToListAsync();
|
||||
|
||||
//更新的时候,需要排除自己
|
||||
if (visitPlan.Id != null)
|
||||
{
|
||||
visitPlanList = visitPlanList.Where(t => t.Id != visitPlan.Id).ToList();
|
||||
}
|
||||
|
||||
if (visitPlanList.Any(t => t.VisitNum < visitPlan.VisitNum))
|
||||
{
|
||||
//比当前 visitNum小的 visitDay的最大值 还小 不允许添加
|
||||
if (visitPlan.VisitDay <= visitPlanList.Where(t => t.VisitNum < visitPlan.VisitNum).Select(t => t.VisitDay).Max())
|
||||
{
|
||||
return ResponseOutput.NotOk("For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum.");
|
||||
}
|
||||
}
|
||||
|
||||
if (visitPlanList.Any(t => t.VisitNum > visitPlan.VisitNum))
|
||||
{
|
||||
if (visitPlan.VisitDay >= visitPlanList.Where(t => t.VisitNum > visitPlan.VisitNum).Select(t => t.VisitDay).Min())
|
||||
{
|
||||
return ResponseOutput.NotOk("For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (visitPlan.Id == Guid.Empty || visitPlan.Id == null)//add
|
||||
{
|
||||
|
||||
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum)))
|
||||
{
|
||||
return ResponseOutput.NotOk("A visit with the same VisitName/VisitNum already existed in the current visit plan.");
|
||||
}
|
||||
|
||||
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine) && visitPlan.IsBaseLine)
|
||||
{
|
||||
return ResponseOutput.NotOk("A visit already is baseline in the current visit plan.");
|
||||
}
|
||||
|
||||
//已添加受试者 都不存在该新增的计划名称 那么该项目所有受试者都增加一个访视记录
|
||||
if (!await _repository.AnyAsync<SubjectVisit>(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId))
|
||||
{
|
||||
var subjectSVS = await _repository.Where<SubjectVisit>(t => t.TrialId == visitPlan.TrialId).Select(t => new { t.SubjectId, t.SiteId,t.IsFinalVisit }).Distinct().ToListAsync();
|
||||
|
||||
var subjects = subjectSVS.Select(t => new { t.SubjectId, t.SiteId }).Distinct().ToList();
|
||||
|
||||
foreach (var subject in subjects)
|
||||
{
|
||||
var svItem = _mapper.Map<SubjectVisit>(visitPlan);
|
||||
|
||||
svItem.SiteId = subject.SiteId;
|
||||
|
||||
svItem.SubjectId = subject.SubjectId;
|
||||
|
||||
//设置了末次访视,那么加访视计划的时候,设置为不可用
|
||||
if (subjectSVS.Any(t => t.SubjectId == svItem.SubjectId && t.IsFinalVisit))
|
||||
{
|
||||
svItem.VisitExecuted = VisitExecutedEnum.Unavailable;
|
||||
}
|
||||
|
||||
await _repository.AddAsync(svItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var visitPlanItem = _mapper.Map<VisitStage>(visitPlan);
|
||||
|
||||
visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3");
|
||||
|
||||
var result = await _repository.AddAsync(visitPlanItem);
|
||||
|
||||
//更新项目访视计划状态为未确认
|
||||
await _repository.UpdateFromQueryAsync<Trial>(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false });
|
||||
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok(result.Id.ToString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
else//update
|
||||
{
|
||||
|
||||
|
||||
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id))
|
||||
{
|
||||
return ResponseOutput.NotOk("A visit with the same VisitName/VisitNum already existed in the current visit plan.");
|
||||
}
|
||||
|
||||
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id) && visitPlan.IsBaseLine)
|
||||
{
|
||||
return ResponseOutput.NotOk("A visit already is baseline in the current visit plan.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
var stage = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id);
|
||||
if (stage == null) return Null404NotFound(stage);
|
||||
|
||||
//修改是否是基线
|
||||
if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine)
|
||||
{
|
||||
if (await _repository.Where<SubjectVisit>(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit))
|
||||
{
|
||||
return ResponseOutput.NotOk("有CRC已经为基线上传了影像数据,不允许修改基线");
|
||||
}
|
||||
}
|
||||
|
||||
_mapper.Map(visitPlan, stage);
|
||||
|
||||
stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3");
|
||||
|
||||
//更新项目访视计划状态为未确认
|
||||
await _repository.UpdateFromQueryAsync<Trial>(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false });
|
||||
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> 删除项目计划某一项[New]</summary>
|
||||
[HttpDelete("{id:guid}/{trialId:guid}")]
|
||||
[TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)]
|
||||
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> DeleteVisitStage(Guid id)
|
||||
{
|
||||
|
||||
var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id);
|
||||
|
||||
if (visitPlan == null) return Null404NotFound(visitPlan);
|
||||
|
||||
if (await _repository.AnyAsync<SubjectVisit>(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed))
|
||||
{
|
||||
return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed.");
|
||||
}
|
||||
|
||||
await _repository.DeleteFromQueryAsync<SubjectVisit>(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName);
|
||||
|
||||
var result = await _visitStageRepository.DeleteFromQueryAsync(u => u.Id == id);
|
||||
|
||||
|
||||
return ResponseOutput.Result(result);
|
||||
}
|
||||
|
||||
|
||||
[UnitOfWork]
|
||||
[HttpPost("{trialId:guid}")]
|
||||
[TrialAudit(AuditType.TrialAudit, AuditOptType.ConfirmTrialVisitPlan)]
|
||||
|
||||
public async Task<IResponseOutput> ConfirmTrialVisitPlan(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository)
|
||||
{
|
||||
if (!await _trialRepository.AnyAsync(t => t.Id == trialId &&( t.TrialStatusStr==StaticData.TrialInitializing || t.TrialStatusStr == StaticData.TrialOngoing)))
|
||||
{
|
||||
return ResponseOutput.NotOk("仅仅在项目初始化或者进行中时,才允许修改确认");
|
||||
}
|
||||
|
||||
if (!await _visitStageRepository.AnyAsync(t => t.TrialId == trialId && t.IsBaseLine))
|
||||
{
|
||||
return ResponseOutput.NotOk("没有基线,不允许确认");
|
||||
}
|
||||
|
||||
if (!await _trialRepository.AnyAsync(t => t.Id == trialId && t.IsTrialBasicLogicConfirmed && t.IsTrialProcessConfirmed && t.IsTrialUrgentConfirmed))
|
||||
{
|
||||
return ResponseOutput.NotOk("项目配置未确认,不允许确认访视计划");
|
||||
}
|
||||
|
||||
var svList = await _visitStageRepository.Where(t => t.TrialId == trialId).Select(u => new { u.VisitDay, u.IsBaseLine }).ToListAsync();
|
||||
|
||||
if (svList.Min(t => t.VisitDay) != svList.Where(t => t.IsBaseLine).FirstOrDefault()?.VisitDay)
|
||||
{
|
||||
return ResponseOutput.NotOk("基线VisitDay 不是最小的, 不允许确认");
|
||||
}
|
||||
|
||||
//更新项目访视计划状态为已确认
|
||||
await _trialRepository.UpdateFromQueryAsync(u => u.Id == trialId, t => new Trial() { VisitPlanConfirmed = true });
|
||||
|
||||
//找到访视计划修改的Item
|
||||
var changedList = await _visitStageRepository.Where(t => t.TrialId == trialId && t.IsConfirmed == false)
|
||||
.Select(t => new { t.Trial.IsHaveFirstGiveMedicineDate, t.Id, t.VisitName, t.VisitWindowLeft, t.VisitWindowRight, t.VisitDay, t.VisitNum, t.IsBaseLine }).ToListAsync();
|
||||
|
||||
|
||||
//访视计划 整体状态变更为 确认
|
||||
await _visitStageRepository.UpdateFromQueryAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true });
|
||||
|
||||
var stat = new VisitPlanInfluenceStat() { TrialId = trialId };
|
||||
|
||||
foreach (var changedItem in changedList)
|
||||
{
|
||||
//找到该项目 访视已经执行,并且配置了有首次给药日期 并且更新后超窗的访视,要把超窗之前的值也要查询出来
|
||||
var qcPassedVisitList = await _repository.Where<SubjectVisit>(t => t.TrialId == trialId
|
||||
&& t.VisitExecuted == VisitExecutedEnum.Executed
|
||||
&& t.AuditState == AuditStateEnum.QCPassed
|
||||
&& t.Trial.IsHaveFirstGiveMedicineDate == true
|
||||
&& t.VisitStageId == changedItem.Id
|
||||
&& t.Subject.FirstGiveMedicineTime != null
|
||||
).Select(k => new
|
||||
{
|
||||
SubjectVisitId = k.Id,
|
||||
SelfWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowLeft),
|
||||
SelfWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowRight + 1).AddSeconds(-1),
|
||||
|
||||
NowWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft),
|
||||
NowWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight + 1).AddSeconds(-1),
|
||||
|
||||
NoneDicomStudyList =
|
||||
k.NoneDicomStudyList //之前是查询调整之后超窗的 现在调整前超窗 调整后 没超窗的也要记录
|
||||
//.Where(study => study.ImageDate <k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft??0)
|
||||
//|| study.ImageDate >k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1))
|
||||
.Select(t => new { NoneDicomStudyId = t.Id, t.Modality, StudyTime = t.ImageDate }),
|
||||
|
||||
|
||||
DicomStudyList = k.StudyList
|
||||
//.Where(study => study.StudyTime <k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft??0)
|
||||
// || study.StudyTime >k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1))
|
||||
.Select(t => new { StudyId = t.Id, Modality = t.Modalities, t.StudyTime })
|
||||
|
||||
}).ToListAsync();
|
||||
|
||||
|
||||
foreach (var visit in qcPassedVisitList)
|
||||
{
|
||||
//找到本身没有超窗的数据 修改后超窗的
|
||||
visit.DicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t =>
|
||||
{
|
||||
stat.InconsistentCount++;
|
||||
stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy()
|
||||
{
|
||||
IsOverWindowNowNotOverWindow = false,
|
||||
Modality = t.Modality,
|
||||
SubjectVisitId = visit.SubjectVisitId,
|
||||
StudyId = t.StudyId,
|
||||
IsDicomStudy = true,
|
||||
StudyTime = t.StudyTime,
|
||||
TrialId = trialId,
|
||||
HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"),
|
||||
NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd")
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
visit.NoneDicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t =>
|
||||
{
|
||||
stat.InconsistentCount++;
|
||||
stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy()
|
||||
{
|
||||
IsOverWindowNowNotOverWindow = false,
|
||||
Modality = t.Modality,
|
||||
SubjectVisitId = visit.SubjectVisitId,
|
||||
StudyId = t.NoneDicomStudyId,
|
||||
IsDicomStudy = false,
|
||||
StudyTime = t.StudyTime,
|
||||
TrialId = trialId,
|
||||
HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"),
|
||||
NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd")
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
//本身超窗 修改后没超窗的
|
||||
visit.DicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t =>
|
||||
{
|
||||
stat.InconsistentCount++;
|
||||
stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy()
|
||||
{
|
||||
IsOverWindowNowNotOverWindow = true,
|
||||
Modality = t.Modality,
|
||||
SubjectVisitId = visit.SubjectVisitId,
|
||||
StudyId = t.StudyId,
|
||||
IsDicomStudy = true,
|
||||
StudyTime = t.StudyTime,
|
||||
TrialId = trialId,
|
||||
HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"),
|
||||
NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd")
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
visit.NoneDicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t =>
|
||||
{
|
||||
stat.InconsistentCount++;
|
||||
stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy()
|
||||
{
|
||||
IsOverWindowNowNotOverWindow = true,
|
||||
Modality = t.Modality,
|
||||
SubjectVisitId = visit.SubjectVisitId,
|
||||
StudyId = t.NoneDicomStudyId,
|
||||
IsDicomStudy = false,
|
||||
StudyTime = t.StudyTime,
|
||||
TrialId = trialId,
|
||||
HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"),
|
||||
NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd")
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//变更某一访视计划Item 受试者访视相关字段
|
||||
await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id, k => new SubjectVisit()
|
||||
{
|
||||
IsBaseLine = changedItem.IsBaseLine,
|
||||
VisitName = changedItem.VisitName,
|
||||
VisitNum = changedItem.VisitNum,
|
||||
VisitDay = changedItem.VisitDay,
|
||||
VisitWindowLeft = changedItem.VisitWindowLeft,
|
||||
VisitWindowRight = changedItem.VisitWindowRight
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
await _repository.AddAsync(stat);
|
||||
await _repository.SaveChangesAsync();
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
[HttpGet("{trialId:guid}")]
|
||||
public async Task<List<VisitPlanInfluenceSubjectVisitStatDTO>> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository)
|
||||
{
|
||||
var list = await _influnceStatRepository.Where(t => t.TrialId == trialId).ProjectTo<VisitPlanInfluenceSubjectVisitStatDTO>(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToListAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[HttpGet("{visitPlanInfluenceStatId:guid}")]
|
||||
public async Task<IActionResult> DownloadInflunceStudyList(Guid visitPlanInfluenceStatId, [FromServices] IRepository<VisitPlanInfluenceStudy> _influnceRepository)
|
||||
{
|
||||
var list = _influnceRepository.Where(t => t.VisitPlanInfluenceStatId == visitPlanInfluenceStatId)
|
||||
.ProjectTo<VisitPlanInfluenceSubjectVisitDTO>(_mapper.ConfigurationProvider).ToList();
|
||||
|
||||
|
||||
IExporter exporter = new ExcelExporter();
|
||||
|
||||
var result = await exporter.ExportAsByteArray(list);
|
||||
|
||||
|
||||
return new XlsxFileResult(bytes: result, fileDownloadName: $"检查导出_{DateTime.Now.ToString("yyyy-MM-dd:hh:mm:ss")}.xlsx");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using AutoMapper;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
public class VisitMapConfig : Profile
|
||||
{
|
||||
public VisitMapConfig()
|
||||
{
|
||||
CreateMap<VisitPlanCommand, VisitStage>();
|
||||
CreateMap<VisitPlanCommand, SubjectVisit>();
|
||||
CreateMap<SubjectCommand, Subject>();
|
||||
|
||||
CreateMap<VisitStage, VisitStageDTO>();
|
||||
|
||||
CreateMap<VisitStage, VisitStageSelectDTO>();
|
||||
CreateMap<VisitStage, SubjectVisit>()
|
||||
.ForMember(d => d.Id, t => t.Ignore())
|
||||
.ForMember(d => d.VisitStageId, t =>t.MapFrom(u=>u.Id));
|
||||
|
||||
|
||||
CreateMap<VisitPlanInfluenceStat, VisitPlanInfluenceSubjectVisitStatDTO>()
|
||||
.ForMember(d => d.CreateUser, u => u.MapFrom(g => g.CreateUser.LastName + " / " + g.CreateUser.FirstName));
|
||||
|
||||
|
||||
|
||||
CreateMap<SubjectStatusChangeCommand, Subject>();
|
||||
CreateMap<VisitStage, VisitStageDTO>();
|
||||
|
||||
CreateMap<Subject, SubjectQueryView>()
|
||||
.ForMember(d => d.SiteName, u => u.MapFrom(s => s.TrialSite.Site.SiteName))
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSite.TrialSiteCode))
|
||||
.ForMember(d => d.LatestBlindName, u => u.MapFrom(s => s.LatestSubjectVisit.BlindName))
|
||||
.ForMember(d => d.LatestVisitName, u => u.MapFrom(s => s.LatestSubjectVisit.VisitName))
|
||||
//.ForMember(d => d.IsSubjectSexView, u => u.MapFrom(s => s.Trial.IsSubjectSexView))
|
||||
//.ForMember(d => d.IsSubjectExpeditedView, u => u.MapFrom(s => s.Trial.IsSubjectExpeditedView))
|
||||
|
||||
//不能对包含聚合或子查询的表达式执行聚合函数
|
||||
//.ForMember(d => d.InPlanStudyCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan).Sum(k => k.StudyList.Count())))
|
||||
//.ForMember(d => d.OutPlanStudyCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan==false).Sum(k => k.StudyList.Count())))
|
||||
|
||||
//.ForMember(d => d.InPlanDicomStudyUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan).SelectMany(k => k.StudyList).Count()))
|
||||
//.ForMember(d => d.OutPlanDicomStudyUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan == false).SelectMany(k => k.StudyList).Count()))
|
||||
|
||||
//.ForMember(d => d.InPlanNoneDicomStudyUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan).SelectMany(k => k.NoneDicomStudyList).Count()))
|
||||
//.ForMember(d => d.OutPlanNoneDicomStudyUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.InPlan == false).SelectMany(k => k.NoneDicomStudyList).Count()))
|
||||
.ForMember(d => d.FinalSubjectVisitId, u => u.MapFrom(s => s.SubjectVisitList.Where(t => t.IsFinalVisit).Select(c=>(Guid?) c.Id).FirstOrDefault()))
|
||||
.ForMember(d => d.InPlanVisitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.InPlan)))
|
||||
.ForMember(d => d.OutPlanVisitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.InPlan == false)))
|
||||
//执行不一定上传了 可能是失访 实际执行过了
|
||||
|
||||
|
||||
.ForMember(d => d.MissingSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.VisitNum <s.LatestSubjectVisit.VisitNum && t.SubmitState != SubmitStateEnum.Submitted && t.IsLostVisit == false)))
|
||||
.ForMember(d => d.InPlanVisitSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.SubmitState == SubmitStateEnum.Submitted && t.InPlan == true)))
|
||||
.ForMember(d => d.LostVisitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.IsLostVisit)))
|
||||
.ForMember(d => d.InPlanVisitSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.SubmitState == SubmitStateEnum.Submitted && t.InPlan == true)))
|
||||
.ForMember(d => d.OutPlanVisitSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.SubmitState == SubmitStateEnum.Submitted && t.InPlan == false)));
|
||||
// .ForMember(d => d.InPlanVisitSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.SubmitState>=SubmitStateEnum.ToSubmit && t.InPlan == true)))
|
||||
//.ForMember(d => d.OutPlanVisitSubmmitCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.SubmitState >= SubmitStateEnum.ToSubmit && t.InPlan == false)));
|
||||
//.ForMember(d => d.InPlanVisitUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.VisitExecuted == VisitExecutedEnum.Executed && t.InPlan)))
|
||||
//.ForMember(d => d.OutPlanVisitUploadCount, u => u.MapFrom(s => s.SubjectVisitList.Count(t => t.VisitExecuted == VisitExecutedEnum.Executed && t.InPlan == false)));
|
||||
|
||||
|
||||
//审计信息 这里不用IncludeMembers 也可以识别 是以导航属性名称开头
|
||||
// 还有 外键? COALESCE([t0].[SubjectId], '00000000-0000-0000-0000-000000000000') 因为destination 是Guid
|
||||
CreateMap<TrialAudit, AuditDTO>()
|
||||
.ForMember(d => d.SubjectName, u => u.MapFrom(s => s.Subject.LastName + " / " + s.Subject.FirstName))
|
||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(s => s.Subject.Code));
|
||||
|
||||
|
||||
CreateMap<SubjectVisitCommand, SubjectVisit>().ForAllMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null));
|
||||
|
||||
|
||||
|
||||
CreateMap<SubjectVisit, DicomTrialSiteSubjectInfo>().IncludeMembers(t=>t.Trial)
|
||||
.ForMember(d => d.SiteName, u => u.MapFrom(s => s.Site.SiteName))
|
||||
.ForMember(d => d.SiteCode, u => u.MapFrom(s => s.Site.SiteCode))
|
||||
.ForMember(d => d.SubjectVisitId, u => u.MapFrom(s => s.Id))
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSite.TrialSiteCode))
|
||||
.ForMember(d => d.TrialCode, u => u.MapFrom(s => s.Trial.TrialCode))
|
||||
.ForMember(d => d.Sponsor, u => u.MapFrom(s => s.Trial.Sponsor.SponsorName));
|
||||
CreateMap<Trial, DicomTrialSiteSubjectInfo>();
|
||||
|
||||
CreateMap<VisitPlanInfluenceStudy, VisitPlanInfluenceSubjectVisitDTO>()
|
||||
.ForMember(d => d.SubjectVisitId, u => u.MapFrom(s => s.Id))
|
||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(s => s.SubjectVisit.Subject.Code))
|
||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName))
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.SubjectVisit.TrialSite.TrialSiteCode));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user