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

1963 lines
82 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.

using Hangfire;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using IRaCIS.Core.Application.BackGroundJob;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Share;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Http;
using MiniExcelLibs;
using ExcelDataReader;
using System.Text;
using System.Data;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Authorization;
using WinSCP;
using Magicodes.ExporterAndImporter.Excel;
using Newtonsoft.Json;
using Magicodes.ExporterAndImporter.Csv;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Core.Application.Image.QA
{
[ApiExplorerSettings(GroupName = "Image")]
public class QCOperationService : BaseService, IQCOperationService
{
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IServiceProvider serviceProvider;
private readonly IInspectionService _inspectionService;
private object _locker = new object();
public QCOperationService(DicomFileStoreHelper dicomFileStoreHelper, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<Trial> trialRepository,
IServiceProvider serviceProvider,
IInspectionService sinspectionService,
IRepository<DicomStudy> _trialRepository
)
{
_dicomFileStoreHelper = dicomFileStoreHelper;
_subjectVisitRepository = subjectVisitRepository;
this._trialRepository = trialRepository;
this.serviceProvider = serviceProvider;
this._inspectionService = sinspectionService;
}
#region QC质疑 以及回复 关闭
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{currentQCType:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> VerifyQCCanAddChallenge(Guid subjectVisitId, [FromRoute] CurrentQC currentQCType)
{
if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == currentQCType))
{
return ResponseOutput.NotOk("必须填写审核问题,并保存,否则不允许添加质疑");
}
return ResponseOutput.Ok();
}
/// <summary>
/// 添加和更新质疑
/// </summary>
/// <param name="qaQuestionCommand"></param>
/// <param name="trialId"></param>
/// <param name="trialQCProcess"></param>
/// <param name="currentQCType"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
[Authorize(Policy = "ImageQCPolicy")]
public async Task<QCChallenge> AddOrUpdateQCChallenge(QCChallengeCommand qaQuestionCommand, Guid trialId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
{
if (qaQuestionCommand.Id == null)
{
if (await _repository.AnyAsync<QCChallenge>(t => t.IsClosed == false && t.SubjectVisitId == qaQuestionCommand.SubjectVisitId && t.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))
{
throw new BusinessValidationFailedException("当前访视有未关闭的 同意CRC上传的质疑不允许再次添加质疑");
}
QCChallenge? qcChallenge = null;
var success = false;
lock (_locker)
{
var trialConfig = _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }).FirstOrDefault();
if (trialConfig == null)
{
throw new BusinessValidationFailedException("项目不存在");
}
#region 处理访视状态变更
//var dbSubjectVisit = _subjectVisitRepository.FirstOrDefault(t => t.Id == qaQuestionCommand.SubjectVisitId);
//if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
//{
// return ResponseOutput.NotOk("项目配置为不审不允许添加QA质疑 ");
//}
//else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
//{
// if ((int)dbSubjectVisit.AuditState == (int)SubjectVisitStateEnum.Submitted)
// {
// dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
// }
// else
// {
// return ResponseOutput.NotOk($"项目配置为单审,当前审核状态不为{SubjectVisitStateEnum.Submitted},不允许添加QA质疑 ");
// }
//}
//else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
//{
// if ((int)dbSubjectVisit.AuditState == (int)SubjectVisitStateEnum.Submitted)
// {
// dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
// }
// else if ((int)dbSubjectVisit.AuditState == (int)SubjectVisitStateEnum.PrimaryQCPassed)
// {
// dbSubjectVisit.AuditState = AuditStateEnum.InSecondaryQC;
// }
// else
// {
// return ResponseOutput.NotOk($"项目配置为双审,访视状态为 {SubjectVisitStateEnum.Submitted}或{SubjectVisitStateEnum.PrimaryQCPassed}才允许添加QA质疑 ");
// }
//}
#endregion
//获取编号
var code = _repository.Where<QCChallenge>(t => t.TrialId == trialId).Select(t => t.ChallengeCode).DefaultIfEmpty().Max();
qcChallenge = _mapper.Map<QCChallenge>(qaQuestionCommand);
qcChallenge.QCProcessEnum = trialConfig.QCProcessEnum;
qcChallenge.CurrentQCEnum = currentQCType;
qcChallenge.TrialId = trialId;
qcChallenge.CreateUser = _userInfo.RealName;
qcChallenge.ChallengeCode = code + 1;
qcChallenge.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;
_ = _repository.AddAsync(qcChallenge).Result;
success = _repository.SaveChangesAsync().Result;
}
//分开两个事务 处理访视质疑状态
await DealChallengeState(qcChallenge.SubjectVisitId);
return qcChallenge;
#region 添加的时候把记录给留存
//var templateItems = _mapper.Map<List<QARecordTemplateItemDetail>>(visitQaCommand.QATrialTemplateItemList);
//templateItems.ForEach(u =>
//{
// u.IQA = _userInfo.RealName;
// u.IQACreateTime = DateTime.Now;
// u.IQANote = visitQaCommand.QARecord.Note;
// u.IQADeadline = visitQaCommand.QARecord.DeadlineTime;
// u.QARecordId = qaRecord.Id;
// qaRecord.QARecordTemplateItemDetailList.Add(u);
//});
////添加了QA记录 引用了QA模板后就不允许删除和编辑需要维护项目模板状态 传统做法
//var qaTrailTemplate = _qaTrailTemplateRepository.FirstOrDefault(t => t.Id == visitQaCommand.QARecord.QATrialTemplateId);
//qaTrailTemplate.Status = QATrialTemplateStatus.HasQuote;
#endregion
}
else
{
var qcChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qaQuestionCommand.Id);
if (qcChallenge == null)
{
throw new BusinessValidationFailedException("QC问题不存在");
};
_mapper.Map(qaQuestionCommand, qcChallenge);
var success = await _repository.SaveChangesAsync();
await DealChallengeState(qcChallenge.SubjectVisitId);
return qcChallenge;
}
}
/// <summary>
/// 关闭质疑,什么情况下允许?
/// </summary>
/// <param name="qcChallengeId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="closeEnum"></param>
/// <param name="closeReason"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{qcChallengeId:guid}/{subjectVisitId:guid}/{closeEnum}/{closeReason}")]
[TypeFilter(typeof(TrialResourceFilter))]
//[Authorize(Policy = "ImageQCPolicy")]
public async Task<IResponseOutput> CloseQCChallenge(Guid qcChallengeId, Guid subjectVisitId, [FromRoute] QCChallengeCloseEnum closeEnum, [FromRoute] string closeReason)
{
var dbQCChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qcChallengeId);
if (dbQCChallenge == null) return Null404NotFound(dbQCChallenge);
if (dbQCChallenge.ReuploadEnum == QCChanllengeReuploadEnum.CRCRequestReupload || dbQCChallenge.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload)
{
return ResponseOutput.NotOk("CRC申请重传的/QC同意重传的质疑在CRC设置重传完成前不允许关闭质疑");
}
dbQCChallenge.CloseResonEnum = closeEnum;
dbQCChallenge.IsClosed = true;
dbQCChallenge.ClosedTime = DateTime.Now;
dbQCChallenge.DialogList.Add(new QCChallengeDialog()
{
SubjectVisitId = dbQCChallenge.SubjectVisitId,
UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
QCChallengeId = dbQCChallenge.Id,
TalkContent = "关闭原因: " + closeReason
});
var success = await _repository.SaveChangesAsync();
await DealChallengeState(subjectVisitId);
return ResponseOutput.Result(success);
}
/// <summary>
/// 访视级别统计 质疑最新的状态
/// </summary>
/// <param name="subjectVisitId"></param>
private async Task DealChallengeState(Guid subjectVisitId)
{
var sv = await _repository.FirstOrDefaultAsync<SubjectVisit>(t => t.Id == subjectVisitId);
var closedStateList = await _repository.Where<QCChallenge>(t => t.SubjectVisitId == subjectVisitId).Select(t => t.IsClosed).ToListAsync();
if (closedStateList.Count == 0)
{
sv.ChallengeState = ChallengeStateEnum.No;
}
else if (closedStateList.All(t => t is true))
{
sv.ChallengeState = ChallengeStateEnum.HaveAndAllClosed;
}
else
{
sv.ChallengeState = ChallengeStateEnum.HaveAndHaveNotClosed;
}
await _repository.SaveChangesAsync();
}
/// <summary>
/// 删除QC质疑记录
/// </summary>
/// <returns></returns>
[HttpDelete("{qcChallengeId:guid}/{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
[Authorize(Policy = "ImageQCPolicy")]
public async Task<IResponseOutput> DeleteQCChallenge(Guid qcChallengeId)
{
if (await _repository.AnyAsync<QCChallengeDialog>(t => t.QCChallengeId == qcChallengeId))
{
ResponseOutput.NotOk("this QC Challenge Has been replied ");
}
var qaRecord = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qcChallengeId);
if (qaRecord == null) return Null404NotFound(qaRecord);
await _repository.DeleteAsync(qaRecord);
var success1 = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success1 /*|| success2 || success3*/);
}
/// <summary>
/// 针对 某条QC质疑 添加回复
/// </summary>
/// <param name="qaDialogCommand"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
[Authorize(Policy = "ImageQCPolicy")]
public async Task<IResponseOutput> AddQCChallengeReply(QADialogCommand qaDialogCommand)
{
var qaReply = _mapper.Map<QCChallengeDialog>(qaDialogCommand);
await _repository.AddAsync(qaReply);
qaReply.CreateUser = _userInfo.RealName;
qaReply.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;
var dbQCChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qaDialogCommand.QCChallengeId);
if (dbQCChallenge == null) return Null404NotFound(dbQCChallenge);
dbQCChallenge.LatestMsgTime = DateTime.Now;
dbQCChallenge.LatestReplyUserId = _userInfo.Id;
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, qaReply);
}
#endregion
#region 一致性核查
/// <summary>
/// 一致性核查 质疑的添加/回复
/// </summary>
/// <param name="checkDialogCommand"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
[Authorize(Policy = "ImageCheckPolicy")]
public async Task<IResponseOutput<CheckChallengeDialog>> AddCheckChallengeReply(CheckChallengeDialogCommand checkDialogCommand)
{
var qaReply = _mapper.Map<CheckChallengeDialog>(checkDialogCommand);
qaReply.CreateUser = _userInfo.RealName;
qaReply.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;
await _repository.AddAsync(qaReply);
//修改一致性核查 质疑状态
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == checkDialogCommand.SubjectVisitId);
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator)
{
sv.CheckChallengeState = CheckChanllengeTypeEnum.CRCWaitPMReply;
}
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager)
{
sv.CheckChallengeState = CheckChanllengeTypeEnum.PMWaitCRCReply;
}
else
{
throw new Exception("一致性核查对话操作用户 只允许 CRC/PM");
}
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success, qaReply);
}
/// <summary>
/// 关闭 一致性核查质疑
/// </summary>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> CloseCheckChallenge(Guid subjectVisitId)
{
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (sv == null) return Null404NotFound(sv);
if (sv.RequestBackState == RequestBackStateEnum.PM_AgressBack)
{
ResponseOutput.NotOk("执行一致性核查的访视 不允许关闭质疑!");
}
sv.CheckChallengeState = CheckChanllengeTypeEnum.Closed;
await _repository.SaveChangesAsync();
return ResponseOutput.Ok(sv);
}
/// <summary>
/// 手动设置一致性核查通过
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="signId"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{signId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetCheckPass(Guid subjectVisitId)
{
if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
{
ResponseOutput.NotOk("只允许PM 手动设置一致性核查通过");
}
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (sv == null) return Null404NotFound(sv);
if (sv.RequestBackState == RequestBackStateEnum.PM_AgressBack)
{
ResponseOutput.NotOk("当前是PM同意回退,不允许设置一致性核查通过");
}
if (sv.CheckChallengeState != CheckChanllengeTypeEnum.Closed && sv.AuditState == AuditStateEnum.QCPassed)
{
ResponseOutput.NotOk("一致性核查质疑未关闭/审核状态不是通过,不允许设置一致性核查通过");
}
sv.CheckState = CheckStateEnum.CVPassed;
sv.ForwardState = ForwardStateEnum.ToForward;
sv.CheckPassedTime = DateTime.Now;
await _repository.SaveChangesAsync();
//var signSuccess = await _repository.UpdateFromQueryAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
return ResponseOutput.Result(true);
}
/// <summary>
/// CRC 请求回退
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> CRCRequstCheckBack(Guid subjectVisitId)
{
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (sv == null) return Null404NotFound(sv);
if (sv.CheckState == CheckStateEnum.CVPassed)
{
return ResponseOutput.NotOk("核查通过的数据不允许申请回退");
}
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { RequestBackState = RequestBackStateEnum.CRC_RequestBack });
return ResponseOutput.Ok();
}
/// <summary>
/// 一致性核查 回退 对话记录不清除 只允许PM回退
/// </summary>
/// <returns></returns>
[HttpPut("{trialId:guid}/{signId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> CheckBack(Guid subjectVisitId)
{
if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
{
return ResponseOutput.NotOk(" 只允许PM 回退!");
}
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (sv == null) return Null404NotFound(sv);
if (sv.CheckState == CheckStateEnum.CVPassed || sv.CheckState == CheckStateEnum.ToCheck)
{
return ResponseOutput.NotOk("待核查/核查通过的数据不允许回退");
}
//sv.CheckChallengeState = (int)CheckChanllengeTypeEnum.None;
//sv.CheckState = CheckStateEnum.None;
//sv.ChallengeState = (int)ChallengeStateEnum.No;
sv.AuditState = AuditStateEnum.None;
sv.SubmitState = SubmitStateEnum.ToSubmit;
//回退后,回退状态恢复
sv.RequestBackState = RequestBackStateEnum.NotRequest;
sv.IsCheckBack = true;
sv.CheckState = CheckStateEnum.None;
sv.CheckChallengeState = CheckChanllengeTypeEnum.None;
sv.SVENDTC = null;
sv.SVSTDTC = null;
sv.PreliminaryAuditTime = null;
sv.SubmitTime = null;
sv.ReviewAuditTime = null;
sv.CurrentActionUserExpireTime = null;
sv.IsTake = false;
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
//var success1 = _studyRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//var succeess2 = _instanceRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//var success3 = _seriesRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_qcChallengeRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_qcChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_checkChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
await _repository.AddAsync(new CheckChallengeDialog() { SubjectVisitId = subjectVisitId, TalkContent = "PM执行了一致性核查回退", UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt });
await _repository.BatchDeleteAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId);
var success = await _repository.SaveChangesAsync();
// var signSuccess = await _repository.UpdateFromQueryAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
return ResponseOutput.Result( success);
}
/// <summary>
/// 一致性核查 excel上传 支持三种格式
/// </summary>
/// <param name="file"></param>
/// <param name="_mediator"></param>
/// <param name="trialId"></param>
/// <param name="_hostEnvironment"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> UploadVisitCheckExcel(IFormFile file, [FromServices] IMediator _mediator, Guid trialId, [FromServices] IWebHostEnvironment _hostEnvironment)
{
if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
{
return ResponseOutput.NotOk("只允许PM 操作");
}
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.ToString().Trim('"').ToLower();
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
{
return ResponseOutput.NotOk("只允许Excel、 CSV");
}
//上传根路径
string uploadFolderPath = Path.Combine(rootPath, "UploadFile", "Check");
if (!Directory.Exists(uploadFolderPath))
{
Directory.CreateDirectory(uploadFolderPath);
}
//存放核对表
var filePath = Path.Combine(uploadFolderPath, DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + fileName);
using (FileStream fs = System.IO.File.Create(filePath))
{
await file.CopyToAsync(fs);
await fs.FlushAsync();
}
//获取Excel表内容
var config = new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
};
var etcCheckList = new List<CheckViewModel>();
#region MiniExcel 需要自己验证数据格式规范
//if (fileName.EndsWith(".csv"))
//{
// //因为csv 需要加配置文件 不然都是null
// etcCheckList = MiniExcel.Query<CheckViewModel>(filePath, null, configuration: config).ToList();
//}
//else if (fileName.EndsWith(".xlsx"))
//{
//
// etcCheckList = MiniExcel.Query<CheckViewModel>(filePath).ToList();
//}
#endregion
//Magicodes 支持自定义特性验证
if (fileName.EndsWith(".xlsx"))
{
var Importer = new ExcelImporter();
var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));
if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
etcCheckList = import.Data.ToList();
}
else if (fileName.EndsWith(".csv"))
{
#region 临时方案 MiniExcel读取 然后保存为xlsx 再用 Magicodes验证数据
//因为csv 需要加配置文件 不然都是null
etcCheckList = MiniExcel.Query<CheckViewModel>(filePath, null, configuration: config).ToList();
var csVToXlsxPath = Path.Combine(uploadFolderPath, DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + Path.GetFileNameWithoutExtension(fileName) + ".xlsx");
await MiniExcel.SaveAsAsync(csVToXlsxPath, etcCheckList, excelType: ExcelType.XLSX);
var Importer = new ExcelImporter();
var import = await Importer.Import<CheckViewModel>(File.OpenRead(csVToXlsxPath));
if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
etcCheckList = import.Data.ToList();
#endregion
#region 导入组件有问题 excel编码格式
//var Importer = new CsvImporter();
//var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));
//if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());
//if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));
//if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));
//etcCheckList = import.Data.ToList();
#endregion
}
//ExcelReaderFactory 需要自己验证数据 并且从固定列取数据
else
{
//为了支持 xls 引入新的组件库
using (var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read))
{
// Auto-detect format, supports:
// - Binary Excel files (2.0-2003 format; *.xls)
// - OpenXml Excel files (2007 format; *.xlsx, *.xlsb)
using (var reader = ExcelReaderFactory.CreateReader(stream))
{
// 2. Use the AsDataSet extension method
var dateset = reader.AsDataSet();
foreach (DataRow col in dateset.Tables[0].Rows)
{
etcCheckList.Add(new CheckViewModel()
{
SiteCode = col[0].ToString(),
SubjectCode = col[1].ToString(),
VisitName = col[2].ToString(),
StudyDate = col[3].ToString(),
Modality = col[4].ToString(),
});
}
etcCheckList.Remove(etcCheckList[0]);
// The result of each spreadsheet is in result.Tables
}
}
}
//etcCheckList = etcCheckList.Where(t=>)
if (etcCheckList == null || etcCheckList.Count == 0)
{
return ResponseOutput.NotOk("请上传规定格式的Excel文件保证有有效数据");
}
else
{
//处理Excel 有时只是清除某些行的数据 读取也会读到数据只是数据是null 后面处理的时候转为字符串为报错
etcCheckList.ForEach(t =>
{
t.Modality = t.Modality ?? string.Empty;
t.SiteCode = t.SiteCode ?? string.Empty;
t.SubjectCode = t.SubjectCode ?? string.Empty;
t.VisitName = t.VisitName ?? string.Empty;
t.StudyDate = t.StudyDate ?? string.Empty;
});
var dt = DateTime.Now;
etcCheckList = etcCheckList.Where(t => !(t.Modality == string.Empty && t.SiteCode == string.Empty && t.SubjectCode == string.Empty && t.VisitName == string.Empty && t.StudyDate == string.Empty && DateTime.TryParse(t.StudyDate, out dt))).ToList();
if (etcCheckList.Count == 0)
{
return ResponseOutput.NotOk("请上传规定格式的Excel文件保证有有效数据");
}
}
await _mediator.Send(new ConsistencyVerificationRequest() { ETCList = etcCheckList, TrialId = trialId });
return ResponseOutput.Ok();
}
#endregion
#region QC 核对问题 操作检查各种操作
/// <summary>
/// 添加或者更新 QC核对问题列表 两个人不能同时操作,就算意外进去了,提交数据,也不会覆盖前一个人数据, 后台已经做好判断
/// </summary>
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> AddOrUpdateQCQuestionAnswerList(QCQuestionAnswerCommand[] qcQuestionAnswerCommands, Guid trialId, Guid subjectVisitId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
{
//验证是否能操作
var verifyResult = await VerifyQCCanOpt(subjectVisitId);
if (!verifyResult.IsSuccess)
{
return verifyResult;
}
//更新
if (qcQuestionAnswerCommands.Any(t => t.Id != null))
{
#region 先删除再添加
//await _repository.DeleteFromQueryAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.QCProcessEnum == trialQCProcess && t.CurrentQCEnum == currentQCType);
//var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);
//addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });
//await _repository.AddRangeAsync(addlist);
#endregion
#region 先查询再更新
var questionAnswerList = await _repository.Where<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.QCProcessEnum == trialQCProcess && t.CurrentQCEnum == currentQCType, true).ToListAsync();
qcQuestionAnswerCommands.ToList().ForEach(t =>
{
var temp = questionAnswerList.FirstOrDefault(u => u.Id == t.Id);
if (temp != null)
{
temp.Answer = t.Answer;
//temp.ChildAnswer = t.ChildAnswer;
}
});
//Automapper 映射有问题 automapper 会把Guid? 类型的null 值转为 guid.Empty 导致映射错误
//_mapper.Map(qcQuestionAnswerCommands, questionAnswerList);
#endregion
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
}
else
{
var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);
addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });
await _repository.AddRangeAsync(addlist);
return ResponseOutput.Result(await _repository.SaveChangesAsync());
}
}
/// <summary>
/// 1、设置为不读片2 设置为读片(取消 先前设置为不读片) 4 设置为删除(数据库记录软删除) 5 恢复为未删除
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="studyId"></param>
/// <param name="seriesId"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{studyId:guid}/{seriesId:guid}/{state:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetSeriesState(Guid subjectVisitId, Guid studyId, Guid seriesId, int state)
{
//验证是否能操作
var verifyResult = await VerifyQCCanOpt(subjectVisitId);
if (!verifyResult.IsSuccess)
{
return verifyResult;
}
var series = await _repository.Where<DicomSeries>(t => t.Id == seriesId, true).IgnoreQueryFilters().FirstOrDefaultAsync();
if (series == null) return Null404NotFound(series);
if (state == 1)
{
series.IsReading = false;
}
else if (state == 2)
{
series.IsReading = true;
}
else if (state == 4)
{
series.IsDeleted = true;
var study = await _repository.Where<DicomStudy>(t => t.Id == studyId, true).IgnoreQueryFilters().FirstOrDefaultAsync();
if (study == null) return Null404NotFound(study);
var instanceIdList = await _repository.Where<DicomInstance>(t => t.SeriesId == seriesId).Select(t => t.Id).ToListAsync();
//instanceIdList.ForEach(t =>
//{
// var path = _dicomFileStoreHelper.GetInstanceFilePath(study, seriesId, t.ToString());
// if (System.IO.File.Exists(path))
// {
// File.Delete(path);
// }
//});
study.InstanceCount = study.InstanceCount - instanceIdList.Count;
study.SeriesCount = study.SeriesCount - 1;
study.IsDeleted = study.SeriesCount == 0;
}
else if (state == 5)
{
series.IsDeleted = false;
var study = await _repository.Where<DicomStudy>(t => t.Id == studyId, true).IgnoreQueryFilters().FirstOrDefaultAsync();
if (study == null) return Null404NotFound(study);
var instanceIdList = await _repository.Where<DicomInstance>(t => t.SeriesId == seriesId).Select(t => t.Id).ToListAsync();
study.InstanceCount = study.InstanceCount + instanceIdList.Count;
study.SeriesCount = study.SeriesCount + 1;
study.IsDeleted = study.SeriesCount == 0;
}
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
}
/// <summary>
///type 1 :study 2: series 3:非dicom QC修改检查部位和 拍片类型
/// </summary>
/// <param name="id"></param>
/// <param name="type"></param>
/// <param name="modality"></param>
/// <param name="bodyPart"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{id:guid}/{type:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> UpdateModality(Guid id, int type, [FromQuery] string modality, [FromQuery] string bodyPart)
{
if (type == 1)
{
var study = await _repository.FirstOrDefaultAsync<DicomStudy>(t => t.Id == id);
if (study == null) return Null404NotFound(study);
study.BodyPartForEdit = bodyPart;
study.Modalities = modality;
await _repository.BatchUpdateAsync<DicomSeries>(t => t.StudyId == id, r => new DicomSeries() { BodyPartForEdit = bodyPart, Modality = modality });
}
else if (type == 2)
{
var series = await _repository.FirstOrDefaultAsync<DicomSeries>(t => t.Id == id);
if (series == null) return Null404NotFound(series);
series.BodyPartForEdit = bodyPart;
}
else if (type == 3)
{
}
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 验证是否质疑都关闭了 可以审核通过和不通过
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
[HttpGet("{subjectVisitId:guid}")]
public async Task<IResponseOutput> VerifyCanQCPassedOrFailed(Guid subjectVisitId)
{
if (await _repository.AnyAsync<QCChallenge>(t => t.SubjectVisitId == subjectVisitId && t.IsClosed == false))
{
return ResponseOutput.NotOk("有质疑未关闭,不允许该操作");
}
return ResponseOutput.Ok();
}
/// <summary>
/// 删除检查列表
/// </summary>
/// <param name="ids"></param>
/// <param name="subjectVisitId"></param>
/// <param name="trialId"></param>
/// <returns></returns>SeriesCount
[HttpPost, Route("{trialId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId)
{
//提交了 但是IQC同意的时候 是可以删除的
if (await _repository.AnyAsync<SubjectVisit>(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
(!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
{
return ResponseOutput.NotOk("CRC Has Submited Imagecan not delete");
}
var DicomStudys = await _repository.GetQueryable<DicomStudy>().Where(x => ids.Contains(x.Id)).ToListAsync();
List<DataInspection> datas = new List<DataInspection>();
DicomStudys.ForEach(x =>
{
datas.Add(new DataInspection()
{
SiteId = x.SiteId,
SubjectId = x.SubjectId,
TrialId = x.TrialId,
SubjectVisitId=x.SubjectVisitId,
GeneralId=x.Id,
Identification= "Delete|DICOM Study|Data|Visit-Image Upload",
JsonDetail = JsonConvert.SerializeObject(new
{
studyUid=x.StudyCode,
modality=x.Modalities,
bodyPart=x.BodyPartForEdit,
seriesNum=x.SeriesCount,
fileNum = x.InstanceCount,
studyTime=x.StudyTime.ToString("yyyy-MM-dd")
})
});
});
#region will calls error wried
//ids.ToList().ForEach(async id =>
//{
// var success1 = await _repository.DeleteFromQueryAsync<DicomStudy>(t => t.Id == id);
// var succeess2 = await _repository.DeleteFromQueryAsync<DicomInstance>(t => t.StudyId == id);
// var success3 = await _repository.DeleteFromQueryAsync<DicomSeries>(t => t.StudyId == id);
//});
#endregion
foreach (var id in ids)
{
var success1 = await _repository.BatchDeleteAsync<DicomStudy>(t => t.Id == id);
var succeess2 = await _repository.BatchDeleteAsync<DicomInstance>(t => t.StudyId == id);
var success3 = await _repository.BatchDeleteAsync<DicomSeries>(t => t.StudyId == id);
//删除 物理文件
var instanceIdList = await _repository.Where<DicomInstance>(t => t.StudyId == id)
.Select(t => new { InstanceId = t.Id, t.SeriesId, t.StudyId, t.SubjectId, t.SiteId }).ToListAsync();
instanceIdList.ForEach(t =>
{
var path = _dicomFileStoreHelper.GetInstanceFilePath(new DicomStudy() { Id = t.StudyId, SubjectId = t.SubjectId, TrialId = trialId, SiteId = t.SiteId, SubjectVisitId = subjectVisitId }, t.SeriesId, t.InstanceId.ToString());
if (System.IO.File.Exists(path))
{
File.Delete(path);
}
});
}
//一个访视下面有多个检查,所以需要检测 没有的时候才清空 非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, SVENDTC = null, SVSTDTC = null, SubmitState = SubmitStateEnum.None });
//_qaNoticeRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_qaNoticeUserRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_qcChallengeRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_qcChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_trialQCQuestionAnswerRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//_checkChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
}
var svTime = await _repository.Where<SubjectVisit>(t => t.Id == 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 == subjectVisitId, u => new SubjectVisit()
{
EarliestScanDate = minArray.Min(),
LatestScanDate = maxArray.Max()
});
var subvisit = await _repository.GetQueryable<SubjectVisit>().FirstOrDefaultAsync(x => x.Id == subjectVisitId);
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();
}
#endregion
#region 临床数据签名 领取、 设置紧急、RequestToQC QC通过、不通过
//[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
//public async Task<IResponseOutput> SignClinicalData(Guid trialId, Guid subjectVisitId)
//{
// await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.Id == subjectVisitId, u => new SubjectVisit() { ClinicalDataSignTime = DateTime.Now, ClinicalDataSignUserId = _userInfo.Id });
// return ResponseOutput.Ok();
//}
/// <summary>
/// 手动领取 或者取消 QC任务
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="obtaionOrCancel">true 获取 false是取消领取</param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{obtaionOrCancel:bool}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> ObtainOrCancelQCTask(Guid trialId, Guid subjectVisitId, bool obtaionOrCancel)
{
var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (dbSubjectVisit == null) return Null404NotFound(dbSubjectVisit);
if (obtaionOrCancel)
{
if (await _subjectVisitRepository.AnyAsync(t => t.Trial.QCQuestionConfirmedUserId == null && t.Id == subjectVisitId))
{
return ResponseOutput.NotOk("QC问题未确认不允许领取任务");
}
if (await _subjectVisitRepository.AnyAsync(t => t.IsTake && t.SubjectId != dbSubjectVisit.SubjectId && t.CurrentActionUserId == _userInfo.Id && t.TrialId == dbSubjectVisit.TrialId))
{
return ResponseOutput.NotOk("您已经领取了其他受试者,完成后才允许领取新的受试者");
}
#region 处理验证
var trialConfig = await _trialRepository
.Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
.FirstOrDefaultAsync(t => t.TrialId == trialId)
.IfNullThrowException();
if (dbSubjectVisit.IsTake)
{
return ResponseOutput.NotOk("当前已被领取,不允许领取");
}
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
return ResponseOutput.NotOk("项目配置为不审没有领取或者取消QC Task");
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.Id)
{
return ResponseOutput.NotOk("初审已通过,不能继续领取");
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
//单审QC 释放后 也是可以领取的
}
else
{
return ResponseOutput.NotOk("项目配置为单审,不满足SubmmitState已提交 或者 AuditState待审核/审核中, 不允许领取,请刷新界面");
}
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.Id)
{
return ResponseOutput.NotOk("复审不能和初审是同一个人");
}
//提交 并且初审通过 那么领取后进入 复审中
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.PrimaryQCPassed)
{
dbSubjectVisit.AuditState = AuditStateEnum.InSecondaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
{
//初审中 复审中 领取也是ok的 其他人接着做
}
else
{
return ResponseOutput.NotOk("项目配置为复审,不满足提交状态:已提交 或者 审核状态:待审核/QC中, 不允许领取,请刷新界面");
}
}
#endregion
dbSubjectVisit.IsTake = true;
dbSubjectVisit.CurrentActionUserId = _userInfo.Id;
dbSubjectVisit.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);
//启动定时任务 1h后处理
//BackgroundJob.Schedule<IObtainTaskAutoCancelJob>(t => t.CancelQCObtaion(subjectVisitId, DateTime.Now), TimeSpan.FromHours(1));
}
else
{
dbSubjectVisit.IsTake = false;
dbSubjectVisit.CurrentActionUserId = null;
dbSubjectVisit.CurrentActionUserExpireTime = null;
}
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
/// <summary>
/// CRC RequestToQC 批量提交
/// </summary>
/// <returns></returns>
[HttpPost]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> CRCRequestToQC(CRCRequestToQCCommand cRCRequestToQCCommand)
{
var trialConfig = await _trialRepository
.Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification, t.IsUrgent, t.IsHaveFirstGiveMedicineDate, t.ClinicalInformationTransmissionEnum })
.FirstOrDefaultAsync(t => t.TrialId == cRCRequestToQCCommand.TrialId);
if (trialConfig == null) return Null404NotFound(trialConfig);
var dbSubjectVisitList = await _subjectVisitRepository.Where(t => cRCRequestToQCCommand.SubjectVisitIds.Contains(t.Id), true).Include(t => t.Subject).ToListAsync();
if (dbSubjectVisitList.Any(t => t.SubmitState == SubmitStateEnum.None))
{
return ResponseOutput.NotOk("有访视未上传任何Dicom/非Dicom数据 不允许提交");
}
foreach (var dbSubjectVisit in dbSubjectVisitList)
{
//基线不验证
if (trialConfig.IsHaveFirstGiveMedicineDate && !dbSubjectVisit.IsBaseLine && dbSubjectVisit.Subject.FirstGiveMedicineTime == null)
{
return ResponseOutput.NotOk("项目配置了需要填写首次给药日期 但是受试者没有填写首次给药日期,不允许提交");
}
//基线 且配置了临床数据
if (trialConfig.ClinicalInformationTransmissionEnum != 0 && dbSubjectVisit.IsBaseLine/*&&dbSubjectVisit.ClinicalDataSignUserId==null*/)
{
//已确认临床数据完整性
dbSubjectVisit.IsConfirmedClinicalData = true;
//var signSuccess = await _repository.UpdateFromQueryAsync<TrialSign>(t => t.Id == cRCRequestToQCCommand.SignId, u => new TrialSign() { IsCompleted = true });
////现在修改为 提交时 设置签名信息
//dbSubjectVisit.ClinicalDataSignUserId = _userInfo.Id;
//dbSubjectVisit.ClinicalDataSignTime = DateTime.Now;
//那么没有录入 不允许提交
//if (!await _repository.AnyAsync<SubjectVisit>(t => t.PreviousHistoryList.Any() || t.PreviousOtherList.Any() || t.PreviousSurgeryList.Any()))
//{
// return ResponseOutput.NotOk("没有临床数据,不允许提交");
//}
//return ResponseOutput.NotOk("没有签名临床数据,不允许提交");
}
var maxVisit = await _subjectVisitRepository.Where(t => t.SubjectId == dbSubjectVisit.SubjectId && t.SubmitState == SubmitStateEnum.Submitted)
.OrderByDescending(t => t.VisitNum).Select(t => new { t.Id, t.VisitNum }).FirstOrDefaultAsync();
//修改受试者最新访视
dbSubjectVisit.Subject.LatestSubjectVisitId = maxVisit == null ? dbSubjectVisit.Id : maxVisit.VisitNum < dbSubjectVisit.VisitNum ? dbSubjectVisit.Id : maxVisit.Id;
//var maxVisitNum = maxVisit == null ? dbSubjectVisit.VisitNum : maxVisit.VisitNum < dbSubjectVisit.VisitNum ? dbSubjectVisit.VisitNum : maxVisit.VisitNum;
////判断是否有缺失影像
//dbSubjectVisit.Subject.IsMissingImages = await _subjectVisitRepository.AnyAsync(t => (t.VisitNum < maxVisitNum && t.SubmitState != SubmitStateEnum.Submitted && t.IsLostVisit == false));
//项目或者Subject IsUrgent 提交时 访视也设置为紧急
if (trialConfig.IsUrgent || dbSubjectVisit.Subject.IsUrgent || (dbSubjectVisit.PDState == PDStateEnum.PDProgress && !dbSubjectVisit.IsBaseLine) || (dbSubjectVisit.IsEnrollmentConfirm && dbSubjectVisit.IsBaseLine))
{
dbSubjectVisit.IsUrgent = true;
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.ToSubmit || dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted)
{
dbSubjectVisit.SubmitState = SubmitStateEnum.Submitted;
dbSubjectVisit.SubmitTime = DateTime.Now;
}
//不审 直接QC通过 可能一致性核查 也可能不一致性核查
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;
// 不一致性核查 就CVPassed ToForward 否则就是待核查
dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;
dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;
}
}
var success = await _repository.SaveChangesAsync();
List<DataInspection> datas = new List<DataInspection>();
dbSubjectVisitList.ForEach(x =>
{
datas.Add(new DataInspection()
{
SiteId = x.SiteId,
SubjectId = x.SubjectId,
TrialId = x.TrialId,
SubjectVisitId = x.Id,
Identification= "Edit|Visit|Status|Visit-Image Upload",
JsonDetail = JsonConvert.SerializeObject(new
{
SubmitState = "已提交",
})
});
});
dbSubjectVisitList.ForEach(x =>
{
datas.Add(new DataInspection()
{
SiteId = x.SiteId,
SubjectId = x.SubjectId,
TrialId = x.TrialId,
SubjectVisitId = x.Id,
Identification = "Edit|Visit|Status|Visit-Image Upload-1",
JsonDetail = JsonConvert.SerializeObject(new
{
SubmitState = "已提交",
})
});
});
await _inspectionService.AddListInspectionRecordAsync(datas);
return ResponseOutput.Result(success);
}
/// <summary>
/// 设置QC 通过或者不通过 7:QC failed 8QC passed
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="signId"></param>
/// <param name="auditState"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{signId:guid}/{auditState:int}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> QCPassedOrFailed(Guid trialId, Guid subjectVisitId, Guid signId, [FromRoute] AuditStateEnum auditState)
{
if (!await _repository.AnyAsync<TrialUser>(t => t.TrialId == trialId && t.UserId == _userInfo.Id))
{
return ResponseOutput.NotOk("您已经被移出项目,不允许该操作");
}
//判断质疑是否都关闭了
if (await _repository.AnyAsync<QCChallenge>(t => t.SubjectVisitId == subjectVisitId && t.IsClosed == false))
{
return ResponseOutput.NotOk("有质疑未关闭,不允许该操作");
}
var trialConfig = await _trialRepository
.Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
.FirstOrDefaultAsync(t => t.TrialId == trialId)
.IfNullThrowException();
var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (dbSubjectVisit == null) return Null404NotFound(dbSubjectVisit);
//有人QC Passed
if (auditState == AuditStateEnum.QCPassed)
{
//判断 QC流程 不审 单审 双审
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
return ResponseOutput.NotOk("不审状态下不允许设置为QC Passed");
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.First))
{
return ResponseOutput.NotOk("必须填写审核问题,并保存,否则不允许提交");
}
// 单审
dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;
dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;
dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;
dbSubjectVisit.PreliminaryAuditUserId = _userInfo.Id;
dbSubjectVisit.PreliminaryAuditTime = DateTime.Now;
dbSubjectVisit.IsTake = false;
dbSubjectVisit.CurrentActionUserExpireTime = null;
}
else
{
return ResponseOutput.NotOk("项目配置为单审 当前审核状态不为 InPrimaryQC不能变更到 QCPassed");
}
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
// 双审 如果当前db 状态是 InPrimaryQC 当前操作为 QCPassed 那么设置为 PrimaryQCPassed
if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.First))
{
return ResponseOutput.NotOk("必须填写审核问题,并保存,否则不允许提交");
}
dbSubjectVisit.AuditState = AuditStateEnum.PrimaryQCPassed;
dbSubjectVisit.PreliminaryAuditUserId = _userInfo.Id;
dbSubjectVisit.PreliminaryAuditTime = DateTime.Now;
dbSubjectVisit.IsTake = false;
dbSubjectVisit.CurrentActionUserExpireTime = null;
}
else if (dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC)
{
if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.Second))
{
return ResponseOutput.NotOk("必须填写审核问题,并保存,否则不允许提交");
}
dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;
dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;
dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;
dbSubjectVisit.ReviewAuditUserId = _userInfo.Id;
dbSubjectVisit.ReviewAuditTime = DateTime.Now;
dbSubjectVisit.IsTake = false;
dbSubjectVisit.CurrentActionUserExpireTime = null;
}
else
{
return ResponseOutput.NotOk($"项目配置为双审 当前审核状态为 {dbSubjectVisit.AuditState},不能变更到 QCPassed");
}
}
}
else if (auditState == AuditStateEnum.QCFailed)
{
//判断 QC流程 不审 单审 双审
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
return ResponseOutput.NotOk("不审状态下不允许设置为QC Failed");
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
// 单审
dbSubjectVisit.AuditState = AuditStateEnum.QCFailed;
}
else
{
return ResponseOutput.NotOk("项目配置为单审 当前审核状态不为 InPrimaryQC不能变更到 QCFailed");
}
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
// 双审
if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC)
{
dbSubjectVisit.AuditState = AuditStateEnum.QCFailed;
}
else
{
return ResponseOutput.NotOk($"项目配置为双审 当前审核状态为 {dbSubjectVisit.AuditState},不能变更到 QCFailed");
}
}
}
//删除 软删除的物理文件
var instanceIdList = await _repository.Where<DicomInstance>(t => t.DicomSerie.IsDeleted && t.SubjectVisitId == subjectVisitId)
.Select(t => new { InstanceId = t.Id, t.SeriesId, t.StudyId, t.SubjectId, t.SiteId }).ToListAsync();
instanceIdList.ForEach(t =>
{
var path = _dicomFileStoreHelper.GetInstanceFilePath(new DicomStudy() { Id = t.StudyId, SubjectId = t.SubjectId, TrialId = trialId, SiteId = t.SiteId, SubjectVisitId = subjectVisitId }, t.SeriesId, t.InstanceId.ToString());
if (System.IO.File.Exists(path))
{
File.Delete(path);
}
});
await _repository.SaveChangesAsync();
var success = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
return ResponseOutput.Result(success);
}
/// <summary>
/// 设置、取消 访视紧急
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="setOrCancel"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{setOrCancel:bool}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetVisitUrgent(Guid trialId, Guid subjectVisitId, bool setOrCancel)
{
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (sv == null) return Null404NotFound(sv);
sv.IsUrgent = setOrCancel;
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
#endregion
#region 重传、重传完设置
/// <summary>
/// QA设置 需要重传
/// </summary>
/// <param name="trialId"></param>
/// <param name="signId"></param>
/// <param name="qcChallengeId"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{qcChallengeId:guid}/{signId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetNeedReupload(Guid trialId, Guid qcChallengeId)
{
if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.IQC)
{
return ResponseOutput.NotOk("重传 只允许QA 设置!");
}
//获取项目配置
var trialConfig = await _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
.FirstOrDefaultAsync().IfNullThrowException();
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
return ResponseOutput.NotOk("不审操作,不会有需要重传的操作!");
}
var qcChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qcChallengeId);
if (qcChallenge == null) return Null404NotFound(qcChallenge);
if (await _repository.CountAsync<QCChallenge>(t => t.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload && t.SubjectVisitId == qcChallenge.SubjectVisitId && t.IsClosed == false) >= 1)
{
return ResponseOutput.NotOk("当前访视,有一个未关闭的质疑 QC设置了需要重传CRC还未完成上传当前不允许再次设置");
}
qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.QCAgreeUpload;
qcChallenge.LatestMsgTime = DateTime.Now;
qcChallenge.LatestReplyUserId = _userInfo.Id;
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == qcChallenge.SubjectVisitId, c => new SubjectVisit() { IsQCConfirmedReupload = true });
qcChallenge.DialogList.Add(new QCChallengeDialog()
{
SubjectVisitId = qcChallenge.SubjectVisitId,
UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
QCChallengeId = qcChallenge.Id,
TalkContent = "QC同意重传"
});
//双审 并且是2QC 那么需要回退到1QC 讲1QC数据清除
if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit && await _repository.AnyAsync<QCChallenge>(t => t.Id == qcChallengeId && t.SubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
{
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == qcChallenge.SubjectVisitId);
if (sv == null) return Null404NotFound(sv);
// //一致性核查质疑状态
// sv.CheckChallengeState = CheckChanllengeTypeEnum.None;
//// 一致性核查状态
// sv.CheckState = CheckStateEnum.None;
// 审核状态
sv.AuditState = AuditStateEnum.InPrimaryQC;
sv.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);
sv.CurrentActionUserId = _userInfo.Id;
BackgroundJob.Schedule<IObtainTaskAutoCancelJob>(t => t.CancelQCObtaion(qcChallenge.SubjectVisitId, DateTime.Now), TimeSpan.FromHours(1));
sv.IsTake = true;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
//删除1QC 填写的问题答案
await _repository.BatchDeleteAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.First);
//2QC 数据变为1QC
await _repository.BatchUpdateAsync<QCChallenge>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.Second, k => new QCChallenge() { CurrentQCEnum = CurrentQC.First });
await _repository.BatchUpdateAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.Second, k => new TrialQCQuestionAnswer() { CurrentQCEnum = CurrentQC.First });
}
var success = await _repository.SaveChangesAsync();
//var signSuccess = await _repository.UpdateFromQueryAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });
return ResponseOutput.Result(success);
}
/// <summary>
/// CRC 设置已经重传完成
/// </summary>
/// <returns></returns>
[HttpPost]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetReuploadFinished(CRCReuploadFinishedCommand cRCReuploadFinishedCommand)
{
if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ClinicalResearchCoordinator)
{
return ResponseOutput.NotOk("重传完成 只允许CRC 设置!");
}
var trialConfig = await _trialRepository
.Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification, t.IsUrgent, t.IsHaveFirstGiveMedicineDate, t.ClinicalInformationTransmissionEnum })
.FirstOrDefaultAsync(t => t.TrialId == cRCReuploadFinishedCommand.TrialId);
var qcChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == cRCReuploadFinishedCommand.QCChallengeId);
if (qcChallenge == null) return Null404NotFound(qcChallenge);
qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.CRCReuploaded;
qcChallenge.ReUploadedTime = DateTime.Now;
qcChallenge.ReUploader = _userInfo.RealName;
qcChallenge.LatestMsgTime = DateTime.Now;
qcChallenge.LatestReplyUserId = _userInfo.Id;
var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == qcChallenge.SubjectVisitId).IfNullThrowException();
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == qcChallenge.SubjectVisitId, c => new SubjectVisit() { IsQCConfirmedReupload = false });
qcChallenge.DialogList.Add(new QCChallengeDialog()
{
SubjectVisitId = qcChallenge.SubjectVisitId,
UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
QCChallengeId = qcChallenge.Id,
TalkContent = "CRC已重传完成"
});
//基线 且配置了临床数据
if (trialConfig.ClinicalInformationTransmissionEnum != 0 && dbSubjectVisit.IsBaseLine)
{
//已确认临床数据完整性
dbSubjectVisit.IsConfirmedClinicalData = true;
var signSuccess = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == cRCReuploadFinishedCommand.SignId, u => new TrialSign() { IsCompleted = true });
}
var success = await _repository.SaveChangesAsync();
return ResponseOutput.Ok(success);
}
[HttpPut("{trialId:guid}/{qcChallengeId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> CRCRequestReUpload(Guid qcChallengeId)
{
var qcChallenge = await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qcChallengeId);
if (qcChallenge == null) return Null404NotFound(qcChallenge);
if (qcChallenge.ReuploadEnum == QCChanllengeReuploadEnum.CRCReuploaded)
{
qcChallenge.ReUploadedTime = null;
}
qcChallenge.LatestMsgTime = DateTime.Now;
qcChallenge.LatestReplyUserId = _userInfo.Id;
qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.CRCRequestReupload;
qcChallenge.DialogList.Add(new QCChallengeDialog()
{
SubjectVisitId = qcChallenge.SubjectVisitId,
UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
QCChallengeId = qcChallenge.Id,
TalkContent = "CRC申请重传/上传影像"
});
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
#endregion
/// <summary>
/// 上传界面 更新受试者首次给药日期 是否入组确认,以及访视 是否PD进展
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> UpdateSubjectAndSVInfo(UploadSubjectAndVisitCommand command)
{
if (command.IsEnrollmentConfirm != null)
{
if (await _subjectVisitRepository.Where(t => t.Id == command.SubjectVisitId)
.AnyAsync(t => t.SubmitState == SubmitStateEnum.Submitted && t.IsEnrollmentConfirm != command.IsEnrollmentConfirm))
{
return ResponseOutput.NotOk("CRC已提交了 不能修改入组确认状态");
}
if (await _subjectVisitRepository.Where(t => t.Id == command.SubjectVisitId)
.AnyAsync(t => t.IsEnrollmentConfirm != command.IsEnrollmentConfirm && t.RequestBackState == RequestBackStateEnum.PM_AgressBack))
{
return ResponseOutput.NotOk("回退的访视不允许修改PD确认状态");
}
await _repository.BatchUpdateAsync<SubjectVisit>(t => t.Id == command.SubjectVisitId, u => new SubjectVisit()
{
IsEnrollmentConfirm = command.IsEnrollmentConfirm.Value,
});
}
if (command.SubjectFirstGiveMedicineTime != null)
{
List<DataInspection> datas = new List<DataInspection>();
var data = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == command.SubjectVisitId);
await _repository.BatchUpdateAsync<Subject>(t => t.Id == command.SubjectId, u => new Subject()
{
FirstGiveMedicineTime = command.SubjectFirstGiveMedicineTime,
});
if (data.IsBaseLine)
{
datas.Add(new DataInspection()
{
SubjectId = command.SubjectId,
SiteId = data.SiteId,
TrialId = data.TrialId,
IsSign = false,
Identification = "Edit|Subject|Info|Subject",
CreateTime = DateTime.Now.AddSeconds(1),
JsonDetail = JsonConvert.SerializeObject(new
{
FirstGiveMedicineTime = command.SubjectFirstGiveMedicineTime.Value.ToString("yyyy-MM-dd")
})
});
}
await _inspectionService.AddListInspectionRecordAsync(datas);
}
////受试者基线 入组确认 或者访视PD 进展 默认加急
//await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.Id == command.SubjectVisitId, u => new SubjectVisit()
//{
// PDState = command.PDState,
// IsUrgent = (command.IsEnrollmentConfirm == true) || (command.PDState == PDStateEnum.PDProgress)
//});
return ResponseOutput.Ok();
}
/// <summary>
/// 验证QC是否可以操作 数据库查询判断当前QC执行人和登陆的用户是否一致
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
private async Task<IResponseOutput> VerifyQCCanOpt(Guid subjectVisitId)
{
var optUser = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).FirstOrDefaultAsync();
if (optUser == null) return Null404NotFound(optUser);
if (optUser.CurrentActionUserId != _userInfo.Id)
{
return ResponseOutput.NotOk("其他QC正在进行审核当前操作不允许");
}
return ResponseOutput.Ok();
}
[HttpPost("{trialId:guid}")]
public async Task<IResponseOutput> ForwardSVDicomImage(Guid[] subjectVisitIdList)
{
foreach (var subjectVisitId in subjectVisitIdList)
{
var info = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo<DicomTrialSiteSubjectInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
var targetPath = "/IMPORT-IMAGES/" + info.TrialCode + "_" + info.SubjectCode + "_" + info.VisitName;
var path = _dicomFileStoreHelper.GetSubjectVisitPath(info.TrialId, info.SiteId, info.SubjectId, info.SubjectVisitId);
try
{
// 主机及端口信息后面可以改到 配置文件
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
PortNumber = 8022,
HostName = "CS-690-sftp.mint-imaging.com",
UserName = "zdong",
Password = "Everest@2021",
SshHostKeyFingerprint = @"ecdsa-sha2-nistp384 384 59gkjJ5lMwv3jsB8Wz2B35tBAIor5pSd8PcJYtoamPo="
};
using (Session session = new Session())
{
var studyFolders = (new DirectoryInfo(path)).GetDirectories();
session.Open(sessionOptions);
if (!session.FileExists(targetPath))
{
session.CreateDirectory(targetPath);
}
foreach (var studyFolder in studyFolders)
{
if (!session.FileExists(Path.Combine(targetPath, studyFolder.Name)))
{
session.CreateDirectory(targetPath);
}
foreach (var file in studyFolder.GetFiles())
{
if (file.Extension.Contains("dcm", StringComparison.OrdinalIgnoreCase))
{
string remoteFilePath =
RemotePath.TranslateLocalPathToRemote(file.FullName, studyFolder.FullName, targetPath);
var result = session.PutFiles(file.FullName, remoteFilePath, false);
if (!result.IsSuccess)
{
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId,
u => new SubjectVisit() { ForwardState = ForwardStateEnum.ForwardFailed });
return ResponseOutput.NotOk("Forward Failed" + result.Failures.ToString() + result.ToJson());
}
}
}
}
}
}
catch (Exception e)
{
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId,
u => new SubjectVisit() { ForwardState = ForwardStateEnum.ForwardFailed });
}
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId,
u => new SubjectVisit() { ForwardState = ForwardStateEnum.Forwarded,ForwardUserId = _userInfo.Id,ForwardTime = DateTime.Now});
}
return ResponseOutput.Ok();
}
}
}