392 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			392 lines
		
	
	
		
			17 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;
 | 
						||
using SixLabors.ImageSharp.Processing;
 | 
						||
using SixLabors.ImageSharp;
 | 
						||
using Microsoft.Extensions.Logging;
 | 
						||
 | 
						||
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 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();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        [HttpGet]
 | 
						||
        public async Task<FileContentResult> NoneDicomFilePreview(string relativePath)
 | 
						||
        {
 | 
						||
            var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
 | 
						||
 | 
						||
            var _fileStorePath = Path.Combine(rootPath, relativePath.Replace('/', '\\').Trim('\\'));
 | 
						||
 | 
						||
            //_logger.LogError(rootPath);
 | 
						||
 | 
						||
            //_logger.LogError(_fileStorePath);
 | 
						||
 | 
						||
            var storePreviewPath = _fileStorePath + ".preview.jpeg";
 | 
						||
 | 
						||
            if (!File.Exists(storePreviewPath))
 | 
						||
            {
 | 
						||
 | 
						||
                using (var image = SixLabors.ImageSharp.Image.Load(await File.ReadAllBytesAsync(_fileStorePath)))
 | 
						||
                {
 | 
						||
                    image.Mutate(x => x
 | 
						||
                         .Resize(image.Width / 2, image.Height / 2)
 | 
						||
                         );
 | 
						||
 | 
						||
                    await image.SaveAsJpegAsync(storePreviewPath);
 | 
						||
 | 
						||
                }
 | 
						||
            }
 | 
						||
          
 | 
						||
            return new FileContentResult(await File.ReadAllBytesAsync(storePreviewPath), "image/jpeg");
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        /// <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;
 | 
						||
        }
 | 
						||
 | 
						||
    }
 | 
						||
}
 |