Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is running Details

Uat_IRC_Net8
he 2026-05-25 16:38:42 +08:00
commit 63e9428d6d
38 changed files with 67997 additions and 205 deletions

View File

@ -8,6 +8,7 @@ using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention; using IRaCIS.Core.Infrastructure.Extention;
using IRaCIS.Core.SCP.Service; using IRaCIS.Core.SCP.Service;
using MassTransit;
using Medallion.Threading; using Medallion.Threading;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -95,7 +96,7 @@ namespace IRaCIS.Core.SCP.Service
public Task OnReceiveAssociationRequestAsync(DicomAssociation association) public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
{ {
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost }; _upload = new SCPImageUpload() { Id = NewId.NextSequentialGuid(), StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接"); Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
@ -644,7 +645,7 @@ namespace IRaCIS.Core.SCP.Service
ms.Position = 0; ms.Position = 0;
//irc 从路径最后一截取Guid //irc 从路径最后一截取Guid
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = _trialId, BatchDataType = BatchDataType.PACSReceive }); storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = _trialId, BatchDataType = BatchDataType.PACSReceive, UploadBatchId = _upload.Id.ToString() });
fileSize = ms.Length; fileSize = ms.Length;

View File

@ -63,6 +63,8 @@ public class FileUploadRecordAddOrEdit
public bool? IsNeedSync { get; set; } public bool? IsNeedSync { get; set; }
public string UploadRegion { get; set; } public string UploadRegion { get; set; }
public string TargetRegion { get; set; } public string TargetRegion { get; set; }
public bool? IsSync { get; set; }
} }
public interface IFileUploadRecordService public interface IFileUploadRecordService
{ {
@ -113,6 +115,19 @@ public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRe
} }
} }
//SCP推送过来IP为空后端归档的设置区域
if (_userInfo.IP.IsNullOrEmpty() && _userInfo.Domain.IsNullOrEmpty())
{
var apiDefalut = ObjectStoreServiceConfig.SyncConfigList.FirstOrDefault(t => t.UploadRegion == ObjectStoreServiceConfig.ApiDeployRegion);
if (apiDefalut != null)
{
addOrEditFileUploadRecord.UploadRegion = apiDefalut.UploadRegion;
addOrEditFileUploadRecord.TargetRegion = apiDefalut.TargetRegion;
}
}
if (addOrEditFileUploadRecord.TrialId != null) if (addOrEditFileUploadRecord.TrialId != null)
{ {
@ -129,9 +144,9 @@ public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRe
{ {
addOrEditFileUploadRecord.IsNeedSync = true; addOrEditFileUploadRecord.IsNeedSync = true;
addOrEditFileUploadRecord.Priority = 0; addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority ?? 0;
addOrEditFileUploadRecord.IsSync = false;
} }
else else
{ {
@ -147,7 +162,9 @@ public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRe
//系统文件,默认同步 //系统文件,默认同步
addOrEditFileUploadRecord.IsNeedSync = true; addOrEditFileUploadRecord.IsNeedSync = true;
addOrEditFileUploadRecord.Priority = 0; addOrEditFileUploadRecord.IsSync = false;
addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority ?? 0;
} }
var entity = await _fileUploadRecordRepository.InsertOrUpdateAsync(addOrEditFileUploadRecord, true); var entity = await _fileUploadRecordRepository.InsertOrUpdateAsync(addOrEditFileUploadRecord, true);

View File

@ -194,7 +194,7 @@ public interface IOSSService
List<string> GetRootFolderNames(); List<string> GetRootFolderNames();
public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null); public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null, string? objectUse = null);
public Task MoveObject(string sourcePath, string destPath, bool overwrite = true); public Task MoveObject(string sourcePath, string destPath, bool overwrite = true);
@ -825,10 +825,12 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null) if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null)
{ {
var fileType = Path.GetExtension(returnPath).TrimStart('.');
uploadInfo.FileSize = fileStream.CanSeek ? fileStream.Length : 0; uploadInfo.FileSize = fileStream.CanSeek ? fileStream.Length : 0;
uploadInfo.Path = returnPath; uploadInfo.Path = returnPath;
uploadInfo.FileName = fileRealName; uploadInfo.FileName = fileRealName;
uploadInfo.FileType = Path.GetExtension(returnPath); uploadInfo.FileType = fileType.IsNullOrEmpty()?"dcm": fileType;
await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo); await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
@ -964,10 +966,14 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null) if (ObjectStoreServiceOptions.IsOpenStoreSync && uploadInfo != null)
{ {
var fileType = Path.GetExtension(returnPath).TrimStart('.');
uploadInfo.FileSize = fileSize; uploadInfo.FileSize = fileSize;
uploadInfo.Path = returnPath; uploadInfo.Path = returnPath;
uploadInfo.FileName = Path.GetFileName(localFilePath); uploadInfo.FileName = Path.GetFileName(localFilePath);
uploadInfo.FileType = Path.GetExtension(returnPath); uploadInfo.FileType = fileType.IsNullOrEmpty() ? "dcm" : fileType;
await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo); await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
@ -1856,23 +1862,39 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null) public ObjectStoreDTO GetObjectStoreTempToken(string? domain = null, bool? isGetAllTempToken = null, string? objectUse = null)
{
string objectStoreUse = string.Empty;
//使用指定配置
if (objectUse != null)
{
objectStoreUse = objectUse?.Trim() ?? string.Empty;
}
//根据域名动态判断
else
{ {
//如果传递了域名,并且打开了存储同步,根据域名使用的具体存储覆盖之前的配置,否则就用固定的配置 //如果传递了域名,并且打开了存储同步,根据域名使用的具体存储覆盖之前的配置,否则就用固定的配置
if (ObjectStoreServiceOptions.IsOpenStoreSync && domain.IsNotNullOrEmpty()) if (ObjectStoreServiceOptions.IsOpenStoreSync && domain.IsNotNullOrEmpty() && ObjectStoreServiceOptions.SyncConfigList.Any(t => t.Domain == domain))
{ {
var userDomain = domain?.Trim();
var find = ObjectStoreServiceOptions.SyncConfigList.FirstOrDefault(t => t.Domain == userDomain); var find = ObjectStoreServiceOptions.SyncConfigList.FirstOrDefault(t => t.Domain == domain);
if (find != null) if (find != null)
{ {
ObjectStoreServiceOptions.ObjectStoreUse = find.Primary; objectStoreUse = find.Primary;
}
}
else
{
//兜底,如果是本地测试环境,那就使用部署默认配置
objectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse;
} }
} }
var objectStoreDTO = new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, IsOpenStoreSync = ObjectStoreServiceOptions.IsOpenStoreSync, SyncConfigList = ObjectStoreServiceOptions.SyncConfigList };
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS" || isGetAllTempToken == true) var objectStoreDTO = new ObjectStoreDTO() { ObjectStoreUse = objectStoreUse, IsOpenStoreSync = ObjectStoreServiceOptions.IsOpenStoreSync, SyncConfigList = ObjectStoreServiceOptions.SyncConfigList };
if (objectStoreUse == "AliyunOSS" || isGetAllTempToken == true)
{ {
var ossOptions = ObjectStoreServiceOptions.AliyunOSS; var ossOptions = ObjectStoreServiceOptions.AliyunOSS;
@ -1920,11 +1942,11 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
objectStoreDTO.AliyunOSS = tempToken; objectStoreDTO.AliyunOSS = tempToken;
} }
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO") if (objectStoreUse == "MinIO")
{ {
objectStoreDTO.MinIO = ObjectStoreServiceOptions.MinIO; objectStoreDTO.MinIO = ObjectStoreServiceOptions.MinIO;
} }
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS" || isGetAllTempToken == true) if (objectStoreUse == "AWS" || isGetAllTempToken == true)
{ {
var awsOptions = ObjectStoreServiceOptions.AWS; var awsOptions = ObjectStoreServiceOptions.AWS;
@ -1969,7 +1991,8 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
objectStoreDTO.AWS = tempToken; objectStoreDTO.AWS = tempToken;
} }
else
if (objectStoreUse.IsNullOrEmpty())
{ {
throw new BusinessValidationFailedException("未定义的存储介质类型"); throw new BusinessValidationFailedException("未定义的存储介质类型");
} }
@ -1980,7 +2003,7 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
public async Task SyncFileAsync(string objectKey, ObjectStoreUse source, ObjectStoreUse destination, CancellationToken ct = default) public async Task SyncFileAsync(string objectKey, ObjectStoreUse source, ObjectStoreUse destination, CancellationToken ct = default)
{ {
GetObjectStoreTempToken(isGetAllTempToken: true); var tempConfig = GetObjectStoreTempToken(isGetAllTempToken: true);
var aliConfig = ObjectStoreServiceOptions.AliyunOSS; var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
@ -1999,36 +2022,76 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
var amazonS3Client = new AmazonS3Client(credentials, clientConfig); var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
// ⭐ 关键变量
IDisposable? owner = null;
Stream sourceStream;
long contentLength;
// 根据源选择流式下载 // ========= 获取流 + 长度 =========
Stream sourceStream = source switch switch (source)
{
case ObjectStoreUse.AliyunOSS:
{ {
ObjectStoreUse.AliyunOSS => _ossClient.GetObject(aliConfig.BucketName, objectKey).Content,
ObjectStoreUse.AWS => (await amazonS3Client.GetObjectAsync(awsConfig.BucketName, objectKey, ct)).ResponseStream,
_ => throw new BusinessValidationFailedException("未定义的同步类型")
};
if (source == ObjectStoreUse.AliyunOSS) var obj = _ossClient.GetObject(
aliConfig.BucketName,
objectKey);
owner = obj;
sourceStream = obj.Content;
contentLength = obj.ContentLength;
break;
}
case ObjectStoreUse.AWS:
{
var response = await amazonS3Client.GetObjectAsync(
awsConfig.BucketName,
objectKey,
ct);
owner = response;
sourceStream = response.ResponseStream;
contentLength = response.Headers.ContentLength;
break;
}
default:
throw new BusinessValidationFailedException("未定义的同步类型");
}
try
{
// ========= 上传 =========
if (destination == ObjectStoreUse.AWS)
{ {
var putRequest = new Amazon.S3.Model.PutObjectRequest var putRequest = new Amazon.S3.Model.PutObjectRequest
{ {
BucketName = awsConfig.BucketName, BucketName = awsConfig.BucketName,
Key = objectKey, Key = objectKey,
InputStream = sourceStream InputStream = sourceStream,
Headers = { ContentLength = contentLength }
}; };
await amazonS3Client.PutObjectAsync(putRequest, ct); await amazonS3Client.PutObjectAsync(putRequest, ct);
} }
else if (source == ObjectStoreUse.AWS) else if (destination == ObjectStoreUse.AliyunOSS)
{ {
_ossClient.PutObject(aliConfig.BucketName, objectKey, sourceStream); _ossClient.PutObject(
aliConfig.BucketName,
objectKey,
sourceStream);
} }
else else
{ {
throw new BusinessValidationFailedException("未定义的同步类型"); throw new BusinessValidationFailedException("未定义的同步类型");
} }
}
await sourceStream.DisposeAsync(); // 释放流 finally
{
// ⭐⭐⭐ 真正释放 HTTP 连接
owner?.Dispose();
}
} }
} }

