352 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
| //--------------------------------------------------------------------
 | ||
| //     此代码由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;
 | ||
| 
 | ||
| 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();
 | ||
| 
 | ||
| 
 | ||
|         public NoneDicomStudyService(IRepository<NoneDicomStudy> noneDicomStudyRepository,
 | ||
|             IHttpContextAccessor httpContext,
 | ||
|             IDictionaryService dictionaryService,
 | ||
|             IInspectionService inspectionService,
 | ||
|             IRepository<StudyMonitor> studyMonitorRepository,
 | ||
|             IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository,IRepository<SubjectVisit> subjectVisitRepository)
 | ||
|         {
 | ||
|             _noneDicomStudyRepository = noneDicomStudyRepository;
 | ||
|            
 | ||
|             this._httpContext = httpContext;
 | ||
|             this._dictionaryService = dictionaryService;
 | ||
|             this._inspectionService = inspectionService;
 | ||
|             this._studyMonitorRepository = studyMonitorRepository;
 | ||
|             _noneDicomStudyFileRepository = noneDicomStudyFileRepository;
 | ||
|             this._subjectVisitRepository = subjectVisitRepository;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         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.EarliestScanDate);
 | ||
| 
 | ||
|             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.LatestScanDate);
 | ||
| 
 | ||
|             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 Image,can 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 Image,can 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;
 | ||
| 
 | ||
|             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;
 | ||
|         }
 | ||
| 
 | ||
|     }
 | ||
| }
 |