irc-netcore-api/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs

460 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using EasyCaching.Core;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Options;
using static IRaCIS.Core.Domain.Share.StaticData;
using Microsoft.AspNetCore.Authorization;
using System.Linq.Expressions;
using System.Linq;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Trial")]
public class TrialService : BaseService, ITrialService
{
private readonly IEasyCachingProvider _provider;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<TrialUser> _trialUserRepository;
private readonly IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig;
private readonly IOptionsMonitor<SystemEmailSendConfig> _systemEmailSendConfig;
public bool TrialExpeditedChange { get; set; } = false;
public TrialService(IEasyCachingProvider provider, IRepository<Trial> trialRepository,
IRepository<TrialUser> trialUserRepository, IOptionsMonitor<ServiceVerifyConfigOption> verifyConfig
, IOptionsMonitor<SystemEmailSendConfig> systemEmailSendConfig
)
{
_systemEmailSendConfig = systemEmailSendConfig;
_verifyConfig = verifyConfig;
_provider = provider;
_trialRepository = trialRepository;
this._trialUserRepository = trialUserRepository;
}
/// <summary>
/// 分页获取临床项目列表 默认后台加急状态为3 查所有的
/// </summary>
/// <param name="searchParam"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<TrialDetailDTO>> GetTrialList(TrialQueryDTO searchParam)
{
var multiModalityIdSelectCount = searchParam.ModalityIds.Count;
var multiCriteriaSelectCount = searchParam.CriterionIds.Count;
var multiReviewTypeSelectCount = searchParam.ReviewTypeIds.Count;
Expression<Func<Trial, bool>> trialDeclarationTypeExpression = x => true;
foreach (var item in searchParam.DeclarationTypeEnumList)
{
trialDeclarationTypeExpression = trialDeclarationTypeExpression.And(t => t.DeclarationTypes.Contains($"|{item}|"));
}
Expression<Func<Trial, bool>> trialAttendedReviewerTypeExpression = x => true;
foreach (var item in searchParam.AttendedReviewerTypeEnumList)
{
trialAttendedReviewerTypeExpression = trialAttendedReviewerTypeExpression.And(t => t.AttendedReviewerTypes.Contains($"|{item}|"));
}
var query = _trialRepository.AsQueryable().IgnoreQueryFilters()
.WhereIf(!string.IsNullOrEmpty(searchParam.TrialStatusStr), o => o.TrialStatusStr.Contains(searchParam.TrialStatusStr))
.WhereIf(searchParam.SponsorId != null, o => o.SponsorId == searchParam.SponsorId)
.WhereIf(searchParam.Expedited != null, o => o.Expedited == searchParam.Expedited)
.WhereIf(!string.IsNullOrEmpty(searchParam.Code), o => o.TrialCode.Contains(searchParam.Code))
.WhereIf(!string.IsNullOrWhiteSpace(searchParam.Indication), o => o.Indication.Contains(searchParam.Indication))
.WhereIf(!string.IsNullOrEmpty(searchParam.ResearchProgramNo), o => o.ResearchProgramNo.Contains(searchParam.ResearchProgramNo))
.WhereIf(!string.IsNullOrWhiteSpace(searchParam.ExperimentName), o => o.ExperimentName.Contains(searchParam.ExperimentName))
.WhereIf(searchParam.PhaseId != null, o => o.PhaseId == searchParam.PhaseId)
.WhereIf(searchParam.DeclarationTypeEnumList.Count > 0, trialDeclarationTypeExpression)
.WhereIf(searchParam.AttendedReviewerTypeEnumList.Count > 0, trialAttendedReviewerTypeExpression)
//.WhereIf(searchParam.AttendedReviewerType != null, o => o.AttendedReviewerType == searchParam.AttendedReviewerType)
.WhereIf(searchParam.IndicationTypeId != null, o => o.IndicationTypeId == searchParam.IndicationTypeId)
.WhereIf(searchParam.CROId != null, o => o.CROId == searchParam.CROId)
.WhereIf(searchParam.BeginDate != null, o => o.CreateTime >= searchParam.BeginDate)
.WhereIf(searchParam.EndDate != null, o => o.CreateTime <= searchParam.EndDate)
.WhereIf(multiModalityIdSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Modality) == multiModalityIdSelectCount)
.WhereIf(multiCriteriaSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Criterion) == multiCriteriaSelectCount)
.WhereIf(multiReviewTypeSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.ReviewType) == multiReviewTypeSelectCount)
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin
&& _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OP, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false)
.ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id , isEn_Us= _userInfo.IsEn_Us });
return await query.ToPagedListAsync(searchParam.PageIndex, searchParam.PageSize, string.IsNullOrWhiteSpace(searchParam.SortField) ? "CreateTime" : searchParam.SortField, searchParam.Asc);
}
//过滤废除的项目
public async Task<List<TrialSelectDTO>> GetTrialSelect()
{
return await _trialRepository.AsQueryable().IgnoreQueryFilters()
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt !=(int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OP
, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id) && t.IsDeleted == false)
.ProjectTo<TrialSelectDTO>(_mapper.ConfigurationProvider).ToListAsync();
}
/// <summary>
/// 获取项目基本信息
/// </summary>
/// <param name="projectId"></param>
/// <returns></returns>
[HttpGet("{projectId:guid}")]
public async Task<TrialDetailDTO> GetTrialInfoAndLockState(Guid projectId)
{
return (await _trialRepository.Where(o => o.Id == projectId).IgnoreQueryFilters().ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new {isEn_Us = _userInfo.IsEn_Us }).FirstOrDefaultAsync()).IfNullThrowException();
}
[HttpGet("{trialId:guid}")]
public async Task<TrialAndTrialStateVieModel> GetTrialInfoAndMaxTrialState(Guid trialId)
{
return new TrialAndTrialStateVieModel()
{
TrialView = await GetTrialInfoAndLockState(trialId),
};
}
[HttpGet("{trialId:guid}")]
public async Task<int> GetTrialExpeditedState(Guid trialId)
{
var trial = (await _trialRepository.FirstOrDefaultAsync(u => u.Id == trialId)).IfNullThrowException();
return trial.Expedited;
}
/// <summary>
/// 添加项目
/// </summary>
/// <param name="trialAddModel"></param>
/// <returns></returns>
[NonDynamicMethod]
public virtual async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand trialAddModel)
{
//测试用户 只能创建非正式项目
if (_userInfo.IsTestUser && trialAddModel.TrialType != TrialType.NoneOfficial)
{
//---测试用户 只能创建非正式项目
throw new BusinessValidationFailedException(_localizer["Trial_TestUserCreateOnlyNonFormal"]);
}
if (trialAddModel.Id == Guid.Empty || trialAddModel.Id == null)
{
if (await _trialRepository.AnyAsync(u => u.TrialCode == trialAddModel.TrialCode))
{
//---已经存在相同的项目编号。
throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
}
var dbMaxCode = await _trialRepository.Where(t => t.CreateTime.Year == DateTime.Now.Year && t.TrialType == trialAddModel.TrialType).Select(t => t.Code).DefaultIfEmpty().MaxAsync();
var currentYearMaxCodeNext = dbMaxCode + 1;
//var test = _trialRepository.Where(t => t.CreateTime.Year == DateTime.Now.Year + 1).Select(t => t.Code).DefaultIfEmpty(1).ToList();
var trial = _mapper.Map<Trial>(trialAddModel);
//trial.Id = NewId.NextGuid();
var yearStr = DateTime.Now.Year.ToString();
trial.Code = currentYearMaxCodeNext;
trial.TrialCode = (trial.TrialType == TrialType.NoneOfficial ? "T0" : yearStr.Substring(yearStr.Length - 2)) + trial.TrialCode + currentYearMaxCodeNext.ToString("D3");
trial.DeclarationTypes = $"|{string.Join('|', trialAddModel.DeclarationTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
trial.AttendedReviewerTypes = $"|{string.Join('|', trialAddModel.AttendedReviewerTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
//多选信息
trialAddModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
trialAddModel.CriterionIds.ForEach(criterionId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = criterionId, KeyName = StaticData.Criterion, TrialId = trial.Id }));
trialAddModel.ReviewTypeIds.ForEach(ReviewTypeId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = ReviewTypeId, KeyName = StaticData.ReviewType, TrialId = trial.Id }));
//添加项目后 项目状态变更为申请下载简历
trial.TrialEnrollStatus = (int)TrialEnrollStatus.ChooseDoctor;
//trial.TrialStatusStr = StaticData.TrialInitializing;
//状态变更详细表
trial.ClinicalTrialProjectDetails.Add(new TrialStatusDetail() { TrialId = trial.Id, TrialStatus = (int)TrialEnrollStatus.ChooseDoctor });
trial = await _trialRepository.AddAsync(trial);
//如果是PM 则需要将该人员添加到 运维人员表
//添加运维人员PM
await _repository.AddAsync(new TrialUser() { TrialId = trial.Id, UserId = _userInfo.Id, JoinTime = DateTime.Now });
//添加访视
await _repository.AddAsync(new VisitStage { TrialId = trial.Id, VisitNum = 0, BlindName = "B" + 0.ToString("D3"), VisitDay = 0, VisitName = "Baseline", IsBaseLine = true });
await _repository.AddAsync(new VisitStage { TrialId = trial.Id, VisitNum = 1, BlindName = "B" + 10.ToString("D3"), VisitDay = 30, VisitName = "Visit 1" });
//默认采用系统邮件
trial.EmailAuthorizationCode = _systemEmailSendConfig.CurrentValue.AuthorizationCode;
trial.EmailFromEmail = _systemEmailSendConfig.CurrentValue.FromEmail;
trial.EmailFromName = _systemEmailSendConfig.CurrentValue.FromName;
trial.EmailSMTPServerAddress = _systemEmailSendConfig.CurrentValue.Host;
trial.EmailSMTPServerPort = _systemEmailSendConfig.CurrentValue.Port;
trial.IsConfigureEmail = true;
var success = await _repository.SaveChangesAsync();
_provider.Set(trial.Id.ToString(), StaticData.TrialState.TrialInitializing, TimeSpan.FromDays(7));
return ResponseOutput.Ok(trial);
}
else
{
var updateModel = trialAddModel;
if (!await _repository.AnyAsync<Trial>(u => u.Id == trialAddModel.Id && (u.TrialStatusStr == StaticData.TrialState.TrialInitializing || u.TrialStatusStr == StaticData.TrialState.TrialOngoing)))
{
//---项目状态只有处于:初始化或者进行中时,才允许操作。
throw new BusinessValidationFailedException(_localizer["Trial_InvalidProjectStatus"]);
}
// 判断项目Id 是否已经存在
if (await _repository.AnyAsync<Trial>(u => u.TrialCode == updateModel.TrialCode && u.Id != updateModel.Id))
{
//---已经存在相同的项目编号。
throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
}
var trial = await _repository.FirstOrDefaultAsync<Trial>(t => t.Id == updateModel.Id);
//删除中间表 Title对应的记录
await _repository.BatchDeleteAsync<TrialDictionary>(t => t.TrialId == updateModel.Id);
//重新插入新的 Title记录
updateModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
updateModel.CriterionIds.ForEach(criterionId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = criterionId, KeyName = StaticData.Criterion, TrialId = trial.Id }));
updateModel.ReviewTypeIds.ForEach(ReviewTypeId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = ReviewTypeId, KeyName = StaticData.ReviewType, TrialId = trial.Id }));
if (updateModel.Expedited != trial.Expedited && updateModel.Expedited != null)
{
TrialExpeditedChange = true;
}
_mapper.Map(updateModel, trial);
trial.DeclarationTypes = $"|{string.Join('|', updateModel.DeclarationTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
trial.AttendedReviewerTypes = $"|{string.Join('|', updateModel.AttendedReviewerTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Ok(trial);
}
}
/// <summary> 真删除项目 方便清理测试数据 </summary>
/// <param name="trialId">临床试验项目Id</param>
[AllowAnonymous]
[HttpDelete, Route("{trialId:guid}")]
public async Task<IResponseOutput> DeleteTrial(Guid trialId)
{
if (_verifyConfig.CurrentValue.OpenTrialRelationDelete)
{
await _repository.BatchDeleteAsync<CheckChallengeDialog>(o => o.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalDataTrialSet>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalQuestionAnswer>(o => o.ClinicalForm.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalQuestionAnswer>(o => o.ClinicalForm.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalForm>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<CriterionNidusSystem>(o => o.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<CriterionNidusTrial>(o => o.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<CheckChallengeDialog>(o => o.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalDataTrialSet>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<InspectionFile>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<CriterionNidusSystem>(o => o.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<DataInspection>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<DicomStudy>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<StudyMonitor>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<DicomSeries>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<DicomInstance>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<NoneDicomStudyFile>(t => t.NoneDicomStudy.TrialId == trialId);
await _repository.BatchDeleteAsync<NoneDicomStudy>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<OrganTrialInfo>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<PreviousHistory>(t => t.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<PreviousOther>(t => t.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<PreviousPDF>(t => t.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<QCChallengeDialog>(t => t.QCChallenge.TrialId == trialId);
await _repository.BatchDeleteAsync<QCChallenge>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingClinicalDataPDF>(t => t.ReadingClinicalData.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingClinicalData>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingGlobalTaskInfo>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingJudgeInfo>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingMedicalReviewDialog>(t => t.TaskMedicalReview.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingMedicineQuestionAnswer>(t => t.TaskMedicalReview.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingMedicineTrialQuestion>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingOncologyTaskInfo>(t => t.VisitTask.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingPeriodPlan>(t => t.ReadingPeriodSet.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingPeriodSet>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingQuestionTrial>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTableAnswerRowInfo>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTableQuestionAnswer>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTableQuestionTrial>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTaskQuestionAnswer>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTaskRelation>(t => t.VisitTask.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadModule>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingTaskQuestionAnswer>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<Subject>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<SubjectVisit>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TaskInfluence>(t => t.InfluenceTask.TrialId == trialId);
await _repository.BatchDeleteAsync<TaskMedicalReview>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TaskMedicalReviewRule>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialStateChange>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<Trial>(o => o.Id == trialId);
await _repository.BatchDeleteAsync<TrialClinicalDataSetCriterion>(t => t.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialCriterionDictionaryCode>(t => t.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<ReadingQuestionCriterionTrial>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialDictionary>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialDocConfirmedUser>(t => t.TrialDocument.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialDocument>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialDocNeedConfirmedUserType>(t => t.TrialDocument.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialEmailNoticeUser>(t => t.TrialEmailNoticeConfig.TrialId == trialId);
//await _repository.BatchDeleteAsync<TrialExperience>(t => t.TrialId == trialId) ;
await _repository.BatchDeleteAsync<TrialEmailNoticeUser>(t => t.TrialEmailNoticeConfig.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialEmailNoticeConfig>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialExternalUser>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialQCQuestion>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialQCQuestionAnswer>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSign>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSite>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSiteSurvey>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSiteUserSurvey>(t => t.TrialSiteSurvey.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSiteEquipmentSurvey>(t => t.TrialSiteSurvey.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialUser>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialSiteUser>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<VisitStage>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<VisitPlanInfluenceStat>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<VisitPlanInfluenceStudy>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<VisitTaskReReading>(t => t.OriginalReReadingTask.TrialId == trialId);
await _repository.BatchDeleteAsync<VisitTask>(t => t.TrialId == trialId);
await _repository.BatchDeleteAsync<TrialStateChange>(t => t.TrialId == trialId) ;
return ResponseOutput.Ok();
}
else
{
//---当前运行环境下,不允许删除项目数据。
return ResponseOutput.NotOk(_localizer["Trial_CannotDeleteProject"]);
}
}
#region 医生用户接口
#endregion
}
}