irc-netcore-api/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs

366 lines
16 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
// 生成时间 2021-12-06 10:54:55
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using IRaCIS.Core.Domain.Share;
using SharpCompress.Archives;
using IRaCIS.Core.Application.Filter;
using Newtonsoft.Json;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using Nito.AsyncEx;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Authorization;
using System.Drawing;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp;
using IRaCIS.Core.Application.Helper;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary>
/// NoneDicomStudyService
/// </summary>
[ApiExplorerSettings(GroupName = "Image")]
public class NoneDicomStudyService : BaseService, INoneDicomStudyService
{
private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
private readonly IHttpContextAccessor _httpContext;
private readonly IDictionaryService _dictionaryService;
private readonly IInspectionService _inspectionService;
private readonly IRepository<StudyMonitor> _studyMonitorRepository;
private readonly IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly AsyncLock _mutex = new AsyncLock();
private readonly ILogger<NoneDicomStudyService> _logger;
public NoneDicomStudyService(IRepository<NoneDicomStudy> noneDicomStudyRepository,
IHttpContextAccessor httpContext,
IDictionaryService dictionaryService,
IInspectionService inspectionService,
IRepository<StudyMonitor> studyMonitorRepository,
IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository, IRepository<SubjectVisit> subjectVisitRepository, ILogger<NoneDicomStudyService> logger)
{
_noneDicomStudyRepository = noneDicomStudyRepository;
this._httpContext = httpContext;
this._dictionaryService = dictionaryService;
this._inspectionService = inspectionService;
this._studyMonitorRepository = studyMonitorRepository;
_noneDicomStudyFileRepository = noneDicomStudyFileRepository;
this._subjectVisitRepository = subjectVisitRepository;
_logger = logger;
}
private void VerifyIsCanQC(SubjectVisit? subjectVisit, Guid? sujectVisitId = null)
{
if (sujectVisitId != null)
{
subjectVisit = _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == sujectVisitId).Result.IfNullThrowException();
}
if (subjectVisit!.CurrentActionUserId != _userInfo.Id)
{
throw new BusinessValidationFailedException("您不是该质控任务当前领取人,没有操作权限!");
}
}
[HttpGet("{subjectVisitId:guid}")]
public async Task<List<NoneDicomStudyView>> GetNoneDicomStudyList(Guid subjectVisitId)
{
var noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId)
.ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken });
return await noneDicomStudyQueryable.ToListAsync();
}
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput<NoneDicomStudyAddReturnDto>> AddOrUpdateNoneDicomStudy(NoneDicomStudyAddOrEdit addOrEditNoneDicomStudy)
{
var visitList = await _subjectVisitRepository.Where(t => t.SubjectId == addOrEditNoneDicomStudy.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToListAsync();
var currentVisitNum = await _subjectVisitRepository.Where(t => t.Id == addOrEditNoneDicomStudy.SubjectVisitId).Select(t => t.VisitNum).FirstOrDefaultAsync();
if (addOrEditNoneDicomStudy.Id == null)
{
//更新验证的时候,排除自己
visitList = visitList.Where(t => t.Id != addOrEditNoneDicomStudy.Id).ToList();
}
//小于当前访视 最近的最晚拍片
var before = visitList.Where(u => u.VisitNum < currentVisitNum).Max(k => k.LatestScanDate);
if (before != null && before > addOrEditNoneDicomStudy.ImageDate)
{
throw new BusinessValidationFailedException($"当前访视检查时间{addOrEditNoneDicomStudy.ImageDate.ToString("yyyy-MM-dd")}不能早于前序访视检查时间{before?.ToString("yyyy-MM-dd")},请核对检查数据是否有误");
}
//大于当前访视 最近的最早拍片日期
var after = visitList.Where(u => u.VisitNum > currentVisitNum).Min(k => k.EarliestScanDate);
if (after != null && after < addOrEditNoneDicomStudy.ImageDate)
{
throw new BusinessValidationFailedException($"当前访视检查时间{addOrEditNoneDicomStudy.ImageDate.ToString("yyyy-MM-dd")}不能晚于该访视之后的检查时间{after?.ToString("yyyy-MM-dd")},请核对检查数据是否有误");
}
NoneDicomStudy? optEntity = null;
using (await _mutex.LockAsync())
{
if (addOrEditNoneDicomStudy.Id == Guid.Empty || addOrEditNoneDicomStudy.Id == null)
{
//默认会是0
var code = await _noneDicomStudyRepository.Where(t => t.TrialId == addOrEditNoneDicomStudy.TrialId).Select(x => x.Code).DefaultIfEmpty().MaxAsync();
addOrEditNoneDicomStudy.Code = code + 1;
optEntity = await _noneDicomStudyRepository.InsertFromDTOAsync(addOrEditNoneDicomStudy);
optEntity.StudyCode = "NST" + optEntity.Code.ToString("D5");
}
else
{
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC)
{
VerifyIsCanQC(null, addOrEditNoneDicomStudy.SubjectVisitId);
}
optEntity = await _noneDicomStudyRepository.UpdateFromDTOAsync(addOrEditNoneDicomStudy);
}
await _noneDicomStudyRepository.SaveChangesAsync();
}
NoneDicomStudyAddReturnDto noneDicom = new NoneDicomStudyAddReturnDto()
{
StudyCode = optEntity.StudyCode,
Id = optEntity.Id
};
return ResponseOutput.Ok(noneDicom);
}
[TypeFilter(typeof(TrialResourceFilter))]
[HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyId:guid}")]
public async Task<IResponseOutput> DeleteNoneDicomStudy(Guid noneDicomStudyId, Guid subjectVisitId)
{
//提交了 但是IQC同意的时候 是可以删除的 | 普通提交后也不能删除
if (await _subjectVisitRepository.AnyAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
(!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
{
return ResponseOutput.NotOk("CRC Has Submited Imagecan not delete");
}
await _noneDicomStudyRepository.DeleteFromQueryAsync(noneDicomStudyId);
await _noneDicomStudyFileRepository.DeleteFromQueryAsync(t => t.NoneDicomStudyId == noneDicomStudyId);
//确认需求 不删除
//await _studyMonitorRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == noneDicomStudyId);
await _noneDicomStudyRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyFileId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> DeleteNoneDicomStudyFile(Guid noneDicomStudyFileId, Guid subjectVisitId)
{
//提交了 但是IQC同意的时候 是可以删除的 | 普通提交后也不能删除
if (await _subjectVisitRepository.AnyAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
(!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
{
return ResponseOutput.NotOk("CRC Has Submited Imagecan not delete");
}
//var subjectVisitId = await _noneDicomStudyFileRepository.Where(t => t.Id == noneDicomStudyFileId).Select(t => t.NoneDicomStudy.SubjectVisitId).FirstOrDefaultAsync();
var success = await _noneDicomStudyFileRepository.DeleteFromQueryAsync(t => t.Id == noneDicomStudyFileId, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 非Dicom检查 文件列表
/// </summary>
/// <param name="noneDicomStudyId"></param>
/// <returns></returns>
[HttpGet("{noneDicomStudyId:guid}")]
public async Task<List<NoneDicomStudyFileView>> GetNoneDicomStudyFileList(Guid noneDicomStudyId)
{
return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudyId == noneDicomStudyId)
.ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }).ToListAsync();
}
[HttpGet("{subjectVisitId:guid}")]
public async Task<List<NoneDicomStudyFileView>> GetVisitNoneDicomStudyFileList(Guid subjectVisitId)
{
return await _repository.Where<NoneDicomStudyFile>(t => t.NoneDicomStudy.SubjectVisitId == subjectVisitId).ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }).ToListAsync();
}
/// <summary>
/// 上传非Dicom 文件 支持压缩包
/// </summary>
/// <param name="formCollection"></param>
/// <param name="subjectVisitId"></param>
/// <param name="noneDicomStudyId"></param>
/// <returns></returns>
//[DisableRequestSizeLimit]
[RequestSizeLimit(1_073_741_824)]
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> UploadNoneDicomFile(IFormCollection formCollection, Guid subjectVisitId, Guid noneDicomStudyId)
{
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
//上传根路径
var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
var sv = await _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefaultAsync().IfNullThrowConvertException();
string uploadFolderPath = Path.Combine(_fileStorePath, sv.TrialId.ToString(), sv.SiteId.ToString(), sv.SubjectId.ToString(), subjectVisitId.ToString(), StaticData.NoneDicomFolder);
if (!Directory.Exists(uploadFolderPath))
{
Directory.CreateDirectory(uploadFolderPath);
}
var startTime = DateTime.Now;
foreach (IFormFile file in formCollection.Files)
{
if (file.FileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || file.FileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
{
var archive = ArchiveFactory.Open(file.OpenReadStream());
foreach (var entry in archive.Entries)
{
if (!entry.IsDirectory)
{
DealCompressFile(entry, sv, subjectVisitId, noneDicomStudyId, uploadFolderPath);
}
}
}
else
{
var trustedFileNameForFileStorage = GetStoreFileName(file.FileName);
var relativePath = $"/{StaticData.TrialDataFolder}/{sv.TrialId}/{sv.SiteId}/{sv.SubjectId}/{subjectVisitId}/{StaticData.NoneDicomFolder}/{trustedFileNameForFileStorage}";
var filePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
using (FileStream fs = System.IO.File.Create(filePath))
{
await file.CopyToAsync(fs);
await fs.FlushAsync();
}
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = file.FileName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });
}
}
// 上传非Dicom 后 将状态改为待提交 分为普通上传 和QC后重传 普通上传时才改为待提交
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.None, u => new SubjectVisit() { SubmitState = SubmitStateEnum.ToSubmit });
var studyCode = await _noneDicomStudyRepository.Where(t => t.Id == noneDicomStudyId).Select(t => t.StudyCode).FirstOrDefaultAsync();
await _studyMonitorRepository.AddAsync(new StudyMonitor()
{
FileCount = formCollection.Files.Count,
FileSize = formCollection.Files.Sum(t => t.Length),
IsDicom = false,
IsDicomReUpload = false,
StudyId = noneDicomStudyId,
StudyCode = studyCode,
UploadStartTime = startTime,
UploadFinishedTime = DateTime.Now,
IP = _userInfo.IP,
TrialId = sv.TrialId,
SiteId = sv.SiteId,
SubjectId = sv.SubjectId,
SubjectVisitId = subjectVisitId,
});
await _noneDicomStudyFileRepository.SaveChangesAsync();
return ResponseOutput.Ok(/*list*/);
}
private string GetStoreFileName(string fileName)
{
//var realName = fileName;
//var fileNameEX = Path.GetExtension(realName);
//var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileName;
return trustedFileNameForFileStorage;
}
private async void DealCompressFile(IArchiveEntry entry, dynamic sv, Guid subjectVisitId, Guid noneDicomStudyId, string uploadFolderPath)
{
var trustedFileNameForFileStorage = GetStoreFileName(entry.Key);
var relativePath = $"/{StaticData.TrialDataFolder}/{sv.TrialId}/{sv.SiteId}/{sv.SubjectId}/{subjectVisitId}/{StaticData.NoneDicomFolder}/{trustedFileNameForFileStorage}";
var filePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
entry.WriteToFile(filePath);
var fileName = string.Empty;
if (entry.Key.Contains("\\"))
{
fileName = entry.Key.Split("\\").Last();
}
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = fileName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });
}
/// <summary>
/// 上传非Dicom 文件 支持压缩包
/// </summary>
[HttpPost]
[Obsolete]
public async Task<IResponseOutput> NewUploadNoneDicomFile([FromForm] UploadNoneDicomFileDto fileDto)
{
var file = this._httpContext.HttpContext?.Request.Form;
var result = await UploadNoneDicomFile(file, fileDto.subjectVisitId, fileDto.noneDicomStudyId);
if (result.IsSuccess)
{
var data = JsonConvert.DeserializeObject<DataInspectionAddDTO>(fileDto.AuditInfo);
data.GeneralId = fileDto.noneDicomStudyId;
await _inspectionService.AddInspectionRecordAsync(data);
}
return result;
}
}
}