using IRaCIS.Application.Interfaces;
using IRaCIS.Application.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using IRaCIS.Core.Application.Contracts.RequestAndResponse;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.WebUtilities;
using System.Threading.Tasks;
using IRaCIS.Core.Application.Contracts.Dicom;
using System.IO;
using System.IO.Compression;
using IRaCIS.Core.API.Filter;
using Microsoft.AspNetCore.Http.Features;
using IRaCIS.Core.Application.Dicom;
using IRaCIS.Core.Domain.Share;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Http;
using IRaCIS.Api.Filter;
using NLog;
using Microsoft.Extensions.Logging;
using System.Text;
namespace IRaCIS.Api.Controllers
{
///
/// Study
///
[Route("study")]
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")]
public class StudyController : ControllerBase
{
private readonly IStudyService _studyService;
private readonly IDicomArchiveService _dicomArchiveService;
private readonly IDoctorService _doctorService;
private static readonly FormOptions _defaultFormOptions = new FormOptions();
private readonly ILogger _logger;
public StudyController(IStudyService studyService,
IDicomArchiveService dicomArchiveService, IDoctorService doctorService,
ILogger logger
)
{
_studyService = studyService;
_dicomArchiveService = dicomArchiveService;
_doctorService = doctorService;
_logger = logger;
}
///// 根据项目Id,受试者Id,获取受试者检查统计(不分页)
//[HttpGet, Route("getStudyStatList/{trialId:guid}/{subjectId:guid}/{siteId:guid}")]
//public IResponseOutput> GetStudy(Guid trialId, Guid subjectId, Guid siteId)
//{
// return ResponseOutput.Ok(_studyService.GetStudyStatList(trialId, subjectId, siteId));
//}
[HttpPost, Route("getStudyList")]
public IResponseOutput> GetStudyList(StudyQueryDTO queryDto)
{
return ResponseOutput.Ok(_studyService.GetStudyList(queryDto));
}
[HttpPost, Route("getDistributeStudyList")]
public IResponseOutput> GetDistributeStudyList(
StudyStatusQueryDTO studyStatusQueryDto)
{
return ResponseOutput.Ok(_studyService.GetDistributeStudyList(studyStatusQueryDto));
}
[HttpPost, Route("updateStudyBinding")]
//[LogFilter]
public IResponseOutput UpdateStudyBinding(StudyEditCommand studyEditCommand)
{
if (studyEditCommand.SubjectVisitId == Guid.Empty)
{
studyEditCommand.SubjectVisitId = _studyService.AddSubjectVisit(studyEditCommand.SubjectId, studyEditCommand.SiteId,
studyEditCommand.VisitStageId, studyEditCommand.SVSTDTC, studyEditCommand.SVENDTC);
}
else
{
_studyService.UpdateSubjectVisit(studyEditCommand.SubjectVisitId, studyEditCommand.SVSTDTC,
studyEditCommand.SVENDTC);
}
return ResponseOutput.Ok( _studyService.UpdateStudyBinding(studyEditCommand).Result);
}
///
/// 获取受试者 这次访视 对应的study modality 列表
///
///
///
///
///
///
[HttpPost, Route("getSubjectVisitStudyList/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{subjectVisitId:guid}")]
[AllowAnonymous]
public IResponseOutput> GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId,
Guid subjectVisitId)
{
return ResponseOutput.Ok(
_studyService.GetSubjectVisitStudyList(trialId, siteId, subjectId, subjectVisitId));
}
///
/// 提示 该项目是否允许上传该study,如果不允许 提示 已经上传到哪个受试者 哪次方式 studyCode是多少
///
///
///
///
///
[HttpGet, Route("verifyStudyAllowUpload/{trialId:guid}/{studyInstanceUid}/{abandonStudyId?}")]
[AllowAnonymous]
public IResponseOutput VerifyStudyAllowUpload(string studyInstanceUid, Guid trialId, Guid? abandonStudyId)
{
return ResponseOutput.Ok(_studyService.VerifyStudyAllowUpload(studyInstanceUid, trialId, abandonStudyId));
}
/// 归档
//[HttpPost, Route("archiveStudy/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{visitStageId:guid}/{subjectVisitId:guid}/{SVSTDTC?}/{SVENDTC?}/{comment}")]
[HttpPost, Route("archiveStudy")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
[LogFilter]
//public async Task ArchiveStudy(Guid trialId, Guid siteId, Guid subjectId, Guid visitStageId, Guid subjectVisitId, DateTime? SVSTDTC, DateTime? SVENDTC, string comment)
public async Task ArchiveStudy([FromForm] ArchiveStudyCommand archiveStudyCommand)
{
//处理 受试者访视没有记录 系统自动添加
#region url方式
//if (subjectVisitId == Guid.Empty)
//{
// subjectVisitId = _studyService.AddSubjectVisit(subjectId, visitStageId);
//}
//string userName = User.FindFirst("realName").Value;
//StudyCommand addtionalInfo = new StudyCommand
//{
// SiteId = siteId,
// SubjectId = subjectId,
// TrialId = trialId,
// SubjectVisitId = subjectVisitId,
//};
//var savedInfo = _studyService.GetSaveToDicomInfo(addtionalInfo);
////加入comment
//savedInfo.Comment = comment;
#endregion
try
{
#region post body 方式 subjectVisitId
////var subjectVisitStudyOldList = new List();
// 受试者方式计划一次性添加,因为没有了上传时添加逻辑
//if (archiveStudyCommand.SubjectVisitId == Guid.Empty)
//{
// archiveStudyCommand.SubjectVisitId = _studyService.AddSubjectVisit(archiveStudyCommand.SubjectId, archiveStudyCommand.SiteId,
// archiveStudyCommand.VisitStageId.Value, archiveStudyCommand.SVSTDTC, archiveStudyCommand.SVENDTC);
//}
//else
//{
//_studyService.UpdateSubjectVisit(archiveStudyCommand.SubjectVisitId, archiveStudyCommand.SVSTDTC,
// archiveStudyCommand.SVENDTC);
//#region 重传和上传放在一起 暂不用
////处理 重传 在归档前 事先查出 这次访视已经有的study列表
////subjectVisitStudyOldList = _studyService.GetSubjectVisitStudyList(archiveStudyCommand.TrialId,
//// archiveStudyCommand.SiteId, archiveStudyCommand.SubjectId, archiveStudyCommand.SubjectVisitId);
//#endregion
//}
var userName = User.FindFirst("realName").Value;
StudyCommand addtionalInfo = new StudyCommand
{
SiteId = archiveStudyCommand.SiteId,
SubjectId = archiveStudyCommand.SubjectId,
TrialId = archiveStudyCommand.TrialId,
SubjectVisitId = archiveStudyCommand.SubjectVisitId,
};
var savedInfo = _studyService.GetSaveToDicomInfo(addtionalInfo);
#endregion
var archiveResult = new DicomArchiveResult();
var archivedStudyIds = new List();
var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
string fileName = contentDisposition.FileName.Value;
try
{
//采用post方式 这里多加一个判断 过滤其他参数
if (string.IsNullOrEmpty(section.ContentType))
{
break;
}
string mediaType = section.ContentType;
if (mediaType.Contains("zip"))
{
var partStream = section.Body;
using (var zipArchive = new ZipArchive(partStream, ZipArchiveMode.Read))
{
foreach (var entry in zipArchive.Entries)
{
if (entry.FullName.EndsWith("/")) continue;
try
{
++archiveResult.ReceivedFileCount;
using (var memoryStream = new MemoryStream())
{
await section.Body.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
DicomInstanceDTO instance = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo);
if (!archivedStudyIds.Contains(instance.StudyId))
archivedStudyIds.Add(instance.StudyId);
}
}
catch
{
archiveResult.ErrorFiles.Add($"{fileName}/{entry.FullName}");
}
}
}
}
++archiveResult.ReceivedFileCount;
if (mediaType.Contains("octet-stream"))
{
using (var memoryStream = new MemoryStream())
{
await section.Body.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
DicomInstanceDTO instance = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo);
if (!archivedStudyIds.Contains(instance.StudyId))
archivedStudyIds.Add(instance.StudyId);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
archiveResult.ErrorFiles.Add(fileName);
}
}
section = await reader.ReadNextSectionAsync();
}
if (archivedStudyIds.Count > 0)
{
//更新受试者访视信息 及上传状态
_studyService.UpdateSubjectVisit(archiveStudyCommand.SubjectVisitId, archiveStudyCommand.SVSTDTC,
archiveStudyCommand.SVENDTC);
//更新受试者最新的访视状态,访视号最大的
_studyService.UpdateSubjectLatestInfo(archiveStudyCommand.SubjectId, archiveStudyCommand.TrialId);
archiveResult.ArchivedDicomStudies = _dicomArchiveService.GetArchivedStudyList(archivedStudyIds);
//归档完成,插入记录表
foreach (var archivedDicomStudy in archiveResult.ArchivedDicomStudies)
{
var seriesModalityList = _dicomArchiveService.GetSeriesList(archivedDicomStudy.Id).Select(u => u.Modality).Distinct();
StringBuilder sb = new StringBuilder();
foreach (var item in seriesModalityList)
{
sb.Append(item).Append(",");
}
string ModaliyStr = sb.ToString();
if (ModaliyStr.Length > 0)
{
ModaliyStr = ModaliyStr.Substring(0, ModaliyStr.Length - 1);
}
string comment = string.Empty;// 上传或重传完成之后,更新Comment信息
if (!string.IsNullOrWhiteSpace(archiveStudyCommand.Comment))
{
comment = archiveStudyCommand.Comment;
}
_studyService.UpdateStudyModaliyAndComment(archivedDicomStudy.Id, ModaliyStr,comment);
//重传 并且不是同一份文件
if (archiveStudyCommand.AbandonStudyId != null &&
archiveStudyCommand.AbandonStudyId != Guid.Empty && archiveStudyCommand.AbandonStudyId != archivedDicomStudy.Id)
{
//更新状态为废弃
_studyService.UpdateStudyStatus(new StudyStatusDetailCommand
{
StudyId = archiveStudyCommand.AbandonStudyId.Value,
Status = (int)StudyStatus.Abandon,
Note = string.Empty
}, userName);
//此时归档的新的Study 初始状态设置为 已重传完成
_studyService.UpdateStudyStatus(new StudyStatusDetailCommand
{
StudyId = archivedDicomStudy.Id,
Status = (int)StudyStatus.QAReuploaded,
Note = string.Empty
}, userName);
//更新新得study code 为废弃的
_studyService.UpdateReUploadNewStudyCode(archiveStudyCommand.AbandonStudyId.Value, archivedDicomStudy.Id);
}//重传 是同一份文件
else if (archiveStudyCommand.AbandonStudyId != null &&
archiveStudyCommand.AbandonStudyId != Guid.Empty && archiveStudyCommand.AbandonStudyId == archivedDicomStudy.Id)
{
//此时归档的新的Study 初始状态设置为 已重传完成
_studyService.UpdateStudyStatus(new StudyStatusDetailCommand
{
StudyId = archivedDicomStudy.Id,
Status = (int)StudyStatus.QAReuploaded,
Note = string.Empty
}, userName);
}//上传
else
{
_studyService.UpdateStudyStatus(new StudyStatusDetailCommand
{
StudyId = archivedDicomStudy.Id,
Status = (int)StudyStatus.Uploaded,
Note = string.Empty
}, userName);
}
}
}
return ResponseOutput.Ok(archiveResult);
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
throw;
}
}
/// 删除检查
[HttpDelete, Route("deleteStudy/{id:guid}")]
[LogFilter]
public IResponseOutput DeleteStudy(Guid id)
{
return _studyService.DeleteStudy(id);
}
/// 指定资源Id,渲染Dicom检查的Jpeg预览图像
/// Dicom检查的Id
[HttpGet, Route("preview/{studyId:guid}")]
[AllowAnonymous]
public FileContentResult GetStudyPreview(Guid studyId)
{
string path = _dicomArchiveService.GetStudyPreview(studyId);
using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path))
{
var bytes = new byte[sw.Length];
sw.Read(bytes, 0, bytes.Length);
sw.Close();
return new FileContentResult(bytes, "image/jpeg");
}
}
/// 指定资源Id,获取Dicom检查信息
/// Dicom检查的Id
[HttpGet, Route("item/{studyId:guid}")]
public IResponseOutput GetStudyItem(Guid studyId)
{
return ResponseOutput.Ok(_dicomArchiveService.GetStudyItem(studyId));
}
/// 更新Study状态,并保存状态变更信息
///
[HttpPost, Route("updateStudyStatus")]
[LogFilter]
public IResponseOutput UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailCommand)
{
string userName = User.FindFirst("realName").Value; ;
return ResponseOutput.Result(_studyService.UpdateStudyStatus(studyStatusDetailCommand, userName));
}
///
/// Dicom匿名化
///
/// 需要匿名化的检查Id
///
[HttpPost, Route("dicomAnonymize/{studyId:guid}")]
[LogFilter]
public async Task DicomAnonymize(Guid studyId)
{
string userName = User.FindFirst("realName").Value; ;
return ResponseOutput.Result(await _studyService.DicomAnonymize(studyId, userName));
}
/// Study分配
[HttpPost, Route("studyDistribution")]
[Obsolete]
public IResponseOutput StudyDistribution(StudyReviewerCommand studyReviewerCommand)
{
string userName = User.FindFirst("realName").Value;
var doctorInfo = _doctorService.GetDoctorBasicInfo(studyReviewerCommand.ReviewerId);
List studyStatusCommandList = new List();
foreach (var study in studyReviewerCommand.StudyList)
{
var studyStatus = new StudyStatusDetailCommand
{
StudyId = study.StudyId,
Status = (int)StudyStatus.Distributed,
Note = doctorInfo.LastName + " " + doctorInfo.FirstName
};
studyStatusCommandList.Add(studyStatus);
}
var result = _studyService.DistributeStudy(studyReviewerCommand);
_studyService.UpdateStudyStatus(studyStatusCommandList, userName);
return ResponseOutput.Result(result);
}
[Obsolete]
[HttpPost, Route("editStudyReviewer")]
public IResponseOutput EditStudyReviewer(StudyReviewerEditCommand studyReviewerEditCommand)
{
return _studyService.EditStudyReviewer(studyReviewerEditCommand);
}
///
/// 根据项目Id 获取可选医生列表
///
///
///
[HttpGet, Route("GetReviewerList/{trialId:guid}")]
public IResponseOutput> GetReviewerListByTrialId(Guid trialId)
{
var result = _studyService.GetReviewerListByTrialId(trialId);
return ResponseOutput.Ok(result);
}
///
/// 根据StudyId获取该Study的操作记录,时间倒序
///
///
///
[HttpGet, Route("getStudyStatusDetailList/{studyId:guid}")]
public IResponseOutput> GetStudyStatusDetailList(Guid studyId)
{
var result = _studyService.GetStudyStatusDetailList(studyId);
return ResponseOutput.Ok(result);
}
///
/// 根据TPCode 获取所有的标记
///
///
///
[HttpGet, Route("getImageLabelList/{tpCode}")]
[AllowAnonymous]
public IResponseOutput> GetImageLabelList(string tpCode)
{
return ResponseOutput.Ok(_dicomArchiveService.GetImageLabel(tpCode));
}
///
/// 保存标记(跟删除合并,每次保存最新的标记),会删除替换之前的标记
/// 外层的TPcode 必须传,里面的标记数组可为空数组,表示删除该Study的所有标记
///
///
///
[HttpPost, Route("saveImageLabelList")]
[AllowAnonymous]
[LogFilter]
public IResponseOutput SaveImageLabelList(ImageLabelCommand imageLabelCommand)
{
return ResponseOutput.Result(_dicomArchiveService.SaveImageLabelList(imageLabelCommand));
}
///
/// 获取某个访视的关联访视
/// 用于获取关联影像(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表)
///
///
///
///
[HttpGet, Route("getRelationVisitList/{visitNum}/{tpCode}")]
[AllowAnonymous]
public IResponseOutput> GetRelationVisitList(decimal visitNum, string tpCode)
{
return ResponseOutput.Ok(_studyService.GetRelationVisitList(visitNum, tpCode));
}
}
}