Merge branch 'Test.Study' into Uat.Study

Uat_Study
hang 2023-09-05 13:39:15 +08:00
commit 277ea50f4e
82 changed files with 2494 additions and 2199 deletions

25
.dockerignore Normal file
View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View File

@ -1,14 +1,8 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed.
#For more information, please see https://aka.ms/containercompat
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 7050
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
@ -29,7 +23,4 @@ RUN dotnet publish "IRaCIS.Core.API.csproj" -c Release -o /app/publish /p:UseApp
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV ASPNETCORE_ENVIRONMENT=Development
ENTRYPOINT ["dotnet", "IRaCIS.Core.API.dll"]

View File

@ -21,6 +21,10 @@ using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infrastructure;
using System.Linq;
using Microsoft.Extensions.Logging;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Sts.Model.V20150401;
using Microsoft.AspNetCore.Hosting;
namespace IRaCIS.Api.Controllers
{
@ -32,7 +36,7 @@ namespace IRaCIS.Api.Controllers
{
@ -43,7 +47,7 @@ namespace IRaCIS.Api.Controllers
/// <summary> 系统用户登录接口[New] </summary>
[HttpPost, Route("user/login")]
[AllowAnonymous]
public async Task<IResponseOutput<LoginReturnDTO>> Login(UserLoginDTO loginUser, [FromServices] IEasyCachingProvider provider, [FromServices] IUserService _userService,
public async Task<IResponseOutput<LoginReturnDTO>> Login(UserLoginDTO loginUser, [FromServices] IEasyCachingProvider provider, [FromServices] IUserService _userService,
[FromServices] ITokenService _tokenService, [FromServices] IConfiguration configuration)
{
@ -118,10 +122,10 @@ namespace IRaCIS.Api.Controllers
// 创建一个 CookieOptions 对象,用于设置 Cookie 的属性
var option = new CookieOptions
{
Expires = DateTime.Now.AddMonths(1), // 设置过期时间为 30 分钟之后
HttpOnly = false, // 确保 cookie 只能通过 HTTP 访问
Expires = DateTime.Now.AddMonths(1),
HttpOnly = true, // 确保 cookie 只能通过 HTTP 访问
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None, // 设置 SameSite 属性
Secure = false // 确保 cookie 只能通过 HTTPS 访问
Secure = true // 确保 cookie 只能通过 HTTPS 访问
};
HttpContext.Response.Cookies.Append("access_token", returnModel.Data.JWTStr, option);
@ -136,6 +140,51 @@ namespace IRaCIS.Api.Controllers
}
[HttpGet("user/GenerateSTS")]
public IResponseOutput GenerateSTS( [FromServices] IWebHostEnvironment webHostEnvironment)
{
var configuration = new ConfigurationBuilder()
.AddJsonFile($"appsettings.{webHostEnvironment.EnvironmentName}.json")
.Build();
IClientProfile profile = DefaultProfile.GetProfile("cn-shanghai", configuration["AliyunOSS:accessKeyId"], configuration["AliyunOSS:accessKeySecret"]);
DefaultAcsClient client = new DefaultAcsClient(profile);
// 创建一个STS请求
AssumeRoleRequest request = new AssumeRoleRequest
{
RoleArn = "acs:ram::1899121822495495:role/oss-upload", // 角色ARN需要替换为你的角色ARN
RoleSessionName = "session-name", // 角色会话名称,可自定义
DurationSeconds = 3600, // 令牌有效期单位这里设置为1小时
};
AssumeRoleResponse response = client.GetAcsResponse(request);
// 返回STS令牌信息给前端
var stsToken = new
{
AccessKeyId = response.Credentials.AccessKeyId,
AccessKeySecret = response.Credentials.AccessKeySecret,
SecurityToken = response.Credentials.SecurityToken,
Expiration = response.Credentials.Expiration,
Region= configuration["AliyunOSS:region"],
BucketName = configuration["AliyunOSS:accessKeyId"],
ViewEndpoint = configuration["AliyunOSS:viewEndpoint"],
};
return ResponseOutput.Ok(stsToken);
}
[HttpGet, Route("imageShare/ShareImage")]
[AllowAnonymous]
@ -162,12 +211,12 @@ namespace IRaCIS.Api.Controllers
[HttpGet("User/UserRedirect")]
[AllowAnonymous]
public async Task<IActionResult> UserRedirect([FromServices] IRepository<User> _userRepository, string url ,[FromServices]ILogger<ExtraController> _logger)
public async Task<IActionResult> UserRedirect([FromServices] IRepository<User> _userRepository, string url, [FromServices] ILogger<ExtraController> _logger)
{
var decodeUrl = System.Web.HttpUtility.UrlDecode(url);
var userId = decodeUrl.Substring(decodeUrl.IndexOf("UserId=") + "UserId=".Length , 36) ;
var userId = decodeUrl.Substring(decodeUrl.IndexOf("UserId=") + "UserId=".Length, 36);
var token = decodeUrl.Substring(decodeUrl.IndexOf("access_token=") + "access_token=".Length);
@ -175,12 +224,12 @@ namespace IRaCIS.Api.Controllers
var domainStrList = decodeUrl.Split("/").ToList().Take(3).ToList();
var errorUrl = domainStrList[0]+"//"+ domainStrList[2]+ "/error";
var errorUrl = domainStrList[0] + "//" + domainStrList[2] + "/error";
if (!await _userRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd))
if (!await _userRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd))
{
decodeUrl = errorUrl+ $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang=="zh"? "": "ErrorThe initialization link has expired. Return")} ";
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang == "zh" ? "" : "ErrorThe initialization link has expired. Return")} ";
}
return Redirect(decodeUrl);

View File

@ -440,7 +440,7 @@ namespace IRaCIS.Core.API.Controllers
#region 废弃
///// <summary>
///// 上传临床数据 多文件
@ -674,78 +674,79 @@ namespace IRaCIS.Core.API.Controllers
//public class UploadNoneDicomFileCommand
//{
// public Guid TrialId { get; set; }
// public Guid SubjectVisitId { get; set; }
// public Guid NoneDicomStudyId { get; set; }
// public Guid StudyMonitorId { get; set; }
// public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
// public class OSSFileDTO
// {
// public string FilePath { get; set; }
// public string FileName { get; set; }
// public int FileFize { get; set; }
// }
//}
///// <summary>
///// 上传非Dicom 文件 支持压缩包 多文件上传
///// </summary>
///// <param name="_noneDicomStudyRepository"></param>
///// <returns></returns>
////[DisableRequestSizeLimit]
//[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
//[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
////[Authorize(Policy = IRaCISPolicy.CRC)]
//public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
// [FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository, [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
//{
// var subjectVisitId = incommand.SubjectVisitId;
// var studyMonitorId = incommand.StudyMonitorId;
// var noneDicomStudyId = incommand.NoneDicomStudyId;
// await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
// var sv = (await _repository.Where<SubjectVisit>(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;
// foreach (var item in incommand.UploadedFileList)
// {
// await _repository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId });
// }
// var uploadFinishedTime = DateTime.Now;
// var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
// noneDicomStudy.FileCount = noneDicomStudy.FileCount + incommand.UploadedFileList.Count;
// studyMonitor.FileCount = incommand.UploadedFileList.Count;
// studyMonitor.FileSize = incommand.UploadedFileList.Sum(t => t.FileFize);
// 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();
//}
#endregion
public class UploadNoneDicomFileCommand
{
public Guid TrialId { get; set; }
public Guid SubjectVisitId { get; set; }
public Guid NoneDicomStudyId { get; set; }
public Guid StudyMonitorId { get; set; }
public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
public class OSSFileDTO
{
public string FilePath { get; set; }
public string FileName { get; set; }
public int FileFize { get; set; }
}
}
/// <summary>
/// 上传非Dicom 文件 支持压缩包 多文件上传
/// </summary>
/// <param name="_noneDicomStudyRepository"></param>
/// <returns></returns>
//[DisableRequestSizeLimit]
[HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
[FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository, [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
{
var subjectVisitId = incommand.SubjectVisitId;
var studyMonitorId = incommand.StudyMonitorId;
var noneDicomStudyId = incommand.NoneDicomStudyId;
await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
var sv = (await _repository.Where<SubjectVisit>(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;
foreach (var item in incommand.UploadedFileList)
{
await _repository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId });
}
var uploadFinishedTime = DateTime.Now;
var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));
noneDicomStudy.FileCount = noneDicomStudy.FileCount + incommand.UploadedFileList.Count;
studyMonitor.FileCount = incommand.UploadedFileList.Count;
studyMonitor.FileSize = incommand.UploadedFileList.Sum(t => t.FileFize);
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();
}
/// <summary>
/// 一致性核查 excel上传 支持三种格式
@ -771,7 +772,7 @@ namespace IRaCIS.Core.API.Controllers
(serverFilePath, relativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, fileName, trialId);
await _repository.AddAsync(new ConsistencyCheckFile()
await _repository.AddAsync(new UserUploadFile()
{
TrialId = trialId,
CreateTime = DateTime.Now,
@ -945,72 +946,6 @@ namespace IRaCIS.Core.API.Controllers
#endregion
#region 医生文件上传下载
/// <summary>医生文件上传下载</summary>
[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;
}
/// <summary>
/// 上传文件[FileUpload]
/// </summary>
/// <param name="attachmentType">附件类型</param>
/// <param name="doctorId">医生Id</param>
/// <returns>返回文件信息</returns>
[HttpPost, Route("file/UploadFile/{attachmentType}/{doctorId}")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
public async Task<IResponseOutput> UploadOrdinaryFile(string attachmentType, Guid doctorId)
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetDoctorOrdinaryFilePath(_hostEnvironment, fileName, doctorId, attachmentType));
}
/// <summary>
/// 上传文件( 不是医生个人的文件)[FileUpload]
/// 例如:阅片章程等
/// </summary>
/// <param name="type">文件类型</param>
/// <returns></returns>
[HttpPost, Route("file/UploadNonDoctorFile/{type}")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
public async Task<IResponseOutput> UploadNonDoctorFile(string type)
{
return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetNonDoctorFilePath(_hostEnvironment, fileName, type));
}
}
#endregion
#region 项目 系统 基本文件 上传 下载 预览
@ -1035,6 +970,11 @@ namespace IRaCIS.Core.API.Controllers
_userInfo = userInfo;
}
[HttpPost, Route("TrialSiteSurvey/TestOOS")]
public string TestUploadFileToOOS(string path)
{
return FileStoreHelper.UploadOOS(path, "testc/test", true);
}
[HttpPost, Route("TrialSiteSurvey/UploadTrialSiteSurveyUser")]
[DisableFormValueModelBinding]
@ -1051,10 +991,13 @@ namespace IRaCIS.Core.API.Controllers
if (!fileName.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase))
{
throw new BusinessValidationFailedException("请用提供格式的模板excel上传需要处理的数据");
// 请用提供格式的模板excel上传需要处理的数据
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_TemplateUploadData"));
}
(serverFilePath, relativePath) = FileStoreHelper.GetTrialSiteSurveyFilePath(_hostEnvironment, fileName, trialId);
(serverFilePath, relativePath) = FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName);
//FileStoreHelper.UploadOOS(serverFilePath, "testc/test", true);
return serverFilePath;
});
@ -1066,32 +1009,41 @@ namespace IRaCIS.Core.API.Controllers
if (excelList.Any(t => string.IsNullOrWhiteSpace(t.TrialSiteCode) || string.IsNullOrWhiteSpace(t.FirstName) || string.IsNullOrWhiteSpace(t.LastName) || string.IsNullOrWhiteSpace(t.Email) || string.IsNullOrWhiteSpace(t.UserTypeStr)))
{
throw new BusinessValidationFailedException("请确保Excel中 每一行的 中心编号,姓名,邮箱,用户类型数据记录完整再进行上传");
//请确保Excel中 每一行的 中心编号,姓名,邮箱,用户类型数据记录完整再进行上传
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_EnsureCompleteData"));
}
var siteCodeList = excelList.Select(t => t.TrialSiteCode.Trim().ToUpper()).Distinct().ToList();
if (_trialSiteRepository.Where(t => t.TrialId==trialId && siteCodeList.Contains(t.TrialSiteCode.ToUpper())).Count() != siteCodeList.Count)
if (_trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode.ToUpper())).Count() != siteCodeList.Count)
{
throw new BusinessValidationFailedException("在项目中未找到该Excel中部分或全部中心");
//在项目中未找到该Excel中部分或全部中心
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidCenters"));
}
if (excelList.GroupBy(t => new { t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
if (excelList.GroupBy(t => new {t.TrialSiteCode, t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
{
throw new BusinessValidationFailedException("同一邮箱,同一用户类型,只能生成一个账户,请核查Excel数据");
// 同一邮箱,同一用户类型,只能生成一个账户,请核查Excel数据
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_CheckDuplicateAccounts"));
}
if (excelList.Any(t => !t.Email.Contains("@")))
{
throw new BusinessValidationFailedException("有邮箱不符合邮箱格式,请核查Excel数据");
//有邮箱不符合邮箱格式,请核查Excel数据
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidEmail"));
}
var generateUserTypeList = new List<string>() { "CRC", "SR", "CRA" };
if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
{
throw new BusinessValidationFailedException("用户类型仅能为 CRC,SR,CRA 请核查Excel数据");
//用户类型仅能为 CRC,SR,CRA 请核查Excel数据
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidUserType"));
}
if (excelList.Count == 0)
{
throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_NoValiddata"));
}
//处理好 用户类型 和用户类型枚举
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.SR).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();
@ -1121,10 +1073,13 @@ namespace IRaCIS.Core.API.Controllers
item.SiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).SiteId;
}
await _trialSiteSurveyService.ImportGenerateAccountAndJoinTrialAsync(trialId, baseUrl, routeUrl, excelList.ToList());
return ResponseOutput.Ok();
}
@ -1262,17 +1217,19 @@ namespace IRaCIS.Core.API.Controllers
public enum UploadFileType
{
DataUpload=1,
DataUpload = 1,
DataDownload=2,
DataDownload = 2,
EmailAttachment=3,
EmailAttachment = 3,
EmailBodyHtml=4,
EmailBodyHtml = 4,
Other = 5
}
/// <summary>
/// 数据上传、导出、 邮件附件 、邮件Html 通过 ----new
/// 1数据上传 2导出、 3邮件附件 4邮件Html 通过 ----new
/// </summary>
/// <returns></returns>
[HttpPost("SystemFile/Upload")]
@ -1283,25 +1240,27 @@ namespace IRaCIS.Core.API.Controllers
IResponseOutput result = null;
switch (fileType)
{
{
case UploadFileType.DataUpload:
result= await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate,fileName));
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));
break;
case UploadFileType.DataDownload:
result= await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate,fileName));
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));
break;
case UploadFileType.EmailAttachment:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
break;
case UploadFileType.EmailBodyHtml:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailHtmlTemplate, fileName));
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
break;
default:
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));
break;
}

View File

@ -0,0 +1,26 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["IRaCIS.Core.API/IRaCIS.Core.API.csproj", "IRaCIS.Core.API/"]
COPY ["IRaCIS.Core.Application/IRaCIS.Core.Application.csproj", "IRaCIS.Core.Application/"]
COPY ["IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj", "IRaCIS.Core.Infra.EFCore/"]
COPY ["IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj", "IRaCIS.Core.Domain/"]
COPY ["IRaCIS.Core.Domain.Share/IRaCIS.Core.Domain.Share.csproj", "IRaCIS.Core.Domain.Share/"]
COPY ["IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj", "IRaCIS.Core.Infrastructure/"]
RUN dotnet restore "IRaCIS.Core.API/IRaCIS.Core.API.csproj"
COPY . .
WORKDIR "/src/IRaCIS.Core.API"
RUN dotnet build "IRaCIS.Core.API.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "IRaCIS.Core.API.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "IRaCIS.Core.API.dll"]

View File

@ -5,7 +5,7 @@
<SignAssembly>false</SignAssembly>
<UserSecretsId>354572d4-9e15-4099-807c-63a2d29ff9f2</UserSecretsId>
<LangVersion>default</LangVersion>
<DockerDefaultTargetOS>Windows</DockerDefaultTargetOS>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<Version>1.0.1.001</Version>
<Company>上海展影医疗科技有限公司</Company>
<Product>IRC影像系统 (EICS)</Product>
@ -66,6 +66,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="aliyun-net-sdk-sts" Version="3.1.1" />
<PackageReference Include="AspNetCoreRateLimit" Version="4.0.2" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
@ -80,7 +81,6 @@
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.6.2" />
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.6.2" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />

View File

@ -212,6 +212,13 @@
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(System.Guid,System.Guid,System.String,System.Nullable{System.Guid},System.Guid,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Core.Application.Contracts.IStudyService,Microsoft.AspNetCore.SignalR.IHubContext{IRaCIS.Core.API.UploadHub,IRaCIS.Core.API.IUploadClient},IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
<summary>Dicom 归档</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFile(IRaCIS.Core.API.Controllers.StudyController.UploadNoneDicomFileCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.StudyMonitor})">
<summary>
上传非Dicom 文件 支持压缩包 多文件上传
</summary>
<param name="_noneDicomStudyRepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid)">
<summary>
一致性核查 excel上传 支持三种格式
@ -219,25 +226,6 @@
<param name="trialId"></param>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.API.Controllers.FileController">
<summary>医生文件上传下载</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.FileController.UploadOrdinaryFile(System.String,System.Guid)">
<summary>
上传文件[FileUpload]
</summary>
<param name="attachmentType">附件类型</param>
<param name="doctorId">医生Id</param>
<returns>返回文件信息</returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.FileController.UploadNonDoctorFile(System.String)">
<summary>
上传文件( 不是医生个人的文件)[FileUpload]
例如:阅片章程等
</summary>
<param name="type">文件类型</param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadCommonDoc">
<summary>
上传通用文档 比如一致性核查的 比如导出的excel 模板
@ -246,7 +234,7 @@
</member>
<member name="M:IRaCIS.Core.API.Controllers.UploadDownLoadController.Upload(IRaCIS.Core.API.Controllers.UploadDownLoadController.UploadFileType)">
<summary>
数据上传、导出、 邮件附件 、邮件Html 通过 ----new
1数据上传 2导出、 3邮件附件 4邮件Html 通过 ----new
</summary>
<returns></returns>
</member>

View File

@ -13,6 +13,8 @@ using System.IO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Application.Services.BackGroundJob;
using Hangfire;
namespace IRaCIS.Core.API
{
@ -59,17 +61,10 @@ namespace IRaCIS.Core.API
Log.Logger.Warning($"当前环境:{enviromentName}");
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
//缓存项目的状态 匿名化数据
await InitCache(host);
////缓存项目的状态 匿名化数据
//await InitCache(host);
host.Run();
@ -107,15 +102,7 @@ namespace IRaCIS.Core.API
var _repository = host.Services.GetService(typeof(IRepository)) as IRepository;
//初始化 国际化数据,并且监测国际化文件变更
await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_repository);
var _mediator = host.Services.GetService(typeof(IMediator)) as IMediator;
await _mediator.Send(new AnonymizeCacheRequest());
await _mediator.Send(new TrialStateCacheRequest());
//await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_repository);
}

View File

@ -1,29 +1,6 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:3305",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
//"IRaCIS.Development": {
// "commandName": "Project",
// "launchBrowser": true,
// "environmentVariables": {
// "ASPNETCORE_ENVIRONMENT": "Development"
// },
// "applicationUrl": "http://localhost:6100"
//},
"profiles": {
"Docker": {
"commandName": "Docker",
"launchBrowser": true,

View File

@ -24,6 +24,11 @@ using Invio.Extensions.Authentication.JwtBearer;
using Microsoft.AspNetCore.SignalR;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.StaticFiles;
using IRaCIS.Application.Services.BackGroundJob;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Http;
using Autofac.Core;
using DocumentFormat.OpenXml.InkML;
namespace IRaCIS.Core.API
{
@ -89,7 +94,7 @@ namespace IRaCIS.Core.API
})
.AddNewtonsoftJsonSetup(); // NewtonsoftJson 序列化 处理
services.AddOptions().Configure<SystemEmailSendConfig>( _configuration.GetSection("SystemEmailSendConfig"));
services.AddOptions().Configure<SystemEmailSendConfig>(_configuration.GetSection("SystemEmailSendConfig"));
services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
@ -162,8 +167,10 @@ namespace IRaCIS.Core.API
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//app.UsePathBase(PathString.FromUriComponent("/api"));
//本地化
app.UseLocalization();
@ -179,7 +186,7 @@ namespace IRaCIS.Core.API
//LogDashboard
app.UseLogDashboard("/LogDashboard");
app.UseLogDashboard("/back/logs");
//hangfire
app.UseHangfireConfig(env);
@ -208,7 +215,7 @@ namespace IRaCIS.Core.API
app.UseStatusCodePagesWithReExecute("/Error/{0}");
SwaggerSetup.Configure(app, env);
////serilog 记录请求的用户信息
@ -236,6 +243,14 @@ namespace IRaCIS.Core.API
endpoints.MapHub<UploadHub>("/UploadHub");
});
var hangfireJobService = app.ApplicationServices.GetRequiredService<IIRaCISHangfireJob>();
await hangfireJobService.InitHangfireJobTaskAsync();
//ÓеÄʱºòÿµ÷ÓÃ
//HangfireJobHelper.NotImmediatelyOnceOnlyJob<IIRaCISHangfireJob>(t => t.InitHangfireJobTaskAsync(),TimeSpan.FromSeconds(1));
}
}
}

View File

@ -1,7 +1,13 @@
using Hangfire.Dashboard;
using System.IdentityModel.Tokens.Jwt;
using System;
using System.Linq;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.API.Filter
{
//从cookie 中取值
public class hangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
@ -11,7 +17,23 @@ namespace IRaCIS.Core.API.Filter
// Allow all authenticated users to see the Dashboard (potentially dangerous).
//return httpContext.User.Identity.IsAuthenticated;
return true;
var jwtToken = httpContext.Request.Cookies["access_token"]?.ToString();
var handler = new JwtSecurityTokenHandler();
if (handler.CanReadToken(jwtToken))
{
var jwtSecurityToken = handler.ReadJwtToken(jwtToken);
return jwtSecurityToken.Claims.Any(t => t.Type == JwtIRaCISClaimType.UserTypeEnum && (t.Value == UserTypeEnum.Admin.ToString()|| t.Value== UserTypeEnum.SuperAdmin.ToString()));
}
else
{
return false;
}
}
}
}

View File

@ -3,6 +3,7 @@ using Hangfire.Dashboard;
using Hangfire.Dashboard.BasicAuthorization;
using IRaCIS.Application.Services.BackGroundJob;
using IRaCIS.Core.API.Filter;
using IRaCIS.Core.Application.Helper;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@ -17,43 +18,48 @@ namespace IRaCIS.Core.API
{
app.UseHangfireDashboard("/api/hangfire", new DashboardOptions()
app.UseHangfireDashboard("/back/hangfire", new DashboardOptions()
{
//直接访问没有带token 获取不到用户身份信息,所以这种自定义授权暂时没法使用
//Authorization = new[] { new hangfireAuthorizationFilter() }
//本地请求 才能看
//Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() }
Authorization = new BasicAuthAuthorizationFilter[] {
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
Authorization = new IDashboardAuthorizationFilter[] { /*new hangfireAuthorizationFilter(),*/
new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
SslRedirect=false,
RequireSsl=false,
Users=new BasicAuthAuthorizationUser[]{
new BasicAuthAuthorizationUser(){
Login="admin",
PasswordClear="test",
PasswordClear="admin",
}
}
})
}
},
DashboardTitle ="后台任务管理",
//Authorization = new BasicAuthAuthorizationFilter[] {
// new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){
// SslRedirect=false,
// RequireSsl=false,
// Users=new BasicAuthAuthorizationUser[]{
// new BasicAuthAuthorizationUser(){
// Login="admin",
// PasswordClear="test",
// }
// }
// })
//}
});
#region hangfire
//// 延迟任务执行 1秒之后执行 有时启动没运行 换成添加到队列中
//BackgroundJob.Schedule<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus(), TimeSpan.FromSeconds(1));
////添加到后台任务队列,
//BackgroundJob.Enqueue<ICacheTrialStatusJob>(t => t.MemoryCacheTrialStatus());
//周期性任务1天执行一次
//RecurringJob.AddOrUpdate<IIRaCISCacheHangfireJob>(t => t.ProjectStartCache(), Cron.Daily);
#endregion
}
}

View File

@ -13,7 +13,7 @@ namespace IRaCIS.Core.API
services.AddLogDashboard(opt =>
{
//opt.PathMatch = "/api/LogDashboard";
opt.PathMatch = "/LogDashboard";
opt.PathMatch = "/back/logs";
//opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));

View File

@ -6,11 +6,10 @@ using Quartz;
namespace IRaCIS.Core.API
{
public static class QuartZSetup
public static class QuartZSetup
{
public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration)
{
services.AddTransient<CacheTrialStatusQuartZJob>();
services.AddTransient<CancelTaskQuartZJob>();
services.AddQuartz(q =>
@ -21,16 +20,17 @@ namespace IRaCIS.Core.API
q.UseMicrosoftDependencyInjectionJobFactory();
// 基本Quartz调度器、作业和触发器配置
var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
.WithDescription("Trial regular work")
);
q.AddTrigger(t => t
.WithIdentity("TrialStatusTrigger")
.ForJob(jobKey)
.WithCronSchedule("0 0 * * * ?")
.WithDescription("My regular trial work trigger")
);
//var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup");
//q.AddJob<CacheTrialStatusQuartZJob>(jobKey, j => j
// .WithDescription("Trial regular work")
//);
//q.AddTrigger(t => t
// .WithIdentity("TrialStatusTrigger")
// .ForJob(jobKey)
// .WithCronSchedule("0 0 * * * ?")
// .WithDescription("My regular trial work trigger")
//);

View File

@ -20,7 +20,7 @@ namespace IRaCIS.Core.API
//指定存储介质
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
{
SchemaName = "hangfire",
SchemaName = "dbo",
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
@ -33,7 +33,10 @@ namespace IRaCIS.Core.API
});
services.AddHangfireServer();
services.AddHangfireServer(option =>
{
option.Queues = new[] { "immediately_once","default","sys_init" , "not_immediately_once" };
});
}
}

View File

@ -6,6 +6,15 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AliyunOSS": {
"regionId": "cn-shanghai",
"region": "oss-cn-shanghai",
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zyypacs",
"viewEndpoint": "https://zyypacs.oss-cn-shanghai.aliyuncs.com"
},
"ConnectionStrings": {
"RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Test.Study;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true",
"Hangfire": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Test.Study.hangfire;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true"
@ -23,7 +32,6 @@
"LoginFailLockMinutes": 30
},
"SystemEmailSendConfig": {
@ -31,7 +39,9 @@
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "test-study@extimaging.com",
"FromName": "Test_Study",
"AuthorizationCode": "zhanying123"
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://test.study.extimaging.com/login"
}
}

View File

@ -6,6 +6,15 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AliyunOSS": {
"regionId": "cn-shanghai",
"region": "oss-cn-shanghai",
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
"bucketName": "zyypacs",
"viewEndpoint": "https://zyypacs.oss-cn-shanghai.aliyuncs.com"
},
"ConnectionStrings": {
"RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Uat.Study;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true",
"Hangfire": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Uat.Study.hangfire;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true"
@ -23,7 +32,6 @@
"LoginFailLockMinutes": 30
},
"SystemEmailSendConfig": {
@ -31,7 +39,8 @@
"Host": "smtp.qiye.aliyun.com",
"FromEmail": "uat-study@extimaging.com",
"FromName": "Uat_Study",
"AuthorizationCode": "zhanying123"
"AuthorizationCode": "zhanying123",
"SiteUrl": "http://uat.study.extimaging.com/login"
}
}

View File

@ -19,6 +19,7 @@
"EndpointWhitelist": [
"post:/study/archivestudy/*"
],
"IpWhitelist": [],
"GeneralRules": [
{

View File

@ -38,7 +38,6 @@
</div>
</div>
<div style='line-height: 24px;font-size: 14px;color:#333;margin-top: 20px;padding-bottom: 40px;'>
<div>祝您顺利!/Best Regards</div>
<div style="font-size: 14px;">展影医疗</div>

View File

@ -1,72 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using EasyCaching.Core;
using IRaCIS.Core.Domain;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Models;
using Microsoft.Extensions.Logging;
using Quartz;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Application.Services.BackGroundJob
{
public class CacheTrialStatusQuartZJob: IJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<CacheTrialStatusQuartZJob> _logger;
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
public CacheTrialStatusQuartZJob(IRepository<Trial> trialRepository, IEasyCachingProvider provider,ILogger<CacheTrialStatusQuartZJob> logger, IRepository<SystemAnonymization> systemAnonymizationRepository)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_systemAnonymizationRepository = systemAnonymizationRepository;
}
public async Task Execute(IJobExecutionContext context)
{
_logger.LogInformation($"开始执行QuartZ定时任务作业");
try
{
await MemoryCacheTrialStatus();
await MemoryCacheAnonymizeData();
}
catch (Exception e)
{
_logger.LogError($" 查询和缓存过程出现异常"+e.Message);
}
_logger.LogInformation("QuartZ定时任务作业结束");
}
public async Task MemoryCacheTrialStatus()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
public async Task MemoryCacheAnonymizeData()
{
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
}
}
}

View File

@ -0,0 +1,200 @@
using EasyCaching.Core;
using Hangfire;
using Hangfire.Storage;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace IRaCIS.Application.Services.BackGroundJob
{
public interface IIRaCISHangfireJob
{
Task MemoryCacheTrialStatusAsync();
Task InitHangfireJobTaskAsync();
}
public class IRaCISCHangfireJob : IIRaCISHangfireJob
{
public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources);
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<IRaCISCHangfireJob> _logger;
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<Internationalization> _internationalizationRepository;
public IRaCISCHangfireJob(IRepository<Trial> trialRepository, ILogger<IRaCISCHangfireJob> logger, IEasyCachingProvider provider, IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<Internationalization> internationalizationRepository)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_internationalizationRepository = internationalizationRepository;
}
public async Task InitHangfireJobTaskAsync()
{
_logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~");
//项目状态 立即加载到缓存中
await MemoryCacheTrialStatusAsync();
//创建项目缓存 定时任务
HangfireJobHelper.AddOrUpdateInitCronJob<IIRaCISHangfireJob>("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily());
//初始化
await InitInternationlizationDataAndWatchJsonFileAsync();
//创建邮件定时任务
await InitSysAndTrialCronJobAsync();
_logger.LogInformation("项目启动 hangfire 任务初始化 执行结束");
}
/// <summary>
/// 缓存项目状态
/// </summary>
/// <returns></returns>
public async Task MemoryCacheTrialStatusAsync()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
#region 国际化 初始化
public async Task InitInternationlizationDataAndWatchJsonFileAsync()
{
//查询数据库的数据
var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new
{
t.Code,
t.Value,
t.ValueCN
}).ToListAsync();
//组织成json 文件
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
//本地静态文件国际化需要
foreach (var tojsonItem in toJsonList)
{
StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value;
StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN;
}
File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic));
File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic));
//监测Json文件变更 实时刷新数据
WatchJsonFile(usJsonPath);
WatchJsonFile(cnJsonPath);
}
public void WatchJsonFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new BusinessValidationFailedException(StaticData.International("IRaCISCHangfireJob_FileNotFound"));
}
FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath));
watcher.Changed += (sender, e) => LoadJsonFile(filePath);
watcher.EnableRaisingEvents = true;
}
private void LoadJsonFile(string filePath)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath);
IConfigurationRoot enConfiguration = builder.Build();
foreach (IConfigurationSection section in enConfiguration.GetChildren())
{
if (filePath.Contains(StaticData.En_US_Json))
{
StaticData.En_US_Dic[section.Key] = section.Value;
}
else
{
StaticData.Zh_CN_Dic[section.Key] = section.Value;
}
}
}
#endregion
public async Task InitSysAndTrialCronJobAsync()
{
//var deleteJobIdList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr != StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
// .Select(t => t.TrialId + "_" + t.Id)
// .ToListAsync();
//foreach (var jobId in deleteJobIdList)
//{
// HangfireJobHelper.RemoveCronJob(jobId);
//}
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
.ToListAsync();
foreach (var task in taskInfoList)
{
//利用主键作为任务Id
var jobId = $"{task.TrialId}_{task.Id}";
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, task.TrialId, task.BusinessScenarioEnum, task.EmailCron);
}
var addOrUpdateJobIdList = taskInfoList.Select(t => $"{t.TrialId}_{t.Id}").ToList();
var list = JobStorage.Current.GetConnection().GetRecurringJobs().ToList();
//项目定时任务都在default 队列
//var dbJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Where(t => t.Queue == "default").Select(t => t.Id).ToList();
//var deleteList= dbJobIdList.Except(addOrUpdateJobIdList).ToList();
// foreach (var jobId in deleteList)
// {
// HangfireJobHelper.RemoveCronJob(jobId);
// }
}
}
}

