irc-netcore-api/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs

482 lines
22 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.

//--------------------------------------------------------------------
// 此代码由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
{
/// <summary>
/// 访视读片任务
/// </summary>
[ApiExplorerSettings(GroupName = "Trial")]
public class VisitTaskService : BaseService
{
private readonly IRepository<VisitTask> _visitTaskRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<TaskAllocationRule> _taskAllocationRuleRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectUser> _subjectUserRepository;
public VisitTaskService(IRepository<VisitTask> visitTaskRepository, IRepository<Trial> trialRepository, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<Subject> subjectRepository, IRepository<SubjectUser> subjectUserRepository, IRepository<TaskAllocationRule> taskAllocationRuleRepository
)
{
_taskAllocationRuleRepository = taskAllocationRuleRepository;
_visitTaskRepository = visitTaskRepository;
_trialRepository = trialRepository;
_subjectVisitRepository = subjectVisitRepository;
_subjectRepository = subjectRepository;
_subjectUserRepository = subjectUserRepository;
}
[HttpPost]
public async Task<(PageOutput<VisitTaskView>, 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<VisitTaskView>(_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<TrialTaskConfig>(_mapper.ConfigurationProvider).FirstOrDefault();
return (pageList, trialTaskConfig);
}
/// <summary>
/// 获取手动分配 未分配的Subject列表(IsHaveAssigned 传递false)
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<SubjectAssignView>> 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<SubjectAssignView>(_mapper.ConfigurationProvider);
var pageList = await subjectQuery.ToPagedListAsync(querySubjectAssign.PageIndex, querySubjectAssign.PageSize, string.IsNullOrWhiteSpace(querySubjectAssign.SortField) ? nameof(querySubjectAssign.SubjectId) : querySubjectAssign.SortField, querySubjectAssign.Asc);
return pageList;
}
/// <summary>
/// 批量为 多个Subject 分配医生 手动分配 IsReAssign 为true 批量删除 重新分配
/// </summary>
/// <param name="assginSubjectDoctorCommand"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> 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();
}
/// <summary>
/// 批量取消Subject 分配的医生
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> 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();
}
/// <summary>
/// 手动分配确认 绑定该Subject的已存在的任务给医生
/// </summary>
/// <param name="assignConfirmCommand"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> 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<Guid> subjectDoctorIdList = new List<Guid>();
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();
}
/// <summary>
/// 自动一次性分配所有未分配的 Subject 给医生
/// </summary>
/// <param name="autoSubjectAssignCommand"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> 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();
}
/// <summary>
/// 任务 手动分配 重新分配 确认 取消分配
/// </summary>分配
/// <param name="assignSubjectTaskToDoctorCommand"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> 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();
}
}
}