diff --git a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs index a1dd8d861..35ffd637d 100644 --- a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs +++ b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs @@ -24,6 +24,7 @@ using Magicodes.ExporterAndImporter.Excel; using MassTransit; using MediatR; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -37,6 +38,7 @@ using Microsoft.Net.Http.Headers; using MiniExcelLibs; using Newtonsoft.Json; using SharpCompress.Archives; +using SkiaSharp; using System; using System.Collections.Generic; using System.Data; @@ -133,6 +135,32 @@ namespace IRaCIS.Core.API.Controllers } } + [Route("base")] + public virtual async Task FileUploadToOSSAsync(Func> toMemoryStreamFunc) + { + 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; + + await toMemoryStreamFunc(fileName, section.Body); + + } + + section = await reader.ReadNextSectionAsync(); + + } + + } + /// 流式上传 Dicom上传 @@ -280,9 +308,6 @@ namespace IRaCIS.Core.API.Controllers - - - if (!HttpContext.Request.HasFormContentType || !MediaTypeHeaderValue.TryParse(HttpContext.Request.ContentType, out var mediaTypeHeader) || string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value)) @@ -518,11 +543,13 @@ namespace IRaCIS.Core.API.Controllers [HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] //[Authorize(Policy = IRaCISPolicy.PM_APM)] - public async Task UploadVisitCheckExcel(Guid trialId) + public async Task UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService) { - var (serverFilePath, relativePath, fileName) = (string.Empty, string.Empty, string.Empty); - await FileUploadAsync(async (realFileName) => + var fileName = string.Empty; + var templateFileStream = new MemoryStream(); + + await FileUploadToOSSAsync(async (realFileName, fileStream) => { fileName = realFileName; @@ -532,19 +559,16 @@ namespace IRaCIS.Core.API.Controllers throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_SupportedFormats")); } - (serverFilePath, relativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, fileName, trialId); + fileStream.CopyTo(templateFileStream); + templateFileStream.Seek(0, SeekOrigin.Begin); - await _repository.AddAsync(new ConsistencyCheckFile() - { - TrialId = trialId, - CreateTime = DateTime.Now, - FileName = fileName, - FilePath = relativePath, - RelativePath = relativePath, - CreateUserId = _userInfo.Id - }); - return serverFilePath; + var ossRelativePath = oSSService.UploadToOSS(fileStream, "InspectionUpload/SiteSurvey", realFileName); + + await _repository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }); + + return ossRelativePath; + }); @@ -576,7 +600,7 @@ namespace IRaCIS.Core.API.Controllers { var Importer = new ExcelImporter(); - var import = await Importer.Import(System.IO.File.OpenRead(serverFilePath)); + var import = await Importer.Import(templateFileStream); if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString()); @@ -591,7 +615,7 @@ namespace IRaCIS.Core.API.Controllers #region 临时方案 MiniExcel读取 然后保存为xlsx 再用 Magicodes验证数据 //因为csv 需要加配置文件 不然都是null - etcCheckList = MiniExcel.Query(serverFilePath, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration() + etcCheckList = MiniExcel.Query(templateFileStream, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration() { StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312")) }).ToList(); @@ -636,35 +660,35 @@ namespace IRaCIS.Core.API.Controllers else { //为了支持 xls 引入新的组件库 - using (var stream = System.IO.File.Open(serverFilePath, FileMode.Open, FileAccess.Read)) + //using (var stream = System.IO.File.Open(templateFileStream, 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(templateFileStream)) { - // 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) { - // 2. Use the AsDataSet extension method - var dateset = reader.AsDataSet(); - - foreach (DataRow col in dateset.Tables[0].Rows) + etcCheckList.Add(new CheckViewModel() { - - 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 + 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) @@ -772,7 +796,7 @@ namespace IRaCIS.Core.API.Controllers [FromServices] IRepository _attachmentrepository) { - var list = await _attachmentrepository.Where(t => command.DoctorIdList.Contains(t.DoctorId) && command.Language==t.Language).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId }) + var list = await _attachmentrepository.Where(t => command.DoctorIdList.Contains(t.DoctorId) && command.Language == t.Language).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId }) .Select(g => new DoctorDownloadInfo() { Id = g.Key.DoctorId, @@ -792,7 +816,7 @@ namespace IRaCIS.Core.API.Controllers /// /// /// - [HttpPost,Route("file/GetTrialDoctorOfficialResume")] + [HttpPost, Route("file/GetTrialDoctorOfficialResume")] public async Task>> GetTrialDoctorOfficialResume(GetDoctorPathCommand command, [FromServices] IDoctorService _doctorService, [FromServices] IRepository _attachmentrepository) @@ -824,7 +848,7 @@ namespace IRaCIS.Core.API.Controllers [FromServices] IRepository _attachmentrepository) { - var find = await _attachmentrepository.Where(t => command.DoctorId==t.DoctorId && command.AttachmentIdList.Contains(t.Id)).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId }) + var find = await _attachmentrepository.Where(t => command.DoctorId == t.DoctorId && command.AttachmentIdList.Contains(t.Id)).GroupBy(t => new { Name = t.Doctor.FirstName + "_" + t.Doctor.LastName, ReviewerCode = t.Doctor.ReviewerCode, t.DoctorId }) .Select(g => new DoctorDownloadInfo() { Id = g.Key.DoctorId, @@ -952,28 +976,36 @@ namespace IRaCIS.Core.API.Controllers public async Task UploadTrialSiteSurveyUser(Guid trialId, string baseUrl, string routeUrl, [FromServices] IRepository _trialSiteRepository, [FromServices] IRepository _usertypeRepository, - [FromServices] ITrialSiteSurveyService _trialSiteSurveyService) + [FromServices] ITrialSiteSurveyService _trialSiteSurveyService, + [FromServices] IOSSService oSSService, + [FromServices] IRepository _inspectionFileRepository) { - var (serverFilePath, relativePath, fileName) = (string.Empty, string.Empty, string.Empty); - await FileUploadAsync(async (realFileName) => - { - fileName = realFileName; + var templateFileStream = new MemoryStream(); - if (!fileName.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase)) + + await FileUploadToOSSAsync(async (realFileName, fileStream) => + { + await fileStream.CopyToAsync(templateFileStream); + templateFileStream.Seek(0, SeekOrigin.Begin); + + if (!realFileName.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase)) { // 请用提供格式的模板excel上传需要处理的数据 throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_TemplateUploadData")); } - (serverFilePath, relativePath) = FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName); + var ossRelativePath = oSSService.UploadToOSS(fileStream, "InspectionUpload/SiteSurvey", realFileName); - //FileStoreHelper.UploadOOS(serverFilePath, "testc/test", true); + await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }); + + + + return ossRelativePath; - return serverFilePath; }); //去掉空白行 - var excelList = MiniExcel.Query(serverFilePath).ToList() + var excelList = MiniExcel.Query(templateFileStream,excelType:ExcelType.XLSX).ToList() .Where(t => !(string.IsNullOrWhiteSpace(t.TrialSiteCode) && string.IsNullOrWhiteSpace(t.FirstName) && string.IsNullOrWhiteSpace(t.LastName) && string.IsNullOrWhiteSpace(t.Email) && string.IsNullOrWhiteSpace(t.Phone) && string.IsNullOrWhiteSpace(t.UserTypeStr) && string.IsNullOrWhiteSpace(t.OrganizationName))).ToList(); @@ -1003,7 +1035,7 @@ namespace IRaCIS.Core.API.Controllers //有邮箱不符合邮箱格式,请核查Excel数据 throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidEmail")); } - var generateUserTypeList = new List() { "CRC", "CRA" }; + var generateUserTypeList = new List() { "CRC", "CRA" }; if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper()))) { @@ -1015,7 +1047,7 @@ namespace IRaCIS.Core.API.Controllers throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_NoValiddata")); } //处理好 用户类型 和用户类型枚举 - var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator ).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList(); + var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList(); var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, t.SiteId }).ToList(); foreach (var item in excelList) @@ -1033,7 +1065,7 @@ namespace IRaCIS.Core.API.Controllers item.UserTypeEnum = UserTypeEnum.CRA; break; - + } diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.xml b/IRaCIS.Core.API/IRaCIS.Core.API.xml index 23a29e1ea..82de82eb7 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.xml +++ b/IRaCIS.Core.API/IRaCIS.Core.API.xml @@ -275,7 +275,7 @@ - + 一致性核查 excel上传 支持三种格式 diff --git a/IRaCIS.Core.Application/Helper/OSSService.cs b/IRaCIS.Core.Application/Helper/OSSService.cs index b4c5b5286..dab2bb588 100644 --- a/IRaCIS.Core.Application/Helper/OSSService.cs +++ b/IRaCIS.Core.Application/Helper/OSSService.cs @@ -1,4 +1,5 @@ using Aliyun.OSS; +using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Infrastructure; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; @@ -7,6 +8,7 @@ using SharpCompress.Common; using System; using System.Collections.Generic; using System.Drawing; +using System.IO; using System.Linq; using System.Security.AccessControl; using System.Text; @@ -85,9 +87,13 @@ namespace IRaCIS.Core.Application.Helper public interface IOSSService { + public string UploadToOSS(Stream fileStream, string oosFolderPath, string fileRealName); + public string UploadToOSS(string localFilePath, string oosFolderPath); + + public void DownLoadFromOSS(string ossRelativePath, string localFilePath); + } - public class OSSService : IOSSService { @@ -107,6 +113,34 @@ namespace IRaCIS.Core.Application.Helper } + public string UploadToOSS(Stream fileStream, string oosFolderPath,string fileRealName) + { + + var ossRelativePath = oosFolderPath + "/" + fileRealName; + + try + { + using (var memoryStream = new MemoryStream()) + { + fileStream.Seek(0, SeekOrigin.Begin); + + fileStream.CopyTo(memoryStream); + + memoryStream.Seek(0, SeekOrigin.Begin); + + // 上传文件 + var result = _ossClient.PutObject(_OSSConfig.BucketName, ossRelativePath, memoryStream); + } + + + return ossRelativePath; + } + catch (Exception ex) + { + throw new BusinessValidationFailedException("oss上传失败" + ex.Message); + + } + } public string UploadToOSS(string localFilePath, string oosFolderPath) { diff --git a/IRaCIS.Core.Application/Service/QC/QCListService.cs b/IRaCIS.Core.Application/Service/QC/QCListService.cs index 9a3e508dc..3f4ff47a3 100644 --- a/IRaCIS.Core.Application/Service/QC/QCListService.cs +++ b/IRaCIS.Core.Application/Service/QC/QCListService.cs @@ -19,7 +19,7 @@ namespace IRaCIS.Core.Application.Image.QA private readonly IRepository _clinicalDataTrialSet; private readonly IRepository _trialQCQuestionAnswerRepository; private readonly IRepository _trialQCQuestionRepository; - private readonly IRepository _consistencyCheckFileRepository; + private readonly IRepository _consistencyCheckFileRepository; private IReadingImageTaskService _IReadingImageTaskService; @@ -30,7 +30,7 @@ namespace IRaCIS.Core.Application.Image.QA IRepository trialQCQuestionAnswerRepository, IRepository trialQCQuestionRepository, IReadingImageTaskService IReadingImageTaskService, - IRepository consistencyCheckFileRepository + IRepository consistencyCheckFileRepository ) { this._IReadingImageTaskService = IReadingImageTaskService; @@ -851,7 +851,7 @@ namespace IRaCIS.Core.Application.Image.QA [HttpPost] public async Task> GetConsistencyCheckFile(GetConsistencyCheckFileInDto indto) { - var query = _repository.Where(t => t.TrialId == indto.TrialId) + var query = _repository.Where(t => t.TrialId == indto.TrialId) .ProjectTo(_mapper.ConfigurationProvider); return await query.ToPagedListAsync(indto.PageIndex, indto.PageSize, "CreateTime", false); diff --git a/IRaCIS.Core.Application/Service/QC/_MapConfig.cs b/IRaCIS.Core.Application/Service/QC/_MapConfig.cs index 5a2f5022c..b53aa1700 100644 --- a/IRaCIS.Core.Application/Service/QC/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/QC/_MapConfig.cs @@ -494,7 +494,7 @@ namespace IRaCIS.Core.Application.Service ; // 一致性核查文件 - CreateMap() + CreateMap() .ForMember(d => d.CreateUserName, u => u.MapFrom(t => t.User.FirstName + "/" + t.User.LastName)); diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs index 22674f8ad..4e842c6ec 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs @@ -431,7 +431,7 @@ namespace IRaCIS.Application.Services await _repository.BatchDeleteAsync(o => o.SubjectVisit.TrialId == trialId); await _repository.BatchDeleteAsync(o => o.TrialId == trialId); - await _repository.BatchDeleteAsync(o => o.TrialId == trialId); + await _repository.BatchDeleteAsync(o => o.TrialId == trialId); await _repository.BatchDeleteAsync(o => o.TrialReadingCriterion.TrialId == trialId); await _repository.BatchDeleteAsync(o => o.TrialId == trialId); await _repository.BatchDeleteAsync(t => t.TrialId == trialId); diff --git a/IRaCIS.Core.Domain/QC/ConsistencyCheckFile.cs b/IRaCIS.Core.Domain/QC/ConsistencyCheckFile.cs index ac90904b7..efd54ed66 100644 --- a/IRaCIS.Core.Domain/QC/ConsistencyCheckFile.cs +++ b/IRaCIS.Core.Domain/QC/ConsistencyCheckFile.cs @@ -7,18 +7,15 @@ namespace IRaCIS.Core.Domain.Models /// /// 一致性核查文件 /// - [Table("ConsistencyCheckFile")] - public class ConsistencyCheckFile : Entity, IAuditAdd + [Table("InspectionFile")] + public class InspectionFile : Entity, IAuditAdd { /// /// 文件名称 /// public string FileName { get; set; } - /// - /// 文件路径 - /// - public string FilePath { get; set; } + /// /// 相对路径 diff --git a/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs b/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs index 6397217b6..f5767b2ad 100644 --- a/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs +++ b/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs @@ -1479,11 +1479,11 @@ namespace IRaCIS.Core.Infra.EFCore.Common // 一致性核查文件 是否需要单独一个表记录? - foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(ConsistencyCheckFile))) + foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(InspectionFile))) { var type = GetEntityAuditOpt(item); - await InsertInspection(item.Entity as ConsistencyCheckFile, type, x => new InspectionConvertDTO() + await InsertInspection(item.Entity as InspectionFile, type, x => new InspectionConvertDTO() { ObjectRelationParentId = x.TrialId diff --git a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs index c1e7eed83..ab463a705 100644 --- a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs +++ b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs @@ -495,7 +495,7 @@ namespace IRaCIS.Core.Infra.EFCore public virtual DbSet FrontAuditConfig { get; set; } - public virtual DbSet ConsistencyCheckFile { get; set; } + public virtual DbSet InspectionFile { get; set; } public virtual DbSet CommonDocument { get; set; }