using AutoMapper;
using DocumentFormat.OpenXml.Drawing;
using EasyCaching.Core;
using ExcelDataReader;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using IRaCIS.Core.Application.MediatR.Handlers;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.Service.ImageAndDoc;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Magicodes.ExporterAndImporter.Excel;
using MassTransit;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using MiniExcelLibs;
using Newtonsoft.Json;
using SharpCompress.Archives;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Path = System.IO.Path;
namespace IRaCIS.Core.API.Controllers
{
#region 上传基类封装
[DisableFormValueModelBinding]
public abstract class UploadBaseController : ControllerBase
{
/// 流式上传 直接返回
[Route("base")]
public virtual async Task SingleFileUploadAsync(Func filePathFunc)
{
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)
{
var (serverFilePath, relativePath) = filePathFunc(contentDisposition.FileName.Value);
await FileStoreHelper.WriteFileAsync(section.Body, serverFilePath);
//仅仅返回一个文件,如果多文件上传 在最后返回多个路径
return ResponseOutput.Ok(new
{
FilePath = relativePath,
FullFilePath = relativePath /*+ "?access_token=" + _userInfo.UserToken*/
});
}
section = await reader.ReadNextSectionAsync();
}
return ResponseOutput.Ok();
}
/// 流式上传 通用封装 不返回任何数据,后续还有事情处理
[Route("base")]
public virtual async Task FileUploadAsync(Func> filePathFunc)
{
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)
{
var fileName = contentDisposition.FileName.Value;
//处理压缩文件
if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
{
var archive = ArchiveFactory.Open(section.Body);
foreach (var entry in archive.Entries)
{
if (!entry.IsDirectory)
{
var serverFilePath = await filePathFunc(entry.Key);
entry.WriteToFile(serverFilePath);
}
}
}
//普通单个文件
else
{
var serverFilePath = await filePathFunc(fileName);
await FileStoreHelper.WriteFileAsync(section.Body, serverFilePath);
}
}
section = await reader.ReadNextSectionAsync();
}
}
/// 流式上传 Dicom上传
[Route("base")]
public virtual async Task DicomFileUploadAsync(Func filePathFunc, string boundary)
{
var fileCount = 0;
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)
{
var fileName = contentDisposition.FileName.Value ?? String.Empty;
string mediaType = section.ContentType ?? String.Empty;
//处理压缩文件
if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
{
var archive = ArchiveFactory.Open(section.Body);
foreach (var entry in archive.Entries)
{
if (!entry.IsDirectory)
{
++fileCount;
await filePathFunc(entry.Key, entry.OpenEntryStream(), fileCount);
}
}
}
//普通单个文件
else
{
if (mediaType.Contains("octet-stream") || mediaType.Contains("dicom"))
{
++fileCount;
await filePathFunc(fileName, section.Body, fileCount);
}
}
}
section = await reader.ReadNextSectionAsync();
}
}
}
#endregion
#region Dicom 影像上传 临床数据 非diocm
[ApiExplorerSettings(GroupName = "Image")]
[ApiController]
public class StudyController : UploadBaseController
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IMediator _mediator;
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IRepository _repository;
private readonly IEasyCachingProvider _provider;
public StudyController(IMapper mapper, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IMediator mediator, IEasyCachingProvider provider,
IRepository repository)
{
_provider = provider;
_hostEnvironment = hostEnvironment;
_mediator = mediator;
_mapper = mapper;
_userInfo = userInfo;
_repository = repository;
}
[HttpPost, Route("Study/PreArchiveStudy")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task PreArchiveStudy(PreArchiveStudyCommand preArchiveStudyCommand,
[FromServices] IStudyService _studyService,
[FromServices] IRepository _studyMonitorRepository)
{
if (_provider.Get>(StaticData.Anonymize.Anonymize_AddFixedFiled).Value == null)
{
await _mediator.Send(new AnonymizeCacheRequest());
}
var savedInfo = _studyService.GetSaveToDicomInfo(preArchiveStudyCommand.SubjectVisitId);
var studyMonitor = new StudyMonitor()
{
TrialId = savedInfo.TrialId,
SiteId = savedInfo.SiteId,
SubjectId = savedInfo.SubjectId,
SubjectVisitId = savedInfo.SubjectVisitId,
IsSuccess = false,
UploadStartTime = DateTime.Now,
IsDicom = preArchiveStudyCommand.IsDicom,
IP = _userInfo.IP
};
var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
return ResponseOutput.Ok(addEntity.Id);
}
/// Dicom 归档
[HttpPost, Route("Study/ArchiveStudy")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task ArchiveStudyNew(/*[FromForm] ArchiveStudyCommand archiveStudyCommand,*/ Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId,Guid studyMonitorId,
[FromServices] ILogger _logger,
[FromServices] IEasyCachingProvider _provider,
[FromServices] IStudyService _studyService,
[FromServices] IHubContext _uploadHub,
[FromServices] IDicomArchiveService _dicomArchiveService,
[FromServices] IRepository _studyMonitorRepository
)
{
if (!HttpContext.Request.HasFormContentType ||
!MediaTypeHeaderValue.TryParse(HttpContext.Request.ContentType, out var mediaTypeHeader) ||
string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
{
return ResponseOutput.NotOk("不支持的MediaType");
}
var archiveStudyCommand = new ArchiveStudyCommand() { AbandonStudyId = abandonStudyId, StudyInstanceUid = studyInstanceUid, SubjectVisitId = subjectVisitId };
string studycode = string.Empty;
var startTime = DateTime.Now;
if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}"))
{
return ResponseOutput.NotOk("当前已有人正在上传和归档该检查!");
}
else
{
_provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
}
//到了接口,代表上传结束了
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);
studyMonitor.UploadFinishedTime = DateTime.Now;
var (archiveResult, archivedStudyIds) = (new DicomArchiveResult(), new List());
var (seriesInstanceUidList, sopInstanceUidList) = (new List(), new List());
//重传的时候,找出当前检查已经上传的series instance
if (archiveStudyCommand.AbandonStudyId != null)
{
(seriesInstanceUidList, sopInstanceUidList) = _studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value);
}
var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId);
try
{
await DicomFileUploadAsync(async (fileName, fileStream, receivedCount) =>
{
try
{
using (var memoryStream = new MemoryStream())
{
await fileStream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var (studyId, studyCode) = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList);
if (!archivedStudyIds.Contains(studyId))
{
archivedStudyIds.Add(studyId);
archiveResult.ArchivedDicomStudies.Add(new DicomStudyBasicDTO() { StudyCode = studyCode, Id = studyId });
}
}
//await _uploadHub.Clients.All.ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);
await _uploadHub.Clients.User(_userInfo.Id.ToString()).ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);
archiveResult.ReceivedFileCount = receivedCount;
}
catch (Exception e)
{
_logger.LogError(e.Message + e.StackTrace);
archiveResult.ErrorFiles.Add(fileName);
}
}, mediaTypeHeader.Boundary.Value);
}
catch (Exception ex)
{
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
throw new BusinessValidationFailedException("请求异常,请重试!");
}
studyMonitor.FileSize = (decimal)HttpContext.Request.ContentLength;
studyMonitor.FileCount = archiveResult.ReceivedFileCount;
studyMonitor.FailedFileCount = archiveResult.ErrorFiles.Count;
studyMonitor.IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null;
studyMonitor.Note = JsonConvert.SerializeObject(archiveResult);
try
{
if (archivedStudyIds.Count > 0) // 上传成功,处理逻辑
{
// 同一个检查批次 多个线程上传处理 批量保存 可能造成死锁 https://www.cnblogs.com/johnblogs/p/9945767.html
await _dicomArchiveService.DicomDBDataSaveChange();
archiveResult.ReuploadNewStudyId = archivedStudyIds[0] == archiveStudyCommand.AbandonStudyId ? archivedStudyIds[0] : Guid.Empty;
studyMonitor.IsSuccess = true;
}
}
catch (Exception e)
{
studyMonitor.Note = JsonConvert.SerializeObject(new { Message = e.Message, Result = archiveResult });
_logger.LogError(e.Message + e.StackTrace);
}
finally
{
_provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");
studyMonitor.StudyId = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.Id ?? Guid.Empty;
studyMonitor.StudyCode = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.StudyCode;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
await _studyMonitorRepository.SaveChangesAsync();
}
return ResponseOutput.Result(studyMonitor.IsSuccess, archiveResult);
}
///
/// 上传临床数据 多文件
///
///
///
[HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}")]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task UploadVisitClinicalData(Guid subjectVisitId)
{
await QCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
var sv = _repository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefault().IfNullThrowException();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalDataPath(_hostEnvironment, fileName, sv.TrialId, sv.SiteId, sv.SubjectId, subjectVisitId);
//插入临床pdf 路径
await _repository.AddAsync(new PreviousPDF()
{
SubjectVisitId = subjectVisitId,
IsVisist = true,
DataType = ClinicalDataType.MedicalHistory,
UploadType = ClinicalUploadType.PDF,
SubjectId = sv.SubjectId,
TrialId = sv.TrialId,
ClinicalLevel = ClinicalLevel.Subject,
Path = relativePath,
FileName = fileRealName
});
return serverFilePath;
});
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
///
/// 上传临床数据模板
///
///
///
[HttpPost("ClinicalData/UploadClinicalTemplate")]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })]
public async Task>> UploadClinicalTemplate(Guid? trialId)
{
if (trialId == null)
trialId = default(Guid);
var filerelativePath = string.Empty;
List fileDtos = new List();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalTemplatePath(_hostEnvironment, fileName, trialId.Value);
//插入临床pdf 路径
filerelativePath = relativePath;
fileDtos.Add(new FileDto()
{
FileName = fileName,
Path = relativePath
});
await Task.CompletedTask;
return serverFilePath;
});
return ResponseOutput.Ok(fileDtos);
}
///
/// 上传阅片临床数据
///
///
///
///
///
[HttpPost("ClinicalData/UploadClinicalData/{trialId:guid}/{subjectId:guid}/{readingId:guid}")]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task>> UploadReadClinicalData(Guid trialId, Guid subjectId, Guid readingId)
{
var filerelativePath = string.Empty;
List fileDtos = new List();
var siteid = await _repository.Where(x => x.Id == subjectId).Select(x => x.SiteId).FirstOrDefaultAsync();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetReadClinicalDataPath(_hostEnvironment, fileName, trialId, siteid, subjectId, readingId);
//插入临床pdf 路径
filerelativePath = relativePath;
fileDtos.Add(new FileDto()
{
FileName = fileName,
Path = relativePath
});
await Task.CompletedTask;
return serverFilePath;
});
return ResponseOutput.Ok(fileDtos);
}
///
/// 上传截图
///
///
///
[HttpPost("Printscreen/UploadPrintscreen/{subjectId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task> UploadPrintscreen(Guid subjectId)
{
var subjectInfo = await this._repository.Where(x => x.Id == subjectId).FirstNotNullAsync();
FileDto fileDto = new FileDto();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetUploadPrintscreenFilePath(_hostEnvironment, fileName, subjectInfo.TrialId, subjectInfo.SiteId, subjectInfo.Id);
fileDto.Path = relativePath;
fileDto.FileName = fileName;
await Task.CompletedTask;
return serverFilePath;
});
return ResponseOutput.Ok(fileDto);
}
///
/// 上传Reading问题的图像
///
///
///
///
[HttpPost("VisitTask/UploadReadingAnswerImage/{trialId:guid}/{visitTaskId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task> UploadReadingAnswerImage(Guid trialId, Guid visitTaskId)
{
FileDto fileDto = new FileDto();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
fileDto.Path = relativePath;
fileDto.FileName = fileName;
await Task.CompletedTask;
return serverFilePath;
});
return ResponseOutput.Ok(fileDto);
}
///
/// 上传裁判任务的图像
///
///
///
///
[HttpPost("VisitTask/UploadJudgeTaskImage/{trialId:guid}/{visitTaskId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task> UploadJudgeTaskImage(Guid trialId, Guid visitTaskId)
{
FileDto fileDto = new FileDto();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
fileDto.Path = relativePath;
fileDto.FileName = fileName;
await Task.CompletedTask;
return serverFilePath;
});
return ResponseOutput.Ok(fileDto);
}
///
/// 上传医学审核图片
///
///
///
///
[HttpPost("TaskMedicalReview/UploadMedicalReviewImage/{trialId:guid}/{taskMedicalReviewId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task> UploadMedicalReviewImage(Guid trialId, Guid taskMedicalReviewId)
{
string path = string.Empty;
FileDto fileDto = new FileDto();
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetMedicalReviewImage(_hostEnvironment, fileName, trialId, taskMedicalReviewId);
//await _repository.UpdatePartialFromQueryAsync(x => x.Id == taskMedicalReviewId, x => new TaskMedicalReview()
//{
// ImagePath = relativePath,
// FileName = fileName,
//});
path = relativePath;
fileDto.Path = relativePath;
fileDto.FileName = fileName;
return serverFilePath;
});
await _repository.SaveChangesAsync();
return ResponseOutput.Ok(fileDto);
}
///
/// 上传非Dicom 文件 支持压缩包 多文件上传
///
///
///
///
///
///
///
//[DisableRequestSizeLimit]
[RequestSizeLimit(1_073_741_824)]
[HttpPost("NoneDicomStudy/UploadNoneDicomFile/{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyId:guid}/{studyMonitorId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task UploadNoneDicomFile(IFormCollection formCollection, Guid subjectVisitId, Guid noneDicomStudyId, Guid studyMonitorId,
[FromServices] IRepository _noneDicomStudyRepository, [FromServices] IRepository _studyMonitorRepository)
{
await QCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
var sv = (await _repository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefaultAsync()).IfNullThrowConvertException();
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);
studyMonitor.UploadFinishedTime = DateTime.Now;
await FileUploadAsync(async (fileName) =>
{
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetNoneDicomFilePath(_hostEnvironment, fileName, sv.TrialId, sv.SiteId, sv.SubjectId, subjectVisitId);
await _repository.AddAsync(new NoneDicomStudyFile() { FileName = fileRealName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });
return serverFilePath;
});
var uploadFinishedTime = DateTime.Now;
//// 上传非Dicom 后 将状态改为待提交 分为普通上传 和QC后重传 普通上传时才改为待提交
//await _repository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.None, u => new SubjectVisit() { SubmitState = SubmitStateEnum.ToSubmit });
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
noneDicomStudy.FileCount = noneDicomStudy.FileCount + formCollection.Files.Count;
studyMonitor.FileCount = formCollection.Files.Count;
studyMonitor.FileSize = formCollection.Files.Sum(t => t.Length);
studyMonitor.IsDicom = false;
studyMonitor.IsDicomReUpload = false;
studyMonitor.StudyId = noneDicomStudyId;
studyMonitor.StudyCode = noneDicomStudy.StudyCode;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
studyMonitor.IP = _userInfo.IP;
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
}
///
/// 一致性核查 excel上传 支持三种格式
///
///
///
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
[Authorize(Policy = IRaCISPolicy.PM_APM)]
public async Task UploadVisitCheckExcel(Guid trialId)
{
var (serverFilePath, relativePath, fileName) = (string.Empty, string.Empty, string.Empty);
await FileUploadAsync(async (realFileName) =>
{
fileName = realFileName;
if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
{
throw new BusinessValidationFailedException("支持.xlsx、.xls、.csv格式的文件上传。");
}
(serverFilePath, relativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, fileName, trialId);
await _repository.AddAsync(new ConsistencyCheckFile()
{
TrialId = trialId,
CreateTime = DateTime.Now,
FileName = fileName,
FilePath = relativePath,
RelativePath = relativePath,
CreateUserId = _userInfo.Id
});
return serverFilePath;
});
var etcCheckList = new List();
#region MiniExcel 需要自己验证数据格式规范
//if (fileName.EndsWith(".csv"))
//{
// //因为csv 需要加配置文件 不然都是null
// etcCheckList = MiniExcel.Query(filePath, null, configuration: config).ToList();
//}
//else if (fileName.EndsWith(".xlsx"))
//{
//
// etcCheckList = MiniExcel.Query(filePath).ToList();
//}
#endregion
//Magicodes 支持自定义特性验证
if (fileName.EndsWith(".xlsx"))
{
var Importer = new ExcelImporter();
var import = await Importer.Import(System.IO.File.OpenRead(serverFilePath));
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(serverFilePath, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
}).ToList();
var (csVToXlsxPath, csVToXlsxRelativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, Path.GetFileNameWithoutExtension(fileName) + ".xlsx", trialId);
await MiniExcel.SaveAsAsync(csVToXlsxPath, etcCheckList, excelType: ExcelType.XLSX);
var Importer = new ExcelImporter();
var import = await Importer.Import(System.IO.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(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(serverFilePath, 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
}
}
}
if (etcCheckList == null || etcCheckList.Count == 0)
{
return ResponseOutput.NotOk("请保证上传数据符合模板文件中的样式,且存在有效数据。");
}
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("请保证上传数据符合模板文件中的样式,且存在有效数据。");
}
}
await _mediator.Send(new ConsistencyVerificationRequest() { ETCList = etcCheckList, TrialId = trialId });
return ResponseOutput.Ok();
}
}
#endregion
#region 医生文件上传下载
/// 医生文件上传下载
[ApiExplorerSettings(GroupName = "Common")]
[ApiController]
public class FileController : UploadBaseController
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IFileService _fileService;
public FileController(IMapper mapper, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IFileService fileService)
{
_fileService = fileService;
_hostEnvironment = hostEnvironment;
_mapper = mapper;
_userInfo = userInfo;
}
///
/// 上传文件[FileUpload]
///
/// 附件类型
/// 医生Id
/// 返回文件信息
[HttpPost, Route("file/UploadFile/{attachmentType}/{doctorId}")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
public async Task UploadOrdinaryFile(string attachmentType, Guid doctorId)
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetDoctorOrdinaryFilePath(_hostEnvironment, fileName, doctorId, attachmentType));
}
///
/// 上传文件( 不是医生个人的文件)[FileUpload]
/// 例如:阅片章程等
///
/// 文件类型
///
[HttpPost, Route("file/UploadNonDoctorFile/{type}")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
public async Task UploadNonDoctorFile(string type)
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetNonDoctorFilePath(_hostEnvironment, fileName, type));
}
///
/// 下载多个医生的所有附件
///
///
///
[HttpPost, Route("file/downloadDoctorAttachments")]
public async Task> DownloadAttachment(Guid[] doctorIds)
{
var path = await _fileService.CreateDoctorsAllAttachmentZip(doctorIds);
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = path,
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
});
}
///
/// 下载医生官方简历
///
///
///
///
[HttpPost, Route("file/downloadOfficialCV/{language}")]
public async Task> DownloadOfficialResume(int language, Guid[] doctorIds)
{
var path = await _fileService.CreateDoctorsAllAttachmentZip(doctorIds);
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = await _fileService.CreateOfficialResumeZip(language, doctorIds),
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
});
}
///
/// 下载指定医生的指定附件
///
/// 医生Id
/// 要下载的附件Id
///
[HttpPost, Route("file/downloadByAttachmentId/{doctorId}")]
public async Task> DownloadAttachmentById(Guid doctorId, Guid[] attachmentIds)
{
var path = await _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds);
return ResponseOutput.Ok(new UploadFileInfoDTO
{
FilePath = await _fileService.CreateZipPackageByAttachment(doctorId, attachmentIds),
FullFilePath = path + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7)
});
}
[HttpPost, Route("enroll/downloadResume/{trialId:guid}/{language}")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
[AllowAnonymous]
public async Task> DownloadResume(int language, Guid trialId, Guid[] doctorIdArray)
{
var zipPath = await _fileService.CreateOfficialResumeZip(language, doctorIdArray);
return ResponseOutput.Ok(zipPath);
}
}
#endregion
#region 项目 系统 基本文件 上传 下载 预览
[ApiExplorerSettings(GroupName = "Common")]
[ApiController]
public class UploadDownLoadController : UploadBaseController
{
public IMapper _mapper { get; set; }
public IUserInfo _userInfo { get; set; }
private readonly IMediator _mediator;
private readonly IWebHostEnvironment _hostEnvironment;
public UploadDownLoadController(IMapper mapper, IUserInfo userInfo, IMediator mediator, IWebHostEnvironment hostEnvironment)
{
_hostEnvironment = hostEnvironment;
_mediator = mediator;
_mapper = mapper;
_userInfo = userInfo;
}
/// 缩略图
[AllowAnonymous]
[HttpGet("Common/LocalFilePreview")]
public async Task LocalFilePreview(string relativePath)
{
var _fileStorePath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, relativePath);
var storePreviewPath = _fileStorePath + ".preview.jpeg";
if (!System.IO.File.Exists(storePreviewPath))
{
ImageHelper.ResizeSave(_fileStorePath, storePreviewPath);
}
return new FileContentResult(await System.IO.File.ReadAllBytesAsync(storePreviewPath), "image/jpeg");
}
/// 通用文件下载
[AllowAnonymous]
[HttpGet("CommonDocument/DownloadCommonDoc")]
public async Task DownloadCommonFile(string code, [FromServices] IRepository _commonDocumentRepository)
{
var (filePath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);
return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);
}
///
/// 下载项目临床数据文件
///
///
///
///
[AllowAnonymous]
[HttpGet("CommonDocument/DownloadTrialClinicalFile")]
public async Task DownloadTrialClinicalFile(Guid clinicalDataTrialSetId, [FromServices] IRepository _clinicalDataTrialSetRepository)
{
var (filePath, fileName) = await FileStoreHelper.GetTrialClinicalPathAsync(_hostEnvironment, _clinicalDataTrialSetRepository, clinicalDataTrialSetId);
new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);
return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);
}
///
/// 下载系统临床数据文件
///
///
///
///
[AllowAnonymous]
[HttpGet("CommonDocument/DownloadSystemClinicalFile")]
public async Task DownloadSystemClinicalFile(Guid clinicalDataSystemSetId, [FromServices] IRepository _clinicalDataSystemSetRepository)
{
var (filePath, fileName) = await FileStoreHelper.GetSystemClinicalPathAsync(_hostEnvironment, _clinicalDataSystemSetRepository, clinicalDataSystemSetId);
new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);
return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);
}
///
///上传项目签名文档
///
///
///
[HttpPost("TrialDocument/UploadTrialDoc/{trialId:guid}")]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task UploadTrialDoc(Guid trialId)
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetTrialSignDocPath(_hostEnvironment, trialId, fileName));
}
///
/// 上传系统签名文档
///
///
[HttpPost("TrialDocument/UploadSystemDoc")]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task UploadSysTemDoc()
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemSignDocPath(_hostEnvironment, fileName));
}
///
/// 上传通用文档 比如一致性核查的 比如导出的excel 模板
///
///
[HttpPost("CommonDocument/UploadCommonDoc")]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task UploadCommonDoc()
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetCommonDocPath(_hostEnvironment, fileName));
}
///
/// 上传系统通知文档
///
///
[HttpPost("SystemNotice/UploadSystemNoticeDoc")]
[DisableRequestSizeLimit]
[DisableFormValueModelBinding]
public async Task UploadSystemNoticeDoc()
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemNoticePath(_hostEnvironment, fileName));
}
}
#endregion
}