364 lines
16 KiB
C#
364 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.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);
|
||
|
||
|
||
//}
|
||
|
||
/// <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;
|
||
}
|
||
|
||
}
|
||
}
|