View File

@ -0,0 +1,16 @@
using AutoMapper;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.SCP.Service;
namespace IRaCIS.Core.Application.Service
{
public class CommonConfig : Profile
{
public CommonConfig()
{
CreateMap<FileUploadRecordAddOrEdit, FileUploadRecord>().ReverseMap();
}
}
}

View File

@ -7,7 +7,28 @@
} }
}, },
"ObjectStoreService": { "ObjectStoreService": {
// 使
"ObjectStoreUse": "AliyunOSS", "ObjectStoreUse": "AliyunOSS",
"IsOpenStoreSync": true,
"ApiDeployRegion": "CN",
"SyncConfigList": [
{
"Domain": "irc.test.extimaging.com",
"Primary": "AliyunOSS",
"Target": "AWS",
"UploadRegion": "CN",
"TargetRegion": "US",
"IsOpenSync": true
},
{
"Domain": "lili.test.extimaging.com",
"Primary": "AWS",
"Target": "AliyunOSS",
"UploadRegion": "US",
"TargetRegion": "CN",
"IsOpenSync": true
}
],
"AliyunOSS": { "AliyunOSS": {
"RegionId": "cn-shanghai", "RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com", "InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
@ -29,6 +50,27 @@
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy", "secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
"bucketName": "hir-test", "bucketName": "hir-test",
"viewEndpoint": "http://106.14.89.110:9001/hir-test/" "viewEndpoint": "http://106.14.89.110:9001/hir-test/"
},
// AWS S3
"AWS": {
// AWS S3 Region
"Region": "us-east-1",
// AWS S3 访
"EndPoint": "s3.us-east-1.amazonaws.com",
// 使 SSL
"UseSSL": true,
// AWS S3 ARN
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
// AWS S3 访 ID
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
// AWS S3 访 Secret
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
// AWS S3 Bucket
"BucketName": "ei-med-s3-lili-uat-store",
// AWS S3 访
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
// AWS S3
"DurationSeconds": 7200
} }
}, },

View File

@ -46,19 +46,19 @@ namespace IRaCIS.Core.API
var emailConfig = new SystemEmailSendConfig(); var emailConfig = new SystemEmailSendConfig();
configuration.GetSection("SystemEmailSendConfig").Bind(emailConfig); configuration.GetSection("SystemEmailSendConfig").Bind(emailConfig);
if (emailConfig.IsOpenErrorNoticeEmail) //if (emailConfig.IsOpenErrorNoticeEmail)
{ //{
config.WriteTo.Email(options: new Serilog.Sinks.Email.EmailSinkOptions() // config.WriteTo.Email(options: new Serilog.Sinks.Email.EmailSinkOptions()
{ // {
From = emailConfig.FromEmail, // From = emailConfig.FromEmail,
To = emailConfig.ErrorNoticeEmailList, // To = emailConfig.ErrorNoticeEmailList,
Host = emailConfig.Host, // Host = emailConfig.Host,
Port = emailConfig.Port, // Port = emailConfig.Port,
Subject = new MessageTemplateTextFormatter("Log Alert - 系统发生了异常,请核查"), // Subject = new MessageTemplateTextFormatter("Log Alert - 系统发生了异常,请核查"),
Credentials = new NetworkCredential(emailConfig.FromEmail, emailConfig.AuthorizationCode) // Credentials = new NetworkCredential(emailConfig.FromEmail, emailConfig.AuthorizationCode)
}, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error); // }, restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error);
} //}
#endregion #endregion
Log.Logger = config.CreateLogger(); Log.Logger = config.CreateLogger();

View File

