From 7de33670c9887fd94aa9fbe6f1b203b09b642732 Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Tue, 7 Jun 2022 17:31:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8C=BB=E7=94=9F=E5=8F=91=E9=80=81=E9=82=AE?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IRaCIS.Core.API/IRaCIS.Core.API.csproj | 6 + .../EmailTemplate/TrialDoctorExistJoin.html | 49 ++++++++ .../EmailTemplate/TrialDoctorFirstJoin.html | 52 ++++++++ .../IRaCIS.Core.Application.xml | 2 +- .../Service/Common/MailService.cs | 118 +++++++++++++++++- .../Service/WorkLoad/DTO/EnrollViewModel.cs | 15 +++ .../Service/WorkLoad/EnrollService.cs | 24 ++-- .../WorkLoad/Interface/IEnrollService.cs | 2 +- .../Allocation/AllocationRelation.cs | 7 +- IRaCIS.Core.Domain/Management/User.cs | 3 + 10 files changed, 261 insertions(+), 17 deletions(-) create mode 100644 IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html create mode 100644 IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index e6053ff27..1365f076d 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -115,12 +115,18 @@ Always + + Always + Always Always + + Always + Always diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html new file mode 100644 index 000000000..e9eb58417 --- /dev/null +++ b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorExistJoin.html @@ -0,0 +1,49 @@ + + + + + Title + + +
+
+
+ 尊敬的 {0} ,您好: +
+
+ 展影医疗作为 [{1} (实验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢! +
+
+ 该项目采用电子化工作流,系统及您的账号信息如下: +
+ +
+
+ 项目编号: {3} +
+
+ 试验方案号: {2} +
+
+ 试验名称: {1} +
+
+ 用户名: {4} +
+
+ 角色: {5} +
+
+ 系统登录地址:{6} +
+
+ + +
+
祝您顺利!/Best Regards
+
上海展影医疗科技有限公司
+
+
+
+ + diff --git a/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html new file mode 100644 index 000000000..4ee19f785 --- /dev/null +++ b/IRaCIS.Core.API/wwwroot/EmailTemplate/TrialDoctorFirstJoin.html @@ -0,0 +1,52 @@ + + + + + Title + + +
+
+
+ 尊敬的 {0} ,您好: +
+
+ 展影医疗作为 [{1} (实验方案号:{2 })] 项目的IRC供应商,诚邀您参加该项目IRC阅片相关工作,欢迎您提供指导和建议,非常感谢! +
+
+ 该项目采用电子化工作流,系统及您的账号信息如下: +
+ +
+
+ 项目编号: {3} +
+
+ 试验方案号: {2} +
+
+ 试验名称: {1} +
+
+ 用户名: {4} +
+
+ 角色: {5} +
+
+ 首次登陆前,请通过该链接修改您的账户信息: + + 初始化账号信息 + +
+
+ + +
+
祝您顺利!/Best Regards
+
上海展影医疗科技有限公司
+
+
+
+ + diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 879cfce3d..3738c6821 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -3485,7 +3485,7 @@ 入组流程-CRO确定医生名单 [ Approve] - + 入组流程-后台确认医生入组[Confirm] diff --git a/IRaCIS.Core.Application/Service/Common/MailService.cs b/IRaCIS.Core.Application/Service/Common/MailService.cs index 9714d12de..d645a0df9 100644 --- a/IRaCIS.Core.Application/Service/Common/MailService.cs +++ b/IRaCIS.Core.Application/Service/Common/MailService.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Hosting; using IRaCIS.Core.Application.Auth; using AutoMapper; using IRaCIS.Application.Contracts; +using Nito.AsyncEx; namespace IRaCIS.Application.Services { @@ -26,6 +27,8 @@ namespace IRaCIS.Application.Services Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl); + Task DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl); + } @@ -43,6 +46,12 @@ namespace IRaCIS.Application.Services private readonly IMapper _mapper; private readonly IRepository _trialRepository; + private readonly IRepository _userTypeRepository; + + private readonly IRepository _doctorTypeRepository; + + private readonly AsyncLock _mutex = new AsyncLock(); + public MailVerificationService(IRepository verificationCodeRepository, @@ -50,7 +59,9 @@ namespace IRaCIS.Application.Services IWebHostEnvironment hostEnvironment, IRepository userRepository, ITokenService tokenService, - IRepository trialRepository, + IRepository trialRepository, + IRepository userTypeRepository, + IRepository doctorTypeRepository, IMapper mapper) { _verificationCodeRepository = verificationCodeRepository; @@ -64,6 +75,9 @@ namespace IRaCIS.Application.Services _userRepository = userRepository; _trialRepository = trialRepository; + _userTypeRepository = userTypeRepository; + _doctorTypeRepository = doctorTypeRepository; + } //重置邮箱 @@ -128,7 +142,6 @@ namespace IRaCIS.Application.Services - //不登录 通过邮箱重置密码 public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode) { @@ -282,8 +295,8 @@ namespace IRaCIS.Application.Services await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + sysUserInfo.UserTypeRole.UserTypeShortName + "&access_token=" + token; - - var domain=baseUrl.Substring(0,baseUrl.IndexOf("/login")); + + var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); var redirectUrl = $"{domain}/api/User/UserRedirect?url={ System.Web.HttpUtility.UrlEncode(routeUrl) }"; @@ -354,7 +367,7 @@ namespace IRaCIS.Application.Services } - + //Site调研 用户加入项目 public async Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl) { var sysUserInfo = (await _userRepository.Where(t => t.Id == userId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); @@ -416,6 +429,7 @@ namespace IRaCIS.Application.Services } + //外部用户 加入项目 public async Task ExternalUserJoinEmail(Guid trialId, Guid userId, string baseUrl, string rootUrl) { var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException(); @@ -480,6 +494,100 @@ namespace IRaCIS.Application.Services + public async Task DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl) + { + var doctor = await _doctorTypeRepository.FindAsync(doctorId); + User sysUserInfo = null; + + + using (await _mutex.LockAsync()) + { + var isDoctorHaveAccount = await _userRepository.AnyAsync(t => t.DoctorId == doctorId); + + + if (!isDoctorHaveAccount) + { + + var saveItem = new User() { FirstName = doctor.FirstName, LastName = doctor.LastName, EMail = doctor.EMail }; + + saveItem.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1; + + saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); + + saveItem.UserName = saveItem.UserCode; + + saveItem.UserTypeEnum = UserTypeEnum.IndependentReviewer; + + saveItem.DoctorId = doctorId; + + sysUserInfo = await _userRepository.AddAsync(saveItem); + + await _userRepository.SaveChangesAsync(); + } + else + { + sysUserInfo = (await _userRepository.Where(t => t.DoctorId == doctorId).Include(t => t.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException(); + } + } + + var userType= await _userTypeRepository.FirstAsync(t => t.UserTypeEnum== UserTypeEnum.IndependentReviewer); + + var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId); + + var messageToSend = new MimeMessage(); + //发件地址 + messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com")); + //收件地址 + messageToSend.To.Add(new MailboxAddress(doctor.FullName, doctor.EMail)); + //主题 + messageToSend.Subject = $"[来自展影IRC] [{ trialInfo.ResearchProgramNo}]邀请信"; + + + var builder = new BodyBuilder(); + + + var token = _tokenService.GetToken(IRaCISClaims.Create(_mapper.Map(sysUserInfo))); + + if (sysUserInfo.IsFirstAdd) + { + await _userRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new User() { EmailToken = token }); + } + + + var pathToFile = _hostEnvironment.WebRootPath + + Path.DirectorySeparatorChar.ToString() + + "EmailTemplate" + + Path.DirectorySeparatorChar.ToString() + + (sysUserInfo.IsFirstAdd ? "TrialDoctorFirstJoin.html" : "TrialDoctorExistJoin.html"); + + using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) + { + var templateInfo = SourceReader.ReadToEnd(); + + var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&UserType=" + userType.UserTypeShortName + "&access_token=" + token; + + var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login")); + + var redirectUrl = $"{domain}/api/User/UserRedirect?url={ System.Web.HttpUtility.UrlEncode(routeUrl) }"; + + builder.HtmlBody = string.Format(templateInfo, + sysUserInfo.FullName, + trialInfo.ExperimentName, + trialInfo.ResearchProgramNo, + trialInfo.TrialCode, + sysUserInfo.UserName, + sysUserInfo.UserTypeRole.UserTypeShortName, + sysUserInfo.IsFirstAdd ? redirectUrl : baseUrl + ); + } + + messageToSend.Body = builder.ToMessageBody(); + + await SendEmailHelper.SendEmailAsync(messageToSend, null); + + + } + } diff --git a/IRaCIS.Core.Application/Service/WorkLoad/DTO/EnrollViewModel.cs b/IRaCIS.Core.Application/Service/WorkLoad/DTO/EnrollViewModel.cs index 0aafd7d1e..9ffb53c47 100644 --- a/IRaCIS.Core.Application/Service/WorkLoad/DTO/EnrollViewModel.cs +++ b/IRaCIS.Core.Application/Service/WorkLoad/DTO/EnrollViewModel.cs @@ -67,6 +67,21 @@ namespace IRaCIS.Core.Application.Service.WorkLoad.DTO } + public class ConfirmReviewerCommand + { + [NotDefault] + public Guid TrialId { get; set; } + + public Guid[] DoctorIdArray { get; set; } = new Guid [0]; + + public int ConfirmState { get; set; } + + public string BaseUrl { get; set; } = string.Empty; + + public string RouteUrl { get; set; } = string.Empty; + } + + public class EnrollCommand { public Guid Id { get; set; } diff --git a/IRaCIS.Core.Application/Service/WorkLoad/EnrollService.cs b/IRaCIS.Core.Application/Service/WorkLoad/EnrollService.cs index 7c0771ab6..a8e09b8ec 100644 --- a/IRaCIS.Core.Application/Service/WorkLoad/EnrollService.cs +++ b/IRaCIS.Core.Application/Service/WorkLoad/EnrollService.cs @@ -20,6 +20,7 @@ namespace IRaCIS.Application.Services private readonly IRepository _doctorRepository; private readonly IRepository _enrollDetailRepository; private readonly IRepository _workloadRepository; + private readonly IMailVerificationService _mailVerificationService; public EnrollService(IRepository clinicalTrialProjectRepository, @@ -27,7 +28,9 @@ namespace IRaCIS.Application.Services IRepository intoGroupRepository, IRepository doctorRepository, IRepository TrialPaymentPriceRepository, - IRepository intoGroupDetailRepository, IRepository workloadRepository) + IRepository intoGroupDetailRepository, + IRepository workloadRepository, + IMailVerificationService mailVerificationService) { _trialRepository = clinicalTrialProjectRepository; _TrialPaymentPriceRepository = TrialPaymentPriceRepository; @@ -38,6 +41,8 @@ namespace IRaCIS.Application.Services _enrollDetailRepository = intoGroupDetailRepository; _workloadRepository = workloadRepository; + _mailVerificationService = mailVerificationService; + } @@ -344,10 +349,11 @@ namespace IRaCIS.Application.Services /// 入组流程-后台确认医生入组[Confirm] /// - [HttpPost("{trialId:guid}/{confirmState:int}")] + [HttpPost] [TypeFilter(typeof(TrialResourceFilter))] [Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM)] - public async Task ConfirmReviewer(Guid trialId, Guid[] doctorIdArray, int confirmState) + [UnitOfWork] + public async Task ConfirmReviewer(ConfirmReviewerCommand confirmReviewerCommand) { //var trial = _trialRepository.FirstOrDefault(t => t.Id == trialId); //var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames); @@ -356,6 +362,8 @@ namespace IRaCIS.Application.Services ////trial.TrialStatus = (int)TrialStatus.HasConfirmedDoctorNames; //_trialRepository.Update(trial); + var trialId = confirmReviewerCommand.TrialId; + var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId); if (trial == null) return Null404NotFound(trial); @@ -364,16 +372,16 @@ namespace IRaCIS.Application.Services //更新入组表 var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId,true).ToListAsync(); - if (confirmState == 1) //确认入组 + if (confirmReviewerCommand.ConfirmState == 1) //确认入组 { foreach (var intoGroupItem in intoGroupList) { - if (doctorIdArray.Contains(intoGroupItem.DoctorId)) + if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId)) { intoGroupItem.EnrollStatus = (int)EnrollStatus.ConfirmIntoGroup; intoGroupItem.EnrollTime = DateTime.Now; - + await _mailVerificationService.DoctorJoinTrialEmail(trialId, intoGroupItem.DoctorId, confirmReviewerCommand.BaseUrl, confirmReviewerCommand.RouteUrl); await _enrollDetailRepository.AddAsync(new EnrollDetail() { DoctorId = intoGroupItem.DoctorId, @@ -385,11 +393,11 @@ namespace IRaCIS.Application.Services } } - else if (confirmState == 0)//回退上一步 + else if (confirmReviewerCommand.ConfirmState == 0)//回退上一步 { foreach (var intoGroupItem in intoGroupList) { - if (doctorIdArray.Contains(intoGroupItem.DoctorId)) + if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId)) { intoGroupItem.EnrollStatus = (int)EnrollStatus.InviteIntoGroup; intoGroupItem.EnrollTime = null; diff --git a/IRaCIS.Core.Application/Service/WorkLoad/Interface/IEnrollService.cs b/IRaCIS.Core.Application/Service/WorkLoad/Interface/IEnrollService.cs index 2ef888d98..bc34d3197 100644 --- a/IRaCIS.Core.Application/Service/WorkLoad/Interface/IEnrollService.cs +++ b/IRaCIS.Core.Application/Service/WorkLoad/Interface/IEnrollService.cs @@ -6,7 +6,7 @@ namespace IRaCIS.Application.Services { Task AddOrUpdateEnroll(EnrollCommand addOrUpdateModel); Task ApproveReviewer(Guid trialId, Guid[] doctorIdArray, int auditState); - Task ConfirmReviewer(Guid trialId, Guid[] doctorIdArray, int confirmState); + //Task ConfirmReviewer(Guid trialId, Guid[] doctorIdArray, int confirmState); Task EnrollBackOrOut(Guid trialId, Guid doctorId, int optType, DateTime? outEnrollTime); Task> GetTrialDoctorList(EnrollGetQuery challengeQuery); Task SelectReviewers(Guid trialId, Guid[] doctorIdArray); diff --git a/IRaCIS.Core.Domain.Share/Allocation/AllocationRelation.cs b/IRaCIS.Core.Domain.Share/Allocation/AllocationRelation.cs index ab982e16c..4c9dfa695 100644 --- a/IRaCIS.Core.Domain.Share/Allocation/AllocationRelation.cs +++ b/IRaCIS.Core.Domain.Share/Allocation/AllocationRelation.cs @@ -4,19 +4,22 @@ namespace IRaCIS.Core.Domain.Share { public enum ReadingCategory { - + //访视 Visit=1, + //阅片周期 ReadingPeriod=2, + //全局 Global=3 } public enum TaskState { - + //未分配 NotAllocate = 0, + //已分配 Allocated = 2, } diff --git a/IRaCIS.Core.Domain/Management/User.cs b/IRaCIS.Core.Domain/Management/User.cs index 493556c2b..cb19102bb 100644 --- a/IRaCIS.Core.Domain/Management/User.cs +++ b/IRaCIS.Core.Domain/Management/User.cs @@ -71,6 +71,9 @@ namespace IRaCIS.Core.Domain.Models public string EmailToken { get; set; } = string.Empty; + //ҽ˺ź󣬻ֵ + public Guid? DoctorId { get; set; } + [Projectable] public string FullName => LastName + " / " + FirstName; //[Projectable] public string FullName => $"{LastName} / {FirstName}";