View File

@ -1,99 +0,0 @@
using EasyCaching.Core;
using IRaCIS.Core.Domain.Share;
using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
using Microsoft.Extensions.Logging;
namespace IRaCIS.Application.Services.BackGroundJob
{
public interface IIRaCISCacheHangfireJob
{
Task ProjectStartCache();
Task MemoryCacheTrialStatus();
Task MemoryCacheAnonymizeData();
Task CacheUserTypePermission(Guid? cacheUserTypeId);
}
public class IRaCISCacheHangfireJob: IIRaCISCacheHangfireJob
{
private readonly IRepository<Trial> _trialRepository;
private readonly IEasyCachingProvider _provider;
private readonly ILogger<IRaCISCacheHangfireJob> _logger;
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
private readonly IRepository<UserTypeMenu> _userTypeMenuRepository;
public IRaCISCacheHangfireJob(IRepository<Trial> trialRepository,
IRepository<SystemAnonymization> systemAnonymizationRepository, IRepository<UserTypeMenu> userTypeMenuRepository,
IEasyCachingProvider provider,ILogger<IRaCISCacheHangfireJob> logger)
{
_trialRepository = trialRepository;
_provider = provider;
_logger = logger;
_systemAnonymizationRepository = systemAnonymizationRepository;
_userTypeMenuRepository = userTypeMenuRepository;
}
public async Task ProjectStartCache()
{
_logger.LogInformation("hangfire 定时缓存项目状态任务开始~");
try
{
await MemoryCacheTrialStatus();
await MemoryCacheAnonymizeData();
await CacheUserTypePermission();
}
catch (Exception e)
{
_logger.LogError("hangfire 定时任务执行失败" + e.Message);
}
_logger.LogInformation("hangfire 定时任务执行结束");
}
public async Task MemoryCacheTrialStatus()
{
var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr })
.ToListAsync();
list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7)));
}
public async Task MemoryCacheAnonymizeData()
{
var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
_provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7));
_provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7));
}
public async Task CacheUserTypePermission(Guid? cacheUserTypeId=null)
{
var permissionList = await _userTypeMenuRepository.Where(t => t.Menu.MenuType == "F")
.WhereIf(cacheUserTypeId != null, t => t.UserTypeId == cacheUserTypeId.Value).Select(t => new { t.UserTypeId, t.Menu.PermissionStr }).ToListAsync();
foreach (var userTypeGroup in permissionList.GroupBy(t => t.UserTypeId))
{
_provider.Set($"{StaticData.CacheKey.UserTypeId}_{userTypeGroup.Key}", userTypeGroup.Select(t => t.PermissionStr).ToList(), TimeSpan.FromDays(7));
}
}
}
}

View File

@ -1,10 +1,14 @@

using Aliyun.OSS;
using Aliyun.OSS.Util;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace IRaCIS.Core.Application.Helper;
@ -12,6 +16,89 @@ namespace IRaCIS.Core.Application.Helper;
public static class FileStoreHelper
{
/// <summary>
/// 上传文件到OOS
/// </summary>
/// <param name="filePath">本地文件路径</param>
/// <param name="oosPath">OOS路径例如(test/test)</param>
/// <param name="isDeleteOriginalFile">是否删除本地文件</param>
/// <returns>返回文件路径</returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public static string UploadOOS(string filePath,string oosPath, bool isDeleteOriginalFile)
{
var config = new ConfigurationBuilder()
.AddEnvironmentVariables()
.Build();
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
var configuration = new ConfigurationBuilder()
.AddJsonFile($"appsettings.{enviromentName}.json")
.Build();
var endpoint = configuration.GetSection("AliyunOSS:endpoint").Value;
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1杭州为例Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
// 阿里云账号AccessKey拥有所有API的访问权限风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维请登录RAM控制台创建RAM用户。
var accessKeyId = configuration.GetSection("AliyunOSS:accessKeyId").Value;
var accessKeySecret = configuration.GetSection("AliyunOSS:accessKeySecret").Value;
// 填写Bucket名称例如examplebucket。
var bucketName = configuration.GetSection("AliyunOSS:bucketName").Value;
// 填写Object完整路径完整路径中不能包含Bucket名称例如exampledir/exampleobject.txt。
var fileNameList = filePath.Split('\\').ToList();
var fileName = fileNameList[fileNameList.Count() - 1];
if (oosPath != string.Empty)
{
fileName = oosPath + "/" + fileName;
}
var objectName = fileName;
// 填写本地文件完整路径例如D:\\localpath\\examplefile.txt。如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。
var localFilename = filePath;
// 创建OSSClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
// 上传文件。
var result = client.PutObject(bucketName, objectName, localFilename);
var expiration = DateTime.Now.AddYears(1);
var url = client.GeneratePresignedUri(bucketName, objectName, expiration).ToString();
if (File.Exists(filePath)&& isDeleteOriginalFile)
{
// 删除文件
File.Delete(filePath);
}
return url;
}
catch (Exception ex)
{
throw new BusinessValidationFailedException("上传异常!");
}
}
private static ObjectMetadata BuildCallbackMetadata(string callbackUrl, string callbackBody)
{
string callbackHeaderBuilder = new CallbackHeaderBuilder(callbackUrl, callbackBody).Build();
string CallbackVariableHeaderBuilder = new CallbackVariableHeaderBuilder().
AddCallbackVariable("x:var1", "x:value1").AddCallbackVariable("x:var2", "x:value2").Build();
var metadata = new ObjectMetadata();
metadata.AddHeader(HttpHeaders.Callback, callbackHeaderBuilder);
metadata.AddHeader(HttpHeaders.CallbackVar, CallbackVariableHeaderBuilder);
return metadata;
}
private static string GetCallbackResponse(PutObjectResult putObjectResult)
{
string callbackResponse = null;
using (var stream = putObjectResult.ResponseStream)
{
var buffer = new byte[4 * 1024];
var bytesRead = stream.Read(buffer, 0, buffer.Length);
callbackResponse = Encoding.Default.GetString(buffer, 0, bytesRead);
}
return callbackResponse;
}
//处理文件名 压缩包,或者目录类的 会带上相对路径
public static (string TrustedFileNameForFileStorage, string RealName) GetStoreFileName(string fileName,bool isChangeToPdfFormat=false)
@ -41,12 +128,12 @@ public static class FileStoreHelper
if (isChangeToPdfFormat==false)
{
trustedFileNameForFileStorage= Guid.NewGuid().ToString() + fileName;
trustedFileNameForFileStorage= Path.GetFileNameWithoutExtension(fileName) + Guid.NewGuid().ToString()+Path.GetExtension(fileName) ;
}
else
{
trustedFileNameForFileStorage=Guid.NewGuid().ToString() + Path.GetFileNameWithoutExtension(fileName) + ".pdf";
trustedFileNameForFileStorage= Path.GetFileNameWithoutExtension(fileName) + Guid.NewGuid().ToString() + ".pdf";
}
return (trustedFileNameForFileStorage, fileName);
@ -227,6 +314,8 @@ public static class FileStoreHelper
return (serverFilePath, relativePath);
}
#region 修改后留存
public static (string PhysicalPath, string RelativePath) GetSystemFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName)
{
@ -247,6 +336,30 @@ public static class FileStoreHelper
return (serverFilePath, relativePath);
}
public static (string PhysicalPath, string RelativePath) GetOtherFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName)
{
var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
//文件类型路径处理
var uploadFolderPath = Path.Combine(rootPath, StaticData.Folder.OtherDataFolder, templateFolderName);
if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath);
var (trustedFileNameForFileStorage, fileRealName) = FileStoreHelper.GetStoreFileName(fileName);
var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.OtherDataFolder}/{templateFolderName}/{trustedFileNameForFileStorage}";
var serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);
return (serverFilePath, relativePath);
}
#endregion
// 获取通用文档存放路径excel模板

View File

@ -0,0 +1,92 @@
using Hangfire;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Domain.Share;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class HangfireJobHelper
{
//public static void AddOrUpdateCronJob(string jobId, string queueName, Expression<Action> methodCall, string cron)
//{
// RecurringJob.AddOrUpdate(jobId, queueName, methodCall, cron);
//}
//添加 或者更新定时任务 Id 要唯一标识一个定义任务
public static void AddOrUpdateCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron, string queueName = "default")
{
RecurringJob.AddOrUpdate<T>(jobId, queueName, methodCall, cron);
}
public static void AddOrUpdateInitCronJob<T>(string jobId, Expression<Action<T>> methodCall, string cron)
{
RecurringJob.AddOrUpdate<T>(jobId, "sys_init", methodCall, cron);
}
public static void RemoveCronJob(string jobId)
{
RecurringJob.RemoveIfExists(jobId);
}
public static void ImmediatelyOnceOnlyJob(Expression<Action> methodCall)
{
BackgroundJob.Enqueue("immediately_once", methodCall);
}
public static void ImmediatelyOnceOnlyJob<T>(Expression<Action<T>> methodCall)
{
BackgroundJob.Enqueue<T>("immediately_once", methodCall);
}
public static void NotImmediatelyOnceOnlyJob(Expression<Action> methodCall, TimeSpan timeSpan)
{
BackgroundJob.Schedule("not_immediately_once", methodCall, timeSpan);
}
public static void NotImmediatelyOnceOnlyJob<T>(Expression<Action<T>> methodCall, TimeSpan timeSpan)
{
BackgroundJob.Schedule<T>("not_immediately_once", methodCall, timeSpan);
}
public static void AddOrUpdateTrialCronJob (string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron)
{
switch (businessScenario)
{
case EmailBusinessScenario.QCTask:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron);
break;
case EmailBusinessScenario.QCQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron);
break;
case EmailBusinessScenario.ImageQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IEmailSendService>(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron);
break;
default:
break;
}
}
}
}

View File

@ -22,7 +22,7 @@ namespace IRaCIS.Core.Application.Helper
if (!Directory.Exists(JsonFileFolder) ||
!Directory.GetFiles(JsonFileFolder).Any(filePath => Path.GetExtension(filePath).Equals(".json", StringComparison.OrdinalIgnoreCase)))
{
throw new BusinessValidationFailedException("国际化Json文件目录有误");
throw new BusinessValidationFailedException(StaticData.International("InternationalizationHelper_PathError"));
}
}
@ -106,73 +106,8 @@ namespace IRaCIS.Core.Application.Helper
}
public static async Task InitInternationlizationDataAndWatchJsonFileAsync(IRepository _repository)
{
//查询数据库的数据
var toJsonList = await _repository.Where<Internationalization>(t => t.InternationalizationType == 1).Select(t => new
{
t.Code,
t.Value,
t.ValueCN
}).ToListAsync();
//组织成json 文件
var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json);
var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json);
//本地静态文件国际化需要
foreach (var tojsonItem in toJsonList)
{
StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value;
StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN;
}
File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic));
File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic));
//监测Json文件变更 实时刷新数据
WatchJsonFile(usJsonPath);
WatchJsonFile(cnJsonPath);
}
public static void WatchJsonFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new BusinessValidationFailedException("国际化Json文件不存在");
}
FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath));
watcher.Changed += (sender, e) => LoadJsonFile(filePath);
watcher.EnableRaisingEvents = true;
}
private static void LoadJsonFile(string filePath)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath);
IConfigurationRoot enConfiguration = builder.Build();
foreach (IConfigurationSection section in enConfiguration.GetChildren())
{
if (filePath.Contains(StaticData.En_US_Json))
{
StaticData.En_US_Dic[section.Key] = section.Value;
}
else
{
StaticData.Zh_CN_Dic[section.Key] = section.Value;
}
}
}
}
}

View File

@ -144,6 +144,9 @@ public static class SendEmailHelper
}
}
}

View File

@ -63,6 +63,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
<PackageReference Include="AutoMapper.Collection.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.1" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
@ -75,6 +76,7 @@
<PackageReference Include="fo-dicom.Drawing" Version="4.0.8" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.0.3" />
<PackageReference Include="FreeSpire.Doc" Version="10.8.0" />
<PackageReference Include="Hangfire.Core" Version="1.8.5" />
<PackageReference Include="Magicodes.IE.Core" Version="2.7.4.2" />
<PackageReference Include="Magicodes.IE.Csv" Version="2.7.4.2">
<TreatAsUsed>true</TreatAsUsed>

View File

@ -34,6 +34,16 @@
主要为了 处理项目结束 锁库,不允许操作
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Helper.FileStoreHelper.UploadOOS(System.String,System.String,System.Boolean)">
<summary>
上传文件到OOS
</summary>
<param name="filePath">本地文件路径</param>
<param name="oosPath">OOS路径例如(test/test)</param>
<param name="isDeleteOriginalFile">是否删除本地文件</param>
<returns>返回文件路径</returns>
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
</member>
<member name="M:IRaCIS.Core.Application.Helper.FileStoreHelper.GetSystemClinicalPathAsync(Microsoft.AspNetCore.Hosting.IWebHostEnvironment,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataSystemSet},System.Guid)">
<summary>
@ -531,6 +541,27 @@
PublishLogService
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialImageQCTaskEmailAsync(System.Guid)">
<summary>
影像质控
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialQCQuestionEmailAsync(System.Guid)">
<summary>
QC质疑
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.EmailSendService.SendTrialImageQuestionAsync(System.Guid)">
<summary>
影像质疑
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService">
<summary>
TrialEmailNoticeConfigService
@ -552,7 +583,7 @@
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.SyncSystemEmainCofigDocListAsync(System.Guid)">
<summary>
同步系统配置的文档到想项目中
同步系统配置的文档到想项目中 ---废弃
</summary>
<param name="trialId"></param>
<returns></returns>
@ -602,6 +633,27 @@
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.GetTrialUserIdSelectList(System.Guid)">
<summary>
黑名单用户Id 列表
</summary>
<param name="trialEmailNoticeConfigId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.GetSysEmailNoticeConfigList(IRaCIS.Core.Application.Contracts.EmailNoticeConfigQuery)">
<summary>
获取系统 邮件配置 勾选列表
</summary>
<param name="queryEmailNoticeConfig"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.BatchAddSysEmailConfig(System.Collections.Generic.List{IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig})">
<summary>
批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系
</summary>
<param name="batchAddList"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.Preview(System.Guid)">
<summary> 指定资源Id渲染Dicom检查的Jpeg预览图像 </summary>
<param name="studyId"> Dicom检查的Id </param>
@ -2508,6 +2560,20 @@
<param name="id"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ClinicalQuestionService.GetSystemClinicalOtherTableQuestionList(IRaCIS.Core.Application.Service.Reading.Dto.GetClinicalOtherTableQuestionListInDto)">
<summary>
获取系统其他表格问题
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ClinicalQuestionService.GetTrialClinicalOtherTableQuestionList(IRaCIS.Core.Application.Service.Reading.Dto.GetClinicalOtherTableQuestionListInDto)">
<summary>
获取项目其他表格问题
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ClinicalQuestionService.GetTrialClinicalTableQuestionList(IRaCIS.Core.Application.Service.Reading.Dto.TrialClinicalTableQuestionQuery)">
<summary>
获取项目表格问题
@ -3166,6 +3232,16 @@
单位
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ClinicalTableQuestionBase.RelevanceId">
<summary>
关联ID
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ClinicalTableQuestionBase.RelevanceValue">
<summary>
关联Value
</summary>
</member>
<member name="T:IRaCIS.Core.Application.Service.Reading.Dto.TrialClinicalTableQuestionDto">
<summary>
项目临床数据问题
@ -8067,6 +8143,27 @@
<member name="T:IRaCIS.Core.Application.ViewModel.TrialEmailNoticeConfigQuery">
<summary>TrialEmailNoticeConfigQuery 列表查询参数模型</summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.BusinessModuleEnum">
<summary> 业务模块 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.BusinessLevelEnum">
<summary> 业务层级 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailTypeEnum">
<summary> 邮件类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailUrgentEnum">
<summary> 邮件加急类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailCron">
<summary> 定时周期 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.EmailTopic">
<summary> 邮件主题 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.ViewModel.BatchAddTrialEmailNoticeConfig.AttachPath">
<summary> 附件 /// </summary>
</member>
<member name="T:IRaCIS.Core.Application.ViewModel.TrialEmailNoticeConfigAddOrEdit">
<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
</member>
@ -8950,6 +9047,24 @@
是否区分标准
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.BusinessModuleEnum">
<summary> 业务模块 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.BusinessLevelEnum">
<summary> 业务层级 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailTypeEnum">
<summary> 邮件类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailUrgentEnum">
<summary> 邮件加急类型 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailCron">
<summary> 定时周期 /// </summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.EmailNoticeConfigAddOrEdit.EmailTopic">
<summary> 邮件主题 /// </summary>
</member>
<member name="T:IRaCIS.Core.Application.Contracts.SystemBasicDataView">
<summary> SystemBasicDataView 列表视图模型 </summary>
</member>
@ -9161,37 +9276,37 @@
受试者ID
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.FileName">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.FileName">
<summary>
文件名称
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.FilePath">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.FilePath">
<summary>
文件路径
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.RelativePath">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.RelativePath">
<summary>
相对路径
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.CreateUserId">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.CreateUserId">
<summary>
创建人
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.CreateTime">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.CreateTime">
<summary>
创建时间
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.TrialId">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.TrialId">
<summary>
项目ID
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileDto.CreateUserName">
<member name="P:IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileDto.CreateUserName">
<summary>
创建者名称
</summary>
@ -10322,7 +10437,7 @@
<param name="trialId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Image.QA.QCListService.GetConsistencyCheckFile(IRaCIS.Core.Application.Contracts.DTO.GetConsistencyCheckFileInDto)">
<member name="M:IRaCIS.Core.Application.Image.QA.QCListService.GetUserUploadFile(IRaCIS.Core.Application.Contracts.DTO.GetUserUploadFileInDto)">
<summary>
获取一致性核查文件上传记录
</summary>
@ -10919,6 +11034,12 @@
构造函数注入
</summary>
</member>
<member name="M:IRaCIS.Application.Services.BackGroundJob.IRaCISCHangfireJob.MemoryCacheTrialStatusAsync">
<summary>
缓存项目状态
</summary>
<returns></returns>
</member>
<member name="T:IRaCIS.Application.Services.BusinessFilter.UnifiedApiResultFilter">
<summary>
统一返回前端数据包装之前在控制器包装现在修改为动态Api 在ResultFilter这里包装减少重复冗余代码

View File