@ -85,10 +85,8 @@
"CompanyShortName": "Extensive Imaging", "CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
"IsEnv_US": false, "IsEnv_US": false,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN", "CronEmailDefaultCulture": "zh-CN"
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {
"Port": "11113", "Port": "11113",

View File

@ -149,14 +149,15 @@
}, },
// //
"SystemEmailSendConfig": { "SystemEmailSendConfig": {
// SMTP
"Port": 465,
// SMTP // SMTP
"Host": "smtp.qiye.aliyun.com", "Host": "smtp.qiye.aliyun.com",
// SMTP
"Port": 465,
"Imap": "imap.qiye.aliyun.com", "Imap": "imap.qiye.aliyun.com",
"ImapPort": 993, "ImapPort": 993,
// //
"FromEmail": "test@extimaging.com", "FromEmail": "test@extimaging.com",
// //
@ -166,14 +167,16 @@
// 访 // 访
"SiteUrl": "http://irc.test.extimaging.com/login", "SiteUrl": "http://irc.test.extimaging.com/login",
"PlatformName": "EICS",
"PlatformNameCN": "展影云平台", // - 使
// 使
"SystemShortName": "IRC", "SystemShortName": "IRC",
// // -
"OrganizationName": "ExtImaging", "OrganizationName": "ExtImaging",
// //
"OrganizationNameCN": "ExtImaging", "OrganizationNameCN": "ExtImaging",
"PlatformName": "EICS",
"PlatformNameCN": "展影云平台",
// //
"CompanyName": "Extensive Imaging", "CompanyName": "Extensive Imaging",
// //
@ -182,15 +185,14 @@
"CompanyShortName": "Extensive Imaging", "CompanyShortName": "Extensive Imaging",
// //
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
//
// 便lili irc
"IsEnv_US": false, "IsEnv_US": false,
//
"IsOpenErrorNoticeEmail": false,
// //
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN",
// //
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "CronEmailDefaultCulture": "zh-CN"
}, },
// PACS // PACS
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -90,10 +90,8 @@
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.elevateimaging.ai/login", "SiteUrl": "https://lili.elevateimaging.ai/login",
"IsEnv_US": true, "IsEnv_US": true,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "en-US", "CronEmailDefaultCulture": "en-US"
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -93,9 +93,7 @@
"CompanyShortName": "Elevate Imaging", "CompanyShortName": "Elevate Imaging",
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.test.elevateimaging.ai/login", "SiteUrl": "https://lili.test.elevateimaging.ai/login",
"IsEnv_US": true, "IsEnv_US": true
"IsOpenErrorNoticeEmail": false,
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -97,10 +97,8 @@
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
"SiteUrl": "https://lili.uat.elevateimaging.ai/login", "SiteUrl": "https://lili.uat.elevateimaging.ai/login",
"IsEnv_US": true, "IsEnv_US": true,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "en-US", "CronEmailDefaultCulture": "en-US"
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -19,6 +19,26 @@
"ObjectStoreService": { "ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS", "ObjectStoreUse": "AliyunOSS",
"IsOpenStoreSync": true,
"ApiDeployRegion": "CN",
"SyncConfigList": [
{
"Domain": "irc.uat.extimaging.com",
"Primary": "AliyunOSS",
"Target": "AWS",
"UploadRegion": "CN",
"TargetRegion": "US",
"IsOpenSync": true
},
{
"Domain": "lili.uat.extimaging.com",
"Primary": "AWS",
"Target": "AliyunOSS",
"UploadRegion": "US",
"TargetRegion": "CN",
"IsOpenSync": true
}
],
"AliyunOSS": { "AliyunOSS": {
"RegionId": "cn-shanghai", "RegionId": "cn-shanghai",
@ -104,10 +124,8 @@
"CompanyShortName": "Extensive Imaging", "CompanyShortName": "Extensive Imaging",
"CompanyShortNameCN": "展影医疗", "CompanyShortNameCN": "展影医疗",
"IsEnv_US": false, "IsEnv_US": false,
"IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN", "CronEmailDefaultCulture": "zh-CN"
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -79,11 +79,12 @@ public class SystemEmailSendConfig
public bool IsEnv_US { get; set; } public bool IsEnv_US { get; set; }
public bool IsOpenErrorNoticeEmail { get; set; }
public string EmailRegexStr { get; set; } public string EmailRegexStr { get; set; }
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>(); //public bool IsOpenErrorNoticeEmail { get; set; }
//public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
} }
public class SystemEmailSendConfigView public class SystemEmailSendConfigView

View File

@ -566,6 +566,27 @@
<param name="options"></param> <param name="options"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Core.Application.Service.Common.DeployConfigService.UpdateSystemBasicConfig(IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption)">
<summary>
更新系统基础配置
</summary>
<param name="basicSystemConfigOption"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.DeployConfigService.GetEmailConfigInfo(Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig})">
<summary>
获取系统邮件配置信息
</summary>
<param name="options"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.DeployConfigService.UpdateSystemEmailConfig(IRaCIS.Core.Domain.Share.SystemEmailSendConfig)">
<summary>
更新系统邮件配置
</summary>
<param name="emailConfig"></param>
<returns></returns>
</member>
<member name="P:IRaCIS.Core.Application.Service.Common.TU_TR_RSBaseModel.ResearchProgramNo"> <member name="P:IRaCIS.Core.Application.Service.Common.TU_TR_RSBaseModel.ResearchProgramNo">
<summary> <summary>
方案编号 STUDYID 方案编号 STUDYID
@ -15963,7 +15984,7 @@
<param name="inQuery"></param> <param name="inQuery"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Core.Application.Service.PatientService.SubmitVisitStudyBinding(IRaCIS.Application.Contracts.SubmitVisitStudyBindingCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance})"> <member name="M:IRaCIS.Core.Application.Service.PatientService.SubmitVisitStudyBinding(IRaCIS.Application.Contracts.SubmitVisitStudyBindingCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.FileUploadRecord})">
<summary> <summary>
提交 患者检查和访视的绑定 提交 患者检查和访视的绑定
</summary> </summary>
@ -16121,6 +16142,13 @@
<param name="outEnrollTime"></param> <param name="outEnrollTime"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Core.Application.Service.TestService.SiteSuveryEquipment">
<summary>
维护中心调研设备默认配置
</summary>
<param name="modelVerify"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.TestService.MaskImage"> <member name="M:IRaCIS.Core.Application.Service.TestService.MaskImage">
<summary> <summary>
遮挡影像 遮挡影像
@ -18905,6 +18933,11 @@
受试者ID 受试者ID
</summary> </summary>
</member> </member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.TrialVisitQADTO.IsSupportQCDownloadImage">
<summary>
QC质控下载
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.DTO.QAStudyInfoDTO.PatientSex"> <member name="P:IRaCIS.Core.Application.Contracts.DTO.QAStudyInfoDTO.PatientSex">
<summary> <summary>
性别 性别
@ -19365,6 +19398,16 @@
检查名称列表 检查名称列表
</summary> </summary>
</member> </member>
<member name="P:IRaCIS.Core.Application.Contracts.BasicTrialConfig.IsSupportQCDownloadImage">
<summary>
QC质控下载
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.BasicTrialConfig.IsOpenLostVistRead">
<summary>
打开失访可读
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Contracts.TrialProcessConfig.IsImageQualityControl"> <member name="P:IRaCIS.Core.Application.Contracts.TrialProcessConfig.IsImageQualityControl">
<summary> <summary>
影像质控风险控制 影像质控风险控制

View File

