437 lines
18 KiB
C#
437 lines
18 KiB
C#
using IRaCIS.Application.Interfaces;
|
||
using IRaCIS.Core.Application.Contracts;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.AspNetCore.Hosting;
|
||
using Microsoft.AspNetCore.Http;
|
||
using IRaCIS.Core.Domain.Share;
|
||
using EasyCaching.Core;
|
||
using IRaCIS.Core.Infrastructure;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using IRaCIS.Core.Application.Auth;
|
||
|
||
namespace IRaCIS.Core.Application
|
||
{
|
||
[ApiExplorerSettings(GroupName = "Trial")]
|
||
public class TrialConfigService : BaseService, ITrialConfigService
|
||
{
|
||
private readonly IRepository<Trial> _trialRepository;
|
||
private readonly IRepository<TrialQCQuestion> _trialQCQuestionRepository;
|
||
private readonly IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository;
|
||
private readonly IRepository<ClinicalDataTrialSet> _clinicalDataTrialSetRepository;
|
||
private readonly IEasyCachingProvider _provider;
|
||
|
||
private readonly IRepository<TaskAllocationRule> _taskAllocationRuleRepository;
|
||
|
||
public TrialConfigService(IRepository<Trial> trialRepository,
|
||
IRepository<TrialQCQuestion> trialQCQuestionRepository,
|
||
IRepository<ReadingQuestionCriterionTrial> readingQuestionCriterionTrialRepository,
|
||
IRepository<ClinicalDataTrialSet> clinicalDataTrialSetRepository,
|
||
IRepository<TaskAllocationRule> taskAllocationRuleRepository,
|
||
IEasyCachingProvider provider
|
||
)
|
||
{
|
||
_trialRepository = trialRepository;
|
||
_taskAllocationRuleRepository = taskAllocationRuleRepository;
|
||
this._trialQCQuestionRepository = trialQCQuestionRepository;
|
||
this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository;
|
||
this._clinicalDataTrialSetRepository = clinicalDataTrialSetRepository;
|
||
this._provider = provider;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取签名文本
|
||
/// </summary>
|
||
/// <param name="signCode"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("{signCode}")]
|
||
public async Task<IResponseOutput> GetSignText(string signCode)
|
||
{
|
||
var signRawText = await _repository.Where<SystemBasicData>(t => t.Code == signCode).Select(t => new { t.Code, t.Value, t.Id, ParentValue = t.Parent.Value, ParentValueCN = t.Parent.ValueCN }).FirstOrDefaultAsync();
|
||
|
||
if (signRawText == null)
|
||
{
|
||
return ResponseOutput.NotOk("该操作需要电子签名确认,但未在系统中找到该场景的签名模板。");
|
||
}
|
||
|
||
return ResponseOutput.Ok(new
|
||
{
|
||
SignCodeId = signRawText.Id,
|
||
SignCode = signRawText.Code,
|
||
SignText = signRawText.ParentValue.Replace("xxx", signRawText.Value),
|
||
SignTextCN = signRawText.ParentValueCN.Replace("xxx", signRawText.Value)
|
||
});
|
||
}
|
||
|
||
|
||
//验证 仅仅在 Initializing/Ongoing 才可以操作
|
||
private async Task VerifyOnlyInOngoingOrInitialIzingOptAsync(Guid trialId)
|
||
{
|
||
if (!await _trialRepository.AnyAsync(t => t.Id == trialId && (t.TrialStatusStr == StaticData.TrialState.TrialInitializing || t.TrialStatusStr == StaticData.TrialState.TrialOngoing)))
|
||
{
|
||
throw new BusinessValidationFailedException("该项目已结束或停止,不允许修改配置。");
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 签名确认 包括项目的三组配置 + QC问题确认 后修改状态 (适用于不会回退的,项目废除、状态修改, 存在回退 不在这里弄,提供单独接口修改状态)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[Authorize(Policy = IRaCISPolicy.PM_APM)]
|
||
public async Task<IResponseOutput> TrialConfigSignatureConfirm(SignConfirmDTO signConfirmDTO)
|
||
{
|
||
await VerifyOnlyInOngoingOrInitialIzingOptAsync(signConfirmDTO.TrialId);
|
||
|
||
|
||
|
||
if (signConfirmDTO.SignCode == ((int)SignEnum.TrialLogicConfim).ToString())
|
||
{
|
||
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialBasicLogicConfirmed = true });
|
||
}
|
||
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialProcessConfim).ToString())
|
||
{
|
||
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialProcessConfirmed = true });
|
||
}
|
||
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialUrgentConfim).ToString())
|
||
{
|
||
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialUrgentConfirmed = true });
|
||
}
|
||
|
||
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
|
||
{
|
||
|
||
var trialConfig = (await _trialRepository
|
||
.Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
|
||
.FirstOrDefaultAsync(t => t.TrialId == signConfirmDTO.TrialId))
|
||
.IfNullThrowException();
|
||
|
||
|
||
var showOrderList = await _repository.Where<TrialQCQuestion>(t => t.TrialId == signConfirmDTO.TrialId).Select(t =>
|
||
new { t.ShowOrder, ParentShowOrder = (int?)t.ParentQCQuestion.ShowOrder }).ToListAsync();
|
||
|
||
if (trialConfig.QCProcessEnum ==
|
||
TrialQCProcess.DoubleAudit || trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
|
||
{
|
||
if (showOrderList.Count == 0)
|
||
{
|
||
throw new BusinessValidationFailedException("当前未添加影像质控审核问题。请先添加影像质控审核问题,再进行确认。");
|
||
}
|
||
}
|
||
|
||
if (showOrderList.Count() != showOrderList.Select(t => t.ShowOrder).Distinct().Count())
|
||
{
|
||
throw new BusinessValidationFailedException("影像质控审核问题显示序号不能重复。");
|
||
}
|
||
|
||
if (showOrderList.Where(t => t.ParentShowOrder != null).Any(t => t.ParentShowOrder > t.ShowOrder))
|
||
{
|
||
throw new BusinessValidationFailedException("父问题的显示序号要比子问题的显示序号小,请确认。");
|
||
}
|
||
|
||
if (await _trialRepository.AnyAsync(t => t.Id == signConfirmDTO.TrialId && t.QCQuestionConfirmedUserId != null && t.QCQuestionConfirmedUserId != _userInfo.Id))
|
||
{
|
||
throw new BusinessValidationFailedException("影像质控审核问题已被其他人员确认,不允许再次确认。");
|
||
}
|
||
|
||
await _trialQCQuestionRepository.UpdatePartialFromQueryAsync(t => t.TrialId == signConfirmDTO.TrialId, x => new TrialQCQuestion
|
||
{
|
||
IsConfirm = true
|
||
});
|
||
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = DateTime.Now, QCQuestionConfirmedUserId = _userInfo.Id, IsQCQuestionConfirmed = true });
|
||
await _trialRepository.SaveChangesAsync();
|
||
}
|
||
|
||
|
||
|
||
return ResponseOutput.Ok();
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 配置 基础逻辑信息
|
||
/// </summary>
|
||
/// <param name="trialConfig"></param>
|
||
/// <returns></returns>
|
||
[HttpPut]
|
||
[Authorize(Policy = IRaCISPolicy.PM_APM)]
|
||
public async Task<IResponseOutput> ConfigTrialBasicInfo(BasicTrialConfig trialConfig)
|
||
{
|
||
await VerifyOnlyInOngoingOrInitialIzingOptAsync(trialConfig.TrialId);
|
||
|
||
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException();
|
||
|
||
|
||
_mapper.Map(trialConfig, trialInfo);
|
||
trialInfo.UpdateTime = DateTime.Now;
|
||
|
||
|
||
var noconfirmids = await _clinicalDataTrialSetRepository.Where(x => x.TrialId == trialConfig.TrialId && !trialConfig.ClinicalDataTrialSetIds.Contains(x.Id)).Select(x => x.Id).ToListAsync();
|
||
foreach (var item in trialConfig.ClinicalDataTrialSetIds)
|
||
{
|
||
await _clinicalDataTrialSetRepository.UpdatePartialFromQueryAsync(item, x => new ClinicalDataTrialSet()
|
||
{
|
||
|
||
IsConfirm = true
|
||
});
|
||
}
|
||
|
||
foreach (var item in noconfirmids)
|
||
{
|
||
await _clinicalDataTrialSetRepository.UpdatePartialFromQueryAsync(item, x => new ClinicalDataTrialSet()
|
||
{
|
||
|
||
IsConfirm = false
|
||
});
|
||
}
|
||
|
||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||
}
|
||
|
||
[HttpGet("{trialId:guid}")]
|
||
public async Task<IResponseOutput> IfTrialCanOngoing(Guid trialId)
|
||
{
|
||
var canOPt = await _trialRepository.AnyAsync(trial =>
|
||
trial.Id == trialId && trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed &&
|
||
trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed);
|
||
return ResponseOutput.Ok(canOPt, msg: canOPt ? "" : "该项目的项目配置(基础配置、流程配置、加急配置) 、访视管理,有配置未确认,不能设置项目状态为启动。");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新项目状态
|
||
/// </summary>
|
||
/// <param name="trialId"></param>
|
||
/// <param name="trialStatusStr"></param>
|
||
/// <param name="reason"></param>
|
||
/// <returns></returns>
|
||
[HttpPut("{trialId:guid}/{trialStatusStr}/{reason?}")]
|
||
[UnitOfWork]
|
||
[Authorize(Policy = IRaCISPolicy.PM)]
|
||
public async Task<IResponseOutput> UpdateTrialState(Guid trialId, string trialStatusStr, string? reason)
|
||
{
|
||
|
||
var trial = (await _trialRepository.Where(t => t.Id == trialId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
|
||
|
||
if (trialStatusStr == StaticData.TrialState.TrialOngoing)
|
||
{
|
||
if (trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed && trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed)
|
||
{
|
||
|
||
}
|
||
else
|
||
{
|
||
return ResponseOutput.NotOk("无法变更项目状态。该项目的项目配置、访视管理中,有未确认项");
|
||
}
|
||
}
|
||
|
||
if ((trialStatusStr == StaticData.TrialState.TrialStopped || trialStatusStr == StaticData.TrialState.TrialCompleted) && trial.TrialStatusStr != StaticData.TrialState.TrialOngoing)
|
||
{
|
||
return ResponseOutput.NotOk("项目没有进入启动状态,不能设置为停止或完成状态");
|
||
}
|
||
|
||
if (trialStatusStr != StaticData.TrialState.TrialOngoing)
|
||
{
|
||
trial.TrialFinishTime = DateTime.Now;
|
||
}
|
||
|
||
trial.TrialStateChangeList.Add(new TrialStateChange() { OriginState = trial.TrialStatusStr, NowState = trialStatusStr, Reason = reason ?? String.Empty, TrialId = trialId });
|
||
|
||
trial.TrialStatusStr = trialStatusStr;
|
||
|
||
|
||
//Paused、 添加工总量 算医生读片中
|
||
if (trialStatusStr.Contains(StaticData.TrialState.TrialCompleted))
|
||
{
|
||
await _repository.BatchUpdateAsync<Enroll>(u => u.TrialId == trialId, e => new Enroll
|
||
{
|
||
EnrollStatus = (int)EnrollStatus.Finished
|
||
});
|
||
|
||
await _trialRepository.BatchUpdateNoTrackingAsync(u => u.Id == trialId, s => new Trial { TrialFinishedTime = DateTime.UtcNow.AddHours(8) });
|
||
|
||
}
|
||
|
||
await _provider.SetAsync(trialId.ToString(), trialStatusStr, TimeSpan.FromDays(7));
|
||
|
||
await _repository.SaveChangesAsync();
|
||
|
||
|
||
//var success = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
|
||
|
||
|
||
return ResponseOutput.Ok();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 项目状态 变更历史
|
||
/// </summary>
|
||
/// <param name="trialId"></param>
|
||
/// <returns></returns>
|
||
|
||
[HttpGet("{trialId:guid}")]
|
||
public async Task<List<TrialStateChangeDTO>> GetTrialStateChangeList(Guid trialId)
|
||
{
|
||
return await _repository.Where<TrialStateChange>(t => t.TrialId == trialId).ProjectTo<TrialStateChangeDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 废除项目
|
||
/// </summary>
|
||
/// <param name="trialId"></param>
|
||
/// <param name="isAbandon"></param>
|
||
/// <returns></returns>
|
||
[HttpPut("{trialId:guid}/{isAbandon:bool}")]
|
||
[Authorize(Policy = IRaCISPolicy.PM)]
|
||
public async Task<IResponseOutput> AbandonTrial(Guid trialId, /*Guid? signId,*/ bool isAbandon)
|
||
{
|
||
|
||
await _trialRepository.UpdatePartialFromQueryAsync(trialId, u => new Trial()
|
||
{
|
||
IsDeleted = isAbandon,
|
||
TrialFinishTime = isAbandon ? DateTime.Now : null
|
||
}, true);
|
||
|
||
|
||
return ResponseOutput.Ok();
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取 配置的所有信息 没有分多个接口
|
||
/// </summary>
|
||
/// <param name="trialId"></param>
|
||
/// <returns></returns>
|
||
[HttpGet("{trialId:guid}")]
|
||
public async Task<TrialConfigDTO> GetTrialConfigInfo(Guid trialId)
|
||
{
|
||
return await _trialRepository.Where(t => t.Id == trialId).ProjectTo<TrialConfigDTO>(_mapper.ConfigurationProvider)
|
||
.FirstOrDefaultAsync().IfNullThrowException();
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 配置流程
|
||
/// </summary>
|
||
/// <param name="trialConfig"></param>
|
||
/// <returns></returns>
|
||
[HttpPut]
|
||
[Authorize(Policy = IRaCISPolicy.PM_APM)]
|
||
public async Task<IResponseOutput> ConfigTrialProcessInfo(TrialProcessConfig trialConfig)
|
||
{
|
||
if (!await _trialRepository.Where(t => t.Id == trialConfig.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialState.TrialInitializing))
|
||
{
|
||
return ResponseOutput.NotOk("该项目当前状态不是初始化,不允许进行该操作。");
|
||
}
|
||
|
||
var trialInfo = await _trialRepository.Where(t => t.Id == trialConfig.TrialId, true).Include(t => t.TrialDicList.Where(u => u.KeyName == StaticData.Criterion)).FirstOrDefaultAsync();
|
||
if (trialInfo == null) return Null404NotFound(trialInfo);
|
||
|
||
_mapper.Map(trialConfig, trialInfo);
|
||
|
||
trialInfo.UpdateTime = DateTime.Now;
|
||
|
||
|
||
var cancelConfirmCriterionIds = await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == trialConfig.TrialId && x.IsConfirm && !trialConfig.TrialCriterionIds.Contains(x.Id)).Select(x => x.Id).ToListAsync();
|
||
|
||
|
||
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => cancelConfirmCriterionIds.Contains(x.Id), x => new ReadingQuestionCriterionTrial()
|
||
{
|
||
IsConfirm = false
|
||
});
|
||
|
||
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => trialConfig.TrialCriterionIds.Contains(x.Id), x => new ReadingQuestionCriterionTrial()
|
||
{
|
||
IsConfirm = true
|
||
}); ;
|
||
|
||
|
||
|
||
|
||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||
}
|
||
|
||
/// <summary>
|
||
/// 配置加急信息
|
||
/// </summary>
|
||
/// <param name="trialConfig"></param>
|
||
/// <returns></returns>
|
||
[HttpPut]
|
||
[Authorize(Policy = IRaCISPolicy.PM_APM)]
|
||
public async Task<IResponseOutput> ConfigTrialUrgentInfo(TrialUrgentConfig trialConfig)
|
||
{
|
||
|
||
await VerifyOnlyInOngoingOrInitialIzingOptAsync(trialConfig.TrialId);
|
||
|
||
|
||
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException();
|
||
|
||
|
||
//项目紧急 当前所有已提交,但未完成的访视,设置为加急。后续提交的访视也设置为加急 (在提交的时候,回去判断 项目加急,Subject加急,是否入组确认,是否Pd,从而设置访视是否加急)
|
||
if (trialConfig.IsUrgent)
|
||
{
|
||
|
||
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.TrialId == trialInfo.Id && t.SubmitState == SubmitStateEnum.Submitted && t.ForwardState < ForwardStateEnum.Forwarded,
|
||
s => new SubjectVisit() { IsUrgent = trialConfig.IsUrgent });
|
||
}
|
||
else //之前设置为加急的访视状态不变。后续提交的访视,为不加急。
|
||
{
|
||
|
||
}
|
||
|
||
_mapper.Map(trialConfig, trialInfo);
|
||
|
||
trialInfo.UpdateTime = DateTime.Now;
|
||
|
||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 配置项目任务信息
|
||
/// </summary>
|
||
/// <param name="trialConfig"></param>
|
||
/// <returns></returns>
|
||
[HttpPut]
|
||
public async Task<IResponseOutput> ConfigTrialTaskInfo(TrialTaskConfig trialConfig)
|
||
{
|
||
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException();
|
||
|
||
_mapper.Map(trialConfig, trialInfo);
|
||
|
||
if (_taskAllocationRuleRepository.Where(t => t.TrialId == trialConfig.TrialId && t.IsEnable).Sum(t => t.PlanReadingRatio) != 100)
|
||
{
|
||
return ResponseOutput.NotOk("已启用医生比率不为百分之100");
|
||
}
|
||
|
||
return ResponseOutput.Ok(await _trialRepository.SaveChangesAsync());
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 配置项目赌片规则信息
|
||
/// </summary>
|
||
/// <param name="trialConfig"></param>
|
||
/// <returns></returns>
|
||
[HttpPut]
|
||
public async Task<IResponseOutput> ConfigTrialReadingTaskViewRule(TrialReadingTaskViewConfig trialConfig)
|
||
{
|
||
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException();
|
||
|
||
_mapper.Map(trialConfig, trialInfo);
|
||
|
||
return ResponseOutput.Ok(await _trialRepository.SaveChangesAsync());
|
||
}
|
||
|
||
|
||
|
||
}
|
||
}
|