@ -1,593 +1,2 @@
{
"test{0}{1}": "英文本地化{0}{1}",
"RequiredAttribute": "{0} is required",
// ------------------------------------------------------------_ServiceExtensions--------------------------------------------------------------------
//ApiResponseHandler
"ApiResponse_NoAccess": "You do not have access to this API",
"ApiResponse_Permission": "You do not have permission to do this",
// ------------------------------------------------------------Controllers--------------------------------------------------------------------
//FinancialChangeController
"Financial_ChargeSettled": "Expenses have been settled and workload can not be reset.",
"Financial_InvalidParameter": "Invalid parameter.",
//UploadDownLoadController
"UploadDownLoad_UnsupportedMedia": "Unsupported media type.",
"UploadDownLoad_ArchiveInProgress": "Another user is uploading or archiving this study.",
"UploadDownLoad_InvalidData": "Please ensure that the uploaded data conforms to the style of the template file and contains valid data.",
"UploadDownLoad_RequestError": "Request error, please try again!",
"UploadDownLoad_SupportedFormats": "Supports upload of .xlsx, .xls, and .csv formats.",
// ------------------------------------------------------------_MediatR--------------------------------------------------------------------
//ConsistencyVerificationRequest
"ConsistencyVerification_Tech": "Study Type",
"ConsistencyVerification_Time": "Incorrect time format",
//ConsistencyVerificationHandler
"ConsistencyVerification_Img": "Hello, according to the automatic recognition of this system, the imaging study submitted by the subject in the current visit in the IRC system is as follows:",
"ConsistencyVerification_Of": "Of",
"ConsistencyVerification_ImgC": "Imaging study",
"ConsistencyVerification_EDCA": "Check EDC data, completely consistent, approved",
"ConsistencyVerification_EDCB": "Check EDC data, completely consistent",
"ConsistencyVerification_Auto": "Automatically verified pass",
"ConsistencyVerification_Prob": "The following problems exist:",
"ConsistencyVerification_EdcL": "Image study (EDC missing)",
"ConsistencyVerification_IrcL": "Image study (IRC missing)",
"ConsistencyVerification_Desc": "Description: In order to efficiently solve all the above doubts, please verify the actual image study accurately. Please note that the image date may not be consistent with the actual study date, and multiple modalities of image studys (such as PET-CT) may exist at the same time. After accurate verification, please reply with the correct image study for this visit.",
"ConsistencyVerification_Conf": "According to the imported consistency check data, please confirm the following inconsistent inspection item information of this visit:",
"ConsistencyVerification_Edc": "EDC is lack of:",
"ConsistencyVerification_IrcLi": "IRC is lack of:",
//-------------------------------------------------------------------------------------Reading-----------------------------------------------------------------
//ClinicalDataSetService
"ClinicalDataSet_Apply": "",
"ClinicalDataSet_DupTypeFail": "The same type of clinical data exists. The operation failed.",
//ClinicalQuestionService
"ClinicalQuestion_Repeat": "",
//ReadingClinicalDataService
"ReadingClinicalData_DupTypeFail": "The same type of clinical data exists. The operation failed.",
"ReadingClinicalData_Unchecked": "The current clinical data status is not verified and signing is not allowed!",
//ReadingGlobalTaskService
"ReadingGlobal_NotGlobal": "System call error. The current read is not a global review read.",
//ReadingImageTaskService
"ReadingImage_NotVisit": "System call error. The current read is not a timepoint read.",
"ReadingImage_CantSplit": "The current read is a baseline read, and lesion split is not allowed.",
"ReadingImage_BeSigned": "The current read has already been signed. Please do not submit it again.",
"ReadingImage_Beinvalid": "The current read has already been invalidated, and reading is not allowed anymore.",
"ReadingImage_PresenceReview": "The current subject has a re-read request that has not been processed and is not allowed to operate",
"ReadingImage_NotaTask": "The coalesced lesions are not from the same timepoint.",
"ReadingImage_DeleteError": "Other lesions have split from or coalesced into the current lesion. Deletion failed.",
"ReadingImage_Idnotcorrespond": "Failed to add the lesion mark. The Instance ID and Series ID of the image do not match.",
"ReadingImage_IsLymphNotbigger": "The short diameter of this nodal non-target lesion on the current visit is smaller than the value on the previous visit, and the state cannot be set to 'Unequivocal progression'.",
"ReadingImage_NotLymphNotbigger": "The long diameter of this non-nodal non-target lesion on the current visit is smaller than the value on the previous visit, and the state cannot be set to 'Unequivocal progression'.",
"ReadingImage_Twice": "System call error. Questions & answers submitted are duplicated.",
"ReadingImage_MaxQuestion": "According to the imaging charter, the number of {0} cannot exceed {1}.",
"ReadingImage_Maxlesion": "According to the imaging charter, the number of target lesions in the same organ cannot exceed {0}. Please confirm.",
"ReadingImage_Maximum": "{0} can only be repeated {1} times, and it has been repeated {2} times so far.",
"ReadingImage_PCWGMaximum": "According to the imaging charter, the number of baseline lesions at the same location should enter only {0} time. Please confirm.",
"ReadingImage_NotNewFocus": "There should be no new lesions in the converted task",
"ReadingImage_RequiredQuestion": "Before submission, please fill in {0}.",
"ReadingImage_ClinicalRead": "The clinical data has not been read. Please confirm!",
"ReadingImage_IDMust": "System call failed. When there is no Read ID, the standard ID must be passed.",
"ReadingImage_TaskFinish": "Please note that all reads of the current subject have been completed.",
"ReadingImage_NeedRest": "You have been continuously reading for {0} hours. Please take a break of {1} minutes before resumption.",
//ReadingJudgeTaskService
"ReadingJudge_SouceIdNull": "System call failed. The Source ID of the global review which is being adjudicated currently is 'null'.",
//ReadingOncologyTaskService
"ReadingOncology_TaskError": "System call error. The current read is not an oncology read.",
"ReadingOncology_Abnormal": "System call exception. The result of adjudication is null",
//ReadingCalculate
"ReadingCalculate_Abnormal": "Configuration error of PCWG3 criteria. Data verification failed.",
"ReadingCalculate_questionable": "Problems with the lesions are as follows:",
"ReadingCalculate_NoMarker": "Lesion {0} lacks mark.",
"ReadingCalculate_StatusIsEmpty": "The state of Lesion {0} is empty.",
"ReadingCalculate_NoMarkerEmpty": "Lesion {0} is not marked, and its state is empty.",
"ReadingCalculate_NoDeveloped": "Please note that the current standard automatic calculation has not been developed.",
//ReadingMedicalReviewService
"MedicalReview_invalid": "This medical review read has already been invalidated, and the operation failed.",
"MedicalReview_SaveQuestion": "Unable to perform the current operation. Please save the medical review questions first.",
"MedicalReview_NeedSave": "Unable to perform the current operation. Please save the medical review questions and conclusions first.",
"MedicalReview_NotClosed": "Unable to perform the current operation. The current medical query conversation has not been closed.",
"MedicalReview_Finish": "The current medical review is the last one.",
//ReadingMedicineQuestionService
"ReadingMed_QNumDup": "Current question number is repeated",
"ReadingMed_HasSubQ": "This question has sub-question, please delete it first",
"ReadingMed_NoMedQ": "Medical review question has not been added yet. Please add it first before confirming",
"ReadingMed_MedQNumDup": "The display number of the medical imaging review question cannot be duplicated.",
"ReadingMed_ParentNumSmall": "The display number of the parent question should be smaller than that of the child question, please confirm.",
"ReadingMed_VisitQNotConfig": "This review criteria has no medical review questions for 'visit'",
"ReadingMed_GlobalQNotConfig": "The global review read is enabled in the current criterion, but has not configured with medical review questions",
"ReadingMed_ArbitrateQNotConfig": "Adjudication review reading is enabled in the current criterion, but has not configured with medical review questions",
"ReadingMed_TumorQNotConfig": "Oncology reading is enabled in the current criterion, but the oncology medical review question has not been configured",
//UserService
"User_CheckNameOrPw": "Please check the username or password.",
//Repository
"Repository_UpdateError": "Updated data does not exist in the database. ",
"Repository_DeleteError": "Deleted data does not exist in the database.",
//OrganInfoService
"OrganInfo_DuplicateData": "There are duplicate data, operation failed.",
//ReadingCriterionService
"ReadingCriterion_Referenced": "The current criterion has been referenced and cannot be deleted.",
"ReadingCriterion_InUse": "This criterion has been used in the project and cannot be deleted.",
"ReadingCriterion_ArbitratorWithoutJudgment": "There is no referee problem but there is an arbitration object, operation failed.",
//ReadingQuestionService
"ReadingQuestion_IdDup": "Duplicate problem ID.",
"ReadingQuestion_ChildrenExist": "This problem has sub-problems, please delete the sub-problems first.",
"ReadingQuestion_GroupReferenced": "This grouping has been referenced, please delete the referenced problems first.",
"ReadingQuestion_JudgmentSet": "The current question already has a referee criterion set, modification failed.",
"ReadingQuestion_ExcludeWithDependency": "The displayed dependent parent question and the required dependent question are the same, but the answers are mutually exclusive, operation failed.",
"ReadingQuestion_CircularDependency": "Calculation dependency has looped!",
//ReadingPeriodSetService
"ReadingPeriodSet_NameDup": "Review period name duplicate, operation failed",
"ReadingPeriodSet_Global": "Review period name cannot be Global",
"ReadingPeriodSet_AlreadyAdded": "{0} has already added the review period, cannot set it effective.",
"ReadingPeriodSet_TaskCompletedCannotRevoke": "The current criterion has generated reads and the reads have been completed, revoke failed.",
"ReadingPeriodSet_LastVisit": "Last visit.",
//ReadModuleService
"ReadModule_AlreadyAdded": "The current visit has already added a review period.",
"ReadModule_AddGlobalFirst": "Please add global review first.",
"ReadModule_VisitNotFound": "No qualified visit was found.",
"ReadModule_SignedDataCannotDelete": "Clinical data has been signed and cannot be deleted.",
"ReadModule_TumorExists": "The current visit has a tumor review, please delete it first.",
"ReadModule_TaskGenerated": "The current review has generated reads, operation failed.",
//UserWLTemplateService
"UserWLTS_MaxTemplate": "The same user can add a maximum of 10 templates.",
"UserWLTS_NameRepeated": "The template name is repeated",
"UserWLTS_ContentRepeated": "The template content is repeated",
// ------------------------------------------------------------Allocation--------------------------------------------------------------------
//TaskAllocationRuleService
"TaskAllocation_DoctorIdNotFound": "Error, the doctor's account Id was not found in the enrollment table.",
"TaskAllocation_DoctorConfigExists": "The doctor configuration is already available, and continued additions cannot be allowed.",
"TaskAllocation_TaskAssigned": "A read has been assigned to the doctor and it cannot be deleted.",
//TaskConsistentRuleService
"TaskConsistent_ConsistencyConfigExists": "Please configure the doctor for consistency analysis.",
"TaskConsistent_TaskGenerated": "The trial configuration is already available, and no continued additions are allowed.",
"TaskConsistent_MedicalAuditTaskExists": "The criterion already has reads generated by the Subject, and configuration modification is not allowed.",
"TaskConsistent_SignedTaskCannotBeInvalidated": "This criterion has generated a consistency analysis task and cannot be deleted.",
//TaskMedicalReviewRuleService
"TaskMedicalRule_TaskAlreadyAssigned": "The doctor configuration is already available, and continued additions cannot be allowed.",
"TaskMedicalRule_TaskStarted": "A medical review task has been generated.",
//TaskMedicalReviewService
"TaskMedical_DirtyData": "Signed files cannot be set to invalid.",
"TaskMedical_SubjectInOtherArm": "A task is currently assigned to someone else,and it cannot be assigned. Please refresh the list.",
//VisitTaskService
"VisitTask_VisitTask_TaskAlreadyApplied": "The trial has not confirmed any of the review criteria.",
"VisitTask_DoctorConfigNotFound": "The current doctor has begun to do the task of this standard of subject, so assignment cannot be canceled.",
"VisitTask_BackendDataError": "One of the reeads has been assigned to the doctor and is not allowed to be assigned.",
"VisitTask_DirtyData": "Dirty data appears, and the task source field has no value.",
"VisitTask_MissingTaskSource": "The subject had a visit and entered the return process, which has not been verified for consistency and is not allowed to be assigned.",
"VisitTask_InconsistentSubjectStatus": "There is a subject that already has the doctor in another Arm group. It is not allowed to add the doctor to a new group.",
"VisitTask_DuplicateDoctorInArm": "There is a subject that already has the doctor in another Arm group, so the futher assignment is not allowed. Please refresh the page to confirm whether the data on the page is expired.",
"VisitTask_DoctorAlreadyInArm": "The assignment of a Subject task cannot be canceled because it has been applied.",
"VisitTask_TaskAlreadyApplied": "The configured doctor cannot be found in the configuration table, and the binding cannot be applied. Please check the data.",
"VisitTask_DoctorConfiguration": "Background data error",
"VisitTask_BackendData": "Reads that have not been completed or have not been effective are not allowed to request re-reading.",
"VisitTask_UnreadTask": "Reads that re-read has been applied or approved are not allowed to apply for re-reading.",
"VisitTask_NoPMRecheck": "Additional review reads do not allow the PM to apply for re-reading",
"VisitTask_Reapply": "PM is not allowed to apply for re-reading of consistency analysis reads.",
"VisitTask_ConsistencyAnalysis": "PM is only allowed to apply for re-reading that the view type is visit.",
"VisitTask_VisitTypeRestriction": "This is chronological read, and the subject has visit that has applied for re-read by PM, but has not been processed, so it cannot been applied for continuing re-read at this time.",
"VisitTask_SequentialReading": "This is chronological read, and the subject has visit that has applied for re-read, but has not been processed, so it cannot been applied for re-read for now.",
"VisitTask_ImageProblem": "This is chronological read, and there is something wrong with the image. PM has applied for returning, so it cannot been applied for re-reading now.",
"VisitTask_LastReading": "This is chronological read, and only the request for re-readinng by the subject reader after completing the global task for the last time is allowed.",
"VisitTask_LastOncologistRecheck": "This is chronological read, and the subject will only be allowed to re-read after IR completing the last oncology read ",
"VisitTask_LastAdjudicatorRecheck": "This is chronological read, and the subject will only be allowed to re-read after IR completing the last adjudication read ",
"VisitTask_IRGlobalRecheck": "This is random read, IR is only allowed to apply for re-reading global and visit reads",
"VisitTask_IRReapply": "This is random read, IR is only allowed to apply for re-reading global and visit reads ",
"VisitTask_InvalidReapplyStatus": "The current re-read status is not requested and cannot be processed. Please refresh the page.",
"VisitTask_ReapplyStatusConflict": "The current re-read status has been affected by another re-read reads. The re-read review operation is not allowed for reads in this state",
"VisitTask_ReReadTaskNotApplied": "Only reads with visit type are allowed to approve of re-read.",
"VisitTask_ReReadTaskAlreadyAffected": "Do not conform to the PM request and SPM / CPM approve , or IR request and PM approve.",
"VisitTask_TaskTypeNotApproved": "The current re-read status is not requested and cannot be processed. Please refresh the page.",
"VisitTask_NoImageReturn": "Additional review reads do not allow PM to apply for re-reading",
"VisitTask_NonEffectiveTaskCannotBeReturned": "Only effective and unfinished visit read can be returned. Please refresh the page data.",
"VisitTask_NoFurtherReturn": "The current visit has been returned to image upload, so continuing to return is not allowed!",
"VisitTask_ConsistencyTaskCannotBeReturned": "The consistency analysis read is not allowed to be set return back.",
"VisitTask_PMOnlyAllowedForReturn": "Only PM can perform the return back.",
"VisitTask_UnsupportedTaskType": "Re-read types are not supported.",
"VisitTask_UndefinedList": "The current user view list is not defined.",
"VisitTask_NoConsistencyReturn": "The conformance analysis read cannot be returned back",
"VisitTask_VisitTypeTaskAllowedForPMOnly": "Only read with visit type can be returned by PM.",
// ------------------------------------------------------------Common--------------------------------------------------------------------
//CommonDocumentService
"Document_CodeDuplication": "The Code of the document cannot be repeated.",
"Document_SingleTemplate": "Only one template file is allowed per scenario and standard.",
"Document_ TemplateRead": "Failed to read the template content, please try saving the file as docx format!",
//DictionaryService
"Dictionary_DictionaryName": "There is already a dictionary with the name {0}.",
"Dictionary_DictionaryDeletion": "The current dictionary is referenced in the standard and cannot be deleted!",
"Dictionary_SubitemDeletion": "There is child data, direct deletion is not allowed!",
"Dictionary_ResumeReference": "The current entry has been referenced in the reader resume.",
"Dictionary_ProjectReference": "The current entry has been referenced in the trial information.",
"Dictionary_StandardReference": "The current entry has been referenced in the review criteria.",
//ExcelExportService
"ExcelExport_UnsupportedExport": "Currently the criterion export is not supported.",
//MailService
"Mail_EmailResetReminder": "[From Extensive Imaging IRC] A reminder about resetting the email.",
"Mail_Dear": "Dear {0},",
"Mail_ResettingEmail": "You are resetting an email address.",
"Mail_IRCResettingPassword ": "[From Extensive Imaging IRC] A reminder about resetting your password",
"Mail_ResettingPassword ": "You are resetting the email password",
"Mail_ImagingIRCReminder": "[From Extensive Imaging IRC] A reminder",
"Mail_IRCProject": "You are participating in the Extensive Imaging IRC trial",
"Mail_ProjectParticipationReminder": "[From Extensive Imaging IRC] [{0}] A reminder of the Site Survey",
"Mail_CenterResearchReminder": "You are participating in the Site Survey of the Extensive Imaging IRC trial.",
"Mail_AccountCreationReminder": "[From Extensive Imaging IRC] A reminder about creating an account",
"Mail_AccountPasswordResetReminder": "[From Extensive Imaging IRC] A reminder about resetting account passwords",
"Mail_InvitationEmail": "[From Extensive Imaging IRC][{0}]Invitation",
//SystemMonitor
"SysMon_JsonConfig": "Parsing the Json file configuration failed",
// ------------------------------------------------------------Doctor--------------------------------------------------------------------
//DoctorService
"Doctor_DupPhoneOrEmail": "The current tel or email number already existed",
"Doctor_DupPhone": "The current tel number already existed!",
"Doctor_DupEmail": "The current email already existed!",
"Doctor_StandardDuplicateFileTypeError": "This type of file has already been added to the current criterion.",
"Doctor_RequiredDocumentsError": "Resume & Consultant Agreement must be upload",
// ------------------------------------------------------------Document--------------------------------------------------------------------
//SystemDocumentService
"SystemD_DuplicateFile": "A file with the same type and same name already exists in the system.",
"SystemD_CannotDeleteSignedFile": "The file has already been read and signed by a user, and not allowed to be deleted.",
//TrialDocumentService
"TrialD_DuplicateFileInProject": "A file with the same type and same name already exists in this trial .",
"TrialD_DocumentHasAlready": "The file has already been read and signed by a user, and not allowed to be deleted.",
"TrialD_FileAlreadySigned": "The file has been signed.",
"TrialD_ObsoleteFile": "The file has been revoked. Signature failed!",
//TrialEmailNoticeConfigService
"TrialEmailN_TaskNotSigned": "Before sending the email, the task must have been signed and triggered to complete the corresponding task generation.",
"TrialEmailN_NoRecipient": "The message cannot be sent without the recipient.",
"TrialEmailN_InvalidEmailConfig": "The configuration of the sender mail of the trial is wrong, please check.",
"TrialEmailN_EmailTemplateNotFound": "The email template in the standard scenario of this trial cannot be found.",
"TrialEmailN_EnrollmentConfirmation": "[Enrollment Confirmation Report] About {0} item {1}Subject",
"TrialEmailN_Enrollment": "The attachment is the Enrollment Confirmation Report, please check.",
"TrialEmailN_PDReport": "[PD Confirmation Report] About {0} item {1}Subject",
"TrialEmailN_SubjectDiseaseProgression": "The attachment is the PD Confirmation Report, please check.",
"TrialEmailN_SingleBlindedSet": "The configuration of the single and chronological read is incorrect (there should be no adjudicator configuration), please check!",
"TrialEmailN_SingleBlindedSequenced": "The single and chronological read, should not enter the logic here, please contact the background developers to check!",
"TrialEmailN_PDProgressEmailTask": "Send PD progress email found problem with the task data!",
"TrialEmailN_DoubleBlindedError": "The double and chronological read does not defined the adjudication rule logic, please contact the developers to check!",
"TrialEmailN_InCons": "The trial is not configured with the Enrollment Confirmation!",
"TrialEmailN_NoBaseLine": "There is no baseline visit configured with Enrollment Confirmation and IR readedso email failed to send",
"TrialEmailN_IncompBase": "The baseline reads for enrollment confirmation has not been finished for IR!",
"TrialEmailN_EmailFail": "Email failed to generate manuallyplease contact developer to verify the failure cause",
"TrialEmailN_NoReader": "No IR has finished the baseline read at present!",
"TrialEmailN_NoPDConfig": "The trial is not configured with PD Confirmation!",
"TrialEmailN_NoPDTasks": "There is no baseline visit configured with “PD Confirmation” and IR readedso email failed to send",
"TrialEmailN_PDNotFinished": "The completion status of the latest PD interview and film reading task of the current subject does not meet the sending conditions",
"TrialEmailN_PDNoImaging": "The trial is configured with review period adjudication, but the current subject' s latest visit marked 'PD' have no review period",
"TrialEmailN_PDPhaseNotFinished": "The review period status of the current subject's latest PD visit does not meet the sending conditions",
"TrialEmailN_NoRuleDefined": "The sending logic for adjudication rule is not defined! ",
"TrialEmailN_NoDoubleOrder": "The current trial is not double and chronological read, so the sending condition is not met",
"TrialEmailN_NoSendLogicDefined": "The current trial is not defined sending logic",
"TrialEmailN_BlindedSequencedReading": "The configuration of the chronological read is wrong (should be single or double reading), please check!",
"TrialEmailN_UnblindedSequencedReading": "The configuration of random read is wrong (should be single read without adjudication, or double read with adjudication for visiting ), please check!",
"TrialEmailN_InvalidTaskTypeForEmailSending": "Do not send emails for other type except visit, adjudication and global read. Please check the logic.",
"TrialEmailN_PDLogicNotDefined": "Reads for this criterion has not yet defined the PD logic, please supplement it after consultation with the developer.",
"TrialEmailN_MailboxWrong": "The configuration of the sender mailbox of the trial is wrong, please check it.",
"TrialEmailN_InvalidRecipient": "The trial does not have a valid recipient, so the message cannot be sent.",
"TrialEmailN_EmailTestMessage": "Trial mail test",
"TrialEmailN_ConfigurationCorrect": "If this email is received, the email configuration is correct.",
"TrialEmailN_InvalidSenderEmailConfig": "The sender configuration is incorrect. Please check whether the server address or authorization code is correct or not.",
// ------------------------------------------------------------Financial--------------------------------------------------------------------
//CalculateService
"Cal_VolDataErr": "Volume reward data error.",
//ExchangeRateService
"ExR_SameMthExist": "The exchange rate of the same month already existed.",
"ExR_MthPymtRate": "The exchange rate has been used in monthly payment",
//PaymentAdjustmentService
"PayAdj_DocPymtLock": "Doctor payment has confirmed lock",
//RankPriceService
"RP_TitleUsedByRev": "This title has been used by reviewer payment information",
//TrialRevenuesPriceService
"TRP_AddMeaningful": "Please add meaningful data",
// ------------------------------------------------------------ImageAndDoc--------------------------------------------------------------------
//DicomArchiveService
"DAS_NoAnonCacheData": "The cache data for anonymous config is not obtained, and the upload stops. Please contact the developer to verify.",
//ImageShareService
"ISS_NoImgToShare": "There are no images to share for the current study.",
"ISS_ResNotExists": "The request resource wasnt found.",
"ISS_SharePwdError": "The shared password is incorrect.",
"ISS_ShareExpiration": "Resource sharing expires.",
//StudyService
"Study_VisitBeforePrevError": "The current visit check time {0} cannot be earlier than the previous visit check time {1}. Please check whether the check data is correct.",
"Study_VisitAfterSubseqError": "The current visit check time {0} cannot be later than the visit check time {1} .Please check whether the check data is correct.",
"Study_UploadArchiving": "Someone is currently uploading and archiving this visit!",
"Study_VisitEndedNotAllowed": "Subject visit is over, and uploading is not allowed!",
"Study_ImgAlreadyUploaded": "Uploading is not allowed above here.The current image check has been uploaded to {1} of subject {0}",
// ------------------------------------------------------------Inspection--------------------------------------------------------------------
//FrontAuditConfigService
"FrontAudit_IdDup": "The identifier is duplicated.",
"FrontAudit_NameDup": "The name is duplicated .",
"FrontAudit_CannotDelSub": "Subclasses exist, cannot delete.",
//InspectionService
"Inspection_UserDisabled": "The current user has been disabled.",
// ------------------------------------------------------------Institution--------------------------------------------------------------------
//CROService
"CRO_DupName": "CRO with the same name already exists. Please confirm.",
"CRO_InProject": "The CRO has participated in the trial and cannot be deleted.",
//HospitalService
"Hospital_DupName": "Hospital with the same name already exists. Please confirm.",
"Hospital_SiteAdded": "The current Site has been added to another Hospital.",
"Hospital_HasDoctors": "There are already doctors registered under the hospital's account and cannot be deleted.",
//SiteService
"Site_DupName": "Site with the same name already exists. Please confirm.",
"Site_InProject": "This site has been added to the project and cannot be deleted.",
//SponsorService
"Sponsor_DupName": "Sponsor with the same name already exists. Please confirm.",
"Sponsor_InProject": "The sponsor has been added to the trial and it is not allowed to delete.",
// ------------------------------------------------------------Management--------------------------------------------------------------------
//MenuService
"Menu_ParentDupChild": "A child node with the same name already exists under the parent node.",
"Menu_ChildExist": "Child nodes already exists under this node . Delete the child nodes before deleting the node.",
//UserService
"User_UsernameExist": "The user name already exists.",
"User_PhoneDup": "A user with the same phone number already exists in this user type.",
"User_EmailDup": "A user with the same email already exists in this user type.",
"User_NewOldPwdSame": "The new password is the same as the old one.",
"User_OldPwdInvalid": "Failed to verify the old password.",
"User_LegalEmail": "Please input a legal email.",
"User_VerificationCodeError": "The verification code is wrong.",
"User_VerificationCodeExpired": "The verification code has expired.",
"User_CreateFailed": "Check the email address or contact maintainers. The email fails to be sent and the account cannot be created.",
"User_InvalidEmail": "Please enter a correct E-mail address.",
"User_EmailError": "The email adress is wrong.",
"User_InProject": "The user has participated in the trial and cannot be deleted.",
"User_Disabled": "The user has been disabled.",
//UserTypeService
"UserType_InUse": "User already exists in that user type, and it cannot be deleted.",
// ------------------------------------------------------------QC--------------------------------------------------------------------
//QCCommon
"QCCommon_CannotOperate": "CRC has submitted the image. Operation is not allowed.",
"QCCommon_NoPermission": "You are not the current recipient of the image QC. No operation authority!",
"QCCommon_CheckTimeEarly": "The current visit study time {0} cannot be earlier than the previous visit study time {1}. Please check whether the study data is correct.",
"QCCommon_CheckTimeLate": "The current visit study time {0} cannot be later than the visit study time {1} .Please check whether the study data is correct.",
//QCOperationService
"QCOperation_CheckFirst": "Please check the image first and save review questions before query.",
"QCOperation_QuestionExist": "The unclosed query of the current visit has been set to approve CRC reupload. After CRC has reuploaded image, please close the original query first and then add a new query.",
"QCOperation_QuestionCannotClose": "CRC has applied for reuploading or QC has agreed to reupload. To close the query is not allowed. Please do not close the query until the QC rejects or the CRC reuploads the image.",
"QCOperation_CloseReason": "Reason for closing:",
"QCOperation_QuestionReplied": "The QC query has been answered.",
"QCOperation_NoPermissionReply": "You do not have permission to reply to the data reconciliation conversation.",
"QCOperation_CannotClose": "The current visit status is CRC request re-upload. The query is not allowed to be closed.",
"QCOperation_Reason": "Notes:",
"QCOperation_CannotPass": "The current visit is in the return status, and the data reconciliation cannot be set.",
"QCOperation_PassAfterClose": "Please close the data reconciliation query first, and then set the data reconciliation pass.",
"QCOperation_Cannotback": "The current visit has passed the consistency check and cannot be applied for re-upload.",
"QCOperation_CRCRollback": "CRC apples for re-upload.",
"QCOperation_OtherCRC": "Other CRCs have applied for processing. Please refresh the page.",
"QCOperation_PMReject": "PM/APM rejected the data reconciliation return.",
"QCOperation_NoPermission": "You do not have operation permission.",
"QCOperation_CannotRollback": "If the current visit has not do reconciliation or has passed, setbacks are not allowed.",
"QCOperation_PMAPMConsistency": "PM/APM agrees to the data reconciliation rollback.",
"QCOperation_NoModifyAfterSubmit": "Once submitted, no modifications are allowed.",
"QCOperation_UnresolvedQCQuery": "Image query of the current visit is not closed. This operation is not allowed.",
"QCOperation_CrcNoDelete": "The CRC has been committed and cannot be deleted.",
"QCOperation_NoRecipient": "You are not the current recipient of the quality control task, no operation authority!",
"QCOperation_QCImageTaskAlreadyReleased": "The image QC of the current visit has been released by the original recipient. You can get it by 'claime'.",
"QCOperation_QCTaskNoAccess": "The image quality control task of the current visit has been claimed by other QC, so it is not allowed to claim.",
"QCOperation_QCConfigFirst": "Please configure the image QC questions before claiming any image QC work.",
"QCOperation_NoQC": "The trial configuration of image QC was not check, and the QC Task was not be claimed.",
"QCOperation_InitialAuditPassed": "The first review has passed, continue to receive can not be allowed.",
"QCOperation_NoSingleAudit": "The trial is configured with single image QC , does not meet Submmit State: Submitted or Audit State: pending QC/ in QC, not allowed to collect.Please refresh the page.",
"QCOperation_NoSameReviewer": "The secondary QC cannot be the same person as the primary QC.",
"QCOperation_NoSecondaryAudit": "The trial is configured withr double image QC , does not meet Submmit State: Submitted or Audit State: pending review/ in QC, not allowed to collect.Please refresh the page.",
"QCOperation_NoTaskAccess": "You are not the current recipient of the quality control task, no operation authority!",
"QCOperation_NoQCFunction": "The project configuration of image QC process was not check, so there is no need to cancel the task function.",
"QCOperation_NoTaskOwner": "The current visiting image QC has not been claimed by anyone, and cannot been released.",
"QCOperation_DiseaseProgressConfirmation": "Current visit required PD Confirmation. Please process the unsubmitted prior visit before submitting the current visit: {0}.",
"QCOperation_UnsubmittedVisits": "After submitting the current visit, please submit any prior visits which have not been submitted as soon as possible. ({0})",
"QCOperation_NoBaselineData": "No clinical data at baseline. Confirm to submit?",
"QCOperation_NoImageData": "Dicom/ Non-dicom image data has not been uploaded. Submission is not allowed.",
"QCOperation_ImagesSubmitted": "The image data of the current visit has been submitted by another CRC.",
"QCOperation_BatchImagesSubmitted": "The visit image data is currently submitted in batches, part of which has been submitted by other CRCs.",
"QCOperation_MissingBaselineDate": "The trial is configured with the visit start date, but the visit start date for the subject is not filled. Submittion is not allowed.",
"QCOperation_RemoveItem": "You have been removed from the trial and have no operation rights.",
"QCOperation_QCNotClosed": "The QC query has not been closed for the current visit. This operation cannot be performed.",
"QCOperation_NoQCNeeded": "The trial configuration of image QC was no. No need to set image QC as pass.",
"QCOperation_QCNotSaved": "Image QC question is not saved. This operation is not allowed.",
"QCOperation_NotChangePass": "The trial configuration of image QC process was double check, so the current image QC task cannot change from the current state to pass.",
"QCOperation_CannotChangeToPass": "The trial configuration of image QC process was double check. The current audit state is {0}, which cannot be changed to approved.",
"QCOperation_NoQCNeededNotEnd": "The trial configuration of image QC process was not check, and setting image quality control termination is not allowed.",
"QCOperation_CannotChangeToStop": "The trial configuration of image QC process was single check, and the current review state is not In Primary QC and cannot be changed to the QC termination.",
"QCOperation_CannotChangeStop": "The trial configuration of image QC process was double check, and the current review state is {0} and cannot be changed to the QC termination.",
"QCOperation_InvalidResend": "The current reupload state is not QC agree, so reuploading is not allowed.",
"QCOperation_NoResendNeeded": "No check operation, there will be no need to reupload!",
"QCOperation_InvalidAgreeResend": "The current re-upload- status is not CRC requested and the approve of reuploading cannot be set.",
"QCOperation_CannotAgreeResend": "At the current visit, there is an unclosed query that QC set to agree to reupload, CRC has not uploaded, currently is not allowed to set again.",
"QCOperation_AgreeResend": "QC agrees to re-upload.",
"QCOperation_InvalidCompleteResend": "The current reupload status is not QC approved, setting reuploading completion is not allowed.",
"QCOperation_NoImageNotAllowed": "No image is currently available. Setting reuploaded is not allowed.",
"QCOperation_CRCTransferCompleted": "CRC reuploading has been completed. ",
"QCOperation_InvalidTransferStatus": "The current query re-upload status is not the initial| CRC re-uploaded. Application for re-uploading is not allowed",
"QCOperation_CRCTransfer": "CRC requests to reupload/upload images.",
"QCOperation_CannotModifyConfirmation": "The visit has been submitted, and the enrollment confirmation state cannot be modified.",
"QCOperation_CannotModifyPDStatus": "This visit status is return back. Modification of PD Confirmation status is not allowed.",
"QCOperation_ForwardingFailed": "Failed to forward the image:",
//QCQuestionService
"QCQuestion_DuplicateIndexFailed": "Operation failed because the serial number is repeated.",
"QCQuestion_HasChildQuestion": "The current task has a sub-question. Deletion failed.",
//TrialQCQuestionService
"TrialQCQuestion_TemplateConfirmed": "Image QC question template has been confirmed. No operation is allowed.",
"TrialQCQuestion_DuplicateIndexFailed": "Operation failed because the serial number is repeated.",
"TrialQCQuestion_DeleteChildFirst": "Before deleting the parent question, delete the child question that references the parent question.",
"TrialQCQuestion_ReferencedByQCProcess": "This review question has been cited by the image QC. Deletion is not allowed.",
// ------------------------------------------------------------QC--------------------------------------------------------------------
// ------------------------------------------------------------SiteSurvey--------------------------------------------------------------------
//TrialSiteEquipmentSurveyService
"TrialSiteEquipment_Locked": "Locked and operation is not allowed.",
//TrialSiteSurveyService
"TrialSiteSurvey_InvalidEmail": "Please enter the correct email address.",
"TrialSiteSurvey_WrongVerificationCode": "The verification code is incorrect.",
"TrialSiteSurvey_ExpiredVerificationCode": "The verification code has expired.",
"TrialSiteSurvey_NoRecordToUpdate": "The site does not have a site survey record for the transferor , so it is not allowed to choose to update.",
"TrialSiteSurvey_RecordUnderReview": "Your site survey record is in review and cannot be updated. If you need to update, please do so after rejection.",
"TrialSiteSurvey_LockedByCurrentUser": "In the current site, the submitted survey record has been locked. Updation of other people's email survey records is not allowed.",
"TrialSiteSurvey_LockedByOtherUsers": "The submitted survey record of the current site has been locked. Currently, the survey record submitted by other personnel is not locked. Updation of the survey submitted before is not allowed.",
"TrialSiteSurvey_UnlockedRecordsExist": "The current site has unlocked survey records. Locked survey records cannot be updated.",
"TrialSiteSurvey_NonLatestLockedRecord": "The site survey corresponding to the mailbox {0} is not the latest. Updation is not allowed",
"TrialSiteSurvey_AlreadyFilledByOtherUsers": "There are already survey filled out by other users under this site. You are not allowed to fill them out",
"TrialSiteSurvey_Locked": "The site survey has been locked, and no operation is allowed.",
"TrialSiteSurvey_IRCNotification": "[from Extensive Imaging IRC] A reminder about the site survey approval.",
"TrialSiteSurvey_CancelUnsubmittedRecord": "Only unsubmitted records are allowed to be repealed.",
"TrialSiteSurvey_NoAdminAcces": "The operation is not allowed by the administrator.",
"TrialSiteSurvey_FailedToGenerateAccountId": "If no value is obtained for the generated account Id. Please check.",
"TrialSiteSurvey_IRCInvitation": "[from Extensive Imaging IRC][{0}] Invitation letter",
"TrialSiteSurvey_IRCInvitationContent": "Hello, as the IRC supplier of experiment plan No. {0} trial, Extensive Imaging sincerely invites you to participate in the IRC related work of this project. Your guidance and suggestions are welcome.",
"TrialSiteSurvey_ViewAndConfirm": "Check and confirm",
//TrialSiteUserSurveyService
"TrialSiteUser_Locked": "Locked and not allowed to operate.",
"TrialSiteUser_InconsistentInfo": "The corresponding user of this email address is {0}, and the phone number is {1}. Please modify the inputted information and make it consistent with that already in the system, and then save.",
"TrialSiteUser_NoTestUserForFormal": "Formal and training triala are not allowed to add test users.",
"TrialSiteUser_NoFormalUserForTest": "It is the test project that regular users are not allowed in.",
// ------------------------------------------------------------Stat--------------------------------------------------------------------
// ------------------------------------------------------------TrialSiteUser--------------------------------------------------------------------
//TrialConfigService
"TrialConfig_JudgeTaskFail": "There are adjudication questions that the conditions for generating adjudication review read are not configured. Operation failed!",
"TrialConfig_StdConfigMissing": "Questions are not configured under the current criterion.",
"TrialConfig_AddEvalReq": "Selected additional assessment, must check additional assessment type",
"TrialConfig_SignTemplateMissing": "This operation requires electronic signature confirmation, but the signature template for this scenario is not found in the system.",
"TrialConfig_ProjectEnded": "The trial has ended or stopped. Configuration changes are not allowed.",
"TrialConfig_NoImageAuditQuestion": "No image QC question is currently added. Please add the image QC questions first, and then confirm.",
"TrialConfig_DuplicateAuditQuestionId": "Image QC question display number cannot be repeated.",
"TrialConfig_InvalidParentQuestionId": "Make sure that the display sequence number of the parent question is smaller than that of the child.",
"TrialConfig_AuditQuestionConfirmed": "The image QC questions have been confirmed by other personnel. Cofirmation again is not allowed. ",
"TrialConfig_ProjectNotInitialized": "The current trial status is not initialized. This operation is not allowed.",
"TrialConfig_UnconfirmedConfiguration": "This trials project configuration, & visit management have not been finished, and its status cannot be changed to “Ongoing”.",
"TrialConfig_UnconfirmedUNACKD": "This trials project configuration, & visit management have not been all confirmed, and its status cannot be changed",
"TrialConfig_ProjectNotStarted": "This trial status is not “Ongoing”, and cannot be set to Stoped or Completed.",
//TrialExternalUserService
"TrialExternalUser_Inconsistency": "The corresponding user of this email address is {0}, and the phone number is {1}. Please modify the inputted information and make it consistent with that already in the system, and then save.",
"TrialExternalUser_EmailTypeDuplicate": "Please confirm that the system already has an account with the same email address and user type as the one entered in the list.",
"TrialExternalUser_TestUserNotAllowed": "Formal and training trials are not allowed to add test users.",
"TrialExternalUser_FormalUserNotAllowed": "It is a training trial that regular users are not allowed in.",
"TrialExternalUser_NotEditable": "Staff information cannot be edited. Please delete it and add it again.",
"TrialExternalUser_CannotDelete": "The current user has participated in the trial and cannot be deleted.",
"TrialExternalUser_IRCInvitation": "Hello, as the IRC supplier of experiment plan No. {0} trial, Extensive Imaging sincerely invites you to participate in the IRC related work of this project. Your guidance and suggestions are welcome.",
"TrialExternalUser_ViewAndConfirm": "Check and confirm",
"TrialExternalUser_InvitationExpired": "The invitation time has expired. You can only confirm it after you are invited again.",
"TrialExternalUser_AccountInfo": "[from Extensive Imaging IRC][{0}] account information",
"TrialExternalUser_Welcome": "Hello, welcome to participate in the relevant work of trial scheme No. {0}IRC of the project. This trial adopts electronic workflow. The system and your account information are as follows:",
"TrialExternalUser_ProjectNumber": "Trial ID: {0}",
"TrialExternalUser_ExperimentPlanNumber": "Protocol ID: {0}",
"TrialExternalUser_ExperimentName": "Study Name: {0}",
"TrialExternalUser_Username": "User name: {0}",
"TrialExternalUser_Password": "Password: {0}Please modify it after login: ***You already have your account. If you forget your password, please find it by email",
"TrialExternalUser_Role": "User role: {0}",
"TrialExternalUser_LoginUrl": "System login address: {0} ",
"TrialExternalUser_ReinvitationRequired": "The invitation time has expired. You can only confirm it after you are invited again.",
"TrialExternalUser_UserIdStorageProblem": "There is a problem with the system user Id storage of the survey table. ",
"TrialExternalUser_IRCAccountInfo": "[from Extensive Imaging IRC][{0}] account information",
//TrialMaintenanceService
"TrialMaint_PersonnelJoined": "Participant has participated in site maintenance",
//TrialService
"Trial_PMApmPermission": "Only PM/APM has the operation permission!",
"Trial_TestUserCreateOnlyNonFormal": "Test users can only create informal projects",
"Trial_DuplicateProjectNumber": "The same project ID already exists.",
"Trial_InvalidProjectStatus": "Operations are allowed only when the project state is: initializing or ongoing.",
"Trial_CannotDeleteProject": "Deleting project data is not allowed in the current running environment.",
//TrialSiteService
"TrialSite_ParticipantJoined": "The subjects has been added to this site, and couldn't be disable.",
"TrialSite_CodeDuplicate": "Code is not allowed to be repeated",
"TrialSite_CannotDeleteAssociatedCRC": "The site has been associated with CRC, and couldn't be deleted.",
"TrialSite_CannotDeleteAssociatedSubject": "The subjects has been added, and couldn't be deleted.",
"TrialSite_CannotDeleteUploadedData": "The site has been uploaded survey, and couldn't be deleted.",
// ------------------------------------------------------------Visit--------------------------------------------------------------------
//SubjectService
"Subject_NoConfirmedPlan": "The visit plan of the trial is not confirmed. Please contact PM to confirm the visit plan before adding subjects.",
"Subject_DuplicateSubjectNum": "Subjects with the relevant subject ID already exists.",
"Subject_UploadedVisitNoDelete": "The subject has visit that has uploaded the image. Deletion is not allowed.",
//SubjectVisitService
"Visit_DuplicateVisitNo": "The subject's visit schedule already includes a visit with the same visit ID.",
"Visit_LastVisitNoChange": "The subject has already had a visit set as the last, and the current visit cannot be set as the last visit.",
"Visit_DuplicateVisitName": "The subject's visit schedule already includes a visit with the same visit name.",
"Visit_NoExtraVisitAfterLast": "Unplanned visits cannot be added after the last assessment is set.",
"Visit_FinishedTasksNoAdd": "The subject has reads completed in follow-up visit ( chronological read ) , which is not allowed to be added here. If necessary, please return.",
"Visit_NoPDStatusChangeAfterSubmission": "The PD Confirmation status cannot be modified after the current visit image is submitted.",
"Visit_UploadedNoLost": "The current visit has already uploaded images and cannot be set as visit lost to follow-up.",
"Visit_UploadedNoDelete": "The current visit has already uploaded images and deletion is not allowed.",
"Visit_PlanVisitNoDelete": "Planned visits are not allowed to be deleted.",
"Visit_PreviousVisitNoDelete": "The current visit has been set to the previous visit of another visit and cannot be deleted.",
//VisitPlanService
"VisitPlan_OnlyInitOrOngoing": "Can be operated only when the trial state is: Initialized or ongoing.",
"VisitPlan_LargerVisitNumLargerInterval": "In the visit plan, the interval between visits with a large number should also be larger than that of a visit with a smaller number.",
"VisitPlan_LargerPlanNumLargerInterval": "In the visit plan, the planned visit with a large number should also have a larger interval than the planned visit with a smaller event number.",
"VisitPlan_ExistNameOrNumTemplate": "A plan visit template with visit name or visit ID of trial already exists in the visit plan.",
"VisitPlan_ExistBaseline": "A baseline already exists in the visit plan.",
"VisitPlan_ExistBaselineImgNoModify": "The subjects baseline image data has been uploaded, so modification of baseline visits is not allowed.",
"VisitPlan_OnlyInitOrOngoingModifyConfirm": "Modification confirmation is allowed only when the trial is initialized or ongoing.",
"VisitPlan_NoBaselineNotConfirm": "No baseline, no confirmation allowed.",
"VisitPlan_ConfigNotConfirmNotConfirm": "If the trial configuration is not confirmed, the visit plan cannot be confirmed.",
"VisitPlan_BaselineNotMinDayNotConfirm": "Baseline's VisitDay is not minimal. Confirmation is not allowed.",
"VisitPlan_CheckExport": "Study export _{0}.xlsx",
"VisitPlan_Assigned": "The visit plan has been assigned to the subjects and executed.",
// ------------------------------------------------------------WorkLoad--------------------------------------------------------------------
//DoctorWorkloadService
"DoctorWorkload_AssignType": "A task has been assigned and does not allow you to reduce the reading type.",
"DoctorWorkload_Unique": "This type of data can only have one",
"DoctorWorkload_FeeSettled": "Expenses have been settled and workload cannot be modified.",
//EnrollService
"Enroll_NotFound": "Cannot find trial {0}",
"Enroll_EmailFormat": "The {0} mailbox format is faulty.",
"Enroll_CannotRollback": "Reviewers with workload cannot go back",
// ------------------------------------------------------------Triggers--------------------------------------------------------------------
//AddlTrialUserTrigger
"AddlTrialUser_NoTestUser": "Formal and training trials are not allowed to be added test users.",
"AddlTrialUser_NoFormalUser": "It is a training trial that regular users are not allowed in.",
//SubjectStateTrigger
"SubjectState_CannotSetCurrentAsLastVisit": "The subject has already had a visit set as the last, and the current visit cannot be set as the last.",
"SubjectState_CannotSetAsLastVisitWithImage": "The image of the subject's visit after the current visit has been uploaded, and the current visit is not allowed to be set as the last visit.",
//SubjectVisitFinalVisitTrigger
"SubjectVisit_CannotSetAsLastVisit": "The subject's follow-up visits has uploaded images or submitted , and the current visit is not allowed to be set as the last visit.",
// ------------------------------------------------------------BusinessFilter--------------------------------------------------------------------
//LimitUserRequestAuthorization
"LimitUser_AuthTokenMissing": "User token was not retrieved from Header/URL, please contact developer",
"LimitUser_AccountLoggedInElsewhere": "User token was not retrieved from Header/URL, please contact developer",
//ModelActionFilter
"ModelAction_InvalidAPIParameter": "Invalid parameters provided for the API.",
//ProjectExceptionFilter
"ProjectException_ConcurrentUpdateNotAllowed": "Concurrent update, operation not allowed at this time.",
"Project_ExceptionContactDeveloper": "Program exception, please contact developer.",
//TrialResourceFilter
"TrialResource_NoAccessPermission": "Sorry, your account does not have operation permissions.",
"TrialResource_ReferTrialIdFailed": "Regular expression failed to fetch trialId from request Refer, please contact developer to check",
"TrialResource_InterceptedProjectStatusRule": "This request was blocked by configured rules: only operations allowed when project status is in progress, please contact developer if this logic is incorrect and needs to be modified",
"TrialResource_MissingProjectNumber": "Project number not passed in the API parameters, please verify.",
//UnifiedApiResultFilter
"UnifiedAPI_ProgramError": "Program error, please contact developer.",
// ------------------------------------------------------------Helper--------------------------------------------------------------------
//FileStoreHelper
"FileStore_TemplateFileNotFound": "Database did not find the corresponding data template file for FileStoreHelper, please contact system maintenance personnel.",
"FileStore_TemplateFileStoragePathInvalid": "File doesnt exist. Please contact the system administrator!",
//SendEmailHelper
"SendEmail_SendFail": "Failed to send email in SendEmailHelper. Your operation was unsuccessful, please check your email or contact maintenance personnel.",
"SendEmail_NoRecipient": "No recipient in SendEmailHelper.",
// ------------------------------------------------------------IRaCIS.Core.Domain--------------------------------------------------------------------
//Trial
"Trial_number": "Subject ID is composed of 5 digits. The first 2 are the Site ID, and the following 3 are the order number. Please ensure it is identical to the ID from the EDC system. ",
// ------------------------------------------------------------IRaCIS.Core.Infrastructure--------------------------------------------------------------------
//ResponseOutput
"RO_BizObjNotExistsOrParamIncorrect": "The business object{0} does not exist in the database, or was deleted by someone else, or an incorrect parameter query caused",
"RO_ExpectChangeButNoEffect": "Expect a change, but the database data has not changed",
"RO_SaveFailed": "Saved failed"
}
}

View File

@ -1,593 +1,2 @@
{
"test{0}{1}": "中文本地化{0}{1}",
"RequiredAttribute": "{0} 字段是必须的",
// ------------------------------------------------------------_ServiceExtensions--------------------------------------------------------------------
//ApiResponseHandler
"ApiResponse_NoAccess": "您无权访问该接口",
"ApiResponse_Permission": "您的权限不允许进行该操作",
// ------------------------------------------------------------Controllers--------------------------------------------------------------------
//FinancialChangeController
"Financial_ChargeSettled": "费用已经结算,无法重置工作量",
"Financial_InvalidParameter": "无效的参数。",
//UploadDownLoadController
"UploadDownLoad_UnsupportedMedia": "不支持的MediaType",
"UploadDownLoad_ArchiveInProgress": "当前已有人正在上传和归档该检查!",
"UploadDownLoad_InvalidData": "请保证上传数据符合模板文件中的样式,且存在有效数据。",
"UploadDownLoad_RequestError": "请求异常,请重试!",
"UploadDownLoad_SupportedFormats": "支持.xlsx、.xls、.csv格式的文件上传。",
// ------------------------------------------------------------_MediatR--------------------------------------------------------------------
//ConsistencyVerificationRequest
"ConsistencyVerification_Tech": "检查技术",
"ConsistencyVerification_Time": "时间格式不对",
//ConsistencyVerificationHandler
"ConsistencyVerification_Img": "您好,根据本系统自动识别该受试者当前访视在IRC系统中已提交的影像检查情况如下",
"ConsistencyVerification_Of": "的",
"ConsistencyVerification_ImgC": "影像检查",
"ConsistencyVerification_EDCA": "核对EDC数据完全一致, 审核通过",
"ConsistencyVerification_EDCB": "核对EDC数据完全一致",
"ConsistencyVerification_Auto": "自动核查通过",
"ConsistencyVerification_Prob": "存在问题如下:",
"ConsistencyVerification_EdcL": "影像检查(EDC 缺少)",
"ConsistencyVerification_IrcL": "影像检查(IRC 缺少)",
"ConsistencyVerification_Desc": "说明:为高效解决/处理以上全部质疑问题麻烦您准确核实实际影像检查情况。请注意影像日期与实际检查的日期可能会不一致部分检查如PET -CT)可能同时存在多种模态影像。准确核实后,请回复该访视正确的影像检查情况。",
"ConsistencyVerification_Conf": "根据导入的一致性核查数据,请确认本访视以下不一致检查项信息:",
"ConsistencyVerification_Edc": "EDC 缺少:",
"ConsistencyVerification_IrcLi": "IRC 缺少:",
// ------------------------------------------------------------Reading--------------------------------------------------------------------
//ClinicalDataSetService
"ClinicalDataSet_Apply": "当前临床数据需要配置一个检查日期才能应用",
"ClinicalDataSet_DupTypeFail": "存在同类型的临床数据,操作失败",
//ClinicalQuestionService
"ClinicalQuestion_Repeat": "存在相同的问题名称!",
//ReadingClinicalDataService
"ReadingClinicalData_DupTypeFail": "存在同类型的临床数据,操作失败",
"ReadingClinicalData_Unchecked": "当前临床数据状态不是已核查状态,不允许签名!",
//ReadingGlobalTaskService
"ReadingGlobal_NotGlobal": "系统调用错误,当前任务不是全局阅片任务。",
//ReadingImageTaskService
"ReadingImage_NotVisit": "系统调用错误,当前任务不是访视任务。",
"ReadingImage_CantSplit": "当前任务是基线任务,不能执行分裂病灶的操作。",
"ReadingImage_BeSigned": "当前任务已经签名,请勿重复提交。",
"ReadingImage_Beinvalid": "当前任务已失效,不能执行阅片。",
"ReadingImage_PresenceReview": "当前受试者存在重阅申请还未处理,不允许操作",
"ReadingImage_NotaTask": "合并的病灶并非同一个访视任务",
"ReadingImage_DeleteError": "当前病灶分裂出其他病灶或者其他病灶合并到了当前病灶,删除失败。",
"ReadingImage_Idnotcorrespond": "病灶标记添加失败影像的Instance ID和Series ID不对应。",
"ReadingImage_IsLymphNotbigger": "当前访视该淋巴结非靶病灶的短径小于上一访视的值,不能设置为显著增大。",
"ReadingImage_NotLymphNotbigger": "当前访视该非淋巴结非靶病灶的长径小于上一访视的值,不能设置为显著增大。",
"ReadingImage_Twice": "系统调用错误,提交的问题及答案重复。",
"ReadingImage_MaxQuestion": "按照《独立影像评估章程》的相关规则,当前{0}的病灶数量不能超过{1}个。",
"ReadingImage_Maxlesion": "按照《独立影像评估章程》的相关规则,同一器官的靶病灶数量不能超过{0}个,请确认",
"ReadingImage_Maximum": "{0}的重复次数限制为{1},目前已重复{2}次。",
"ReadingImage_PCWGMaximum": "按照《独立影像评估章程》的相关规则,同一部位的基线病灶只需录入{0}次,请确认。",
"ReadingImage_NotNewFocus": "转换后的任务不应该存在新病灶",
"ReadingImage_RequiredQuestion": "提交前,请完成{0}",
"ReadingImage_ClinicalRead": "临床数据未阅读,请确认!",
"ReadingImage_IDMust": "系统调用失败当没有任务ID的时候标准ID必传。",
"ReadingImage_TaskFinish": "当前受试者所有阅片任务已完成,请知悉。",
"ReadingImage_NeedRest": "您已连续阅片{0}个小时,请休息{1}分钟后,再继续阅片。",
//ReadingJudgeTaskService
"ReadingJudge_SouceIdNull": "系统调用失败当前裁判的全局任务的SouceId为null。",
//ReadingOncologyTaskService
"ReadingOncology_TaskError": "系统调用错误,当前任务不是肿瘤学任务。",
"ReadingOncology_Abnormal": "系统调用异常裁判结果为null。",
//ReadingCalculate
"ReadingCalculate_Abnormal": "PCWG3标准配置错误数据验证失败。",
"ReadingCalculate_questionable": "病灶存在以下问题:",
"ReadingCalculate_NoMarker": "病灶{0}缺少标记",
"ReadingCalculate_StatusIsEmpty": "病灶{0}状态为空",
"ReadingCalculate_NoMarkerEmpty": "病灶{0}未做标记,且状态为空",
"ReadingCalculate_NoDeveloped": "当前标准自动计算未完成开发,请知悉。",
//ReadingMedicalReviewService
"MedicalReview_invalid": "该医学审核任务已失效,操作失败。",
"MedicalReview_SaveQuestion": "无法执行当前操作,请先保存医学审核问题。",
"MedicalReview_NeedSave": "无法执行当前操作,请先保存医学审核问题和结论。",
"MedicalReview_NotClosed": "无法执行当前操作,当前医学质询对话未关闭。",
"MedicalReview_Finish": "当前医学审核任务为最后一个任务。",
//ReadingMedicineQuestionService
"ReadingMed_QNumDup": "当前问题序号存在重复",
"ReadingMed_HasSubQ": "此问题存在子问题,请先删除子问题",
"ReadingMed_NoMedQ": "当前未添加医学审核问题。请先添加医学审核问题,再进行确认。",
"ReadingMed_MedQNumDup": "影像医学审核问题显示序号不能重复。",
"ReadingMed_ParentNumSmall": "父问题的显示序号要比子问题的显示序号小,请确认。",
"ReadingMed_VisitQNotConfig": "当前标准未配置访视医学审核问题。",
"ReadingMed_GlobalQNotConfig": "当前标准启用了全局阅片,但未配置全局医学审核问题",
"ReadingMed_ArbitrateQNotConfig": "当前标准启用了仲裁阅片,但未配置仲裁医学审核问题",
"ReadingMed_TumorQNotConfig": "当前标准启用了肿瘤学阅片,但未配置肿瘤学医学审核问题",
//UserService
"User_CheckNameOrPw": "请检查用户名或者密码。",
//Repository
"Repository_UpdateError": "修改的数据在数据库不存在。",
"Repository_DeleteError": "删除的数据在数据库不存在。",
//OrganInfoService
"OrganInfo_DuplicateData": "存在相同的数据,操作失败",
//ReadingCriterionService
"ReadingCriterion_Referenced": "当前标准被引用过了,不可以删除",
"ReadingCriterion_InUse": "此标准在项目里面已被使用,操作失败",
"ReadingCriterion_ArbitratorWithoutJudgment": "无裁判问题却有仲裁对象,操作失败",
//ReadingQuestionService
"ReadingQuestion_IdDup": "问题编号重复",
"ReadingQuestion_ChildrenExist": "此问题存在子问题,请先删除子问题",
"ReadingQuestion_GroupReferenced": "此分组已被引用,请先删除被引用的问题",
"ReadingQuestion_JudgmentSet": "当前问题已经设置了裁判标准了,修改失败",
"ReadingQuestion_ExcludeWithDependency": "显示依赖父问题和必填依赖的问题为同一个,但答案互斥,操作失败",
"ReadingQuestion_CircularDependency": "计算依赖循环了!",
//ReadingPeriodSetService
"ReadingPeriodSet_NameDup": "阅片期名称重复,操作失败",
"ReadingPeriodSet_Global": "阅片期名称不能为Global",
"ReadingPeriodSet_AlreadyAdded": "{0}已经添加过阅片期,无法设置生效",
"ReadingPeriodSet_TaskCompletedCannotRevoke": "当前标准阅片已生成任务并且阅片完成,撤销失败。",
"ReadingPeriodSet_LastVisit": "末次访视",
//ReadModuleService
"ReadModule_AlreadyAdded": "当前访视已经添加过阅片期",
"ReadModule_AddGlobalFirst": "请先添加全局阅片",
"ReadModule_VisitNotFound": "未找到符合要求的访视",
"ReadModule_SignedDataCannotDelete": "临床资料已签名,不允许删除",
"ReadModule_TumorExists": "当前访视存在肿瘤学阅片,请先删除肿瘤学阅片",
"ReadModule_TaskGenerated": "当前阅片已生成任务,操作失败。",
//UserWLTemplateService
"UserWLTS_MaxTemplate": "同一个用户最多只能添加10个模板",
"UserWLTS_NameRepeated": "模板名称存在重复",
"UserWLTS_ContentRepeated": "模板内容存在重复",
// ------------------------------------------------------------Allocation--------------------------------------------------------------------
//TaskAllocationRuleService
"TaskAllocation_DoctorIdNotFound": "错误未在入组表中找到该医生的账号Id",
"TaskAllocation_DoctorConfigExists": "已有该医生配置,不允许继续增加",
"TaskAllocation_TaskAssigned": "已分配任务给该医生,不允许删除",
//TaskConsistentRuleService
"TaskConsistent_ConsistencyConfigExists": "请配置一致性分析的医生",
"TaskConsistent_TaskGenerated": "已有该项目配置,不允许继续增加",
"TaskConsistent_MedicalAuditTaskExists": "该标准已有Subject 生成了任务,不允许修改配置",
"TaskConsistent_SignedTaskCannotBeInvalidated": "该标准已产生一致性分析任务,不允许删除",
//TaskMedicalReviewRuleService
"TaskMedicalRule_TaskAlreadyAssigned": "已有该医生配置,不允许继续增加",
"TaskMedicalRule_TaskStarted": "已产生医学审核任务",
//TaskMedicalReviewService
"TaskMedical_DirtyData": "已签名的不允许设置为失效",
"TaskMedical_SubjectInOtherArm": "当前有任务已分配给其他人,不允许分配,请刷新列表",
//VisitTaskService
"VisitTask_VisitTask_TaskAlreadyApplied": "该项目还未确认任何一个阅片标准",
"VisitTask_DoctorConfigNotFound": "当前医生已开始做该Subject 该标准的任务,不允许取消分配",
"VisitTask_BackendDataError": "其中一个任务已分配给该医生,不允许分配",
"VisitTask_DirtyData": "出现脏数据 任务来源字段没有值",
"VisitTask_MissingTaskSource": "该受试者有访视进入了退回流程,还未经过一致性核查通过,不允许分配",
"VisitTask_InconsistentSubjectStatus": "有Subject 在其他Arm组已有该医生不允许在新的组添加该医生",
"VisitTask_DuplicateDoctorInArm": "有Subject 已有该Arm组的医生不允许继续分配,请刷新页面,确认页面数据是否过期",
"VisitTask_DoctorAlreadyInArm": "有Subject任务已应用不允许取消分配",
"VisitTask_TaskAlreadyApplied": "在配置表中未找到配置的医生,无法应用绑定,请核对数据",
"VisitTask_DoctorConfiguration": "后台数据有错误",
"VisitTask_BackendData": "未阅片完成,或者未生效的任务不允许申请重阅",
"VisitTask_UnreadTask": "重阅已申请,或者重阅已同意状态下不允许申请重阅",
"VisitTask_NoPMRecheck": "附加评估标准任务不允许PM 申请影像重阅",
"VisitTask_Reapply": "PM 不允许对一致性分析任务进行申请重阅",
"VisitTask_ConsistencyAnalysis": "PM 仅仅允许对访视类型的任务申请重阅",
"VisitTask_VisitTypeRestriction": "当前为有序阅片,该受试者已有访视已申请重阅还未处理(项目组申请),暂不能继续申请重阅",
"VisitTask_SequentialReading": "当前为有序阅片,该受试者已有访视已申请重阅还未处理,暂不能继续申请重阅",
"VisitTask_ImageProblem": "当前为有序阅片,影像存在问题,项目组已申请回退,暂不能申请重阅",
"VisitTask_LastReading": "有序阅片,只允许申请该受试者阅片人最后一次完成全局任务重阅",
"VisitTask_LastOncologistRecheck": "有序阅片,只允许申请该受试者阅片人最后一次完成肿瘤学任务重阅",
"VisitTask_LastAdjudicatorRecheck": "有序阅片,只允许申请该受试者阅片人最后一次完成裁判的任务重阅",
"VisitTask_IRGlobalRecheck": "无序阅片仅仅允许IR 申请 全局和访视类型类别的任务进行重阅",
"VisitTask_IRReapply": "无序阅片仅仅允许IR申请全局和访视类型类别的任务进行重阅",
"VisitTask_InvalidReapplyStatus": "当前重阅任务状态不为已申请状态,不允许进行处理,请刷新页面",
"VisitTask_ReapplyStatusConflict": "当前申请重阅任务的状态,已被其他任务重阅已影响,不允许对该状态下的任务进行重阅同意与否操作",
"VisitTask_ReReadTaskNotApplied": "仅允许同意访视类型的任务重阅",
"VisitTask_ReReadTaskAlreadyAffected": "不符合 PM申请 SPM / CPM审批 | IR申请 PM 审批 ",
"VisitTask_TaskTypeNotApproved": "当前重阅任务状态不为已申请状态,不允许进行处理,请刷新页面",
"VisitTask_NoImageReturn": "附加评估标准任务不允许在此入口影像退回",
"VisitTask_NonEffectiveTaskCannotBeReturned": "仅仅允许针对生效、未完成的访视任务进行退回操作,请刷新页面数据",
"VisitTask_NoFurtherReturn": "当前访视已回退到影像上传,不允许继续回退!",
"VisitTask_ConsistencyTaskCannotBeReturned": "一致性分析的任务,不允许设置退回",
"VisitTask_PMOnlyAllowedForReturn": "仅PM 可以进行回退操作",
"VisitTask_UnsupportedTaskType": "不支持重阅的任务类型",
"VisitTask_UndefinedList": "当前用户查看列表未定义",
"VisitTask_NoConsistencyReturn": "不允许退回一致性分析任务",
"VisitTask_VisitTypeTaskAllowedForPMOnly": "仅仅访视类型的任务支持PM退回",
// ------------------------------------------------------------Common--------------------------------------------------------------------
//CommonDocumentService
"Document_CodeDuplication": "文档的Code不能够重复。",
"Document_SingleTemplate": "一个场景一个标准只允许有一个模板文档",
"Document_ TemplateRead": "读取模板内容失败, 请将文件另存为docx格式尝试!",
//DictionaryService
"Dictionary_DictionaryName": "已有{0}名称的字典",
"Dictionary_DictionaryDeletion": "当前字典在标准中被引用,不允许删除!",
"Dictionary_SubitemDeletion": "有子项数据,不允许直接删除!",
"Dictionary_ResumeReference": "当前条目已经在阅片人的简历中被引用。",
"Dictionary_ProjectReference": "当前条目已经在项目信息中被引用。",
"Dictionary_StandardReference": "当前条目已经在阅片标准中被引用。",
//ExcelExportService
"ExcelExport_UnsupportedExport": "当前标准导出还未支持",
//MailService
"Mail_EmailResetReminder": "[来自展影IRC] 关于重置邮箱的提醒",
"Mail_Dear": " 尊敬的 {0} , ",
"Mail_ResettingEmail": "您正在进行邮箱重置操作",
"Mail_IRCResettingPassword ": "[来自展影IRC] 关于重置密码的提醒",
"Mail_ResettingPassword ": "您正在进行邮箱重置密码操作",
"Mail_ImagingIRCReminder": "[来自展影IRC]的提醒",
"Mail_IRCProject": "您正在参与展影医疗IRC项目",
"Mail_ProjectParticipationReminder": "[来自展影IRC] [{0}] 关于中心调研的提醒",
"Mail_CenterResearchReminder": "您正在参与展影医疗IRC项目中心调研工作",
"Mail_AccountCreationReminder": "[来自展影IRC] 关于创建账户的提醒",
"Mail_AccountPasswordResetReminder": "[来自展影IRC] 关于重置账户密码的提醒",
"Mail_InvitationEmail": "[来自展影IRC] [{0}]邀请信",
//SystemMonitor
"SysMon_JsonConfig": "解析Json文件配置出现问题",
// ------------------------------------------------------------Doctor--------------------------------------------------------------------
//DoctorService
"Doctor_DupPhoneOrEmail": "当前的电话或电子邮件号码已经存在",
"Doctor_DupPhone": "当前的电话号码已经存在!",
"Doctor_DupEmail": "当前的邮箱已经存在!",
"Doctor_StandardDuplicateFileTypeError": "当前标准已添加过此类型文件",
"Doctor_RequiredDocumentsError": "简历及顾问协议必须上传",
// ------------------------------------------------------------Document--------------------------------------------------------------------
//SystemDocumentService
"SystemD_DuplicateFile": "系统中已存在同类型的同名文件。",
"SystemD_CannotDeleteSignedFile": "已有用户阅读该文档,并签名,不允许删除。",
//TrialDocumentService
"TrialD_DuplicateFileInProject": "该项目中已经存在同类型的同名文件。",
"TrialD_DocumentHasAlready": "已有用户阅读该文档,并签名,不允许删除。",
"TrialD_FileAlreadySigned": "该文件已经签名",
"TrialD_ObsoleteFile": "文件已废除,签署失败!",
//TrialEmailNoticeConfigService
"TrialEmailN_TaskNotSigned": "进行邮件发送前,该任务必须已签名完成并已经触发完成相应的任务生成",
"TrialEmailN_NoRecipient": "没有收件人,无法发送邮件",
"TrialEmailN_InvalidEmailConfig": "项目发件邮箱配置有误,请核实",
"TrialEmailN_EmailTemplateNotFound": "找不到该项目标准场景下邮件模板",
"TrialEmailN_EnrollmentConfirmation": "【入组确认报告】关于{0}项目{1}受试者",
"TrialEmailN_Enrollment": " 附件为入组确认报告,请查收",
"TrialEmailN_PDReport": "【疾病进展确认报告】关于{0}项目{1}受试者",
"TrialEmailN_SubjectDiseaseProgression": " 附件为疾病进展确认报告,请查收 ",
"TrialEmailN_SingleBlindedSet": "单重有序阅片配置有误(不应该有仲裁对象配置),请核查!",
"TrialEmailN_SingleBlindedSequenced": "单重有序阅片 该类型的任务不应进入此处逻辑,请联系后台开发核查!",
"TrialEmailN_PDProgressEmailTask": "发送PD 进展邮件中发现任务数据有问题!",
"TrialEmailN_DoubleBlindedError": "双重有序阅片 没有定义该仲裁规则处理逻辑,请联系业务和后台开发核查!",
"TrialEmailN_InCons": "项目未配置入组确认!",
"TrialEmailN_NoBaseLine": "不存在配置了入组确认的并且已阅的基线访视",
"TrialEmailN_IncompBase": "做入组确认的阅片人基线任务没有阅片完!",
"TrialEmailN_EmailFail": "邮件手动生成失败,请联系开发核实该场景失败原因",
"TrialEmailN_NoReader": "当前未有阅片人读完基线任务!",
"TrialEmailN_NoPDConfig": "项目未配置PD进展",
"TrialEmailN_NoPDTasks": "不存在配置了PD进展的并且已阅的访视",
"TrialEmailN_PDNotFinished": "当前受试者最新PD访视阅片任务完成状态不符合发送条件",
"TrialEmailN_PDNoImaging": "项目配置了阅片期仲裁但是当前受试者最新PD访视没有影像学阅片期",
"TrialEmailN_PDPhaseNotFinished": "当前受试者最新PD访视阅片期任务完成状态不符合发送条件",
"TrialEmailN_NoRuleDefined": "未定义该仲裁规则发送业务逻辑!",
"TrialEmailN_NoDoubleOrder": "当前项目配置,不满足双重有序阅片,不满足发送条件!",
"TrialEmailN_NoSendLogicDefined": "当前项目配置,未定义发送业务逻辑!",
"TrialEmailN_BlindedSequencedReading": "有序阅片配置有误(应为单重或者双重阅片),请核查!",
"TrialEmailN_UnblindedSequencedReading": "无序阅片配置有误(应为单重无仲裁对象,双重针对访视仲裁),请核查!",
"TrialEmailN_InvalidTaskTypeForEmailSending": "不应有除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑",
"TrialEmailN_PDLogicNotDefined": "该标准任务还未定义PD获取逻辑联系业务和后台开发协商后补充",
"TrialEmailN_MailboxWrong": "项目发件邮箱配置有误,请核实",
"TrialEmailN_InvalidRecipient": "项目没有有效的收件人,无法发送邮件",
"TrialEmailN_EmailTestMessage": "项目邮件测试",
"TrialEmailN_ConfigurationCorrect": " 收到此邮件,代表邮件配置正确",
"TrialEmailN_InvalidSenderEmailConfig": "发件人配置错误,请核对服务器地址或者授权码是否填写有误",
// ------------------------------------------------------------Financial--------------------------------------------------------------------
//CalculateService
"Cal_VolDataErr": "体积数据错误",
//ExchangeRateService
"ExR_SameMthExist": "同月的汇率已存在",
"ExR_MthPymtRate": "按月付款采用汇率",
//PaymentAdjustmentService
"PayAdj_DocPymtLock": "医生付款已确认锁定",
//RankPriceService
"RP_TitleUsedByRev": "此标题已被审稿人付款信息所使用",
//TrialRevenuesPriceService
"TRP_AddMeaningful": "请添加有意义的数据",
// ------------------------------------------------------------ImageAndDoc--------------------------------------------------------------------
//DicomArchiveService
"DAS_NoAnonCacheData": "未取到缓存匿名化配置数据,上传停止,请联系开发人员核实",
//ImageShareService
"ISS_NoImgToShare": "当前检查没有影像可以分享。 ",
"ISS_ResNotExists": "资源不存在。",
"ISS_SharePwdError": "分享密码错误。",
"ISS_ShareExpiration": "资源分享过期。",
//StudyService
"Study_VisitBeforePrevError": "当前访视检查时间{0}不能早于前序访视检查时间{1},请核对检查数据是否有误",
"Study_VisitAfterSubseqError": "当前访视检查时间{0}不能晚于该访视之后的检查时间{1},请核对检查数据是否有误",
"Study_UploadArchiving": "当前有人正在上传归档该检查!",
"Study_VisitEndedNotAllowed": "受试者访视结束,不允许上传!",
"Study_ImgAlreadyUploaded": "此处不可以上传。当前影像检查已经上传给受试者{0}的{1}",
// ------------------------------------------------------------Inspection--------------------------------------------------------------------
//FrontAuditConfigService
"FrontAudit_IdDup": "标识重复",
"FrontAudit_NameDup": "名称重复",
"FrontAudit_CannotDelSub": "存在子类 不能删除",
//InspectionService
"Inspection_UserDisabled": "当前用户已被禁用。",
// ------------------------------------------------------------Institution--------------------------------------------------------------------
//CROService
"CRO_DupName": "已经存在同名的CRO请确认。",
"CRO_InProject": "该CRO已经参与项目不能被删除。",
//HospitalService
"Hospital_DupName": "已经存在同名的医院,请确认。",
"Hospital_SiteAdded": "当前Site已经添加到其他Hospital了。",
"Hospital_HasDoctors": "该医院下已经注册有医生,不可以删除。",
//SiteService
"Site_DupName": "已经存在同名的中心,请确认。",
"Site_InProject": "该中心已经加入项目,不可以被删除。",
//SponsorService
"Sponsor_DupName": "已经存在同名的申办方,请确认。",
"Sponsor_InProject": "该申办方已经加入项目,不允许删除。",
// ------------------------------------------------------------Management--------------------------------------------------------------------
//MenuService
"Menu_ParentDupChild": "该父节点下已经存在同名的子节点。",
"Menu_ChildExist": "该节点存在子节点,请在删除子节点后,再删除该节点。",
//UserService
"User_UsernameExist": "用户名已经存在。",
"User_PhoneDup": "该用户类型中已存在具有相同的电话的用户。",
"User_EmailDup": "该用户类型中已存在具有相同邮箱的用户。",
"User_NewOldPwdSame": "新密码与旧密码相同。",
"User_OldPwdInvalid": "旧密码验证失败。",
"User_LegalEmail": "请输入合法的电子邮件。",
"User_VerificationCodeError": "验证码错误。",
"User_VerificationCodeExpired": "验证码已经过期。",
"User_CreateFailed": "请检查邮箱地址或者联系维护人员, 邮件发送失败, 未能创建账户成功。",
"User_InvalidEmail": "请输入一个正确的邮箱。",
"User_EmailError": "邮箱错误。",
"User_InProject": "该用户已经参加项目,不能够删除。",
"User_Disabled": "该用户已经被禁用。",
//UserTypeService
"UserType_InUse": "该用户类型中已存在用户,不能删除。",
// ------------------------------------------------------------QC--------------------------------------------------------------------
//QCCommon
"QCCommon_CannotOperate": "CRC已提交影像不能进行操作。",
"QCCommon_NoPermission": "您不是该质控任务当前领取人,没有操作权限!",
"QCCommon_CheckTimeEarly": "当前访视检查时间{0}不能早于前序访视检查时间{1},请核对检查数据是否有误",
"QCCommon_CheckTimeLate": "当前访视检查时间{0}不能晚于该访视之后的检查时间{1},请核对检查数据是否有误",
//QCOperationService
"QCOperation_CheckFirst": "请先核查图像,并保存审核问题,然后再发质疑。",
"QCOperation_QuestionExist": "当前访视未关闭的质疑已设置了同意CRC重传影像。请在CRC完成影像重传后先关闭原质疑再添加新的质疑。",
"QCOperation_QuestionCannotClose": "CRC已申请重传或者QC同意重传不允许关闭该质疑。请在QC拒绝重传申请或者CRC设置重传影像后再关闭质疑。",
"QCOperation_CloseReason": "关闭原因: ",
"QCOperation_QuestionReplied": "当前QC质疑已经回复。",
"QCOperation_NoPermissionReply": "您没有权限回复一致性核查对话。",
"QCOperation_CannotClose": "当前访视处于申请重传状态, 不允许关闭质疑。",
"QCOperation_Reason": "原因:",
"QCOperation_CannotPass": "当前访视处于回退状态,不允许设置一致性核查通过",
"QCOperation_PassAfterClose": "请先关闭一致性核查质疑后,再设置一致性核查通过。",
"QCOperation_Cannotback": "当前访视已通过一致性核查,不允许申请重传",
"QCOperation_CRCRollback": "CRC申请重传",
"QCOperation_OtherCRC": "其他CRC已申请处理请刷新页面",
"QCOperation_PMReject": "PM/APM拒绝一致性核查回退",
"QCOperation_NoPermission": "您不具备操作权限。",
"QCOperation_CannotRollback": "当前访视还未进行核查或者核查已通过,不允许设置回退。",
"QCOperation_PMAPMConsistency": "PM/APM同意一致性核查回退。",
"QCOperation_NoModifyAfterSubmit": "提交之后,不允许修改!",
"QCOperation_UnresolvedQCQuery": "当前访视有质疑未关闭,不允许该操作",
"QCOperation_CrcNoDelete": "CRC已经提交不允许删除。",
"QCOperation_NoRecipient": "您不是该质控任务当前领取人,没有操作权限!",
"QCOperation_QCImageTaskAlreadyReleased": "当前访视的影像质控任务已被原领取人释放。您可以通过“领取”获得",
"QCOperation_QCTaskNoAccess": "当前访视的影像质控任务已被其他QC领取不允许领取",
"QCOperation_QCConfigFirst": "请先配置影像质控审核问题,再领取影像质控任务",
"QCOperation_NoQC": "项目配置为不审没有领取QC Task",
"QCOperation_InitialAuditPassed": "初审已通过,不能继续领取",
"QCOperation_NoSingleAudit": "项目配置为单审,不满足Submmit State已提交 或者 Audit State待审核/审核中, 不允许领取,请刷新界面",
"QCOperation_NoSameReviewer": "复审不能和初审是同一个人",
"QCOperation_NoSecondaryAudit": "项目配置为复审,不满足提交状态:已提交或者审核状态:待审核/QC中, 不允许领取,请刷新界面",
"QCOperation_NoTaskAccess": "您不是该质控任务当前领取人,没有操作权限!",
"QCOperation_NoQCFunction": "项目配置影像质控为不审,不需要取消任务功能",
"QCOperation_NoTaskOwner": "当前访视影像质控任务没有当前领取人,不能释放。",
"QCOperation_DiseaseProgressConfirmation": "当前访视要求进行疾病进展确认。请在提交当前访视前,先处理未提交的前序访视:{0}。",
"QCOperation_UnsubmittedVisits": "在提交当前访视后,请尽快处理尚未提交的前序访视:{0}。",
"QCOperation_NoBaselineData": "基线没有临床数据,确认提交?",
"QCOperation_NoImageData": "有访视未上传任何Dicom/非Dicom影像数据不允许提交",
"QCOperation_ImagesSubmitted": "当前访视的影像数据已经由其他CRC提交。",
"QCOperation_BatchImagesSubmitted": "当前批量提交访视的影像数据其中部分已由其他CRC提交。",
"QCOperation_MissingBaselineDate": "项目配置了需要填写访视基准日期。但是受试者没有填写访视基准日期,不允许提交",
"QCOperation_RemoveItem": "您已经被移出项目,没有操作权限。",
"QCOperation_QCNotClosed": "当前访视有影像质控质疑未关闭,不能进行此操作。",
"QCOperation_NoQCNeeded": "项目配置影像质控为不审,不需要设置为影像质控通过。",
"QCOperation_QCNotSaved": "影像质控审核问题没有保存,不能进行此操作。",
"QCOperation_NotChangePass": "项目配置影像质控为单审,当前访视影像质控任务不能从当前审核状态变更到 审核通过。",
"QCOperation_CannotChangeToPass": "项目配置影像质控为双审。当前审核状态为 {0},不能变更到 审核通过。",
"QCOperation_NoQCNeededNotEnd": "项目配置影像质控为不审,不允许设置影像质控终止。",
"QCOperation_CannotChangeToStop": "项目配置影像质控为单审,当前审核状态不为 In Primary QC不能变更到 审核终止",
"QCOperation_CannotChangeStop": "项目配置影像质控为双审,当前审核状态为 {0},不能变更到 审核终止",
"QCOperation_InvalidResend": "当前重传状态不为QC同意重传不允许重传",
"QCOperation_NoResendNeeded": "不审操作,不会有需要重传的操作!",
"QCOperation_InvalidAgreeResend": "当前重传状态不为CRC申请重传不允许设置同意重传",
"QCOperation_CannotAgreeResend": "当前访视,有一个未关闭的质疑 QC设置了同意重传CRC还未完成上传当前不允许再次设置",
"QCOperation_AgreeResend": "QC同意重传",
"QCOperation_InvalidCompleteResend": "当前重传状态不为QC同意重传不允许设置重传完成",
"QCOperation_NoImageNotAllowed": "当前没有影像,不允许设置重传完成",
"QCOperation_CRCTransferCompleted": "CRC已重传完成",
"QCOperation_InvalidTransferStatus": "当前质疑重传状态不为初始状态|CRC重传完成状态不允许申请重传",
"QCOperation_CRCTransfer": "CRC申请重传/上传影像",
"QCOperation_CannotModifyConfirmation": "该访视已提交,不能修改入组确认状态",
"QCOperation_CannotModifyPDStatus": "该访视为回退访视不允许修改PD确认状态",
"QCOperation_ForwardingFailed": "转发影像失败。",
//QCQuestionService
"QCQuestion_DuplicateIndexFailed": "序号重复,操作失败",
"QCQuestion_HasChildQuestion": "当前任务存在子问题,删除失败",
//TrialQCQuestionService
"TrialQCQuestion_TemplateConfirmed": "影像质控审核问题模板已经确认,不允许操作。",
"TrialQCQuestion_DuplicateIndexFailed": "序号重复,操作失败",
"TrialQCQuestion_DeleteChildFirst": "请在删除父问题前,请先删除引用该父问题的子问题。",
"TrialQCQuestion_ReferencedByQCProcess": "该审核问题已被影像质控过程引用,不允许删除",
// ------------------------------------------------------------QC--------------------------------------------------------------------
// ------------------------------------------------------------SiteSurvey--------------------------------------------------------------------
//TrialSiteEquipmentSurveyService
"TrialSiteEquipment_Locked": "已锁定,不允许操作",
//TrialSiteSurveyService
"TrialSiteSurvey_InvalidEmail": "请输入正确的邮箱地址。",
"TrialSiteSurvey_WrongVerificationCode": "验证码错误。",
"TrialSiteSurvey_ExpiredVerificationCode": "验证码已经过期。",
"TrialSiteSurvey_NoRecordToUpdate": "该中心不存在该交接人的中心调研记录表,不允许选择更新。",
"TrialSiteSurvey_RecordUnderReview": "您的中心调研记录正在审核中,不允许进行更新操作。若需要更新,请在驳回后进行操作。",
"TrialSiteSurvey_LockedByCurrentUser": "当前中心中,您提交调研记录表已锁定,不允许更新其他人邮箱调研记录。",
"TrialSiteSurvey_LockedByOtherUsers": "当前中心,您提交的调研记录表已锁定。当前存在其他人员提交的调研记录表未锁定,不允许更新您之前提交的调研记录。",
"TrialSiteSurvey_UnlockedRecordsExist": "当前中心存在未锁定的调研记录,不允许更新已锁定的调研记录。",
"TrialSiteSurvey_NonLatestLockedRecord": "该邮箱{0}对应的调查表不是最新锁定的记录,不允许更新!",
"TrialSiteSurvey_AlreadyFilledByOtherUsers": "该中心下已经有其他用户已填写的调研表,您不被允许继续填写",
"TrialSiteSurvey_Locked": "中心调研已锁定,不允许操作。",
"TrialSiteSurvey_IRCNotification": "[来自展影IRC] [{0}] 关于中心调研审批的提醒",
"TrialSiteSurvey_CancelUnsubmittedRecord": "只允许废除未提交的记录。",
"TrialSiteSurvey_NoAdminAcces": "不允许管理员操作。",
"TrialSiteSurvey_FailedToGenerateAccountId": "生成账户Id 未取到值,请排查",
"TrialSiteSurvey_IRCInvitation": "[来自展影IRC] [{0}] 邀请信",
"TrialSiteSurvey_IRCInvitationContent": " 您好,展影医疗作为 实验方案号:{0} 项目的IRC供应商诚邀您参加该项目IRC相关工作欢迎您提供指导和建议非常感谢",
"TrialSiteSurvey_ViewAndConfirm": "查看并确认",
//TrialSiteUserSurveyService
"TrialSiteUser_Locked": "已锁定,不允许操作",
"TrialSiteUser_InconsistentInfo": "该邮件地址在系统中所对应的用户为 {0}, 电话号码是 {1}。请将所输入的信息修改为与系统一致后,再保存。",
"TrialSiteUser_NoTestUserForFormal": "正式类型 、培训类型的项目 不允许加入测试用户",
"TrialSiteUser_NoFormalUserForTest": "测试项目 不允许加入正式用户",
// ------------------------------------------------------------Stat--------------------------------------------------------------------
// ------------------------------------------------------------TrialSiteUser--------------------------------------------------------------------
//TrialConfigService
"TrialConfig_JudgeTaskFail": "有裁判问题未配置产生裁判阅片任务的条件,操作失败!",
"TrialConfig_StdConfigMissing": "当前标准下未配置问题",
"TrialConfig_AddEvalReq": "选择了附加评估,必须勾选附加评估类型",
"TrialConfig_SignTemplateMissing": "该操作需要电子签名确认,但未在系统中找到该场景的签名模板。",
"TrialConfig_ProjectEnded": "该项目已结束或停止,不允许修改配置。",
"TrialConfig_NoImageAuditQuestion": "当前未添加影像质控审核问题。请先添加影像质控审核问题,再进行确认。",
"TrialConfig_DuplicateAuditQuestionId": "影像质控审核问题显示序号不能重复。",
"TrialConfig_InvalidParentQuestionId": "父问题的显示序号要比子问题的显示序号小,请确认。",
"TrialConfig_AuditQuestionConfirmed": "影像质控审核问题已被其他人员确认,不允许再次确认。",
"TrialConfig_ProjectNotInitialized": "该项目当前状态不是初始化,不允许进行该操作。",
"TrialConfig_UnconfirmedConfiguration": "该项目的项目配置、访视管理尚未完成,无法将项目状态设为”启动”。",
"TrialConfig_UnconfirmedUNACKD": "该项目的项目配置、访视管理中,有未确认项,无法变更项目状态。",
"TrialConfig_ProjectNotStarted": "项目没有进入启动状态,不能设置为停止或完成状态",
//TrialExternalUserService
"TrialExternalUser_Inconsistency": "该邮件地址在系统中所对应的用户为 {0}, 电话号码是 {1}。请将所输入的信息修改为与系统一致后,再保存。",
"TrialExternalUser_EmailTypeDuplicate": "系统已经存在与列表中填写的邮箱和用户类型相同的账户,请确认。",
"TrialExternalUser_TestUserNotAllowed": "正式类型 、培训类型的项目 不允许加入测试用户 ",
"TrialExternalUser_FormalUserNotAllowed": "测试项目 不允许加入正式用户 ",
"TrialExternalUser_NotEditable": "人员信息不支持编辑,请删除后重新添加。",
"TrialExternalUser_CannotDelete": "当前用户已参与到项目,不允许删除",
"TrialExternalUser_IRCInvitation": " 您好,展影医疗作为 实验方案号:{0} 项目的IRC供应商诚邀您参加该项目IRC相关工作欢迎您提供指导和建议非常感谢",
"TrialExternalUser_ViewAndConfirm": "查看并确认",
"TrialExternalUser_InvitationExpired": "邀请加入时间已过期,重新被邀请后才可以进行确认操作",
"TrialExternalUser_AccountInfo": "[来自展影IRC] [{0}] 账户信息",
"TrialExternalUser_Welcome": "您好,欢迎您参加项目 实验方案号:{0}IRC相关工作。该项目采用电子化工作流系统及您的账号信息如下",
"TrialExternalUser_ProjectNumber": "项目编号: {0}",
"TrialExternalUser_ExperimentPlanNumber": "试验方案号: {0}",
"TrialExternalUser_ExperimentName": "试验名称: {0}",
"TrialExternalUser_Username": "用户名: {0}",
"TrialExternalUser_Password": "密码: ({0})(请在登录后进行修改) : ***(您已有账号, 若忘记密码, 请通过邮箱找回)",
"TrialExternalUser_Role": "角色: {0}",
"TrialExternalUser_LoginUrl": "系统登录地址: {0} ",
"TrialExternalUser_ReinvitationRequired": "邀请加入时间已过期,重新被邀请后才可以进行确认操作",
"TrialExternalUser_UserIdStorageProblem": "调研表系统用户Id 存储有问题",
"TrialExternalUser_IRCAccountInfo": "[来自展影IRC] [{0}] 账户信息",
//TrialMaintenanceService
"TrialMaint_PersonnelJoined": "人员已加入现场维护",
//TrialService
"Trial_PMApmPermission": "只有PM/APM拥有操作权限!",
"Trial_TestUserCreateOnlyNonFormal": "测试用户 只能创建非正式项目",
"Trial_DuplicateProjectNumber": "已经存在相同的项目编号。",
"Trial_InvalidProjectStatus": "项目状态只有处于:初始化或者进行中时,才允许操作。",
"Trial_CannotDeleteProject": "当前运行环境下,不允许删除项目数据。",
//TrialSiteService
"TrialSite_ParticipantJoined": "已有受试者加入中心,无法禁用",
"TrialSite_CodeDuplicate": "代码不能重复",
"TrialSite_CannotDeleteAssociatedCRC": "中心已经和CRC关联不能删除",
"TrialSite_CannotDeleteAssociatedSubject": "受试者已经添加,不能删除",
"TrialSite_CannotDeleteUploadedData": "中心已经上传调研,无法删除",
// ------------------------------------------------------------Visit--------------------------------------------------------------------
//SubjectService
"Subject_NoConfirmedPlan": "项目访视计划没有确认。请联系项目经理确认项目访视计划后,再添加受试者。",
"Subject_DuplicateSubjectNum": "已存在具有相关受试者编号的受试者。",
"Subject_UploadedVisitNoDelete": "该受试者已经有访视已经上传影像,不允许删除。",
//SubjectVisitService
"Visit_DuplicateVisitNo": "该受试者的访视计划中已经包含一个具有相同访视号的访视。",
"Visit_LastVisitNoChange": "该受试者已经有访视设置为末次访视,不允许将当前访视设置为末次访视。",
"Visit_DuplicateVisitName": "该受试者的访视计划中已经包含一个具有相同访视名称的访视。",
"Visit_NoExtraVisitAfterLast": "设置末次评估后,不允许添加计划外访视。",
"Visit_FinishedTasksNoAdd": "该受试者后续访视已有任务完成阅片(有序阅片标准),不允许在此添加,如果确实需要,请回退",
"Visit_NoPDStatusChangeAfterSubmission": "当前访视影像提交后不允许修改PD确认状态。",
"Visit_UploadedNoLost": "当前访视已经有影像上传,不允许设置为失访。",
"Visit_UploadedNoDelete": "当前访视已经有影像上传,不允许删除。",
"Visit_PlanVisitNoDelete": "计划内的访视不允许删除。",
"Visit_PreviousVisitNoDelete": "当前访视已经被设置为另一访视的上一访视,不允许删除。",
//VisitPlanService
"VisitPlan_OnlyInitOrOngoing": "只有当项目状态为:初始化或进行中时,可以操作。",
"VisitPlan_LargerVisitNumLargerInterval": "访视计划中,访视号大的访视,其访视间隔也应该比访视号小的访视大。",
"VisitPlan_LargerPlanNumLargerInterval": "访视计划中,访视号大的计划访视,其访视间隔也应该比访视号小的计划访视大。",
"VisitPlan_ExistNameOrNumTemplate": "访视计划中已经存在具有项目访视名称或者访视号的计划访视模板。",
"VisitPlan_ExistBaseline": "访视计划中已经存在基线。",
"VisitPlan_ExistBaselineImgNoModify": "有受试者的基线已经上传了影像数据,不允许修改基线访视。",
"VisitPlan_OnlyInitOrOngoingModifyConfirm": "仅仅在项目初始化或者进行中时,才允许修改确认",
"VisitPlan_NoBaselineNotConfirm": "没有基线,不允许确认",
"VisitPlan_ConfigNotConfirmNotConfirm": "项目配置未确认,不允许确认访视计划",
"VisitPlan_BaselineNotMinDayNotConfirm": "基线VisitDay 不是最小的, 不允许确认",
"VisitPlan_CheckExport": "检查导出_{0}.xlsx",
"VisitPlan_Assigned": "访问计划已分配给受试者并已执行",
// ------------------------------------------------------------WorkLoad--------------------------------------------------------------------
//DoctorWorkloadService
"DoctorWorkload_AssignType": "已分配任务,不允许减少阅片类型",
"DoctorWorkload_Unique": "此类数据唯一",
"DoctorWorkload_FeeSettled": "费用已结算,工作量无法修改",
//EnrollService
"Enroll_NotFound": "无法找到项目{0}",
"Enroll_EmailFormat": "{0}邮箱格式存在问题",
"Enroll_CannotRollback": "已有分配的审核人员不能回退",
// ------------------------------------------------------------Triggers--------------------------------------------------------------------
//AddlTrialUserTrigger
"AddlTrialUser_NoTestUser": "正式类型 、培训类型的项目 不允许加入测试用户",
"AddlTrialUser_NoFormalUser": "测试项目不允许加入正式用户",
//SubjectStateTrigger
"SubjectState_CannotSetCurrentAsLastVisit": "该受试者已经有访视被设置为末次访视,不允许将当前访视设置为末次访视。",
"SubjectState_CannotSetAsLastVisitWithImage": "该受试者当前访视后有访视的影像已上传,当前访视不允许设置为末次访视。",
//SubjectVisitFinalVisitTrigger
"SubjectVisit_CannotSetAsLastVisit": "该受试者已有后续访视已上传影像或已提交,当前访视不允许设置为末次访视。",
// ------------------------------------------------------------BusinessFilter--------------------------------------------------------------------
//LimitUserRequestAuthorization
"LimitUser_AuthTokenMissing": "当前请求未从Header/Url取到用户Token,请联系开发者",
"LimitUser_AccountLoggedInElsewhere": "您的账户在其他地方已登陆,您被迫下线。",
//ModelActionFilter
"ModelAction_InvalidAPIParameter": "提供给接口的参数无效。",
//ProjectExceptionFilter
"ProjectException_ConcurrentUpdateNotAllowed": "并发更新,当前不允许该操作",
"Project_ExceptionContactDeveloper": "程序异常,请联系开发人员。 ",
//TrialResourceFilter
"TrialResource_NoAccessPermission": "对不起,您的账户没有操作权限。",
"TrialResource_ReferTrialIdFailed": "正则取请求Refer 中trialId 失败,请联系开发人员核查",
"TrialResource_InterceptedProjectStatusRule": "本次请求被配置规则拦截:项目状态处于进行中时,才允许操作,若此处逻辑有误,请联系开发人员修改",
"TrialResource_MissingProjectNumber": "该接口参数中,没有传递项目编号,请核对。",
//UnifiedApiResultFilter
"UnifiedAPI_ProgramError": "程序错误,请联系开发人员。",
// ------------------------------------------------------------Helper--------------------------------------------------------------------
//FileStoreHelper
"FileStore_TemplateFileNotFound": "数据库没有找到对应的数据模板文件,请联系系统运维人员。",
"FileStore_TemplateFileStoragePathInvalid": "文件不存在,请联系系统管理员!",
//SendEmailHelper
"SendEmail_SendFail": "邮件发送失败,您进行的操作未能成功,请检查邮箱或联系维护人员",
"SendEmail_NoRecipient": "没有收件人",
// ------------------------------------------------------------IRaCIS.Core.Domain--------------------------------------------------------------------
//Trial
"Trial_number": "编号由5位数字组成前2位为中心编号后3位为顺序号请与EDC录入的编号保持一致",
// ------------------------------------------------------------IRaCIS.Core.Infrastructure--------------------------------------------------------------------
//ResponseOutput
"RO_BizObjNotExistsOrParamIncorrect": "业务对象{0}在数据库中不存在,或被他人删除,或参数查询不正确导致",
"RO_ExpectChangeButNoEffect": "期望发生更改,但数据库数据没有更改",
"RO_SaveFailed": "保存失败"
}
}

View File

@ -200,8 +200,16 @@ namespace IRaCIS.Core.Application.ViewModel
//任务来源访视Id 方便回更访视读片状态
public Guid? SourceSubjectVisitId { get; set; }
public Guid? SouceReadModuleId { get; set; }
public List<PIReadingResult> PIReadingResultList { get; set; }
}
public class PIReadingResult
{
public Guid QuestionId { get; set; }
public string Answer { get; set; }
}
@ -457,6 +465,13 @@ namespace IRaCIS.Core.Application.ViewModel
public Guid VisitTaskId { get; set; }
}
public class ClinicalDataDialog
{
public Guid Id { get; set; }
public DateTime CreateTime { get; set; }
public string Content { get; set; }
}
public class PIAuditDialogListView : PIAuditTaskCommand
{
@ -471,7 +486,7 @@ namespace IRaCIS.Core.Application.ViewModel
public Guid CreateUserId { get; set; }
public string CreateUserName { get; set; }
public string CreateUserName { get; set; }
public DateTime CreateTime { get; set; }

View File

@ -24,6 +24,7 @@ using IRaCIS.Core.Domain.Share.Reading;
using Quartz;
using IRaCIS.Application.Services.BackGroundJob;
using Magicodes.ExporterAndImporter.Core.Extension;
using Hangfire;
namespace IRaCIS.Core.Application.Service.Allocation
{
@ -43,6 +44,7 @@ namespace IRaCIS.Core.Application.Service.Allocation
private readonly IRepository<VisitTaskReReading> _visitTaskReReadingRepository;
private readonly IRepository<TaskMedicalReview> _taskMedicalReviewRepository;
private readonly IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository;
private readonly IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository;
private readonly IRepository<ReadingClinicalData> _readingClinicalDataReposiotry;
@ -58,7 +60,8 @@ namespace IRaCIS.Core.Application.Service.Allocation
IRepository<ReadingTaskQuestionAnswer> readingTaskQuestionAnswerRepository
, IRepository<ReadingQuestionCriterionTrial> trialReadingCriterionRepository,
IRepository<ReadingClinicalData> readingClinicalDataReposiotry,
IRepository<PIAudit> PIAuditRepository
IRepository<PIAudit> PIAuditRepository,
IRepository<ReadingQuestionTrial> readingQuestionTrialRepository
)
{
_PIAuditRepository = PIAuditRepository;
@ -72,7 +75,7 @@ namespace IRaCIS.Core.Application.Service.Allocation
_taskMedicalReviewRepository = taskMedicalReviewRepository;
_readingTaskQuestionAnswerRepository = readingTaskQuestionAnswerRepository;
_trialReadingCriterionRepository = trialReadingCriterionRepository;
_readingQuestionTrialRepository = readingQuestionTrialRepository;
}
/// <summary>
@ -231,6 +234,11 @@ namespace IRaCIS.Core.Application.Service.Allocation
var trialTaskConfig = _trialRepository.Where(t => t.Id == queryVisitTask.TrialId).ProjectTo<TrialUrgentConfig>(_mapper.ConfigurationProvider).FirstOrDefault();
var questionList = _readingQuestionTrialRepository.Where(t => t.TrialId == queryVisitTask.TrialId && t.ReadingQuestionCriterionTrialId == queryVisitTask.TrialReadingCriterionId)
.Where(t => t.IsJudgeQuestion == true)
.Select(t => new { QuestionId = t.Id, QuestionName = _userInfo.IsEn_Us ? t.QuestionEnName : t.QuestionName ,t.DictionaryCode}).ToList();
trialTaskConfig!.OtherObj = questionList;
return ResponseOutput.Ok(pageList, trialTaskConfig);
}
@ -280,7 +288,7 @@ namespace IRaCIS.Core.Application.Service.Allocation
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> PIAuditTaskEnrollOrPD(PIAuditTaskEnrollOrPdCommand incommand, [FromServices] ITrialEmailNoticeConfigService trialEmailNoticeConfigService)
public async Task<IResponseOutput> PIAuditTaskEnrollOrPD(PIAuditTaskEnrollOrPdCommand incommand, [FromServices] IEmailSendService emailSendService)
{
var visitTask = await _visitTaskRepository.FirstOrDefaultAsync(t => t.Id == incommand.VisitTaskId);
visitTask.IsEnrollment = incommand.IsEnrollment != null ? incommand.IsEnrollment : visitTask.IsEnrollment;
@ -290,7 +298,7 @@ namespace IRaCIS.Core.Application.Service.Allocation
await _visitTaskRepository.SaveChangesAsync();
await trialEmailNoticeConfigService.CommonBusinessScenarioSendEmailAsync(visitTask.Id, incommand.IsEnrollment, incommand.IsPDConfirm);
await emailSendService.SendEnrollOrPdEmail(visitTask.Id, incommand.IsEnrollment, incommand.IsPDConfirm);
return ResponseOutput.Ok();
}
@ -329,6 +337,27 @@ namespace IRaCIS.Core.Application.Service.Allocation
}
public async Task<IResponseOutput> AddClinicalDataDialog(Guid visiTaskId, string content,
[FromServices] IRepository<SubjectVisitClinicalDialog> subjectVisitClinicalDialogRepository,
[FromServices] IEmailSendService emailSendService)
{
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => new { t.SourceSubjectVisitId, t.Subject.Code, t.SourceSubjectVisit.VisitName, t.Trial.ResearchProgramNo, t.Trial.TrialCode }).FirstOrDefaultAsync();
await subjectVisitClinicalDialogRepository.AddAsync(new SubjectVisitClinicalDialog() { SubjectVisitId = (Guid)taskInfo.SourceSubjectVisitId, Content = content }, true);
await emailSendService.SendClinicalDataQuestionAsync(visiTaskId, content);
return ResponseOutput.Ok();
}
public async Task<List<ClinicalDataDialog>> GetClinicalDataDialog(Guid visiTaskId,
[FromServices] IRepository<SubjectVisitClinicalDialog> _subjectVisitClinicalDialogRepository)
{
var subjectVisitId = await _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => t.SourceSubjectVisitId).FirstOrDefaultAsync();
var list = _subjectVisitClinicalDialogRepository.Where(t => t.SubjectVisitId == subjectVisitId).ProjectTo<ClinicalDataDialog>(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToList();
return list;
}
/// <summary>
@ -340,7 +369,7 @@ namespace IRaCIS.Core.Application.Service.Allocation
public async Task<IResponseOutput<PageOutput<ReadingTaskView>>> GetReadingTaskList(VisitTaskQuery queryVisitTask)
{
var visitTaskQueryable = GetReadingTaskQueryable(queryVisitTask)
.ProjectTo<ReadingTaskView>(_mapper.ConfigurationProvider);
.ProjectTo<ReadingTaskView>(_mapper.ConfigurationProvider,new { isEn_Us =_userInfo.IsEn_Us });
var defalutSortArray = new string[] { nameof(VisitTask.IsUrgent) + " desc", nameof(VisitTask.SubjectId), nameof(VisitTask.VisitTaskNum) };
@ -348,6 +377,11 @@ namespace IRaCIS.Core.Application.Service.Allocation
var trialTaskConfig = _trialRepository.Where(t => t.Id == queryVisitTask.TrialId).ProjectTo<TrialUrgentConfig>(_mapper.ConfigurationProvider).FirstOrDefault();
var questionList = _readingQuestionTrialRepository.Where(t => t.TrialId == queryVisitTask.TrialId && t.Id == queryVisitTask.TrialReadingCriterionId)
.Where(t => t.IsJudgeQuestion == true)
.Select(t => new { QuestionId = t.Id, QuestionName = _userInfo.IsEn_Us ? t.QuestionEnName : t.QuestionName, t.DictionaryCode }).ToList();
trialTaskConfig!.OtherObj = questionList;
return ResponseOutput.Ok(pageList, trialTaskConfig);
}

View File

@ -38,10 +38,11 @@ namespace IRaCIS.Core.Application.Service
.ForMember(o => o.OncologyTaskTypeCount, t => t.MapFrom(u => u.SubjectVisitTaskList.Where(t => t.ReadingCategory == ReadingCategory.Oncology && t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect).Select(t => t.VisitTaskNum).Distinct().Count()))
.ForMember(o => o.JudgeTaskTypeCount, t => t.MapFrom(u => u.SubjectVisitTaskList.Where(t => t.ReadingCategory == ReadingCategory.Judge && t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect).Select(t => t.VisitTaskNum).Distinct().Count()));
CreateMap<SubjectVisitClinicalDialog, ClinicalDataDialog>();
CreateMap<SubjectVisit, VisitGenerataTaskDTO>();
@ -73,14 +74,16 @@ namespace IRaCIS.Core.Application.Service
.ForMember(o => o.PDState, t => t.MapFrom(u => u.SourceSubjectVisit.PDState)) ;
var isEn_Us = true;
CreateMap<VisitTask, JudgeVisitTaskView>().IncludeBase<VisitTask, VisitTaskView>()
.ForMember(o => o.HistoryReadingDoctorUserList, t => t.MapFrom(u => u.JudgeVisitList));
CreateMap<VisitTask, ReadingTaskView>().IncludeBase<VisitTask, VisitTaskView>();
CreateMap<VisitTask, ReadingTaskView>().IncludeBase<VisitTask, VisitTaskView>()
.ForMember(t=>t.PIReadingResultList,u=>u.MapFrom(c=>c.ReadingTaskQuestionAnswerList
.Where(t=>t.ReadingQuestionTrial.IsJudgeQuestion==true ).Select(d=>new PIReadingResult() { QuestionId= d.ReadingQuestionTrialId,Answer=d.Answer})));
CreateMap<VisitTask, PIReaingTaskView>().IncludeBase<VisitTask, ReadingTaskView>()
.ForMember(o => o.FirstAuditUserName, t => t.MapFrom(u => u.FirstAuditUser.UserName))

View File

@ -3,10 +3,16 @@
// 生成时间 2022-02-15 11:55:57
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
namespace IRaCIS.Core.Application.Contracts
{
public class TrialSelectEmailNoticeConfigView: EmailNoticeConfigView
{
public bool IsHaveSelected { get; set; }
}
/// <summary> EmailNoticeConfigView 列表视图模型 </summary>
public class EmailNoticeConfigView : EmailNoticeConfigAddOrEdit
{
@ -19,6 +25,12 @@ namespace IRaCIS.Core.Application.Contracts
public List<EmailUserTypeDto> EmailNoticeUserList { get; set; }
public new List<UserTypeEnum> ToUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList();
public new List<UserTypeEnum> CopyUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList();
//[JsonIgnore]
//public SystemBasicDataSelect Scenario { get; set; }
////public Guid? ScenarioParentId => Scenario.ParentId;
@ -28,6 +40,13 @@ namespace IRaCIS.Core.Application.Contracts
}
public class EmailUserTypeDto
{
public UserTypeEnum UserType { get; set; }
public EmailUserType EmailUserType { get; set; }
}
///<summary>EmailNoticeConfigQuery 列表查询参数模型</summary>
public class EmailNoticeConfigQuery:PageInput
{
@ -36,9 +55,14 @@ namespace IRaCIS.Core.Application.Contracts
public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; }
public bool? IsReturnRequired { get; set; }
public bool? IsUrgent { get; set; }
public bool? IsEnable { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
public Guid? TrialId { get; set; }
public bool? IsDistinguishCriteria { get; set; }
}
///<summary> EmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
@ -47,7 +71,6 @@ namespace IRaCIS.Core.Application.Contracts
public Guid? Id { get; set; }
public string Code { get; set; } = String.Empty;
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
/// <summary>
@ -55,23 +78,59 @@ namespace IRaCIS.Core.Application.Contracts
/// </summary>
public bool IsDistinguishCriteria { get; set; }
//public string AuthorizationCode { get; set; } = String.Empty;
//public Guid ScenarioId { get; set; }
//public string Title { get; set; } = String.Empty;
//public string Body { get; set; } = String.Empty;
//public string FromEmail { get; set; } = String.Empty;
//public string ReceiveEmail { get; set; } = String.Empty;
//public string CopyEmail { get; set; } = String.Empty;
public bool IsReturnRequired { get; set; }
public bool IsUrgent { get; set; }
public bool IsEnable { get; set; }
public bool IsAutoSend { get; set; }
public bool IsDeleted { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
public string Description { get; set; } = string.Empty;
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
public string AttachName { get; set; }
public string AttachNameCN { get; set; }
public List<UserTypeEnum> ToUserTypeList { get; set; }
public List<UserTypeEnum> CopyUserTypeList { get; set; }
}
}

View File

@ -17,19 +17,22 @@ namespace IRaCIS.Core.Application.Contracts
public class EmailNoticeConfigService : BaseService, IEmailNoticeConfigService
{
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigrepository;
private readonly IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository;
public EmailNoticeConfigService(IRepository<EmailNoticeConfig> repository)
public EmailNoticeConfigService(IRepository<EmailNoticeConfig> repository, IRepository<EmailNoticeUserType> emailNoticeUserTypeRepository)
{
_emailNoticeConfigrepository = repository;
_emailNoticeUserTypeRepository = emailNoticeUserTypeRepository;
}
[HttpPost]
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig)
{
var emailNoticeConfigQueryable = _emailNoticeConfigrepository
.WhereIf(queryEmailNoticeConfig.IsDistinguishCriteria != null, t => t.IsDistinguishCriteria == queryEmailNoticeConfig.IsDistinguishCriteria)
.WhereIf(queryEmailNoticeConfig.CriterionTypeEnum != null, t => t.CriterionTypeEnum == queryEmailNoticeConfig.CriterionTypeEnum)
.WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum)
.WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired)
.WhereIf(queryEmailNoticeConfig.IsUrgent != null, t => t.IsUrgent == queryEmailNoticeConfig.IsUrgent)
.WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable)
.ProjectTo<EmailNoticeConfigView>(_mapper.ConfigurationProvider);
@ -39,10 +42,55 @@ namespace IRaCIS.Core.Application.Contracts
public async Task<IResponseOutput> AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig)
{
var entity = await _emailNoticeConfigrepository.InsertOrUpdateAsync(addOrEditEmailNoticeConfig, true);
if (addOrEditEmailNoticeConfig.Id == null)
{
var entity = _mapper.Map<EmailNoticeConfig>(addOrEditEmailNoticeConfig);
foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList)
{
entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item });
}
foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList)
{
entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item });
}
await _emailNoticeConfigrepository.AddAsync(entity, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
else
{
var emailNoticeConfigId = addOrEditEmailNoticeConfig.Id;
await _emailNoticeUserTypeRepository.BatchDeleteNoTrackingAsync(t => t.EmailNoticeConfigId == emailNoticeConfigId);
foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList)
{
await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item,EmailNoticeConfigId= (Guid)emailNoticeConfigId });
}
foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList)
{
await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item, EmailNoticeConfigId = (Guid)emailNoticeConfigId });
}
var entity = await _emailNoticeConfigrepository.UpdateFromDTOAsync(addOrEditEmailNoticeConfig, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
return ResponseOutput.Ok(entity.Id.ToString());
}

View File

@ -48,7 +48,7 @@ namespace IRaCIS.Core.Application.Service
if (!Version.TryParse(addOrEditPublishLog.Version, out version))
{
return ResponseOutput.NotOk("版本号不符合要求");
return ResponseOutput.NotOk(_localizer["PublishLog_VersionNotMatch"]);
}
var verifyExp1 = new EntityVerifyExp<PublishLog>()

View File

@ -3,6 +3,7 @@ using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
namespace IRaCIS.Core.Application.Service
{
@ -20,7 +21,18 @@ namespace IRaCIS.Core.Application.Service
CreateMap<FrontAuditConfig, FrontAuditConfigAddOrEdit>().ReverseMap();
CreateMap<EmailNoticeConfigAddOrEdit, EmailNoticeConfig>().ReverseMap();
CreateMap<EmailNoticeConfig, EmailNoticeConfigView>();
CreateMap<EmailNoticeUserType, EmailUserTypeDto>();
var trialId = Guid.Empty;
CreateMap<EmailNoticeConfig, TrialSelectEmailNoticeConfigView>().IncludeBase<EmailNoticeConfig, EmailNoticeConfigView>()
.ForMember(o => o.IsHaveSelected, t => t.MapFrom(u => u.TrialEmailNoticeConfigList.Any(c=>c.TrialId==trialId && c.SysEmailNoticeConfigId==u.Id)))
;
CreateMap<EmailNoticeConfig, EmailNoticeConfigView>()
.ForMember(t => t.EmailNoticeUserList, u => u.MapFrom(c => c.EmailNoticeUserTypeList));
CreateMap<Dictionary, DicView>()
.ForMember(t => t.ParentCode, u => u.MapFrom(c => c.Parent.Code));

View File

@ -77,7 +77,7 @@ namespace IRaCIS.Core.Application.ViewModel
/// <summary>
/// SMTP端口
/// </summary>
public int? EmailSMTPServerPort { get; set; }
public int EmailSMTPServerPort { get; set; }
/// <summary>
/// 是否配置过邮箱
@ -100,7 +100,7 @@ namespace IRaCIS.Core.Application.ViewModel
[NotDefault]
public Guid TrialId { get; set; }
public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; }
public EmailBusinessScenario? BusinessScenarioEnum { get; set; }
//public CriterionType? CriterionTypeEnum { get; set; }
@ -117,50 +117,97 @@ namespace IRaCIS.Core.Application.ViewModel
public Guid TrialReadingCriterionId { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
}
///<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
public class TrialEmailNoticeConfigAddOrEdit
public class BatchAddTrialEmailNoticeConfig
{
public Guid? Id { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
public string Code { get; set; } = string.Empty;
public Guid? TrialReadingCriterionId { get; set; }
public Guid TrialId { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
public List<UserTypeEnum> ToUserTypeList { get; set; }
public List<UserTypeEnum> CopyUserTypeList { get; set; }
public bool IsEnable { get; set; }
public bool IsAutoSend { get; set; }
public bool IsReturnRequired { get; set; }
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; } = string.Empty;
public string AttachNameCN { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
}
///<summary> TrialEmailNoticeConfigAddOrEdit 列表查询参数模型</summary>
public class TrialEmailNoticeConfigAddOrEdit: BatchAddTrialEmailNoticeConfig
{
public Guid? TrialReadingCriterionId { get; set; }
public string AuthorizationCode { get; set; } = string.Empty;
public string SMTPServerAddress { get; set; } = string.Empty;
public int SMTPServerPort { get; set; }
public CriterionType CriterionTypeEnum { get; set; }
public string FromName { get; set; } = string.Empty;
public string FromEmail { get; set; } = string.Empty;
public List<UserTypeEnum>? ToUserTypeList { get; set; }
public List<UserTypeEnum> CopyUserTypeList { get; set; }
public bool IsUrgent { get; set; }
public bool IsAutoSend { get; set; }
public bool IsReturnRequired { get; set; }
public string FilePath { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public List<Guid> BlackUserIdList { get; set; }
}

View File

@ -0,0 +1,460 @@
using DocumentFormat.OpenXml.EMMA;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MailKit;
using Microsoft.Extensions.Options;
using Microsoft.VisualBasic;
using MimeKit;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service
{
public interface IEmailSendService
{
Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm);
Task SendClinicalDataQuestionAsync(Guid visitTaskId, string content);
Task SendTrialImageQCTaskEmailAsync(Guid trialId);
Task SendTrialQCQuestionEmailAsync(Guid trialId);
Task SendTrialImageQuestionAsync(Guid trialId);
Task SendPIAuditResultAsync(Guid visitTaskId);
}
public class EmailSendService : BaseService, IEmailSendService
{
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IDictionaryService _dictionaryService;
private readonly IOptionsMonitor<SystemEmailSendConfig> _SystemEmailSendConfig;
public readonly static string EmailNamePlaceholder="EmailNamePlaceholder";
public EmailSendService(IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<EmailNoticeConfig> emailNoticeConfigRepository, IRepository<Trial> trialRepository, IOptionsMonitor<SystemEmailSendConfig> systemEmailSendConfig, IDictionaryService dictionaryService)
{
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_emailNoticeConfigRepository = emailNoticeConfigRepository;
_trialRepository = trialRepository;
_SystemEmailSendConfig = systemEmailSendConfig;
_dictionaryService = dictionaryService;
}
//入组确认/PD确认
public async Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm)
{
EmailBusinessScenario businessScenarioEnum;
bool? result = null;
if (isEnrollment != null && isPDConfirm == null)
{
businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed;
result = isEnrollment;
}
else
{
businessScenarioEnum = EmailBusinessScenario.PDConfirmed;
result = isPDConfirm;
}
var taskInfo = await _repository.Where<VisitTask>(t => t.Id == visitTaskId).Select(t => new
{
t.Subject.SiteId,
t.Trial.ResearchProgramNo,
t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
t.Trial.Sponsor.SponsorName,
t.SourceSubjectVisit.VisitName,
t.TrialId,
}).FirstNotNullAsync();
var isEn_us = _userInfo.IsEn_Us;
var resultStr = isEn_us ? (result == true ? "Yes" : "No") : (result == true ? "是" : "否");
if (isEnrollment == true)
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, resultStr);
return (topicStr, htmlBodyStr,isEn_us, null);
};
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc);
}
else
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName, resultStr);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc,taskInfo.SiteId);
}
}
/// <summary>
/// 影像质控
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialImageQCTaskEmailAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = await _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
//找到 该项目的IQC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
var userIdList = userList.Select(t => t.UserId).ToList();
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository.Where(t => t.Id == trialId)
.Where(t => t.QCProcessEnum != TrialQCProcess.NotAudit)
.Select(t => new
{
//待领取量
ToBeClaimedCount = t.SubjectVisitList.Where(u => u.SubmitState==SubmitStateEnum.Submitted && u.CurrentActionUserId == null && (u.PreliminaryAuditUserId == null || (u.PreliminaryAuditUserId != userId && u.ReviewAuditUserId == null))).Count(),
//待审核通过统计从已领取到QC提交之间的 已领取 待审核 审核中 (审核完成 领取人就会清理 所以只用查询当前领取人是自己的就好了)
ToBeReviewedCount = t.SubjectVisitList.Where(u => u.CurrentActionUserId == userId).Count()
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人 有待领取的或者有待审核的才发邮件
if (sendStat != null && (sendStat.ToBeClaimedCount > 0 || sendStat.ToBeReviewedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false,userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCTask, topicAndHtmlFunc);
}
}
}
/// <summary>
/// QC质疑
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialQCQuestionEmailAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr,t.DeclarationTypeEnumList }).FirstOrDefault();
//找到 该项目的IQC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository
.Where(t => t.Id == trialId)
.Select(t => new
{
ReUploadTobeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList)
.Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && u.ReuploadEnum == QCChanllengeReuploadEnum.CRCRequestReupload).Count(),
//质疑待处理 发送邮件的时候 需要减去ReUploadTobeDealedCount
ToBeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList)
.Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Count(),
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人
if (sendStat != null && (sendStat.ToBeDealedCount > 0 || sendStat.ReUploadTobeDealedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeDealedCount- sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, false, userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCQuestion, topicAndHtmlFunc);
}
}
}
/// <summary>
/// 影像质疑
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task SendTrialImageQuestionAsync(Guid trialId)
{
var isEn_us = false;
var trialInfo = _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstOrDefault();
//找到 该项目的CRC 用户Id
var userList = await _repository.Where<TrialUser>(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.User.FullName }).ToListAsync();
//判断是否任务可以领取 ,可以的话 发送邮件
foreach (var user in userList)
{
var userId = user.UserId;
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
var query = _trialRepository.Where(t=>t.Id==trialId)
.Select(t => new
{
//质疑待处理
ToBeDealedCount = t.SubjectVisitList.Where(t=>t.TrialSite.CRCUserList.Any(t=>t.UserId==userId)).SelectMany(c => c.QCChallengeList)
.Where(u => u.IsClosed == false && (u.LatestReplyUser.UserTypeEnum == UserTypeEnum.IQC || u.LatestReplyUserId==null)).Count(),
});
var sendStat = await query.FirstOrDefaultAsync();
//当前人
if (sendStat != null && (sendStat.ToBeDealedCount > 0))
{
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
user.FullName, DateTime.Now, sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, userId);
};
await SendTrialEmailAsync(trialId, EmailBusinessScenario.ImageQuestion, topicAndHtmlFunc);
}
}
}
//临床数据质询
public async Task SendClinicalDataQuestionAsync(Guid visitTaskId, string content)
{
var isEn_us = _userInfo.IsEn_Us;
var info = await _repository.Where<VisitTask>(t => t.Id == visitTaskId, ignoreQueryFilters: true).Select(t => new { t.TrialId, t.Trial.ResearchProgramNo, t.Trial.TrialCode, t.SourceSubjectVisit.VisitName, t.Subject.SiteId, t.Subject.Code }).FirstOrDefaultAsync();
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, info.ResearchProgramNo,info.Code,info.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, info.ResearchProgramNo, info.Code, info.VisitName,_userInfo.UserName,content, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(info.TrialId, EmailBusinessScenario.ClinicalDataQuestion, topicAndHtmlFunc,info.SiteId);
}
public async Task SendPIAuditResultAsync(Guid visitTaskId)
{
var isEn_us = _userInfo.IsEn_Us;
var info = await _repository.Where<VisitTask>(t => t.Id == visitTaskId, ignoreQueryFilters: true).Select(t => new { t.TrialId, t.Trial.ResearchProgramNo, t.Trial.TrialCode, t.SourceSubjectVisit.VisitName, t.Subject.SiteId, t.Subject.Code }).FirstOrDefaultAsync();
var answerList= await _repository.Where<VisitTask>(t => t.Id == visitTaskId, ignoreQueryFilters: true).SelectMany(t=>t.ReadingTaskQuestionAnswerList).Where(t=>t.ReadingQuestionTrial.IsJudgeQuestion==true).Select(t=>new { QuestionName= isEn_us? t.ReadingQuestionTrial.QuestionEnName:t.ReadingQuestionTrial.QuestionName, t.ReadingQuestionTrial.DictionaryCode, t.Answer}).ToListAsync();
var template = " <div style=\"margin-left: 2ch;\"> {0}: {1} </div>";
var needTranslateDicNameList=answerList.Where(t=>!string.IsNullOrEmpty(t.DictionaryCode)).Select(t=>t.DictionaryCode).ToList();
var translateDataList = await _dictionaryService.GetBasicDataSelect(needTranslateDicNameList.ToArray());
Func<bool, string, string, string> transFunc = (bool isNeedTranslate, string dicCode, string answer) =>
{
if (isNeedTranslate && translateDataList.ContainsKey(dicCode))
{
var result = translateDataList[dicCode].Where(t => t.Code.ToLower() == answer.ToLower()).Select(t => isEn_us ? t.Value : t.ValueCN).FirstOrDefault() ?? answer;
return result;
}
else
{
return answer;
}
};
var piResult= string.Join(' ', answerList.Select(t => string.Format(template, t.QuestionName, transFunc(!string.IsNullOrEmpty(t.DictionaryCode),t.DictionaryCode,t.Answer ) ))) ;
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
{
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, info.ResearchProgramNo, info.Code, info.VisitName);
var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN,
EmailNamePlaceholder, info.ResearchProgramNo, info.Code, info.VisitName, _userInfo.UserName, piResult, _SystemEmailSendConfig.CurrentValue.SiteUrl);
return (topicStr, htmlBodyStr, isEn_us, null);
};
await SendTrialEmailAsync(info.TrialId, EmailBusinessScenario.PIAuditResutl, topicAndHtmlFunc, info.SiteId);
}
public async Task SendTrialEmailAsync(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? siteId = null, Guid? trialReadingCriterionId = null)
{
//找到配置
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false)
{
return;
}
else
{
var sendEmailConfig = new SMTPEmailConfig();
var (topicStr, htmlBodyStr, isEn_us,onlyToUserId) = topicAndHtmlFunc(trialEmailConfig);
sendEmailConfig.TopicDescription = topicStr;
sendEmailConfig.HtmlBodyStr = htmlBodyStr;
var blackUserIdList = trialEmailConfig.TrialEmailBlackUserList.Select(t => t.UserId).ToList();
var toUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(c => c.UserType).ToList();
var copyUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(c => c.UserType).ToList();
var allUserTypeEnumList = toUserTypeEnumList.Union(copyUserTypeEnumList).Distinct().ToList();
var allUserList = await _repository.Where<TrialUser>(t => t.TrialId == trialId && allUserTypeEnumList.Contains(t.User.UserTypeEnum)).Select(t => new { t.UserId, t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToListAsync();
var toUserList = allUserList.Where(t => toUserTypeEnumList.Contains(t.UserTypeEnum))
.ToList();
//收件人 有CRC CRA CRC CRA的账户要按照中心发送
if (siteId == null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA) && onlyToUserId == null)
{
throw new BusinessValidationFailedException("当前场景收件人包含CRC CRA,但是没有siteId,请联系后端开发");
}
if (siteId != null && toUserTypeEnumList.Any(t=>t==UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA))
{
var curentSiteUserIdList= _repository.Where<TrialSiteUser>(t=>t.TrialId==trialId && t.SiteId==siteId).Select(t=>t.UserId).ToList();
toUserList=toUserList.Where(t=>(t.UserTypeEnum!=UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator)|| curentSiteUserIdList.Contains(t.UserId)).ToList();
}
//去除黑名单
toUserList = toUserList.Where(t => !blackUserIdList.Contains(t.UserId)).ToList();
var copyUserList = allUserList.Where(t => copyUserTypeEnumList.Contains(t.UserTypeEnum)).Where(t => !blackUserIdList.Contains(t.UserId)).ToList();
if(onlyToUserId!=null)
{
toUserList= toUserList.Where(t=>t.UserId == onlyToUserId).ToList();
}
else
{
sendEmailConfig.HtmlBodyStr = htmlBodyStr.Replace(EmailNamePlaceholder, string.Join(isEn_us ? ", " : "、", toUserList.Select(t => t.FullName).ToList()));
}
if (toUserList.Count() == 0)
{
//---没有收件人,无法发送邮件
throw new BusinessValidationFailedException(_localizer["TrialEmailN_NoRecipient"]);
}
if (trialEmailConfig.FromEmail.Contains("@") && !string.IsNullOrEmpty(trialEmailConfig.FromEmail))
{
sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(trialEmailConfig.FromName, trialEmailConfig.FromEmail);
sendEmailConfig.AuthorizationCode = trialEmailConfig.AuthorizationCode;
sendEmailConfig.UserName = trialEmailConfig.FromEmail;
sendEmailConfig.Host = trialEmailConfig.SMTPServerAddress;
sendEmailConfig.Port = trialEmailConfig.SMTPServerPort;
}
else
{
//---项目发件邮箱配置有误,请核实
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidEmailConfig"]);
}
foreach (var item in toUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
foreach (var item in copyUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
await SendEmailHelper.SendEmailAsync(sendEmailConfig);
}
}
}
}

View File

@ -25,7 +25,6 @@ namespace IRaCIS.Core.Application.Interfaces
Task<string> BaseBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? isMedicalReviewAndSuggestApplyReReading = null, EmailStoreSendMode emailStoreMode = EmailStoreSendMode.StoreLocalSend, string sendFileRelativePath="");
Task CommonBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? IsEnrollment, bool? IsPDConfirm);
}

View File

@ -32,30 +32,41 @@ namespace IRaCIS.Core.Application.Service
{
private readonly IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository;
private readonly IRepository<TrialEmailBlackUser> _trialEmailBlackUserRepository;
private readonly IRepository<EmailNoticeConfig> _emailNoticeConfigRepository;
private readonly IRepository<Trial> _trialRepository;
private readonly IRepository<TaskMedicalReview> _taskMedicalReviewRepository;
private readonly IRepository<VisitTask> _visitTaskRepository;
private readonly IRepository<TrialUser> _trialUserRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
public IRepository<VisitTask> _visitTaskRepository { get; }
public IRepository<TrialUser> _trialUserRepository { get; }
public IRepository<Subject> _subjectRepository { get; }
public IRepository<SubjectVisit> _subjectVisitRepository { get; }
public TrialEmailNoticeConfigService(IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository, IRepository<VisitTask> visitTaskRepository,
public TrialEmailNoticeConfigService(
IRepository<TrialEmailNoticeConfig> trialEmailNoticeConfigRepository,
IRepository<VisitTask> visitTaskRepository,
IRepository<Trial> trialRepository,
IRepository<TrialUser> trialUserRepository, IRepository<TaskMedicalReview> taskMedicalReviewRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository)
IRepository<TrialUser> trialUserRepository,
IRepository<TaskMedicalReview> taskMedicalReviewRepository,
IRepository<Subject> subjectRepository,
IRepository<SubjectVisit> subjectVisitRepository,
IRepository<TrialEmailBlackUser> trialEmailBlackUserRepository,
IRepository<EmailNoticeConfig> emailNoticeConfigRepository
)
{
_trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository;
_visitTaskRepository = visitTaskRepository;
this._trialRepository = trialRepository;
_trialRepository = trialRepository;
_trialUserRepository = trialUserRepository;
_taskMedicalReviewRepository = taskMedicalReviewRepository;
_subjectRepository = subjectRepository;
_subjectVisitRepository = subjectVisitRepository;
_trialEmailBlackUserRepository = trialEmailBlackUserRepository;
_emailNoticeConfigRepository = emailNoticeConfigRepository;
}
/// <summary>
@ -66,7 +77,7 @@ namespace IRaCIS.Core.Application.Service
[HttpPost]
public async Task<GetTrialEmailSetOutDto> GetTrialEmail(GetTrialEmailSetInDto inDto)
{
return await _trialRepository.Where(x => x.Id == inDto.TrialId).Select(x => new GetTrialEmailSetOutDto()
return await _trialRepository.Where(x => x.Id == inDto.TrialId,ignoreQueryFilters:true).Select(x => new GetTrialEmailSetOutDto()
{
TrialId = inDto.TrialId,
EmailAuthorizationCode = x.EmailAuthorizationCode,
@ -76,7 +87,7 @@ namespace IRaCIS.Core.Application.Service
IsConfigureEmail = x.IsConfigureEmail,
EmailSMTPServerPort = x.EmailSMTPServerPort
}).FirstNotNullAsync();
}).FirstOrDefaultAsync();
}
/// <summary>
@ -94,7 +105,7 @@ namespace IRaCIS.Core.Application.Service
FromEmail = inDto.EmailFromEmail,
FromName = inDto.EmailFromName,
SMTPServerAddress = inDto.EmailSMTPServerAddress,
SMTPServerPort = inDto.EmailSMTPServerPort.Value,
SMTPServerPort = inDto.EmailSMTPServerPort,
TrialId = inDto.TrialId,
});
@ -117,7 +128,7 @@ namespace IRaCIS.Core.Application.Service
FromEmail = inDto.EmailFromEmail,
FromName = inDto.EmailFromName,
SMTPServerAddress = inDto.EmailSMTPServerAddress,
SMTPServerPort = inDto.EmailSMTPServerPort.Value,
SMTPServerPort = inDto.EmailSMTPServerPort,
});
await _trialRepository.SaveChangesAsync();
@ -125,7 +136,7 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 同步系统配置的文档到想项目中
/// 同步系统配置的文档到想项目中 ---废弃
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
@ -148,8 +159,10 @@ namespace IRaCIS.Core.Application.Service
var confirmedCriterionTypeList = list.Select(t => (CriterionType?)t.CriterionType).ToList();
var docmentList = _repository.Where<CommonDocument>(t => t.BusinessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed || t.BusinessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
.Where(t => (confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)) || t.CriterionTypeEnum == null).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum }).ToList();
var docmentList = _repository.Where<TrialEmailNoticeConfig>(t => t.BusinessScenarioEnum == EmailBusinessScenario.EnrollConfirmed || t.BusinessScenarioEnum == EmailBusinessScenario.PDConfirmed)
//.Where(t => (confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)) || t.CriterionTypeEnum == null).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum })
.ToList();
foreach (var item in docmentList)
@ -158,8 +171,8 @@ namespace IRaCIS.Core.Application.Service
{
TrialId = trialId,
TrialReadingCriterionId = list.Where(t => t.CriterionType == item.CriterionTypeEnum).FirstOrDefault()?.TrialReadingCriterionId,
FileName = item.Name,
FilePath = item.Path,
//FileName = item.Name,
//FilePath = item.Path,
BusinessScenarioEnum = item.BusinessScenarioEnum,
Code = item.Code
});
@ -176,166 +189,6 @@ namespace IRaCIS.Core.Application.Service
}
public async Task CommonBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm)
{
#region 区分场景
CommonDocumentBusinessScenario businessScenarioEnum;
if (isEnrollment != null && isPDConfirm == null)
{
businessScenarioEnum = CommonDocumentBusinessScenario.EnrollConfirmed;
}
else /*if (isEnrollment == null && isPDConfirm != null)*/
{
businessScenarioEnum = CommonDocumentBusinessScenario.PDConfirmed;
}
#endregion
#region 任务 基本信息,邮件需要
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new
{
t.Subject.SiteId,
t.Trial.ResearchProgramNo,
t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
t.Trial.Sponsor.SponsorName,
t.TrialId,
}).FirstNotNullAsync();
var trialId = taskInfo.TrialId;
#endregion
#region 发收件人配置 确保无误
var emailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId==null && t.BusinessScenarioEnum == businessScenarioEnum)
.Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync();
if (emailConfig == null || emailConfig.IsAutoSend == false)
{
return;
}
var sendEmailConfig = new SMTPEmailConfig();
//收件人 如果是CRC CRA 要按照中心发送
var toUserTypeEnumList = emailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(c => c.UserType).ToList();
var toUserList = _repository.Where<TrialSiteUser>(t => t.TrialId == trialId && toUserTypeEnumList.Contains(t.User.UserTypeEnum) && t.SiteId == taskInfo.SiteId).Select(t => new { t.User.EMail, t.User.FullName }).ToList();
var copyUserTypeEnumList = emailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(c => c.UserType).ToList();
var copyUserList = _repository.Where<TrialUser>(t => t.TrialId == trialId && copyUserTypeEnumList.Contains(t.User.UserTypeEnum)).Select(t => new { t.User.EMail, t.User.FullName }).ToList();
if (toUserList.Count() == 0)
{
//---没有收件人,无法发送邮件
throw new BusinessValidationFailedException(_localizer["TrialEmailN_NoRecipient"]);
}
if (emailConfig.FromEmail.Contains("@") && !string.IsNullOrEmpty(emailConfig.FromEmail))
{
sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(emailConfig.FromName, emailConfig.FromEmail);
sendEmailConfig.AuthorizationCode = emailConfig.AuthorizationCode;
sendEmailConfig.UserName = emailConfig.FromEmail;
sendEmailConfig.Host = emailConfig.SMTPServerAddress;
sendEmailConfig.Port = emailConfig.SMTPServerPort;
}
else
{
//---项目发件邮箱配置有误,请核实
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidEmailConfig"]);
}
foreach (var item in toUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
foreach (var item in copyUserList)
{
if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail))
{
sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail));
}
}
#endregion
#region 确保 设置邮件Tile
var pathToFile = _hostEnvironment.WebRootPath
+ Path.DirectorySeparatorChar.ToString()
+ "EmailTemplate"
+ Path.DirectorySeparatorChar.ToString()
//+ "SubjectEnrollConfirmOrPDProgress.html";
+ (_userInfo.IsEn_Us ? "SubjectEnrollConfirmOrPDProgress_US.html" : "SubjectEnrollConfirmOrPDProgress.html");
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_EnrollmentConfirmation", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
{
var templateInfo = SourceReader.ReadToEnd();
sendEmailConfig.HtmlBodyStr = string.Format(templateInfo,
//--- 附件为疾病进展确认报告,
//_localizer["TrialEmailN_SubjectDiseaseProgression"]
$"请查收 关于{taskInfo.ResearchProgramNo}项目{taskInfo.SubjectCode}受试者入组确认已完成 PI / MM入组确认{(isEnrollment == true ? "" : "")}"
);
}
}
else /*if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)*/
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_PDReport", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile))
{
var templateInfo = SourceReader.ReadToEnd();
sendEmailConfig.HtmlBodyStr = string.Format(templateInfo,
//--- 附件为疾病进展确认报告,请查收
//_localizer["TrialEmailN_SubjectDiseaseProgression"]
$"请查收 关于{taskInfo.ResearchProgramNo}项目{taskInfo.SubjectCode}受试者PD确认已完成 PI / MM PD确认{(isPDConfirm == true ? "" : "")}"
);
}
}
#endregion
await SendEmailHelper.SendEmailAsync(sendEmailConfig);
}
private async Task<bool> DealMedicalReviewTasKGenerateAndIsSendAsync(Guid trialId, bool? isHandSend, string pdAnswer, List<Guid> taskIdList, List<Guid> minUserIdList)
@ -403,7 +256,7 @@ namespace IRaCIS.Core.Application.Service
public async Task<string> BaseBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? isHandSend, EmailStoreSendMode emailStoreMode, string sendFileRelativePath)
{
CommonDocumentBusinessScenario? businessScenarioEnum = null;
EmailBusinessScenario? businessScenarioEnum = null;
#region 任务关联的项目配置 标准信息及配置subject 信息
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new
@ -471,7 +324,7 @@ namespace IRaCIS.Core.Application.Service
//入组确认场景
if (taskInfo.IsEnrollmentConfirm == true && taskInfo.IsEnrollementQualificationConfirm == true && taskInfo.IsBaseline == true)
{
businessScenarioEnum = CommonDocumentBusinessScenario.EnrollConfirmed;
businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed;
}
@ -480,7 +333,7 @@ namespace IRaCIS.Core.Application.Service
(taskInfo.PDState == PDStateEnum.PDProgress && taskInfo.SourceSubjectVisitId != null) ||
(taskInfo.SouceReadModuleId != null && taskInfo.MoudulePDState == PDStateEnum.PDProgress))
{
businessScenarioEnum = CommonDocumentBusinessScenario.PDConfirmed;
businessScenarioEnum = EmailBusinessScenario.PDConfirmed;
}
else
{
@ -580,7 +433,7 @@ namespace IRaCIS.Core.Application.Service
#region 确保 邮件Html存在
//邮件附件
var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, emailConfig.FilePath);
var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, _userInfo.IsEn_Us ? emailConfig.AttachPath : emailConfig.AttachCNPath);
if (!File.Exists(path))
{
@ -601,7 +454,7 @@ namespace IRaCIS.Core.Application.Service
#region 不同场景 Tile 设置
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_EnrollmentConfirmation", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
@ -616,7 +469,7 @@ namespace IRaCIS.Core.Application.Service
);
}
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
sendEmailConfig.TopicDescription = _localizer["TrialEmailN_PDReport", taskInfo.ResearchProgramNo, taskInfo.SubjectCode];
@ -648,7 +501,7 @@ namespace IRaCIS.Core.Application.Service
//入组确认 根据每个标准配置的是否自动发送,发送邮件与否
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
if (await _repository.Where<ReadingTableQuestionAnswer>().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() &&
x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion))
@ -693,7 +546,7 @@ namespace IRaCIS.Core.Application.Service
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
@ -950,7 +803,7 @@ namespace IRaCIS.Core.Application.Service
//先预先生成了邮件,发送预先生成的邮件
sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig()
{
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf",
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf",
FileStream = File.OpenRead(phyPath),
});
@ -1018,7 +871,7 @@ namespace IRaCIS.Core.Application.Service
sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig()
{
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf",
FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf",
FileStream = pdfMemoryStream
});
@ -1062,7 +915,7 @@ namespace IRaCIS.Core.Application.Service
//找到入组确认 或者Pd 进展 已生成任务的 访视
var subjectVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId & t.CheckState == CheckStateEnum.CVPassed && (t.IsEnrollmentConfirm == true || t.PDState == PDStateEnum.PDProgress)).ToListAsync();
if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed)
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
{
if (trialConfig.IsEnrollementQualificationConfirm == false)
@ -1129,7 +982,7 @@ namespace IRaCIS.Core.Application.Service
}
}
else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed)
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
{
if (trialConfig.IsPDProgressView == false)
@ -1497,19 +1350,127 @@ namespace IRaCIS.Core.Application.Service
var query = _trialUserRepository.Where(t => t.TrialId == trialId, false, true).IgnoreQueryFilters().Select(t => t.User.UserTypeRole).Distinct()
.ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
.ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
return await query.ToListAsync();
}
/// <summary>
/// 黑名单用户Id 列表
/// </summary>
/// <param name="trialEmailNoticeConfigId"></param>
/// <returns></returns>
public async Task<List<TrialSelectUser>> GetTrialUserIdSelectList(Guid trialEmailNoticeConfigId)
{
var trialEmailNoticeConfig = await _trialEmailNoticeConfigRepository.Where(t => t.Id == trialEmailNoticeConfigId).Include(t => t.TrialEmailNoticeUserList).FirstNotNullAsync();
var trialId = trialEmailNoticeConfig.TrialId;
var userTypeList = trialEmailNoticeConfig.TrialEmailNoticeUserList.Select(t => t.UserType).ToList();
var query = _trialUserRepository.Where(t => t.TrialId == trialId && userTypeList.Contains(t.User.UserTypeEnum), false, true).IgnoreQueryFilters()
.Select(t => new TrialSelectUser()
{
UserId = t.UserId,
UserName = t.User.UserName,
RealName = t.User.FullName,
UserTypeEnum = t.User.UserTypeEnum
}).Distinct();
return await query.ToListAsync();
}
/// <summary>
/// 获取系统 邮件配置 勾选列表
/// </summary>
/// <param name="queryEmailNoticeConfig"></param>
/// <returns></returns>
public async Task<PageOutput<TrialSelectEmailNoticeConfigView>> GetSysEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig)
{
var emailNoticeConfigQueryable = _emailNoticeConfigRepository
.WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum)
.WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired)
.WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable)
.ProjectTo<TrialSelectEmailNoticeConfigView>(_mapper.ConfigurationProvider, new { trialId = queryEmailNoticeConfig.TrialId });
return await emailNoticeConfigQueryable.ToPagedListAsync(queryEmailNoticeConfig.PageIndex, queryEmailNoticeConfig.PageSize, queryEmailNoticeConfig.SortField, queryEmailNoticeConfig.Asc);
}
/// <summary>
/// 批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系
/// </summary>
/// <param name="batchAddList"></param>
/// <returns></returns>
public async Task<IResponseOutput> BatchAddSysEmailConfig(List<BatchAddTrialEmailNoticeConfig> batchAddList)
{
var first = batchAddList.First();
var trialId = first.TrialId;
var emailConfig = await _trialRepository.Where(t => t.Id == trialId).Select(x => new
{
TrialId = x.Id,
EmailAuthorizationCode = x.EmailAuthorizationCode,
EmailSMTPServerAddress = x.EmailSMTPServerAddress,
EmailFromEmail = x.EmailFromEmail,
EmailFromName = x.EmailFromName,
IsConfigureEmail = x.IsConfigureEmail,
EmailSMTPServerPort = x.EmailSMTPServerPort
}).FirstNotNullAsync();
var list = await _repository.Where<ReadingQuestionCriterionTrial>(t => t.TrialId == trialId && t.IsConfirm).Select(t => new { t.CriterionType, TrialReadingCriterionId = t.Id }).ToListAsync();
var addList = _mapper.Map<List<TrialEmailNoticeConfig>>(batchAddList);
foreach (var item in addList)
{
item.SysEmailNoticeConfigId = item.Id;
item.Id = Guid.Empty;
item.AuthorizationCode = emailConfig.EmailAuthorizationCode;
item.FromEmail = emailConfig.EmailFromEmail;
item.SMTPServerAddress = emailConfig.EmailSMTPServerAddress;
item.FromName=emailConfig.EmailFromName;
item.SMTPServerPort = emailConfig.EmailSMTPServerPort;
item.IsAutoSend = false;
item.IsEnable = false;
item.TrialReadingCriterionId = list.FirstOrDefault(t => t.CriterionType == item.CriterionTypeEnum)?.TrialReadingCriterionId;
item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId)
.SelectMany(t => t.ToUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = t }));
item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId)
.SelectMany(t => t.CopyUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = t }));
await _trialEmailNoticeConfigRepository.AddAsync(item);
}
await _trialEmailNoticeConfigRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpPost]
public async Task<List<TrialEmailNoticeConfigView>> GetTrialEmailNoticeConfigList(TrialEmailNoticeConfigQuery inQuery)
{
await SyncSystemEmainCofigDocListAsync(inQuery.TrialId);
//await SyncSystemEmainCofigDocListAsync(inQuery.TrialId);
var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.IsDistinguishCriteria == false, t => t.TrialReadingCriterionId == null)
.WhereIf(inQuery.IsDistinguishCriteria == true, t => t.CriterionTypeEnum != null)
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
.WhereIf(inQuery.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == inQuery.BusinessScenarioEnum)
.ProjectTo<TrialEmailNoticeConfigView>(_mapper.ConfigurationProvider);
@ -1517,6 +1478,7 @@ namespace IRaCIS.Core.Application.Service
return await trialEmailNoticeConfigQueryable.ToListAsync();
}
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> AddOrUpdateTrialEmailNoticeConfig(TrialEmailNoticeConfigAddOrEdit addOrEditTrialEmailNoticeConfig)
{
@ -1541,6 +1503,10 @@ namespace IRaCIS.Core.Application.Service
}
foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList)
{
entity.TrialEmailBlackUserList.Add(new TrialEmailBlackUser() { UserId = userid });
}
await _trialEmailNoticeConfigRepository.AddAsync(entity, true);
@ -1549,10 +1515,10 @@ namespace IRaCIS.Core.Application.Service
}
else
{
var id = (Guid)addOrEditTrialEmailNoticeConfig.Id;
await _repository.BatchDeleteAsync<TrialEmailNoticeUser>(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id);
var entity = (await _trialEmailNoticeConfigRepository.Where(t => t.Id == addOrEditTrialEmailNoticeConfig.Id, true, true).Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync()).IfNullThrowException();
await _repository.BatchDeleteAsync<TrialEmailBlackUser>(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id);
List<TrialEmailNoticeUser> trialEmailNoticeUsers = new List<TrialEmailNoticeUser>();
@ -1560,28 +1526,48 @@ namespace IRaCIS.Core.Application.Service
foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserTypeList)
{
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = entity.Id });
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = id });
}
foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserTypeList)
{
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = entity.Id });
trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = id });
}
await _repository.AddRangeAsync(trialEmailNoticeUsers);
foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList)
{
await _trialEmailBlackUserRepository.AddAsync(new TrialEmailBlackUser() { UserId = userid, TrialEmailNoticeConfigId = id });
}
await _trialEmailNoticeConfigRepository.UpdateFromDTOAsync(addOrEditTrialEmailNoticeConfig);
await _trialEmailNoticeConfigRepository.SaveChangesAsync();
var jobId = $"{addOrEditTrialEmailNoticeConfig.TrialId}_{id}";
if (addOrEditTrialEmailNoticeConfig.IsAutoSend)
{
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, addOrEditTrialEmailNoticeConfig.TrialId, addOrEditTrialEmailNoticeConfig.BusinessScenarioEnum, addOrEditTrialEmailNoticeConfig.EmailCron);
}
else
{
HangfireJobHelper.RemoveCronJob(jobId);
}
return ResponseOutput.Ok();
}
}
private async Task TestEmailConfigAsync(TrialEmailNoticeConfigAddOrEdit config)
{
@ -1684,6 +1670,11 @@ namespace IRaCIS.Core.Application.Service
[HttpDelete("{trialEmailNoticeConfigId:guid}")]
public async Task<IResponseOutput> DeleteTrialEmailNoticeConfig(Guid trialEmailNoticeConfigId)
{
var trialId=await _trialEmailNoticeConfigRepository.Where(t=>t.Id==trialEmailNoticeConfigId).Select(t=>t.TrialId).FirstOrDefaultAsync();
var jobId = $"{trialId}_{trialEmailNoticeConfigId}";
HangfireJobHelper.RemoveCronJob(jobId);
var success = await _trialEmailNoticeConfigRepository.DeleteFromQueryAsync(t => t.Id == trialEmailNoticeConfigId, true);
return ResponseOutput.Ok();

View File

@ -72,7 +72,8 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialEmailNoticeConfig, TrialEmailNoticeConfigView>()
.ForMember(d => d.TrialCriterionName, c => c.MapFrom(t => t.TrialReadingCriterion.CriterionName))
.ForMember(d => d.TrialEmailNoticeUserList, c => c.MapFrom(t => t.TrialEmailNoticeUserList));
.ForMember(d => d.TrialEmailNoticeUserList, c => c.MapFrom(t => t.TrialEmailNoticeUserList))
.ForMember(d => d.BlackUserIdList, c => c.MapFrom(t => t.TrialEmailBlackUserList.Select(c=>c.UserId)));
CreateMap<TrialEmailNoticeConfigAddOrEdit, TrialEmailNoticeConfig>();
@ -85,6 +86,9 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialEmailNoticeUser, EmailUserInfoDto>();
CreateMap<BatchAddTrialEmailNoticeConfig, TrialEmailNoticeConfig>();
}
}

View File

@ -190,7 +190,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
.WhereIf(dto.StartTime != null, x => x.CreateTime >= dto.StartTime)
.WhereIf(dto.EndTime != null, x => x.CreateTime <= dto.EndTime)
.WhereIf(dto.ModuleType != null, x => x.ModuleTypeId == dto.ModuleType)
.WhereIf(!dto.Description.IsNullOrEmpty(), x => x.Description == dto.Description)
.WhereIf(!dto.Description.IsNullOrEmpty(), x => x.Description.Contains(dto.Description)|| x.DescriptionCN.Contains(dto.Description))
.WhereIf(!dto.OpByUserName.IsNullOrEmpty(), x => x.CreateUserName.Contains(dto.OpByUserName))
//.WhereIf(!dto.SubjectInfo.IsNullOrEmpty(), x => x.SubjectCode.Contains(dto.SubjectInfo))
.WhereIf(dto.IsSign != null, x => x.IsSign == dto.IsSign);

View File

@ -12,7 +12,7 @@ namespace IRaCIS.Application.Contracts
{
public Guid? Id { get; set; }
public string SiteName { get; set; } = String.Empty;
public string SiteNameCN { get; set; } = String.Empty;
public int Code { get; set; }
public string SiteCode { get; set; } = String.Empty;
@ -54,7 +54,7 @@ namespace IRaCIS.Application.Contracts
public string City { get; set; } = string.Empty;
public string Province { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
}
}

View File

@ -31,6 +31,7 @@ namespace IRaCIS.Application.Services
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.AliasName), t => t.AliasName.Contains(searchModel.AliasName))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.City), t => t.City.Contains(searchModel.City))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.Country), t => t.Country.Contains(searchModel.Country))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.Province), t => t.Country.Contains(searchModel.Province))
.ProjectTo<SiteSelectDTO>(_mapper.ConfigurationProvider);

View File

@ -64,6 +64,16 @@ namespace IRaCIS.Core.Application.Contracts
}
public class TrialSelectUser
{
public Guid UserId { get; set; }
public string UserName { get; set; }
public string RealName { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
}
public class TrialUserType
{

View File

@ -690,7 +690,7 @@ namespace IRaCIS.Application.Services
var userLogQueryable =
_userLogRepository
.WhereIf(inQuery.TrialId != null, t => t.LoginUser.UserTrials.Any(c => c.TrialId == inQuery.TrialId && c.UserId == t.CreateUserId))
.WhereIf(inQuery.TrialId != null, t => t.LoginUser.UserTrials.Any(c => c.TrialId == inQuery.TrialId && c.UserId == t.LoginUserId))
.WhereIf(inQuery.OptType != null, t => t.OptType == inQuery.OptType)
.WhereIf(inQuery.BeginDate != null, t => t.CreateTime >= inQuery.BeginDate)
.WhereIf(inQuery.EndDate != null, t => t.CreateTime <= inQuery.EndDate)

View File

@ -119,7 +119,7 @@ namespace IRaCIS.Core.Application.Contracts
}
else
{
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.PI, UserTypeEnum.MIM };
userTypeEnums = new List<UserTypeEnum>() { UserTypeEnum.PI, UserTypeEnum.MIM , UserTypeEnum.IQC};
}
}

View File

@ -129,7 +129,7 @@ namespace IRaCIS.Core.Application.Contracts.DTO
}
public class GetConsistencyCheckFileDto/*: ConsistencyCheckFile*/
public class GetUserUploadFileDto/*: UserUploadFile*/
{
/// <summary>
/// 文件名称
@ -170,7 +170,7 @@ namespace IRaCIS.Core.Application.Contracts.DTO
}
public class GetConsistencyCheckFileInDto
public class GetUserUploadFileInDto
{
public Guid TrialId { get; set; }
@ -349,9 +349,9 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public int? TotalChallengeCount { get; set; }
public int TotalChallengeCount { get; set; }
public int? NotClosedChallengeCount { get; set; }
public int NotClosedChallengeCount { get; set; }

View File

@ -19,7 +19,7 @@ namespace IRaCIS.Core.Application.Image.QA
private readonly IRepository<ClinicalDataTrialSet> _clinicalDataTrialSet;
private readonly IRepository<TrialQCQuestionAnswer> _trialQCQuestionAnswerRepository;
private readonly IRepository<TrialQCQuestion> _trialQCQuestionRepository;
private readonly IRepository<ConsistencyCheckFile> _consistencyCheckFileRepository;
private readonly IRepository<UserUploadFile> _UserUploadFileRepository;
private IReadingImageTaskService _IReadingImageTaskService;
@ -30,14 +30,14 @@ namespace IRaCIS.Core.Application.Image.QA
IRepository<TrialQCQuestionAnswer> trialQCQuestionAnswerRepository,
IRepository<TrialQCQuestion> trialQCQuestionRepository,
IReadingImageTaskService IReadingImageTaskService,
IRepository<ConsistencyCheckFile> consistencyCheckFileRepository
IRepository<UserUploadFile> UserUploadFileRepository
)
{
this._IReadingImageTaskService = IReadingImageTaskService;
_subjectVisitRepository = subjectVisitRepository;
this._trialQCQuestionAnswerRepository = trialQCQuestionAnswerRepository;
this._trialQCQuestionRepository = trialQCQuestionRepository;
this._consistencyCheckFileRepository = consistencyCheckFileRepository;
this._UserUploadFileRepository = UserUploadFileRepository;
_trialRepository = trialRepository;
this._clinicalDataTrialSet = clinicalDataTrialSet;
}
@ -849,10 +849,10 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<GetConsistencyCheckFileDto>> GetConsistencyCheckFile(GetConsistencyCheckFileInDto indto)
public async Task<PageOutput<GetUserUploadFileDto>> GetUserUploadFile(GetUserUploadFileInDto indto)
{
var query = _repository.Where<ConsistencyCheckFile>(t => t.TrialId == indto.TrialId)
.ProjectTo<GetConsistencyCheckFileDto>(_mapper.ConfigurationProvider);
var query = _repository.Where<UserUploadFile>(t => t.TrialId == indto.TrialId)
.ProjectTo<GetUserUploadFileDto>(_mapper.ConfigurationProvider);
return await query.ToPagedListAsync(indto.PageIndex, indto.PageSize, "CreateTime", false);
}

View File

@ -494,7 +494,7 @@ namespace IRaCIS.Core.Application.Service
;
// 一致性核查文件
CreateMap<ConsistencyCheckFile, GetConsistencyCheckFileDto>()
CreateMap<UserUploadFile, GetUserUploadFileDto>()
.ForMember(d => d.CreateUserName, u => u.MapFrom(t => t.User.FirstName + "/" + t.User.LastName));

View File

@ -11,6 +11,7 @@ using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Domain.Share;
using MassTransit;
using IRaCIS.Core.Domain.Models;
namespace IRaCIS.Core.Application.Service
{
@ -240,12 +241,12 @@ namespace IRaCIS.Core.Application.Service
if (await _trialClinicalQuestionRepository.AnyAsync(x => x.TrialClinicalId == inDto.TrialClinicalId && x.Id != inDto.Id && x.ShowOrder == inDto.ShowOrder))
{
return ResponseOutput.NotOk("问题序号存在重复!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateId"]);
}
if (await _trialClinicalQuestionRepository.AnyAsync(x => x.TrialClinicalId == inDto.TrialClinicalId && x.Id != inDto.Id && x.IsCheckDate == inDto.IsCheckDate&&inDto.IsCheckDate))
{
return ResponseOutput.NotOk("已经添加过类型为检查日期的问题!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateType"]);
}
var entity = await _trialClinicalQuestionRepository.InsertOrUpdateAsync(inDto, true);
@ -338,11 +339,11 @@ namespace IRaCIS.Core.Application.Service
if (await _systemClinicalQuestionRepository.AnyAsync(x => x.SystemClinicalId == inDto.SystemClinicalId && x.Id != inDto.Id && x.ShowOrder == inDto.ShowOrder))
{
return ResponseOutput.NotOk("问题序号存在重复!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateId"]);
}
if (await _systemClinicalQuestionRepository.AnyAsync(x => x.SystemClinicalId == inDto.SystemClinicalId && x.Id != inDto.Id && x.IsCheckDate == inDto.IsCheckDate && inDto.IsCheckDate))
{
return ResponseOutput.NotOk("已经添加过类型为检查日期的问题!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateType"]);
}
var entity = await _systemClinicalQuestionRepository.InsertOrUpdateAsync(inDto, true);
return ResponseOutput.Ok(entity.Id.ToString());
@ -435,7 +436,7 @@ namespace IRaCIS.Core.Application.Service
if (await _systemClinicalTableQuestionRepository.AnyAsync(x => x.QuestionId == inDto.QuestionId && x.Id != inDto.Id && x.ShowOrder == inDto.ShowOrder))
{
return ResponseOutput.NotOk("问题序号存在重复!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateId"]);
}
var entity = await _systemClinicalTableQuestionRepository.InsertOrUpdateAsync(inDto, true);
@ -455,11 +456,46 @@ namespace IRaCIS.Core.Application.Service
var success = await _systemClinicalTableQuestionRepository.DeleteFromQueryAsync(t => t.Id == id, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 获取系统其他表格问题
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<SystemClinicalTableQuestionDto>> GetSystemClinicalOtherTableQuestionList(GetClinicalOtherTableQuestionListInDto inDto)
{
var types = new List<string>()
{
"select","radio"
};
return await this._systemClinicalTableQuestionRepository.Where(x => x.QuestionId == inDto.QuestionId && types.Contains(x.ClinicalTableQuestionType))
.Where(x=>x.Id!= inDto.TableQuestionId)
.ProjectTo<SystemClinicalTableQuestionDto>(_mapper.ConfigurationProvider).ToListAsync();
}
#endregion
#region 项目表格问题
/// <summary>
/// 获取项目其他表格问题
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<TrialClinicalTableQuestionDto>> GetTrialClinicalOtherTableQuestionList(GetClinicalOtherTableQuestionListInDto inDto)
{
var types = new List<string>()
{
"select","radio"
};
return await this._trialClinicalTableQuestionRepository.Where(x => x.QuestionId == inDto.QuestionId && types.Contains(x.ClinicalTableQuestionType))
.Where(x => x.Id != inDto.TableQuestionId)
.ProjectTo<TrialClinicalTableQuestionDto>(_mapper.ConfigurationProvider).ToListAsync();
}
/// <summary>
/// 获取项目表格问题
/// </summary>
@ -498,7 +534,7 @@ namespace IRaCIS.Core.Application.Service
if (await _trialClinicalTableQuestionRepository.AnyAsync(x => x.QuestionId == inDto.QuestionId && x.Id != inDto.Id && x.ShowOrder == inDto.ShowOrder))
{
return ResponseOutput.NotOk("问题序号存在重复!");
return ResponseOutput.NotOk(_localizer["ClinicalQuestion_DuplicateId"]);
}
var entity = await _trialClinicalTableQuestionRepository.InsertOrUpdateAsync(inDto, true);
@ -621,6 +657,11 @@ namespace IRaCIS.Core.Application.Service
tableQuestionRelation.Add(x.Id, newid);
x.Id = newid;
}
if (x.RelevanceId != null)
{
x.RelevanceId = questionRelation[x.RelevanceId ?? default(Guid)];
}
});
foreach (var x in newTrialTableQuestionList)

View File

@ -370,12 +370,18 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
{
public Guid SystemClinicalId { get; set; }
}
public class GetClinicalOtherTableQuestionListInDto
{
public Guid QuestionId { get; set; }
public Guid TableQuestionId { get; set; }
}
#endregion
#region 表格问题
public class ClinicalTableQuestionBase
{
public Guid? Id { get; set; }
@ -456,6 +462,25 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
/// 单位
/// </summary>
public string Unit { get; set; } = string.Empty;
/// <summary>
/// 关联ID
/// </summary>
public Guid? RelevanceId { get; set; }
/// <summary>
/// 关联Value
/// </summary>
public string RelevanceValue
{
get
{
return string.Join(',', this.RelevanceValueList);
}
}
public List<string> RelevanceValueList { get; set; } = new List<string>();
}

View File

@ -462,7 +462,7 @@ namespace IRaCIS.Core.Application.Service
{
await _readingMedicineTrialQuestionRepository.BatchDeleteNoTrackingAsync(x => inDto.Ids.Contains(x.Id));
var result= await _readingMedicineTrialQuestionRepository.SaveChangesAsync();
return ResponseOutput.Result(result);
return ResponseOutput.Ok();
}
@ -518,7 +518,7 @@ namespace IRaCIS.Core.Application.Service
await _readingMedicineTrialQuestionRepository.AddRangeAsync(needList);
var result = await _readingMedicineTrialQuestionRepository.SaveChangesAsync();
return ResponseOutput.Result(result);
return ResponseOutput.Ok();
}

View File

@ -666,7 +666,7 @@ namespace IRaCIS.Application.Services
if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.DoctorUserId != _userInfo.Id && x.SubjectCriterionClaimUserId != _userInfo.Id))
{
throw new BusinessValidationFailedException("当前任务领取人不是你,不允许提交签名");
throw new BusinessValidationFailedException(_localizer["InternationalizationHelper_PathError"]);
}
if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.TaskState != TaskState.Effect))
@ -2536,7 +2536,7 @@ namespace IRaCIS.Application.Services
if (_visitTaskRepository.Any(t => t.Id == claimSubjectDto.SubejctId && t.TrialReadingCriterionId == claimSubjectDto.TrialReadingCriterionId
&& t.SubjectCriterionClaimUserId != _userInfo.Id && t.SubjectCriterionClaimUserId != null))
{
throw new BusinessValidationFailedException("当前任务已被其他人领取,请进行其他的阅片任务");
throw new BusinessValidationFailedException(_localizer["ReadingImageTask_TaskTaken"]);
}
else
{
@ -2580,7 +2580,7 @@ namespace IRaCIS.Application.Services
{
if (_visitTaskRepository.Any(t => t.Id == claimSubjectDto.VisitTaskId && t.DoctorUserId != _userInfo.Id && t.DoctorUserId != null))
{
throw new BusinessValidationFailedException("当前任务已被其他人领取,请进行其他的阅片任务");
throw new BusinessValidationFailedException(_localizer["ReadingImageTask_TaskTaken"]);
}
else
{

View File

@ -43,7 +43,7 @@ namespace IRaCIS.Core.Application.Contracts
if (await _trialSiteSurveyRepository.AnyAsync(t => t.Id == addOrEditTrialSiteEquipmentSurvey.TrialSiteSurveyId && (t.IsDeleted == true ||t.State==TrialSiteSurveyEnum.PMCreatedAndLock), true))
{
return ResponseOutput.NotOk("当前调研表已废除,或者调研表状态已锁定,不允许操作");
return ResponseOutput.NotOk(_localizer["TrialSiteEquipment_Invalid"]);
}

View File

@ -260,7 +260,7 @@ namespace IRaCIS.Core.Application.Contracts
var currentLatest = dbEntityList.OrderByDescending(t => t.CreateTime).FirstOrDefault();
if (currentLatest.Email != userInfo.EmailOrPhone)
if (currentLatest!.Email != userInfo.EmailOrPhone)
{
//---该中心下已经有其他用户已填写的调研表,您不被允许继续填写
return ResponseOutput.NotOk(_localizer["TrialSiteSurvey_AlreadyFilledByOtherUsers"]);
@ -291,7 +291,7 @@ namespace IRaCIS.Core.Application.Contracts
if (currentLatest == null)
{
return ResponseOutput.NotOk("当前site没有调研表可以更新请确认");
return ResponseOutput.NotOk(_localizer["TrialSite_NoSurveyToUpdate"]);
}
if (currentLatest.Email != userInfo.ReplaceUserEmailOrPhone)
@ -317,6 +317,8 @@ namespace IRaCIS.Core.Application.Contracts
copy.State = TrialSiteSurveyEnum.ToSubmit;
copy.IsDeleted = false;
copy.Phone=string.Empty;
copy.UserName=string.Empty;
copy.Email = userInfo.EmailOrPhone;
copy.Id = Guid.Empty;
copy.CreateTime = DateAndTime.Now;
@ -702,7 +704,7 @@ namespace IRaCIS.Core.Application.Contracts
if (trialSiteSurvey.IsDeleted == true || trialSiteSurvey.State == TrialSiteSurveyEnum.PMCreatedAndLock)
{
throw new BusinessValidationFailedException("当前调研表已废除,或者调研表状态已锁定,不允许操作");
throw new BusinessValidationFailedException(_localizer["TrialSiteSurvey_Invalid"]);
}
@ -728,13 +730,13 @@ namespace IRaCIS.Core.Application.Contracts
if (!currentUserList.Any(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator) ||
!currentUserList.Any(t => t.UserTypeEnum == UserTypeEnum.SR))
{
throw new BusinessValidationFailedException("本次提交生成账号必须要有CRC和SR");
throw new BusinessValidationFailedException(_localizer["TrialSiteSurvey_MissingAccount"]);
}
if(currentUserList.GroupBy(t=>new {t.UserTypeId,t.Email})
.Any(g => g.Count() > 1))
{
throw new BusinessValidationFailedException("同一邮箱同一用户类型,生成账号的数据只允许存在一条!");
throw new BusinessValidationFailedException(_localizer["TrialSiteSurvey_DuplicateEmail"]);
}

View File

@ -48,7 +48,7 @@ namespace IRaCIS.Core.Application.Contracts
if (await _trialSiteSurveyRepository.AnyAsync(t => t.Id == addOrEditTrialSiteUserSurvey.TrialSiteSurveyId && (t.IsDeleted == true || t.State == TrialSiteSurveyEnum.PMCreatedAndLock), true))
{
//当前调研表已废除,或者调研表状态已锁定,不允许操作
return ResponseOutput.NotOk("当前调研表已废除,或者调研表状态已锁定,不允许操作");
return ResponseOutput.NotOk(_localizer["TrialSiteUserSurvey_Invalid"]);
}

View File

@ -333,7 +333,7 @@ namespace IRaCIS.Core.Application.Contracts
public UserTypeEnum? PDProgressDefaultUserType { get; set; }
public object? OtherObj { get; set; }
}
public class TrialStateChangeDTO

View File

@ -286,7 +286,7 @@ namespace IRaCIS.Application.Services
await _repository.BatchDeleteAsync<CheckChallengeDialog>(o => o.SubjectVisit.TrialId == trialId);
await _repository.BatchDeleteAsync<ClinicalDataTrialSet>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<ConsistencyCheckFile>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<UserUploadFile>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<CriterionNidusSystem>(o => o.TrialReadingCriterion.TrialId == trialId);
await _repository.BatchDeleteAsync<DataInspection>(o => o.TrialId == trialId);
await _repository.BatchDeleteAsync<DicomStudy>(t => t.TrialId == trialId);

View File

@ -165,7 +165,7 @@ namespace IRaCIS.Core.Application.Services
.WhereIf(!string.IsNullOrWhiteSpace(param.UserKeyInfo), t => t.CRCUserList.Any(k => (k.User.FullName).Contains(param.UserKeyInfo)
|| k.User.UserName.Contains(param.UserKeyInfo) || k.User.EMail.Contains(param.UserKeyInfo)))
.ProjectTo<SiteStatSimpleDTO>(_mapper.ConfigurationProvider);
.ProjectTo<SiteStatSimpleDTO>(_mapper.ConfigurationProvider ,new { isEn_Us = _userInfo.IsEn_Us });
var result = await siteStatQuery.ToPagedListAsync(param.PageIndex,
@ -198,7 +198,7 @@ namespace IRaCIS.Core.Application.Services
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.AliasName), t => t.AliasName.Contains(searchModel.AliasName))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.City), t => t.City.Contains(searchModel.City))
.WhereIf(!string.IsNullOrWhiteSpace(searchModel.Country), t => t.Country.Contains(searchModel.Country))
.ProjectTo<TrialSiteScreeningDTO>(_mapper.ConfigurationProvider, new { trialId = searchModel.TrialId });
.ProjectTo<TrialSiteScreeningDTO>(_mapper.ConfigurationProvider, new { trialId = searchModel.TrialId , isEn_Us =_userInfo.IsEn_Us});
return await siteQueryable.ToPagedListAsync(searchModel.PageIndex,

View File

@ -1,5 +1,6 @@
using AutoMapper;
using AutoMapper.EquivalencyExpression;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
@ -110,8 +111,11 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.HospitalName, u => u.MapFrom(s => s.Hospital.HospitalName));
//trial site 选择列表 subjectVisit pannel 模式添加的时候
var isEn_Us = false;
CreateMap<Site, TrialSiteScreeningDTO>()
.ForMember(d => d.IsSelect, u => u.MapFrom(s => s.TrialSiteList.Any(k => k.TrialId == trialId)));
.ForMember(d => d.IsSelect, u => u.MapFrom(s => s.TrialSiteList.Any(k => k.TrialId == trialId)))
.ForMember(d => d.SiteName, u => u.MapFrom(c=> isEn_Us?c.SiteName:c.SiteNameCN));
#region 项目 stie pannel
@ -144,7 +148,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialSite, SiteStatSimpleDTO>().IncludeMembers(t => t.Site)
.ForMember(d => d.Id, u => u.MapFrom(s => s.Id))
.ForMember(d => d.UpdateTime, u => u.MapFrom(s => s.UpdateTime))
.ForMember(d => d.Site, u => u.MapFrom(s => s.Site.SiteName))
.ForMember(d => d.Site, u => u.MapFrom(s => isEn_Us ?s.Site.SiteName:s.Site.SiteNameCN))
.ForMember(d => d.Hospital, u => u.MapFrom(s => s.Site.Hospital.HospitalName))
.ForMember(d => d.UserCount, u => u.MapFrom(s => s.CRCUserList.Count()))
.ForMember(d => d.UserNameList, u => u.MapFrom(s => s.CRCUserList.Where(t => t.IsDeleted == false).Select(u => u.User.FullName)));
@ -162,7 +166,6 @@ namespace IRaCIS.Core.Application.Service
CreateMap<AssginSiteCRCCommand, TrialSiteUser>();
var isEn_Us = false;
CreateMap<Domain.Models.Trial, TrialConfigDTO>().ForMember(t => t.TrialId, u => u.MapFrom(c => c.Id))
.ForMember(t => t.TrialCriterionIds, u => u.MapFrom(c => c.ReadingQuestionCriterionTrialList.Where(v =>v.IsConfirm).OrderBy(x=>x.ShowOrder).Select(r => r.Id)))