@ -1016,9 +1016,9 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
if (critrion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) if (critrion.IsReadingTaskViewInOrder == ReadingOrder.InOrder)
{ {
var extralObj = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.TrialExtraConfigJsonStr }).FirstOrDefault(); var extralObj = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.IsOpenLostVistRead }).FirstOrDefault();
var extralConfig = JsonConvert.DeserializeObject<TrialExtraConfig>(extralObj?.TrialExtraConfigJsonStr) ?? new TrialExtraConfig(); //var extralConfig = JsonConvert.DeserializeObject<TrialExtraConfig>(extralObj?.TrialExtraConfigJsonStr) ?? new TrialExtraConfig();
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect && x.Subject.IsSubjectQuit == false) var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect && x.Subject.IsSubjectQuit == false)
@ -1027,7 +1027,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
.WhereIf(critrion.IsAutoCreate == false, t => !t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(f => f.IsGeneratedTask == false && t.VisitTaskNum > f.SubjectVisit.VisitNum)) .WhereIf(critrion.IsAutoCreate == false, t => !t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(f => f.IsGeneratedTask == false && t.VisitTaskNum > f.SubjectVisit.VisitNum))
// 前序 不存在 未一致性核查未通过的 // 前序 不存在 未一致性核查未通过的
.Where(t => !t.Subject.SubjectVisitList.Where(t => extralConfig.IsOpenLostVistRead ? t.IsLostVisit == false : true).Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum >= sv.VisitNum)) .Where(t => !t.Subject.SubjectVisitList.Where(t => extralObj.IsOpenLostVistRead ? t.IsLostVisit == false : true).Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum >= sv.VisitNum))
//.WhereIf(critrion.IsAutoCreate == false, t => t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(t => t.IsGeneratedTask == false) ? //.WhereIf(critrion.IsAutoCreate == false, t => t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(t => t.IsGeneratedTask == false) ?
//t.VisitTaskNum <= t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsGeneratedTask == false).Min(t => t.SubjectVisit.VisitNum) : true) //t.VisitTaskNum <= t.Subject.SubjectCriteriaEvaluationVisitFilterList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsGeneratedTask == false).Min(t => t.SubjectVisit.VisitNum) : true)
//.Where(t => t.Subject.SubjectVisitList.Any(t => t.CheckState != CheckStateEnum.CVPassed) ? t.VisitTaskNum <= t.Subject.SubjectVisitList.Where(t => t.CheckState != CheckStateEnum.CVPassed).Min(t => t.VisitNum) : true) //.Where(t => t.Subject.SubjectVisitList.Any(t => t.CheckState != CheckStateEnum.CVPassed) ? t.VisitTaskNum <= t.Subject.SubjectVisitList.Where(t => t.CheckState != CheckStateEnum.CVPassed).Min(t => t.VisitNum) : true)
@ -1050,14 +1050,14 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
UnReadTaskCount = x.Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned).Count(), UnReadTaskCount = x.Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned).Count(),
//未读 里可读任务量 //未读 里可读任务量
UnReadCanReadTaskCount = x.Where(t => extralConfig.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false).Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned && (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true) UnReadCanReadTaskCount = x.Where(t => extralObj.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false).Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned && (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true)
//不能对包含聚合或子查询的表达式执行聚合函数 //不能对包含聚合或子查询的表达式执行聚合函数
//&& !x.Any(t => t.ReadingTaskState != ReadingTaskState.HaveSigned && t.IsNeedClinicalDataSign == true && t.IsClinicalDataSign == false && t.VisitTaskNum<y.VisitTaskNum ) //&& !x.Any(t => t.ReadingTaskState != ReadingTaskState.HaveSigned && t.IsNeedClinicalDataSign == true && t.IsClinicalDataSign == false && t.VisitTaskNum<y.VisitTaskNum )
).Count(), ).Count(),
UnReadCanReadTaskList = x.Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned) UnReadCanReadTaskList = x.Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned)
.Where(t => extralConfig.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false) .Where(t => extralObj.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false)
.Where(y => /*y.IsFrontTaskNeedSignButNotSign == false &&*/ (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true)) .Where(y => /*y.IsFrontTaskNeedSignButNotSign == false &&*/ (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true))
.OrderBy(x => x.VisitTaskNum) .OrderBy(x => x.VisitTaskNum)
.Select(u => new IRUnreadTaskView() .Select(u => new IRUnreadTaskView()

View File

@ -13,10 +13,11 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service.Common namespace IRaCIS.Core.Application.Service.Common;
[ApiExplorerSettings(GroupName = "Common")]
public class DeployConfigService(IMapper _mapper, IUserInfo _userInfo, IWebHostEnvironment _hostEnvironment, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService
{ {
public class DeployConfigService(IMapper _mapper, IUserInfo _userInfo, IWebHostEnvironment _hostEnvironment, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService
{
/// <summary> /// <summary>
/// 获取系统基础配置信息 /// 获取系统基础配置信息
@ -28,6 +29,11 @@ namespace IRaCIS.Core.Application.Service.Common
return options.CurrentValue; return options.CurrentValue;
} }
/// <summary>
/// 更新系统基础配置
/// </summary>
/// <param name="basicSystemConfigOption"></param>
/// <returns></returns>
[HttpPost] [HttpPost]
public async Task<IResponseOutput> UpdateSystemBasicConfig(ServiceVerifyConfigOption basicSystemConfigOption) public async Task<IResponseOutput> UpdateSystemBasicConfig(ServiceVerifyConfigOption basicSystemConfigOption)
{ {
@ -51,7 +57,7 @@ namespace IRaCIS.Core.Application.Service.Common
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ReadingRestTimeMin)] = basicSystemConfigOption.ReadingRestTimeMin; obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ReadingRestTimeMin)] = basicSystemConfigOption.ReadingRestTimeMin;
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.IsNeedChangePassWord)] = basicSystemConfigOption.IsNeedChangePassWord; obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.IsNeedChangePassWord)] = basicSystemConfigOption.IsNeedChangePassWord;
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ChangePassWordDays)] = basicSystemConfigOption.ChangePassWordDays; obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ChangePassWordDays)] = basicSystemConfigOption.ChangePassWordDays;
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.TemplateType)] = ((int)basicSystemConfigOption.TemplateType).ToString(); // 枚举需要转换为字符串 obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.TemplateType)] = ((int)basicSystemConfigOption.TemplateType); // 枚举需要转换为字符串
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ThirdPdfUrl)] = basicSystemConfigOption.ThirdPdfUrl; obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ThirdPdfUrl)] = basicSystemConfigOption.ThirdPdfUrl;
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.UserMFAVerifyMinutes)] = basicSystemConfigOption.UserMFAVerifyMinutes; obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.UserMFAVerifyMinutes)] = basicSystemConfigOption.UserMFAVerifyMinutes;
@ -64,13 +70,61 @@ namespace IRaCIS.Core.Application.Service.Common
return ResponseOutput.Ok(); return ResponseOutput.Ok();
} }
/// <summary>
/// 获取系统邮件配置信息
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public async Task<SystemEmailSendConfig> GetEmailConfigInfo([FromServices] IOptionsMonitor<SystemEmailSendConfig> options) public async Task<SystemEmailSendConfig> GetEmailConfigInfo([FromServices] IOptionsMonitor<SystemEmailSendConfig> options)
{ {
return options.CurrentValue; return options.CurrentValue;
} }
/// <summary>
/// 更新系统邮件配置
/// </summary>
/// <param name="emailConfig"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> UpdateSystemEmailConfig(SystemEmailSendConfig emailConfig)
{
var path = $"appsettings.{_hostEnvironment.EnvironmentName}.json";
string text = System.IO.File.ReadAllText(path);
// 修改
JObject obj = JObject.Parse(text);
// SystemEmailSendConfig 相关配置
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.Port)] = emailConfig.Port;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.Host)] = emailConfig.Host;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.Imap)] = emailConfig.Imap;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.ImapPort)] = emailConfig.ImapPort;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.FromEmail)] = emailConfig.FromEmail;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.FromName)] = emailConfig.FromName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.AuthorizationCode)] = emailConfig.AuthorizationCode;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.SiteUrl)] = emailConfig.SiteUrl;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.PlatformName)] = emailConfig.PlatformName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.PlatformNameCN)] = emailConfig.PlatformNameCN;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.SystemShortName)] = emailConfig.SystemShortName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.OrganizationName)] = emailConfig.OrganizationName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.OrganizationNameCN)] = emailConfig.OrganizationNameCN;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.CompanyName)] = emailConfig.CompanyName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.CompanyNameCN)] = emailConfig.CompanyNameCN;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.CompanyShortName)] = emailConfig.CompanyShortName;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.CompanyShortNameCN)] = emailConfig.CompanyShortNameCN;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.IsEnv_US)] = emailConfig.IsEnv_US;
obj["SystemEmailSendConfig"][nameof(SystemEmailSendConfig.EmailRegexStr)] = emailConfig.EmailRegexStr;
// 重新写入appsettings.json
string result = obj.ToString();
System.IO.File.WriteAllText(path, result);
return ResponseOutput.Ok();
} }
} }

View File

