//-------------------------------------------------------------------- // 此代码由T4模板自动生成 byzhouhang 20210918 // 生成时间 2022-06-07 14:10:49 // 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。 //-------------------------------------------------------------------- using IRaCIS.Core.Domain.Models; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Contracts; namespace IRaCIS.Core.Application.Service { /// /// 访视读片任务 /// [ApiExplorerSettings(GroupName = "Trial")] public class VisitTaskService : BaseService { private readonly IRepository _visitTaskRepository; private readonly IRepository _trialRepository; private readonly IRepository _subjectVisitRepository; private readonly IRepository _taskAllocationRuleRepository; private readonly IRepository _subjectRepository; private readonly IRepository _subjectUserRepository; public VisitTaskService(IRepository visitTaskRepository, IRepository trialRepository, IRepository subjectVisitRepository, IRepository subjectRepository, IRepository subjectUserRepository, IRepository taskAllocationRuleRepository ) { _taskAllocationRuleRepository = taskAllocationRuleRepository; _visitTaskRepository = visitTaskRepository; _trialRepository = trialRepository; _subjectVisitRepository = subjectVisitRepository; _subjectRepository = subjectRepository; _subjectUserRepository = subjectUserRepository; } [HttpPost] public async Task<(PageOutput, object)> GetVisitTaskList(VisitTaskQuery queryVisitTask, [FromServices] IVisitTaskHelpeService _visitTaskCommonService) { //以前访视未产生任务的,在查询这里要产生 var svIdList = await _subjectVisitRepository.Where(t => t.TrialId == queryVisitTask.TrialId && t.CheckState == CheckStateEnum.CVPassed && t.IsVisitTaskGenerated == false).Select(t => t.Id).ToListAsync(); await _visitTaskCommonService.GenerateVisitTaskAsync(queryVisitTask.TrialId, svIdList); var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == queryVisitTask.TrialId) .WhereIf(queryVisitTask.SiteId != null, t => t.Subject.SiteId == queryVisitTask.SiteId) .WhereIf(queryVisitTask.SubjectId != null, t => t.SubjectId == queryVisitTask.SubjectId) .WhereIf(queryVisitTask.IsUrgent != null, t => t.IsUrgent == queryVisitTask.IsUrgent) .WhereIf(queryVisitTask.DoctorUserId != null, t => t.DoctorUserId == queryVisitTask.DoctorUserId) .WhereIf(queryVisitTask.ReadingCategory != null, t => t.ReadingCategory == queryVisitTask.ReadingCategory) .WhereIf(queryVisitTask.TaskState != null, t => t.TaskState == queryVisitTask.TaskState) .WhereIf(!string.IsNullOrEmpty(queryVisitTask.TaskName), t => t.TaskName.Contains(queryVisitTask.TaskName) || t.TaskBlindName.Contains(queryVisitTask.TaskName)) .WhereIf(!string.IsNullOrEmpty(queryVisitTask.SubjectCode), t => t.Subject.Code.Contains(queryVisitTask.SubjectCode)) .WhereIf(queryVisitTask.BeginAllocateDate != null, t => t.AllocateTime > queryVisitTask.BeginAllocateDate) .WhereIf(queryVisitTask.EndAllocateDate != null, t => t.AllocateTime < queryVisitTask.EndAllocateDate.Value.AddDays(1)) .ProjectTo(_mapper.ConfigurationProvider); var defalutSortArray = new string[] { nameof(VisitTask.IsUrgent) + " desc", nameof(VisitTask.SubjectId) }; var pageList = await visitTaskQueryable.ToPagedListAsync(queryVisitTask.PageIndex, queryVisitTask.PageSize, queryVisitTask.SortField, queryVisitTask.Asc, string.IsNullOrWhiteSpace(queryVisitTask.SortField), defalutSortArray); var trialTaskConfig = _trialRepository.Where(t => t.Id == queryVisitTask.TrialId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); return (pageList, trialTaskConfig); } /// /// 获取手动分配 未分配的Subject列表(IsHaveAssigned 传递false) /// /// [HttpPost] public async Task> GetSubjectAssignList(SubjectAssignQuery querySubjectAssign) { var subjectQuery = _subjectRepository.Where(t => t.TrialId == querySubjectAssign.TrialId) .WhereIf(querySubjectAssign.SiteId != null, t => t.SiteId == querySubjectAssign.SiteId) .WhereIf(querySubjectAssign.SubjectId != null, t => t.Id == querySubjectAssign.SubjectId) .WhereIf(querySubjectAssign.IsHaveAssigned != null && querySubjectAssign.IsHaveAssigned == true, t => t.SubjectDoctorList.Count() > 0) .WhereIf(querySubjectAssign.IsHaveAssigned != null && querySubjectAssign.IsHaveAssigned == false, t => !t.SubjectDoctorList.Any()) .WhereIf(querySubjectAssign.IsHaveApplyedTask != null && querySubjectAssign.IsHaveApplyedTask == true, t => t.SubjectDoctorList.SelectMany(t => t.Subject.SubjectVisitTaskList).All(u => u.DoctorUserId != null)) .WhereIf(querySubjectAssign.IsHaveApplyedTask != null && querySubjectAssign.IsHaveApplyedTask == false, t => t.SubjectDoctorList.SelectMany(t => t.Subject.SubjectVisitTaskList).Any(u => u.DoctorUserId == null)) .WhereIf(querySubjectAssign.DoctorUserId != null, t => t.SubjectDoctorList.Any(t => t.DoctorUserId == querySubjectAssign.DoctorUserId)) .ProjectTo(_mapper.ConfigurationProvider); var pageList = await subjectQuery.ToPagedListAsync(querySubjectAssign.PageIndex, querySubjectAssign.PageSize, string.IsNullOrWhiteSpace(querySubjectAssign.SortField) ? nameof(querySubjectAssign.SubjectId) : querySubjectAssign.SortField, querySubjectAssign.Asc); return pageList; } /// /// 批量为 多个Subject 分配医生 手动分配 IsReAssign 为true 批量删除 重新分配 /// /// /// [HttpPost] public async Task AssignSubjectDoctor(AssginSubjectDoctorCommand assginSubjectDoctorCommand) { var doctorUserIdList = assginSubjectDoctorCommand.DoctorUserIdArmList.Select(t => t.DoctorUserId).ToList(); if (assginSubjectDoctorCommand.IsReAssign) { await _subjectUserRepository.BatchDeleteNoTrackingAsync(t => doctorUserIdList.Contains(t.DoctorUserId) && assginSubjectDoctorCommand.SubjectIdList.Contains(t.SubjectId)); } foreach (var subjectId in assginSubjectDoctorCommand.SubjectIdList) { foreach (var doctorUserId in doctorUserIdList) { var armEnum = assginSubjectDoctorCommand.DoctorUserIdArmList.Where(t => t.DoctorUserId == doctorUserId).First().ArmEnum; await _subjectUserRepository.AddAsync(new SubjectUser() { TrialId = assginSubjectDoctorCommand.TrialId, SubjectId = subjectId, DoctorUserId = doctorUserId, ArmEnum= armEnum, AssignTime = DateTime.Now }); } //await _subjectRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectId, u => new Subject() { IsAssignDoctorUser = true }); } await _subjectUserRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 批量取消Subject 分配的医生 /// /// [HttpPost] public async Task CancelSubjectAssignDoctor(CancelSubjectAssignCommand cancelSubjectAssignCommand) { foreach (var subjectId in cancelSubjectAssignCommand.SubjectIdList) { await _subjectUserRepository.DeleteFromQueryAsync(t => t.SubjectId == subjectId); //await _subjectRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectId, u => new Subject() { IsAssignDoctorUser = false }); } await _subjectUserRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 手动分配确认 绑定该Subject的已存在的任务给医生 /// /// /// [HttpPost] [UnitOfWork] public async Task ManualAssignDoctorApplyTask(AssignConfirmCommand assignConfirmCommand) { var trialId= assignConfirmCommand.TrialId; //获取项目配置 判断应该分配几个医生 //var trialConfig = (await _trialRepository.Where(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.ReadingType, t.IsFollowVisitAutoAssign, t.IsFollowGlobalVisitAutoAssign, t.FollowGlobalVisitAutoAssignDefaultState, t.TaskAllocateObjEnum }).FirstOrDefaultAsync()).IfNullThrowException(); //需要确认的Subject var subjectIdList = assignConfirmCommand.SubjectDoctorUserList.Select(t => t.SubjectId).ToList(); var taskList = _visitTaskRepository.Where(t => t.TrialId == assignConfirmCommand.TrialId && t.DoctorUserId == null, true) .WhereIf(subjectIdList.Count() > 0 /*&& trialConfig.ReadingType==ReadingMethod.Double*/, t => subjectIdList.Contains(t.SubjectId) && t.Subject.SubjectDoctorList.Any()) .ToList(); foreach (var subjectTaskGroup in taskList.GroupBy(t => t.SubjectId)) { var subjectId = subjectTaskGroup.Key; //如果数据为空 那么就是确认所有已分配的 List subjectDoctorIdList = new List(); if (assignConfirmCommand.SubjectDoctorUserList.Count == 0) { subjectDoctorIdList = _subjectUserRepository.Where(t => t.SubjectId == subjectId).Select(t => t.DoctorUserId).ToList(); } else { subjectDoctorIdList = assignConfirmCommand.SubjectDoctorUserList.Where(t => t.SubjectId == subjectId).First().DoctorUserIdList; } foreach (var task in subjectTaskGroup.OrderBy(t => t.ArmEnum).ToList()) { //单重阅片 if (task.ArmEnum == 0) { if (subjectDoctorIdList.Count() == 0) { throw new BusinessValidationFailedException("当前提交的数据,有Subject 未绑定医生"); } task.DoctorUserId = subjectDoctorIdList.FirstOrDefault(); } //双重阅片 任务1 else if (task.ArmEnum == 1) { if (subjectDoctorIdList.Count() != 2) { throw new BusinessValidationFailedException("当前提交的数据,有Subject绑定的医生数量不是2个"); } task.DoctorUserId = subjectDoctorIdList.FirstOrDefault(); } else if (task.ArmEnum == 2) { task.DoctorUserId = subjectDoctorIdList.Skip(1).FirstOrDefault(); } task.AllocateTime = DateTime.Now; task.TaskState = TaskState.Allocated; } } await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 自动一次性分配所有未分配的 Subject 给医生 /// /// /// [HttpPost] [UnitOfWork] public async Task AutoSubjectAssignDoctor(AutoSubjectAssignCommand autoSubjectAssignCommand) { //自动分配的话,需要把手动分配的给删掉 var trialId = autoSubjectAssignCommand.TrialId; //获取所有的Subject 目前的分配情况 var subjectList = _subjectRepository.Where(t => t.TrialId == trialId).Select(t => new { SubjectId = t.Id, DoctorUserIdList = t.SubjectDoctorList.Select(t => t.DoctorUserId) }).ToList(); //受试者总数 var subjectCount = subjectList.Count(); //获取待分配的医生列表 指导分配医生的数量 var waitAllocationDoctorList = _taskAllocationRuleRepository.Where(t => t.TrialId == trialId && t.IsEnable) .Select(t => new { t.DoctorUserId, t.PlanReadingRatio, Weight = (double)(subjectCount * t.PlanReadingRatio) % 100 }) .OrderByDescending(t => t.PlanReadingRatio).ThenByDescending(t => t.Weight); //获取项目配置 判断应该分配几个医生 var trialConfig = (await _trialRepository.Where(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.ReadingType, t.IsFollowVisitAutoAssign, t.IsFollowGlobalVisitAutoAssign, t.FollowGlobalVisitAutoAssignDefaultState, t.TaskAllocateObjEnum }).FirstOrDefaultAsync()).IfNullThrowException(); //存放分配后Subject 医生的情况 var assignedSubjectDoctorList = subjectList.Clone().SelectMany(t => t.DoctorUserIdList.Select(c => new { t.SubjectId, DoctorUserId = c })).ToList(); //给医生分配Subject 前验证 已经分配的数据是否符合分配的规范 foreach (var doctor in waitAllocationDoctorList) { //该医生的目前已分配到的受试者 var hasAssignedSubjectIdList = assignedSubjectDoctorList.Where(t => t.DoctorUserId == doctor.DoctorUserId).Select(t => t.SubjectId).ToList(); //验证已经分配的Subject 是否 符合项目配置规范 foreach (var subjectId in hasAssignedSubjectIdList) { var hasAssignDoctorCount = subjectList.Where(t => t.SubjectId == subjectId).FirstOrDefault().DoctorUserIdList.Count(); //分配两个医生 if (trialConfig.ReadingType == ReadingMethod.Double) { if (hasAssignDoctorCount > 2) { throw new BusinessValidationFailedException("当前有Subject绑定医生数量大于2"); } } else if (trialConfig.ReadingType == ReadingMethod.Single) { if (hasAssignDoctorCount > 1) { throw new BusinessValidationFailedException("当前有Subject绑定医生数量大于1"); } } } } //验证通过 给医生开始分配 //eg : 10个Sujbect 都是1/4 先分配整数 再分配 10%4=2个 //不够分的subject数量 适用于 2个Subject 4个医生 这种 var specialSubjectCount = subjectCount % waitAllocationDoctorList.Count(); foreach (var doctor in waitAllocationDoctorList) { //该医生的目前已分配到的受试者 var hasAssignedSubjectIdList = assignedSubjectDoctorList.Where(t => t.DoctorUserId == doctor.DoctorUserId).Select(t => t.SubjectId).ToList(); //已分配的Subject 数量 var hasAssignedSubjectCount = hasAssignedSubjectIdList.Count(); //该医生计划分配到的Subject 最接近的整数数量 var planSubjectCount = (int)Math.Ceiling((double)(subjectCount * doctor.PlanReadingRatio) / 100); //权重大的,将特殊的分配 if (doctor.Weight >= 50) { if (specialSubjectCount > 0) { specialSubjectCount--; planSubjectCount++; } } //如果计划的数量 大于已经分配的数量 那么该医生 可以分配新的Subject if (planSubjectCount > hasAssignedSubjectCount) { //从未分配的Subjct找到可以分配的分配给该医生 var allAssignedSubjectIdList = assignedSubjectDoctorList.Select(t => t.SubjectId).ToList(); //取需要分配的数量 并且没有分配给其他医生的包括自己 var assignSubjectIdList = subjectList.Where(t => !allAssignedSubjectIdList.Contains(t.SubjectId)).Select(t => t.SubjectId).Take(planSubjectCount - hasAssignedSubjectCount).ToList(); foreach (var assignSubjectId in assignSubjectIdList) { //将分配结果记录 assignedSubjectDoctorList.Add(new { SubjectId = assignSubjectId, DoctorUserId = doctor.DoctorUserId }); await _subjectUserRepository.AddAsync(new SubjectUser() { TrialId = trialId, SubjectId = assignSubjectId, DoctorUserId = doctor.DoctorUserId, AssignTime = DateTime.Now }); } } } //验证是否所有Subject 是否分配好 if (assignedSubjectDoctorList.Select(t => t.SubjectId).Count() != subjectCount) { throw new BusinessValidationFailedException("分配算法有问题,有Subject 未分配"); } await _subjectUserRepository.SaveChangesAsync(); //如果是2个Subject 3个医生 这种 都是百分之33的比率 // 10 3 #region 按照Subject 遍历去分 //foreach (var subject in subjectList) //{ // //该Subject 已经分配的医生数量 // var hasAssignDoctorCount = subject.DoctorUserIdList.Count(); // //分配两个医生 // if (trialConfig.ReadingType == ReadingMethod.Double) // { // //await _subjectUserRepository.AddAsync(new SubjectUser() { TrialId = trialId, SubjectId = subject.SubjectId, DoctorUserId = doctorUserId, AssignTime = DateTime.Now }); // if (hasAssignDoctorCount == 0) // { // } // else if (hasAssignDoctorCount == 1) // { // } // else if (hasAssignDoctorCount == 2) // { // } // else // { // throw new BusinessValidationFailedException("当前有Subject绑定医生数量大于2"); // } // } // else if (trialConfig.ReadingType == ReadingMethod.Single) // { // if (hasAssignDoctorCount == 0) // { // } // else if (hasAssignDoctorCount == 1) // { // } // else // { // throw new BusinessValidationFailedException("当前有Subject绑定医生数量大于1"); // } // } //} #endregion return ResponseOutput.Ok(); } /// /// 任务 手动分配 重新分配 确认 取消分配 /// 分配 /// /// [HttpPost] [UnitOfWork] public async Task AssignSubjectTaskToDoctor(AssignSubjectTaskToDoctorCommand assignSubjectTaskToDoctorCommand) { var visitTask = await _visitTaskRepository.FirstOrDefaultAsync(t => t.Id == assignSubjectTaskToDoctorCommand.Id); if (assignSubjectTaskToDoctorCommand.TaskOptType == TaskOptType.Assign || assignSubjectTaskToDoctorCommand.TaskOptType == TaskOptType.ReAssign) { visitTask.AllocateTime = DateTime.Now; visitTask.DoctorUserId = assignSubjectTaskToDoctorCommand.DoctorUserId; visitTask.TaskState = TaskState.Allocated; } else if (assignSubjectTaskToDoctorCommand.TaskOptType == TaskOptType.ReAssign) { //验证 是不是两个任务都给了同一个医生 //是否删除配置规则表里的 Subject 医生绑定关系 重新添加绑定关系 //是否其该Subject 其他访视 绑定的医生 也同时变更? } else if (assignSubjectTaskToDoctorCommand.TaskOptType == TaskOptType.Confirm) { visitTask.TaskState = TaskState.Allocated; } else if (assignSubjectTaskToDoctorCommand.TaskOptType == TaskOptType.CancelAssign) { visitTask.AllocateTime = null; visitTask.DoctorUserId = null; visitTask.TaskState = TaskState.NotAllocate; } await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } } }