添加项目文件。
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
//using AutoMapper;
|
||||
//using AutoMapper.QueryableExtensions;
|
||||
//using IRaCIS.Application.ViewModels;
|
||||
//using IRaCIS.Core.Application.Contracts;
|
||||
//using IRaCIS.Core.Application.Filter;
|
||||
//using IRaCIS.Core.Application.MediatR.CommandAndQueries;
|
||||
//using IRaCIS.Core.Domain.Models;
|
||||
//using IRaCIS.Core.Domain.Share;
|
||||
//using IRaCIS.Core.Infra.EFCore;
|
||||
//using IRaCIS.Core.Infrastructure.Extention;
|
||||
//using Magicodes.ExporterAndImporter.Core;
|
||||
//using Magicodes.ExporterAndImporter.Excel;
|
||||
//using MediatR;
|
||||
//using Microsoft.AspNetCore.Hosting;
|
||||
//using Microsoft.AspNetCore.Http;
|
||||
//using Microsoft.AspNetCore.Mvc;
|
||||
//using Microsoft.AspNetCore.WebUtilities;
|
||||
//using Microsoft.Net.Http.Headers;
|
||||
//using System;
|
||||
//using System.IO;
|
||||
//using System.Linq;
|
||||
//using System.Threading.Tasks;
|
||||
|
||||
//namespace IRaCIS.Core.API.Controllers
|
||||
//{
|
||||
// [ApiExplorerSettings(GroupName = "Image")]
|
||||
// [ApiController]
|
||||
// public class DownLoadController : ControllerBase
|
||||
// {
|
||||
// public IMapper _mapper { get; set; }
|
||||
// public IUserInfo _userInfo { get; set; }
|
||||
// private readonly IMediator _mediator;
|
||||
|
||||
// private readonly IWebHostEnvironment _hostEnvironment;
|
||||
|
||||
// private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
|
||||
// public DownLoadController(IMapper mapper, IUserInfo userInfo, IMediator mediator, IWebHostEnvironment hostEnvironment, IServiceProvider serviceProvider)
|
||||
// {
|
||||
// _serviceProvider = serviceProvider;
|
||||
// _hostEnvironment = hostEnvironment;
|
||||
// _mediator = mediator;
|
||||
// _mapper = mapper;
|
||||
// _userInfo = userInfo;
|
||||
// }
|
||||
|
||||
// [HttpGet("VisitPlan/DownloadInflunceStudyList{trialId:guid}/{createTime:dateTime}")]
|
||||
// public async Task<IActionResult> DownloadInflunceStudyList(Guid trialId, DateTime createTime, [FromServices] IRepository<VisitPlanInfluenceSubjectVisit> _influnceRepository)
|
||||
// {
|
||||
// var list = _influnceRepository.Where(t => t.TrialId == trialId && t.CreateTime == createTime)
|
||||
// .ProjectTo<VisitPlanInfluenceSubjectVisitDTO>(_mapper.ConfigurationProvider).ToList();
|
||||
|
||||
// if(list.Count == 0)
|
||||
// {
|
||||
// list.Add(new VisitPlanInfluenceSubjectVisitDTO() { CreateTime=DateTime.Now,SubjectCode="test",StudyTime=DateTime.Now,IsDicomStudy=false,HistoryWindow="test"});
|
||||
// }
|
||||
|
||||
// IExporter exporter = new ExcelExporter();
|
||||
|
||||
// var result = await exporter.ExportAsByteArray(list);
|
||||
|
||||
|
||||
// return new XlsxFileResult(bytes: bytes);
|
||||
|
||||
// //return File(result, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"检查导出_{DateTime.Now}.xlsx");
|
||||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,39 @@
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
|
||||
namespace EasyCaching.Demo.Interceptors.Controllers
|
||||
{
|
||||
|
||||
[NonDynamicWebApi]
|
||||
public class ErrorController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 主要处理 前端404等错误 全局业务异常已统一处理了,非业务错误会来到这里
|
||||
/// </summary>
|
||||
/// <param name="code"></param>
|
||||
/// <returns></returns>
|
||||
[Route("error/{code:int}")]
|
||||
[HttpGet]
|
||||
public IResponseOutput Error(int code)
|
||||
{
|
||||
|
||||
if (code < 500)
|
||||
{
|
||||
//LogDashboard 要求返回码必须是401不能覆盖,否则 认证有问题
|
||||
if (code == 401)
|
||||
{
|
||||
ControllerContext.HttpContext.Response.StatusCode = 401;
|
||||
}
|
||||
|
||||
return ResponseOutput.NotOk($"Client error, actual request error status code({code})");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
return ResponseOutput.NotOk($"Server error , actual request error status code({code})");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using EasyCaching.Core;
|
||||
using gRPC.ZHiZHUN.AuthServer.protos;
|
||||
using Grpc.Net.Client;
|
||||
using Grpc.Net.Client.Configuration;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Auth;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Application.Services;
|
||||
|
||||
namespace IRaCIS.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 医生基本信息 、工作信息 专业信息、审核状态
|
||||
/// </summary>
|
||||
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||
public class ExtraController : ControllerBase
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取医生详情
|
||||
/// </summary>
|
||||
/// <param name="attachmentService"></param>
|
||||
/// <param name="_doctorService"></param>
|
||||
/// <param name="_educationService"></param>
|
||||
/// <param name="_trialExperienceService"></param>
|
||||
/// <param name="_researchPublicationService"></param>
|
||||
/// <param name="_vacationService"></param>
|
||||
/// <param name="doctorId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, Route("doctor/getDetail/{doctorId:guid}")]
|
||||
|
||||
public async Task<IResponseOutput<DoctorDetailDTO>> GetDoctorDetail([FromServices] IAttachmentService attachmentService, [FromServices] IDoctorService _doctorService,
|
||||
[FromServices] IEducationService _educationService, [FromServices] ITrialExperienceService _trialExperienceService,
|
||||
[FromServices] IResearchPublicationService _researchPublicationService, [FromServices] IVacationService _vacationService, Guid doctorId)
|
||||
{
|
||||
var education = await _educationService.GetEducation(doctorId);
|
||||
|
||||
var sowList = _doctorService.GetDoctorSowList(doctorId);
|
||||
var ackSowList = _doctorService.GetDoctorAckSowList(doctorId);
|
||||
|
||||
var doctorDetail = new DoctorDetailDTO
|
||||
{
|
||||
AuditView =await _doctorService.GetAuditState(doctorId),
|
||||
BasicInfoView = await _doctorService.GetBasicInfo(doctorId),
|
||||
EmploymentView = await _doctorService.GetEmploymentInfo(doctorId),
|
||||
//AttachmentList = attachmentService.GetAttachments(doctorId),
|
||||
|
||||
EducationList = education.EducationList,
|
||||
PostgraduateList = education.PostgraduateList,
|
||||
|
||||
TrialExperienceView = await _trialExperienceService.GetTrialExperience(doctorId),
|
||||
ResearchPublicationView = await _researchPublicationService.GetResearchPublication(doctorId),
|
||||
|
||||
SpecialtyView =await _doctorService.GetSpecialtyInfo(doctorId),
|
||||
InHoliday = (await _vacationService.OnVacation(doctorId)).IsSuccess,
|
||||
IntoGroupInfo = _doctorService.GetDoctorIntoGroupInfo(doctorId),
|
||||
SowList = sowList,
|
||||
AckSowList = ackSowList
|
||||
};
|
||||
|
||||
return ResponseOutput.Ok(doctorDetail);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[HttpPost, Route("enroll/downloadResume/{trialId:guid}/{language}")]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput<string>> DownloadResume([FromServices] IFileService _fileService, int language, Guid trialId, Guid[] doctorIdArray)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
var zipPath = await _fileService.CreateOfficialResumeZip(language, doctorIdArray);
|
||||
|
||||
return ResponseOutput.Ok(zipPath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary> 系统用户登录接口[New] </summary>
|
||||
[HttpPost, Route("user/login")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput<LoginReturnDTO>> Login(UserLoginDTO loginUser, [FromServices] IEasyCachingProvider provider, [FromServices] IUserService _userService,
|
||||
[FromServices] ITokenService _tokenService, [FromServices] IConfiguration configuration)
|
||||
{
|
||||
|
||||
var returnModel = await _userService.Login(loginUser.UserName, loginUser.Password);
|
||||
|
||||
if (returnModel.IsSuccess)
|
||||
{
|
||||
#region GRPC 调用鉴权中心,因为服务器IIS问题 http/2 故而没法使用
|
||||
|
||||
////重试策略
|
||||
//var defaultMethodConfig = new MethodConfig
|
||||
//{
|
||||
// Names = { MethodName.Default },
|
||||
// RetryPolicy = new RetryPolicy
|
||||
// {
|
||||
// MaxAttempts = 3,
|
||||
// InitialBackoff = TimeSpan.FromSeconds(1),
|
||||
// MaxBackoff = TimeSpan.FromSeconds(5),
|
||||
// BackoffMultiplier = 1.5,
|
||||
// RetryableStatusCodes = { Grpc.Core.StatusCode.Unavailable }
|
||||
// }
|
||||
//};
|
||||
|
||||
//#region unable to trust the certificate then the gRPC client can be configured to ignore the invalid certificate
|
||||
|
||||
//var httpHandler = new HttpClientHandler();
|
||||
//// Return `true` to allow certificates that are untrusted/invalid
|
||||
//httpHandler.ServerCertificateCustomValidationCallback =
|
||||
// HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||
|
||||
|
||||
//////这一句是让grpc支持本地 http 如果本地访问部署在服务器上,那么是访问不成功的
|
||||
//AppContext.SetSwitch(
|
||||
// "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//var grpcAdress = configuration.GetValue<string>("GrpcAddress");
|
||||
////var grpcAdress = "http://localhost:7200";
|
||||
|
||||
//var channel = GrpcChannel.ForAddress(grpcAdress, new GrpcChannelOptions
|
||||
//{
|
||||
// HttpHandler = httpHandler,
|
||||
// ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
|
||||
|
||||
//});
|
||||
////var channel = GrpcChannel.ForAddress(grpcAdress);
|
||||
//var grpcClient = new TokenGrpcService.TokenGrpcServiceClient(channel);
|
||||
|
||||
//var userInfo = returnModel.Data.BasicInfo;
|
||||
|
||||
//var tokenResponse = grpcClient.GetUserToken(new GetTokenReuqest()
|
||||
//{
|
||||
// Id = userInfo.Id.ToString(),
|
||||
// ReviewerCode = userInfo.ReviewerCode,
|
||||
// IsAdmin = userInfo.IsAdmin,
|
||||
// RealName = userInfo.RealName,
|
||||
// UserTypeEnumInt = (int)userInfo.UserTypeEnum,
|
||||
// UserTypeShortName = userInfo.UserTypeShortName,
|
||||
// UserName = userInfo.UserName
|
||||
//});
|
||||
|
||||
//returnModel.Data.JWTStr = tokenResponse.Token;
|
||||
|
||||
#endregion
|
||||
|
||||
returnModel.Data.JWTStr = _tokenService.GetToken(IRaCISClaims.Create(returnModel.Data.BasicInfo));
|
||||
|
||||
}
|
||||
|
||||
var userId = returnModel.Data.BasicInfo.Id.ToString();
|
||||
provider.Set(userId, userId, TimeSpan.FromMinutes(AppSettings.LoginExpiredTimeSpan));
|
||||
return returnModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet, Route("imageShare/ShareImage")]
|
||||
public IResponseOutput ShareImage([FromServices] ITokenService _tokenService)
|
||||
{
|
||||
var token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
IsReviewer = false,
|
||||
IsAdmin = false,
|
||||
RealName = "Share001",
|
||||
UserName = "Share001",
|
||||
Sex = 0,
|
||||
//UserType = "ShareType",
|
||||
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||
Code = "ShareCode001",
|
||||
}));
|
||||
return ResponseOutput.Ok("/#/preview?studyId=d8e7ed1c-4b59-a483-563d-4f05bd4f8921&token=" + token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//外部用户 邮件链接调用 以及跳转逻辑
|
||||
|
||||
[HttpGet("trialExternalUser/ExternalUserJoinTrial")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> ExternalUserJoinTrial([FromServices] ITrialExternalUserService _trialExternalUserService, Guid trialId, Guid trialExternalUserId, string url)
|
||||
{
|
||||
await _trialExternalUserService.UserConfirmJoinTrial(trialId, trialExternalUserId);
|
||||
|
||||
|
||||
var decodeUrl = System.Web.HttpUtility.UrlDecode(url);
|
||||
|
||||
|
||||
return Redirect(decodeUrl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[HttpGet, Route("ip")]
|
||||
[AllowAnonymous]
|
||||
public IResponseOutput Get([FromServices] IHttpContextAccessor _context, [FromServices] IUserService _userService)
|
||||
{
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"RemoteIpAddress:{_context.HttpContext.Connection.RemoteIpAddress}");
|
||||
|
||||
if (Request.Headers.ContainsKey("X-Real-IP"))
|
||||
{
|
||||
sb.AppendLine($"X-Real-IP:{Request.Headers["X-Real-IP"].ToString()}");
|
||||
}
|
||||
|
||||
if (Request.Headers.ContainsKey("X-Forwarded-For"))
|
||||
{
|
||||
sb.AppendLine($"X-Forwarded-For:{Request.Headers["X-Forwarded-For"].ToString()}");
|
||||
}
|
||||
return ResponseOutput.Ok(sb.ToString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.API.Utility;
|
||||
using IRaCIS.Core.Application.Contracts.Image;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
|
||||
namespace IRaCIS.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件上传
|
||||
/// </summary>
|
||||
[Route("file")]
|
||||
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Common")]
|
||||
public class FileController : ControllerBase
|
||||
{
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private ILogger<FileController> _logger;
|
||||
|
||||
private string _targetFilePath;
|
||||
private readonly long _fileSizeLimit;
|
||||
private readonly string[] _permittedExtensions = { ".pdf", ".doc", ".docx" };
|
||||
|
||||
public string trustedFileNameForFileStorage = "";
|
||||
|
||||
// Get the default form options so that we can use them to set the default
|
||||
// limits for request body data.
|
||||
private static readonly FormOptions _defaultFormOptions = new FormOptions();
|
||||
private string defaultUploadFilePath = string.Empty;
|
||||
public FileController(IFileService fileService, Microsoft.Extensions.Configuration.IConfiguration config,
|
||||
IHostEnvironment hostEnvironment, ILogger<FileController> logger,
|
||||
IWebHostEnvironment webHostEnvironment)
|
||||
{
|
||||
_fileService = fileService;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
_fileSizeLimit = config.GetValue<long>("FileSizeLimit");
|
||||
defaultUploadFilePath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).FullName;
|
||||
|
||||
_logger = logger;
|
||||
|
||||
_logger.LogWarning("File Path:" + defaultUploadFilePath);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件[FileUpload]
|
||||
/// </summary>
|
||||
/// <param name="attachmentType">附件类型</param>
|
||||
/// <param name="doctorId">医生Id</param>
|
||||
/// <returns>返回文件信息</returns>
|
||||
[HttpPost, Route("uploadFile/{attachmentType}/{doctorId}")]
|
||||
[DisableFormValueModelBinding]
|
||||
public async Task<IActionResult> UploadOrdinaryFile(string attachmentType, Guid doctorId)
|
||||
{
|
||||
#region 官方文档方式
|
||||
|
||||
|
||||
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
|
||||
{
|
||||
ModelState.AddModelError("File",
|
||||
$"The request couldn't be processed (Error 1).");
|
||||
// Log error
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var boundary = MultipartRequestHelper.GetBoundary(
|
||||
MediaTypeHeaderValue.Parse(Request.ContentType),
|
||||
_defaultFormOptions.MultipartBoundaryLengthLimit);
|
||||
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)
|
||||
{
|
||||
// This check assumes that there's a file
|
||||
// present without form data. If form data
|
||||
// is present, this method immediately fails
|
||||
// and returns the model error.
|
||||
if (!MultipartRequestHelper
|
||||
.HasFileContentDisposition(contentDisposition))
|
||||
{
|
||||
ModelState.AddModelError("File",
|
||||
$"The request couldn't be processed (Error 2).");
|
||||
// Log error
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't trust the file name sent by the client. To display
|
||||
// the file name, HTML-encode the value.
|
||||
var trustedFileNameForDisplay = WebUtility.HtmlEncode(
|
||||
contentDisposition.FileName.Value);
|
||||
|
||||
//var trustedFileNameForFileStorage = Path.GetRandomFileName();
|
||||
trustedFileNameForFileStorage = contentDisposition.FileName.Value;
|
||||
|
||||
// **WARNING!**
|
||||
// In the following example, the file is saved without
|
||||
// scanning the file's contents. In most production
|
||||
// scenarios, an anti-virus/anti-malware scanner API
|
||||
// is used on the file before making the file available
|
||||
// for download or for use by other systems.
|
||||
// For more information, see the topic that accompanies
|
||||
// this sample.
|
||||
|
||||
var streamedFileContent = await FileHelpers.ProcessStreamedFile(
|
||||
section, contentDisposition, ModelState,
|
||||
_permittedExtensions, _fileSizeLimit);
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
|
||||
//实际文件处理
|
||||
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile/" + doctorId + "/");
|
||||
|
||||
var doctorAttachmentUploadFolder = Path.Combine(uploadFolderPath, attachmentType);
|
||||
|
||||
_targetFilePath = doctorAttachmentUploadFolder;
|
||||
|
||||
if (!Directory.Exists(doctorAttachmentUploadFolder)) Directory.CreateDirectory(doctorAttachmentUploadFolder);
|
||||
|
||||
using (var targetStream = System.IO.File.Create(
|
||||
Path.Combine(_targetFilePath, trustedFileNameForFileStorage)))
|
||||
{
|
||||
await targetStream.WriteAsync(streamedFileContent);
|
||||
|
||||
var attachmentPath = $"/UploadFile/{doctorId}/{attachmentType}/{trustedFileNameForFileStorage}";
|
||||
|
||||
return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath, FullFilePath = attachmentPath + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7) }));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Drain any remaining section body that hasn't been consumed and
|
||||
// read the headers for the next section.
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
|
||||
|
||||
return Created(nameof(FileController), null);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件( 不是医生个人的文件)[FileUpload]
|
||||
/// 例如:阅片章程等
|
||||
/// </summary>
|
||||
/// <param name="type">文件类型</param>
|
||||
/// <returns></returns>
|
||||
|
||||
[HttpPost, Route("uploadNonDoctorFile/{type}")]
|
||||
[DisableFormValueModelBinding]
|
||||
public async Task<IActionResult> UploadNonDoctorFile(string type)
|
||||
{
|
||||
#region New Test 实测OK
|
||||
|
||||
//上传根路径
|
||||
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile");
|
||||
|
||||
|
||||
if (uploadFolderPath != null)
|
||||
{
|
||||
//文件类型路径处理
|
||||
var uploadTypePath = Path.Combine(uploadFolderPath, type);
|
||||
if (!Directory.Exists(uploadTypePath)) Directory.CreateDirectory(uploadTypePath);
|
||||
|
||||
|
||||
////实际文件处理
|
||||
|
||||
_targetFilePath = uploadTypePath;
|
||||
|
||||
//获取boundary
|
||||
|
||||
#region 方式二
|
||||
|
||||
var boundary = MultipartRequestHelper.GetBoundary(
|
||||
MediaTypeHeaderValue.Parse(Request.ContentType),
|
||||
_defaultFormOptions.MultipartBoundaryLengthLimit);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 方式一
|
||||
//var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//得到reader
|
||||
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
|
||||
//{ BodyLengthLimit = 2000 };//
|
||||
var section = await reader.ReadNextSectionAsync();
|
||||
|
||||
//读取section
|
||||
while (section != null)
|
||||
{
|
||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
||||
if (hasContentDispositionHeader)
|
||||
{
|
||||
trustedFileNameForFileStorage = contentDisposition.FileName.Value;
|
||||
|
||||
|
||||
await WriteFileAsync(section.Body, Path.Combine(_targetFilePath, trustedFileNameForFileStorage));
|
||||
|
||||
#region 方式二
|
||||
|
||||
//using (var targetStream = System.IO.File.Create(
|
||||
// Path.Combine(_targetFilePath, trustedFileNameForFileStorage)))
|
||||
//{
|
||||
|
||||
// using (var memoryStream = new MemoryStream())
|
||||
// {
|
||||
// await section.Body.CopyToAsync(memoryStream);
|
||||
|
||||
// await targetStream.WriteAsync(memoryStream.ToArray());
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
var attachmentPath = $"/UploadFile/{type}/{trustedFileNameForFileStorage}";
|
||||
|
||||
return new JsonResult(ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath, FullFilePath = attachmentPath + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7) }));
|
||||
}
|
||||
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
return Created(nameof(FileController), null);
|
||||
|
||||
|
||||
}
|
||||
return new JsonResult(ResponseOutput.NotOk("服务器端映射路径操作失败"));
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 写文件导到磁盘
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="path">文件保存路径</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<int> WriteFileAsync(System.IO.Stream stream, string path)
|
||||
{
|
||||
const int FILE_WRITE_SIZE = 84975;//写出缓冲区大小
|
||||
int writeCount = 0;
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true))
|
||||
{
|
||||
byte[] byteArr = new byte[FILE_WRITE_SIZE];
|
||||
int readCount = 0;
|
||||
while ((readCount = await stream.ReadAsync(byteArr, 0, byteArr.Length)) > 0)
|
||||
{
|
||||
await fileStream.WriteAsync(byteArr, 0, readCount);
|
||||
writeCount += readCount;
|
||||
}
|
||||
}
|
||||
return writeCount;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region 上传无影响部分
|
||||
|
||||
/// <summary>
|
||||
/// 下载多个医生的所有附件
|
||||
/// </summary>
|
||||
/// <param name="doctorIds"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[HttpPost, Route("downloadDoctorAttachments")]
|
||||
public async Task<IResponseOutput<UploadFileInfoDTO>> 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)
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载医生官方简历
|
||||
/// </summary>
|
||||
/// <param name="language"></param>
|
||||
/// <param name="doctorIds"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost, Route("downloadOfficialCV/{language}")]
|
||||
public async Task<IResponseOutput<UploadFileInfoDTO>> DownloadOfficialResume(int language, Guid[] doctorIds)
|
||||
{
|
||||
|
||||
var path = _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)
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载指定医生的指定附件
|
||||
/// </summary>
|
||||
/// <param name="doctorId">医生Id</param>
|
||||
/// <param name="attachmentIds">要下载的附件Id</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost, Route("downloadByAttachmentId/{doctorId}")]
|
||||
public async Task<IResponseOutput<UploadFileInfoDTO>> 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)
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 废弃
|
||||
|
||||
public class UploadDTFCommand
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 流式上传 临时文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("UploadDTF/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{subjectVisitId:guid}/{studyId:guid}")]
|
||||
[DisableFormValueModelBinding]
|
||||
[DisableRequestSizeLimit]
|
||||
[Obsolete]
|
||||
public async Task<IResponseOutput> UploadingStream(Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId, Guid studyId, [FromServices] IStudyDTFService studyDTFService)
|
||||
{
|
||||
|
||||
//上传根路径
|
||||
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "Dicom");
|
||||
|
||||
|
||||
var dtfPath = Path.Combine(uploadFolderPath, DateTime.Now.Year.ToString(), trialId.ToString(),
|
||||
siteId.ToString(), subjectId.ToString(), subjectVisitId.ToString());
|
||||
|
||||
if (!Directory.Exists(dtfPath))
|
||||
{
|
||||
Directory.CreateDirectory(dtfPath);
|
||||
}
|
||||
|
||||
|
||||
#region 之前DTF 先上传临时文件,再拷贝
|
||||
////上传根路径
|
||||
//string uploadFolderPath = Path.Combine(defaultUploadFilePath, "UploadFile");
|
||||
////文件类型路径处理
|
||||
//var uploadTempFilePath = Path.Combine(uploadFolderPath, "TempFile");
|
||||
//if (!Directory.Exists(uploadTempFilePath)) Directory.CreateDirectory(uploadTempFilePath);
|
||||
|
||||
|
||||
//var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
|
||||
|
||||
//await WriteFileAsync(section.Body, Path.Combine(uploadTempFilePath, trustedFileNameForFileStorage));
|
||||
|
||||
//var attachmentPath = $"{uploadTempFilePath}/{trustedFileNameForFileStorage}";
|
||||
|
||||
////多个文件上传,在这里返回就不合适,需要在外层,返回所有的文件路径,实际需要时再更改
|
||||
//return ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = attachmentPath });
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//获取boundary
|
||||
var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
|
||||
//得到reader
|
||||
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
|
||||
|
||||
var section = await reader.ReadNextSectionAsync();
|
||||
|
||||
//读取section
|
||||
while (section != null)
|
||||
{
|
||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
||||
if (hasContentDispositionHeader)
|
||||
{
|
||||
var realName = contentDisposition.FileName.Value;
|
||||
|
||||
var fileNameEX = Path.GetExtension(contentDisposition.FileName.Value);
|
||||
var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
|
||||
|
||||
|
||||
var relativePath = $"/Dicom/{DateTime.Now.Year.ToString()}/{trialId}/{siteId}/{subjectId}/{subjectVisitId}/{trustedFileNameForFileStorage}";
|
||||
studyDTFService.AddStudyDTF(new Core.Application.Contracts.Dicom.DTO.StudyDTFAddOrUpdateCommand()
|
||||
{
|
||||
StudyId = studyId,
|
||||
|
||||
FileName = realName,
|
||||
|
||||
Path = relativePath
|
||||
});
|
||||
|
||||
await WriteFileAsync(section.Body, Path.Combine(dtfPath, trustedFileNameForFileStorage));
|
||||
|
||||
//仅仅返回一个文件,如果多文件上传 在最后返回多个路径
|
||||
return ResponseOutput.Ok(new UploadFileInfoDTO() { FilePath = relativePath, FullFilePath = relativePath + "?access_token=" + HttpContext.Request.Headers["Authorization"].ToString().Substring(7) });
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
return ResponseOutput.NotOk("Upload error");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 流式上传 非Dicom文件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("UploadNoneDICOM")]
|
||||
[DisableFormValueModelBinding]
|
||||
[DisableRequestSizeLimit]
|
||||
[Obsolete]
|
||||
public async Task<IResponseOutput> UploadingNoneDicomStream([FromForm] ArchiveStudyCommand archiveStudyCommand, [FromServices] IStudyService studyService)
|
||||
{
|
||||
//上传根路径
|
||||
string uploadFolderPath = Path.Combine(defaultUploadFilePath, "Dicom");
|
||||
|
||||
//文件类型路径处理
|
||||
//var noneDicomPath = Path.Combine(uploadFolderPath, DateTime.Now.Year.ToString(), archiveStudyCommand.TrialId.ToString(),
|
||||
// archiveStudyCommand.SiteId.ToString(), archiveStudyCommand.SubjectId.ToString(), archiveStudyCommand.SubjectVisitId.ToString(), "Data");
|
||||
|
||||
//var dtfPath = Path.Combine(uploadFolderPath, DateTime.Now.Year.ToString(), archiveStudyCommand.TrialId.ToString(),
|
||||
// archiveStudyCommand.SiteId.ToString(), archiveStudyCommand.SubjectId.ToString(), archiveStudyCommand.SubjectVisitId.ToString());
|
||||
|
||||
var noneDicomPath = string.Empty;
|
||||
|
||||
var dtfPath = string.Empty;
|
||||
|
||||
var tempDtfPath = Path.Combine(defaultUploadFilePath/*, archiveStudyCommand.DTFPath*/);
|
||||
|
||||
|
||||
if (!Directory.Exists(noneDicomPath))
|
||||
{
|
||||
Directory.CreateDirectory(noneDicomPath);
|
||||
}
|
||||
if (!System.IO.File.Exists(tempDtfPath))
|
||||
{
|
||||
return ResponseOutput.NotOk("DTF file can not found");
|
||||
}
|
||||
|
||||
System.IO.File.Move(tempDtfPath, dtfPath);
|
||||
|
||||
var saveFileDic = new Dictionary<string, string>();
|
||||
|
||||
//获取boundary
|
||||
var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
|
||||
//得到reader
|
||||
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
|
||||
|
||||
var section = await reader.ReadNextSectionAsync();
|
||||
|
||||
//读取section
|
||||
while (section != null)
|
||||
{
|
||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
||||
if (hasContentDispositionHeader)
|
||||
{
|
||||
var fileName = contentDisposition.FileName.Value;
|
||||
var fileNameEX = Path.GetExtension(contentDisposition.FileName.Value);
|
||||
var trustedFileNameForFileStorage = Guid.NewGuid() + fileNameEX;
|
||||
|
||||
|
||||
|
||||
await WriteFileAsync(section.Body, Path.Combine(noneDicomPath, trustedFileNameForFileStorage));
|
||||
|
||||
var attachmentPath = $"{noneDicomPath}/{trustedFileNameForFileStorage}";
|
||||
|
||||
saveFileDic.Add(attachmentPath, fileName);
|
||||
|
||||
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
|
||||
//处理数据库操作
|
||||
|
||||
//studyService.DealNonDicomFile(saveFileDic, archiveStudyCommand);
|
||||
return ResponseOutput.Ok(saveFileDic);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Application.Services;
|
||||
|
||||
namespace IRaCIS.Core.API.Controllers.Special
|
||||
{
|
||||
//谨慎修改 涉及到财务模块
|
||||
|
||||
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Financial")]
|
||||
public class FinancialChangeController : ControllerBase
|
||||
{
|
||||
private readonly ITrialService _trialService;
|
||||
private readonly ICalculateService _calculateService;
|
||||
|
||||
public FinancialChangeController(ITrialService trialService, ICalculateService calculateService)
|
||||
{
|
||||
_trialService = trialService;
|
||||
_calculateService = calculateService;
|
||||
}
|
||||
|
||||
/// <summary> 添加实验项目-返回新增Id[AUTH]</summary>
|
||||
/// <param name="param"></param>
|
||||
/// <returns>新记录Id</returns>
|
||||
|
||||
//[TrialAudit(AuditType.TrialAudit, AuditOptType.AddOrUpdateTrial)]
|
||||
|
||||
[HttpPost, Route("trial/addOrUpdateTrial")]
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateTrial(TrialCommand param)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
var result = await _trialService.AddOrUpdateTrial(param);
|
||||
|
||||
if (_trialService.TrialExpeditedChange)
|
||||
{
|
||||
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(param.Id.Value);
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||
|
||||
calcList.ForEach(t =>
|
||||
{
|
||||
if (needCalReviewerIds.Contains(t.DoctorId))
|
||||
{
|
||||
_calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
t.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(t.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新工作量[AUTH]
|
||||
/// </summary>
|
||||
/// <param name="_trialWorkloadService"></param>
|
||||
/// <param name="workLoadAddOrUpdateModel"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[HttpPost, Route("doctorWorkload/workLoadAddOrUpdate")]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> WorkLoadAddOrUpdate([FromServices] IDoctorWorkloadService _trialWorkloadService, WorkloadCommand workLoadAddOrUpdateModel)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
var result = await _trialWorkloadService.AddOrUpdateWorkload(workLoadAddOrUpdateModel, userId);
|
||||
if (result.IsSuccess && workLoadAddOrUpdateModel.DataFrom == 2)
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
workLoadAddOrUpdateModel.DoctorId
|
||||
},
|
||||
CalculateMonth = workLoadAddOrUpdateModel.WorkTime
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpDelete, Route("doctorWorkload/deleteWorkLoad/{id:guid}/{trialId:guid}")]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> DeleteWorkLoad([FromServices] IDoctorWorkloadService _trialWorkloadService, Guid id)
|
||||
{
|
||||
//先判断该工作量的费用是否被锁定,如果被锁定,则不能删除
|
||||
var workload = await _trialWorkloadService.GetWorkloadDetailById(id);
|
||||
var yearMonth = workload.WorkTime.ToString("yyyy-MM");
|
||||
var isLock = await _calculateService.IsLock(workload.DoctorId, yearMonth);
|
||||
|
||||
if (isLock)
|
||||
{
|
||||
return ResponseOutput.NotOk("Expenses have been settled and workload can not be reset.");
|
||||
}
|
||||
|
||||
var deleteResult = await _trialWorkloadService.DeleteWorkload(id);
|
||||
if (workload.DataFrom == (int)Domain.Share.WorkLoadFromStatus.FinalConfirm)
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
workload.DoctorId
|
||||
},
|
||||
CalculateMonth = workload.WorkTime
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
return deleteResult;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新汇率(会触发没有对锁定的费用计算)
|
||||
/// </summary>
|
||||
|
||||
[HttpPost, Route("exchangeRate/addOrUpdateExchangeRate")]
|
||||
public async Task<IResponseOutput> AddOrUpdateExchangeRate([FromServices] IExchangeRateService _exchangeRateService, [FromServices] IPaymentAdjustmentService _costAdjustmentService, ExchangeRateCommand addOrUpdateModel)
|
||||
{
|
||||
var result = await _exchangeRateService.AddOrUpdateExchangeRate(addOrUpdateModel);
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, addOrUpdateModel.YearMonth);
|
||||
foreach (var item in calcList)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
item.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
}
|
||||
_costAdjustmentService.CalculateCNY(addOrUpdateModel.YearMonth, addOrUpdateModel.Rate);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新 职称单价[AUTH]
|
||||
/// </summary>
|
||||
|
||||
[HttpPost, Route("rankPrice/addOrUpdateRankPrice")]
|
||||
public async Task<IResponseOutput> AddOrUpdateRankPrice([FromServices] IReviewerPayInfoService _reviewerPayInfoService, [FromServices] IRankPriceService _rankPriceService, RankPriceCommand addOrUpdateModel)
|
||||
{
|
||||
if (addOrUpdateModel.Id != Guid.Empty && addOrUpdateModel.Id != null)
|
||||
{
|
||||
var needCalReviewerIds =await _reviewerPayInfoService.GetReviewerIdByRankId(Guid.Parse(addOrUpdateModel.Id.ToString()));
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||
|
||||
foreach (var item in calcList)
|
||||
{
|
||||
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
item.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
return await _rankPriceService.AddOrUpdateRankPrice(addOrUpdateModel, userId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新(替换)医生支付展信息[AUTH]
|
||||
/// </summary>
|
||||
|
||||
[HttpPost, Route("reviewerPayInfo/addOrUpdateReviewerPayInfo")]
|
||||
public async Task<IResponseOutput> AddOrUpdateReviewerPayInfo([FromServices] IReviewerPayInfoService _doctorPayInfoService, ReviewerPayInfoCommand addOrUpdateModel)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
var result =await _doctorPayInfoService.AddOrUpdateReviewerPayInfo(addOrUpdateModel, userId);
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(addOrUpdateModel.DoctorId, string.Empty);
|
||||
foreach (var item in calcList)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
item.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 保存(替换)项目支付价格信息(会触发没有被锁定的费用计算)[AUTH]
|
||||
/// </summary>
|
||||
|
||||
[HttpPost, Route("trialPaymentPrice/addOrUpdateTrialPaymentPrice")]
|
||||
public async Task<IResponseOutput> AddOrUpdateTrialPaymentPrice([FromServices] ITrialPaymentPriceService _trialPaymentPriceService, TrialPaymentPriceCommand addOrUpdateModel)
|
||||
{
|
||||
var userId = Guid.Parse(User.FindFirst("id").Value);
|
||||
var result =await _trialPaymentPriceService.AddOrUpdateTrialPaymentPrice(addOrUpdateModel);
|
||||
var needCalReviewerIds = await _trialService.GetTrialEnrollmentReviewerIds(addOrUpdateModel.TrialId);
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||
|
||||
foreach (var item in calcList)
|
||||
{
|
||||
if (item != null && needCalReviewerIds.Contains(item.DoctorId))
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
item.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新奖励费用[AUTH]
|
||||
/// </summary>
|
||||
|
||||
[HttpPost, Route("volumeReward/addOrUpdatevolumeRewardPriceList")]
|
||||
public async Task<IResponseOutput> AddOrUpdateAwardPriceList([FromServices] IVolumeRewardService _volumeRewardService, IEnumerable<AwardPriceCommand> addOrUpdateModel)
|
||||
{
|
||||
|
||||
var result =await _volumeRewardService.AddOrUpdateVolumeRewardPriceList(addOrUpdateModel);
|
||||
|
||||
var calcList = await _calculateService.GetNeedCalculateReviewerList(Guid.Empty, string.Empty);
|
||||
foreach (var item in calcList)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
await _calculateService.CalculateMonthlyPayment(new CalculateDoctorAndMonthDTO()
|
||||
{
|
||||
NeedCalculateReviewers = new List<Guid>()
|
||||
{
|
||||
item.DoctorId
|
||||
},
|
||||
CalculateMonth = DateTime.Parse(item.YearMonth)
|
||||
}, User.FindFirst("id").Value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 计算医生月度费用,并将计算的结果存入费用表
|
||||
/// </summary>
|
||||
[HttpPost, Route("financial/calculateMonthlyPayment")]
|
||||
public async Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return ResponseOutput.NotOk("Invalid parameter.");
|
||||
}
|
||||
return await _calculateService.CalculateMonthlyPayment(param, User.FindFirst("id").Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Financials /Monthly Payment 列表查询接口
|
||||
/// </summary>
|
||||
[HttpPost, Route("financial/getMonthlyPaymentList")]
|
||||
public async Task<IResponseOutput<PaymentDTO>> GetMonthlyPaymentList([FromServices] IPaymentService _paymentService, [FromServices] IExchangeRateService _exchangeRateService, MonthlyPaymentQueryDTO queryParam)
|
||||
{
|
||||
return ResponseOutput.Ok(new PaymentDTO
|
||||
{
|
||||
CostList = await _paymentService.GetMonthlyPaymentList(queryParam),
|
||||
ExchangeRate = await _exchangeRateService.GetExchangeRateByMonth(queryParam.StatisticsDate.ToString("yyyy-MM"))
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IRaCIS.Core.API.Controllers
|
||||
{
|
||||
|
||||
[ApiController, ApiExplorerSettings(GroupName = "Reviewer")]
|
||||
public class InspectionController : ControllerBase
|
||||
{
|
||||
private readonly IRepository _repository;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IUserInfo _userInfo;
|
||||
|
||||
public InspectionController(IRepository repository, IMapper mapper, IUserInfo userInfo)
|
||||
{
|
||||
_repository = repository;
|
||||
_mapper = mapper;
|
||||
_userInfo = userInfo;
|
||||
}
|
||||
|
||||
[HttpPost, Route("trialDocument/userConfirm")]
|
||||
public async Task<IResponseOutput> UserConfirm(TrialDocumentConfirmDTO opt, [FromServices] ITrialDocumentService _trialDocumentService)
|
||||
{
|
||||
var verifyResult = await VerifySignatureAsync(opt.SignInfo);
|
||||
|
||||
if (verifyResult.IsSuccess == false)
|
||||
{
|
||||
return verifyResult;
|
||||
}
|
||||
|
||||
var bResult = await _trialDocumentService.UserConfirm(opt.OptCommand);
|
||||
|
||||
if (bResult.IsSuccess == false)
|
||||
{
|
||||
return bResult;
|
||||
}
|
||||
|
||||
//SiteId SubjectId SubjectVisitId TrialId 最开始没有 需要特殊处理
|
||||
//表冗余字段 前端只传递一次的话 后台模型就需要单独处理
|
||||
|
||||
|
||||
if (opt.AuditInfo.IsSign)
|
||||
{
|
||||
var signId = await AddSignRecordAsync(opt.SignInfo);
|
||||
|
||||
await AddInspectionRecordAsync(opt.AuditInfo, signId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await AddInspectionRecordAsync(opt.AuditInfo, null);
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary> 验证用户签名信息 </summary> ///
|
||||
private async Task<IResponseOutput> VerifySignatureAsync(SignDTO signDTO)
|
||||
{
|
||||
var user = await _repository.FirstOrDefaultAsync<User>(u => u.UserName == signDTO.UserName && u.Password == signDTO.PassWord);
|
||||
if (user == null)
|
||||
{
|
||||
return ResponseOutput.NotOk("password error");
|
||||
}
|
||||
else if (user.Status == UserStateEnum.Disable)
|
||||
{
|
||||
return ResponseOutput.NotOk("The user has been disabled!");
|
||||
}
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary> 添加签名记录 </summary> ///
|
||||
private async Task<Guid> AddSignRecordAsync(SignDTO signDTO)
|
||||
{
|
||||
var add = await _repository.AddAsync(_mapper.Map<TrialSign>(signDTO));
|
||||
|
||||
var success = await _repository.SaveChangesAsync();
|
||||
|
||||
return add.Id;
|
||||
|
||||
}
|
||||
|
||||
/// <summary> 添加稽查记录( 有的会签名,有的不会签名) </summary> ///
|
||||
private async Task AddInspectionRecordAsync(DataInspectionAddDTO addDto, Guid? signId)
|
||||
{
|
||||
|
||||
var add = await _repository.AddAsync(_mapper.Map<DataInspection>(addDto));
|
||||
|
||||
add.SignId = signId;
|
||||
add.IP = _userInfo.IP;
|
||||
|
||||
var success = await _repository.SaveChangesAsync();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,408 @@
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using IRaCIS.Core.Application.Dicom;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using EasyCaching.Core;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
|
||||
namespace IRaCIS.Api.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Study
|
||||
/// </summary>
|
||||
[Route("study")]
|
||||
[ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")]
|
||||
public class StudyController : ControllerBase
|
||||
{
|
||||
private readonly IStudyService _studyService;
|
||||
private readonly IDicomArchiveService _dicomArchiveService;
|
||||
private readonly ILogger<StudyController> _logger;
|
||||
|
||||
private IEasyCachingProvider _provider;
|
||||
private IUserInfo _userInfo;
|
||||
private static object _locker = new object();
|
||||
|
||||
|
||||
public StudyController(IStudyService studyService,
|
||||
IDicomArchiveService dicomArchiveService,
|
||||
ILogger<StudyController> logger,
|
||||
IEasyCachingProvider provider, IUserInfo userInfo
|
||||
)
|
||||
{
|
||||
_userInfo = userInfo;
|
||||
_provider = provider;
|
||||
_studyService = studyService;
|
||||
_dicomArchiveService = dicomArchiveService;
|
||||
_logger = logger;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary> 归档</summary>
|
||||
[HttpPost, Route("archiveStudy/{trialId:guid}")]
|
||||
[DisableFormValueModelBinding]
|
||||
[DisableRequestSizeLimit]
|
||||
[TypeFilter(typeof(TrialResourceFilter))]
|
||||
public async Task<IResponseOutput> ArchiveStudy([FromForm] ArchiveStudyCommand archiveStudyCommand)
|
||||
{
|
||||
//Stopwatch sw = new Stopwatch();
|
||||
var startTime = DateTime.Now;
|
||||
//sw.Start();
|
||||
|
||||
if (_provider.Exists("StudyUid_" + archiveStudyCommand.StudyInstanceUid))
|
||||
{
|
||||
return ResponseOutput.NotOk("当前已有人正在上传和归档该检查!");
|
||||
}
|
||||
else
|
||||
{
|
||||
_provider.Set("StudyUid_" + archiveStudyCommand.StudyInstanceUid, _userInfo.Id, TimeSpan.FromMinutes(30));
|
||||
}
|
||||
|
||||
var archiveResult = new DicomArchiveResult();
|
||||
var archivedStudyIds = new List<Guid>();
|
||||
var seriesInstanceUidList = new List<string>();
|
||||
var instanceUidList = new List<string>();
|
||||
|
||||
//重传的时候,找出当前检查已经上传的series instance
|
||||
if (archiveStudyCommand.AbandonStudyId != null)
|
||||
{
|
||||
_studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value, ref seriesInstanceUidList, ref instanceUidList);
|
||||
}
|
||||
|
||||
var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId);
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
//采用post方式 这里多加一个判断 过滤其他参数
|
||||
if (string.IsNullOrEmpty(section.ContentType))
|
||||
{
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
continue;
|
||||
}
|
||||
|
||||
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
|
||||
if (hasContentDispositionHeader)
|
||||
{
|
||||
string fileName = contentDisposition.FileName.Value;
|
||||
try
|
||||
{
|
||||
|
||||
string mediaType = section.ContentType;
|
||||
|
||||
if (mediaType.Contains("zip"))
|
||||
{
|
||||
var partStream = section.Body;
|
||||
using (var zipArchive = new ZipArchive(partStream, ZipArchiveMode.Read))
|
||||
{
|
||||
foreach (var entry in zipArchive.Entries)
|
||||
{
|
||||
if (entry.FullName.EndsWith("/")) continue;
|
||||
try
|
||||
{
|
||||
++archiveResult.ReceivedFileCount;
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await section.Body.CopyToAsync(memoryStream);
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, instanceUidList);
|
||||
|
||||
if (!archivedStudyIds.Contains(archiveStudyId))
|
||||
archivedStudyIds.Add(archiveStudyId);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
archiveResult.ErrorFiles.Add($"{fileName}/{entry.FullName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++archiveResult.ReceivedFileCount;
|
||||
|
||||
|
||||
if (mediaType.Contains("octet-stream"))
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
await section.Body.CopyToAsync(memoryStream);
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, instanceUidList);
|
||||
if (!archivedStudyIds.Contains(archiveStudyId))
|
||||
archivedStudyIds.Add(archiveStudyId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e.Message + e.StackTrace);
|
||||
|
||||
archiveResult.ErrorFiles.Add(fileName);
|
||||
|
||||
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
|
||||
|
||||
}
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
|
||||
if (archivedStudyIds.Count > 0) // 上传成功,处理逻辑
|
||||
{
|
||||
|
||||
|
||||
// 同一个访视 多个线程上传处理 批量保存 可能造成死锁 https://www.cnblogs.com/johnblogs/p/9945767.html
|
||||
|
||||
await _dicomArchiveService.DicomDBDataSaveChange();
|
||||
|
||||
//sw.Stop();
|
||||
_studyService.UploadOrReUploadNeedTodo(archiveStudyCommand, archivedStudyIds, ref archiveResult, new StudyMonitor()
|
||||
{
|
||||
TrialId = savedInfo.TrialId,
|
||||
SiteId = savedInfo.SiteId,
|
||||
SubjectId = savedInfo.SubjectId,
|
||||
SubjectVisitId = savedInfo.SubjectVisitId,
|
||||
StudyId = archivedStudyIds[0],
|
||||
UploadStartTime = startTime,
|
||||
UploadFinishedTime = DateTime.Now,
|
||||
FileSize = (decimal)HttpContext.Request.ContentLength,
|
||||
FileCount = archiveResult.ReceivedFileCount,
|
||||
IsDicom = true,
|
||||
IsDicomReUpload = archiveStudyCommand.AbandonStudyId!=null,
|
||||
IP =_userInfo.IP
|
||||
});
|
||||
|
||||
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return ResponseOutput.NotOk("未完成该检查的归档", archiveResult);
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok(archiveResult);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#region 2021.12.14 整理废弃
|
||||
|
||||
//[Obsolete]
|
||||
//[HttpGet, Route("forwardStudy/{studyId:guid}/{trialId:guid}")]
|
||||
//[TrialAudit(AuditType.StudyAudit, AuditOptType.Forwarded)]
|
||||
//[TypeFilter(typeof(TrialResourceFilter))]
|
||||
|
||||
//public IResponseOutput ForwardStudy(Guid studyId)
|
||||
//{
|
||||
// return _studyService.ForwardStudy(studyId);
|
||||
//}
|
||||
|
||||
///// <summary> 指定资源Id,获取Dicom检查信息 </summary>
|
||||
///// <param name="studyId"> Dicom检查的Id </param>
|
||||
//[HttpGet, Route("item/{studyId:guid}")]
|
||||
//[Obsolete]
|
||||
//public IResponseOutput<DicomStudyDTO> GetStudyItem(Guid studyId)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetStudyItem(studyId));
|
||||
//}
|
||||
|
||||
//[Obsolete]
|
||||
//[HttpDelete, Route("deleteStudy/{id:guid}/{trialId:guid}")]
|
||||
//public IResponseOutput DeleteStudy(Guid id)
|
||||
//{
|
||||
// return _studyService.DeleteStudy(id);
|
||||
//}
|
||||
|
||||
//[Obsolete]
|
||||
//[HttpPost, Route("getStudyList")]
|
||||
//public IResponseOutput<PageOutput<StudyDTO>> GetStudyList(StudyQueryDTO queryDto)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetStudyList(queryDto));
|
||||
//}
|
||||
|
||||
|
||||
/////// <summary> 指定资源Id,渲染Dicom检查的Jpeg预览图像 </summary>
|
||||
/////// <param name="studyId"> Dicom检查的Id </param>
|
||||
////[HttpGet, Route("preview/{studyId:guid}")]
|
||||
////[AllowAnonymous]
|
||||
////public FileContentResult GetStudyPreview(Guid studyId)
|
||||
////{
|
||||
//// string path = _studyService.GetStudyPreview(studyId);
|
||||
//// using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path))
|
||||
//// {
|
||||
//// var bytes = new byte[sw.Length];
|
||||
//// sw.Read(bytes, 0, bytes.Length);
|
||||
//// sw.Close();
|
||||
//// return new FileContentResult(bytes, "image/jpeg");
|
||||
//// }
|
||||
////}
|
||||
|
||||
///// <summary>
|
||||
///// Dicom匿名化
|
||||
///// </summary>
|
||||
///// <param name="studyId">需要匿名化的检查Id</param>
|
||||
///// <returns></returns>
|
||||
//[HttpPost, Route("dicomAnonymize/{studyId:guid}/{trialId:guid}")]
|
||||
//[TrialAudit(AuditType.StudyAudit, AuditOptType.Anonymized)]
|
||||
//[Obsolete]
|
||||
//[TypeFilter(typeof(TrialResourceFilter))]
|
||||
//public async Task<IResponseOutput> DicomAnonymize(Guid studyId)
|
||||
//{
|
||||
// string userName = User.FindFirst("realName").Value; ;
|
||||
// return await _studyService.DicomAnonymize(studyId, userName);
|
||||
//}
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// 获取受试者 这次访视 对应的study modality 列表
|
||||
///// </summary>
|
||||
///// <param name="trialId"></param>
|
||||
///// <param name="siteId"></param>
|
||||
///// <param name="subjectId"></param>
|
||||
///// <param name="subjectVisitId"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpPost, Route("getSubjectVisitStudyList/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{subjectVisitId:guid}")]
|
||||
//[Obsolete]
|
||||
//[AllowAnonymous]
|
||||
//public IResponseOutput<List<SubjectVisitStudyDTO>> GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId,
|
||||
// Guid subjectVisitId)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetSubjectVisitStudyList(trialId, siteId, subjectId, subjectVisitId));
|
||||
//}
|
||||
|
||||
//[HttpPost, Route("getDistributeStudyList")]
|
||||
//[Obsolete]
|
||||
//public IResponseOutput<PageOutput<DistributeReviewerStudyStatusDTO>> GetDistributeStudyList(StudyStatusQueryDTO studyStatusQueryDto)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetDistributeStudyList(studyStatusQueryDto));
|
||||
//}
|
||||
|
||||
/////// <summary> 删除检查</summary>
|
||||
////[HttpDelete, Route("deleteStudy/{id:guid}/{trialId:guid}")]
|
||||
////
|
||||
////[TypeFilter(typeof(TrialResourceFilter))]
|
||||
////public IResponseOutput DeleteStudy(Guid id)
|
||||
////{
|
||||
//// return _studyService.DeleteStudy(id);
|
||||
////}
|
||||
|
||||
///// <summary> 更新Study状态,并保存状态变更信息 </summary>
|
||||
///// <param name="studyStatusDetailCommand"></param>
|
||||
|
||||
//[HttpPost, Route("updateStudyStatus/{trialId:guid}")]
|
||||
|
||||
//[TrialAudit(AuditType.StudyAudit, AuditOptType.ChangeStudyStatus)]
|
||||
//[Obsolete]
|
||||
//[TypeFilter(typeof(TrialResourceFilter))]
|
||||
//public IResponseOutput UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailCommand)
|
||||
//{
|
||||
// return _studyService.UpdateStudyStatus(studyStatusDetailCommand);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 根据项目Id 获取可选医生列表
|
||||
///// </summary>
|
||||
///// <param name="trialId"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpGet, Route("GetReviewerList/{trialId:guid}")]
|
||||
//[Obsolete]
|
||||
//public IResponseOutput<List<ReviewerDistributionDTO>> GetReviewerListByTrialId(Guid trialId)
|
||||
//{
|
||||
// var result = _studyService.GetReviewerListByTrialId(trialId);
|
||||
// return ResponseOutput.Ok(result);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 根据StudyId获取该Study的操作记录,时间倒序
|
||||
///// </summary>
|
||||
///// <param name="studyId"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpGet, Route("getStudyStatusDetailList/{studyId:guid}")]
|
||||
//[Obsolete]
|
||||
//public IResponseOutput<List<StudyStatusDetailDTO>> GetStudyStatusDetailList(Guid studyId)
|
||||
//{
|
||||
// var result = _studyService.GetStudyStatusDetailList(studyId);
|
||||
// return ResponseOutput.Ok(result);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 获取某个访视的关联访视
|
||||
///// 用于获取关联影像(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表)
|
||||
///// </summary>
|
||||
///// <param name="visitNum"></param>
|
||||
///// <param name="tpCode"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpGet, Route("getRelationVisitList/{visitNum}/{tpCode}")]
|
||||
//[Obsolete]
|
||||
//[AllowAnonymous]
|
||||
//public IResponseOutput<IEnumerable<RelationVisitDTO>> GetRelationVisitList(decimal visitNum, string tpCode)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetRelationVisitList(visitNum, tpCode));
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 保存标记(跟删除合并,每次保存最新的标记),会删除替换之前的标记
|
||||
///// 外层的TPcode 必须传,里面的标记数组可为空数组,表示删除该Study的所有标记
|
||||
///// </summary>
|
||||
///// <param name="imageLabelCommand"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpPost, Route("saveImageLabelList")]
|
||||
//[AllowAnonymous]
|
||||
//[Obsolete]
|
||||
|
||||
//public IResponseOutput SaveImageLabelList(ImageLabelCommand imageLabelCommand)
|
||||
//{
|
||||
// return ResponseOutput.Result(_studyService.SaveImageLabelList(imageLabelCommand));
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 根据TPCode 获取所有的标记
|
||||
///// </summary>
|
||||
///// <param name="tpCode"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpGet, Route("getImageLabelList/{tpCode}")]
|
||||
//[Obsolete]
|
||||
//[AllowAnonymous]
|
||||
//public IResponseOutput<IEnumerable<ImageLabelDTO>> GetImageLabelList(string tpCode)
|
||||
//{
|
||||
// return ResponseOutput.Ok(_studyService.GetImageLabel(tpCode));
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
using AutoMapper;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.API.Controllers
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
[ApiController]
|
||||
public class UploadController : ControllerBase
|
||||
{
|
||||
public IMapper _mapper { get; set; }
|
||||
public IUserInfo _userInfo { get; set; }
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
private readonly IWebHostEnvironment _hostEnvironment;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
|
||||
public UploadController(IMapper mapper, IUserInfo userInfo, IMediator mediator, IWebHostEnvironment hostEnvironment, IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_mediator = mediator;
|
||||
_mapper = mapper;
|
||||
_userInfo = userInfo;
|
||||
}
|
||||
|
||||
[HttpPost("TrialDocument/UploadTrialDoc/{trialId:guid}/{type}")]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
public async Task<IResponseOutput> UploadTrialDoc(Guid trialId,string type)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
DealTrialStorePath(trialId, type, contentDisposition.FileName.Value, out string serverFilePath, out string relativePath );
|
||||
|
||||
await WriteFileAsync(section.Body, serverFilePath);
|
||||
|
||||
//仅仅返回一个文件,如果多文件上传 在最后返回多个路径
|
||||
return ResponseOutput.Ok(new
|
||||
{
|
||||
FilePath = relativePath,
|
||||
FullFilePath = relativePath + "?access_token=" + _userInfo.UserToken
|
||||
});
|
||||
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("TrialDocument/UploadSystemDoc/{type}")]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
public async Task<IResponseOutput> UploadSysTemDoc( string type)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
||||
DealSysTemStorePath( type, contentDisposition.FileName.Value, out string serverFilePath, out string relativePath);
|
||||
|
||||
await WriteFileAsync(section.Body, serverFilePath);
|
||||
|
||||
//仅仅返回一个文件,如果多文件上传 在最后返回多个路径
|
||||
return ResponseOutput.Ok(new
|
||||
{
|
||||
FilePath = relativePath,
|
||||
FullFilePath = relativePath + "?access_token=" + _userInfo.UserToken
|
||||
});
|
||||
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
private void DealSysTemStorePath( string type, string fileRealName, out string serverFilePath, out string relativePath)
|
||||
{
|
||||
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).FullName;
|
||||
//上传根路径
|
||||
var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
|
||||
|
||||
//文件类型路径处理
|
||||
var uploadFolderPath = Path.Combine(_fileStorePath, "SysTemDocument", type);
|
||||
if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
|
||||
|
||||
|
||||
var fileNameEX = Path.GetExtension(fileRealName);
|
||||
var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
|
||||
|
||||
relativePath = $"/{StaticData.TrialDataFolder}/SysTemDocument/{type}/{trustedFileNameForFileStorage}";
|
||||
|
||||
serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
|
||||
}
|
||||
|
||||
|
||||
private void DealTrialStorePath(Guid trialId,string type,string fileRealName, out string serverFilePath, out string relativePath)
|
||||
{
|
||||
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).FullName;
|
||||
//上传根路径
|
||||
var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
|
||||
|
||||
//文件类型路径处理
|
||||
var uploadFolderPath = Path.Combine(_fileStorePath, trialId.ToString(), type);
|
||||
if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
|
||||
|
||||
|
||||
var fileNameEX = Path.GetExtension(fileRealName);
|
||||
var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
|
||||
|
||||
relativePath = $"/{StaticData.TrialDataFolder}/{trialId}/{type}/{trustedFileNameForFileStorage}";
|
||||
|
||||
serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 上传临床数据
|
||||
/// </summary>
|
||||
/// <param name="subjectVisitId"></param>
|
||||
/// <param name="uploadType"> 1:DICOM DTF 2:非DIOM DTF 3: 受试者临床数据</param>
|
||||
/// <param name="_subjectVisitRepository"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}/{type}")]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
[Obsolete]
|
||||
public async Task<IResponseOutput> UploadVisitData(Guid subjectVisitId, [FromRoute] UploadFileTypeEnum uploadType, [FromServices] IRepository<SubjectVisit> _subjectVisitRepository)
|
||||
{
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
DealStorePath(subjectVisitId, contentDisposition.FileName.Value, uploadType, out string serverFilePath, out string relativePath, _subjectVisitRepository);
|
||||
|
||||
await WriteFileAsync(section.Body, serverFilePath);
|
||||
|
||||
//仅仅返回一个文件,如果多文件上传 在最后返回多个路径
|
||||
return ResponseOutput.Ok(new
|
||||
{
|
||||
FilePath = relativePath,
|
||||
FullFilePath = relativePath + "?access_token=" + _userInfo.UserToken
|
||||
});
|
||||
|
||||
}
|
||||
section = await reader.ReadNextSectionAsync();
|
||||
}
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
}
|
||||
|
||||
public enum UploadFileTypeEnum
|
||||
{
|
||||
DICOM_DTF = 1,
|
||||
|
||||
NonDICOM_DTF = 2,
|
||||
|
||||
SubjectTreatement = 3
|
||||
}
|
||||
|
||||
private void DealStorePath(Guid subjectVisitId, string realName, UploadFileTypeEnum typeEnum, out string serverFilePath, out string relativePath, IRepository<SubjectVisit> _subjectVisitRepository)
|
||||
{
|
||||
|
||||
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).FullName;
|
||||
|
||||
//上传根路径
|
||||
var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
|
||||
|
||||
var sv = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefault();
|
||||
|
||||
//处理存储的文件夹
|
||||
var typeFolder = typeEnum == UploadFileTypeEnum.SubjectTreatement ? StaticData.TreatmenthistoryFolder
|
||||
: typeEnum == UploadFileTypeEnum.NonDICOM_DTF ? StaticData.NoneDicomFolder
|
||||
: /*typeEnum == UploadFileTypeEnum.DICOM_DTF ?*/ StaticData.DicomFolder;
|
||||
|
||||
string uploadFolderPath = Path.Combine(_fileStorePath, sv.TrialId.ToString(), sv.SiteId.ToString(), sv.SubjectId.ToString(), subjectVisitId.ToString(), typeFolder);
|
||||
|
||||
if (!Directory.Exists(uploadFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(uploadFolderPath);
|
||||
}
|
||||
|
||||
var fileNameEX = Path.GetExtension(realName);
|
||||
|
||||
var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;
|
||||
|
||||
relativePath = $"/{StaticData.TrialDataFolder}/{sv.TrialId}/{sv.SiteId}/{sv.SubjectId}/{subjectVisitId}/{typeFolder}/{trustedFileNameForFileStorage}";
|
||||
|
||||
serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
|
||||
|
||||
//处理 是上传文件返回路径 还是上传文件后,需要保存数据库
|
||||
|
||||
|
||||
if (typeEnum == UploadFileTypeEnum.SubjectTreatement)
|
||||
{
|
||||
var repository = _serviceProvider.GetService(typeof(IRepository<PreviousPDF>)) as IRepository<PreviousPDF>;
|
||||
|
||||
_= repository.InsertOrUpdateAsync(new PreviousPDFAddOrEdit() { FileName = realName, Path = relativePath, SubjectVisitId = subjectVisitId }, true).Result;
|
||||
}
|
||||
else if (typeEnum == UploadFileTypeEnum.NonDICOM_DTF)
|
||||
{
|
||||
|
||||
}
|
||||
else if (typeEnum == UploadFileTypeEnum.NonDICOM_DTF)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写文件导到磁盘
|
||||
/// </summary>
|
||||
/// <param name="stream">流</param>
|
||||
/// <param name="path">文件保存路径</param>
|
||||
/// <returns></returns>
|
||||
private static async Task<int> WriteFileAsync(System.IO.Stream stream, string path)
|
||||
{
|
||||
const int FILE_WRITE_SIZE = 84975;//写出缓冲区大小
|
||||
int writeCount = 0;
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write, FILE_WRITE_SIZE, true))
|
||||
{
|
||||
byte[] byteArr = new byte[FILE_WRITE_SIZE];
|
||||
int readCount = 0;
|
||||
while ((readCount = await stream.ReadAsync(byteArr, 0, byteArr.Length)) > 0)
|
||||
{
|
||||
await fileStream.WriteAsync(byteArr, 0, readCount);
|
||||
writeCount += readCount;
|
||||
}
|
||||
}
|
||||
return writeCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user