@ -138,7 +138,7 @@ namespace IRaCIS.Core.Application.Service
var isNeedSend = true; var isNeedSend = true;
//手动发送的时候,也有可能答案是是 此时是 这里不发送,发送已经生成的文件 //手动发送的时候,也有可能答案是是 此时是 这里不发送,发送已经生成的文件
if (answer == "是" && isHandSend == null) if ((answer == "是" || answer == "Yes") && isHandSend == null)
{ {
isNeedSend = true; isNeedSend = true;
@ -1183,7 +1183,7 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
/// <param name="userWorkLanguage"></param> /// <param name="userWorkLanguage"></param>
/// <returns></returns> /// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception> /// <exception cref="BusinessValidationFailedException"></exception>
private async Task<string> TranslatePdStateAsync(Guid visitTaskId, ReadingCategory readingCategory, CriterionType criterionType, UserWorkLanguage userWorkLanguage, bool? IsGlobalGenerate = null ) private async Task<string> TranslatePdStateAsync(Guid visitTaskId, ReadingCategory readingCategory, CriterionType criterionType, UserWorkLanguage userWorkLanguage, bool? IsGlobalGenerate = null)
{ {
var answer = string.Empty; var answer = string.Empty;

View File

@ -263,6 +263,12 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public class TrialVisitQADTO public class TrialVisitQADTO
{ {
/// <summary>
/// QC质控下载
/// </summary>
public bool IsSupportQCDownloadImage { get; set; } = false;
public bool ExistsManual { get; set; } public bool ExistsManual { get; set; }
public bool IsHaveStudyClinicalData { get; set; } public bool IsHaveStudyClinicalData { get; set; }
public bool QCRiskControl { get; set; } public bool QCRiskControl { get; set; }

View File

@ -421,6 +421,7 @@ namespace IRaCIS.Core.Application.Image.QA
List<SecondReviewDto> secondReviewList = new List<SecondReviewDto>(); List<SecondReviewDto> secondReviewList = new List<SecondReviewDto>();
var isSupportQCImageDownload = _trialRepository.Where(t => t.Id == sv.TrialId).Select(t => t.IsSupportQCDownloadImage).FirstOrDefault();
if (sv.SecondReviewState != SecondReviewState.None) if (sv.SecondReviewState != SecondReviewState.None)
{ {
@ -459,6 +460,7 @@ namespace IRaCIS.Core.Application.Image.QA
return new TrialVisitQADTO return new TrialVisitQADTO
{ {
IsSupportQCDownloadImage = isSupportQCImageDownload,
QCQuestionAnswerList = qacheckList, QCQuestionAnswerList = qacheckList,
QCRiskControl = _verifyConfig.CurrentValue.QCRiskControl, QCRiskControl = _verifyConfig.CurrentValue.QCRiskControl,
SecondReviewList = secondReviewList, SecondReviewList = secondReviewList,
@ -776,7 +778,7 @@ namespace IRaCIS.Core.Application.Image.QA
var query = _inspectionFileRepository.Where(t => t.TrialId == inQuery.TrialId && (t.CheckState == EDCCheckState.Success || t.CheckState == EDCCheckState.Failed)) var query = _inspectionFileRepository.Where(t => t.TrialId == inQuery.TrialId && (t.CheckState == EDCCheckState.Success || t.CheckState == EDCCheckState.Failed))
.ProjectTo<GetUserUploadFileDto>(_mapper.ConfigurationProvider); .ProjectTo<GetUserUploadFileDto>(_mapper.ConfigurationProvider);
return await query.ToPagedListAsync(inQuery,nameof(GetUserUploadFileDto.CreateTime)); return await query.ToPagedListAsync(inQuery, nameof(GetUserUploadFileDto.CreateTime));
} }

View File

@ -1111,12 +1111,12 @@ namespace IRaCIS.Core.Application.Image.QA
var visit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId); var visit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
var isExistStudyClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(t => t.TrialId == visit.TrialId && t.ClinicalDataLevel == ClinicalLevel.Study&&t.IsConfirm&&t.IsApply); var isExistStudyClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(t => t.TrialId == visit.TrialId && t.ClinicalDataLevel == ClinicalLevel.Study && t.IsConfirm && t.IsApply);
if(isExistStudyClinicalData) if (isExistStudyClinicalData)
{ {
List<string> modalitieTypes = new List<string>() { "PT、CT", "CT、PT", "PET-CT" }; List<string> modalitieTypes = new List<string>() { "PT、CT", "CT、PT", "PET-CT" };
var studyList=await _dicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId&& modalitieTypes.Contains(t.Modalities)).ProjectTo<QAStudyInfoDTO>(_mapper.ConfigurationProvider).ToListAsync(); var studyList = await _dicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId && modalitieTypes.Contains(t.Modalities)).ProjectTo<QAStudyInfoDTO>(_mapper.ConfigurationProvider).ToListAsync();
if (studyList.Any(x => x.IsHasEmptyPatientInfo)) if (studyList.Any(x => x.IsHasEmptyPatientInfo))
{ {
return ResponseOutput.NotOk(_localizer["QCOperation_IsHasEmptyPatientInfo"]); return ResponseOutput.NotOk(_localizer["QCOperation_IsHasEmptyPatientInfo"]);
@ -1189,7 +1189,7 @@ namespace IRaCIS.Core.Application.Image.QA
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == id, u => new SCPStudy() { SubjectVisitId = null }); await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == id, u => new SCPStudy() { SubjectVisitId = null });
if (fisrtPath.IsNotNullOrEmpty()) if (fisrtPath.IsNotNullOrEmpty() && study.IsFromPACS == false)
{ {
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1); var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);

View File

@ -6,17 +6,9 @@
namespace IRaCIS.Core.Application.Contracts namespace IRaCIS.Core.Application.Contracts
{ {
/// <summary> TrialSiteEquipmentSurveyView 列表视图模型 </summary> /// <summary> TrialSiteEquipmentSurveyView 列表视图模型 </summary>
public class TrialSiteEquipmentSurveyView public class TrialSiteEquipmentSurveyView: TrialSiteEquipmentSurveyAddOrEdit
{ {
public Guid Id { get; set; }
public Guid TrialSiteSurveyId { get; set; }
public string EquipmentType { get; set; } = string.Empty;
public Guid? EquipmentTypeId { get; set; }
public string Parameters { get; set; } = string.Empty;
public string ManufacturerName { get; set; } = string.Empty;
public string ScannerType { get; set; } = string.Empty;
public string Note { get; set; } = string.Empty;
public DateTime CreateTime { get; set; } public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; } public Guid CreateUserId { get; set; }
public DateTime UpdateTime { get; set; } public DateTime UpdateTime { get; set; }
@ -56,6 +48,36 @@ namespace IRaCIS.Core.Application.Contracts
public string ManufacturerName { get; set; } = string.Empty; public string ManufacturerName { get; set; } = string.Empty;
public string ScannerType { get; set; } = string.Empty; public string ScannerType { get; set; } = string.Empty;
public string Note { get; set; } = string.Empty; public string Note { get; set; } = string.Empty;
[Comment("扫描设备-New")]
public int? EquipmentTypeEnum { get; set; }
public string OtherEquipmentType { get; set; }
[Comment("扫描设备厂商")]
public int? ManufacturerType { get; set; }
[Comment("磁场强度 (1.5T / 3.0T)")]
public int? MagneticFieldStrengthType { get; set; }
[Comment("体部线圈通道数 (≥16 或 16)")]
public int? BodyCoilChannelCount { get; set; }
[Comment("是否具备专用的PDFF脂肪定量序列CSE-MRI序列")]
public bool? HasDedicatedPdfFatQuantificationSequence { get; set; }
[Comment("专用的PDFF脂肪定量序列类型 (当 HasDedicatedPdfFatQuantificationSequence = true 时有效)")]
public int? PdfFatQuantificationSequenceType { get; set; }
[Comment("其他序列详细说明 (当 PdfFatQuantificationSequenceType = Other 时建议填写)")]
public string OtherSequenceSpecification { get; set; }
[Comment("是否包含 T2/R2 校正(用于铁沉积校正)")]
public bool? HasT2R2Correction { get; set; }
[Comment("是否可完整导出 PDFF 参数图及全部原始 DICOM 数据")]
public bool? CanFullyExportPdfParameterMapsAndRawDicom { get; set; }
} }

View File

@ -678,7 +678,7 @@ namespace IRaCIS.Core.Application.Contracts
if (currentLatest.Email != userInfo.ReplaceUserEmailOrPhone) if (currentLatest.Email != userInfo.ReplaceUserEmailOrPhone)
{ {
//---该中心不存在该交接人的中心调研记录表,不允许选择更新。 //---该中心不存在该交接人的中心调研记录表,不允许选择更新。
return ResponseOutput.NotOk(_localizer["TrialSiteSurvey_NoRecordToUpdate"]); return ResponseOutput.NotOk(_localizer["TrialSiteSurvey_NoRecordToUpdate", currentLatest.Email]);
} }

View File

@ -39,8 +39,7 @@ namespace IRaCIS.Core.Application.AutoMapper
//列表 //列表
CreateMap<TrialSiteEquipmentSurvey, TrialSiteEquipmentSurveyView>() CreateMap<TrialSiteEquipmentSurvey, TrialSiteEquipmentSurveyView>();
.ForMember(t => t.EquipmentType, u => u.MapFrom(d => isEn_Us ? d.EquipmentType.Value : d.EquipmentType.ValueCN));

View File

@ -87,6 +87,17 @@ namespace IRaCIS.Core.Application.Contracts
public List<TrialObjectNameConfig> TrialObjectNameList { get; set; } public List<TrialObjectNameConfig> TrialObjectNameList { get; set; }
/// <summary>
/// QC质控下载
/// </summary>
public bool IsSupportQCDownloadImage { get; set; } = false;
/// <summary>
/// 打开失访可读
/// </summary>
public bool IsOpenLostVistRead { get; set; } = true;
} }
public class ConfigTrialProcessInfoVerificationInDto public class ConfigTrialProcessInfoVerificationInDto

View File

@ -243,11 +243,16 @@ namespace IRaCIS.Application.Contracts
} }
public class TrialExtraConfig public class TrialExtraConfig
{ {
#region QC 影像下载 #region QC 影像下载--下个版本删除
//QC质控 //QC质控下载
public bool IsSupportQCDownloadImage { get; set; } = false; public bool IsSupportQCDownloadImage { get; set; } = false;
/// <summary>
/// 打开失访可读
/// </summary>
public bool IsOpenLostVistRead { get; set; } = true;
#endregion #endregion
@ -260,20 +265,19 @@ namespace IRaCIS.Application.Contracts
public List<SiteSurveyModifyFiled> ModifyFiledList { get; set; } = new List<SiteSurveyModifyFiled>(); public List<SiteSurveyModifyFiled> ModifyFiledList { get; set; } = new List<SiteSurveyModifyFiled>();
public List<SiteSurveyEquipmentField> EquipmentControlFieldList { get; set; } = new List<SiteSurveyEquipmentField>();
#endregion #endregion
/// <summary>
/// 打开失访可读
/// </summary>
public bool IsOpenLostVistRead { get; set; } = true;
} }
public class TrialConfigInfo: TrialExtraConfig public class TrialConfigInfo : TrialExtraConfig
{ {
#region 视图模型返回 项目术语配置 ,实际数据库没有配置 #region 视图模型返回 项目术语配置 ,实际数据库没有配置
public List<TrialObjectNameConfig> TrialObjectNameList { get; set; } public List<TrialObjectNameConfig> TrialObjectNameList { get; set; }
@ -311,6 +315,14 @@ namespace IRaCIS.Application.Contracts
} }
public class SiteSurveyEquipmentField
{
public string FiledName { get; set; }
public int ShowOrder { get; set; }
public bool IsView { get; set; }
}
} }

View File

@ -255,6 +255,28 @@ namespace IRaCIS.Core.Application.Service
trial.IsConfigureEmail = true; trial.IsConfigureEmail = true;
#endregion #endregion
#region 中心调研默认值
var trialExtalConfig = new TrialExtraConfig()
{
EquipmentControlFieldList = new List<SiteSurveyEquipmentField> {
new SiteSurveyEquipmentField() { FiledName = "EquipmentTypeEnum", ShowOrder = 0, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "OtherEquipmentType", ShowOrder = 1, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "Parameters", ShowOrder = 2, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ManufacturerType", ShowOrder = 3, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ManufacturerName", ShowOrder = 4, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ScannerType", ShowOrder = 5, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "Note", ShowOrder = 6, IsView = true },
}
};
trial.TrialExtraConfigJsonStr = trialExtalConfig.ToJsonStr();
#endregion
//如果是PM 则需要将该人员添加到 运维人员表 //如果是PM 则需要将该人员添加到 运维人员表
//添加运维人员PM //添加运维人员PM
await _trialIdentityUserRepository.AddAsync(new TrialIdentityUser() await _trialIdentityUserRepository.AddAsync(new TrialIdentityUser()

View File

@ -5,6 +5,7 @@ using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure;
using MassTransit;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Pipelines.Sockets.Unofficial.Arenas; using Pipelines.Sockets.Unofficial.Arenas;
using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core;
@ -42,7 +43,7 @@ namespace IRaCIS.Core.Application.Service
var instanceList = await _instanceRepository.Where(s => s.StudyId == scpStudyId).OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber) var instanceList = await _instanceRepository.Where(s => s.StudyId == scpStudyId).OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime) .ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber,t.FileSize }).ToListAsync();//.GroupBy(u => u.SeriesId); .Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber, t.FileSize }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList) foreach (var series in seriesList)
{ {
@ -55,7 +56,7 @@ namespace IRaCIS.Core.Application.Service
//HtmlPath = string.Empty, //HtmlPath = string.Empty,
Path = k.Path, Path = k.Path,
InstanceNumber = k.InstanceNumber, InstanceNumber = k.InstanceNumber,
FileSize=k.FileSize, FileSize = k.FileSize,
}).ToList(); }).ToList();
} }
@ -378,11 +379,12 @@ namespace IRaCIS.Core.Application.Service
/// <returns></returns> /// <returns></returns>
[HttpPost] [HttpPost]
[UnitOfWork] [UnitOfWork]
[TrialGlobalLimit( "AfterStopCannNotOpt" )] [TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand, public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand,
[FromServices] IRepository<DicomStudy> _dicomstudyRepository, [FromServices] IRepository<DicomStudy> _dicomstudyRepository,
[FromServices] IRepository<DicomSeries> _dicomSeriesRepository, [FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
[FromServices] IRepository<DicomInstance> _dicomInstanceRepository) [FromServices] IRepository<DicomInstance> _dicomInstanceRepository,
[FromServices] IRepository<FileUploadRecord> _fileUploadRecordRepository)
{ {
//这里要做校验 + 同时验证本地系统里面的影像是否存在pacs推过来的 //这里要做校验 + 同时验证本地系统里面的影像是否存在pacs推过来的
@ -403,11 +405,14 @@ namespace IRaCIS.Core.Application.Service
var subjectVisitId = inCommand.SubjectVisitId; var subjectVisitId = inCommand.SubjectVisitId;
var trialId = inCommand.TrialId; var trialId = inCommand.TrialId;
var studyCode = "";
var studyUid = "";
var @lock = _distributedLockProvider.CreateLock($"StudyCode"); var @lock = _distributedLockProvider.CreateLock($"StudyCode");
using (await @lock.AcquireAsync()) using (await @lock.AcquireAsync())
{ {
var dbStudyCodeIntMax = _dicomStudyRepository.Where(s => s.TrialId == inCommand.TrialId).Select(t => t.Code).DefaultIfEmpty().Max(); var dbStudyCodeIntMax = _trialRepository.Where(s => s.Id == trialId, ignoreQueryFilters: true).Select(t => t.MaxDicomCode).DefaultIfEmpty().Max();
int currentNextCodeInt = dbStudyCodeIntMax + 1; int currentNextCodeInt = dbStudyCodeIntMax + 1;
@ -430,6 +435,8 @@ namespace IRaCIS.Core.Application.Service
newStuty.SubjectId = subjectId; newStuty.SubjectId = subjectId;
newStuty.SubjectVisitId = subjectVisitId; newStuty.SubjectVisitId = subjectVisitId;
studyCode = newStuty.StudyCode;
await _dicomStudyRepository.AddAsync(newStuty); await _dicomStudyRepository.AddAsync(newStuty);
@ -457,12 +464,22 @@ namespace IRaCIS.Core.Application.Service
} }
await _dicomInstanceRepository.AddRangeAsync(newInstanceList); await _dicomInstanceRepository.AddRangeAsync(newInstanceList);
//回更StudyCode
await _fileUploadRecordRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trialId && t.Path.Contains(newStuty.StudyInstanceUid), u => new FileUploadRecord() { StudyCode = studyCode, SubjectId = newStuty.SubjectId, SubjectVisitId = newStuty.SubjectVisitId });
await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == trialId, u => new Trial() { MaxDicomCode = currentNextCodeInt });
await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == find.SCPStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId });
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudyId, u => new SCPStudy() { SubjectVisitId = subjectVisitId });
} }
currentNextCodeInt++; currentNextCodeInt++;
await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == find.SCPStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId });
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudyId, u => new SCPStudy() { SubjectVisitId = subjectVisitId });
} }
@ -549,6 +566,10 @@ namespace IRaCIS.Core.Application.Service
} }
} }
//回更StudyCode
await _fileUploadRecordRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trialId && t.Path.Contains(study.StudyInstanceUid), u => new FileUploadRecord() { StudyCode = studyCode, SubjectId = study.SubjectId, SubjectVisitId = study.SubjectVisitId });
await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId }); await _scpPatientRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId });
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudyId, u => new SCPStudy() { SubjectVisitId = subjectVisitId }); await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == scpStudyId, u => new SCPStudy() { SubjectVisitId = subjectVisitId });
} }

