EI-Image-Viewer-Api/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs

351 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.Hosting;
using Microsoft.AspNetCore.Http;
using IRaCIS.Core.Domain.Share;
using SharpCompress.Archives;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infra.EFCore;
using Newtonsoft.Json;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using IRaCIS.Core.Application.Service.Inspection.DTO;
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 IWebHostEnvironment _hostEnvironment;
private readonly IInspectionService _inspectionService;
private readonly IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository;
public NoneDicomStudyService(IRepository<NoneDicomStudy> noneDicomStudyRepository,
IHttpContextAccessor httpContext,
IWebHostEnvironment hostEnvironment,
IInspectionService inspectionService,
IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository)
{
_noneDicomStudyRepository = noneDicomStudyRepository;
this._httpContext = httpContext;
this._hostEnvironment = hostEnvironment;
this._inspectionService = inspectionService;
_noneDicomStudyFileRepository = noneDicomStudyFileRepository;
}
[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 entity = await _noneDicomStudyRepository.InsertOrUpdateAsync(addOrEditNoneDicomStudy, false);
if (_repository.Entry(entity).State == Microsoft.EntityFrameworkCore.EntityState.Added)
{
entity.Code = _noneDicomStudyRepository.Where(t => t.TrialId == addOrEditNoneDicomStudy.TrialId).Select(t => t.Code).DefaultIfEmpty().Max() + 1;
}
entity.StudyCode = "NST" + entity.Code.ToString("D5");
await _repository.SaveChangesAsync();
var svTime = _repository.Where<SubjectVisit>(t => t.Id == addOrEditNoneDicomStudy.SubjectVisitId).Select(t => new
{
DicomStudyMinStudyTime = t.StudyList.Min(t => (DateTime?)t.StudyTime),
DicomStudyMaxStudyTime = t.StudyList.Max(t => (DateTime?)t.StudyTime),
NoneDicomStudyMinStudyTime = t.NoneDicomStudyList.Min(t => (DateTime?)t.ImageDate),
NoneDicomStudyMaxStudyTime = t.NoneDicomStudyList.Max(t => (DateTime?)t.ImageDate)
}).FirstOrDefault().IfNullThrowException();
var minArray = new DateTime?[] { svTime.DicomStudyMinStudyTime, svTime.NoneDicomStudyMinStudyTime, addOrEditNoneDicomStudy.ImageDate };
var maxArray = new DateTime?[] { svTime.DicomStudyMaxStudyTime, svTime.NoneDicomStudyMaxStudyTime, addOrEditNoneDicomStudy.ImageDate };
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == addOrEditNoneDicomStudy.SubjectVisitId, u => new SubjectVisit()
{
VisitExecuted = VisitExecutedEnum.Executed,
EarliestScanDate = minArray.Min(),
LatestScanDate = maxArray.Max()
});
await _repository.SaveChangesAsync();
NoneDicomStudyAddReturnDto noneDicom = new NoneDicomStudyAddReturnDto()
{
StudyCode= entity.StudyCode,
Id= entity.Id
};
return ResponseOutput.Ok(noneDicom);
}
[TypeFilter(typeof(TrialResourceFilter))]
[HttpDelete("{noneDicomStudyId:guid}/{trialId:guid}")]
public async Task<IResponseOutput> DeleteNoneDicomStudy(Guid noneDicomStudyId)
{
if (_noneDicomStudyRepository.Where(t => t.Id == noneDicomStudyId)
.Any(t => t.NoneDicomFileList.Count() > 0))
{
return ResponseOutput.NotOk("先移除文件才允许删除非Dicom");
}
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync(t => t.Id == noneDicomStudyId);
if (noneDicomStudy == null) return Null404NotFound(noneDicomStudy);
await _noneDicomStudyRepository.BatchDeleteAsync(t => t.Id == noneDicomStudyId);
await _noneDicomStudyFileRepository.BatchDeleteAsync(t => t.NoneDicomStudyId == noneDicomStudyId);
var svTime = await _repository.Where<SubjectVisit>(t => t.Id == noneDicomStudy.SubjectVisitId).Select(t => new
{
DicomStudyMinStudyTime = t.StudyList.Min(t => (DateTime?)t.StudyTime),
DicomStudyMaxStudyTime = t.StudyList.Max(t => (DateTime?)t.StudyTime),
NoneDicomStudyMinStudyTime = t.NoneDicomStudyList.Min(t => (DateTime?)t.ImageDate),
NoneDicomStudyMaxStudyTime = t.NoneDicomStudyList.Max(t => (DateTime?)t.ImageDate)
}).FirstOrDefaultAsync().IfNullThrowException();
var minArray = new DateTime?[] { svTime.DicomStudyMinStudyTime, svTime.NoneDicomStudyMinStudyTime };
var maxArray = new DateTime?[] { svTime.DicomStudyMaxStudyTime, svTime.NoneDicomStudyMaxStudyTime };
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == noneDicomStudy.SubjectVisitId, u => new SubjectVisit()
{
EarliestScanDate = minArray.Min(),
LatestScanDate = maxArray.Max()
});
//如果既没有 dicom数据 也没有非dicom 文件 那么提交状态变更回去
if (await _repository.CountAsync<DicomStudy>(t => t.SubjectVisitId == noneDicomStudy.SubjectVisitId) == 0 && await _repository.CountAsync<NoneDicomStudyFile>(t => t.NoneDicomStudy.SubjectVisitId == noneDicomStudy.SubjectVisitId) == 0)
{
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == noneDicomStudy.SubjectVisitId && t.SubmitState == SubmitStateEnum.ToSubmit, u => new SubjectVisit() { VisitExecuted = 0, SubmitState = SubmitStateEnum.None });
}
return ResponseOutput.Ok();
}
[HttpDelete("{noneDicomStudyFileId:guid}")]
public async Task<IResponseOutput> DeleteNoneDicomStudyFile(Guid noneDicomStudyFileId)
{
var subjectVisitId = await _noneDicomStudyFileRepository.Where(t=>t.Id== noneDicomStudyFileId).Select(t => t.NoneDicomStudy.SubjectVisitId).FirstOrDefaultAsync();
var success = await _noneDicomStudyFileRepository.BatchDeleteAsync(t => t.Id == noneDicomStudyFileId);
//如果既没有 dicom数据 也没有非dicom 文件 那么提交状态变更回去
if (await _repository.CountAsync<DicomStudy>(t => t.SubjectVisitId == subjectVisitId) == 0 && await _repository.CountAsync<NoneDicomStudyFile>(t => t.NoneDicomStudy.SubjectVisitId == subjectVisitId) == 0)
{
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.ToSubmit, u => new SubjectVisit() { VisitExecuted = 0, SubmitState = SubmitStateEnum.None });
}
var subvisit = await _repository.GetQueryable<SubjectVisit>().FirstOrDefaultAsync(x => x.Id == subjectVisitId);
List<DataInspection> datas = new List<DataInspection>();
datas.Add(new DataInspection()
{
SiteId = subvisit.SiteId,
SubjectId = subvisit.SubjectId,
TrialId = subvisit.TrialId,
SubjectVisitId = subvisit.Id,
Identification = "Edit|Visit|Status|Visit-Image Upload|Add Image",
JsonDetail = JsonConvert.SerializeObject(new
{
SubmitState = "待提交",
})
});
await _inspectionService.AddListInspectionRecordAsync(datas);
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>
[HttpPost]
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);
var subvisit =await _repository.GetQueryable<SubjectVisit>().FirstOrDefaultAsync(x => x.Id == fileDto.subjectVisitId);
List<DataInspection> datas = new List<DataInspection>();
datas.Add(new DataInspection()
{
SiteId = subvisit.SiteId,
SubjectId = subvisit.SubjectId,
TrialId = subvisit.TrialId,
SubjectVisitId = subvisit.Id,
Identification = "Edit|Visit|Status|Visit-Image Upload|Add Image",
JsonDetail = JsonConvert.SerializeObject(new
{
SubmitState = "待提交",
})
});
await _inspectionService.AddListInspectionRecordAsync(datas);
}
return result;
}
/// <summary>
/// 上传非Dicom 文件 支持压缩包
/// </summary>
/// <param name="formCollection"></param>
/// <param name="subjectVisitId"></param>
/// <param name="noneDicomStudyId"></param>
/// <param name="_hostEnvironment"></param>
/// <returns></returns>
//[DisableRequestSizeLimit]
[RequestSizeLimit(1_073_741_824)]
[HttpPost("{noneDicomStudyId:guid}/{subjectVisitId:guid}")]
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 _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.None, u => new SubjectVisit() { SubmitState = SubmitStateEnum.ToSubmit });
await _repository.AddAsync(new StudyMonitor()
{
FileCount = formCollection.Files.Count, FileSize = formCollection.Files.Sum(t => t.Length), IsDicom = false,
IsDicomReUpload = false, StudyId = noneDicomStudyId,
UploadStartTime = startTime, UploadFinishedTime = DateTime.Now, IP = _userInfo.IP,
TrialId = sv.TrialId,
SiteId = sv.SiteId,
SubjectId = sv.SubjectId,
SubjectVisitId = subjectVisitId,
});
await _repository.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 _repository.AddAsync(new NoneDicomStudyFile() { FileName = fileName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });
}
}
}