View File

@ -46,25 +46,34 @@ namespace IRaCIS.Application.Services
}
[AllowAnonymous]
public async Task<IResponseOutput> InternationazitionInit()
public async Task<IResponseOutput> GetMemoryStoreData()
{
var rows = await MiniExcel.QueryAsync<InternationalizationAddOrEdit>(@"C:\Users\Administrator\Desktop\Export\vue.xlsx");
foreach (var row in rows)
{
await _repository.InsertOrUpdateAsync<Internationalization, InternationalizationAddOrEdit>(row);
}
await _repository.SaveChangesAsync();
return ResponseOutput.Ok();
return ResponseOutput.Ok(new { StaticData.En_US_Dic , StaticData.Zh_CN_Dic });
}
//[AllowAnonymous]
//public async Task<IResponseOutput> InternationazitionInit()
//{
// var rows = await MiniExcel.QueryAsync<InternationalizationAddOrEdit>(@"C:\Users\Administrator\Desktop\Export\vue.xlsx");
// foreach (var row in rows)
// {
// await _repository.InsertOrUpdateAsync<Internationalization, InternationalizationAddOrEdit>(row);
// }
// await _repository.SaveChangesAsync();
// return ResponseOutput.Ok();
//}
[AllowAnonymous]
[UnitOfWork]
public async Task<string> Get()

View File

@ -10,33 +10,33 @@ using System.Linq.Expressions;
namespace IRaCIS.Core.Application.Triggers
{
public class VisitTaskIAfterSignTrigger : IAfterSaveTrigger<VisitTask>
public class VisitTaskIAfterSignTrigger : IAfterSaveTrigger<VisitTask>,IBeforeSaveTrigger<VisitTask>
{
private readonly IRepository<VisitTask> _visitTaskRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IUserInfo _userInfo;
private readonly IEmailSendService _emailSendService;
public VisitTaskIAfterSignTrigger(IRepository<VisitTask> visitTaskRepository, IRepository<Subject> subjectRepository)
public VisitTaskIAfterSignTrigger(IRepository<VisitTask> visitTaskRepository, IRepository<Subject> subjectRepository, IUserInfo userInfo, IEmailSendService emailSendService)
{
_visitTaskRepository = visitTaskRepository;
_subjectRepository = subjectRepository;
_userInfo = userInfo;
_emailSendService = emailSendService;
}
//添加任务的时候 如果需要签名 并且已经签名了
public async Task AfterSave(ITriggerContext<VisitTask> context, CancellationToken cancellationToken)
{
var visitTask = context.Entity;
if (visitTask.SignTime != null && visitTask.ReadingTaskState == ReadingTaskState.HaveSigned
//&& _subjectRepository.Where(t=>t.Id==visitTask.SubjectId).SelectMany(c=>c.SubjectVisitList)
//.Any(t=>t.Id==visitTask.SourceSubjectVisitId && t.IsBaseLine)
)
if (visitTask.SignTime != null && visitTask.ReadingTaskState == ReadingTaskState.HaveSigned )
{
//任务阅片完成 自动释放
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.SubjectId == visitTask.SubjectId && t.TrialReadingCriterionId==visitTask.TrialReadingCriterionId , t=>new VisitTask() { SubjectCriterionClaimUserId=null});
@ -45,6 +45,19 @@ namespace IRaCIS.Core.Application.Triggers
}
public async Task BeforeSave(ITriggerContext<VisitTask> context, CancellationToken cancellationToken)
{
var visitTask = context.Entity;
if (context.ChangeType == ChangeType.Modified && visitTask.ReadingTaskState==ReadingTaskState.HaveSigned && visitTask.ReadingTaskState != context.UnmodifiedEntity.ReadingTaskState && _userInfo.UserTypeEnumInt == (int)UserTypeEnum.PI)
{
visitTask.PIAuditState = PIAuditState.PIAgree;
}
if (context.ChangeType == ChangeType.Modified && visitTask.PIAuditState!=context.UnmodifiedEntity.PIAuditState && visitTask.PIAuditState==PIAuditState.PIAgree)
{
await _emailSendService.SendPIAuditResultAsync(visitTask.Id);
}
}
}
}

View File

@ -37,13 +37,28 @@ namespace IRaCIS.Core.Domain.Share
public enum CommonDocumentBusinessScenario
{
EnrollConfirmed = 1,
PDConfirmed = 2,
Trial=3,
Reviewer=4,
}
public enum EmailBusinessScenario
{
EnrollConfirmed = 1,
PDConfirmed = 2,
QCTask = 5,
QCQuestion = 6,
ImageQuestion = 7,
ClinicalDataQuestion = 8,
PIAuditResutl=9
}

View File

@ -18,10 +18,58 @@ namespace IRaCIS.Core.Domain.Models
[Table("EmailNoticeConfig")]
public class EmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd,ISoftDelete
{
[JsonIgnore]
public List<TrialEmailNoticeConfig> TrialEmailNoticeConfigList { get; set; }
[JsonIgnore]
public List<EmailNoticeUserType> EmailNoticeUserTypeList { get; set; }=new List<EmailNoticeUserType>();
public string Code { get; set; } = String.Empty;
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
/// <summary> 标准类型 /// </summary>
public CriterionType? CriterionTypeEnum { get; set; }
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; }=string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; } = string.Empty;
public string AttachNameCN { get; set; } = string.Empty;
/// <summary>
/// 是否区分标准
/// </summary>
@ -34,10 +82,6 @@ namespace IRaCIS.Core.Domain.Models
[Required]
public bool IsReturnRequired { get; set; }
[Required]
public bool IsUrgent { get; set; }
public bool IsAutoSend { get; set; }
public bool IsEnable { get; set; }
@ -61,14 +105,21 @@ namespace IRaCIS.Core.Domain.Models
public Guid? DeleteUserId { get; set; }
}
[Table("EmailNoticeUserType")]
public class EmailNoticeUserType:Entity
{
[JsonIgnore]
public EmailNoticeConfig EmailNoticeConfig { get; set; }
public Guid EmailNoticeConfigId { get; set; }
public UserTypeEnum UserType { get; set; }
public EmailUserType EmailUserType { get; set; }
}
}

View File

@ -16,8 +16,11 @@ namespace IRaCIS.Core.Domain.Models
///TrialEmailNoticeConfig
///</summary>
[Table("TrialEmailNoticeConfig")]
public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd
public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd,ISoftDelete
{
[JsonIgnore]
public Trial Trial { get; set; }
[Required]
public Guid TrialId { get; set; }
@ -32,44 +35,71 @@ namespace IRaCIS.Core.Domain.Models
public string FromName { get; set; } = string.Empty;
public List<TrialEmailNoticeUser> TrialEmailNoticeUserList { get; set; } = new List<TrialEmailNoticeUser>();
//[Required]
//public string ReceiveEmailsStr { get; set; } = string.Empty;
//public string CopyEmailsStr { get; set; } = string.Empty;
//[NotMapped]
//public List<string> ReceiveEmailList => ReceiveEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t => !string.IsNullOrEmpty(t)).Select(t=>t.Trim()).ToList();
//[NotMapped]
//public List<string> CopyEmailList => CopyEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t=> !string.IsNullOrEmpty(t)).Select(t => t.Trim()).ToList();
public string FromEmail { get; set; } = string.Empty;
[Required]
public bool IsUrgent { get; set; }
[JsonIgnore]
public List<TrialEmailNoticeUser> TrialEmailNoticeUserList { get; set; } = new List<TrialEmailNoticeUser>();
[Required]
public List<TrialEmailBlackUser> TrialEmailBlackUserList { get; set; } = new List<TrialEmailBlackUser>();
/// <summary> 业务模块 /// </summary>
public int BusinessModuleEnum { get; set; }
/// <summary> 业务层级 /// </summary>
public int BusinessLevelEnum { get; set; }
/// <summary> 邮件类型 /// </summary>
public int EmailTypeEnum { get; set; }
/// <summary> 邮件加急类型 /// </summary>
public int EmailUrgentEnum { get; set; }
/// <summary> 定时周期 /// </summary>
public string EmailCron { get; set; } = string.Empty;
/// <summary> 邮件主题 /// </summary>
public string EmailTopic { get; set; } = string.Empty;
public string EmailTopicCN { get; set; } = string.Empty;
/// <summary> 附件 /// </summary>
public string AttachPath { get; set; } = string.Empty;
public string AttachCNPath { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string AttachName { get; set; }
public string AttachNameCN { get; set; }
public string EmailHtmlContent { get; set; } = string.Empty;
public string EmailHtmlContentCN { get; set; } = string.Empty;
[JsonIgnore]
public EmailNoticeConfig SysEmailNoticeConfig { get; set; }
public Guid? SysEmailNoticeConfigId { get; set; }
[Required]
public string Code { get; set; } = string.Empty;
[Required]
public bool IsReturnRequired { get; set; }
[Required]
public bool IsAutoSend { get; set; }
public bool IsEnable { get; set; }
public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; }
public EmailBusinessScenario BusinessScenarioEnum { get; set; }
public CriterionType? CriterionTypeEnum { get; set; }
@ -80,12 +110,6 @@ namespace IRaCIS.Core.Domain.Models
[JsonIgnore]
public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; }
[Required]
public string FilePath { get; set; } = string.Empty;
[Required]
public string FileName { get; set; } = string.Empty;
[Required]
public Guid CreateUserId { get; set; }
@ -98,7 +122,28 @@ namespace IRaCIS.Core.Domain.Models
[Required]
public DateTime UpdateTime { get; set; }
public bool IsDeleted { get; set; }
}
public DateTime? DeletedTime { get; set; }
public Guid? DeleteUserId { get; set; }
}
public class TrialEmailBlackUser:Entity
{
[JsonIgnore]
public TrialEmailNoticeConfig TrialEmailNoticeConfig { get; set; }
[JsonIgnore]
public User User { get; set; }
public Guid TrialEmailNoticeConfigId { get; set; }
public Guid UserId { get; set; }
}
}

View File

@ -9,15 +9,15 @@ namespace IRaCIS.Core.Domain.Models
{
[JsonIgnore]
public Hospital Hospital { get; set; }
public string SiteName { get; set; }
public string SiteName { get; set; } = string.Empty;
public string SiteNameCN{ get; set; } = string.Empty;
public string AliasName { get; set; } = string.Empty;
public string SiteCode { get; set; }
public int Code { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string City { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
public Guid? HospitalId { get; set; }
public int State { get; set; }

View File

@ -7,8 +7,8 @@ namespace IRaCIS.Core.Domain.Models
///<summary>
/// 一致性核查文件
///</summary>
[Table("ConsistencyCheckFile")]
public class ConsistencyCheckFile : Entity, IAuditAdd
[Table("UserUploadFile")]
public class UserUploadFile : Entity, IAuditAdd
{
/// <summary>
/// 文件名称
@ -42,14 +42,23 @@ namespace IRaCIS.Core.Domain.Models
/// </summary>
public Guid TrialId { get; set; }
[JsonIgnore]
/// <summary>
[JsonIgnore]
/// <summary>
/// 创建人
/// </summary>
[ForeignKey("CreateUserId")]
public User User { get; set; }
public UploadScenarios UploadScenarios { get;set; }
}
public enum UploadScenarios
{
Check=0,
Site=1,
}
}

View File

@ -7,6 +7,9 @@ using System;
using IRaCIS.Core.Domain.Share;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.Domain.Models
{
///<summary>
@ -95,6 +98,34 @@ namespace IRaCIS.Core.Domain.Models
/// </summary>
public string Unit { get; set; } = string.Empty;
/// <summary>
/// 关联ID
/// </summary>
public Guid? RelevanceId { get; set; }
/// <summary>
/// 关联Value
/// </summary>
public string RelevanceValue { get; set; } = string.Empty;
[NotMapped]
public List<string> RelevanceValueList
{
get
{
try
{
return this.RelevanceValue.Split(',').ToList();
}
catch (Exception)
{
return new List<string>();
}
}
}
}

View File

@ -7,6 +7,9 @@ using System;
using IRaCIS.Core.Domain.Share;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Collections.Generic;
using System.Linq;
namespace IRaCIS.Core.Domain.Models
{
///<summary>
@ -110,6 +113,34 @@ namespace IRaCIS.Core.Domain.Models
/// </summary>
public string Unit { get; set; } = string.Empty;
/// <summary>
/// 关联ID
/// </summary>
public Guid? RelevanceId { get; set; }
/// <summary>
/// 关联Value
/// </summary>
public string RelevanceValue { get; set; } = string.Empty;
[NotMapped]
public List<string> RelevanceValueList
{
get
{
try
{
return this.RelevanceValue.Split(',').ToList();
}
catch (Exception)
{
return new List<string>();
}
}
}
}

View File

@ -176,6 +176,8 @@ namespace IRaCIS.Core.Domain.Models
[ForeignKey("DependParentId")]
[JsonIgnore]
public ReadingTableQuestionSystem DependParentQuestion { get; set; }
}

View File

@ -1,2 +1,6 @@

update TrialSiteUserSurvey set TrialRoleCode= (select Code from Dictionary where Id=TrialSiteUserSurvey.TrialRoleNameId)
--
update TrialSiteUserSurvey set TrialRoleCode= (select Code from Dictionary where Id=TrialSiteUserSurvey.TrialRoleNameId)
--
update TrialEmailNoticeConfig set AttachCNPath=FilePath,AttachPath=FilePath,AttachNameCN=FileName,AttachName=FileName

View File

@ -382,7 +382,7 @@ namespace IRaCIS.Core.Domain.Models
/// <summary>
/// SMTP端口
/// </summary>
public int? EmailSMTPServerPort { get; set; }
public int EmailSMTPServerPort { get; set; }
/// <summary>
/// 是否配置过邮箱

View File

@ -0,0 +1,46 @@
//--------------------------------------------------------------------
// 此代码由T4模板自动生成 byzhouhang 20210918
// 生成时间 2023-08-22 16:56:15
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
using System;
using IRaCIS.Core.Domain.Share;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace IRaCIS.Core.Domain.Models
{
///<summary>
///SubjectVisitClinicalDialog
///</summary>
[Table("SubjectVisitClinicalDialog")]
public class SubjectVisitClinicalDialog : Entity, IAuditAdd
{
/// <summary>
/// SubjectVisitId
/// </summary>
[Required]
public Guid SubjectVisitId { get; set; }
/// <summary>
/// CreateUserId
/// </summary>
[Required]
public Guid CreateUserId { get; set; }
/// <summary>
/// CreateTime
/// </summary>
[Required]
public DateTime CreateTime { get; set; }
/// <summary>
/// Content
/// </summary>
[Required]
public string Content { get; set; }
}
}

View File

@ -35,6 +35,8 @@ namespace IRaCIS.Core.Domain.Share
public string FromName { get; set; }
public string AuthorizationCode { get; set; }
public string SiteUrl { get; set; }
}

View File

@ -83,12 +83,22 @@ public static class StaticData
public static readonly string SystemDataFolder = "SystemData";
public static readonly string OtherDataFolder = "OtherData";
public static readonly string SignDocumentFolder = "SignDocument";
public static readonly string DataTemplate = "DataTemplate";
public static readonly string EmailHtmlTemplate = "EmailHtml";
public static readonly string EmailTemplate = "EmailTemplate";
public static readonly string CommonFile = "CommonFile";
public static readonly string TempFile = "TempFile";
public static readonly string CheckFile = "CheckFile";
public static readonly string SiteUserSurveryFile = "SiteUserSurveryFile";
public static readonly string NoticeAttachment = "NoticeAttachment";

View File

@ -14,6 +14,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace IRaCIS.Core.Infra.EFCore.Common
@ -794,7 +795,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
CreateUserName = _userInfo.UserName,
UserType = _userInfo.UserTypeShortName,
IsSigned = entity.ConfirmTime!=null, // 是否签署 添加了就是签署了
IsSigned = entity.ConfirmTime != null, // 是否签署 添加了就是签署了
});
}
@ -919,10 +920,10 @@ namespace IRaCIS.Core.Infra.EFCore.Common
.Where(t => t.TrialEmailNoticeConfigId == entity.Id).Select(t =>
new { t.TrialEmailNoticeConfigId, t.EmailUserType, t.UserType }).ToList();
if (_userInfo.RequestUrl == "TrialEmailNoticeConfig/getTrialEmailNoticeConfigList")
{
extraIdentification = "/Auto";
}
//找到黑名单
var blackUserIdList = entitys.Where(x => x.Entity.GetType() == typeof(TrialEmailBlackUser)).Select(t => t.Entity as TrialEmailBlackUser)
.Where(t => t.TrialEmailNoticeConfigId == entity.Id).Select(t =>
new { t.UserId }).ToList();
await InsertInspection<TrialEmailNoticeConfig>(entity, type, x => new InspectionConvertDTO()
{
@ -934,6 +935,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
{
ToUserTypes = configUserTypeList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList(),
CopyUserTypes = configUserTypeList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList(),
BlackUserIds = blackUserIdList
});
@ -993,7 +995,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
#region 附加评估
#endregion
#region 医学审核
@ -1010,7 +1012,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
var questionIdList = list.Select(t => t.ReadingMedicineQuestionId).ToList();
var questionNameList = await _dbContext.ReadingMedicineTrialQuestion.Where(x => questionIdList.Contains(x.Id)).Select(t => new { t.QuestionName, ReadingMedicineQuestionId = t.Id, t.ShowOrder }).ToListAsync();
var questionNameList = await _dbContext.ReadingMedicineTrialQuestion.Where(x => questionIdList.Contains(x.Id)).Select(t => new { t.QuestionName, ReadingMedicineQuestionId = t.Id, t.ShowOrder }).ToListAsync();
var firstEntity = list.FirstOrDefault();
@ -1159,7 +1161,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
var trialQuestionIdList = list.Select(t => t.TrialQCQuestionConfigureId);
var trialQuestionNameList = await _dbContext.TrialQCQuestionConfigure.Where(x => x.TrialId == firstEntity.TrialId).Select(t => new { t.QuestionName, TrialQCQuestionConfigureId = t.Id, t.ShowOrder }).ToListAsync();
var trialQuestionNameList = await _dbContext.TrialQCQuestionConfigure.Where(x => x.TrialId == firstEntity.TrialId).Select(t => new { t.QuestionName, TrialQCQuestionConfigureId = t.Id, t.ShowOrder }).ToListAsync();
var beforeAnswerList = await _dbContext.TrialQCQuestionAnswer.Where(x => x.SubjectVisitId == firstEntity.SubjectVisitId && x.CurrentQCEnum == firstEntity.CurrentQCEnum && x.QCProcessEnum == firstEntity.QCProcessEnum)
.Select(u => new { u.TrialQCQuestionConfigureId, u.Answer }).ToListAsync();
@ -1355,11 +1357,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(UserUploadFile)))
{
var type = GetEntityAuditOpt(item);
await InsertInspection<ConsistencyCheckFile>(item.Entity as ConsistencyCheckFile, type, x => new InspectionConvertDTO()
await InsertInspection<UserUploadFile>(item.Entity as UserUploadFile, type, x => new InspectionConvertDTO()
{
ObjectRelationParentId = x.TrialId
@ -1367,6 +1369,9 @@ namespace IRaCIS.Core.Infra.EFCore.Common
}
#endregion
#region 中心调研
// 中心调研表
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(TrialSiteSurvey)))
{
@ -1408,78 +1413,10 @@ namespace IRaCIS.Core.Infra.EFCore.Common
});
}
#endregion
// 既往手术史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousSurgery)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousSurgery;
await InsertInspection<PreviousSurgery>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
}, new
{
Type = ClinicalFileType.PreviousSurgery
});
}
// 既往放疗史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousHistory)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousHistory;
await InsertInspection<PreviousHistory>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
ObjectRelationParentId = x.SubjectVisitId,
}, new
{
Type = ClinicalFileType.PreviousHistory
});
}
// 其他治疗史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousOther)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousOther;
await InsertInspection<PreviousOther>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
ObjectRelationParentId = x.SubjectVisitId,
}, new
{
Type = ClinicalFileType.PreviousOther
});
}
//系统 Qc 问题
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(QCQuestion)))
@ -1567,6 +1504,9 @@ namespace IRaCIS.Core.Infra.EFCore.Common
}
#region 项目参与人员 项目site
// 项目中心 Site未稽查
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(TrialSite)))
@ -1636,6 +1576,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
});
}
#endregion
// 受试者
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(Subject)))
@ -1778,6 +1719,8 @@ namespace IRaCIS.Core.Infra.EFCore.Common
);
}
#region Dicom 非Dicom 既往手术史..临床数据
// Dicom
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(DicomStudy)))
{
@ -1828,6 +1771,78 @@ namespace IRaCIS.Core.Infra.EFCore.Common
});
}
// 既往手术史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousSurgery)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousSurgery;
await InsertInspection<PreviousSurgery>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
}, new
{
Type = ClinicalFileType.PreviousSurgery
});
}
// 既往放疗史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousHistory)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousHistory;
await InsertInspection<PreviousHistory>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
ObjectRelationParentId = x.SubjectVisitId,
}, new
{
Type = ClinicalFileType.PreviousHistory
});
}
// 其他治疗史
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PreviousOther)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PreviousOther;
await InsertInspection<PreviousOther>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
SubjectVisitId = x.SubjectVisitId,
ObjectRelationParentId2 = x.ClinicalDataTrialSetId,
ObjectRelationParentId = x.SubjectVisitId,
}, new
{
Type = ClinicalFileType.PreviousOther
});
}
#endregion
#region 阅片人入组
@ -1839,6 +1854,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
//系统临床数据配置
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(ClinicalDataSystemSet)))
@ -1867,6 +1883,33 @@ namespace IRaCIS.Core.Infra.EFCore.Common
{
extraIdentification = "/ConfirmSelect";
}
if (_userInfo.RequestUrl == "ClinicalDataSet/applyTrialClinical" )
{
extraIdentification = "/SaveTemplate";
var list = await _dbContext.TrialClinicalQuestion.Where(x => x.TrialClinicalId == entity.Id)
.Select(t => new
{
t.QuestionEnName,
t.QuestionName,
GroupNameCN = t.GroupQuestin.QuestionName,
GroupName = t.GroupQuestin.QuestionEnName,
t.ClinicalQuestionType,
t.ClinicalQuestionShowEnum,
t.TypeValue,
t.IsRequired
}).ToListAsync();
await InsertInspection<ClinicalDataTrialSet>(entity, type, x => new InspectionConvertDTO()
{
IsDistinctionInterface = false,
ExtraIndentification = extraIdentification
}, new { QuestionList = list });
continue;
}
//获取配置的标准名称
@ -2056,7 +2099,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
case "VisitTask/ConfirmReReading":
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager )
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager)
{
extraIdentification = "/" + 1;
}
@ -2095,7 +2138,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
//一致性分析规则
#endregion
@ -2512,6 +2555,37 @@ namespace IRaCIS.Core.Infra.EFCore.Common
#endregion
#region PI 审核
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(PIAudit)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as PIAudit;
await InsertInspection<PIAudit>(item.Entity as PIAudit, type, x => new InspectionConvertDTO()
{
ObjectRelationParentId = entity.VisitTaskId,
IsDistinctionInterface = true
});
}
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(SubjectVisitClinicalDialog)))
{
var type = GetEntityAuditOpt(item);
var entity = item.Entity as SubjectVisitClinicalDialog;
await InsertInspection<SubjectVisitClinicalDialog>(item.Entity as SubjectVisitClinicalDialog, type, x => new InspectionConvertDTO()
{
ObjectRelationParentId = entity.SubjectVisitId,
IsDistinctionInterface = false
});
}
#endregion
//任务
foreach (var item in entitys.Where(x => x.Entity.GetType() == typeof(VisitTask)))
{
@ -2557,7 +2631,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
//同意重阅
case "VisitTask/ConfirmReReading":
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager )
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager)
{
type = type + "/" + 1;
@ -2735,7 +2809,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
var generalId = (inspection.GeneralId != null && inspection.GeneralId != Guid.Empty) ? inspection.GeneralId : entityObj.Id;
inspection.GeneralId = generalId;
inspection.Identification = GetInspectionRecordIdentification(entityObj, type, inspection.IsDistinctionInterface, inspection.IsSelfDefine) + inspection.ExtraIndentification;
inspection.Identification = GetInspectionRecordIdentification(entityObj, type, inspection.IsDistinctionInterface, inspection.IsSelfDefine) + inspection.ExtraIndentification;
//将实体对象属性 映射到稽查实体
MapEntityPropertyToAuditEntity(entityObj, inspection);
@ -2944,7 +3018,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
/// 获取稽查记录的标识符 部分业务会进行特殊处理
/// </summary>
/// <returns></returns>
public string GetInspectionRecordIdentification<T>(T entityObj, string type, bool IsDistinctionInterface = true, bool isSelfDefine = false)
public string GetInspectionRecordIdentification<T>(T entityObj, string type, bool IsDistinctionInterface = true, bool isSelfDefine = false)
{
var entityTypeName = entityObj.GetType().Name;

View File

@ -467,7 +467,7 @@ namespace IRaCIS.Core.Infra.EFCore
public virtual DbSet<FrontAuditConfig> FrontAuditConfig { get; set; }
public virtual DbSet<ConsistencyCheckFile> ConsistencyCheckFile { get; set; }
public virtual DbSet<UserUploadFile> UserUploadFile { get; set; }
public virtual DbSet<CommonDocument> CommonDocument { get; set; }
@ -482,6 +482,7 @@ namespace IRaCIS.Core.Infra.EFCore
public virtual DbSet<PublishLog> PublishLog { get; set; }
public virtual DbSet<UserLog> UserLog { get; set; }
public virtual DbSet<SubjectVisitClinicalDialog> SubjectVisitClinicalDialog { get; set; }
@ -754,6 +755,9 @@ namespace IRaCIS.Core.Infra.EFCore
public virtual DbSet<PIAudit> PIAudit { get; set; }
public virtual DbSet<EmailNoticeUserType> EmailNoticeUserType { get; set; }
public virtual DbSet<TrialEmailBlackUser> TrialEmailBlackUser { get; set; }
}

View File

@ -1,5 +1,6 @@
using IRaCIS.Core.Domain.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -25,5 +26,19 @@ namespace IRaCIS.Core.Infra.EFCore.EntityConfigration
.HasPrincipalKey(c => new { c.TrialId, c.SiteId });
}
}
public class DictionaryConfigration : IEntityTypeConfiguration<Dictionary>
{
public void Configure(EntityTypeBuilder<Dictionary> builder)
{
builder.Property(e => e.MappedValue).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore);
builder.Property(e => e.MappedValue).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
}
}
}

View File

@ -1,10 +1,10 @@
<#+
public class config
{
public static readonly string ConnectionString = "Server=123.56.94.154,1433\\MSSQLSERVER;Database=IRaCIS_New_Tet;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true";
public static readonly string DbDatabase = "CenterImage_Test";
public static readonly string ConnectionString = "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Test.Study;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true";
public static readonly string DbDatabase = "Test.Study";
//表名称用字符串,拼接
public static readonly string TableName = "PIAudit";
public static readonly string TableName = "SubjectVisitClinicalDialog";
//具体文件里面 例如service 可以配置是否分页
}
#>
@ -21,10 +21,10 @@
}
string sql = string.Format(@"SELECT
obj.name tablename
from {0}.sys.objects obj
inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
left join {0}.sys.extended_properties g ON (obj.object_id = g.major_id AND g.minor_id = 0 AND g.name= 'MS_Description')
from sys.objects obj
inner join dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
INNER JOIN sys.schemas schem ON obj.schema_id=schem.schema_id
left join sys.extended_properties g ON (obj.object_id = g.major_id AND g.minor_id = 0 AND g.name= 'MS_Description')
where type='U' {1}
order by obj.name", database,tables);
DataTable dt = GetDataTable(connectionString, sql);
@ -50,9 +50,9 @@
ELSE 0
END
AS BIT) HasPrimaryKey
from {0}.sys.objects obj
inner join {0}.dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
INNER JOIN {0}.sys.schemas schem ON obj.schema_id=schem.schema_id
from sys.objects obj
inner join dbo.sysindexes idx on obj.object_id=idx.id and idx.indid<=1
INNER JOIN sys.schemas schem ON obj.schema_id=schem.schema_id
where type='U' {1}
order by obj.name", database, tables);
#endregion
@ -79,8 +79,8 @@
ic.column_id,
ic.index_column_id,
ic.object_id
FROM {0}.sys.indexes idx
INNER JOIN {0}.sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id
FROM sys.indexes idx
INNER JOIN sys.index_columns ic ON idx.index_id = ic.index_id AND idx.object_id = ic.object_id
WHERE idx.object_id =OBJECT_ID(@tableName) AND idx.is_primary_key=1
)
select
@ -102,14 +102,14 @@
cast(colm.precision as int) Precision,
cast(colm.scale as int) Scale,
prop.value Remark
from {0}.sys.columns colm
inner join {0}.sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id
left join {0}.sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id
from sys.columns colm
inner join sys.types systype on colm.system_type_id=systype.system_type_id and colm.user_type_id=systype.user_type_id
left join sys.extended_properties prop on colm.object_id=prop.major_id and colm.column_id=prop.minor_id
LEFT JOIN indexCTE ON colm.column_id=indexCTE.column_id AND colm.object_id=indexCTE.object_id
where colm.object_id=OBJECT_ID(@tableName)
order by colm.column_id", database);
#endregion
SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, 100) { Value = string.Format("{0}.{1}.{2}", database, schema, tableName) };
SqlParameter param = new SqlParameter("@tableName", SqlDbType.NVarChar, 100) { Value = string.Format("{1}.{2}", database, schema, tableName) };
DataTable dt = GetDataTable(connectionString, sql, param);
return dt.Rows.Cast<DataRow>().Select(row => new DbColumn()
{

View File

@ -14,7 +14,7 @@ steps:
commands:
- date +%H:%M:%S
- pwd
- docker build -t Test.Study .
- docker build -t Test_Study .
- date +%H:%M:%S
- name: docker-deploy
@ -28,13 +28,13 @@ steps:
commands:
- date +%H:%M:%S
- docker rm -f test-study-container
- docker run -itd -e TZ=Asia/Shanghai -e ASPNETCORE_ENVIRONMENT=Test_Study --restart=always --name test-study-container -p 8030:80 Test.Study
- docker run -itd -e TZ=Asia/Shanghai -e ASPNETCORE_ENVIRONMENT=Test_Study --restart=always --name test-study-container -p 8030:80 Test_Study
- date +%H:%M:%S
volumes:
- name: cached_nuget_packages
host:
path: /mnt/f/docker_publish/nuget_packages
path: /mnt/d/docker_publish/nuget_packages
- name: dockersock
host:
path: /var/run/docker.sock