View File

@ -33,6 +33,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using MiniExcelLibs; using MiniExcelLibs;
using Minio.DataModel; using Minio.DataModel;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions; using NPOI.SS.Formula.Functions;
using NPOI.XWPF.UserModel; using NPOI.XWPF.UserModel;
using SharpCompress.Common; using SharpCompress.Common;
@ -107,6 +108,70 @@ namespace IRaCIS.Core.Application.Service
public DateTime? DateTimeNUllValue { get; set; } public DateTime? DateTimeNUllValue { get; set; }
} }
/// <summary>
/// 维护中心调研设备默认配置
/// </summary>
/// <param name="modelVerify"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("{email}")]
public async Task<IResponseOutput> SiteSuveryEquipment()
{
//默认配置
var trialExtalConfig = new TrialExtraConfig()
{
EquipmentControlFieldList = new List<SiteSurveyEquipmentField> {
new SiteSurveyEquipmentField() { FiledName = "EquipmentTypeEnum", ShowOrder = 0, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "OtherEquipmentType", ShowOrder = 1, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "Parameters", ShowOrder = 2, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ManufacturerType", ShowOrder = 3, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ManufacturerName", ShowOrder = 4, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "ScannerType", ShowOrder = 5, IsView = true },
new SiteSurveyEquipmentField() { FiledName = "Note", ShowOrder = 6, IsView = true },
}
};
var list = _trialRepository.Where(t => t.TrialExtraConfigJsonStr != "").Select(t => new { t.Id, t.TrialExtraConfigJsonStr }).ToList();
foreach (var item in list)
{
var extralConfig = JsonConvert.DeserializeObject<TrialExtraConfig>(item.TrialExtraConfigJsonStr);
if (extralConfig.ModifyFiledList.Count > 0)
{
extralConfig.EquipmentControlFieldList = trialExtalConfig.EquipmentControlFieldList.Where(t => t.ShowOrder != 2).ToList();
}
else
{
extralConfig.EquipmentControlFieldList = trialExtalConfig.EquipmentControlFieldList;
}
var jsonInfo = extralConfig.ToJsonStr();
await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new Trial() { TrialExtraConfigJsonStr = jsonInfo });
}
var info = trialExtalConfig.ToJsonStr();
var idQuery = _trialRepository.Where(t => t.TrialExtraConfigJsonStr == "").Select(t => t.Id);
await _trialRepository.BatchUpdateNoTrackingAsync(t => idQuery.Contains(t.Id), u => new Trial() { TrialExtraConfigJsonStr = info });
return ResponseOutput.Ok();
}
//创建一个模型验证的方法 //创建一个模型验证的方法
[AllowAnonymous] [AllowAnonymous]

