EI-Image-Viewer-Api/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs

347 lines
15 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.

using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Excel.AspNetCore;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Auth;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Trial")]
public class VisitPlanService : BaseService, IVisitPlanService
{
private readonly IRepository<VisitStage> _visitStageRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<VisitPlanInfluenceStudy> _influnceRepository;
public VisitPlanService(IRepository<VisitStage> visitStageRepository, IRepository<Trial> trialRepository, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<VisitPlanInfluenceStudy> visitPlanInfluenceStudy)
{
_visitStageRepository = visitStageRepository;
_trialRepository = trialRepository;
_subjectVisitRepository = subjectVisitRepository;
_influnceRepository = visitPlanInfluenceStudy;
}
///暂时不用
/// <summary> 获取项目访视计划</summary>
[HttpPost]
public async Task<PageOutput<VisitStageDTO>> GetTrialVisitStageList(VisitPlanQueryDTO param)
{
var visitStageQuery = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == param.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(param.Keyword), t => t.VisitName.Contains(param.Keyword))
.ProjectTo<VisitStageDTO>(_mapper.ConfigurationProvider);
return await visitStageQuery.ToPagedListAsync(param.PageIndex, param.PageSize, "CreateTime", param.Asc);
}
/// <summary> 根据项目Id获取项目访视计划(不分页)[New]</summary>
[HttpGet("{trialId:guid}")]
public async Task<VisitPlanView> GetVisitStageList(Guid trialId)
{
var query = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == trialId)
.ProjectTo<VisitStageDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
var list = await query.ToListAsync();
var trial = (await _repository.FirstOrDefaultAsync<Trial>(t => t.Id == trialId)).IfNullThrowException();
return new VisitPlanView()
{
VisitPlanList = list,
TimePointsPerPatient = trial.TimePointsPerPatient,
VisitPlanConfirmed = trial.VisitPlanConfirmed,
IsHaveFirstGiveMedicineDate = trial.IsHaveFirstGiveMedicineDate,
//SubjectHasAdded = _subjectVisitRepository.Any(t => t.TrialId == trialId)
};
}
/// <summary>
/// 获取访视计划下拉框列表
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpGet("{trialId:guid}")]
public async Task<IEnumerable<VisitStageSelectDTO>> GetTrialVisitStageSelect(Guid trialId)
{
var query = _visitStageRepository.Where(u => u.TrialId == trialId)
.ProjectTo<VisitStageSelectDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
var list = await query.ToListAsync();
return list;
}
/// <summary> 添加或更新访视计划某项</summary>
[UnitOfWork]
[HttpPost]
[Authorize(Policy = IRaCISPolicy.PM_APM)]
public async Task<IResponseOutput> AddOrUpdateVisitStage(VisitPlanCommand visitPlan)
{
if (!await _trialRepository.Where(t => t.Id == visitPlan.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialState.TrialOngoing || t.TrialStatusStr == StaticData.TrialState.TrialInitializing))
{
throw new BusinessValidationFailedException("只有当项目状态为:初始化或进行中时,可以操作。 ");
}
var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId, ignoreQueryFilters: true)
.Select(t => new { t.Id, t.VisitNum, t.VisitDay }).OrderBy(t => t.VisitNum).ToListAsync();
//更新的时候,需要排除自己
if (visitPlan.Id != null)
{
visitPlanList = visitPlanList.Where(t => t.Id != visitPlan.Id).ToList();
}
if (visitPlanList.Any(t => t.VisitNum < visitPlan.VisitNum))
{
//比当前 visitNum小的 visitDay的最大值 还小 不允许添加
if (visitPlan.VisitDay <= visitPlanList.Where(t => t.VisitNum < visitPlan.VisitNum).Select(t => t.VisitDay).Max())
{
throw new BusinessValidationFailedException("访视计划中,访视号大的访视,其访视间隔也应该比访视号小的访视大。");
}
}
if (visitPlanList.Any(t => t.VisitNum > visitPlan.VisitNum))
{
if (visitPlan.VisitDay >= visitPlanList.Where(t => t.VisitNum > visitPlan.VisitNum).Select(t => t.VisitDay).Min())
{
throw new BusinessValidationFailedException("访视计划中,访视号大的计划访视,其访视间隔也应该比访视号小的计划访视大。");
}
}
if (visitPlan.Id == Guid.Empty || visitPlan.Id == null)//add
{
var trial = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.TrialId)).IfNullThrowException();
trial.VisitPlanConfirmed = false;
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum), true))
{
throw new BusinessValidationFailedException("访视计划中已经存在具有项目访视名称或者访视号的计划访视模板。");
}
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine, true) && visitPlan.IsBaseLine)
{
throw new BusinessValidationFailedException("访视计划中已经存在基线。");
}
//不用前端传递的值
visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3");
var visitPlanItem = await _visitStageRepository.InsertFromDTOAsync(visitPlan, true);
#region 废弃前
// var visitPlanItem = _mapper.Map<VisitStage>(visitPlan);
//visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3");
//var result = await _visitStageRepository.AddAsync(visitPlanItem,true);
#endregion
return ResponseOutput.Ok(visitPlanItem.Id);
}
else//update
{
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id, true))
{
throw new BusinessValidationFailedException("访视计划中已经存在具有项目访视名称或者访视号的计划访视模板。");
}
if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id, true) && visitPlan.IsBaseLine)
{
throw new BusinessValidationFailedException("访视计划中已经存在基线。");
}
#region 废弃前
//var stage = (await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id, true)).IfNullThrowException();
////修改是否是基线
//if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine)
//{
// if (await _repository.Where<SubjectVisit>(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit))
// {
// throw new BusinessValidationFailedException("有CRC已经为基线上传了影像数据,不允许修改基线");
// }
//}
//_mapper.Map(visitPlan, stage);
//stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3");
//await _visitStageRepository.SaveChangesAsync();
#endregion
//不用前端传递的值
visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3");
//返回的是数据库查询的数据
var stage = await _visitStageRepository.UpdateFromDTOAsync(visitPlan, true);
if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine)
{
if (await _repository.Where<SubjectVisit>(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit))
{
throw new BusinessValidationFailedException("有受试者的基线已经上传了影像数据,不允许修改基线访视。");
}
}
return ResponseOutput.Ok();
}
}
[UnitOfWork]
[HttpPost("{trialId:guid}")]
[Authorize(Policy = IRaCISPolicy.PM_APM)]
public async Task<IResponseOutput> ConfirmTrialVisitPlan(Guid trialId)
{
if (!await _trialRepository.AnyAsync(t => t.Id == trialId && (t.TrialStatusStr == StaticData.TrialState.TrialInitializing || t.TrialStatusStr == StaticData.TrialState.TrialOngoing)))
{
return ResponseOutput.NotOk("仅仅在项目初始化或者进行中时,才允许修改确认");
}
if (!await _visitStageRepository.AnyAsync(t => t.TrialId == trialId && t.IsBaseLine))
{
return ResponseOutput.NotOk("没有基线,不允许确认");
}
if (!await _trialRepository.AnyAsync(t => t.Id == trialId && t.IsTrialBasicLogicConfirmed && t.IsTrialProcessConfirmed && t.IsTrialUrgentConfirmed))
{
return ResponseOutput.NotOk("项目配置未确认,不允许确认访视计划");
}
var svList = await _visitStageRepository.Where(t => t.TrialId == trialId).Select(u => new { u.VisitDay, u.IsBaseLine }).ToListAsync();
if (svList.Min(t => t.VisitDay) != svList.Where(t => t.IsBaseLine).FirstOrDefault()?.VisitDay)
{
return ResponseOutput.NotOk("基线VisitDay 不是最小的, 不允许确认");
}
//更新项目访视计划状态为已确认 必定生成更新的sql 通过状态改变 触发操作
//await _trialRepository.UpdatePartialNowNoQueryAsync(trialId, t => new Trial() { VisitPlanConfirmed = true });
var trial = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException();
trial.VisitPlanConfirmed = true;
var subjects = _repository.GetQueryable<Subject>().Where(x => x.TrialId == trialId).Select(x => new
{
x.Code,
x.SiteId,
x.Id,
x.IsEnrollment,
x.IsUrgent,
x.TrialId
});
List<SubjectVisit> subjectVisits = new List<SubjectVisit>();
var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync();
addvisitStages.ForEach(visitPlan =>
{
subjects.ForEach(subject =>
{
var addSv = _mapper.Map<SubjectVisit>(visitPlan);
addSv.SubjectId = subject.Id;
addSv.TrialId = subject.TrialId;
addSv.SiteId = subject.SiteId;
subjectVisits.Add(addSv);
});
});
await _subjectVisitRepository.AddRangeAsync(subjectVisits);
//访视计划 整体状态变更为 确认
await _visitStageRepository.UpdatePartialFromQueryAsync(u => u.TrialId == trialId && u.IsConfirmed == false, t => new VisitStage() { IsConfirmed = true, IsHaveFirstConfirmed = true });
await _visitStageRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpGet("{trialId:guid}")]
public async Task<List<VisitPlanInfluenceSubjectVisitStatDTO>> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository)
{
var list = await _influnceStatRepository.Where(t => t.TrialId == trialId).ProjectTo<VisitPlanInfluenceSubjectVisitStatDTO>(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToListAsync();
return list;
}
[HttpGet("{visitPlanInfluenceStatId:guid}")]
public async Task<IActionResult> DownloadInflunceStudyList(Guid visitPlanInfluenceStatId)
{
var list = _influnceRepository.Where(t => t.VisitPlanInfluenceStatId == visitPlanInfluenceStatId)
.ProjectTo<VisitPlanInfluenceSubjectVisitDTO>(_mapper.ConfigurationProvider).ToList();
IExporter exporter = new ExcelExporter();
var result = await exporter.ExportAsByteArray(list);
return new XlsxFileResult(bytes: result, fileDownloadName: $"检查导出_{DateTime.Now.ToString("yyyy-MM-dd:hh:mm:ss")}.xlsx");
}
/// <summary> 删除项目计划某一项 废弃 </summary>
[HttpDelete("{id:guid}/{trialId:guid}")]
[TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)]
[TypeFilter(typeof(TrialResourceFilter))]
[Obsolete]
public async Task<IResponseOutput> DeleteVisitStage(Guid id)
{
var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id);
if (visitPlan == null) return Null404NotFound(visitPlan);
if (await _repository.AnyAsync<SubjectVisit>(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed))
{
return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed.");
}
await _repository.BatchDeleteAsync<SubjectVisit>(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName);
var result = await _visitStageRepository.BatchDeleteNoTrackingAsync(u => u.Id == id);
return ResponseOutput.Result(result);
}
}
}