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}";