View File

@ -14,12 +14,52 @@ public class TrialSiteEquipmentSurvey : BaseFullAuditEntity
#endregion #endregion
public Guid TrialSiteSurveyId { get; set; } public Guid TrialSiteSurveyId { get; set; }
[Comment("扫描设备-废弃")]
public Guid EquipmentTypeId { get; set; } public Guid EquipmentTypeId { get; set; }
[Comment("扫描设备参数")]
public string Parameters { get; set; } = string.Empty; public string Parameters { get; set; } = string.Empty;
[Comment("扫描设备厂商其他补充")]
public string ManufacturerName { get; set; } = string.Empty; public string ManufacturerName { get; set; } = string.Empty;
[Comment("扫描设备型号")]
public string ScannerType { get; set; } = string.Empty; public string ScannerType { get; set; } = string.Empty;
public string Note { get; set; } = string.Empty; public string Note { get; set; } = string.Empty;
#region 新增
[Comment("扫描设备-New")]
public int EquipmentTypeEnum { get; set; }
public string OtherEquipmentType { get; set; }
[Comment("扫描设备厂商")]
public int? ManufacturerType { get; set; }
[Comment("磁场强度 (1.5T / 3.0T)")]
public int? MagneticFieldStrengthType { get; set; }
[Comment("体部线圈通道数 (≥16 或 16)")]
public int? BodyCoilChannelCount { get; set; }
[Comment("是否具备专用的PDFF脂肪定量序列CSE-MRI序列")]
public bool? HasDedicatedPdfFatQuantificationSequence { get; set; }
[Comment("专用的PDFF脂肪定量序列类型 (当 HasDedicatedPdfFatQuantificationSequence = true 时有效)")]
public int? PdfFatQuantificationSequenceType { get; set; }
[Comment("其他序列详细说明 (当 PdfFatQuantificationSequenceType = Other 时建议填写)")]
public string OtherSequenceSpecification { get; set; }
[Comment("是否包含 T2/R2 校正(用于铁沉积校正)")]
public bool? HasT2R2Correction { get; set; }
[Comment("是否可完整导出 PDFF 参数图及全部原始 DICOM 数据")]
public bool? CanFullyExportPdfParameterMapsAndRawDicom { get; set; }
#endregion
} }

View File

@ -324,6 +324,16 @@ public partial class Trial : BaseFullDeleteAuditEntity
[Comment("最大的NoneDicom检查编号 整型")] [Comment("最大的NoneDicom检查编号 整型")]
public int MaxNoneDicomCode { get; set; } public int MaxNoneDicomCode { get; set; }
/// <summary>
/// QC质控下载
/// </summary>
public bool IsSupportQCDownloadImage { get; set; } = false;
/// <summary>
/// 打开失访可读
/// </summary>
public bool IsOpenLostVistRead { get; set; } = true;
} }
public enum TrialDataStore public enum TrialDataStore

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,223 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class SiteSurveyEquipmentModify : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "ScannerType",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
comment: "扫描设备型号",
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400);
migrationBuilder.AlterColumn<string>(
name: "Parameters",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
comment: "扫描设备参数",
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400);
migrationBuilder.AlterColumn<string>(
name: "ManufacturerName",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
comment: "扫描设备厂商其他补充",
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400);
migrationBuilder.AlterColumn<Guid>(
name: "EquipmentTypeId",
table: "TrialSiteEquipmentSurvey",
type: "uniqueidentifier",
nullable: false,
comment: "扫描设备-废弃",
oldClrType: typeof(Guid),
oldType: "uniqueidentifier");
migrationBuilder.AddColumn<int>(
name: "BodyCoilChannelCount",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "体部线圈通道数 (≥16 或 16)");
migrationBuilder.AddColumn<bool>(
name: "CanFullyExportPdfParameterMapsAndRawDicom",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否可完整导出 PDFF 参数图及全部原始 DICOM 数据");
migrationBuilder.AddColumn<int>(
name: "EquipmentTypeEnum",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "扫描设备-New");
migrationBuilder.AddColumn<bool>(
name: "HasDedicatedPdfFatQuantificationSequence",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否具备专用的PDFF脂肪定量序列CSE-MRI序列");
migrationBuilder.AddColumn<bool>(
name: "HasT2R2Correction",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否包含 T2/R2 校正(用于铁沉积校正)");
migrationBuilder.AddColumn<int>(
name: "MagneticFieldStrengthType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "磁场强度 (1.5T / 3.0T)");
migrationBuilder.AddColumn<int>(
name: "ManufacturerType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "扫描设备厂商");
migrationBuilder.AddColumn<string>(
name: "OtherEquipmentType",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "OtherSequenceSpecification",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
defaultValue: "",
comment: "其他序列详细说明 (当 PdfFatQuantificationSequenceType = Other 时建议填写)");
migrationBuilder.AddColumn<int>(
name: "PdfFatQuantificationSequenceType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: true,
comment: "专用的PDFF脂肪定量序列类型 (当 HasDedicatedPdfFatQuantificationSequence = true 时有效)");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "BodyCoilChannelCount",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "CanFullyExportPdfParameterMapsAndRawDicom",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "EquipmentTypeEnum",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "HasDedicatedPdfFatQuantificationSequence",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "HasT2R2Correction",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "MagneticFieldStrengthType",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "ManufacturerType",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "OtherEquipmentType",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "OtherSequenceSpecification",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.DropColumn(
name: "PdfFatQuantificationSequenceType",
table: "TrialSiteEquipmentSurvey");
migrationBuilder.AlterColumn<string>(
name: "ScannerType",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400,
oldComment: "扫描设备型号");
migrationBuilder.AlterColumn<string>(
name: "Parameters",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400,
oldComment: "扫描设备参数");
migrationBuilder.AlterColumn<string>(
name: "ManufacturerName",
table: "TrialSiteEquipmentSurvey",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400,
oldComment: "扫描设备厂商其他补充");
migrationBuilder.AlterColumn<Guid>(
name: "EquipmentTypeId",
table: "TrialSiteEquipmentSurvey",
type: "uniqueidentifier",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uniqueidentifier",
oldComment: "扫描设备-废弃");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class modifyTrialJson : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsOpenLostVistRead",
table: "Trial",
type: "bit",
nullable: false,
defaultValue: true);
migrationBuilder.AddColumn<bool>(
name: "IsSupportQCDownloadImage",
table: "Trial",
type: "bit",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsOpenLostVistRead",
table: "Trial");
migrationBuilder.DropColumn(
name: "IsSupportQCDownloadImage",
table: "Trial");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,150 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class modifySurvey : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "ManufacturerType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: true,
comment: "扫描设备厂商",
oldClrType: typeof(int),
oldType: "int",
oldComment: "扫描设备厂商");
migrationBuilder.AlterColumn<int>(
name: "MagneticFieldStrengthType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: true,
comment: "磁场强度 (1.5T / 3.0T)",
oldClrType: typeof(int),
oldType: "int",
oldComment: "磁场强度 (1.5T / 3.0T)");
migrationBuilder.AlterColumn<bool>(
name: "HasT2R2Correction",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: true,
comment: "是否包含 T2/R2 校正(用于铁沉积校正)",
oldClrType: typeof(bool),
oldType: "bit",
oldComment: "是否包含 T2/R2 校正(用于铁沉积校正)");
migrationBuilder.AlterColumn<bool>(
name: "HasDedicatedPdfFatQuantificationSequence",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: true,
comment: "是否具备专用的PDFF脂肪定量序列CSE-MRI序列",
oldClrType: typeof(bool),
oldType: "bit",
oldComment: "是否具备专用的PDFF脂肪定量序列CSE-MRI序列");
migrationBuilder.AlterColumn<bool>(
name: "CanFullyExportPdfParameterMapsAndRawDicom",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: true,
comment: "是否可完整导出 PDFF 参数图及全部原始 DICOM 数据",
oldClrType: typeof(bool),
oldType: "bit",
oldComment: "是否可完整导出 PDFF 参数图及全部原始 DICOM 数据");
migrationBuilder.AlterColumn<int>(
name: "BodyCoilChannelCount",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: true,
comment: "体部线圈通道数 (≥16 或 16)",
oldClrType: typeof(int),
oldType: "int",
oldComment: "体部线圈通道数 (≥16 或 16)");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<int>(
name: "ManufacturerType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "扫描设备厂商",
oldClrType: typeof(int),
oldType: "int",
oldNullable: true,
oldComment: "扫描设备厂商");
migrationBuilder.AlterColumn<int>(
name: "MagneticFieldStrengthType",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "磁场强度 (1.5T / 3.0T)",
oldClrType: typeof(int),
oldType: "int",
oldNullable: true,
oldComment: "磁场强度 (1.5T / 3.0T)");
migrationBuilder.AlterColumn<bool>(
name: "HasT2R2Correction",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否包含 T2/R2 校正(用于铁沉积校正)",
oldClrType: typeof(bool),
oldType: "bit",
oldNullable: true,
oldComment: "是否包含 T2/R2 校正(用于铁沉积校正)");
migrationBuilder.AlterColumn<bool>(
name: "HasDedicatedPdfFatQuantificationSequence",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否具备专用的PDFF脂肪定量序列CSE-MRI序列",
oldClrType: typeof(bool),
oldType: "bit",
oldNullable: true,
oldComment: "是否具备专用的PDFF脂肪定量序列CSE-MRI序列");
migrationBuilder.AlterColumn<bool>(
name: "CanFullyExportPdfParameterMapsAndRawDicom",
table: "TrialSiteEquipmentSurvey",
type: "bit",
nullable: false,
defaultValue: false,
comment: "是否可完整导出 PDFF 参数图及全部原始 DICOM 数据",
oldClrType: typeof(bool),
oldType: "bit",
oldNullable: true,
oldComment: "是否可完整导出 PDFF 参数图及全部原始 DICOM 数据");
migrationBuilder.AlterColumn<int>(
name: "BodyCoilChannelCount",
table: "TrialSiteEquipmentSurvey",
type: "int",
nullable: false,
defaultValue: 0,
comment: "体部线圈通道数 (≥16 或 16)",
oldClrType: typeof(int),
oldType: "int",
oldNullable: true,
oldComment: "体部线圈通道数 (≥16 或 16)");
}
}
}

View File

@ -12642,6 +12642,9 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasColumnType("bit") .HasColumnType("bit")
.HasComment("是否 提醒受试者编号规则"); .HasComment("是否 提醒受试者编号规则");
b.Property<bool>("IsOpenLostVistRead")
.HasColumnType("bit");
b.Property<bool>("IsPACSConnect") b.Property<bool>("IsPACSConnect")
.HasColumnType("bit"); .HasColumnType("bit");
@ -12677,6 +12680,9 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<bool>("IsSubjectSexView") b.Property<bool>("IsSubjectSexView")
.HasColumnType("bit"); .HasColumnType("bit");
b.Property<bool>("IsSupportQCDownloadImage")
.HasColumnType("bit");
b.Property<bool>("IsTrialBasicLogicConfirmed") b.Property<bool>("IsTrialBasicLogicConfirmed")
.HasColumnType("bit"); .HasColumnType("bit");
@ -15017,34 +15023,81 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int?>("BodyCoilChannelCount")
.HasColumnType("int")
.HasComment("体部线圈通道数 (≥16 或 16)");
b.Property<bool?>("CanFullyExportPdfParameterMapsAndRawDicom")
.HasColumnType("bit")
.HasComment("是否可完整导出 PDFF 参数图及全部原始 DICOM 数据");
b.Property<DateTime>("CreateTime") b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2"); .HasColumnType("datetime2");
b.Property<Guid>("CreateUserId") b.Property<Guid>("CreateUserId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<int>("EquipmentTypeEnum")
.HasColumnType("int")
.HasComment("扫描设备-New");
b.Property<Guid>("EquipmentTypeId") b.Property<Guid>("EquipmentTypeId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier")
.HasComment("扫描设备-废弃");
b.Property<bool?>("HasDedicatedPdfFatQuantificationSequence")
.HasColumnType("bit")
.HasComment("是否具备专用的PDFF脂肪定量序列CSE-MRI序列");
b.Property<bool?>("HasT2R2Correction")
.HasColumnType("bit")
.HasComment("是否包含 T2/R2 校正(用于铁沉积校正)");
b.Property<int?>("MagneticFieldStrengthType")
.HasColumnType("int")
.HasComment("磁场强度 (1.5T / 3.0T)");
b.Property<string>("ManufacturerName") b.Property<string>("ManufacturerName")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)")
.HasComment("扫描设备厂商其他补充");
b.Property<int?>("ManufacturerType")
.HasColumnType("int")
.HasComment("扫描设备厂商");
b.Property<string>("Note") b.Property<string>("Note")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("Parameters") b.Property<string>("OtherEquipmentType")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<string>("OtherSequenceSpecification")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)")
.HasComment("其他序列详细说明 (当 PdfFatQuantificationSequenceType = Other 时建议填写)");
b.Property<string>("Parameters")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)")
.HasComment("扫描设备参数");
b.Property<int?>("PdfFatQuantificationSequenceType")
.HasColumnType("int")
.HasComment("专用的PDFF脂肪定量序列类型 (当 HasDedicatedPdfFatQuantificationSequence = true 时有效)");
b.Property<string>("ScannerType") b.Property<string>("ScannerType")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)")
.HasComment("扫描设备型号");
b.Property<Guid>("TrialSiteSurveyId") b.Property<Guid>("TrialSiteSurveyId")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");