Compare commits
219 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fe84cd2ad | |||
| dd1da21738 | |||
| 7185be2ff2 | |||
| c1d0bf8914 | |||
| 64fec97864 | |||
| edd562183d | |||
| 84bf6d9145 | |||
| a065f4533c | |||
| 52d64682cb | |||
| 5e0513ebcb | |||
| f7525942e7 | |||
| 3971e65482 | |||
| 4fde957519 | |||
| 8faa078afc | |||
| 7f55877688 | |||
| 84922152bd | |||
| a267c52109 | |||
| 1cad62fe1b | |||
| ac284241b7 | |||
| efbcdce768 | |||
| 00d8be6ff5 | |||
| 152ee46fd6 | |||
| 0208ffa8f4 | |||
| 71b765a28b | |||
| e72791b0f8 | |||
| 77f9275d93 | |||
| 3ba953ac7e | |||
| a627be0234 | |||
| 5eb49ca378 | |||
| 04954a4b25 | |||
| 7d08a3d920 | |||
| 4328862c92 | |||
| 58e705716e | |||
| d786b3bb61 | |||
| 905f11625a | |||
| 24c5b3c91f | |||
| ad6f593743 | |||
| f0369e15c7 | |||
| 4b7778ee7f | |||
| 7f970edd52 | |||
| d37ab8ee65 | |||
| 1570731516 | |||
| ed004fe54e | |||
| cbca0ac08f | |||
| a5b5dfb214 | |||
| 19cd09439d | |||
| 18f844601f | |||
| ea79bb71fc | |||
| 01783f9a7f | |||
| c9573fc610 | |||
| 270c4abde4 | |||
| 07270ee83d | |||
| 64060c125d | |||
| c9b998213b | |||
| fe79c77285 | |||
| 72591ee203 | |||
| 1d180fa83f | |||
| 9bf639dac0 | |||
| 11450a973a | |||
| bbb361d0cd | |||
| 7c9959b9ee | |||
| d1fb6314db | |||
| 4047220d53 | |||
| d1b45fa56d | |||
| 4c2c72fe12 | |||
| a0d1a39125 | |||
| 33618e8dfb | |||
| 1edc52bd76 | |||
| 2fa0e9e88e | |||
| 7f5e9f1bfc | |||
| 9910fb3c8e | |||
| aaf8fd62e0 | |||
| 5df54fd75d | |||
| ad00478511 | |||
| cd3508da21 | |||
| e7a116f228 | |||
| 82c0d2bcb4 | |||
| afba3b073c | |||
| 4e37c2d53e | |||
| c03c739ba0 | |||
| 65137e585c | |||
| e0111a2419 | |||
| 73b7aae6c0 | |||
| 14e212c4a8 | |||
| 344146a46e | |||
| cd5a1fcbb7 | |||
| 424448db2f | |||
| 629116cb6a | |||
| 64c3d96807 | |||
| d607018832 | |||
| 0d65625caa | |||
| 2b82044213 | |||
| 2769cf7efd | |||
| 1c84a374a1 | |||
| 2a59cfe3b5 | |||
| 0dff3d6e4b | |||
| 1d6731e3a4 | |||
| 224318e0c4 | |||
| 7096062d76 | |||
| a0b06fbc28 | |||
| 4a76705ec7 | |||
| 7676e3cc4d | |||
| 234a5706a8 | |||
| 956e214632 | |||
| 974adb4367 | |||
| 00189b992f | |||
| f192219621 | |||
| 4b0d6fe8b9 | |||
| bb6dc19924 | |||
| ec9af97742 | |||
| a5472e1509 | |||
| a1bb730cfe | |||
| 1aa411c0f8 | |||
| 10de82132d | |||
| db11656862 | |||
| a47ac76729 | |||
| f86a88332c | |||
| f6be5e4355 | |||
| 8deeb0290a | |||
| fb6231373b | |||
| a407313a95 | |||
| b1806d2eff | |||
| 19351f34e1 | |||
| e0f708082d | |||
| 44464a809d | |||
| c7c01b7ba3 | |||
| 38b71d5267 | |||
| 3950a3453a | |||
| 7aa59da586 | |||
| 9b2fbdb13f | |||
| c98b9e1bd4 | |||
| 9522461508 | |||
| 5bb99180b6 | |||
| 62ec1e4955 | |||
| 58e1af24c9 | |||
| a7394e7119 | |||
| a93d81de0d | |||
| 6aafe02c6c | |||
| 1511ef1608 | |||
| 1141439c8e | |||
| 559663082b | |||
| 3a298518f9 | |||
| 7f20232401 | |||
| 20b0849b40 | |||
| db951e9195 | |||
| d5d78a99d2 | |||
| 1609a7a88a | |||
| 289831fce8 | |||
| dde058be18 | |||
| be8b730ee4 | |||
| 28360861aa | |||
| 3e097fa42b | |||
| b8a7cd6ebc | |||
| a9aefaf240 | |||
| 266a0c5dd5 | |||
| 54822ae038 | |||
| 05203d6716 | |||
| 2ce8edde80 | |||
| 3c30f5dc14 | |||
| e4ad1c0653 | |||
| 84df49ca07 | |||
| 400edd0b70 | |||
| c4add1ecc8 | |||
| d5879e28d7 | |||
| 37e083face | |||
| 290506a060 | |||
| 1b4bc3690a | |||
| 6374781d26 | |||
| b28013a02f | |||
| fe429d2bdc | |||
| d63af2ed20 | |||
| cebf9875b1 | |||
| 131681a0b3 | |||
| f833adc710 | |||
| df80d1e551 | |||
| 82dc092247 | |||
| 44894fcaa9 | |||
| 083bebdc03 | |||
| e808764dd6 | |||
| 77d198cb09 | |||
| 180b02b28c | |||
| c49a74d742 | |||
| c76fc8f052 | |||
| 14875dfacc | |||
| 0a68788c0f | |||
| b17e5d9ff3 | |||
| 05ce4b7155 | |||
| c8bbb3da48 | |||
| 65de108ecd | |||
| d20c306219 | |||
| e69991ae37 | |||
| e1e2544ee3 | |||
| 318333bae4 | |||
| d569de4dfe | |||
| 05627ff126 | |||
| 627618c854 | |||
| 2711c5eb04 | |||
| a6982f79c3 | |||
| 2a542949cd | |||
| a8ccbce76f | |||
| df7cf30aed | |||
| 0664fbdfb7 | |||
| 0a6ee05417 | |||
| f9bd8c3f5c | |||
| cb83c2a737 | |||
| fdd9afd4f0 | |||
| 53d26c0445 | |||
| 40d035e7a7 | |||
| a13807ae5f | |||
| 9d5aaf1e26 | |||
| c347d08e2b | |||
| 87f2d0e429 | |||
| 89d009fcbf | |||
| 7d65cf5051 | |||
| e74427c45c | |||
| e8825c7efa | |||
| 628e0ad034 | |||
| 2f3f639918 | |||
| 87caf24dd1 |
@@ -12,9 +12,8 @@
|
|||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="4.0.21" />
|
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.5.19" />
|
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
||||||
|
|
||||||
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ public class AWSTempToken
|
|||||||
public string SecretAccessKey { get; set; }
|
public string SecretAccessKey { get; set; }
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime? Expiration { get; set; }
|
public DateTime Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
public enum ObjectStoreUse
|
||||||
@@ -231,8 +231,8 @@ public class OSSService : IOSSService
|
|||||||
//提供awsEndPoint(域名)进行访问配置
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
var clientConfig = new AmazonS3Config
|
var clientConfig = new AmazonS3Config
|
||||||
{
|
{
|
||||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
//,UseHttp = true,
|
UseHttp = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
@@ -320,8 +320,8 @@ public class OSSService : IOSSService
|
|||||||
//提供awsEndPoint(域名)进行访问配置
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
var clientConfig = new AmazonS3Config
|
var clientConfig = new AmazonS3Config
|
||||||
{
|
{
|
||||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
//,UseHttp = true,
|
UseHttp = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
@@ -397,8 +397,8 @@ public class OSSService : IOSSService
|
|||||||
//提供awsEndPoint(域名)进行访问配置
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
var clientConfig = new AmazonS3Config
|
var clientConfig = new AmazonS3Config
|
||||||
{
|
{
|
||||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
//,UseHttp = true,
|
UseHttp = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
@@ -493,8 +493,8 @@ public class OSSService : IOSSService
|
|||||||
//提供awsEndPoint(域名)进行访问配置
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
var clientConfig = new AmazonS3Config
|
var clientConfig = new AmazonS3Config
|
||||||
{
|
{
|
||||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
//,UseHttp = true,
|
UseHttp = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
@@ -625,8 +625,8 @@ public class OSSService : IOSSService
|
|||||||
//提供awsEndPoint(域名)进行访问配置
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
var clientConfig = new AmazonS3Config
|
var clientConfig = new AmazonS3Config
|
||||||
{
|
{
|
||||||
RegionEndpoint = RegionEndpoint.GetBySystemName(awsConfig.Region)
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
//,UseHttp = true,
|
UseHttp = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|||||||
@@ -1,175 +0,0 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
using IRaCIS.Core.Application.Service;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.SCP.Service;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP;
|
|
||||||
|
|
||||||
|
|
||||||
public class SyncFileRecoveryService(IServiceScopeFactory _scopeFactory, FileSyncQueue _fileSyncQueue) : BackgroundService
|
|
||||||
{
|
|
||||||
|
|
||||||
private readonly int _pageSize = 500;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 多个程序,如果恢复同一份数据,造成重复同步,SCP服务不恢复任务
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stoppingToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
//在本地调试的时候,不干涉部署同步任务
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await Task.CompletedTask;
|
|
||||||
|
|
||||||
//using var scope = _scopeFactory.CreateScope();
|
|
||||||
//var fileUploadRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<FileUploadRecord>>();
|
|
||||||
|
|
||||||
//// 延迟启动,保证主机快速启动
|
|
||||||
//await Task.Delay(5000, stoppingToken);
|
|
||||||
|
|
||||||
//int page = 0;
|
|
||||||
|
|
||||||
|
|
||||||
//while (!stoppingToken.IsCancellationRequested)
|
|
||||||
//{
|
|
||||||
// // 分页获取未入队任务
|
|
||||||
// var pending = await fileUploadRecordRepository
|
|
||||||
// .Where(x => x.IsNeedSync == true && (x.IsSync == false || x.IsSync == null))
|
|
||||||
// .OrderByDescending(x => x.Priority)
|
|
||||||
// .Select(t => new { t.Id, t.Priority })
|
|
||||||
// .Skip(page * _pageSize)
|
|
||||||
// .Take(_pageSize)
|
|
||||||
// .ToListAsync(stoppingToken);
|
|
||||||
|
|
||||||
// if (!pending.Any())
|
|
||||||
// break; // 扫描完毕,退出循环
|
|
||||||
|
|
||||||
// foreach (var file in pending)
|
|
||||||
// {
|
|
||||||
// //file.IsQueued = true; // 避免重复入队
|
|
||||||
// _fileSyncQueue.Enqueue(file.Id, file.Priority ?? 0); // 放入队列
|
|
||||||
// }
|
|
||||||
|
|
||||||
// page++; // 下一页
|
|
||||||
// await Task.Delay(200, stoppingToken); // 缓解数据库压力
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FileSyncWorker(IServiceScopeFactory _scopeFactory, ILogger<FileSyncWorker> _logger, FileSyncQueue _fileSyncQueue) : BackgroundService
|
|
||||||
{
|
|
||||||
|
|
||||||
// ⭐ 自动根据服务器CPU
|
|
||||||
private readonly int _workerCount = Math.Max(1, Environment.ProcessorCount - 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _workerCount; i++)
|
|
||||||
Task.Run(() => WorkerLoop(stoppingToken));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async Task WorkerLoop(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
var id = await _fileSyncQueue.DequeueAsync(stoppingToken);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var scope = _scopeFactory.CreateScope();
|
|
||||||
var _fileUploadRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<FileUploadRecord>>();
|
|
||||||
var _uploadFileSyncRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<UploadFileSyncRecord>>();
|
|
||||||
|
|
||||||
var syncConfig = (scope.ServiceProvider.GetRequiredService<IOptionsMonitor<ObjectStoreServiceOptions>>()).CurrentValue;
|
|
||||||
|
|
||||||
var oss = scope.ServiceProvider.GetRequiredService<IOSSService>();
|
|
||||||
|
|
||||||
var file = await _fileUploadRecordRepository.FirstOrDefaultAsync(t => t.Id == id);
|
|
||||||
|
|
||||||
// ✅ 不要 return
|
|
||||||
if (file == null || file.IsNeedSync != true || syncConfig.IsOpenStoreSync == false)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncConfig.SyncConfigList.Any(t => t.UploadRegion == file.UploadRegion && t.IsOpenSync == false))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//如果发现系统配置某一边同步进行了关闭,那么就直接返回,不执行任务
|
|
||||||
if (syncConfig.SyncConfigList.Any(t => t.UploadRegion == file.UploadRegion && t.IsOpenSync == false))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var log = new UploadFileSyncRecord
|
|
||||||
{
|
|
||||||
FileUploadRecordId = id,
|
|
||||||
StartTime = DateTime.Now,
|
|
||||||
JobState = jobState.RUNNING
|
|
||||||
};
|
|
||||||
|
|
||||||
await _uploadFileSyncRecordRepository.AddAsync(log);
|
|
||||||
await _uploadFileSyncRecordRepository.SaveChangesAsync(stoppingToken);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await oss.SyncFileAsync(file.Path.TrimStart('/'), file.UploadRegion == "CN" ? ObjectStoreUse.AliyunOSS : ObjectStoreUse.AWS, file.UploadRegion == "CN" ? ObjectStoreUse.AWS : ObjectStoreUse.AliyunOSS);
|
|
||||||
|
|
||||||
file.IsSync = true;
|
|
||||||
file.SyncFinishedTime = DateTime.Now;
|
|
||||||
|
|
||||||
log.JobState = jobState.SUCCESS;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.JobState = jobState.FAILED;
|
|
||||||
|
|
||||||
log.Msg = ex.Message.Length > 300 ? ex.Message.Substring(0, 300) : ex.Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.EndTime = DateTime.Now;
|
|
||||||
|
|
||||||
await _uploadFileSyncRecordRepository.SaveChangesAsync(stoppingToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Sync failed {Id}", id);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// ⭐⭐⭐ 永远执行
|
|
||||||
_fileSyncQueue.Complete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7,28 +7,28 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.2.0" />
|
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="11.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="4.0.21" />
|
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.5.19" />
|
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
||||||
<PackageReference Include="DistributedLock.Core" Version="1.0.9" />
|
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.7" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.2.6" />
|
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
||||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.7" />
|
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
|
||||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.6" />
|
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||||
<PackageReference Include="AutoMapper" Version="16.1.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Minio" Version="7.0.0" />
|
<PackageReference Include="Minio" Version="6.0.3" />
|
||||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||||
<TreatAsUsed>true</TreatAsUsed>
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.9.0" />
|
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
|
||||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="10.0.0" />
|
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.1.7" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ builder.Host
|
|||||||
#region 配置服务
|
#region 配置服务
|
||||||
var _configuration = builder.Configuration;
|
var _configuration = builder.Configuration;
|
||||||
|
|
||||||
builder.Services.AddSingleton<FileSyncQueue>();
|
|
||||||
builder.Services.AddHostedService<SyncFileRecoveryService>();
|
|
||||||
builder.Services.AddHostedService<FileSyncWorker>();
|
|
||||||
|
|
||||||
//健康检查
|
//健康检查
|
||||||
builder.Services.AddHealthChecks();
|
builder.Services.AddHealthChecks();
|
||||||
|
|
||||||
@@ -117,9 +113,6 @@ builder.Services.AddAutoMapper(automapper =>
|
|||||||
//EF ORM QueryWithNoLock
|
//EF ORM QueryWithNoLock
|
||||||
builder.Services.AddEFSetup(_configuration);
|
builder.Services.AddEFSetup(_configuration);
|
||||||
|
|
||||||
// FusionCache
|
|
||||||
builder.Services.AddFusionCache();
|
|
||||||
|
|
||||||
builder.Services.AddMediator(cfg =>
|
builder.Services.AddMediator(cfg =>
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -198,7 +191,6 @@ app.MapControllers();
|
|||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
//.MinimumLevel.Information()
|
//.MinimumLevel.Information()
|
||||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
|
||||||
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
|
||||||
.WriteTo.Console()
|
.WriteTo.Console()
|
||||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
using FellowOakDicom;
|
using FellowOakDicom.Network;
|
||||||
using FellowOakDicom.Imaging;
|
using FellowOakDicom;
|
||||||
using FellowOakDicom.IO.Buffer;
|
|
||||||
using FellowOakDicom.Network;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using IRaCIS.Core.SCP.Service;
|
|
||||||
using MassTransit;
|
|
||||||
using Medallion.Threading;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Serilog;
|
|
||||||
using SharpCompress.Common;
|
|
||||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using IRaCIS.Core.SCP.Service;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using Medallion.Threading;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using Serilog;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Data;
|
||||||
|
using FellowOakDicom.Imaging;
|
||||||
|
using SharpCompress.Common;
|
||||||
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
using FellowOakDicom.IO.Buffer;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
@@ -53,8 +51,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
private Guid _trialSiteId { get; set; }
|
private Guid _trialSiteId { get; set; }
|
||||||
|
|
||||||
private bool _releasedNormally = false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
||||||
@@ -96,7 +92,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
||||||
{
|
{
|
||||||
|
|
||||||
_upload = new SCPImageUpload() { Id = NewId.NextSequentialGuid(), StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
|
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
|
||||||
|
|
||||||
|
|
||||||
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
|
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
|
||||||
@@ -122,7 +118,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();
|
var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();
|
||||||
|
|
||||||
|
|
||||||
var findTrialSiteAE = _trialSiteDicomAERepository.Where(t => t.CallingAE == association.CallingAE && t.TrialId == _trialId).FirstOrDefault();
|
var findTrialSiteAE = _trialSiteDicomAERepository.Where(t => t.CallingAE == association.CallingAE && t.TrialId==_trialId).FirstOrDefault();
|
||||||
|
|
||||||
if (findTrialSiteAE != null)
|
if (findTrialSiteAE != null)
|
||||||
{
|
{
|
||||||
@@ -131,7 +127,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
isCanReceiveIamge = true;
|
isCanReceiveIamge = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (association.CallingAE == "test-callingAE")
|
if (association.CallingAE == "test-callingAE")
|
||||||
@@ -184,15 +180,12 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
await AddUploadLogAsync();
|
await AddUploadLogAsync();
|
||||||
|
|
||||||
|
|
||||||
_releasedNormally = true;
|
|
||||||
|
|
||||||
Log.Logger.Information($"进入释放连接请求 {_releasedNormally}");
|
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||||
|
//将检查设置为传输结束
|
||||||
|
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||||
|
|
||||||
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||||
////将检查设置为传输结束
|
|
||||||
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
|
||||||
|
|
||||||
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,25 +199,15 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
||||||
|
|
||||||
//有时候没有建立连接会走关闭通过日志发现
|
_upload.EndTime = DateTime.Now;
|
||||||
if (_upload != null)
|
_upload.StudyCount = _ImageUploadList.Count;
|
||||||
{
|
_upload.TrialId = _trialId;
|
||||||
_upload.EndTime = DateTime.Now;
|
_upload.TrialSiteId = _trialSiteId;
|
||||||
_upload.StudyCount = _ImageUploadList.Count;
|
|
||||||
_upload.TrialId = _trialId;
|
|
||||||
_upload.TrialSiteId = _trialSiteId;
|
|
||||||
|
|
||||||
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
|
|
||||||
|
|
||||||
//可能是测试echo 导致记录了
|
|
||||||
if (_upload.FileCount > 0)
|
|
||||||
{
|
|
||||||
//可能是测试echo 导致记录了
|
|
||||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
|
||||||
|
|
||||||
|
//可能是测试echo 导致记录了
|
||||||
|
await _SCPImageUploadRepository.AddAsync(_upload, _upload.FileCount > 0 ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -279,26 +262,23 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
public async void OnConnectionClosed(Exception exception)
|
public async void OnConnectionClosed(Exception exception)
|
||||||
{
|
{
|
||||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
/* nothing to do here */
|
||||||
|
|
||||||
|
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
|
||||||
if (exception != null || _releasedNormally == false)
|
if (exception == null)
|
||||||
{
|
{
|
||||||
//客户端断网,恢复后,也是没有异常的,估计是超时走了关闭
|
//var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||||
|
////将检查设置为传输结束
|
||||||
|
//await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||||
|
|
||||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true, IsUploadFaild = true });
|
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||||
//记录日志
|
|
||||||
await AddUploadLogAsync();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//将检查设置为传输结束
|
//记录日志
|
||||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true, IsUploadFaild = false });
|
await AddUploadLogAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
|
||||||
|
|
||||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,11 +316,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
||||||
|
|
||||||
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||||
var _fusionCache = _serviceProvider.GetService<IFusionCache>();
|
|
||||||
var _trialSiteRepository = _serviceProvider.GetService<IRepository<TrialSite>>();
|
|
||||||
var _systemAnonymizationRepository = _serviceProvider.GetService<IRepository<SystemAnonymization>>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var storeRelativePath = string.Empty;
|
var storeRelativePath = string.Empty;
|
||||||
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}/{studyInstanceUid}";
|
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}/{studyInstanceUid}";
|
||||||
@@ -349,383 +324,74 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
long fileSize = 0;
|
long fileSize = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 直接拿 Dataset(已经完整)
|
using (MemoryStream ms = new MemoryStream())
|
||||||
var dataset = request.Dataset;
|
|
||||||
|
|
||||||
#region 匿名化
|
|
||||||
|
|
||||||
|
|
||||||
var anonymizeList = await _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7));
|
|
||||||
|
|
||||||
var trialSiteInfo = await _fusionCache.GetOrSetAsync(CacheKeys.TrialSiteInfo(_trialSiteId), _ => CacheHelper.GetTrialSiteInfo(_trialSiteId, _trialSiteRepository), TimeSpan.FromMinutes(2));
|
|
||||||
|
|
||||||
var fixedFiledList = anonymizeList.Where(t => t.IsFixed).ToList();
|
|
||||||
|
|
||||||
var ircFiledList = anonymizeList.Where(t => t.IsFixed == false).ToList();
|
|
||||||
|
|
||||||
foreach (var item in fixedFiledList)
|
|
||||||
{
|
{
|
||||||
|
await request.File.SaveAsync(ms);
|
||||||
|
|
||||||
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
#region 1帧拆成多个固定大小的,方便移动端浏览
|
||||||
|
|
||||||
dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
|
// 回到开头,读取 dicom
|
||||||
}
|
ms.Position = 0;
|
||||||
|
var dicomFile = DicomFile.Open(ms);
|
||||||
|
|
||||||
foreach (var item in ircFiledList)
|
|
||||||
{
|
|
||||||
|
|
||||||
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
|
||||||
|
|
||||||
if (dicomTag == DicomTag.ClinicalTrialProtocolID)
|
|
||||||
{
|
|
||||||
dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, trialSiteInfo.TrialCode);
|
|
||||||
|
|
||||||
}
|
|
||||||
if (dicomTag == DicomTag.ClinicalTrialSiteID)
|
|
||||||
{
|
|
||||||
dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, trialSiteInfo.TrialSiteCode);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dicomTag == DicomTag.ClinicalTrialSubjectID)
|
|
||||||
{
|
|
||||||
dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, "");
|
|
||||||
|
|
||||||
}
|
|
||||||
if (dicomTag == DicomTag.ClinicalTrialTimePointID)
|
|
||||||
{
|
|
||||||
dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dicomTag == DicomTag.PatientID)
|
|
||||||
{
|
|
||||||
var pid = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
|
||||||
|
|
||||||
dataset.AddOrUpdate(DicomTag.PatientID, trialSiteInfo.TrialCode + "-" + pid);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// 构造 DicomFile(不用 Open)
|
|
||||||
var dicomFile = new DicomFile(dataset);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region 1帧拆成多个固定大小的,方便移动端浏览
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var numberOfFrames = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1);
|
|
||||||
|
|
||||||
//多帧处理逻辑
|
|
||||||
if (numberOfFrames > 1)
|
|
||||||
{
|
|
||||||
//一定要有像素数据才处理
|
|
||||||
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||||
|
var syntax = pixelData.Syntax;
|
||||||
|
|
||||||
if (pixelData != null)
|
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
|
||||||
|
int fragmentSize = 20 * 1024;
|
||||||
|
|
||||||
|
if (syntax.IsEncapsulated)
|
||||||
{
|
{
|
||||||
try
|
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
||||||
|
|
||||||
|
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
||||||
{
|
{
|
||||||
|
var frameData = pixelData.GetFrame(n); // 获取完整一帧
|
||||||
|
var data = frameData.Data;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 开始处理多帧instanceId:{instanceId}");
|
while (offset < data.Length)
|
||||||
|
|
||||||
var syntax = pixelData.Syntax;
|
|
||||||
|
|
||||||
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
|
|
||||||
int fragmentSize = 20 * 1024;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var frag = dicomFile.Dataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData);
|
|
||||||
|
|
||||||
int fragmentCount = frag?.Fragments?.Count() ?? 0;
|
|
||||||
|
|
||||||
var originOffsetTable = frag?.OffsetTable; //有可能没有表,需要自己重建
|
|
||||||
|
|
||||||
var bot = new List<uint>();
|
|
||||||
|
|
||||||
uint botOffset = 0;
|
|
||||||
|
|
||||||
//需要拆成固定片段的
|
|
||||||
if (syntax.IsEncapsulated && fragmentCount == pixelData.NumberOfFrames && numberOfFrames > 1)
|
|
||||||
{
|
{
|
||||||
|
int size = Math.Min(fragmentSize, data.Length - offset);
|
||||||
|
var buffer = new byte[size];
|
||||||
|
Buffer.BlockCopy(data, offset, buffer, 0, size);
|
||||||
|
|
||||||
|
newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
||||||
|
offset += size;
|
||||||
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
|
||||||
|
|
||||||
#region test
|
|
||||||
//var newDicomFile = dicomFile.Clone();
|
|
||||||
|
|
||||||
//var newDataset = newDicomFile.Dataset;
|
|
||||||
|
|
||||||
//var dstPd = DicomPixelData.Create(newDataset, true);
|
|
||||||
|
|
||||||
//for (int i = 0; i < pixelData.NumberOfFrames; i++)
|
|
||||||
//{
|
|
||||||
// var frame = pixelData.GetFrame(i);
|
|
||||||
|
|
||||||
// dstPd.AddFrame(frame);
|
|
||||||
|
|
||||||
// var data = frame.Data;
|
|
||||||
// int offset = 0;
|
|
||||||
|
|
||||||
// while (offset < data.Length)
|
|
||||||
// {
|
|
||||||
// int size = Math.Min(fragmentSize, data.Length - offset);
|
|
||||||
// var buffer = new byte[size];
|
|
||||||
// Buffer.BlockCopy(data, offset, buffer, 0, size);
|
|
||||||
|
|
||||||
// newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
|
||||||
|
|
||||||
// offset += size;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
//var newOffsetTable = newDataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData).OffsetTable;
|
|
||||||
|
|
||||||
//newFragments.OffsetTable.AddRange(newOffsetTable.ToArray());
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region test fo-dicom auto bot
|
|
||||||
//var newDicomFile = dicomFile.Clone();
|
|
||||||
|
|
||||||
//var newDataset = newDicomFile.Dataset;
|
|
||||||
|
|
||||||
//var dstPd = DicomPixelData.Create(newDataset, true);
|
|
||||||
|
|
||||||
//for (int i = 0; i < pixelData.NumberOfFrames; i++)
|
|
||||||
//{
|
|
||||||
// var frame = pixelData.GetFrame(i);
|
|
||||||
|
|
||||||
// dstPd.AddFrame(frame);
|
|
||||||
//}
|
|
||||||
//var newOffsetTable = newDataset.GetDicomItem<DicomOtherByteFragment>(DicomTag.PixelData).OffsetTable;
|
|
||||||
|
|
||||||
//Console.WriteLine(newOffsetTable.ToJsonStr());
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 最终使用
|
|
||||||
|
|
||||||
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
|
||||||
{
|
|
||||||
var frameData = pixelData.GetFrame(n); // 获取完整一帧
|
|
||||||
var data = frameData.Data;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
bot.Add(botOffset);
|
|
||||||
|
|
||||||
botOffset += (uint)data.Length;
|
|
||||||
|
|
||||||
|
|
||||||
while (offset < data.Length)
|
|
||||||
{
|
|
||||||
botOffset += 8;
|
|
||||||
|
|
||||||
|
|
||||||
int size = Math.Min(fragmentSize, data.Length - offset);
|
|
||||||
var buffer = new byte[size];
|
|
||||||
Buffer.BlockCopy(data, offset, buffer, 0, size);
|
|
||||||
|
|
||||||
newFragments.Fragments.Add(new MemoryByteBuffer(buffer));
|
|
||||||
|
|
||||||
offset += size;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//保留原始偏移表
|
|
||||||
|
|
||||||
//if (originOffsetTable.Count == pixelData.NumberOfFrames)
|
|
||||||
//{
|
|
||||||
// newFragments.OffsetTable.AddRange(originOffsetTable.ToArray());
|
|
||||||
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
{
|
|
||||||
newFragments.OffsetTable.AddRange(bot.ToArray());
|
|
||||||
|
|
||||||
//Console.WriteLine(bot.ToJsonStr());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
dicomFile.Dataset.AddOrUpdate(newFragments);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//传递过来的就是拆分的,但是是没有偏移表的,我需要自己创建偏移表,不然生成缩略图失败
|
|
||||||
else if (syntax.IsEncapsulated && fragmentCount > pixelData.NumberOfFrames && originOffsetTable.Count == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint offset = 0;
|
|
||||||
|
|
||||||
bot.Add(offset);
|
|
||||||
|
|
||||||
var fistSize = frag.Fragments.FirstOrDefault()?.Size ?? 0;
|
|
||||||
|
|
||||||
//和上一个大小不一样
|
|
||||||
var isDiffrentBefore = false;
|
|
||||||
|
|
||||||
uint count = 0;
|
|
||||||
|
|
||||||
// 假设你知道每帧对应的 fragment 数量
|
|
||||||
foreach (var frameFragments in frag.Fragments)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
|
|
||||||
if (frameFragments.Size == fistSize)
|
|
||||||
{
|
|
||||||
isDiffrentBefore = false;
|
|
||||||
// 累加这一帧所有 fragment 的大小
|
|
||||||
offset += (uint)frameFragments.Size;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset += (uint)frameFragments.Size;
|
|
||||||
isDiffrentBefore = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDiffrentBefore)
|
|
||||||
{
|
|
||||||
//每个Fragment 也占用字节
|
|
||||||
offset += 8 * count;
|
|
||||||
bot.Add(offset);
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.RemoveAt(bot.Count - 1);
|
|
||||||
// 设置到新的 PixelData
|
|
||||||
frag.OffsetTable.AddRange(bot.ToArray());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception mutiEx)
|
|
||||||
{
|
|
||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 处理多帧失败,上传原始文件:{mutiEx.ToString()}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 替换原 PixelData
|
||||||
|
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||||
|
|
||||||
|
|
||||||
|
// 重新保存 dicom 到流
|
||||||
|
ms.SetLength(0);
|
||||||
|
dicomFile.Save(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
ms.Position = 0;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 本地测试
|
|
||||||
//// --- 保存到本地文件测试 ---
|
|
||||||
//var localPath = @"D:\TestDicom.dcm";
|
|
||||||
//using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write))
|
|
||||||
//{
|
|
||||||
// ms.CopyTo(fs);
|
|
||||||
//}
|
|
||||||
//return new DicomCStoreResponse(request, DicomStatus.Success);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// 直接写入内存
|
|
||||||
await using var ms = new MemoryStream();
|
|
||||||
await dicomFile.SaveAsync(ms);
|
|
||||||
ms.Position = 0;
|
|
||||||
|
|
||||||
//irc 从路径最后一截取Guid
|
|
||||||
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = _trialId, BatchDataType = BatchDataType.PACSReceive, UploadBatchId = _upload.Id.ToString() });
|
|
||||||
|
|
||||||
fileSize = ms.Length;
|
|
||||||
|
|
||||||
|
|
||||||
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
#region 本地测试
|
||||||
|
//// --- 保存到本地文件测试 ---
|
||||||
|
//var localPath = @"D:\TestDicom.dcm";
|
||||||
|
//using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write))
|
||||||
|
//{
|
||||||
|
// ms.CopyTo(fs);
|
||||||
|
//}
|
||||||
|
//return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
|
|
||||||
using (await @lock.AcquireAsync())
|
#endregion
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(dicomFile, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE, fileSize);
|
|
||||||
|
|
||||||
|
|
||||||
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
//irc 从路径最后一截取Guid
|
||||||
|
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
||||||
//没有缩略图
|
|
||||||
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
|
|
||||||
{
|
|
||||||
|
|
||||||
// 生成缩略图
|
|
||||||
using (var memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
DicomImage image = new DicomImage(dicomFile.Dataset);
|
|
||||||
|
|
||||||
var sharpimage = image.RenderImage().AsSharpImage();
|
|
||||||
sharpimage.Save(memoryStream, new JpegEncoder());
|
|
||||||
|
|
||||||
// 上传缩略图到 OSS
|
|
||||||
|
|
||||||
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, $"{seriesId.ToString()}_{instanceId.ToString()}.preview.jpg", false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = _trialId, BatchDataType = BatchDataType.PACSReceive });
|
|
||||||
|
|
||||||
|
|
||||||
series.ImageResizePath = seriesPath;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await _seriesRepository.SaveChangesAsync();
|
|
||||||
|
|
||||||
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
|
||||||
{
|
|
||||||
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
|
||||||
|
|
||||||
|
|
||||||
find.SuccessImageCount++;
|
|
||||||
|
|
||||||
if (!find.PatientNameList.Any(t => t == patientIdStr) && patientIdStr.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
find.PatientNameList.Add(patientIdStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
//首次 (默认是Guid 空,数据库归档出了Id)
|
|
||||||
if (find.SCPStudyId != scpStudyId)
|
|
||||||
{
|
|
||||||
find.SCPStudyId = scpStudyId;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//监控信息设置
|
|
||||||
_upload.FileCount++;
|
|
||||||
_upload.FileSize = _upload.FileSize + fileSize;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
|
||||||
|
|
||||||
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
|
||||||
{
|
|
||||||
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
|
||||||
|
|
||||||
find.FailedImageCount++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
fileSize = ms.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");
|
Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");
|
||||||
@@ -736,6 +402,87 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
||||||
|
|
||||||
|
using (await @lock.AcquireAsync())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.File, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
||||||
|
|
||||||
|
|
||||||
|
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||||
|
|
||||||
|
//没有缩略图
|
||||||
|
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
|
||||||
|
{
|
||||||
|
|
||||||
|
// 生成缩略图
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
DicomImage image = new DicomImage(request.Dataset);
|
||||||
|
|
||||||
|
var sharpimage = image.RenderImage().AsSharpImage();
|
||||||
|
sharpimage.Save(memoryStream, new JpegEncoder());
|
||||||
|
|
||||||
|
// 上传缩略图到 OSS
|
||||||
|
|
||||||
|
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);
|
||||||
|
|
||||||
|
Console.WriteLine(seriesPath + " Id: " + seriesId);
|
||||||
|
|
||||||
|
series.ImageResizePath = seriesPath;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _seriesRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||||
|
{
|
||||||
|
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||||
|
|
||||||
|
|
||||||
|
find.SuccessImageCount++;
|
||||||
|
|
||||||
|
if (!find.PatientNameList.Any(t => t == patientIdStr) && patientIdStr.IsNotNullOrEmpty())
|
||||||
|
{
|
||||||
|
find.PatientNameList.Add(patientIdStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//首次 (默认是Guid 空,数据库归档出了Id)
|
||||||
|
if (find.SCPStudyId != scpStudyId)
|
||||||
|
{
|
||||||
|
find.SCPStudyId = scpStudyId;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
||||||
|
|
||||||
|
if (_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||||
|
{
|
||||||
|
var find = _ImageUploadList.FirstOrDefault(t => t.StudyInstanceUid.Equals(studyInstanceUid));
|
||||||
|
|
||||||
|
find.FailedImageCount++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//监控信息设置
|
||||||
|
_upload.FileCount++;
|
||||||
|
_upload.FileSize = _upload.FileSize + fileSize;
|
||||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service;
|
|
||||||
|
|
||||||
|
|
||||||
public static class CacheKeys
|
|
||||||
{
|
|
||||||
//项目缓存
|
|
||||||
public static string Trial(string trialIdStr) => $"TrialId:{trialIdStr}";
|
|
||||||
|
|
||||||
//检查编号递增锁
|
|
||||||
public static string TrialStudyMaxCode(Guid trialId) => $"TrialStudyMaxCode:{trialId}";
|
|
||||||
|
|
||||||
public static string TrialStudyUidUploading(Guid trialId, string studyUid) => $"TrialStudyUid:{trialId}_{studyUid}";
|
|
||||||
//CRC上传影像提交锁key
|
|
||||||
public static string TrialStudyUidDBLock(Guid trialId, string studyUid) => $"TrialStudyUidDBLock:{trialId}_{studyUid}";
|
|
||||||
|
|
||||||
public static string TrialTaskStudyUidUploading(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialStudyUid:{trialId}_{visiTaskId}_{studyUid}";
|
|
||||||
//影像后处理上传提交锁key
|
|
||||||
public static string TrialTaskStudyUidDBLock(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialTaskStudyUidDBLock:{trialId}_{visiTaskId}_{studyUid}";
|
|
||||||
//系统匿名化
|
|
||||||
public static string SystemAnonymization => $"SystemAnonymization";
|
|
||||||
//前端国际化
|
|
||||||
public static string FrontInternational => $"FrontInternationalList";
|
|
||||||
|
|
||||||
//登录挤账号
|
|
||||||
public static string UserToken(Guid userId) => $"UserToken:{userId}";
|
|
||||||
|
|
||||||
//超时没请求接口自动退出
|
|
||||||
public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}";
|
|
||||||
|
|
||||||
|
|
||||||
public static string UserDisable(Guid userId) => $"UserDisable:{userId}";
|
|
||||||
|
|
||||||
public static string UserRoleDisable(Guid userRoleId) => $"UserRoleDisable:{userRoleId}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户登录错误 限制登录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userName"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string UserLoginError(string userName) => $"login-failures:{userName}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 跳过阅片
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string SkipReadingCacheKey(Guid userId) => $"{userId}SkipReadingCache";
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始阅片时间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string StartReadingTimeKey(Guid userId) => $"{userId}StartReadingTime";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 开始休息时间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="userId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
|
||||||
|
|
||||||
//每个用户 每个浏览器独立时间
|
|
||||||
public static string UserMFAVerifyPass(Guid userId, string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}";
|
|
||||||
|
|
||||||
public static string TrialSiteInfo(Guid trialSiteId) => $"{trialSiteId}TrialSiteInfo";
|
|
||||||
|
|
||||||
public static string TrialDataStoreType(Guid trialId) => $"TrialDataStoreType:{trialId}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CacheHelper
|
|
||||||
{
|
|
||||||
public static async Task<string?> GetTrialStatusAsync(Guid trialId, IRepository<Trial> _trialRepository)
|
|
||||||
{
|
|
||||||
var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
return statusStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TrialSiteInfoDTO
|
|
||||||
{
|
|
||||||
public string TrialSiteCode { get; set; }
|
|
||||||
public string TrialCode { get; set; }
|
|
||||||
}
|
|
||||||
public static async Task<TrialSiteInfoDTO> GetTrialSiteInfo(Guid trialSiteId, IRepository<TrialSite> _trialSiteRepository)
|
|
||||||
{
|
|
||||||
var obj = await _trialSiteRepository.Where(t => t.Id == trialSiteId, ignoreQueryFilters: true).Select(t => new TrialSiteInfoDTO { TrialCode= t.Trial.TrialCode, TrialSiteCode= t.TrialSiteCode }).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
return obj??new TrialSiteInfoDTO();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<List<SystemAnonymization>> GetSystemAnonymizationListAsync(IRepository<SystemAnonymization> _systemAnonymizationRepository)
|
|
||||||
{
|
|
||||||
var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +1,49 @@
|
|||||||
using FellowOakDicom;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using FellowOakDicom.Imaging.Codec;
|
|
||||||
using FellowOakDicom.Network;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using IRaCIS.Core.SCP.Service;
|
|
||||||
using MassTransit;
|
|
||||||
using Medallion.Threading;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Serilog.Sinks.File;
|
|
||||||
using System.Data;
|
|
||||||
using System.Runtime.Intrinsics.X86;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using static IRaCIS.Core.SCP.Service.CacheHelper;
|
using IRaCIS.Core.Infrastructure;
|
||||||
|
using Medallion.Threading;
|
||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Imaging.Codec;
|
||||||
|
using System.Data;
|
||||||
|
using IRaCIS.Core.Domain.Models;
|
||||||
|
using FellowOakDicom.Network;
|
||||||
|
using IRaCIS.Core.SCP.Service;
|
||||||
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
|
using MassTransit;
|
||||||
|
using System.Runtime.Intrinsics.X86;
|
||||||
|
using Serilog.Sinks.File;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
public class DicomArchiveService(IRepository<SCPPatient> _patientRepository,
|
public class DicomArchiveService : BaseService, IDicomArchiveService
|
||||||
IRepository<SCPStudy> _studyRepository,
|
|
||||||
IRepository<SCPSeries> _seriesRepository,
|
|
||||||
IRepository<SCPInstance> _instanceRepository
|
|
||||||
) : BaseService, IDicomArchiveService
|
|
||||||
{
|
{
|
||||||
|
private readonly IRepository<SCPPatient> _patientRepository;
|
||||||
|
private readonly IRepository<SCPStudy> _studyRepository;
|
||||||
|
private readonly IRepository<SCPSeries> _seriesRepository;
|
||||||
|
private readonly IRepository<SCPInstance> _instanceRepository;
|
||||||
|
private readonly IRepository<Dictionary> _dictionaryRepository;
|
||||||
|
private readonly IDistributedLockProvider _distributedLockProvider;
|
||||||
|
|
||||||
|
|
||||||
|
private List<Guid> _instanceIdList = new List<Guid>();
|
||||||
|
|
||||||
|
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
|
||||||
|
IRepository<SCPSeries> seriesRepository,
|
||||||
|
IRepository<SCPInstance> instanceRepository,
|
||||||
|
IRepository<Dictionary> dictionaryRepository,
|
||||||
|
IDistributedLockProvider distributedLockProvider)
|
||||||
|
{
|
||||||
|
_distributedLockProvider = distributedLockProvider;
|
||||||
|
_studyRepository = studyRepository;
|
||||||
|
_patientRepository = patientRepository;
|
||||||
|
_seriesRepository = seriesRepository;
|
||||||
|
_instanceRepository = instanceRepository;
|
||||||
|
_dictionaryRepository = dictionaryRepository;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -36,19 +53,18 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
/// <param name="dataset"></param>
|
/// <param name="dataset"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="NotImplementedException"></exception>
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE, long fileSize)
|
public async Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
|
||||||
{
|
{
|
||||||
|
|
||||||
var dataset = dicomFile.Dataset;
|
var dataset = dicomFile.Dataset;
|
||||||
|
|
||||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||||
|
|
||||||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
|
||||||
|
|
||||||
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
||||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
|
||||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
||||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
||||||
|
|
||||||
@@ -61,9 +77,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
//using (@lock.Acquire())
|
//using (@lock.Acquire())
|
||||||
{
|
{
|
||||||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId == trialSiteId);
|
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
|
||||||
var findStudy = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
|
||||||
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||||
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
|
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
|
||||||
|
|
||||||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
||||||
@@ -77,8 +93,8 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
findPatient = new SCPPatient()
|
findPatient = new SCPPatient()
|
||||||
{
|
{
|
||||||
Id = NewId.NextSequentialGuid(),
|
Id = NewId.NextSequentialGuid(),
|
||||||
TrialId = trialId,
|
TrialId=trialId,
|
||||||
TrialSiteId = trialSiteId,
|
TrialSiteId=trialSiteId,
|
||||||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||||
@@ -106,7 +122,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
|
|
||||||
DateTime birthDate;
|
DateTime birthDate;
|
||||||
|
|
||||||
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate, out birthDate))
|
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
|
||||||
{
|
{
|
||||||
var patientAge = studyTime.Value.Year - birthDate.Year;
|
var patientAge = studyTime.Value.Year - birthDate.Year;
|
||||||
// 如果生日还未到,年龄减去一岁
|
// 如果生日还未到,年龄减去一岁
|
||||||
@@ -204,18 +220,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||||||
|
|
||||||
RadionuclideTotalDose= dataset.GetSingleValueOrDefault(DicomTag.RadionuclideTotalDose, string.Empty),
|
|
||||||
|
|
||||||
RadionuclideHalfLife= dataset.GetSingleValueOrDefault(DicomTag.RadionuclideHalfLife, string.Empty),
|
|
||||||
RadiopharmaceuticalStartTime = dataset.GetSingleValueOrDefault(DicomTag.RadiopharmaceuticalStartTime, string.Empty),
|
|
||||||
|
|
||||||
|
|
||||||
Manufacturer = dataset.GetSingleValueOrDefault(DicomTag.Manufacturer, string.Empty),
|
|
||||||
ManufacturerModelName = dataset.GetSingleValueOrDefault(DicomTag.ManufacturerModelName, string.Empty),
|
|
||||||
DeviceSerialNumber = dataset.GetSingleValueOrDefault(DicomTag.DeviceSerialNumber, string.Empty),
|
|
||||||
DeviceUID = dataset.GetSingleValueOrDefault(DicomTag.DeviceUID, string.Empty),
|
|
||||||
SoftwareVersions = dataset.GetSingleValueOrDefault(DicomTag.SoftwareVersions, string.Empty),
|
|
||||||
PatientWeight = dataset.GetSingleValueOrDefault(DicomTag.PatientWeight, string.Empty),
|
|
||||||
|
|
||||||
|
|
||||||
//IsDoubleReview = addtionalInfo.IsDoubleReview,
|
//IsDoubleReview = addtionalInfo.IsDoubleReview,
|
||||||
@@ -235,7 +239,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
||||||
findStudy.CalledAE = calledAE;
|
findStudy.CalledAE = calledAE;
|
||||||
findStudy.CallingAE = callingAE;
|
findStudy.CallingAE = callingAE;
|
||||||
findStudy.PatientIdStr = patientIdStr;
|
|
||||||
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||||
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||||
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||||
@@ -278,9 +281,6 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||||||
|
|
||||||
RadiopharmaceuticalInformationSequence = dataset.GetSingleValueOrDefault(DicomTag.RadiopharmaceuticalInformationSequence, string.Empty),
|
|
||||||
AcquisitionDate = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionDate, string.Empty),
|
|
||||||
|
|
||||||
|
|
||||||
InstanceCount = 0
|
InstanceCount = 0
|
||||||
};
|
};
|
||||||
@@ -325,31 +325,16 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||||||
|
|
||||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||||
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1),
|
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
|
||||||
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
||||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||||||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
||||||
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
||||||
|
|
||||||
PhotometricInterpretation = dataset.GetSingleValueOrDefault(DicomTag.PhotometricInterpretation, string.Empty),
|
|
||||||
BitsAllocated = dataset.GetSingleValueOrDefault(DicomTag.BitsAllocated, 0),
|
|
||||||
PixelRepresentation = dataset.GetSingleValueOrDefault(DicomTag.PixelRepresentation, string.Empty),
|
|
||||||
RescaleIntercept = dataset.GetSingleValueOrDefault(DicomTag.RescaleIntercept, string.Empty),
|
|
||||||
RescaleSlope = dataset.GetSingleValueOrDefault(DicomTag.RescaleSlope, string.Empty),
|
|
||||||
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
|
|
||||||
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
|
|
||||||
SequenceOfUltrasoundRegions = dataset.GetSingleValueOrDefault(DicomTag.SequenceOfUltrasoundRegions, string.Empty),
|
|
||||||
FrameTime = dataset.GetSingleValueOrDefault(DicomTag.FrameTime, string.Empty),
|
|
||||||
CorrectedImage = dataset.GetSingleValueOrDefault(DicomTag.CorrectedImage, string.Empty),
|
|
||||||
Units = dataset.GetSingleValueOrDefault(DicomTag.Units, string.Empty),
|
|
||||||
DecayCorrection = dataset.GetSingleValueOrDefault(DicomTag.DecayCorrection, string.Empty),
|
|
||||||
EncapsulatedDocument = dataset.GetSingleValueOrDefault(DicomTag.EncapsulatedDocument, string.Empty),
|
|
||||||
|
|
||||||
|
|
||||||
Path = fileRelativePath,
|
Path = fileRelativePath,
|
||||||
|
|
||||||
FileSize = fileSize,
|
FileSize= fileSize,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -389,7 +374,7 @@ namespace IRaCIS.Core.SCP.Service
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath, FileSize = fileSize });
|
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
|
||||||
}
|
}
|
||||||
|
|
||||||
await _studyRepository.SaveChangesAsync();
|
await _studyRepository.SaveChangesAsync();
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2026-03-10 06:15:17Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using AutoMapper;
|
|
||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.Infra.EFCore.Common;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using IRaCIS.Core.SCP;
|
|
||||||
using IRaCIS.Core.SCP.Service;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Localization;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Threading.Channels;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ZiggyCreatures.Caching.Fusion;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service;
|
|
||||||
|
|
||||||
public class FileUploadRecordAddOrEdit
|
|
||||||
{
|
|
||||||
public Guid? Id { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
public long FileSize { get; set; }
|
|
||||||
|
|
||||||
public string FileType { get; set; }
|
|
||||||
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string UploadBatchId { get; set; }
|
|
||||||
public BatchDataType BatchDataType { get; set; }
|
|
||||||
|
|
||||||
public string StudyCode { get; set; }
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectVisitId { get; set; }
|
|
||||||
|
|
||||||
public Guid? DicomStudyId { get; set; }
|
|
||||||
|
|
||||||
public Guid? NoneDicomStudyId { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public string FileMarkId { get; set; }
|
|
||||||
|
|
||||||
public int? Priority { get; set; }
|
|
||||||
public string IP { get; set; }
|
|
||||||
public bool? IsNeedSync { get; set; }
|
|
||||||
public string UploadRegion { get; set; }
|
|
||||||
public string TargetRegion { get; set; }
|
|
||||||
|
|
||||||
public bool? IsSync { get; set; }
|
|
||||||
}
|
|
||||||
public interface IFileUploadRecordService
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
Task<IResponseOutput> AddOrUpdateFileUploadRecord(FileUploadRecordAddOrEdit addOrEditFileUploadRecord);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
|
||||||
public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRecordRepository,
|
|
||||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IOptionsMonitor<ObjectStoreServiceOptions> options,
|
|
||||||
IFusionCache _fusionCache, IRepository<Trial> _trialRepository, FileSyncQueue _fileSyncQueue) : BaseService, IFileUploadRecordService
|
|
||||||
{
|
|
||||||
|
|
||||||
ObjectStoreServiceOptions ObjectStoreServiceConfig = options.CurrentValue;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<IResponseOutput> AddOrUpdateFileUploadRecord(FileUploadRecordAddOrEdit addOrEditFileUploadRecord)
|
|
||||||
{
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IP = _userInfo.IP;
|
|
||||||
|
|
||||||
if (ObjectStoreServiceConfig.IsOpenStoreSync && _userInfo.Domain.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
var find = ObjectStoreServiceConfig.SyncConfigList.FirstOrDefault(t => t.Domain == _userInfo.Domain);
|
|
||||||
if (find != null)
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.UploadRegion = find.UploadRegion;
|
|
||||||
addOrEditFileUploadRecord.TargetRegion = find.TargetRegion;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//前后端调试的时候,上传的时候域名不对应,自动按照后端配置设置上传区域和同步区域
|
|
||||||
var apiDefalut = ObjectStoreServiceConfig.SyncConfigList.FirstOrDefault(t => t.UploadRegion == ObjectStoreServiceConfig.ApiDeployRegion);
|
|
||||||
|
|
||||||
if (apiDefalut != null)
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.UploadRegion = apiDefalut.UploadRegion;
|
|
||||||
addOrEditFileUploadRecord.TargetRegion = apiDefalut.TargetRegion;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//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)
|
|
||||||
{
|
|
||||||
|
|
||||||
var trialDataStore = await _fusionCache.GetOrSetAsync(CacheKeys.TrialDataStoreType(addOrEditFileUploadRecord.TrialId.Value), async _ =>
|
|
||||||
{
|
|
||||||
return await _trialRepository.Where(t => t.Id == addOrEditFileUploadRecord.TrialId).Select(t => t.TrialDataStoreType)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
},
|
|
||||||
TimeSpan.FromDays(7)
|
|
||||||
);
|
|
||||||
|
|
||||||
//项目配置了,那么就设置需要同步
|
|
||||||
if (trialDataStore == TrialDataStore.MUtiCenter)
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = true;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority ?? 0;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IsSync = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = false;
|
|
||||||
|
|
||||||
//addOrEditFileUploadRecord.TargetRegion = "";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//系统文件,默认同步
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = true;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IsSync = false;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = await _fileUploadRecordRepository.InsertOrUpdateAsync(addOrEditFileUploadRecord, true);
|
|
||||||
|
|
||||||
if (addOrEditFileUploadRecord.IsNeedSync == true)
|
|
||||||
{
|
|
||||||
_fileSyncQueue.Enqueue(entity.Id, addOrEditFileUploadRecord.Priority ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(entity.Id.ToString());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public sealed class FileSyncQueue
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 优先级队列(仅负责排序)
|
|
||||||
/// </summary>
|
|
||||||
private readonly PriorityQueue<Guid, int> _queue = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前等待中的任务(唯一真实数据)
|
|
||||||
/// key = Guid
|
|
||||||
/// value = 最新 priority
|
|
||||||
/// </summary>
|
|
||||||
private readonly Dictionary<Guid, int> _waiting = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 正在执行的任务(防止重复执行)
|
|
||||||
/// </summary>
|
|
||||||
private readonly HashSet<Guid> _running = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// worker 等待信号
|
|
||||||
/// </summary>
|
|
||||||
private readonly SemaphoreSlim _signal = new(0);
|
|
||||||
|
|
||||||
|
|
||||||
private readonly object _lock = new();
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Enqueue
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 入队(同 Guid 会覆盖优先级)
|
|
||||||
/// </summary>
|
|
||||||
public void Enqueue(Guid id, int priority)
|
|
||||||
{
|
|
||||||
bool needSignal = false;
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
// 如果正在执行,忽略(防止重复)
|
|
||||||
if (_running.Contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 是否新任务(用于减少 signal 风暴)
|
|
||||||
if (!_waiting.ContainsKey(id))
|
|
||||||
needSignal = true;
|
|
||||||
|
|
||||||
// 更新为最新优先级(最后一次为准)
|
|
||||||
_waiting[id] = priority; //等价于添加或者更新
|
|
||||||
|
|
||||||
// PriorityQueue 无法更新节点
|
|
||||||
// 允许旧节点存在,Dequeue 时过滤
|
|
||||||
_queue.Enqueue(id, -priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只有新增任务才唤醒 worker
|
|
||||||
if (needSignal)
|
|
||||||
_signal.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Dequeue
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取一个待执行任务(无任务时自动等待)
|
|
||||||
/// </summary>
|
|
||||||
public async Task<Guid> DequeueAsync(CancellationToken ct)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await _signal.WaitAsync(ct);
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
while (_queue.Count > 0)
|
|
||||||
{
|
|
||||||
var id = _queue.Dequeue();
|
|
||||||
|
|
||||||
// 已被覆盖或取消
|
|
||||||
if (!_waiting.TryGetValue(id, out _))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// 标记为运行中
|
|
||||||
_waiting.Remove(id);
|
|
||||||
_running.Add(id);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Complete
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 任务执行完成(必须调用)
|
|
||||||
/// </summary>
|
|
||||||
public void Complete(Guid id)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_running.Remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Snapshot
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前等待中的任务快照
|
|
||||||
/// </summary>
|
|
||||||
public Guid[] Snapshot()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
return _waiting.Keys.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// 状态信息(调试用)
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
public int WaitingCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
return _waiting.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RunningCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
return _running.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+105
-1432
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
|
|
||||||
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
|
|
||||||
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
|
|
||||||
"BucketName": "tl-med-irc-event-store",
|
|
||||||
"ViewEndpoint": "https://tl-med-irc-event-store.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=101.132.253.119,1435;Database=irc_Prpd_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=101.132.253.119,1435;Database=irc_Hangfire_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
|
|
||||||
"DicomSCPServiceConfig": {
|
|
||||||
"CalledAEList": [
|
|
||||||
"STORESCP"
|
|
||||||
],
|
|
||||||
"ServerPort": 11112
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -8,26 +8,6 @@
|
|||||||
},
|
},
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
"IsOpenStoreSync": true,
|
|
||||||
"ApiDeployRegion": "CN",
|
|
||||||
"SyncConfigList": [
|
|
||||||
{
|
|
||||||
"Domain": "irc.extimaging.com",
|
|
||||||
"Primary": "AliyunOSS",
|
|
||||||
"Target": "AWS",
|
|
||||||
"UploadRegion": "CN",
|
|
||||||
"TargetRegion": "US",
|
|
||||||
"IsOpenSync": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Domain": "eiirc.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",
|
||||||
@@ -39,18 +19,6 @@
|
|||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"Region": "oss-cn-shanghai",
|
||||||
"DurationSeconds": 7200
|
"DurationSeconds": 7200
|
||||||
},
|
|
||||||
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
|
||||||
"BucketName": "ei-med-s3-irc-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-irc-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -7,28 +7,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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",
|
||||||
@@ -50,27 +29,6 @@
|
|||||||
"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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,38 +8,6 @@
|
|||||||
},
|
},
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AWS",
|
"ObjectStoreUse": "AWS",
|
||||||
"IsOpenStoreSync": true,
|
|
||||||
"ApiDeployRegion": "US",
|
|
||||||
"SyncConfigList": [
|
|
||||||
{
|
|
||||||
"Domain": "eilili.elevateimaging.ai",
|
|
||||||
"Primary": "AliyunOSS",
|
|
||||||
"Target": "AWS",
|
|
||||||
"UploadRegion": "CN",
|
|
||||||
"TargetRegion": "US",
|
|
||||||
"IsOpenSync": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Domain": "lili.elevateimaging.ai",
|
|
||||||
"Primary": "AWS",
|
|
||||||
"Target": "AliyunOSS",
|
|
||||||
"UploadRegion": "US",
|
|
||||||
"TargetRegion": "CN",
|
|
||||||
"IsOpenSync": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-lili-store",
|
|
||||||
"ViewEndpoint": "https://zy-lili-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"Region": "us-east-1",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||||
|
|||||||
@@ -8,58 +8,17 @@
|
|||||||
},
|
},
|
||||||
"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",
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
|
||||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
|
||||||
"BucketName": "zy-irc-test-store",
|
"BucketName": "tl-med-irc-uat-store",
|
||||||
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
"ViewEndpoint": "https://tl-med-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
"Region": "oss-cn-shanghai",
|
"Region": "oss-cn-shanghai",
|
||||||
"DurationSeconds": 7200
|
"DurationSeconds": 7200
|
||||||
},
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ using Microsoft.Extensions.Options;
|
|||||||
using Org.BouncyCastle.Tls;
|
using Org.BouncyCastle.Tls;
|
||||||
using RestSharp;
|
using RestSharp;
|
||||||
using RestSharp.Authenticators;
|
using RestSharp.Authenticators;
|
||||||
using Serilog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -127,7 +126,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
var token = _tokenService.GetToken(new UserTokenInfo()
|
var token = _tokenService.GetToken(new UserTokenInfo()
|
||||||
{
|
{
|
||||||
IdentityUserId = Guid.NewGuid(),
|
IdentityUserId = Guid.NewGuid(),
|
||||||
UserName = "ImageShare",
|
UserName = "Share001",
|
||||||
UserTypeEnum = UserTypeEnum.ShareImage,
|
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -138,14 +137,9 @@ namespace IRaCIS.Api.Controllers
|
|||||||
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
public async Task<IResponseOutput> GetObjectStoreTokenAsync([FromServices] IOptionsMonitor<ObjectStoreServiceOptions> options, [FromServices] IOSSService _oSSService)
|
||||||
{
|
{
|
||||||
|
|
||||||
var domain = HttpContext.Request.Host.Host;
|
var result = _oSSService.GetObjectStoreTempToken();
|
||||||
|
|
||||||
|
//result.AWS = await GetAWSTemToken(options.CurrentValue);
|
||||||
var result = _oSSService.GetObjectStoreTempToken(domain);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Log.Logger.Information($"使用域名:{domain}请求token.返回{result.ToJsonStr()}");
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(result);
|
return ResponseOutput.Ok(result);
|
||||||
|
|
||||||
@@ -285,7 +279,7 @@ namespace IRaCIS.Api.Controllers
|
|||||||
|
|
||||||
var isExpire = _tokenService.IsTokenExpired(token);
|
var isExpire = _tokenService.IsTokenExpired(token);
|
||||||
|
|
||||||
if ( Guid.TryParse(userId,out _) == false || isExpire || !await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd) )
|
if (!await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd) || isExpire)
|
||||||
{
|
{
|
||||||
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(I18n.T("UserRedirect_InitializationLinkExpire"))} ";
|
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(I18n.T("UserRedirect_InitializationLinkExpire"))} ";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
ITrialDocumentService _trialDocumentService,
|
ITrialDocumentService _trialDocumentService,
|
||||||
IReadingImageTaskService _iReadingImageTaskService,
|
IReadingImageTaskService _iReadingImageTaskService,
|
||||||
ITrialConfigService _trialConfigService,
|
ITrialConfigService _trialConfigService,
|
||||||
IStudyService _studyService,
|
|
||||||
IClinicalAnswerService _clinicalAnswerService,
|
IClinicalAnswerService _clinicalAnswerService,
|
||||||
IReadingClinicalDataService _readingClinicalDataService,
|
IReadingClinicalDataService _readingClinicalDataService,
|
||||||
IQCOperationService _qCOperationService,
|
IQCOperationService _qCOperationService,
|
||||||
@@ -147,26 +146,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 修正患者基本信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="opt"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost, Route("Inspection/Study/AmendmentPatientInfo")]
|
|
||||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
|
||||||
|
|
||||||
[UnitOfWork]
|
|
||||||
public async Task<IResponseOutput> AmendmentPatientInfo(DataInspectionDto<EditPatientInfoCommand> opt)
|
|
||||||
{
|
|
||||||
|
|
||||||
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
|
||||||
var result = await _studyService.AmendmentPatientInfo(opt.Data);
|
|
||||||
await _inspectionService.CompletedSign(singid, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 医学审核完成
|
/// 医学审核完成
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -176,19 +155,10 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||||
|
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
public async Task<IResponseOutput> FinishMedicalReview(DataInspectionDto<CloseAndFinishMedicalReview> opt)
|
public async Task<IResponseOutput> FinishMedicalReview(DataInspectionDto<FinishMedicalReviewInDto> opt)
|
||||||
{
|
{
|
||||||
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||||
|
var result = await _readingMedicalReviewService.FinishMedicalReview(opt.Data);
|
||||||
await _readingMedicalReviewService.ClosedMedicalReviewDialog(new ClosedMedicalReviewDialogInDto() {
|
|
||||||
DialogCloseReason=opt.Data.DialogCloseReason,
|
|
||||||
IsClosedDialog=opt.Data.IsClosedDialog,
|
|
||||||
MedicalDialogCloseEnum=opt.Data.MedicalDialogCloseEnum,
|
|
||||||
TaskMedicalReviewId=opt.Data.TaskMedicalReviewId
|
|
||||||
});
|
|
||||||
var result = await _readingMedicalReviewService.FinishMedicalReview(new FinishMedicalReviewInDto() {
|
|
||||||
TaskMedicalReviewId=opt.Data.TaskMedicalReviewId
|
|
||||||
});
|
|
||||||
await _inspectionService.CompletedSign(singid, result);
|
await _inspectionService.CompletedSign(singid, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using IRaCIS.Core.Application.Filter;
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
using IRaCIS.Core.Application.MassTransit.Command;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Core.Application.Service;
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
@@ -569,7 +568,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
/// 一致性核查 excel上传 支持三种格式
|
/// 一致性核查 excel上传 支持三种格式
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="trialId"></param>
|
/// <param name="trialId"></param>
|
||||||
/// <param name="isFullCheck"></param>
|
|
||||||
/// <param name="oSSService"></param>
|
/// <param name="oSSService"></param>
|
||||||
/// <param name="_inspectionFileRepository"></param>
|
/// <param name="_inspectionFileRepository"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -577,14 +575,12 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
|
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
|
||||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||||
|
|
||||||
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, bool isFullCheck, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||||
{
|
{
|
||||||
|
|
||||||
var fileName = string.Empty;
|
var fileName = string.Empty;
|
||||||
var templateFileStream = new MemoryStream();
|
var templateFileStream = new MemoryStream();
|
||||||
|
|
||||||
var inspectionFileId = Guid.Empty;
|
|
||||||
|
|
||||||
await FileUploadToOSSAsync(async (realFileName, fileStream) =>
|
await FileUploadToOSSAsync(async (realFileName, fileStream) =>
|
||||||
{
|
{
|
||||||
fileName = realFileName;
|
fileName = realFileName;
|
||||||
@@ -599,11 +595,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
templateFileStream.Seek(0, SeekOrigin.Begin);
|
templateFileStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
|
||||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DataReconciliation });
|
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName);
|
||||||
|
|
||||||
var addEntity = await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||||
|
|
||||||
inspectionFileId = addEntity.Id;
|
|
||||||
|
|
||||||
return ossRelativePath;
|
return ossRelativePath;
|
||||||
|
|
||||||
@@ -749,11 +743,8 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
if (etcCheckList == null || etcCheckList.Count == 0)
|
if (etcCheckList == null || etcCheckList.Count == 0)
|
||||||
{
|
{
|
||||||
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Failed });
|
|
||||||
|
|
||||||
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
||||||
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -773,8 +764,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
if (etcCheckList.Count == 0)
|
if (etcCheckList.Count == 0)
|
||||||
{
|
{
|
||||||
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Failed });
|
|
||||||
|
|
||||||
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
||||||
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
||||||
}
|
}
|
||||||
@@ -786,19 +775,8 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
|
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
|
||||||
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
||||||
|
|
||||||
if (isFullCheck)
|
//不获取结果,不用定义返回类型
|
||||||
{
|
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
||||||
await _mediator.Send(new ConsistenFullCheckCommand() { ETCList = etcCheckList, TrialId = trialId, InspectionFileId = inspectionFileId });
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
//不获取结果,不用定义返回类型
|
|
||||||
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
return ResponseOutput.Ok();
|
||||||
|
|
||||||
@@ -857,7 +835,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_TemplateUploadData"]);
|
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_TemplateUploadData"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/SiteSurvey", realFileName, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.SiteUserSurvey });
|
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/SiteSurvey", realFileName);
|
||||||
|
|
||||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||||
|
|
||||||
@@ -933,7 +911,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
//处理好 用户类型 和用户类型枚举
|
//处理好 用户类型 和用户类型枚举
|
||||||
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
|
var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
|
||||||
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, TrialSiteId = t.Id, t.Country }).ToList();
|
var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, TrialSiteId = t.Id }).ToList();
|
||||||
|
|
||||||
foreach (var item in excelList)
|
foreach (var item in excelList)
|
||||||
{
|
{
|
||||||
@@ -955,8 +933,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.Trim().ToUpper() == item.TrialSiteCode.Trim().ToUpper()).TrialSiteId;
|
item.TrialSiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.Trim().ToUpper() == item.TrialSiteCode.Trim().ToUpper()).TrialSiteId;
|
||||||
|
|
||||||
item.Country = siteList.FirstOrDefault(t => t.TrialSiteCode.Trim().ToUpper() == item.TrialSiteCode.Trim().ToUpper()).Country;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = excelList.Where(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.CRA).ToList();
|
var list = excelList.Where(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.CRA).ToList();
|
||||||
@@ -1007,11 +983,7 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
|
|
||||||
EmailBodyHtml = 4,
|
EmailBodyHtml = 4,
|
||||||
|
|
||||||
ReadKeyFile = 5,
|
Other = 5
|
||||||
|
|
||||||
Other = 6,
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1043,9 +1015,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||||||
case UploadFileType.EmailBodyHtml:
|
case UploadFileType.EmailBodyHtml:
|
||||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
|
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
|
||||||
break;
|
break;
|
||||||
case UploadFileType.ReadKeyFile:
|
|
||||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.ReadKetFile, fileName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));
|
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));
|
||||||
|
|||||||
@@ -15,13 +15,12 @@ using Hangfire.Storage;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using MassTransit.Mediator;
|
using MassTransit.Mediator;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API.HostService;
|
namespace IRaCIS.Core.API.HostService;
|
||||||
|
|
||||||
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
|
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
|
||||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
||||||
IConfiguration _config,
|
|
||||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||||
IMediator _mediator,
|
IMediator _mediator,
|
||||||
ILogger<HangfireHostService> _logger) : IHostedService
|
ILogger<HangfireHostService> _logger) : IHostedService
|
||||||
@@ -57,9 +56,7 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string defaultCulture = _config.GetValue<string>("SystemEmailSendConfig:CronEmailDefaultCulture");
|
|
||||||
|
|
||||||
// 项目手动选择,周期性邮件
|
|
||||||
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
|
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, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
|
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -71,11 +68,11 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||||||
|
|
||||||
var trialId = task.TrialId;
|
var trialId = task.TrialId;
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, trialId, task.BusinessScenarioEnum, task.EmailCron, defaultCulture);
|
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, trialId, task.BusinessScenarioEnum, task.EmailCron);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 系统邮件定时任务 要设置默认语言
|
// 系统邮件定时任务
|
||||||
var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend)
|
var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend)
|
||||||
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, })
|
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, })
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@@ -85,7 +82,7 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||||||
//利用主键作为任务Id
|
//利用主键作为任务Id
|
||||||
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
|
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron, defaultCulture);
|
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
using IRaCIS.Core.Application.Service;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API.HostService;
|
|
||||||
|
|
||||||
|
|
||||||
public class SyncFileRecoveryService(IServiceScopeFactory _scopeFactory, FileSyncQueue _fileSyncQueue) : BackgroundService
|
|
||||||
{
|
|
||||||
|
|
||||||
private readonly int _pageSize = 500;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 多个程序,如果恢复同一份数据,造成重复同步,SCP服务不恢复任务
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="stoppingToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
//在本地调试的时候,不干涉部署同步任务
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var scope = _scopeFactory.CreateScope();
|
|
||||||
var fileUploadRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<FileUploadRecord>>();
|
|
||||||
|
|
||||||
// 延迟启动,保证主机快速启动
|
|
||||||
await Task.Delay(5000, stoppingToken);
|
|
||||||
|
|
||||||
int page = 0;
|
|
||||||
|
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// 分页获取未入队任务
|
|
||||||
var pending = await fileUploadRecordRepository
|
|
||||||
.Where(x => x.IsNeedSync == true && (x.IsSync == false || x.IsSync == null))
|
|
||||||
.OrderByDescending(x => x.Priority)
|
|
||||||
.Select(t => new { t.Id, t.Priority })
|
|
||||||
.Skip(page * _pageSize)
|
|
||||||
.Take(_pageSize)
|
|
||||||
.ToListAsync(stoppingToken);
|
|
||||||
|
|
||||||
if (!pending.Any())
|
|
||||||
break; // 扫描完毕,退出循环
|
|
||||||
|
|
||||||
foreach (var file in pending)
|
|
||||||
{
|
|
||||||
//file.IsQueued = true; // 避免重复入队
|
|
||||||
_fileSyncQueue.Enqueue(file.Id, file.Priority ?? 0); // 放入队列
|
|
||||||
}
|
|
||||||
|
|
||||||
page++; // 下一页
|
|
||||||
await Task.Delay(200, stoppingToken); // 缓解数据库压力
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FileSyncWorker(IServiceScopeFactory _scopeFactory, ILogger<FileSyncWorker> _logger, FileSyncQueue _fileSyncQueue) : BackgroundService
|
|
||||||
{
|
|
||||||
|
|
||||||
// ⭐ 自动根据服务器CPU
|
|
||||||
private readonly int _workerCount = Math.Max(1, Environment.ProcessorCount - 1);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override Task ExecuteAsync(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _workerCount; i++)
|
|
||||||
Task.Run(() => WorkerLoop(stoppingToken));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task WorkerLoop(CancellationToken stoppingToken)
|
|
||||||
{
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
var id = await _fileSyncQueue.DequeueAsync(stoppingToken);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var scope = _scopeFactory.CreateScope();
|
|
||||||
var _fileUploadRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<FileUploadRecord>>();
|
|
||||||
var _uploadFileSyncRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<UploadFileSyncRecord>>();
|
|
||||||
|
|
||||||
var syncConfig = (scope.ServiceProvider.GetRequiredService<IOptionsMonitor<ObjectStoreServiceOptions>>()).CurrentValue;
|
|
||||||
|
|
||||||
var oss = scope.ServiceProvider.GetRequiredService<IOSSService>();
|
|
||||||
|
|
||||||
var file = await _fileUploadRecordRepository.FirstOrDefaultAsync(t => t.Id == id);
|
|
||||||
|
|
||||||
// ✅ 不要 return
|
|
||||||
if (file == null || file.IsNeedSync != true || syncConfig.IsOpenStoreSync == false)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncConfig.SyncConfigList.Any(t => t.UploadRegion == file.UploadRegion && t.IsOpenSync == false))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//如果发现系统配置某一边同步进行了关闭,那么就直接返回,不执行任务
|
|
||||||
if (syncConfig.SyncConfigList.Any(t => t.UploadRegion == file.UploadRegion && t.IsOpenSync == false))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var log = new UploadFileSyncRecord
|
|
||||||
{
|
|
||||||
FileUploadRecordId = id,
|
|
||||||
StartTime = DateTime.Now,
|
|
||||||
JobState = jobState.RUNNING
|
|
||||||
};
|
|
||||||
|
|
||||||
await _uploadFileSyncRecordRepository.AddAsync(log);
|
|
||||||
await _uploadFileSyncRecordRepository.SaveChangesAsync(stoppingToken);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await oss.SyncFileAsync(file.Path.TrimStart('/'), file.UploadRegion == "CN" ? ObjectStoreUse.AliyunOSS : ObjectStoreUse.AWS, file.UploadRegion == "CN" ? ObjectStoreUse.AWS : ObjectStoreUse.AliyunOSS);
|
|
||||||
|
|
||||||
file.IsSync = true;
|
|
||||||
file.SyncFinishedTime = DateTime.Now;
|
|
||||||
|
|
||||||
log.JobState = jobState.SUCCESS;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.JobState = jobState.FAILED;
|
|
||||||
|
|
||||||
log.Msg = ex.Message.Length > 300 ? ex.Message.Substring(0, 300) : ex.Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.EndTime = DateTime.Now;
|
|
||||||
|
|
||||||
await _uploadFileSyncRecordRepository.SaveChangesAsync(stoppingToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Sync failed {Id}", id);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// ⭐⭐⭐ 永远执行
|
|
||||||
_fileSyncQueue.Complete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -136,14 +136,7 @@
|
|||||||
<param name="opt"></param>
|
<param name="opt"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.AmendmentPatientInfo(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.EditPatientInfoCommand})">
|
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.FinishMedicalReview(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.FinishMedicalReviewInDto})">
|
||||||
<summary>
|
|
||||||
修正患者基本信息
|
|
||||||
</summary>
|
|
||||||
<param name="opt"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.FinishMedicalReview(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.CloseAndFinishMedicalReview})">
|
|
||||||
<summary>
|
<summary>
|
||||||
医学审核完成
|
医学审核完成
|
||||||
</summary>
|
</summary>
|
||||||
@@ -325,12 +318,11 @@
|
|||||||
<param name="_noneDicomStudyFileRepository"></param>
|
<param name="_noneDicomStudyFileRepository"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,System.Boolean,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
|
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitCheckExcel(System.Guid,IRaCIS.Core.Application.Helper.IOSSService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.InspectionFile})">
|
||||||
<summary>
|
<summary>
|
||||||
一致性核查 excel上传 支持三种格式
|
一致性核查 excel上传 支持三种格式
|
||||||
</summary>
|
</summary>
|
||||||
<param name="trialId"></param>
|
<param name="trialId"></param>
|
||||||
<param name="isFullCheck"></param>
|
|
||||||
<param name="oSSService"></param>
|
<param name="oSSService"></param>
|
||||||
<param name="_inspectionFileRepository"></param>
|
<param name="_inspectionFileRepository"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
@@ -351,13 +343,6 @@
|
|||||||
</summary>
|
</summary>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.API.HostService.SyncFileRecoveryService.ExecuteAsync(System.Threading.CancellationToken)">
|
|
||||||
<summary>
|
|
||||||
多个程序,如果恢复同一份数据,造成重复同步,SCP服务不恢复任务
|
|
||||||
</summary>
|
|
||||||
<param name="stoppingToken"></param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
|
<member name="T:IRaCIS.Core.API.IpPolicyRateLimitSetup">
|
||||||
<summary>
|
<summary>
|
||||||
IPLimit限流 启动服务
|
IPLimit限流 启动服务
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using FellowOakDicom;
|
using IRaCIS.Core.API;
|
||||||
using IRaCIS.Core.API;
|
|
||||||
using IRaCIS.Core.API.HostService;
|
using IRaCIS.Core.API.HostService;
|
||||||
using IRaCIS.Core.Application.BusinessFilter;
|
using IRaCIS.Core.Application.BusinessFilter;
|
||||||
using IRaCIS.Core.Application.BusinessFilter.LegacyController.Database.Api;
|
|
||||||
using IRaCIS.Core.Application.Filter;
|
using IRaCIS.Core.Application.Filter;
|
||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
using IRaCIS.Core.Application.Service;
|
using IRaCIS.Core.Application.Service;
|
||||||
@@ -15,7 +13,6 @@ using Microsoft.AspNetCore.Builder;
|
|||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
@@ -24,7 +21,6 @@ using Newtonsoft.Json;
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -32,10 +28,6 @@ using System.Runtime.InteropServices;
|
|||||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine("Startup Culture: " + CultureInfo.CurrentCulture.Name);
|
|
||||||
Console.WriteLine("Startup UI Culture: " + CultureInfo.CurrentUICulture.Name);
|
|
||||||
|
|
||||||
#region 获取环境变量
|
#region 获取环境变量
|
||||||
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||||||
var config = new ConfigurationBuilder()
|
var config = new ConfigurationBuilder()
|
||||||
@@ -65,8 +57,7 @@ SerilogExtension.AddSerilogSetup(enviromentName);
|
|||||||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
||||||
{
|
{
|
||||||
|
|
||||||
EnvironmentName = enviromentName,
|
EnvironmentName = enviromentName
|
||||||
Args = args
|
|
||||||
});
|
});
|
||||||
|
|
||||||
#region 主机配置
|
#region 主机配置
|
||||||
@@ -91,10 +82,6 @@ builder.Services.ConfigureServices(_configuration);
|
|||||||
|
|
||||||
builder.Services.AddHostedService<HangfireHostService>();
|
builder.Services.AddHostedService<HangfireHostService>();
|
||||||
|
|
||||||
builder.Services.AddSingleton<FileSyncQueue>();
|
|
||||||
builder.Services.AddHostedService<SyncFileRecoveryService>();
|
|
||||||
builder.Services.AddHostedService<FileSyncWorker>();
|
|
||||||
|
|
||||||
//minimal api 异常处理
|
//minimal api 异常处理
|
||||||
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
|
||||||
//builder.Services.AddProblemDetails();
|
//builder.Services.AddProblemDetails();
|
||||||
@@ -108,18 +95,11 @@ builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resourc
|
|||||||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||||
builder.Services.AddControllers(options =>
|
builder.Services.AddControllers(options =>
|
||||||
{
|
{
|
||||||
// 关键配置:禁用不可空引用类型的自动 Required 验证
|
|
||||||
options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
|
|
||||||
|
|
||||||
// 插到最前,抢在默认绑定器之前
|
|
||||||
//options.ModelBinderProviders.Insert(0, new SpecificNullableBinderProvider());
|
|
||||||
|
|
||||||
options.Filters.Add<ModelActionFilter>();
|
options.Filters.Add<ModelActionFilter>();
|
||||||
options.Filters.Add<ProjectExceptionFilter>();
|
options.Filters.Add<ProjectExceptionFilter>();
|
||||||
options.Filters.Add<UnitOfWorkFilter>();
|
options.Filters.Add<UnitOfWorkFilter>();
|
||||||
options.Filters.Add<LimitUserRequestAuthorization>();
|
options.Filters.Add<LimitUserRequestAuthorization>();
|
||||||
options.Filters.Add<TrialGlobalLimitActionFilter>();
|
options.Filters.Add<TrialGlobalLimitActionFilter>();
|
||||||
options.Filters.Add<RequestDuplicationFilter>();
|
|
||||||
|
|
||||||
})
|
})
|
||||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||||
@@ -180,7 +160,6 @@ var env = app.Environment;
|
|||||||
|
|
||||||
#region 配置中间件
|
#region 配置中间件
|
||||||
|
|
||||||
DicomSetupBuilder.UseServiceProvider(app.Services);
|
|
||||||
|
|
||||||
app.UseMiddleware<EncryptionRequestMiddleware>();
|
app.UseMiddleware<EncryptionRequestMiddleware>();
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://0.0.0.0:3305",
|
"applicationUrl": "http://localhost:3305",
|
||||||
"sslPort": 0
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC",
|
"ASPNETCORE_ENVIRONMENT": "Test_IRC",
|
||||||
"ASPNETCORE_OpenSwagger": "true"
|
"ASPNETCORE_OpenSwagger": "true"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Test_IRC_PGSQL": {
|
"IRaCIS.Test_IRC_PGSQL": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@@ -31,15 +31,15 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
|
"ASPNETCORE_ENVIRONMENT": "Test_IRC_PGSQL"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Prod_Event_IRC": {
|
"IRaCIS.Event_IRC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Prod_Event_IRC"
|
"ASPNETCORE_ENVIRONMENT": "Event_IRC"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"Docker": {
|
"Docker": {
|
||||||
"commandName": "Docker",
|
"commandName": "Docker",
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Uat_IRC"
|
"ASPNETCORE_ENVIRONMENT": "Uat_IRC"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.Prod_IRC": {
|
"IRaCIS.Prod_IRC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Prod_IRC"
|
"ASPNETCORE_ENVIRONMENT": "Prod_IRC"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.US_Uat_IRC": {
|
"IRaCIS.US_Uat_IRC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "US_Uat_IRC"
|
"ASPNETCORE_ENVIRONMENT": "US_Uat_IRC"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
},
|
},
|
||||||
"IRaCIS.US_Prod_IRC": {
|
"IRaCIS.US_Prod_IRC": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "US_Prod_IRC"
|
"ASPNETCORE_ENVIRONMENT": "US_Prod_IRC"
|
||||||
},
|
},
|
||||||
"applicationUrl": "http://0.0.0.0:6100"
|
"applicationUrl": "http://localhost:6100"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ namespace IRaCIS.Core.API._PipelineExtensions.Serilog
|
|||||||
|
|
||||||
var requestBodyPayload = await ReadRequestBody(context.Request);
|
var requestBodyPayload = await ReadRequestBody(context.Request);
|
||||||
|
|
||||||
context.Items["RequestBody"] = requestBodyPayload;
|
|
||||||
|
|
||||||
using (LogContext.PushProperty("RequestBody", requestBodyPayload))
|
using (LogContext.PushProperty("RequestBody", requestBodyPayload))
|
||||||
{
|
{
|
||||||
//await _next.Invoke()
|
//await _next.Invoke()
|
||||||
|
|||||||
@@ -8,21 +8,13 @@ namespace IRaCIS.Core.API
|
|||||||
{
|
{
|
||||||
public static void AddDicomSetup(this IServiceCollection services)
|
public static void AddDicomSetup(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
|
||||||
// ⭐ 先做全局 DICOM 配置
|
|
||||||
new DicomSetupBuilder()
|
new DicomSetupBuilder()
|
||||||
.SkipValidation() // 👈 在这里设置
|
.RegisterServices(s => s.AddFellowOakDicom()
|
||||||
.Build();
|
.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||||
|
.AddImageManager<ImageSharpImageManager>()
|
||||||
services.AddFellowOakDicom().AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>().AddImageManager<ImageSharpImageManager>();
|
)
|
||||||
|
.SkipValidation()
|
||||||
// new DicomSetupBuilder()
|
.Build();
|
||||||
// .RegisterServices(s => s.AddFellowOakDicom()
|
|
||||||
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
|
||||||
// .AddImageManager<ImageSharpImageManager>()
|
|
||||||
// )
|
|
||||||
// .SkipValidation()
|
|
||||||
// .Build();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ namespace IRaCIS.Core.API
|
|||||||
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value;
|
var dbType = configuration.GetSection("ConnectionStrings:Db_Type").Value;
|
||||||
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
|
if (!string.IsNullOrWhiteSpace(dbType) && dbType == "pgsql")
|
||||||
{
|
{
|
||||||
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure().CommandTimeout(90));
|
options.UseNpgsql(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure().CommandTimeout(90));
|
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value, contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -71,27 +71,29 @@ namespace IRaCIS.Core.API
|
|||||||
|
|
||||||
DateTime dateTime;
|
DateTime dateTime;
|
||||||
|
|
||||||
// 2. 检查目标类型是否可空
|
if (reader.ValueType == typeof(DateTime) || reader.ValueType == typeof(DateTime?))
|
||||||
bool isNullable = objectType == typeof(DateTime?);
|
|
||||||
|
|
||||||
var canConvert = DateTime.TryParse(reader.Value?.ToString(), out dateTime);
|
|
||||||
|
|
||||||
|
|
||||||
if (isNullable == false && canConvert == false)
|
|
||||||
{
|
{
|
||||||
|
DateTime? nullableDateTime = reader.Value as DateTime?;
|
||||||
|
|
||||||
throw new JsonSerializationException($"Could not convert string to DateTime: {reader.Value} Path {reader.Path}");
|
|
||||||
|
if (nullableDateTime != null && nullableDateTime.HasValue)
|
||||||
|
{
|
||||||
|
dateTime = nullableDateTime.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (canConvert == false)
|
if (DateTime.TryParse((string)reader.Value, out dateTime) == false)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////如果前端传递带时区的,那么转换会报错,需要DateTimeKind.Unspecified
|
|
||||||
//dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
|
|
||||||
|
|
||||||
// 将客户端时间转换为服务器时区的时间
|
// 将客户端时间转换为服务器时区的时间
|
||||||
var serverZoneTime = TimeZoneInfo.ConvertTime(dateTime, _clientTimeZone, TimeZoneInfo.Local);
|
var serverZoneTime = TimeZoneInfo.ConvertTime(dateTime, _clientTimeZone, TimeZoneInfo.Local);
|
||||||
@@ -111,10 +113,7 @@ namespace IRaCIS.Core.API
|
|||||||
//第一个参数默认使用系统本地时区 也就是应用服务器的时区
|
//第一个参数默认使用系统本地时区 也就是应用服务器的时区
|
||||||
DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone);
|
DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone);
|
||||||
|
|
||||||
|
//writer.WriteValue(clientZoneTime);
|
||||||
//// 最简单的方式:创建 DateTimeOffset
|
|
||||||
//DateTimeOffset dateTimeOffset = new DateTimeOffset(clientZoneTime, _clientTimeZone.GetUtcOffset(clientZoneTime));
|
|
||||||
//writer.WriteValue(dateTimeOffset.ToString("yyyy-MM-dd HH:mm:sszzz"));
|
|
||||||
|
|
||||||
writer.WriteValue(clientZoneTime.ToString(_dateFormat));
|
writer.WriteValue(clientZoneTime.ToString(_dateFormat));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ using Newtonsoft.Json;
|
|||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.API
|
namespace IRaCIS.Core.API
|
||||||
{
|
{
|
||||||
@@ -53,90 +51,34 @@ namespace IRaCIS.Core.API
|
|||||||
}
|
}
|
||||||
public class NullToEmptyStringValueProvider : IValueProvider
|
public class NullToEmptyStringValueProvider : IValueProvider
|
||||||
{
|
{
|
||||||
PropertyInfo _memberInfo;
|
PropertyInfo _MemberInfo;
|
||||||
private readonly bool _isNullable;
|
|
||||||
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
||||||
{
|
{
|
||||||
_memberInfo = memberInfo;
|
_MemberInfo = memberInfo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// DTO → JSON 返回前端的时候 处理null 变为"" 方便前端判断
|
|
||||||
public object GetValue(object target)
|
public object GetValue(object target)
|
||||||
{
|
{
|
||||||
var result = _memberInfo.GetValue(target);
|
object result = _MemberInfo.GetValue(target);
|
||||||
// 检查类型是否为string或string?
|
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
|
||||||
if (_memberInfo.PropertyType == typeof(string) && result == null)
|
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
|
||||||
{
|
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
|
||||||
|
//else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
|
||||||
|
|
||||||
#region 返回的时候处理 string string? null 为"" 不区分处理
|
|
||||||
|
|
||||||
|
|
||||||
//// 如果是string?类型,返回null 可以做到,但是得反射,因为 string string? 是编译层区分的
|
|
||||||
|
|
||||||
//var isNullable1 = _memberInfo.CustomAttributes
|
|
||||||
// .Any(a => a.AttributeType.Name == "NullableAttribute");
|
|
||||||
|
|
||||||
////var isNullable2 = _memberInfo.CustomAttributes
|
|
||||||
//// .Any(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
|
|
||||||
|
|
||||||
//if (isNullable1)
|
|
||||||
//{
|
|
||||||
// return result;
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
// 如果是string类型,返回空字符串
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//影响 模型绑定时接收前端的值,同时影响 正常 JSON 序列化
|
|
||||||
public void SetValue(object target, object value)
|
public void SetValue(object target, object value)
|
||||||
{
|
{
|
||||||
|
|
||||||
_memberInfo.SetValue(target, value);
|
if (_MemberInfo.PropertyType == typeof(string))
|
||||||
|
{
|
||||||
#region 前端针对 string 类型的变量,如果传递null 会报错必传
|
//去掉前后空格
|
||||||
|
_MemberInfo.SetValue(target, value == null ? string.Empty : value.ToString() == string.Empty ? value : value/*.ToString().Trim()*/);
|
||||||
//if (_memberInfo.PropertyType == typeof(string))
|
|
||||||
//{
|
|
||||||
// _memberInfo.SetValue(target, value == null ? string.Empty : value);
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
// _memberInfo.SetValue(target, value);
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 处理模型验证区分 string string?
|
|
||||||
|
|
||||||
//////接收模型的时候 定义的明明是string 但是上面也有该属性,判断不准的 比如阅片跟踪列表查询
|
|
||||||
//var isNullable1 = _memberInfo.CustomAttributes.Any(a => a.AttributeType.Name == "NullableAttribute");
|
|
||||||
|
|
||||||
////不影响 string? 传递null 变为""
|
|
||||||
//if (_memberInfo.PropertyType == typeof(string) && isNullable1 == false)
|
|
||||||
//{
|
|
||||||
// //如果不处理 前段传递null string不会接收,说前段没传递会验证报错
|
|
||||||
// _memberInfo.SetValue(target, value == null ? string.Empty : value);
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
//{
|
|
||||||
|
|
||||||
// _memberInfo.SetValue(target, value);
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_MemberInfo.SetValue(target, value);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace IRaCIS.Core.API
|
|||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
|
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
|
||||||
.WriteTo.Console()
|
.WriteTo.Console()
|
||||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:365);
|
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:60);
|
||||||
|
|
||||||
#region 根据环境配置是否打开错误发送邮件通知
|
#region 根据环境配置是否打开错误发送邮件通知
|
||||||
|
|
||||||
@@ -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();
|
||||||
|
|||||||
@@ -28,13 +28,12 @@ public static class ServiceCollectionSetup
|
|||||||
services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||||||
services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||||
services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
||||||
services.AddOptions().Configure<RequestDuplicationOptions>(_configuration.GetSection("RequestDuplicationOptions"));
|
|
||||||
services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
||||||
services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));
|
services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));
|
||||||
|
|
||||||
services.Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
services.Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
||||||
|
|
||||||
//ת��ͷ���� ��ȡ��ʵIP
|
//转发头设置 获取真实IP
|
||||||
services.Configure<ForwardedHeadersOptions>(options =>
|
services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
{
|
{
|
||||||
options.ForwardedHeaders =
|
options.ForwardedHeaders =
|
||||||
@@ -52,7 +51,7 @@ public static class ServiceCollectionSetup
|
|||||||
|
|
||||||
services.AddScoped<IObtainTaskAutoCancelJob, ObtainTaskAutoCancelJob>();
|
services.AddScoped<IObtainTaskAutoCancelJob, ObtainTaskAutoCancelJob>();
|
||||||
|
|
||||||
// ע����Service ��β�ķ���
|
// 注册以Service 结尾的服务
|
||||||
services.Scan(scan => scan
|
services.Scan(scan => scan
|
||||||
.FromAssemblies(typeof(BaseService).Assembly)
|
.FromAssemblies(typeof(BaseService).Assembly)
|
||||||
.AddClasses(classes => classes.Where(t => t.Name.Contains("Service")))
|
.AddClasses(classes => classes.Where(t => t.Name.Contains("Service")))
|
||||||
@@ -71,23 +70,23 @@ public static class ServiceCollectionSetup
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
// MediatR ��������Ϣ �¼����� �ӳ����� ע�������handler��Ӧ��ϵ
|
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||||||
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region ��ʷ��������
|
#region 历史废弃配置
|
||||||
//builder.Services.AddMemoryCache();
|
//builder.Services.AddMemoryCache();
|
||||||
////�ϴ����� ����
|
////上传限制 配置
|
||||||
//builder.Services.Configure<FormOptions>(options =>
|
//builder.Services.Configure<FormOptions>(options =>
|
||||||
//{
|
//{
|
||||||
// options.MultipartBodyLengthLimit = int.MaxValue;
|
// options.MultipartBodyLengthLimit = int.MaxValue;
|
||||||
// options.ValueCountLimit = int.MaxValue;
|
// options.ValueCountLimit = int.MaxValue;
|
||||||
// options.ValueLengthLimit = int.MaxValue;
|
// options.ValueLengthLimit = int.MaxValue;
|
||||||
//});
|
//});
|
||||||
//IP ���� �����ð����� ���ߺ�����
|
//IP 限流 可设置白名单 或者黑名单
|
||||||
//services.AddIpPolicyRateLimitSetup(_configuration);
|
//services.AddIpPolicyRateLimitSetup(_configuration);
|
||||||
// �û����� ������Ȩ
|
// 用户类型 策略授权
|
||||||
//services.AddAuthorizationPolicySetup(_configuration);
|
//services.AddAuthorizationPolicySetup(_configuration);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -95,25 +94,25 @@ public static class ServiceCollectionSetup
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Autofac ����
|
#region Autofac 废弃
|
||||||
//public class AutofacModuleSetup : Autofac.Module
|
//public class AutofacModuleSetup : Autofac.Module
|
||||||
//{
|
//{
|
||||||
// protected override void Load(ContainerBuilder containerBuilder)
|
// protected override void Load(ContainerBuilder containerBuilder)
|
||||||
// {
|
// {
|
||||||
|
|
||||||
// #region byzhouhang 20210917 �˴�ע�᷺�Ͳִ� ���Լ���Domain�� ��Infra.EFcore ���� �յIJִ��ӿڶ���� �ִ��ļ�����
|
// #region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
|
||||||
|
|
||||||
// containerBuilder.RegisterGeneric(typeof(Repository<>))
|
// containerBuilder.RegisterGeneric(typeof(Repository<>))
|
||||||
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//ע�᷺�Ͳִ�
|
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
|
||||||
|
|
||||||
// containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
|
// containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region ָ��������Ҳ��autofac ������ʵ����ȡ https://www.cnblogs.com/xwhqwer/p/15320838.html
|
// #region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
|
||||||
|
|
||||||
// //��ȡ���п��������Ͳ�ʹ������ע��
|
// //获取所有控制器类型并使用属性注入
|
||||||
// containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
// containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
||||||
// .Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
// .Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
||||||
// .PropertiesAutowired();
|
// .PropertiesAutowired();
|
||||||
@@ -129,7 +128,7 @@ public static class ServiceCollectionSetup
|
|||||||
// //containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
// //containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
|
||||||
// //ע��hangfire���� ����ע��
|
// //注册hangfire任务 依赖注入
|
||||||
// containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
|
// containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -116,9 +116,6 @@ public static class SwaggerSetup
|
|||||||
//DocExpansion设置为none可折叠所有方法
|
//DocExpansion设置为none可折叠所有方法
|
||||||
options.DocExpansion(DocExpansion.None);
|
options.DocExpansion(DocExpansion.None);
|
||||||
|
|
||||||
// 开启Swagger UI的搜索/过滤功能
|
|
||||||
options.EnableFilter();
|
|
||||||
|
|
||||||
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
//DefaultModelsExpandDepth设置为 - 1 可不显示models
|
||||||
options.DefaultModelsExpandDepth(-1);
|
options.DefaultModelsExpandDepth(-1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"RemoteNew": "Server=101.132.253.119,1435;Database=irc_Prpd_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
|
"Hangfire": "Server=101.132.253.119,1435;Database=irc_Hangfire_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
|
},
|
||||||
|
"ObjectStoreService": {
|
||||||
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
|
"AliyunOSS": {
|
||||||
|
"RegionId": "cn-shanghai",
|
||||||
|
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||||
|
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
|
||||||
|
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
|
||||||
|
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
|
||||||
|
"BucketName": "tl-med-irc-event-store",
|
||||||
|
"ViewEndpoint": "https://tl-med-irc-event-store.oss-cn-shanghai.aliyuncs.com",
|
||||||
|
"Region": "oss-cn-shanghai",
|
||||||
|
"DurationSeconds": 7200
|
||||||
|
},
|
||||||
|
"MinIO": {
|
||||||
|
"endpoint": "http://192.168.3.68",
|
||||||
|
"port": "8001",
|
||||||
|
"useSSL": false,
|
||||||
|
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
||||||
|
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
||||||
|
"bucketName": "test"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"BasicSystemConfig": {
|
||||||
|
|
||||||
|
"OpenUserComplexPassword": true,
|
||||||
|
|
||||||
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
|
"OpenLoginLimit": true,
|
||||||
|
"LoginMaxFailCount": 5,
|
||||||
|
|
||||||
|
"LoginFailLockMinutes": 30,
|
||||||
|
"AutoLoginOutMinutes": 60,
|
||||||
|
|
||||||
|
"ContinuousReadingTimeMin": 120,
|
||||||
|
|
||||||
|
"ReadingRestTimeMin": 10,
|
||||||
|
|
||||||
|
"IsNeedChangePassWord": true,
|
||||||
|
|
||||||
|
"ChangePassWordDays": 90,
|
||||||
|
|
||||||
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
|
"TemplateType": 2
|
||||||
|
},
|
||||||
|
"SystemEmailSendConfig": {
|
||||||
|
"Port": 465,
|
||||||
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
|
"FromEmail": "uat@extimaging.com",
|
||||||
|
"FromName": "UAT_IRC",
|
||||||
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
|
"SiteUrl": "http://irc.event.extimaging.com/login",
|
||||||
|
"CompanyName": "Extensive Imaging",
|
||||||
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
|
"CompanyShortName": "Extensive Imaging",
|
||||||
|
"CompanyShortNameCN": "展影医疗",
|
||||||
|
"IsEnv_US": false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"RemoteNew": "Server=101.132.193.237,1433;Database=Prod_IRC_pidr_restore;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
|
||||||
"Hangfire": "Server=101.132.193.237,1433;Database=irc_Hangfire_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
|
||||||
//"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
|
||||||
//"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
|
||||||
},
|
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
|
||||||
"IsOpenStoreSync": true,
|
|
||||||
"ApiDeployRegion": "CN",
|
|
||||||
"SyncConfigList": [
|
|
||||||
{
|
|
||||||
"Domain": "irc.extimaging.com",
|
|
||||||
"Primary": "AliyunOSS",
|
|
||||||
"Target": "AWS",
|
|
||||||
"UploadRegion": "CN",
|
|
||||||
"TargetRegion": "US",
|
|
||||||
"IsOpenSync": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Domain": "eiirc.extimaging.com",
|
|
||||||
"Primary": "AWS",
|
|
||||||
"Target": "AliyunOSS",
|
|
||||||
"UploadRegion": "US",
|
|
||||||
"TargetRegion": "CN",
|
|
||||||
"IsOpenSync": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-irc-store",
|
|
||||||
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
|
||||||
"AWS": {
|
|
||||||
"Region": "us-east-1",
|
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
|
||||||
"UseSSL": true,
|
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
|
||||||
"BucketName": "ei-med-s3-irc-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-irc-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"BasicSystemConfig": {
|
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
|
||||||
|
|
||||||
"OpenLoginLimit": true,
|
|
||||||
"LoginMaxFailCount": 5,
|
|
||||||
"LoginFailLockMinutes": 30,
|
|
||||||
"AutoLoginOutMinutes": 120,
|
|
||||||
|
|
||||||
"OpenLoginMFA": false,
|
|
||||||
|
|
||||||
"ContinuousReadingTimeMin": 120,
|
|
||||||
"ReadingRestTimeMin": 10,
|
|
||||||
|
|
||||||
"IsNeedChangePassWord": true,
|
|
||||||
"ChangePassWordDays": 90,
|
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
|
||||||
"TemplateType": 2,
|
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
},
|
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
|
||||||
"Port": 465,
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
"Imap": "imap.qiye.aliyun.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "irc@extimaging.com",
|
|
||||||
"FromName": "IRC Imaging System",
|
|
||||||
"AuthorizationCode": "ExtImg@2022",
|
|
||||||
"SiteUrl": "http://irc.extimaging.com/login",
|
|
||||||
|
|
||||||
"PlatformName": "EICS",
|
|
||||||
"PlatformNameCN": "展影云平台",
|
|
||||||
"SystemShortName": "IRC",
|
|
||||||
"OrganizationName": "ExtImaging",
|
|
||||||
"OrganizationNameCN": "ExtImaging",
|
|
||||||
"CompanyName": "Extensive Imaging",
|
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
|
||||||
"CompanyShortName": "Extensive Imaging",
|
|
||||||
"CompanyShortNameCN": "展影医疗",
|
|
||||||
"IsEnv_US": false,
|
|
||||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
|
||||||
"CronEmailDefaultCulture": "zh-CN"
|
|
||||||
},
|
|
||||||
"SystemPacsConfig": {
|
|
||||||
"Port": "11113",
|
|
||||||
"IP": "101.132.193.237"
|
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,39 +7,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"RemoteNew": "Server=10.10.10.49,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=10.10.10.49,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||||
//"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
//"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||||
//"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
//"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AliyunOSS",
|
"ObjectStoreUse": "AliyunOSS",
|
||||||
"IsOpenStoreSync": true,
|
|
||||||
"ApiDeployRegion": "CN",
|
|
||||||
"SyncConfigList": [
|
|
||||||
{
|
|
||||||
"Domain": "irc.extimaging.com",
|
|
||||||
"Primary": "AliyunOSS",
|
|
||||||
"Target": "AWS",
|
|
||||||
"UploadRegion": "CN",
|
|
||||||
"TargetRegion": "US",
|
|
||||||
"IsOpenSync": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Domain": "eiirc.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",
|
||||||
@@ -52,21 +26,17 @@
|
|||||||
"Region": "oss-cn-shanghai",
|
"Region": "oss-cn-shanghai",
|
||||||
"DurationSeconds": 7200
|
"DurationSeconds": 7200
|
||||||
},
|
},
|
||||||
"AWS": {
|
"MinIO": {
|
||||||
"Region": "us-east-1",
|
"endpoint": "http://192.168.3.68",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"port": "8001",
|
||||||
"UseSSL": true,
|
"useSSL": false,
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/lili_s3_access",
|
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
||||||
"AccessKeyId": "AKIAW3MEAFJXZ2TZK7GM",
|
"secretKey": "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",
|
||||||
"SecretAccessKey": "9MLQCQ1HifEVW1gf068zBRAOb4wNnfrOkvBVByth",
|
"bucketName": "test"
|
||||||
"BucketName": "ei-med-s3-irc-store",
|
|
||||||
"ViewEndpoint": "https://ei-med-s3-irc-store.s3.amazonaws.com",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": true,
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
@@ -83,43 +53,31 @@
|
|||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 2,
|
"TemplateType": 2
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 465,
|
"Port": 465,
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
"Imap": "imap.qiye.aliyun.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "irc@extimaging.com",
|
"FromEmail": "irc@extimaging.com",
|
||||||
"FromName": "IRC Imaging System",
|
"FromName": "IRC Imaging System",
|
||||||
"AuthorizationCode": "ExtImg@2022",
|
"AuthorizationCode": "ExtImg@2022",
|
||||||
"SiteUrl": "http://irc.extimaging.com/login",
|
"SiteUrl": "http://irc.extimaging.com/login",
|
||||||
|
|
||||||
"PlatformName": "EICS",
|
|
||||||
"PlatformNameCN": "展影云平台",
|
|
||||||
"SystemShortName": "IRC",
|
"SystemShortName": "IRC",
|
||||||
"OrganizationName": "ExtImaging",
|
"OrganizationName": "Extlmaging",
|
||||||
"OrganizationNameCN": "ExtImaging",
|
"OrganizationNameCN": "Extlmaging",
|
||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"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"
|
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||||
},
|
},
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "11113",
|
"Port": "11113",
|
||||||
"IP": "101.132.193.237"
|
"IP": "101.132.193.237"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,36 +18,10 @@
|
|||||||
// Hangfire 定时任务数据库链接字符串
|
// Hangfire 定时任务数据库链接字符串
|
||||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
// 对象存储服务配置
|
// 对象存储服务配置
|
||||||
"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": {
|
||||||
// 阿里云 OSS 的 Region ID
|
// 阿里云 OSS 的 Region ID
|
||||||
@@ -114,8 +88,6 @@
|
|||||||
},
|
},
|
||||||
// 系统配置
|
// 系统配置
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
// 打开用户复杂密码
|
// 打开用户复杂密码
|
||||||
"OpenUserComplexPassword": false,
|
"OpenUserComplexPassword": false,
|
||||||
// 是否在开始工作前强制签署电子知情同意书
|
// 是否在开始工作前强制签署电子知情同意书
|
||||||
@@ -138,26 +110,19 @@
|
|||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
// 密码有效期(天),到期后必须修改
|
// 密码有效期(天),到期后必须修改
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
// 模板类型 1 Elevate(LiLi) 2 Extensive(展影)
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 2,
|
"TemplateType": 2,
|
||||||
// 是否打开项目关联删除
|
// 是否打开项目关联删除
|
||||||
"OpenTrialRelationDelete": true,
|
"OpenTrialRelationDelete": true,
|
||||||
// 转换PDF服务配置
|
// 转换PDF服务配置
|
||||||
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf",
|
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf"
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
},
|
},
|
||||||
// 邮件服务配置(用于系统通知、找回密码、错误报警等)
|
// 邮件服务配置(用于系统通知、找回密码、错误报警等)
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
|
|
||||||
// 企业邮箱SMTP服务器地址
|
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
|
||||||
// SMTP端口
|
// SMTP端口
|
||||||
"Port": 465,
|
"Port": 465,
|
||||||
|
// 企业邮箱SMTP服务器地址
|
||||||
"Imap": "imap.qiye.aliyun.com",
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
"ImapPort": 993,
|
|
||||||
|
|
||||||
// 发件人邮箱地址
|
// 发件人邮箱地址
|
||||||
"FromEmail": "test@extimaging.com",
|
"FromEmail": "test@extimaging.com",
|
||||||
// 发件人显示名称
|
// 发件人显示名称
|
||||||
@@ -166,17 +131,12 @@
|
|||||||
"AuthorizationCode": "SHzyyl2021",
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
// 系统对外访问地址
|
// 系统对外访问地址
|
||||||
"SiteUrl": "http://irc.test.extimaging.com/login",
|
"SiteUrl": "http://irc.test.extimaging.com/login",
|
||||||
|
// 系统简称
|
||||||
|
|
||||||
// 系统简称 - 一致性核查使用
|
|
||||||
"SystemShortName": "IRC",
|
"SystemShortName": "IRC",
|
||||||
// 组织英文名称-添加用户默认值
|
// 组织英文名称
|
||||||
"OrganizationName": "ExtImaging",
|
"OrganizationName": "Extlmaging",
|
||||||
// 组织中文名称
|
// 组织中文名称
|
||||||
"OrganizationNameCN": "ExtImaging",
|
"OrganizationNameCN": "Extlmaging",
|
||||||
|
|
||||||
"PlatformName": "EICS",
|
|
||||||
"PlatformNameCN": "展影云平台",
|
|
||||||
// 公司英文全称
|
// 公司英文全称
|
||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
// 公司中文全称
|
// 公司中文全称
|
||||||
@@ -185,14 +145,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,}$",
|
||||||
|
// 接收系统异常报警的邮箱列表
|
||||||
//后端周期性邮件默认语言
|
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||||
"CronEmailDefaultCulture": "zh-CN"
|
|
||||||
},
|
},
|
||||||
// PACS 连接配置
|
// PACS 连接配置
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
@@ -200,16 +160,5 @@
|
|||||||
"Port": "11113",
|
"Port": "11113",
|
||||||
// PACS服务器IP地址
|
// PACS服务器IP地址
|
||||||
"IP": "106.14.89.110"
|
"IP": "106.14.89.110"
|
||||||
},
|
|
||||||
// 重复请求配置
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
// 是否启用重复请求检测
|
|
||||||
"IsEnabled": true,
|
|
||||||
// 重复请求时间窗口(毫秒)
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
// 缓存请求时间(秒)
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": false,
|
"OpenUserComplexPassword": false,
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": false,
|
"OpenSignDocumentBeforeWork": false,
|
||||||
@@ -76,15 +75,13 @@
|
|||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 465,
|
"Port": 465,
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
"Imap": "imap.qiye.aliyun.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "test@extimaging.com",
|
"FromEmail": "test@extimaging.com",
|
||||||
"FromName": "Test_IRC",
|
"FromName": "Test_IRC",
|
||||||
"AuthorizationCode": "SHzyyl2021",
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
"SiteUrl": "http://irc.test.extimaging.com/login",
|
"SiteUrl": "http://irc.test.extimaging.com/login",
|
||||||
|
|
||||||
"OrganizationName": "ExtImaging",
|
"OrganizationName": "Extlmaging",
|
||||||
"OrganizationNameCN": "ExtImaging",
|
"OrganizationNameCN": "Extlmaging",
|
||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"CompanyShortName": "Extensive Imaging",
|
"CompanyShortName": "Extensive Imaging",
|
||||||
@@ -94,12 +91,5 @@
|
|||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "11113",
|
"Port": "11113",
|
||||||
"IP": "106.14.89.110"
|
"IP": "106.14.89.110"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,46 +12,19 @@
|
|||||||
//"RemoteNew": "Server=44.210.231.169,1435;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
//"RemoteNew": "Server=44.210.231.169,1435;Database=US_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
//"Hangfire": "Server=44.210.231.169,1435;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
//"Hangfire": "Server=44.210.231.169,1435;Database=US_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
},
|
},
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
"ObjectStoreUse": "AWS",
|
"ObjectStoreUse": "AWS",
|
||||||
"IsOpenStoreSync": true,
|
"MinIO": {
|
||||||
"ApiDeployRegion": "US",
|
"endPoint": "44.210.231.169",
|
||||||
"SyncConfigList": [
|
"port": "9001",
|
||||||
{
|
"useSSL": false,
|
||||||
"Domain": "eilili.elevateimaging.ai",
|
"accessKey": "e9bT1isTOqSAUxb6wd4n",
|
||||||
"Primary": "AliyunOSS",
|
"secretKey": "b5TaDzNdQCBtCvfm8eZ3dR6yY7tfZu2JYze2Po1i",
|
||||||
"Target": "AWS",
|
"bucketName": "prod-irc-us",
|
||||||
"UploadRegion": "CN",
|
"viewEndpoint": "http://44.210.231.169:9001/prod-irc-us/"
|
||||||
"TargetRegion": "US",
|
|
||||||
"IsOpenSync": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Domain": "lili.elevateimaging.ai",
|
|
||||||
"Primary": "AWS",
|
|
||||||
"Target": "AliyunOSS",
|
|
||||||
"UploadRegion": "US",
|
|
||||||
"TargetRegion": "CN",
|
|
||||||
"IsOpenSync": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"AliyunOSS": {
|
|
||||||
"RegionId": "cn-shanghai",
|
|
||||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
|
||||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
|
|
||||||
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
|
|
||||||
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
|
|
||||||
"BucketName": "zy-lili-store",
|
|
||||||
"ViewEndpoint": "https://zy-lili-cache.oss-cn-shanghai.aliyuncs.com",
|
|
||||||
"Region": "oss-cn-shanghai",
|
|
||||||
"DurationSeconds": 7200
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"AWS": {
|
"AWS": {
|
||||||
"Region": "us-east-1",
|
"Region": "us-east-1",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||||
@@ -65,8 +38,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": true,
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
@@ -85,24 +57,17 @@
|
|||||||
// 模板类型 1 Elevate 2 Extensive
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 1,
|
"TemplateType": 1,
|
||||||
|
|
||||||
"OpenTrialRelationDelete": false,
|
"OpenTrialRelationDelete": false
|
||||||
//MFA免验证
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 587,
|
"Port": 587,
|
||||||
"Host": "smtp-mail.outlook.com",
|
"Host": "smtp-mail.outlook.com",
|
||||||
"Imap": "imap-mail.outlook.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
"FromEmail": "donotreply@elevateimaging.ai",
|
||||||
"FromName": "LiLi System",
|
"FromName": "LiLi System",
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
"AuthorizationCode": "Q#669869497420ul",
|
||||||
|
|
||||||
|
|
||||||
"PlatformName": "LiLi",
|
|
||||||
"PlatformNameCN": "LiLi",
|
|
||||||
"SystemShortName": "LiLi",
|
"SystemShortName": "LiLi",
|
||||||
"OrganizationName": "Elevate Imaging",
|
"OrganizationName": "Elevate Imaging",
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
"OrganizationNameCN": "Elevate Imaging",
|
||||||
@@ -112,20 +77,14 @@
|
|||||||
"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"
|
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "104",
|
"Port": "104",
|
||||||
"IP": "44.210.231.169"
|
"IP": "44.210.231.169"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": true,
|
||||||
|
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": true,
|
||||||
@@ -67,24 +66,16 @@
|
|||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 1,
|
"TemplateType": 1,
|
||||||
"OpenLoginMFA": true,
|
"OpenLoginMFA": true
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 587,
|
"Port": 587,
|
||||||
"Host": "smtp-mail.outlook.com",
|
"Host": "smtp-mail.outlook.com",
|
||||||
"Imap": "imap-mail.outlook.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
"FromEmail": "donotreply@elevateimaging.ai",
|
||||||
"FromName": "LiLi System",
|
"FromName": "LiLi System",
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
"AuthorizationCode": "Q#669869497420ul",
|
||||||
|
|
||||||
|
|
||||||
"PlatformName": "LiLi",
|
|
||||||
"PlatformNameCN": "LiLi",
|
|
||||||
"SystemShortName": "LiLi",
|
"SystemShortName": "LiLi",
|
||||||
"OrganizationName": "Elevate Imaging",
|
"OrganizationName": "Elevate Imaging",
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
"OrganizationNameCN": "Elevate Imaging",
|
||||||
@@ -93,19 +84,14 @@
|
|||||||
"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": {
|
||||||
"Port": "104",
|
"Port": "104",
|
||||||
"IP": "3.226.182.187"
|
"IP": "3.226.182.187"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,6 @@
|
|||||||
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
"RemoteNew": "Server=3.226.182.187,1435;Database=US_Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=3.226.182.187,1435;Database=US_Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
|
|
||||||
"ObjectStoreService": {
|
"ObjectStoreService": {
|
||||||
|
|
||||||
@@ -54,8 +48,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": true,
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
@@ -72,22 +65,16 @@
|
|||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 1,
|
"TemplateType": 1
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 587,
|
"Port": 587,
|
||||||
"Host": "smtp-mail.outlook.com",
|
"Host": "smtp-mail.outlook.com",
|
||||||
"Imap": "imap-mail.outlook.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "donotreply@elevateimaging.ai",
|
"FromEmail": "donotreply@elevateimaging.ai",
|
||||||
"FromName": "LiLi System",
|
"FromName": "LiLi System",
|
||||||
"AuthorizationCode": "Q#669869497420ul",
|
"AuthorizationCode": "Q#669869497420ul",
|
||||||
|
|
||||||
"PlatformName": "LiLi",
|
|
||||||
"PlatformNameCN": "LiLi",
|
|
||||||
"SystemShortName": "LiLi",
|
"SystemShortName": "LiLi",
|
||||||
"OrganizationName": "Elevate Imaging",
|
"OrganizationName": "Elevate Imaging",
|
||||||
"OrganizationNameCN": "Elevate Imaging",
|
"OrganizationNameCN": "Elevate Imaging",
|
||||||
@@ -97,19 +84,14 @@
|
|||||||
"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"
|
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "104",
|
"Port": "104",
|
||||||
"IP": "3.226.182.187"
|
"IP": "3.226.182.187"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,35 +10,9 @@
|
|||||||
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
"RemoteNew": "Server=101.132.253.119,1435;Database=Uat_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||||
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
"Hangfire": "Server=101.132.253.119,1435;Database=Uat_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||||
},
|
},
|
||||||
"WeComNoticeConfig": {
|
|
||||||
"IsOpenWeComNotice": true,
|
|
||||||
"WebhookUrl": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4355b98e-1e72-4678-8dfb-2fc6ad0bf449", //4355b98e-1e72-4678-8dfb-2fc6ad0bf449 //cdd97aab-d256-4f07-9145-a0a2b1555322
|
|
||||||
"APINoticeUserList": [ "u", "wait..." ],
|
|
||||||
"VueNoticeUserList": [ "wangxiaoshuang", "6b7717a31647293621b97b96f74e6f3d" ]
|
|
||||||
},
|
|
||||||
"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",
|
||||||
@@ -70,9 +44,9 @@
|
|||||||
"Region": "us-east-1",
|
"Region": "us-east-1",
|
||||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||||
"UseSSL": true,
|
"UseSSL": true,
|
||||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
"RoleArn": "arn:aws:iam::471112624751:role/sts_s3_upload",
|
||||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
"AccessKeyId": "AKIAW3MEAFJXWRCGSX5Z",
|
||||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
"SecretAccessKey": "miais4jQGSd37A+TfBEP11AQM5u/CvotSmznJd8k",
|
||||||
"BucketName": "ei-med-s3-lili-uat-store",
|
"BucketName": "ei-med-s3-lili-uat-store",
|
||||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com/",
|
||||||
"DurationSeconds": 7200
|
"DurationSeconds": 7200
|
||||||
@@ -80,8 +54,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"BasicSystemConfig": {
|
"BasicSystemConfig": {
|
||||||
// 启用质控风险控制功能
|
|
||||||
"QCRiskControl": true,
|
|
||||||
"OpenUserComplexPassword": true,
|
"OpenUserComplexPassword": true,
|
||||||
"OpenSignDocumentBeforeWork": true,
|
"OpenSignDocumentBeforeWork": true,
|
||||||
|
|
||||||
@@ -99,45 +72,33 @@
|
|||||||
"IsNeedChangePassWord": true,
|
"IsNeedChangePassWord": true,
|
||||||
"ChangePassWordDays": 90,
|
"ChangePassWordDays": 90,
|
||||||
// 模板类型 1 Elevate 2 Extensive
|
// 模板类型 1 Elevate 2 Extensive
|
||||||
"TemplateType": 2,
|
"TemplateType": 2
|
||||||
//MFA免验证发送天数
|
|
||||||
"UserMFAVerifyMinutes": 1440
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"SystemEmailSendConfig": {
|
"SystemEmailSendConfig": {
|
||||||
"Port": 465,
|
"Port": 465,
|
||||||
"Host": "smtp.qiye.aliyun.com",
|
"Host": "smtp.qiye.aliyun.com",
|
||||||
"Imap": "imap.qiye.aliyun.com",
|
|
||||||
"ImapPort": 993,
|
|
||||||
"FromEmail": "uat@extimaging.com",
|
"FromEmail": "uat@extimaging.com",
|
||||||
"FromName": "Uat IRC Imaging System",
|
"FromName": "Uat IRC Imaging System",
|
||||||
"AuthorizationCode": "SHzyyl2021",
|
"AuthorizationCode": "SHzyyl2021",
|
||||||
"SiteUrl": "http://irc.uat.extimaging.com/login",
|
"SiteUrl": "http://irc.uat.extimaging.com/login",
|
||||||
|
|
||||||
"PlatformName": "EICS",
|
|
||||||
"PlatformNameCN": "展影云平台",
|
|
||||||
"SystemShortName": "IRC",
|
"SystemShortName": "IRC",
|
||||||
"OrganizationName": "ExtImaging",
|
"OrganizationName": "Extlmaging",
|
||||||
"OrganizationNameCN": "ExtImaging",
|
"OrganizationNameCN": "Extlmaging",
|
||||||
"CompanyName": "Extensive Imaging",
|
"CompanyName": "Extensive Imaging",
|
||||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||||
"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"
|
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||||
},
|
},
|
||||||
|
|
||||||
"SystemPacsConfig": {
|
"SystemPacsConfig": {
|
||||||
"Port": "11113",
|
"Port": "11113",
|
||||||
"IP": "101.132.253.119"
|
"IP": "101.132.253.119"
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
|
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
|
||||||
"Issuer": "Extimaging",
|
"Issuer": "Extimaging",
|
||||||
"Audience": "EICS",
|
"Audience": "EICS",
|
||||||
"TokenExpireMinute": "10080" //7天
|
"TokenExpireMinute": "10080"//7天
|
||||||
},
|
},
|
||||||
"IpRateLimiting": {
|
"IpRateLimiting": {
|
||||||
"EnableEndpointRateLimiting": true,
|
"EnableEndpointRateLimiting": true,
|
||||||
@@ -74,12 +74,5 @@
|
|||||||
"redirect_uri": "https://oauthlogin.net/oauth/githubcallback",
|
"redirect_uri": "https://oauthlogin.net/oauth/githubcallback",
|
||||||
"scope": "repo"
|
"scope": "repo"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"RequestDuplicationOptions": {
|
|
||||||
"IsEnabled": true,
|
|
||||||
"DuplicationWindowMs": 200,
|
|
||||||
"CacheTimeSeconds": 5,
|
|
||||||
"ExcludedPaths": [
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
<!-- HTML for static distribution bundle build -->
|
<!-- HTML for static distribution bundle build -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>%(DocumentTitle)</title>
|
<title>%(DocumentTitle)</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
|
||||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css">
|
||||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
@@ -112,23 +113,8 @@
|
|||||||
}, info: function () {
|
}, info: function () {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
fn: {
|
|
||||||
opsFilter: function (taggedOps, phrase) {
|
|
||||||
var normalPhrase = phrase.toLowerCase();
|
|
||||||
return taggedOps.map(function (tagObj, tag) {
|
|
||||||
var operations = tagObj.get("operations").filter(function (op) {
|
|
||||||
var summary = op.getIn(["operation", "summary"]) || "";
|
|
||||||
var path = op.get("path") || "";
|
|
||||||
var tagMatch = tag.toLowerCase().indexOf(normalPhrase) !== -1;
|
|
||||||
return tagMatch || summary.toLowerCase().indexOf(normalPhrase) !== -1 || path.toLowerCase().indexOf(normalPhrase) !== -1;
|
|
||||||
});
|
|
||||||
return tagObj.set("operations", operations);
|
|
||||||
}).filter(function (tagObj) {
|
|
||||||
return tagObj.get("operations").size > 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -505,8 +505,8 @@ var abp = abp || {};
|
|||||||
|
|
||||||
//Inputs
|
//Inputs
|
||||||
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
|
createInput(modalUxContent, 'tenancyName', 'Tenancy Name (Leave empty for Host)');
|
||||||
createInput(modalUxContent, 'userName', 'Username or email address', 'text', 'user1wj');
|
createInput(modalUxContent, 'userName', 'Username or email address', 'text', 'cyldev');
|
||||||
createInput(modalUxContent, 'password', 'Password', 'password', '1');
|
createInput(modalUxContent, 'password', 'Password', 'password', '123456');
|
||||||
createInput(modalUxContent, 'pwdMd5', 'PwdMd5', 'text', '');
|
createInput(modalUxContent, 'pwdMd5', 'PwdMd5', 'text', '');
|
||||||
createSelect(modalUxContent, 'roleSelect', 'role', [])
|
createSelect(modalUxContent, 'roleSelect', 'role', [])
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
new Claim(JwtIRaCISClaimType.UserTypeShortName,user.UserTypeShortName),
|
||||||
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
new Claim(JwtIRaCISClaimType.PermissionStr,user.PermissionStr),
|
||||||
new Claim(JwtIRaCISClaimType.IsZhiZhun,user.IsZhiZhun.ToString()),
|
new Claim(JwtIRaCISClaimType.IsZhiZhun,user.IsZhiZhun.ToString()),
|
||||||
new Claim(JwtIRaCISClaimType.IsTestUser,user.IsTestUser.ToString()),
|
new Claim(JwtIRaCISClaimType.IsTestUser,user.IsTestUser.ToString())
|
||||||
new Claim(JwtIRaCISClaimType.UserWorkLanguage,user.UserWorkLanguage.ToString())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////创建令牌
|
////创建令牌
|
||||||
|
|||||||
@@ -23,7 +23,5 @@ namespace IRaCIS.Core.Application.Auth
|
|||||||
public bool IsZhiZhun { get; set; }
|
public bool IsZhiZhun { get; set; }
|
||||||
|
|
||||||
public string UserTypeShortName { get; set; } = string.Empty;
|
public string UserTypeShortName { get; set; } = string.Empty;
|
||||||
|
|
||||||
public UserWorkLanguage UserWorkLanguage { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,14 @@
|
|||||||
using IRaCIS.Core.Application.Helper.OtherTool;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
||||||
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class ModelActionFilter(IStringLocalizer _localizer, IConfiguration _config, IUserInfo _userInfo) : ActionFilterAttribute, IActionFilter
|
public class ModelActionFilter(IStringLocalizer _localizer) : ActionFilterAttribute, IActionFilter
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@@ -31,55 +23,8 @@ public class ModelActionFilter(IStringLocalizer _localizer, IConfiguration _conf
|
|||||||
.Select(e => e.ErrorMessage)
|
.Select(e => e.ErrorMessage)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var request = context.HttpContext.Request;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool isOpenWeComNotice = _config.GetValue<bool>("WeComNoticeConfig:IsOpenWeComNotice");
|
|
||||||
|
|
||||||
if (isOpenWeComNotice)
|
|
||||||
{
|
|
||||||
string webhook = _config["WeComNoticeConfig:WebhookUrl"] ?? string.Empty;
|
|
||||||
|
|
||||||
var uri = new Uri(_config["SystemEmailSendConfig:SiteUrl"]);
|
|
||||||
var baseUrl = uri.GetLeftPart(UriPartial.Authority);
|
|
||||||
|
|
||||||
var userList = _config.GetSection("WeComNoticeConfig:VueNoticeUserList").Get<string[]>();
|
|
||||||
|
|
||||||
var requestBody = context.HttpContext.Items["RequestBody"] as string;
|
|
||||||
|
|
||||||
|
|
||||||
// 🔔 异步告警(不要阻塞请求)
|
|
||||||
_ = WeComNotifier.SendAlertAsync(
|
|
||||||
webhook: webhook,
|
|
||||||
alert: new WeComAlert
|
|
||||||
{
|
|
||||||
Env = baseUrl,
|
|
||||||
UserName = _userInfo.UserName.IsNotNullOrEmpty()? $"{_userInfo.UserName}({_userInfo.UserTypeShortName})": "匿名",
|
|
||||||
Api = $"{request.Method} {request.Path}",
|
|
||||||
Message = $"前端传递参数,后端模型验证失败\n 具体信息:{JsonConvert.SerializeObject(validationErrors)}",
|
|
||||||
JsonData = requestBody,
|
|
||||||
AtUsers = userList ?? []
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Logger.Error($"模型验证过滤器里发送企业微信出现错误:{ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---提供给接口的参数无效。
|
//---提供给接口的参数无效。
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject(validationErrors)));
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject(validationErrors)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
using IRaCIS.Core.Application.Helper.OtherTool;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Filter;
|
namespace IRaCIS.Core.Application.Filter;
|
||||||
|
|
||||||
public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, IStringLocalizer _localizer, IConfiguration _config, IUserInfo _userInfo) : Attribute, IExceptionFilter
|
public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, IStringLocalizer _localizer) : Attribute, IExceptionFilter
|
||||||
{
|
{
|
||||||
|
|
||||||
public void OnException(ExceptionContext context)
|
public void OnException(ExceptionContext context)
|
||||||
@@ -49,44 +46,7 @@ public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, ISt
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message)
|
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (exception.InnerException is null ? (exception.Message)
|
||||||
: (exception.Message + "Inner ExceptionMsg:" + exception.InnerException?.Message)), ApiResponseCodeEnum.ProgramException));
|
: (exception.InnerException?.Message )), ApiResponseCodeEnum.ProgramException));
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool isOpenWeComNotice = _config.GetValue<bool>("WeComNoticeConfig:IsOpenWeComNotice");
|
|
||||||
|
|
||||||
if (isOpenWeComNotice)
|
|
||||||
{
|
|
||||||
string webhook = _config["WeComNoticeConfig:WebhookUrl"] ?? string.Empty;
|
|
||||||
|
|
||||||
var uri = new Uri(_config["SystemEmailSendConfig:SiteUrl"]);
|
|
||||||
var baseUrl = uri.GetLeftPart(UriPartial.Authority);
|
|
||||||
|
|
||||||
var userList = _config.GetSection("WeComNoticeConfig:APINoticeUserList").Get<string[]>();
|
|
||||||
|
|
||||||
var requestBody = context.HttpContext.Items["RequestBody"] as string;
|
|
||||||
|
|
||||||
var alert = new WeComAlert
|
|
||||||
{
|
|
||||||
Env = baseUrl,
|
|
||||||
UserName = $"{_userInfo.UserName}({_userInfo.UserTypeShortName})",
|
|
||||||
Api = context.HttpContext.Request.Path,
|
|
||||||
Message = exception.Message,
|
|
||||||
JsonData = requestBody,
|
|
||||||
Stack = exception.StackTrace,
|
|
||||||
AtUsers = userList ?? []
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = WeComNotifier.SendAlertAsync(webhook, alert);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
_logger.LogError($"异常过滤器里发送企业微信出现错误:{ex.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +58,6 @@ public class ProjectExceptionFilter(ILogger<ProjectExceptionFilter> _logger, ISt
|
|||||||
|
|
||||||
_logger.LogError(errorInfo);
|
_logger.LogError(errorInfo);
|
||||||
|
|
||||||
|
|
||||||
//_logger.LogError(exception, exception.Message);
|
//_logger.LogError(exception, exception.Message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.BusinessFilter.LegacyController
|
|
||||||
{
|
|
||||||
using Database.Api;
|
|
||||||
using DocumentFormat.OpenXml.InkML;
|
|
||||||
using IRaCIS.Core.Application.Service.Common;
|
|
||||||
using IRaCIS.Core.Infrastructure;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using Microsoft.AspNetCore.Components.Endpoints;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Minio.Helper;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Database.Api
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 请求拦截 请求前后的操作
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="logger">logger</param>
|
|
||||||
/// <param name="accessor">loggerHelper</param>
|
|
||||||
public class RequestDuplicationFilter(ILogger<RequestDuplicationFilter> logger, IHttpContextAccessor accessor, IUserInfo _userInfo, IStringLocalizer _localizer, IOptionsMonitor<RequestDuplicationOptions> RequestDuplicationOptionsMonitor) : ExceptionFilterAttribute, IAsyncActionFilter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 传入的参数
|
|
||||||
/// </summary>
|
|
||||||
public string Intoparam { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 这个是正常记录(请求刚进入的时候)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">context</param>
|
|
||||||
/// <param name="next">next</param>
|
|
||||||
/// <returns>返回的对象</returns>
|
|
||||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
|
||||||
{
|
|
||||||
if (RequestDuplicationOptionsMonitor.CurrentValue.IsEnabled)
|
|
||||||
{
|
|
||||||
Dictionary<string, object?> dic = new Dictionary<string, object?>();
|
|
||||||
var desc = context.ActionDescriptor as ControllerActionDescriptor;
|
|
||||||
foreach (var p in desc.Parameters)
|
|
||||||
{
|
|
||||||
// 关键判断:绑定源是否是 Services
|
|
||||||
if (p.BindingInfo?.BindingSource == BindingSource.Services) continue;
|
|
||||||
// 普通参数,取值
|
|
||||||
if (context.ActionArguments.TryGetValue(p.Name, out var value) && value != null)
|
|
||||||
{
|
|
||||||
dic.Add(p.Name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Intoparam = JsonConvert.SerializeObject(dic);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this.RequestDuplication();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var resultContext = await next();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
private void RequestDuplication()
|
|
||||||
{
|
|
||||||
var requestPath = accessor?.HttpContext?.Request?.Path.ToString() ?? string.Empty;
|
|
||||||
|
|
||||||
// 验证请求频繁情况
|
|
||||||
if (
|
|
||||||
!requestPath
|
|
||||||
.Split("/", StringSplitOptions.RemoveEmptyEntries)
|
|
||||||
.Any(segment => segment.StartsWith("get", StringComparison.OrdinalIgnoreCase)) &&
|
|
||||||
_userInfo.UserRoleId != default(Guid)&&
|
|
||||||
RequestDuplicationOptionsMonitor.CurrentValue.IsEnabled &&
|
|
||||||
!RequestDuplicationOptionsMonitor.CurrentValue.ExcludePaths.Contains(requestPath))
|
|
||||||
{
|
|
||||||
RequestInfo requestInfo = new RequestInfo
|
|
||||||
{
|
|
||||||
UserRoleId = _userInfo.UserRoleId,
|
|
||||||
RequestPath = requestPath,
|
|
||||||
ParameterHash = GenerateParameterHash(this.Intoparam),
|
|
||||||
RequestTime = DateTime.Now
|
|
||||||
};
|
|
||||||
|
|
||||||
IRCSystemInfo.RequestRecordList= IRCSystemInfo.RequestRecordList.Where(x => x.RequestTime >= DateTime.Now.AddSeconds(-RequestDuplicationOptionsMonitor.CurrentValue.CacheTimeSeconds)).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
var requestsTimes = IRCSystemInfo.RequestRecordList.Any(x=>
|
|
||||||
x.RequestTime>= requestInfo.RequestTime.AddMilliseconds(-RequestDuplicationOptionsMonitor.CurrentValue.DuplicationWindowMs)&&
|
|
||||||
x.RequestKey== requestInfo.RequestKey);
|
|
||||||
if (requestsTimes)
|
|
||||||
{
|
|
||||||
throw new BusinessValidationFailedException(_localizer["RequestDuplicationFilter_RequestDuplication"], ApiResponseCodeEnum.BusinessValidationFailed);
|
|
||||||
}
|
|
||||||
IRCSystemInfo.RequestRecordList.Add(requestInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateParameterHash(string parameters)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(parameters))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
using var sha256 = SHA256.Create();
|
|
||||||
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(parameters));
|
|
||||||
return Convert.ToBase64String(hashBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+5
-5
@@ -29,11 +29,11 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
|
|||||||
var requestHost = context.HttpContext.Request.Host;
|
var requestHost = context.HttpContext.Request.Host;
|
||||||
|
|
||||||
// 检查请求是否来自 localhost:6100
|
// 检查请求是否来自 localhost:6100
|
||||||
if (requestHost.Host == "localhost" && (requestHost.Port == 6100 || requestHost.Port == 3305))
|
//if (requestHost.Host == "localhost" && (requestHost.Port == 6100 || requestHost.Port == 3305))
|
||||||
{
|
//{
|
||||||
await next();
|
// await next();
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
#region 特殊用户类型拦截
|
#region 特殊用户类型拦截
|
||||||
// 用户类型检查
|
// 用户类型检查
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ namespace IRaCIS.Core.Domain.Share;
|
|||||||
[Description("多环境 配置环境实体")]
|
[Description("多环境 配置环境实体")]
|
||||||
public class ServiceVerifyConfigOption
|
public class ServiceVerifyConfigOption
|
||||||
{
|
{
|
||||||
public bool QCRiskControl { get; set; }
|
|
||||||
public bool OpenUserComplexPassword { get; set; }
|
public bool OpenUserComplexPassword { get; set; }
|
||||||
|
|
||||||
public bool OpenSignDocumentBeforeWork { get; set; }
|
public bool OpenSignDocumentBeforeWork { get; set; }
|
||||||
@@ -39,8 +38,6 @@ public class ServiceVerifyConfigOption
|
|||||||
|
|
||||||
public string ThirdPdfUrl { get; set; }
|
public string ThirdPdfUrl { get; set; }
|
||||||
|
|
||||||
public int UserMFAVerifyMinutes { get; set; } = 1440;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemEmailSendConfig
|
public class SystemEmailSendConfig
|
||||||
@@ -48,10 +45,6 @@ public class SystemEmailSendConfig
|
|||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
|
||||||
public string Host { get; set; } = string.Empty;
|
public string Host { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Imap { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public int ImapPort { get; set; }
|
|
||||||
public string FromEmail { get; set; } = string.Empty;
|
public string FromEmail { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string FromName { get; set; } = string.Empty;
|
public string FromName { get; set; } = string.Empty;
|
||||||
@@ -60,11 +53,7 @@ public class SystemEmailSendConfig
|
|||||||
|
|
||||||
public string SiteUrl { get; set; } = string.Empty;
|
public string SiteUrl { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public string SystemShortName { get; set; } = string.Empty;
|
||||||
public string PlatformName { get; set; } = string.Empty;
|
|
||||||
public string PlatformNameCN { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string SystemShortName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string OrganizationName { get; set; } = string.Empty;
|
public string OrganizationName { get; set; } = string.Empty;
|
||||||
public string OrganizationNameCN { get; set; } = string.Empty;
|
public string OrganizationNameCN { get; set; } = string.Empty;
|
||||||
@@ -79,17 +68,16 @@ 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 bool IsOpenErrorNoticeEmail { get; set; }
|
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
|
||||||
|
|
||||||
|
|
||||||
//public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemEmailSendConfigView
|
public class SystemEmailSendConfigView
|
||||||
{
|
{
|
||||||
public string SystemShortName { get; set; } = string.Empty;
|
public string SystemShortName { get; set; } = string.Empty;
|
||||||
public string CompanyName { get; set; } = string.Empty;
|
public string CompanyName { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string CompanyNameCN { get; set; } = string.Empty;
|
public string CompanyNameCN { get; set; } = string.Empty;
|
||||||
@@ -117,54 +105,6 @@ public class IRCEncreptOption
|
|||||||
public List<string> ApiPathList { get; set; }
|
public List<string> ApiPathList { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 请求缓存配置
|
|
||||||
/// </summary>
|
|
||||||
public class RequestDuplicationOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 缓存时间(秒),默认5秒
|
|
||||||
/// </summary>
|
|
||||||
public int CacheTimeSeconds { get; set; } = 5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重复请求检测时间窗口(毫秒),默认500毫秒
|
|
||||||
/// </summary>
|
|
||||||
public int DuplicationWindowMs { get; set; } = 500;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否启用防重复请求
|
|
||||||
/// </summary>
|
|
||||||
public bool IsEnabled { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 需要排除的路径(不进行重复检测)
|
|
||||||
/// </summary>
|
|
||||||
public List<string> ExcludePaths { get; set; } = new List<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class IRCSystemInfo
|
|
||||||
{
|
|
||||||
public static List<RequestInfo> RequestRecordList { get; set; } = new List<RequestInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RequestInfo
|
|
||||||
{
|
|
||||||
public Guid UserRoleId { get; set; }
|
|
||||||
|
|
||||||
public string RequestPath { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string ParameterHash { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public DateTime RequestTime { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 请求的唯一标识
|
|
||||||
/// </summary>
|
|
||||||
public string RequestKey => $"{UserRoleId}_{RequestPath}_{ParameterHash}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IRaCISBasicConfigOption
|
public class IRaCISBasicConfigOption
|
||||||
{
|
{
|
||||||
public string DoctorCodePrefix { get; set; }
|
public string DoctorCodePrefix { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
|
||||||
|
|
||||||
|
|
||||||
public static class CacheKeys
|
public static class CacheKeys
|
||||||
@@ -63,15 +61,6 @@ public static class CacheKeys
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
||||||
|
|
||||||
//每个用户 每个浏览器独立时间
|
|
||||||
public static string UserMFAVerifyPass(Guid userId,string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}";
|
|
||||||
|
|
||||||
public static string UserMFATag(Guid userId) => $"UserMFAVerifyPass:{userId}";
|
|
||||||
|
|
||||||
public static string TrialDataStoreType(Guid trialId) => $"TrialDataStoreType:{trialId}";
|
|
||||||
|
|
||||||
|
|
||||||
public static string UserQCSkipTask(Guid userId) => $"UserSKipQCTask:{userId}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CacheHelper
|
public static class CacheHelper
|
||||||
@@ -83,9 +72,6 @@ public static class CacheHelper
|
|||||||
return statusStr;
|
return statusStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static async Task<List<SystemAnonymization>> GetSystemAnonymizationListAsync(IRepository<SystemAnonymization> _systemAnonymizationRepository)
|
public static async Task<List<SystemAnonymization>> GetSystemAnonymizationListAsync(IRepository<SystemAnonymization> _systemAnonymizationRepository)
|
||||||
{
|
{
|
||||||
var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync();
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using DocumentFormat.OpenXml.Office.CustomUI;
|
using FellowOakDicom;
|
||||||
using FellowOakDicom;
|
|
||||||
using FellowOakDicom.Media;
|
using FellowOakDicom.Media;
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using NPOI.Util;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
@@ -61,11 +57,6 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
var mappings = new List<string>();
|
var mappings = new List<string>();
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
|
||||||
var trialId = Guid.Empty;
|
|
||||||
|
|
||||||
Guid.TryParse(ossFolder.Split('/', StringSplitOptions.RemoveEmptyEntries)[0], out trialId);
|
|
||||||
|
|
||||||
var studyUid = list.FirstOrDefault()?.StudyInstanceUid;
|
|
||||||
|
|
||||||
var dicomDir = new DicomDirectory();
|
var dicomDir = new DicomDirectory();
|
||||||
|
|
||||||
@@ -109,11 +100,11 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
var dicomFile = new DicomFile(dataset);
|
var dicomFile = new DicomFile(dataset);
|
||||||
|
|
||||||
// 文件名递增格式:IM_00001, IM_00002, ...
|
// 文件名递增格式:IM_00001, IM_00002, ...
|
||||||
string filename = $@"IMAGE\IM_{index:D5}"; // :D5 表示补足5位
|
string filename = $@"IMAGE/IM_{index:D5}"; // :D5 表示补足5位
|
||||||
|
|
||||||
mappings.Add($"{filename} => {item.InstanceId}");
|
mappings.Add($"{filename} => {item.InstanceId}");
|
||||||
|
|
||||||
dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());
|
dic.Add(item.InstanceId.ToString(), Path.GetFileName(filename));
|
||||||
|
|
||||||
dicomDir.AddFile(dicomFile, filename);
|
dicomDir.AddFile(dicomFile, filename);
|
||||||
|
|
||||||
@@ -137,9 +128,7 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
// 重置流位置
|
// 重置流位置
|
||||||
memoryStream.Position = 0;
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
var relativePath = await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", true, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DICOMDIR });
|
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
|
||||||
|
|
||||||
dic.Add($"{studyUid}_DICOMDIR", relativePath.Split('/').Last());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//清理临时文件
|
//清理临时文件
|
||||||
@@ -153,7 +142,7 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
var mappingText = string.Join(Environment.NewLine, mappings);
|
var mappingText = string.Join(Environment.NewLine, mappings);
|
||||||
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
|
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
|
||||||
|
|
||||||
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DICOMDIR });
|
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -161,91 +150,6 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static async Task GenerateStudyDIR(List<StudyDIRInfo> list, Dictionary<string, string> dic, string? dirSavePath = null, Stream? outputStream = null)
|
|
||||||
{
|
|
||||||
var mappings = new List<string>();
|
|
||||||
int index = 1;
|
|
||||||
|
|
||||||
var trialId = Guid.Empty;
|
|
||||||
|
|
||||||
|
|
||||||
var studyUid = list.FirstOrDefault()?.StudyInstanceUid;
|
|
||||||
|
|
||||||
var dicomDir = new DicomDirectory();
|
|
||||||
|
|
||||||
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
|
|
||||||
{
|
|
||||||
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);
|
|
||||||
|
|
||||||
if (dicomUid != null)
|
|
||||||
{
|
|
||||||
var ts = DicomTransferSyntax.Query(dicomUid);
|
|
||||||
|
|
||||||
var dataset = new DicomDataset(ts)
|
|
||||||
{
|
|
||||||
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
|
|
||||||
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
|
|
||||||
{ DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
|
|
||||||
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
|
|
||||||
|
|
||||||
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
|
|
||||||
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
|
|
||||||
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
|
|
||||||
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
|
|
||||||
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
|
|
||||||
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
|
|
||||||
|
|
||||||
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
|
|
||||||
{ DicomTag.Modality, item.Modality ?? string.Empty },
|
|
||||||
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
|
|
||||||
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
|
|
||||||
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
|
|
||||||
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
|
|
||||||
|
|
||||||
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
|
|
||||||
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
|
|
||||||
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
|
|
||||||
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
|
|
||||||
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
|
|
||||||
{ DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
|
|
||||||
};
|
|
||||||
|
|
||||||
var dicomFile = new DicomFile(dataset);
|
|
||||||
|
|
||||||
// 文件名递增格式:IM_00001, IM_00002, ...
|
|
||||||
string filename = $@"IMAGE\IM_{index:D5}"; // :D5 表示补足5位
|
|
||||||
|
|
||||||
mappings.Add($"{filename} => {item.InstanceId}");
|
|
||||||
|
|
||||||
dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());
|
|
||||||
|
|
||||||
dicomDir.AddFile(dicomFile, filename);
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//有实际的文件
|
|
||||||
if (mappings.Count > 0)
|
|
||||||
{
|
|
||||||
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
|
|
||||||
|
|
||||||
if (dirSavePath.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
await dicomDir.SaveAsync(dirSavePath);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await dicomDir.SaveAsync(outputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
|
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using MailKit;
|
using MailKit;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
using Org.BouncyCastle.Tls;
|
|
||||||
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
@@ -10,15 +9,12 @@ namespace IRaCIS.Core.Application.Helper;
|
|||||||
public static class SendEmailHelper
|
public static class SendEmailHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
public static async Task<string> SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
public static async Task SendEmailAsync(MimeMessage messageToSend, SystemEmailSendConfig _systemEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
||||||
{
|
{
|
||||||
string result = string.Empty;
|
|
||||||
result = messageToSend.MessageId;
|
|
||||||
|
|
||||||
//没有收件人 那么不发送
|
//没有收件人 那么不发送
|
||||||
if (messageToSend.To.Count == 0)
|
if (messageToSend.To.Count == 0)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -46,7 +42,6 @@ public static class SendEmailHelper
|
|||||||
|
|
||||||
await smtp.DisconnectAsync(true);
|
await smtp.DisconnectAsync(true);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -56,133 +51,9 @@ public static class SendEmailHelper
|
|||||||
throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
|
throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 发送项目邮件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="messageToSend"></param>
|
|
||||||
/// <param name="trial"></param>
|
|
||||||
/// <param name="messageSentSuccess"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="Exception"></exception>
|
|
||||||
public static async Task<string> SendTrialEmailAsync(MimeMessage messageToSend, Trial trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
// 项目的需要重设 发件地址与邮件地址
|
|
||||||
var fromAddress = messageToSend.From.Mailboxes.FirstOrDefault();
|
|
||||||
if (fromAddress != null)
|
|
||||||
{
|
|
||||||
messageToSend.From.Clear();
|
|
||||||
messageToSend.From.Add(new MailboxAddress(trial.EmailFromName, trial.EmailFromEmail));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string result = string.Empty;
|
|
||||||
result = messageToSend.MessageId;
|
|
||||||
|
|
||||||
|
|
||||||
//没有收件人 那么不发送
|
|
||||||
if (messageToSend.To.Count == 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 替换邮件标题
|
|
||||||
if (!string.IsNullOrEmpty(messageToSend.Subject))
|
|
||||||
{
|
|
||||||
foreach (var item in trial.TrialObjectNameList)
|
|
||||||
{
|
|
||||||
// 把标题里的占位符替换成真实名称
|
|
||||||
messageToSend.Subject = messageToSend.Subject.Replace(item.Name, item.TrialName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建替换字典
|
|
||||||
var replacements = new Dictionary<string, string>();
|
|
||||||
foreach (var item in trial.TrialObjectNameList)
|
|
||||||
{
|
|
||||||
replacements[item.Name] = item.TrialName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安全替换 HTML
|
|
||||||
ReplaceHtmlContent(messageToSend.Body, replacements);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
|
|
||||||
{
|
|
||||||
if (messageSentSuccess != null)
|
|
||||||
{
|
|
||||||
smtp.MessageSent += messageSentSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
|
|
||||||
|
|
||||||
//await smtp.ConnectAsync("smtp.qq.com", 465, SecureSocketOptions.SslOnConnect);
|
|
||||||
|
|
||||||
//await smtp.AuthenticateAsync("zhou941003@qq.com", "sqfhlpfdvnexbcab");
|
|
||||||
|
|
||||||
|
|
||||||
//await smtp.ConnectAsync(_systemEmailConfig.Host, _systemEmailConfig.Port, SecureSocketOptions.Auto);
|
|
||||||
|
|
||||||
//await smtp.AuthenticateAsync(_systemEmailConfig.FromEmail, _systemEmailConfig.AuthorizationCode);
|
|
||||||
|
|
||||||
|
|
||||||
await smtp.ConnectAsync(trial.EmailSMTPServerAddress, trial.EmailSMTPServerPort, SecureSocketOptions.Auto);
|
|
||||||
|
|
||||||
await smtp.AuthenticateAsync(trial.EmailFromEmail, trial.EmailAuthorizationCode);
|
|
||||||
|
|
||||||
|
|
||||||
await smtp.SendAsync(messageToSend);
|
|
||||||
|
|
||||||
await smtp.DisconnectAsync(true);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
//---邮件发送失败,您进行的操作未能成功,请检查邮箱或联系维护人员
|
|
||||||
throw new Exception(I18n.T("SendEmail_SendFail"), new Exception(ex.Message));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 遍历邮件体,找到 HTML 部分并替换
|
|
||||||
public static void ReplaceHtmlContent(MimeEntity entity, Dictionary<string, string> replacements)
|
|
||||||
{
|
|
||||||
if (entity is Multipart multipart)
|
|
||||||
{
|
|
||||||
foreach (var part in multipart)
|
|
||||||
{
|
|
||||||
ReplaceHtmlContent(part, replacements);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (entity is TextPart textPart && textPart.IsHtml)
|
|
||||||
{
|
|
||||||
// 只有这里才是真正的 HTML
|
|
||||||
foreach (var kv in replacements)
|
|
||||||
{
|
|
||||||
textPart.Text = textPart.Text.Replace(kv.Key, kv.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static async Task<bool> TestEmailConfigAsync(SystemEmailSendConfig _systemEmailConfig)
|
public static async Task<bool> TestEmailConfigAsync(SystemEmailSendConfig _systemEmailConfig)
|
||||||
{
|
{
|
||||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
|
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
|
||||||
@@ -202,7 +73,7 @@ public static class SendEmailHelper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig, Trial? trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
|
||||||
{
|
{
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
@@ -216,9 +87,8 @@ public static class SendEmailHelper
|
|||||||
|
|
||||||
if (sMTPEmailConfig.ToMailAddressList.Count == 0)
|
if (sMTPEmailConfig.ToMailAddressList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
//---没有收件人
|
//---没有收件人
|
||||||
//throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
|
throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -273,7 +143,7 @@ public static class SendEmailHelper
|
|||||||
|
|
||||||
await smtp.ConnectAsync(sMTPEmailConfig.Host, sMTPEmailConfig.Port, SecureSocketOptions.Auto);
|
await smtp.ConnectAsync(sMTPEmailConfig.Host, sMTPEmailConfig.Port, SecureSocketOptions.Auto);
|
||||||
|
|
||||||
await smtp.AuthenticateAsync(trial.EmailFromEmail, trial.EmailAuthorizationCode);
|
await smtp.AuthenticateAsync(sMTPEmailConfig.UserName, sMTPEmailConfig.AuthorizationCode);
|
||||||
|
|
||||||
await smtp.SendAsync(messageToSend);
|
await smtp.SendAsync(messageToSend);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ using NPOI.HSSF.UserModel;
|
|||||||
using NPOI.SS.Formula.Functions;
|
using NPOI.SS.Formula.Functions;
|
||||||
using NPOI.SS.UserModel;
|
using NPOI.SS.UserModel;
|
||||||
using NPOI.XSSF.UserModel;
|
using NPOI.XSSF.UserModel;
|
||||||
using SharpCompress.Common;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Xceed.Document.NET;
|
using Xceed.Document.NET;
|
||||||
@@ -700,7 +699,7 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
enumValues = JsonConvert.DeserializeObject<int[]>(itemValue) ?? new int[0];
|
enumValues = JsonConvert.DeserializeObject<int[]>(itemValue)?? new int[0];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +709,7 @@ public static class ExcelExportHelper
|
|||||||
enumValues.Select(code =>
|
enumValues.Select(code =>
|
||||||
dynamicTranslateDataList[itemDicName]
|
dynamicTranslateDataList[itemDicName]
|
||||||
.FirstOrDefault(t =>
|
.FirstOrDefault(t =>
|
||||||
string.Equals(code.ToString(), t.Code, StringComparison.OrdinalIgnoreCase)
|
string.Equals(code.ToString(),t.Code, StringComparison.OrdinalIgnoreCase)
|
||||||
) is var r && r != null
|
) is var r && r != null
|
||||||
? (isEn_US ? r.Value : r.ValueCN)
|
? (isEn_US ? r.Value : r.ValueCN)
|
||||||
: string.Empty
|
: string.Empty
|
||||||
@@ -719,7 +718,7 @@ public static class ExcelExportHelper
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
translatedItemData = dynamicTranslateDataList[itemDicName].Where(t => t.Code.ToLower() == itemValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,19 +727,7 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var unit = iteObjDic.ContainsKey("Unit") ? iteObjDic["Unit"]?.ToString() : null;
|
row.GetCell(writeIndex).SetCellValue(itemValue);
|
||||||
|
|
||||||
if (unit.IsNotNullOrEmpty() && unit == "9")
|
|
||||||
{
|
|
||||||
row.GetCell(writeIndex).SetCellValue(itemValue + "%");
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
row.GetCell(writeIndex).SetCellValue(itemValue);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,16 +858,17 @@ public static class ExcelExportHelper
|
|||||||
//模板路径
|
//模板路径
|
||||||
var tplPath = physicalPath;
|
var tplPath = physicalPath;
|
||||||
|
|
||||||
|
|
||||||
// 获取文件流
|
|
||||||
var templateStream = new MemoryStream();
|
|
||||||
|
|
||||||
#region 根据中英文 删除模板sheet
|
#region 根据中英文 删除模板sheet
|
||||||
|
|
||||||
// 打开模板文件
|
// 打开模板文件
|
||||||
var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
|
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
var workbook = new XSSFWorkbook(templateFileStream);
|
// 获取文件流
|
||||||
|
var templateStream = new MemoryStream();
|
||||||
|
templateFile.CopyTo(templateStream);
|
||||||
|
templateStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
var workbook = new XSSFWorkbook(templateStream);
|
||||||
|
|
||||||
int sheetCount = workbook.NumberOfSheets;
|
int sheetCount = workbook.NumberOfSheets;
|
||||||
|
|
||||||
@@ -985,8 +973,14 @@ public static class ExcelExportHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
workbook.Write(templateStream, leaveOpen: true);
|
using (var memoryStream2 = new MemoryStream())
|
||||||
templateStream.Position = 0;
|
{
|
||||||
|
workbook.Write(memoryStream2, true);
|
||||||
|
|
||||||
|
memoryStream2.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
templateStream = memoryStream2;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1084,91 +1078,6 @@ public static class ExcelExportHelper
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static async Task<IActionResult> MutiSheetDataExportAsync(string code, object data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment)
|
|
||||||
{
|
|
||||||
|
|
||||||
var (physicalPath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);
|
|
||||||
|
|
||||||
|
|
||||||
//模板路径
|
|
||||||
var tplPath = physicalPath;
|
|
||||||
|
|
||||||
var templateStream = new MemoryStream();
|
|
||||||
|
|
||||||
|
|
||||||
#region npoi 移除某一行
|
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
if (isEn_US)
|
|
||||||
{
|
|
||||||
// 打开模板文件
|
|
||||||
using var templateFileStream = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
|
|
||||||
|
|
||||||
using var workbook = new XSSFWorkbook(templateFileStream);
|
|
||||||
|
|
||||||
int sheetCount = workbook.NumberOfSheets;
|
|
||||||
|
|
||||||
int removeRowIndex = 1; // 要删除的行(0-based)
|
|
||||||
|
|
||||||
for (int i = 0; i < sheetCount; i++)
|
|
||||||
{
|
|
||||||
var sheet = workbook.GetSheetAt(i);
|
|
||||||
|
|
||||||
// 2️ 删除行
|
|
||||||
var row = sheet.GetRow(removeRowIndex);
|
|
||||||
if (row != null)
|
|
||||||
{
|
|
||||||
sheet.RemoveRow(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3️ 上移后续行
|
|
||||||
if (removeRowIndex < sheet.LastRowNum)
|
|
||||||
{
|
|
||||||
sheet.ShiftRows(
|
|
||||||
removeRowIndex + 1,
|
|
||||||
sheet.LastRowNum,
|
|
||||||
-1,
|
|
||||||
true, // copyRowHeight
|
|
||||||
false // resetOriginalRowHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
workbook.Write(templateStream, leaveOpen: true);
|
|
||||||
templateStream.Position = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (var fs = new FileStream(tplPath, FileMode.Open, FileAccess.Read))
|
|
||||||
{
|
|
||||||
fs.CopyTo(templateStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
templateStream.Position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
var memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
var config = new OpenXmlConfiguration()
|
|
||||||
{
|
|
||||||
IgnoreTemplateParameterMissing = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), data, config);
|
|
||||||
|
|
||||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
|
||||||
|
|
||||||
|
|
||||||
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
||||||
{
|
|
||||||
FileDownloadName = $"{(string.IsNullOrEmpty(exportFileNamePrefix) ? "" : exportFileNamePrefix + "_")}{Path.GetFileNameWithoutExtension(fileName)}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出文件模板
|
/// 导出文件模板
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1250,7 +1159,4 @@ public static class ExcelExportHelper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using MassTransit.Mediator;
|
using MassTransit.Mediator;
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper
|
namespace IRaCIS.Core.Application.Helper
|
||||||
{
|
{
|
||||||
@@ -58,29 +57,25 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void AddOrUpdateTrialCronJob(string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron,string defaultCulture="")
|
public static void AddOrUpdateTrialCronJob(string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron)
|
||||||
{
|
{
|
||||||
if (defaultCulture == "")
|
|
||||||
{
|
|
||||||
defaultCulture = CultureInfo.CurrentCulture.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (businessScenario)
|
switch (businessScenario)
|
||||||
{
|
{
|
||||||
|
|
||||||
case EmailBusinessScenario.QCTask:
|
case EmailBusinessScenario.QCTask:
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new ImageQCRecurringEvent() { TrialId = trialId,CultureInfoName= defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new ImageQCRecurringEvent() { TrialId = trialId }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
case EmailBusinessScenario.CRCToQCQuestion:
|
case EmailBusinessScenario.CRCToQCQuestion:
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new CRCImageQuestionRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new CRCImageQuestionRecurringEvent() { TrialId = trialId }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
case EmailBusinessScenario.QCToCRCImageQuestion:
|
case EmailBusinessScenario.QCToCRCImageQuestion:
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new QCImageQuestionRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new QCImageQuestionRecurringEvent() { TrialId = trialId }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
//加急阅片 10分钟
|
//加急阅片 10分钟
|
||||||
case EmailBusinessScenario.ExpeditedReading:
|
case EmailBusinessScenario.ExpeditedReading:
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -88,25 +83,20 @@ namespace IRaCIS.Core.Application.Helper
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron, string defaultCulture="")
|
public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron)
|
||||||
{
|
{
|
||||||
if (defaultCulture == "")
|
|
||||||
{
|
|
||||||
defaultCulture = CultureInfo.CurrentCulture.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (businessScenario)
|
switch (businessScenario)
|
||||||
{
|
{
|
||||||
|
|
||||||
case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
|
case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
|
||||||
|
|
||||||
|
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { CultureInfoName = defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
case EmailBusinessScenario.TrialTraining_ExpirationNotification:
|
case EmailBusinessScenario.TrialTraining_ExpirationNotification:
|
||||||
|
|
||||||
Console.WriteLine("更新项目到期job");
|
Console.WriteLine("更新项目到期job");
|
||||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { CultureInfoName = defaultCulture }, default), emailCron);
|
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { }, default), emailCron);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,106 +0,0 @@
|
|||||||
using IdentityModel;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using RestSharp;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper.OtherTool;
|
|
||||||
|
|
||||||
|
|
||||||
public class WeComAlert
|
|
||||||
{
|
|
||||||
public string Env { get; set; } = "";
|
|
||||||
public string UserName { get; set; } = "";
|
|
||||||
public string Api { get; set; } = "";
|
|
||||||
public string Message { get; set; } = "";
|
|
||||||
public string? JsonData { get; set; }
|
|
||||||
public string? Stack { get; set; }
|
|
||||||
public bool HasStack => !string.IsNullOrWhiteSpace(Stack);
|
|
||||||
public string[] AtUsers { get; set; } = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class WeComNotifier
|
|
||||||
{
|
|
||||||
|
|
||||||
public static async Task SendAlertAsync(string webhook, WeComAlert alert)
|
|
||||||
{
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
await Task.CompletedTask;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var client = new RestClient();
|
|
||||||
var request = new RestRequest(webhook, Method.Post);
|
|
||||||
|
|
||||||
var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
// 处理 @
|
|
||||||
var atText = alert.AtUsers != null && alert.AtUsers.Any()
|
|
||||||
? string.Join("", alert.AtUsers.Select(u => $" <@{u}>"))
|
|
||||||
: "";
|
|
||||||
|
|
||||||
// 处理堆栈
|
|
||||||
var stack = alert.Stack;
|
|
||||||
if (!string.IsNullOrWhiteSpace(stack))
|
|
||||||
{
|
|
||||||
stack = stack.Replace("\n", "\n> ");
|
|
||||||
if (stack.Length > 600)
|
|
||||||
stack = stack[..600] + "...(已截断)";
|
|
||||||
}
|
|
||||||
|
|
||||||
var markdown = $@"## 🚨 系统告警
|
|
||||||
> {atText}
|
|
||||||
> **部署环境:** [{alert.Env}]({alert.Env})
|
|
||||||
> **发生时间:** {time}
|
|
||||||
> **操作人:** {alert.UserName}
|
|
||||||
> **接口地址:** {alert.Api}
|
|
||||||
### ❗ 告警信息
|
|
||||||
<font color=""warning"">{alert.Message}</font>";
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(alert.JsonData))
|
|
||||||
{
|
|
||||||
markdown += $@"
|
|
||||||
> **📦 请求数据(JSON 格式):**
|
|
||||||
```json
|
|
||||||
{alert.JsonData}
|
|
||||||
```";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(stack))
|
|
||||||
{
|
|
||||||
markdown += $@"
|
|
||||||
### 堆栈信息(部分)
|
|
||||||
<font color=""comment"">{stack}</font>";
|
|
||||||
}
|
|
||||||
|
|
||||||
var payload = new
|
|
||||||
{
|
|
||||||
msgtype = "markdown",
|
|
||||||
markdown = new { content = markdown }
|
|
||||||
};
|
|
||||||
|
|
||||||
request.AddHeader("Content-Type", "application/json");
|
|
||||||
request.AddStringBody(JsonConvert.SerializeObject(payload), DataFormat.Json);
|
|
||||||
|
|
||||||
await client.ExecuteAsync(request);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Logger.Error("企业微信告警发送失败: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -33,37 +33,38 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
|
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.2.0" />
|
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
|
||||||
|
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.1.3" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="4.0.21" />
|
<PackageReference Include="AWSSDK.S3" Version="4.0.4.1" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.5.19" />
|
<PackageReference Include="DocX" Version="4.0.25105.5786" />
|
||||||
<PackageReference Include="DocX" Version="5.0.0" />
|
|
||||||
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
||||||
<PackageReference Include="ExcelDataReader" Version="3.8.0" />
|
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
|
||||||
<PackageReference Include="ExcelDataReader.DataSet" Version="3.8.0" />
|
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
|
||||||
<PackageReference Include="DistributedLock.Redis" Version="1.1.1" />
|
<PackageReference Include="DistributedLock.Redis" Version="1.1.0" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.7" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.2.6" />
|
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.6" />
|
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.7" />
|
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||||
<PackageReference Include="IP2Region.Net" Version="3.0.2" />
|
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
|
||||||
<PackageReference Include="MailKit" Version="4.15.1" />
|
<PackageReference Include="MailKit" Version="4.11.0" />
|
||||||
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.1.0" />
|
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
|
||||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.4.1" />
|
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||||
<PackageReference Include="MimeKit" Version="4.15.1" />
|
<PackageReference Include="MimeKit" Version="4.11.0" />
|
||||||
<PackageReference Include="MiniExcel" Version="1.41.2" />
|
<PackageReference Include="MiniExcel" Version="1.41.2" />
|
||||||
<PackageReference Include="Minio" Version="6.0.3" />
|
<PackageReference Include="Minio" Version="6.0.3" />
|
||||||
<PackageReference Include="MiniWord" Version="0.9.2" />
|
<PackageReference Include="MiniWord" Version="0.9.2" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||||
<TreatAsUsed>true</TreatAsUsed>
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NPOI" Version="2.7.4" />
|
<PackageReference Include="NPOI" Version="2.7.4" />
|
||||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||||
<PackageReference Include="RestSharp" Version="114.0.0" />
|
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
|
||||||
|
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -74,8 +75,4 @@
|
|||||||
<Folder Include="Service\MinimalApiService\CodeTemplate\FrontTemplate\" />
|
<Folder Include="Service\MinimalApiService\CodeTemplate\FrontTemplate\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Service\TrialSiteUser\TrialStatService.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,8 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using MiniExcelLibs.Attributes;
|
||||||
using MiniExcelLibs.Attributes;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.MassTransit.Command
|
namespace IRaCIS.Core.Application.MassTransit.Command
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 全量一致性核查
|
|
||||||
/// </summary>
|
|
||||||
public record ConsistenFullCheckCommand
|
|
||||||
{
|
|
||||||
public List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
|
|
||||||
|
|
||||||
public Guid TrialId { get; set; }
|
|
||||||
|
|
||||||
public Guid InspectionFileId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public record ConsistenCheckCommand
|
public record ConsistenCheckCommand
|
||||||
{
|
{
|
||||||
public List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
|
public List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
|
||||||
@@ -30,26 +17,13 @@ namespace IRaCIS.Core.Application.MassTransit.Command
|
|||||||
|
|
||||||
public class CheckDBModel : CheckViewModel
|
public class CheckDBModel : CheckViewModel
|
||||||
{
|
{
|
||||||
|
|
||||||
public Guid SubjectVisitId { get; set; }
|
public Guid SubjectVisitId { get; set; }
|
||||||
|
|
||||||
public Guid StudyId { get; set; }
|
public Guid StudyId { get; set; }
|
||||||
|
|
||||||
public string SiteCounty { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FullCheckResult: CheckViewModel
|
|
||||||
{
|
|
||||||
public string LatestScanDateStr { get; set; } = string.Empty;
|
|
||||||
public string Modalitys { get; set; } = string.Empty;
|
|
||||||
public DateTime CheckTime { get; set; }
|
|
||||||
|
|
||||||
public string CheckResult { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
[DictionaryTranslateAttribute("CheckState")]
|
|
||||||
public CheckStateEnum CheckState { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//[ExcelImporter(/*ImportResultFilter = typeof(ImportResultFilteTest),*/ IsLabelingError = true)]
|
//[ExcelImporter(/*ImportResultFilter = typeof(ImportResultFilteTest),*/ IsLabelingError = true)]
|
||||||
@@ -88,13 +62,8 @@ namespace IRaCIS.Core.Application.MassTransit.Command
|
|||||||
[ExcelColumnName("Modality")]
|
[ExcelColumnName("Modality")]
|
||||||
public string Modality { get; set; } = string.Empty;
|
public string Modality { get; set; } = string.Empty;
|
||||||
|
|
||||||
#region 全量一致性核查加入
|
|
||||||
[DictionaryTranslateAttribute("Subject_Visit_Status")]
|
|
||||||
public SubjectStatus SubjectStatus { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,14 +21,12 @@ public static class CommonEmailHelper
|
|||||||
/// <param name="configInfo"></param>
|
/// <param name="configInfo"></param>
|
||||||
/// <param name="messageToSend"></param>
|
/// <param name="messageToSend"></param>
|
||||||
/// <param name="emailFunc"></param>
|
/// <param name="emailFunc"></param>
|
||||||
/// <param name="userWorkLanguage"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public static async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailNoticeConfig configInfo, MimeMessage messageToSend,
|
public static async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailNoticeConfig configInfo, MimeMessage messageToSend,
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc, UserWorkLanguage? userWorkLanguage = null)
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
|
||||||
{
|
{
|
||||||
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
bool isEn_US = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
||||||
|
|
||||||
@@ -62,14 +60,13 @@ Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr
|
|||||||
/// <param name="configInfo"></param>
|
/// <param name="configInfo"></param>
|
||||||
/// <param name="messageToSend"></param>
|
/// <param name="messageToSend"></param>
|
||||||
/// <param name="emailFunc"></param>
|
/// <param name="emailFunc"></param>
|
||||||
/// <param name="userWorkLanguage"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public static async Task<TrialEmailNoticeConfig> GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(TrialEmailNoticeConfig configInfo, MimeMessage messageToSend,
|
public static async Task<TrialEmailNoticeConfig> GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(TrialEmailNoticeConfig configInfo, MimeMessage messageToSend,
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc, UserWorkLanguage? userWorkLanguage = null)
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
|
||||||
{
|
{
|
||||||
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
bool isEn_US = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
var (topicStr, htmlBodyStr) = isEn_US ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
||||||
|
|
||||||
@@ -97,20 +94,12 @@ Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr
|
|||||||
return configInfo;
|
return configInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReplacePlatformName(SystemEmailSendConfig _systemEmailConfig, string needDealtxt, UserWorkLanguage? userWorkLanguage = null)
|
|
||||||
|
|
||||||
|
|
||||||
|
public static string ReplaceCompanyName(SystemEmailSendConfig _systemEmailConfig, string needDealtxt)
|
||||||
{
|
{
|
||||||
var isEn_US = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
var platformName = isEn_US ? _systemEmailConfig.PlatformName : _systemEmailConfig.PlatformNameCN;
|
|
||||||
|
|
||||||
var str = needDealtxt.Replace("{platformName}", platformName);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static string ReplaceCompanyName(SystemEmailSendConfig _systemEmailConfig, string needDealtxt, UserWorkLanguage? userWorkLanguage = null)
|
|
||||||
{
|
|
||||||
var isEn_US = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
var str = needDealtxt.Replace("{company}", isEn_US ? _systemEmailConfig.CompanyName : _systemEmailConfig.CompanyNameCN)
|
var str = needDealtxt.Replace("{company}", isEn_US ? _systemEmailConfig.CompanyName : _systemEmailConfig.CompanyNameCN)
|
||||||
.Replace("{company abbreviation}", isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN);
|
.Replace("{company abbreviation}", isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN);
|
||||||
|
|||||||
@@ -1,52 +1,53 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using IRaCIS.Application.Contracts;
|
|
||||||
using IRaCIS.Application.Interfaces;
|
using IRaCIS.Application.Interfaces;
|
||||||
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
|
|
||||||
using IRaCIS.Core.Application.Contracts;
|
|
||||||
using IRaCIS.Core.Application.Contracts.DTO;
|
using IRaCIS.Core.Application.Contracts.DTO;
|
||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
using IRaCIS.Core.Application.MassTransit.Command;
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using MaxMind.GeoIP2.Model;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.MassTransit.Consumer
|
namespace IRaCIS.Core.Application.MassTransit.Consumer
|
||||||
{
|
{
|
||||||
public class ConsistencyCheckConsumer(
|
public class ConsistencyCheckConsumer : IConsumer<ConsistenCheckCommand>
|
||||||
IRepository<DicomStudy> _studyRepository,
|
|
||||||
IUserInfo _userInfo,
|
|
||||||
IRepository<Subject> _subjectRepository,
|
|
||||||
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
|
||||||
IRepository<SubjectVisit> _subjectVisitRepository,
|
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
|
||||||
IOSSService _oSSService,
|
|
||||||
IMapper _mapper,
|
|
||||||
IDictionaryService _dictionaryService,
|
|
||||||
IRepository<CommonDocument> _commonDocumentRepository,
|
|
||||||
IStringLocalizer _localizer,
|
|
||||||
IWebHostEnvironment _hostEnvironment,
|
|
||||||
IRepository<InspectionFile> _inspectionFileRepository,
|
|
||||||
IOptionsMonitor<SystemEmailSendConfig> _systemEmailSendConfig
|
|
||||||
) : IConsumer<ConsistenCheckCommand>, IConsumer<ConsistenFullCheckCommand>
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private readonly IRepository<DicomStudy> _studyRepository;
|
||||||
|
private readonly IUserInfo _userInfo;
|
||||||
|
private readonly IRepository<Subject> _subjectRepository;
|
||||||
|
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
|
||||||
|
private readonly IRepository<TrialSite> _trialSiteRepository;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
|
||||||
|
public IStringLocalizer _localizer { get; set; }
|
||||||
|
|
||||||
|
private readonly SystemEmailSendConfig _systemEmailConfig;
|
||||||
|
|
||||||
private readonly SystemEmailSendConfig _systemEmailConfig = _systemEmailSendConfig.CurrentValue;
|
private readonly IRepository<Dictionary> _dictionaryRepository;
|
||||||
|
/// <summary>
|
||||||
|
/// 构造函数注入
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public ConsistencyCheckConsumer(IRepository<DicomStudy> studyRepository, IUserInfo userInfo,
|
||||||
|
IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository,
|
||||||
|
IRepository<TrialSite> trialSiteRepository, IRepository<NoneDicomStudy> noneDicomStudyRepository,
|
||||||
|
IMapper mapper, IStringLocalizer localizer, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig, IRepository<Dictionary> dictionaryRepository)
|
||||||
|
{
|
||||||
|
_noneDicomStudyRepository = noneDicomStudyRepository;
|
||||||
|
_studyRepository = studyRepository;
|
||||||
|
_userInfo = userInfo;
|
||||||
|
_subjectRepository = subjectRepository;
|
||||||
|
_subjectVisitRepository = subjectVisitRepository;
|
||||||
|
_trialSiteRepository = trialSiteRepository;
|
||||||
|
_mapper = mapper;
|
||||||
|
_localizer = localizer;
|
||||||
|
|
||||||
|
_systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
|
_dictionaryRepository = dictionaryRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -66,8 +67,8 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
|
|
||||||
//subjectVisitLambda2= subjectVisitLambda2.And(x => x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
|
//subjectVisitLambda2= subjectVisitLambda2.And(x => x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
|
||||||
|
|
||||||
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId && x.Subject.IsSubjectQuit == false && x.AuditState == AuditStateEnum.QCPassed &&
|
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId && x.Subject.IsSubjectQuit == false &&
|
||||||
(x.CheckState == CheckStateEnum.ToCheck || x.CheckState == CheckStateEnum.CVIng);
|
(x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
|
||||||
|
|
||||||
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
||||||
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
|
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
|
||||||
@@ -81,8 +82,6 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
Modality = study.ModalityForEdit,
|
Modality = study.ModalityForEdit,
|
||||||
SubjectCode = subject.Code,
|
SubjectCode = subject.Code,
|
||||||
VisitName = sv.VisitName,
|
VisitName = sv.VisitName,
|
||||||
|
|
||||||
SiteCounty = sv.TrialSite.Country,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var noneDicomQuey = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
var noneDicomQuey = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
||||||
@@ -97,8 +96,6 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
Modality = noneDicomStudy.Modality,
|
Modality = noneDicomStudy.Modality,
|
||||||
SubjectCode = subject.Code,
|
SubjectCode = subject.Code,
|
||||||
VisitName = sv.VisitName,
|
VisitName = sv.VisitName,
|
||||||
|
|
||||||
SiteCounty = sv.TrialSite.Country,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var dbList = (await dicomQuery.ToListAsync()).Union(await noneDicomQuey.ToListAsync()).ToList();
|
var dbList = (await dicomQuery.ToListAsync()).Union(await noneDicomQuey.ToListAsync()).ToList();
|
||||||
@@ -120,27 +117,12 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
foreach (var sv in svExcelGroup)
|
foreach (var sv in svExcelGroup)
|
||||||
{
|
{
|
||||||
|
|
||||||
//Excel 的数据 在IRC 中可以找到该访视(一致性核查中,或者待核查)
|
//Excel 的数据 在IRC 中可以找到该访视
|
||||||
if (dbCheckList.Any(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName))
|
if (dbCheckList.Any(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName))
|
||||||
{
|
{
|
||||||
|
|
||||||
var dbVisitStudyList = dbList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
var dbVisitStudyList = dbList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
||||||
|
|
||||||
//设置当前中心语言
|
|
||||||
|
|
||||||
var isEn_us = dbVisitStudyList.First().SiteCounty == StaticData.SiteCountry.US;
|
|
||||||
|
|
||||||
var cultureInfoName = StaticData.CultureInfo.en_US;
|
|
||||||
|
|
||||||
if (isEn_us == false)
|
|
||||||
{
|
|
||||||
cultureInfoName = StaticData.CultureInfo.zh_CN;
|
|
||||||
}
|
|
||||||
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(cultureInfoName);
|
|
||||||
CultureInfo.CurrentUICulture = new CultureInfo(cultureInfoName);
|
|
||||||
|
|
||||||
|
|
||||||
//找到etc 当前visit site 和subject 一致的检查列表
|
//找到etc 当前visit site 和subject 一致的检查列表
|
||||||
var etcVisitStudyList = etcList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
var etcVisitStudyList = etcList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
||||||
|
|
||||||
@@ -219,7 +201,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
|
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
|
||||||
|
|
||||||
// excel 存在
|
// excel 存在
|
||||||
var excelExceptDB = etcVisitStudyList.Except(dbVisitStudyList);
|
var excelExceptDB = etcVisitStudyList.Except(dbCheckList);
|
||||||
|
|
||||||
//ETC 和系统的完全一致 两者没有差别
|
//ETC 和系统的完全一致 两者没有差别
|
||||||
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
|
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
|
||||||
@@ -319,169 +301,12 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||||||
}
|
}
|
||||||
await _subjectVisitRepository.SaveChangesAsync();
|
await _subjectVisitRepository.SaveChangesAsync();
|
||||||
|
|
||||||
|
//await context.RespondAsync<ConsistenCheckResult>(new
|
||||||
|
//{
|
||||||
|
|
||||||
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Consume(ConsumeContext<ConsistenFullCheckCommand> context)
|
|
||||||
{
|
|
||||||
var inspectionFileId = context.Message.InspectionFileId;
|
|
||||||
var trialId = context.Message.TrialId;
|
|
||||||
|
|
||||||
//系统定义MRI 到底是MR 还是MRI
|
|
||||||
var mriModality = await _dictionaryRepository.Where(t => t.Parent.Code == "Modality").Where(t => t.Code == "MRI").Select(t => t.Value).FirstNotNullAsync();
|
|
||||||
|
|
||||||
//处理Excel大小写
|
|
||||||
context.Message.ETCList.ForEach(t => { t.Modality = t.Modality.ToUpper().Trim(); t.StudyDate = Convert.ToDateTime(t.StudyDate).ToString("yyyy-MM-dd"); t.SiteCode = t.SiteCode.ToUpper().Trim(); t.VisitName = t.VisitName.ToUpper().Trim(); t.SubjectCode = t.SubjectCode.ToUpper().Trim(); });
|
|
||||||
var etcList = context.Message.ETCList;
|
|
||||||
|
|
||||||
|
|
||||||
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId /*&& x.Subject.IsSubjectQuit == false*/ && x.AuditState == AuditStateEnum.QCPassed;
|
|
||||||
|
|
||||||
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
|
||||||
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
|
|
||||||
join study in _studyRepository.AsQueryable() on sv.Id equals study.SubjectVisitId
|
|
||||||
select new CheckDBModel()
|
|
||||||
{
|
|
||||||
SubjectStatus = sv.Subject.Status,
|
|
||||||
SubjectVisitId = sv.Id,
|
|
||||||
SiteCode = sv.TrialSite.TrialSiteCode,
|
|
||||||
StudyDate = study.StudyTime == null ? string.Empty : ((DateTime)study.StudyTime).ToString("yyyy-MM-dd"),
|
|
||||||
StudyId = study.Id,
|
|
||||||
Modality = study.ModalityForEdit,
|
|
||||||
SubjectCode = subject.Code,
|
|
||||||
VisitName = sv.VisitName,
|
|
||||||
};
|
|
||||||
|
|
||||||
var noneDicomQuey = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
|
||||||
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
|
|
||||||
join noneDicomStudy in _noneDicomStudyRepository.Where(t => t.FileCount > 0) on sv.Id equals noneDicomStudy.SubjectVisitId
|
|
||||||
select new CheckDBModel()
|
|
||||||
{
|
|
||||||
SubjectStatus = sv.Subject.Status,
|
|
||||||
SubjectVisitId = sv.Id,
|
|
||||||
SiteCode = sv.TrialSite.TrialSiteCode,
|
|
||||||
StudyDate = noneDicomStudy.ImageDate.ToString("yyyy-MM-dd"),
|
|
||||||
StudyId = noneDicomStudy.Id,
|
|
||||||
Modality = noneDicomStudy.Modality,
|
|
||||||
SubjectCode = subject.Code,
|
|
||||||
VisitName = sv.VisitName,
|
|
||||||
};
|
|
||||||
|
|
||||||
var dbList = (await dicomQuery.ToListAsync()).Union(await noneDicomQuey.ToListAsync()).ToList();
|
|
||||||
|
|
||||||
//处理数据库 大小写
|
|
||||||
dbList.ForEach(t => { t.Modality = t.Modality.ToUpper().Trim(); t.SiteCode = t.SiteCode.ToUpper().Trim(); t.VisitName = t.VisitName.ToUpper().Trim(); t.SubjectCode = t.SubjectCode.ToUpper().Trim(); });
|
|
||||||
|
|
||||||
var dbCheckList = _mapper.Map<List<CheckViewModel>>(dbList);
|
|
||||||
|
|
||||||
|
|
||||||
//按照Excel数据访视分组 按照数据库的数据 一个个的访视对比
|
|
||||||
var svExcelGroup = etcList.GroupBy(t => new { t.SiteCode, t.SubjectCode, t.VisitName })
|
|
||||||
.Select(g => new { g.Key.SubjectCode, g.Key.VisitName, g.Key.SiteCode, ExcelStudyList = g.ToList() }).ToList();
|
|
||||||
|
|
||||||
var fullCheckResultList = new List<FullCheckResult>();
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var sv in svExcelGroup)
|
|
||||||
{
|
|
||||||
|
|
||||||
//Excel 的数据 在IRC 中可以找到该访视(一致性核查中,或者待核查)
|
|
||||||
if (dbCheckList.Any(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName))
|
|
||||||
{
|
|
||||||
|
|
||||||
var dbVisitStudyList = dbList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
|
||||||
|
|
||||||
//找到etc 当前visit site 和subject 一致的检查列表
|
|
||||||
var etcVisitStudyList = etcList.Where(t => t.SubjectCode == sv.SubjectCode && t.SiteCode == sv.SiteCode && t.VisitName == sv.VisitName).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
//以我们系统数据库为准 ,判断是MR 还是MRI, 把Excel 里的MR 或者MRI 处理成一致,MR MRI 是一致的
|
|
||||||
foreach (var item in etcVisitStudyList)
|
|
||||||
{
|
|
||||||
if (item.Modality == "MR" || item.Modality == "MRI")
|
|
||||||
{
|
|
||||||
item.Modality = mriModality;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//etc 和数据库 并集
|
|
||||||
var unionList = dbVisitStudyList.Union(etcVisitStudyList);
|
|
||||||
// 数据库存在
|
|
||||||
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
|
|
||||||
|
|
||||||
// excel 存在
|
|
||||||
var excelExceptDB = etcVisitStudyList.Except(dbVisitStudyList);
|
|
||||||
|
|
||||||
var dbCurrentVisitFirst = dbVisitStudyList.First();
|
|
||||||
|
|
||||||
//ETC 和系统的完全一致 两者没有差别
|
|
||||||
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
//每个受试者每个访视加一条记录
|
|
||||||
fullCheckResultList.Add(new FullCheckResult()
|
|
||||||
{
|
|
||||||
SubjectStatus = dbCurrentVisitFirst.SubjectStatus,
|
|
||||||
CheckTime = DateTime.Now,
|
|
||||||
CheckState = CheckStateEnum.CVPassed,
|
|
||||||
SiteCode = dbCurrentVisitFirst.SiteCode,
|
|
||||||
SubjectCode = dbCurrentVisitFirst.SubjectCode,
|
|
||||||
VisitName = dbCurrentVisitFirst.VisitName,
|
|
||||||
Modalitys = string.Join('、', dbVisitStudyList.Select(t => t.Modality)),
|
|
||||||
LatestScanDateStr = dbVisitStudyList.Select(t => t.StudyDate).MaxBy(d => DateTime.Parse(d)) ?? ""
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var checkResult =
|
|
||||||
String.Join(" | ", dbExceptExcel.Select(t => $"{_localizer["ConsistencyVerification_EdcL", t.StudyDate, t.Modality/*, _systemEmailConfig.SystemShortName*/]}")) + " | "
|
|
||||||
+ String.Join(" | ", excelExceptDB.Select(t => $"{_localizer["ConsistencyVerification_IrcLi", t.StudyDate, t.Modality, _systemEmailConfig.SystemShortName]}"));
|
|
||||||
|
|
||||||
//每个受试者每个访视加一条记录
|
|
||||||
fullCheckResultList.Add(new FullCheckResult()
|
|
||||||
{
|
|
||||||
SubjectStatus = dbCurrentVisitFirst.SubjectStatus,
|
|
||||||
CheckState = CheckStateEnum.None,
|
|
||||||
CheckTime = DateTime.Now,
|
|
||||||
SiteCode = dbCurrentVisitFirst.SiteCode,
|
|
||||||
SubjectCode = dbCurrentVisitFirst.SubjectCode,
|
|
||||||
VisitName = dbCurrentVisitFirst.VisitName,
|
|
||||||
Modalitys = string.Join('、', dbVisitStudyList.Select(t => t.Modality)),
|
|
||||||
LatestScanDateStr = dbVisitStudyList.Select(t => t.StudyDate).MaxBy(d => DateTime.Parse(d)) ?? "",
|
|
||||||
CheckResult = checkResult
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//导到Excel 上传oss 回更记录状态
|
|
||||||
|
|
||||||
var list = fullCheckResultList;
|
|
||||||
|
|
||||||
var exportInfo = new ExcelExportInfo();
|
|
||||||
|
|
||||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
|
||||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
|
||||||
|
|
||||||
var fileStreamResult = (FileStreamResult)await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialConsistentFUllCheckList_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(FullCheckResult));
|
|
||||||
|
|
||||||
var ossRelativePath = await _oSSService.UploadToOSSAsync(fileStreamResult.FileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", "DataReconciliation", uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DataReconciliation });
|
|
||||||
|
|
||||||
|
|
||||||
//var add = await _inspectionFileRepository.FindAsync(inspectionFileId);
|
|
||||||
//add.CheckState = EDCCheckState.Success;
|
|
||||||
//add.ResultPath = ossRelativePath;
|
|
||||||
|
|
||||||
//更新
|
|
||||||
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Success, ResultPath = ossRelativePath });
|
|
||||||
|
|
||||||
await _subjectVisitRepository.SaveChangesAsync();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,16 +27,5 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer.Dto
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SendEmailUserDto
|
|
||||||
{
|
|
||||||
public UserTypeEnum UserTypeEnum { get; set; }
|
|
||||||
|
|
||||||
public string FullName { get; set; }
|
|
||||||
|
|
||||||
public UserWorkLanguage UserWorkLanguage { get; set; }
|
|
||||||
|
|
||||||
public string EMail { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ public class ImageConsumer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送影像重传相关邮件的通用方法 已经处理项目
|
/// 发送影像重传相关邮件的通用方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task SendImageReuploadEmail(SendImageReuploadEmailInDto inDto)
|
private async Task SendImageReuploadEmail(SendImageReuploadEmailInDto inDto)
|
||||||
{
|
{
|
||||||
@@ -273,30 +273,15 @@ public class ImageConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 根据不同场景获取不同角色的用户 先排除CRC和CRA
|
// 根据不同场景获取不同角色的用户 先排除CRC和CRA
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == inDto.TrialId && !x.TrialUser.IsDeleted && !filterUserTypeList.Contains(x.UserRole.UserTypeEnum) ).Include(x => x.UserRole).Select(x => x.UserRole)
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == inDto.TrialId && !x.TrialUser.IsDeleted && !filterUserTypeList.Contains(x.UserRole.UserTypeEnum) ).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(x => new SendEmailUserDto()
|
|
||||||
{
|
|
||||||
UserTypeEnum = x.UserTypeEnum,
|
|
||||||
FullName = x.FullName,
|
|
||||||
UserWorkLanguage = x.IdentityUser.UserWorkLanguage,
|
|
||||||
EMail=x.EMail,
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// CRC和CRA单独取
|
// CRC和CRA单独取
|
||||||
var crcAndcraUserList = await _trialSiteRepository.Where(x => x.Id == inDto.SubjectVisit.TrialSiteId).SelectMany(x => x.CRCUserList.Select(y => y.UserRole))
|
var crcAndcraUserList = await _trialSiteRepository.Where(x => x.Id == inDto.SubjectVisit.TrialSiteId).SelectMany(x => x.CRCUserList.Select(y => y.UserRole)).ToListAsync();
|
||||||
.Select(x => new SendEmailUserDto()
|
|
||||||
{
|
|
||||||
UserTypeEnum = x.UserTypeEnum,
|
|
||||||
FullName = x.FullName,
|
|
||||||
UserWorkLanguage = x.IdentityUser.UserWorkLanguage,
|
|
||||||
EMail = x.EMail,
|
|
||||||
}).ToListAsync();
|
|
||||||
trialUserList.AddRange(crcAndcraUserList);
|
trialUserList.AddRange(crcAndcraUserList);
|
||||||
|
|
||||||
// 根据场景确定收件人
|
// 根据场景确定收件人
|
||||||
List<SendEmailUserDto> toUserList = new List<SendEmailUserDto>();
|
List<UserRole> toUserList = new List<UserRole>();
|
||||||
List<SendEmailUserDto> ccUserList = new List<SendEmailUserDto>();
|
List<UserRole> ccUserList = new List<UserRole>();
|
||||||
|
|
||||||
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == inDto.EmailNoticeConfig.Id).ToListAsync();
|
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == inDto.EmailNoticeConfig.Id).ToListAsync();
|
||||||
var userTypeEnumList = emailNoticeUserList.Select(x => x.UserType).ToList();
|
var userTypeEnumList = emailNoticeUserList.Select(x => x.UserType).ToList();
|
||||||
@@ -349,55 +334,40 @@ public class ImageConsumer(
|
|||||||
DictionaryList = dictionaryDtos
|
DictionaryList = dictionaryDtos
|
||||||
});
|
});
|
||||||
|
|
||||||
|
foreach (var userinfo in toUserList)
|
||||||
var userWorkLanguageList = toUserList.Select(x => x.UserWorkLanguage).Distinct().ToList();
|
|
||||||
|
|
||||||
foreach (var workLanguage in userWorkLanguageList)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
var userinfoList = toUserList.Where(x => x.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
// 发件地址
|
// 发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 添加抄送
|
// 添加抄送
|
||||||
foreach (var ccUser in ccUserList)
|
foreach (var ccUser in ccUserList)
|
||||||
{
|
{
|
||||||
messageToSend.Cc.Add(new MailboxAddress(ccUser.FullName, ccUser.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, ccUser.EMail));
|
||||||
}
|
}
|
||||||
|
|
||||||
var userNames = userinfoList.Select(x => x.FullName).ToList();
|
|
||||||
|
|
||||||
// 格式化邮件内容
|
// 格式化邮件内容
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var subjectCode = inDto.SubjectVisit.Subject.Code;
|
var subjectCode = inDto.SubjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, inDto.SubjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, inDto.SubjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames), // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
inDto.SubjectVisit.VisitName, // 访视 {3}
|
inDto.SubjectVisit.VisitName, // 访视 {3}
|
||||||
dictionValue[0], // 是否加急 {4}
|
dictionValue[0], // 是否加急 {4}
|
||||||
dictionValue[1], // 审批结果 {5}
|
dictionValue[1], // 审批结果 {5}
|
||||||
_systemEmailConfig.SiteUrl // 链接 {6}
|
_systemEmailConfig.SiteUrl // 链接 {6}
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(inDto.EmailNoticeConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(inDto.EmailNoticeConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +434,7 @@ public class ImageConsumer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 发送阅片人筛选相关邮件的通用方法 已经处理项目
|
/// 发送阅片人筛选相关邮件的通用方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task SendReviewerSelectionEmail(EmailNoticeConfig emailNoticeConfig, Guid trialId, List<Guid> enrollIdList)
|
private async Task SendReviewerSelectionEmail(EmailNoticeConfig emailNoticeConfig, Guid trialId, List<Guid> enrollIdList)
|
||||||
{
|
{
|
||||||
@@ -474,19 +444,11 @@ public class ImageConsumer(
|
|||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
|
|
||||||
// 根据不同场景获取不同角色的用户
|
// 根据不同场景获取不同角色的用户
|
||||||
var trialUser = await _trialUseRoleRepository.Where(x => x.TrialId == trialId && !x.TrialUser.IsDeleted).Include(x => x.UserRole).Select(x => x.UserRole)
|
var trialUser = await _trialUseRoleRepository.Where(x => x.TrialId == trialId && !x.TrialUser.IsDeleted).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(x => new SendEmailUserDto()
|
|
||||||
{
|
|
||||||
UserTypeEnum = x.UserTypeEnum,
|
|
||||||
FullName = x.FullName,
|
|
||||||
UserWorkLanguage = x.IdentityUser.UserWorkLanguage,
|
|
||||||
EMail = x.EMail,
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// 根据场景确定收件人
|
// 根据场景确定收件人
|
||||||
List<SendEmailUserDto> toUserList = new List<SendEmailUserDto>();
|
List<UserRole> toUserList = new List<UserRole>();
|
||||||
List<SendEmailUserDto> ccUserList = new List<SendEmailUserDto>();
|
List<UserRole> ccUserList = new List<UserRole>();
|
||||||
|
|
||||||
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == emailNoticeConfig.Id).ToListAsync();
|
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == emailNoticeConfig.Id).ToListAsync();
|
||||||
|
|
||||||
@@ -505,35 +467,26 @@ public class ImageConsumer(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userWorkLanguageList = toUserList.Select(x => x.UserWorkLanguage).Distinct().ToList();
|
foreach (var userinfo in toUserList)
|
||||||
|
|
||||||
foreach (var workLanguage in userWorkLanguageList)
|
|
||||||
{
|
{
|
||||||
var userinfoList = toUserList.Where(x => x.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
// 发件地址
|
// 发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加抄送
|
// 添加抄送
|
||||||
foreach (var ccUser in ccUserList)
|
foreach (var ccUser in ccUserList)
|
||||||
{
|
{
|
||||||
messageToSend.Cc.Add(new MailboxAddress(ccUser.FullName, ccUser.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, ccUser.EMail));
|
||||||
}
|
}
|
||||||
|
|
||||||
var userNames = userinfoList.Select(x => x.FullName).ToList();
|
|
||||||
|
|
||||||
// 格式化邮件内容
|
// 格式化邮件内容
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames), // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
"", // 受试者 {2} - 阅片人筛选不涉及受试者
|
"", // 受试者 {2} - 阅片人筛选不涉及受试者
|
||||||
"", // 访视 {3} - 阅片人筛选不涉及访视
|
"", // 访视 {3} - 阅片人筛选不涉及访视
|
||||||
@@ -545,9 +498,9 @@ public class ImageConsumer(
|
|||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailNoticeConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailNoticeConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
using IRaCIS.Core.Application.MassTransit.Command;
|
||||||
using IRaCIS.Core.Application.MassTransit.Consumer.Dto;
|
|
||||||
using IRaCIS.Core.Domain;
|
using IRaCIS.Core.Domain;
|
||||||
using IRaCIS.Core.Domain.BaseModel;
|
using IRaCIS.Core.Domain.BaseModel;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
@@ -69,7 +68,7 @@ public class UrgentMedicalReviewAddedEventConsumer(
|
|||||||
|
|
||||||
|
|
||||||
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
||||||
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).Include(x => x.IdentityUser).FirstOrDefaultAsync();
|
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
||||||
|
|
||||||
@@ -79,23 +78,22 @@ public class UrgentMedicalReviewAddedEventConsumer(
|
|||||||
|
|
||||||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var workLanguage = userinfo.IdentityUser?.UserWorkLanguage;
|
|
||||||
var userIsEn_US = workLanguage.HasValue ? workLanguage.Value == UserWorkLanguage.US : isEn_US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
DictionaryRepository = _dictionaryRepository,
|
||||||
IsEn_US = userIsEn_US,
|
IsEn_US = isEn_US,
|
||||||
|
|
||||||
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
DictionaryList = new List<DictionaryDto>()
|
||||||
@@ -112,7 +110,7 @@ public class UrgentMedicalReviewAddedEventConsumer(
|
|||||||
var subjectName = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
var subjectName = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectName, taskInfo.TaskBlindName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectName, taskInfo.TaskBlindName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
userinfo.FullName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
criterion.CriterionName, // 阅片标准 {2}
|
criterion.CriterionName, // 阅片标准 {2}
|
||||||
@@ -128,9 +126,9 @@ public class UrgentMedicalReviewAddedEventConsumer(
|
|||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +177,7 @@ public class UrgentIRRepliedMedicalReviewConsumer(
|
|||||||
|
|
||||||
|
|
||||||
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
||||||
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).Include(x => x.IdentityUser).FirstOrDefaultAsync();
|
var userinfo = await _userRoleRepository.Where(x => x.Id == medicalReview.MedicalManagerUserId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
||||||
|
|
||||||
@@ -189,24 +187,22 @@ public class UrgentIRRepliedMedicalReviewConsumer(
|
|||||||
|
|
||||||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var workLanguage = userinfo.IdentityUser?.UserWorkLanguage;
|
|
||||||
var userIsEn_US = workLanguage.HasValue ? workLanguage.Value == UserWorkLanguage.US : isEn_US;
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
DictionaryRepository = _dictionaryRepository,
|
||||||
IsEn_US = userIsEn_US,
|
IsEn_US = isEn_US,
|
||||||
|
|
||||||
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
DictionaryList = new List<DictionaryDto>()
|
||||||
@@ -223,7 +219,7 @@ public class UrgentIRRepliedMedicalReviewConsumer(
|
|||||||
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
userinfo.FullName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
criterion.CriterionName, // 阅片标准 {2}
|
criterion.CriterionName, // 阅片标准 {2}
|
||||||
@@ -238,9 +234,9 @@ public class UrgentIRRepliedMedicalReviewConsumer(
|
|||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -297,7 +293,7 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
|
|||||||
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
var criterion = await _readingQuestionCriterionTrialRepository.FirstOrDefaultAsync(x => x.Id == medicalReview.VisitTask.TrialReadingCriterionId);
|
||||||
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
var taskInfo = await _visitTaskRepository.Where(x => x.Id == medicalReview.VisitTaskId).Include(x => x.SourceSubjectVisit).Include(x => x.ReadModule).Include(x => x.Subject).FirstNotNullAsync();
|
||||||
|
|
||||||
var userinfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).Include(x => x.IdentityUser).FirstOrDefaultAsync();
|
var userinfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -307,25 +303,22 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
|
|||||||
|
|
||||||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var workLanguage = userinfo.IdentityUser?.UserWorkLanguage;
|
|
||||||
var userIsEn_US = workLanguage.HasValue ? workLanguage.Value == UserWorkLanguage.US : isEn_US;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == medicalReview.TrialId);
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
DictionaryRepository = _dictionaryRepository,
|
||||||
IsEn_US = userIsEn_US,
|
IsEn_US = isEn_US,
|
||||||
|
|
||||||
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
DictionaryList = new List<DictionaryDto>()
|
||||||
@@ -342,7 +335,7 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
|
|||||||
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
userinfo.FullName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
@@ -359,8 +352,9 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
|
|||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,15 +400,7 @@ public class UrgentIRApplyedReReadingConsumer(
|
|||||||
|
|
||||||
var doctorInfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
|
var doctorInfo = await _userRoleRepository.Where(x => x.Id == taskInfo.DoctorUserId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == taskInfo.TrialId && x.TrialUser.IsDeleted==false).Include(x => x.UserRole).Select(x => x.UserRole)
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == taskInfo.TrialId && x.TrialUser.IsDeleted==false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(x => new SendEmailUserDto()
|
|
||||||
{
|
|
||||||
UserTypeEnum = x.UserTypeEnum,
|
|
||||||
FullName = x.FullName,
|
|
||||||
UserWorkLanguage = x.IdentityUser.UserWorkLanguage,
|
|
||||||
EMail = x.EMail,
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ProjectManager || x.UserTypeEnum == UserTypeEnum.APM).ToList();
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ProjectManager || x.UserTypeEnum == UserTypeEnum.APM).ToList();
|
||||||
if (context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
|
if (context.Message.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
|
||||||
@@ -427,48 +413,37 @@ public class UrgentIRApplyedReReadingConsumer(
|
|||||||
|
|
||||||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == visitid).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == taskInfo.TrialId);
|
|
||||||
|
|
||||||
var userWorkLanguageList = userinfoList.Select(x => x.UserWorkLanguage).Distinct().ToList();
|
foreach (var userinfo in userinfoList)
|
||||||
|
|
||||||
foreach (var workLanguage in userWorkLanguageList)
|
|
||||||
{
|
{
|
||||||
var langUserinfoList = userinfoList.Where(x => x.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
if (!langUserinfoList.Any()) continue;
|
|
||||||
|
|
||||||
var userIsEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
|
||||||
{
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
|
||||||
IsEn_US = userIsEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
|
||||||
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), }, //任务类型
|
|
||||||
new DictionaryDto (){DictionaryCode= "RequestReReadingResult",EnumValue="0", }, //审批结果 都是待审批
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
foreach (var userinfo in langUserinfoList)
|
|
||||||
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == taskInfo.TrialId);
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
DictionaryRepository = _dictionaryRepository,
|
||||||
|
IsEn_US = isEn_US,
|
||||||
var userNames = langUserinfoList.Select(x => x.FullName).ToList();
|
DictionaryList = new List<DictionaryDto>()
|
||||||
|
{
|
||||||
|
new DictionaryDto (){DictionaryCode= "ReadingCategory",EnumValue=taskInfo.ReadingCategory.GetEnumInt(), }, //任务类型
|
||||||
|
new DictionaryDto (){DictionaryCode= "RequestReReadingResult",EnumValue="0", }, //审批结果 都是待审批
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
var subjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? taskInfo.Subject.Code : taskInfo.BlindSubjectCode;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, taskInfo.TaskBlindName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames), // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
taskInfo.TaskBlindName, // 访视 {3}
|
taskInfo.TaskBlindName, // 访视 {3}
|
||||||
@@ -477,14 +452,18 @@ public class UrgentIRApplyedReReadingConsumer(
|
|||||||
criterion.CriterionName, // 阅片标准 {6}
|
criterion.CriterionName, // 阅片标准 {6}
|
||||||
dictionValue[1], // 审批结果 {7}
|
dictionValue[1], // 审批结果 {7}
|
||||||
_systemEmailConfig.SiteUrl // 链接 {8}
|
_systemEmailConfig.SiteUrl // 链接 {8}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
using DocumentFormat.OpenXml.Spreadsheet;
|
||||||
using DocumentFormat.OpenXml.Vml;
|
using DocumentFormat.OpenXml.Vml;
|
||||||
using DocumentFormat.OpenXml.Wordprocessing;
|
using DocumentFormat.OpenXml.Wordprocessing;
|
||||||
using IRaCIS.Application.Contracts;
|
|
||||||
using IRaCIS.Core.Application.Contracts;
|
using IRaCIS.Core.Application.Contracts;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Command;
|
using IRaCIS.Core.Application.MassTransit.Command;
|
||||||
@@ -56,86 +55,74 @@ public class UserSiteSurveySubmitedEventConsumer(
|
|||||||
|
|
||||||
if (emailConfig != null)
|
if (emailConfig != null)
|
||||||
{
|
{
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
|
||||||
|
|
||||||
|
|
||||||
var trialUserList = await _trialUserRoleRepository.Where(t => t.TrialId == siteSurveyInfo.TrialId && t.TrialUser.IsDeleted == false)
|
var trialUserList = await _trialUserRoleRepository.Where(t => t.TrialId == siteSurveyInfo.TrialId && t.TrialUser.IsDeleted == false)
|
||||||
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
|
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
|
||||||
.Select(t => new { t.UserRole.FullName, t.UserRole.IdentityUser.EMail, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
.Select(t => new { t.UserRole.FullName, t.UserRole.IdentityUser.EMail, t.UserRole.UserTypeEnum }).ToListAsync();
|
||||||
|
|
||||||
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
|
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
|
||||||
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
|
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
|
||||||
|
|
||||||
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
var toUserName = string.Empty;
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
|
//有SPM
|
||||||
|
if (sPMOrCPMList.Count > 0)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
foreach (var user in sPMOrCPMList)
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
|
|
||||||
var toUserName = string.Empty;
|
|
||||||
|
|
||||||
//有SPM 并且参与
|
|
||||||
if (trialInfo.IsSPMJoinSiteSurvey && sPMOrCPMList.Count > 0)
|
|
||||||
{
|
{
|
||||||
var lan_SPMOrCPMList = sPMOrCPMList.Where(t => t.UserWorkLanguage == workLanguage);
|
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
||||||
|
|
||||||
foreach (var user in lan_SPMOrCPMList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
toUserName = string.Join('、', lan_SPMOrCPMList.Select(t => t.FullName));
|
|
||||||
|
|
||||||
foreach (var user in pmAndAPMList)
|
|
||||||
{
|
|
||||||
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var lan_pmAndAPMList = pmAndAPMList.Where(t => t.UserWorkLanguage == workLanguage);
|
|
||||||
|
|
||||||
foreach (var user in lan_pmAndAPMList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
toUserName = string.Join('、', lan_pmAndAPMList.Select(t => t.FullName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//发件地址
|
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
|
|
||||||
|
foreach (var user in pmAndAPMList)
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
}
|
||||||
toUserName,
|
|
||||||
siteInfo.TrialSiteCode,
|
|
||||||
siteInfo.TrialSiteAliasName,
|
|
||||||
|
|
||||||
siteSurveyInfo.UserName,
|
|
||||||
siteSurveyInfo.Email,
|
|
||||||
siteSurveyInfo.Phone,
|
|
||||||
_systemEmailConfig.SiteUrl
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var user in pmAndAPMList)
|
||||||
|
{
|
||||||
|
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
||||||
|
}
|
||||||
|
|
||||||
|
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
//发件地址
|
||||||
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
|
||||||
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
|
|
||||||
|
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
|
{
|
||||||
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
||||||
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
|
toUserName,
|
||||||
|
siteInfo.TrialSiteCode,
|
||||||
|
siteInfo.TrialSiteAliasName,
|
||||||
|
|
||||||
|
siteSurveyInfo.UserName,
|
||||||
|
siteSurveyInfo.Email,
|
||||||
|
siteSurveyInfo.Phone,
|
||||||
|
_systemEmailConfig.SiteUrl
|
||||||
|
);
|
||||||
|
|
||||||
|
return (topicStr, htmlBodyStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -164,74 +151,61 @@ public class SiteSurveySPMSubmitedEventConsumer(
|
|||||||
|
|
||||||
var trialId = siteSurveyInfo.TrialId;
|
var trialId = siteSurveyInfo.TrialId;
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
|
|
||||||
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
|
||||||
|
|
||||||
var trialUserList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
|
|
||||||
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
|
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToList();
|
|
||||||
|
|
||||||
var scenario = EmailBusinessScenario.Approval_SubmitSiteSurvey;
|
var scenario = EmailBusinessScenario.Approval_SubmitSiteSurvey;
|
||||||
|
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
if (emailConfig != null)
|
if (emailConfig != null)
|
||||||
{
|
{
|
||||||
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
var trialUserList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM || t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)
|
||||||
|
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum }).ToList();
|
||||||
|
|
||||||
|
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
|
||||||
|
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
|
||||||
|
|
||||||
|
var toUserName = string.Empty;
|
||||||
|
|
||||||
|
foreach (var item in pmAndAPMList)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
messageToSend.To.Add(new MailboxAddress(item.FullName, item.EMail));
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
|
|
||||||
var sPMOrCPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.SPM || t.UserTypeEnum == UserTypeEnum.CPM).ToList();
|
|
||||||
var pmAndAPMList = trialUserList.Where(t => t.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserTypeEnum == UserTypeEnum.APM).ToList();
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
|
|
||||||
var toUserName = string.Empty;
|
|
||||||
|
|
||||||
var lan_pmAndAPMList = pmAndAPMList.Where(t => t.UserWorkLanguage == workLanguage);
|
|
||||||
|
|
||||||
foreach (var item in lan_pmAndAPMList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(item.FullName, item.EMail));
|
|
||||||
|
|
||||||
toUserName = string.Join('、', lan_pmAndAPMList.Select(t => t.FullName));
|
|
||||||
}
|
|
||||||
|
|
||||||
//发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
toUserName,
|
|
||||||
siteInfo.TrialSiteCode, //中心编号
|
|
||||||
siteInfo.TrialSiteAliasName,//中心名称
|
|
||||||
|
|
||||||
siteSurveyInfo.UserName, //联系人
|
|
||||||
siteSurveyInfo.Email, //联系邮箱
|
|
||||||
siteSurveyInfo.Phone, //联系电话
|
|
||||||
_systemEmailConfig.SiteUrl
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
|
||||||
|
toUserName = string.Join('、', pmAndAPMList.Select(t => t.FullName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//发件地址
|
||||||
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
|
||||||
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
|
|
||||||
|
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
||||||
|
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
|
{
|
||||||
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo);
|
||||||
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
|
toUserName,
|
||||||
|
siteInfo.TrialSiteCode, //中心编号
|
||||||
|
siteInfo.TrialSiteAliasName,//中心名称
|
||||||
|
|
||||||
|
siteSurveyInfo.UserName, //联系人
|
||||||
|
siteSurveyInfo.Email, //联系邮箱
|
||||||
|
siteSurveyInfo.Phone, //联系电话
|
||||||
|
_systemEmailConfig.SiteUrl
|
||||||
|
);
|
||||||
|
|
||||||
|
return (topicStr, htmlBodyStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -260,108 +234,92 @@ public class SiteSurverRejectedEventConsumer(
|
|||||||
|
|
||||||
var trialSiteSurveyId = context.Message.TrialSiteSurveyId;
|
var trialSiteSurveyId = context.Message.TrialSiteSurveyId;
|
||||||
|
|
||||||
var siteSurveyInfo = _trialSiteSurveyRepository.Where(t => t.Id == trialSiteSurveyId, ignoreQueryFilters: true).FirstOrDefault().IfNullThrowException();
|
var siteSurveyInfo = _trialSiteSurveyRepository.Where(t => t.Id == trialSiteSurveyId ,ignoreQueryFilters:true).FirstOrDefault().IfNullThrowException();
|
||||||
|
|
||||||
var trialId = siteSurveyInfo.TrialId;
|
var trialId = siteSurveyInfo.TrialId;
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
|
|
||||||
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
|
||||||
|
|
||||||
var scenario = EmailBusinessScenario.SiteSurveyReject;
|
var scenario = EmailBusinessScenario.SiteSurveyReject;
|
||||||
|
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
if (emailConfig != null)
|
if (emailConfig != null)
|
||||||
{
|
{
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
|
var toUserName = siteSurveyInfo.UserName;
|
||||||
|
|
||||||
|
if (context.Message.IsHaveSPMOrCPM)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
//PM 驳回到SPM
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
|
|
||||||
var toUserName = siteSurveyInfo.UserName;
|
|
||||||
|
|
||||||
if (context.Message.IsHaveSPMOrCPM)
|
|
||||||
{
|
{
|
||||||
//PM 驳回到SPM
|
//var user = await _userRoleRepository.FirstOrDefaultAsync(t => t.Id == siteSurveyInfo.PreliminaryUserId);
|
||||||
if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
|
|
||||||
|
//name = user.FullName;
|
||||||
|
|
||||||
|
var sPMOrCPMList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
|
||||||
|
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM)
|
||||||
|
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum }).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var user in sPMOrCPMList)
|
||||||
{
|
{
|
||||||
|
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
||||||
var sPMOrCPMList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
|
|
||||||
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM)
|
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToList();
|
|
||||||
|
|
||||||
var lan_SPMOrCPMList = sPMOrCPMList.Where(t => t.UserWorkLanguage == workLanguage);
|
|
||||||
|
|
||||||
foreach (var user in lan_SPMOrCPMList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
toUserName = string.Join('、', lan_SPMOrCPMList.Select(t => t.FullName));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//SPM 驳回到CRC
|
|
||||||
else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
|
|
||||||
{
|
|
||||||
//使用中心国家语言 一致才发送
|
|
||||||
if ((siteInfo.Country == StaticData.SiteCountry.US && isEn_US) || (siteInfo.Country == StaticData.SiteCountry.CN && isEn_US == false))
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
|
|
||||||
|
|
||||||
}
|
toUserName = string.Join('、', sPMOrCPMList.Select(t => t.FullName));
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
//SPM 驳回到CRC
|
||||||
|
else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
|
||||||
{
|
{
|
||||||
//没有SPM PM驳回到CRC
|
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
|
||||||
|
|
||||||
//使用中心国家语言 一致才发送
|
|
||||||
if ((siteInfo.Country == StaticData.SiteCountry.US && isEn_US) || (siteInfo.Country == StaticData.SiteCountry.CN && isEn_US == false))
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
toUserName,
|
|
||||||
trialInfo.TrialCode,
|
|
||||||
trialInfo.ResearchProgramNo,
|
|
||||||
trialInfo.ExperimentName,
|
|
||||||
|
|
||||||
siteInfo.TrialSiteCode, //中心编号
|
|
||||||
siteInfo.TrialSiteAliasName,//中心名称
|
|
||||||
siteSurveyInfo.LatestBackReason, //驳回原因
|
|
||||||
_systemEmailConfig.SiteUrl, //链接
|
|
||||||
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none")
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//没有SPM PM驳回到CRC
|
||||||
|
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, siteSurveyInfo.Email));
|
||||||
|
}
|
||||||
|
|
||||||
|
//发件地址
|
||||||
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
|
||||||
|
|
||||||
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
|
|
||||||
|
var siteInfo = await _trialSiteRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.Id == siteSurveyInfo.TrialSiteId, true);
|
||||||
|
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
|
{
|
||||||
|
var topicStr = string.Format(input.topicStr, companyName,trialInfo.ResearchProgramNo);
|
||||||
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
|
toUserName,
|
||||||
|
trialInfo.TrialCode,
|
||||||
|
trialInfo.ResearchProgramNo,
|
||||||
|
trialInfo.ExperimentName,
|
||||||
|
|
||||||
|
siteInfo.TrialSiteCode, //中心编号
|
||||||
|
siteInfo.TrialSiteAliasName,//中心名称
|
||||||
|
siteSurveyInfo.LatestBackReason, //驳回原因
|
||||||
|
_systemEmailConfig.SiteUrl, //链接
|
||||||
|
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none")
|
||||||
|
);
|
||||||
|
|
||||||
|
return (topicStr, htmlBodyStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class CRCSubmitedAndQCToAuditEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<CRCSubmitedAndQCToAuditEvent> context)
|
public async Task Consume(ConsumeContext<CRCSubmitedAndQCToAuditEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(005,006) 【加急项目所有IQC待领取质控任务】邮件!!!");
|
Console.WriteLine("发送(005,006) 【加急项目所有IQC待领取质控任务】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
var subjectVisitId = context.Message.SubjectVisitId;
|
var subjectVisitId = context.Message.SubjectVisitId;
|
||||||
@@ -49,91 +49,80 @@ public class CRCSubmitedAndQCToAuditEventConsumer(
|
|||||||
|
|
||||||
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
|
||||||
|
|
||||||
if (trialEmailConfig != null)
|
if (trialEmailConfig != null)
|
||||||
{
|
{
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
|
|
||||||
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
var pmandAPm = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
||||||
|
|
||||||
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
|
var auditStateCode = "AuditStatePE";
|
||||||
|
|
||||||
|
if (trialInfo.QCProcessEnum == TrialQCProcess.DoubleAudit)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
auditStateCode = "AuditStateRC";
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
}
|
||||||
|
|
||||||
|
|
||||||
var iqcList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.IQC).Where(t => t.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
|
{
|
||||||
|
|
||||||
var pmandAPm = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
DictionaryRepository = _dictionaryRepository,
|
||||||
|
IsEn_US = isEn_US,
|
||||||
|
DictionaryList = new List<DictionaryDto>()
|
||||||
var auditStateCode = "AuditStatePE";
|
|
||||||
|
|
||||||
if (trialInfo.QCProcessEnum == TrialQCProcess.DoubleAudit)
|
|
||||||
{
|
|
||||||
auditStateCode = "AuditStateRC";
|
|
||||||
}
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
|
||||||
{
|
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
|
||||||
IsEn_US = isEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
{
|
||||||
new DictionaryDto (){DictionaryCode= auditStateCode,EnumValue=subjectVisit.AuditState.GetEnumInt(), }, //审核状态
|
new DictionaryDto (){DictionaryCode= auditStateCode,EnumValue=subjectVisit.AuditState.GetEnumInt(), }, //审核状态
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
|
||||||
|
|
||||||
foreach (var userinfo in iqcList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var userNames = iqcList.Select(x => x.FullName).ToList();
|
|
||||||
|
|
||||||
foreach (var pm in pmandAPm)
|
|
||||||
{
|
|
||||||
messageToSend.Cc.Add(new MailboxAddress(pm.FullName, pm.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
var subjectCode = subjectVisit.Subject.Code;
|
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
|
||||||
var htmlBodyStr = string.Format(
|
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
string.Join(',', userNames), // 用户名 {0}
|
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
|
||||||
subjectCode, // 受试者 {2}
|
|
||||||
subjectVisit.VisitName, // 访视 {3}
|
|
||||||
dictionValue[0], // 审核状态 {4}
|
|
||||||
_systemEmailConfig.SiteUrl // 链接 {5}
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var userinfo in userinfoList)
|
||||||
|
{
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userNames = userinfoList.Select(x => x.FullName).ToList();
|
||||||
|
|
||||||
|
foreach (var pm in pmandAPm)
|
||||||
|
{
|
||||||
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, pm.EMail));
|
||||||
|
}
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
|
{
|
||||||
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
|
var htmlBodyStr = string.Format(
|
||||||
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
|
string.Join(',', userNames), // 用户名 {0}
|
||||||
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
|
subjectCode, // 受试者 {2}
|
||||||
|
subjectVisit.VisitName, // 访视 {3}
|
||||||
|
dictionValue[0], // 审核状态 {4}
|
||||||
|
_systemEmailConfig.SiteUrl // 链接 {5}
|
||||||
|
);
|
||||||
|
|
||||||
|
return (topicStr, htmlBodyStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -158,7 +147,7 @@ public class CRCRepliedQCChallengeEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<CRCRepliedQCChallengeEvent> context)
|
public async Task Consume(ConsumeContext<CRCRepliedQCChallengeEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(Code012,013) 【CRC 回复质控质疑 通知QC】邮件!!!");
|
Console.WriteLine("发送(Code012,013) 【CRC 回复质控质疑 通知QC】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
var subjectVisitId = context.Message.SubjectVisitId;
|
var subjectVisitId = context.Message.SubjectVisitId;
|
||||||
@@ -169,37 +158,34 @@ public class CRCRepliedQCChallengeEventConsumer(
|
|||||||
|
|
||||||
var scenario = context.Message.IsPd ? EmailBusinessScenario.PDVerification_UnderQCQuery : EmailBusinessScenario.EligibilityVerification_Pending;
|
var scenario = context.Message.IsPd ? EmailBusinessScenario.PDVerification_UnderQCQuery : EmailBusinessScenario.EligibilityVerification_Pending;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
if (trialEmailConfig != null)
|
if (trialEmailConfig != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var qCChallengeDialog = await _qCChallengeDialogRepository.Where(x => x.Id == context.Message.QCChallengeDialogId).Include(x => x.QCChallenge).FirstNotNullAsync();
|
var qCChallengeDialog = await _qCChallengeDialogRepository.Where(x => x.Id == context.Message.QCChallengeDialogId).Include(x => x.QCChallenge).FirstNotNullAsync();
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
|
||||||
|
|
||||||
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
|
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.IQC).ToList();
|
||||||
var pmandAPm = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
var pmandAPm = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
||||||
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
|
|
||||||
var userinfo = subjectVisit.CurrentActionUser;
|
var userinfo = subjectVisit.CurrentActionUser;
|
||||||
|
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = _userRoleRepository.Where(t => t.Id == userinfo.Id).Select(t => t.IdentityUser.UserWorkLanguage).First();
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
foreach (var pm in pmandAPm)
|
foreach (var pm in pmandAPm)
|
||||||
{
|
{
|
||||||
messageToSend.Cc.Add(new MailboxAddress(pm.FullName, pm.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, pm.EMail));
|
||||||
}
|
}
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
@@ -221,7 +207,7 @@ public class CRCRepliedQCChallengeEventConsumer(
|
|||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
userinfo.FullName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
@@ -233,9 +219,9 @@ public class CRCRepliedQCChallengeEventConsumer(
|
|||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +244,7 @@ public class QCRepliedQCChallengeEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<QCRepliedQCChallengeEvent> context)
|
public async Task Consume(ConsumeContext<QCRepliedQCChallengeEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(014,015) 【 QC回复 质控质疑,通知CRC】邮件!!!");
|
Console.WriteLine("发送(014,015) 【 QC回复 质控质疑,通知CRC】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
var subjectVisitId = context.Message.SubjectVisitId;
|
var subjectVisitId = context.Message.SubjectVisitId;
|
||||||
@@ -291,61 +277,54 @@ public class QCRepliedQCChallengeEventConsumer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
|
|
||||||
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).ToList();
|
||||||
|
|
||||||
|
var craInfo = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.CRA).FirstOrDefault();
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
DictionaryRepository = _dictionaryRepository,
|
||||||
|
IsEn_US = isEn_US,
|
||||||
|
DictionaryList = new List<DictionaryDto>()
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Where(t => t.UserWorkLanguage == workLanguage).ToList();
|
{
|
||||||
|
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=isclose.ToString().ToLower(), }, //是否关闭
|
||||||
var craInfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.CRA).ToList();
|
|
||||||
|
}
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
});
|
||||||
{
|
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
|
||||||
IsEn_US = isEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
|
||||||
new DictionaryDto (){DictionaryCode= "YesOrNo",EnumValue=isclose.ToString().ToLower(), }, //是否关闭
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var userinfo in userinfoList)
|
||||||
|
{
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
var toUserName = string.Join('、', userinfoList.Select(t => t.FullName));
|
if (craInfo != null)
|
||||||
|
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
{
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, craInfo.EMail));
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var user in craInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
toUserName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
subjectVisit.VisitName, // 访视 {3}
|
subjectVisit.VisitName, // 访视 {3}
|
||||||
@@ -358,13 +337,10 @@ public class QCRepliedQCChallengeEventConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,7 +364,7 @@ public class CRCRepliedCheckChallengeEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<CRCRepliedCheckChallengeEvent> context)
|
public async Task Consume(ConsumeContext<CRCRepliedCheckChallengeEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(019,020) 【 CRC 回复一致性核查质疑 通知PM】邮件!!!");
|
Console.WriteLine("发送(019,020) 【 CRC 回复一致性核查质疑 通知PM】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
|
|
||||||
@@ -407,58 +383,49 @@ public class CRCRepliedCheckChallengeEventConsumer(
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
|
||||||
|
|
||||||
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
||||||
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
DictionaryRepository = _dictionaryRepository,
|
||||||
|
IsEn_US = isEn_US,
|
||||||
|
DictionaryList = new List<DictionaryDto>()
|
||||||
|
{
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //审核状态
|
||||||
{
|
|
||||||
|
}
|
||||||
DictionaryRepository = _dictionaryRepository,
|
});
|
||||||
IsEn_US = isEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
|
||||||
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //审核状态
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager)
|
|
||||||
.Where(t => t.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var userinfo in userinfoList)
|
||||||
|
{
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
var toUserName = string.Join('、', userinfoList.Select(t => t.FullName));
|
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
toUserName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
subjectVisit.VisitName, // 访视 {3}
|
subjectVisit.VisitName, // 访视 {3}
|
||||||
@@ -470,17 +437,10 @@ public class CRCRepliedCheckChallengeEventConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,12 +466,12 @@ public class PMRepliedCheckChallengeEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<PMRepliedCheckChallengeEvent> context)
|
public async Task Consume(ConsumeContext<PMRepliedCheckChallengeEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(016,017) 【 PM 一致性核查 通知CRC】邮件!!!");
|
Console.WriteLine("发送(016,017) 【 PM 一致性核查 通知CRC】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
var subjectVisitId = context.Message.SubjectVisitId;
|
var subjectVisitId = context.Message.SubjectVisitId;
|
||||||
|
|
||||||
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).Include(x => x.NoneDicomStudyList).Include(x => x.StudyList).Include(x => x.Subject).Include(t => t.TrialSite).FirstNotNullAsync();
|
var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).Include(x => x.NoneDicomStudyList).Include(x => x.StudyList).Include(x => x.Subject).FirstNotNullAsync();
|
||||||
|
|
||||||
var trialId = subjectVisit.TrialId;
|
var trialId = subjectVisit.TrialId;
|
||||||
|
|
||||||
@@ -526,11 +486,11 @@ public class PMRepliedCheckChallengeEventConsumer(
|
|||||||
var checkChallengeDialog = await _checkChallengeDialogRepository.Where(x => x.Id == context.Message.CheckChallengeDialogId).FirstNotNullAsync();
|
var checkChallengeDialog = await _checkChallengeDialogRepository.Where(x => x.Id == context.Message.CheckChallengeDialogId).FirstNotNullAsync();
|
||||||
|
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
|
||||||
|
|
||||||
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).ToList();
|
||||||
|
|
||||||
var craInfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.CRA).ToList();
|
var craInfo = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.CRA).FirstOrDefault();
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
@@ -539,46 +499,28 @@ public class PMRepliedCheckChallengeEventConsumer(
|
|||||||
modalities = subjectVisit.NoneDicomStudyList.Select(t => t.Modality)
|
modalities = subjectVisit.NoneDicomStudyList.Select(t => t.Modality)
|
||||||
.Union(subjectVisit.StudyList.Select(k => k.ModalityForEdit)).ToList();
|
.Union(subjectVisit.StudyList.Select(k => k.ModalityForEdit)).ToList();
|
||||||
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
//foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
|
|
||||||
isEn_US = subjectVisit.TrialSite.Country == StaticData.SiteCountry.US;
|
DictionaryRepository = _dictionaryRepository,
|
||||||
|
IsEn_US = isEn_US,
|
||||||
|
DictionaryList = new List<DictionaryDto>()
|
||||||
|
{
|
||||||
|
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //核查状态
|
||||||
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
}
|
||||||
|
});
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Where(t => t.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
foreach (var userinfo in userinfoList)
|
||||||
{
|
{
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
|
||||||
IsEn_US = isEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
|
||||||
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //核查状态
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
var toUserName = string.Join('、', userinfoList.Select(t => t.FullName));
|
if (craInfo != null)
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
{
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, craInfo.EMail));
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var user in craInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
@@ -589,8 +531,8 @@ public class PMRepliedCheckChallengeEventConsumer(
|
|||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
toUserName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
|
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
@@ -605,11 +547,10 @@ public class PMRepliedCheckChallengeEventConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -651,57 +592,49 @@ public class CheckStateChangedToAuditEventConsumer(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false)
|
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == subjectVisit.TrialId && x.TrialUser.IsDeleted == false).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||||
.Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
|
||||||
|
|
||||||
|
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager).ToList();
|
||||||
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == subjectVisit.TrialId);
|
||||||
|
|
||||||
|
|
||||||
// 遍历语言枚举 在底层判断收件人是否为空,决定是否跳过邮件发送,避免每个邮件场景的地方都重复判断
|
|
||||||
foreach (UserWorkLanguage workLanguage in Enum.GetValues<UserWorkLanguage>())
|
|
||||||
|
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var userinfoList = trialUserList.Where(x => x.UserTypeEnum == UserTypeEnum.APM || x.UserTypeEnum == UserTypeEnum.ProjectManager)
|
DictionaryRepository = _dictionaryRepository,
|
||||||
.Where(t => t.UserWorkLanguage == workLanguage).ToList();
|
IsEn_US = isEn_US,
|
||||||
|
DictionaryList = new List<DictionaryDto>()
|
||||||
|
{
|
||||||
|
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //审核状态
|
||||||
|
|
||||||
var dictionValue = await CommonEmailHelper.TranslationDictionary(new TranslationDictionaryDto()
|
}
|
||||||
{
|
});
|
||||||
|
|
||||||
DictionaryRepository = _dictionaryRepository,
|
|
||||||
IsEn_US = isEn_US,
|
|
||||||
DictionaryList = new List<DictionaryDto>()
|
|
||||||
{
|
|
||||||
new DictionaryDto (){DictionaryCode= "CheckState",EnumValue=subjectVisit.CheckState.GetEnumInt(), }, //审核状态
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var userinfo in userinfoList)
|
||||||
|
{
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
var toUserName = string.Join('、', userinfoList.Select(t => t.FullName));
|
|
||||||
|
|
||||||
foreach (var userinfo in userinfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
toUserName, // 姓名 {0}
|
userinfo.FullName, // 姓名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
subjectCode, // 受试者 {2}
|
subjectCode, // 受试者 {2}
|
||||||
subjectVisit.VisitName, // 访视 {3}
|
subjectVisit.VisitName, // 访视 {3}
|
||||||
@@ -713,11 +646,10 @@ public class CheckStateChangedToAuditEventConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -739,7 +671,7 @@ public class QCClaimTaskEventConsumer(
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<QCClaimTaskEvent> context)
|
public async Task Consume(ConsumeContext<QCClaimTaskEvent> context)
|
||||||
{
|
{
|
||||||
Log.Logger.Warning("发送(Code007,008) 【QC 领取了质控任务】邮件!!!");
|
Console.WriteLine("发送(Code007,008) 【QC 领取了质控任务】邮件!!!");
|
||||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
|
|
||||||
@@ -771,23 +703,15 @@ public class QCClaimTaskEventConsumer(
|
|||||||
|
|
||||||
|
|
||||||
var userinfo = subjectVisit.CurrentActionUser;
|
var userinfo = subjectVisit.CurrentActionUser;
|
||||||
if (userinfo == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = _userRoleRepository.Where(t => t.Id == userinfo.Id).Select(t => t.IdentityUser.UserWorkLanguage).First();
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
foreach (var pm in pmandAPm)
|
foreach (var pm in pmandAPm)
|
||||||
{
|
{
|
||||||
messageToSend.Cc.Add(new MailboxAddress(pm.FullName, pm.EMail));
|
messageToSend.Cc.Add(new MailboxAddress(String.Empty, pm.EMail));
|
||||||
}
|
}
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
@@ -817,7 +741,7 @@ public class QCClaimTaskEventConsumer(
|
|||||||
var subjectCode = subjectVisit.Subject.Code;
|
var subjectCode = subjectVisit.Subject.Code;
|
||||||
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
var topicStr = string.Format(input.topicStr, trialInfo.ResearchProgramNo, subjectCode, subjectVisit.VisitName);
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
userinfo.FullName, // 用户名 {0}
|
userinfo.FullName, // 用户名 {0}
|
||||||
trialInfo.ExperimentName, // 项目 {1}
|
trialInfo.ExperimentName, // 项目 {1}
|
||||||
string.Join(',', subjectcodes), // 受试者 {2}
|
string.Join(',', subjectcodes), // 受试者 {2}
|
||||||
@@ -831,9 +755,9 @@ public class QCClaimTaskEventConsumer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
using IRaCIS.Core.Application.Helper.OtherTool;
|
using System;
|
||||||
using IRaCIS.Core.Domain.BaseModel;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using MassTransit;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using IRaCIS.Core.Domain.BaseModel;
|
||||||
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using MassTransit;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using NPOI.SS.Formula.Functions;
|
||||||
|
|
||||||
public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logger, IConfiguration _config) : IFilter<ConsumeContext<T>> where T : DomainEvent
|
public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logger) : IFilter<ConsumeContext<T>> where T : DomainEvent
|
||||||
{
|
{
|
||||||
|
|
||||||
public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next)
|
public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next)
|
||||||
@@ -25,44 +23,6 @@ public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logge
|
|||||||
{
|
{
|
||||||
var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : "");
|
var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : "");
|
||||||
_logger.LogError(errorInfo);
|
_logger.LogError(errorInfo);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool isOpenWeComNotice = _config.GetValue<bool>("WeComNoticeConfig:IsOpenWeComNotice");
|
|
||||||
|
|
||||||
if (isOpenWeComNotice)
|
|
||||||
{
|
|
||||||
string webhook = _config["WeComNoticeConfig:WebhookUrl"] ?? string.Empty;
|
|
||||||
|
|
||||||
var uri = new Uri(_config["SystemEmailSendConfig:SiteUrl"]);
|
|
||||||
var baseUrl = uri.GetLeftPart(UriPartial.Authority);
|
|
||||||
|
|
||||||
var userList = _config.GetSection("WeComNoticeConfig:APINoticeUserList").Get<string[]>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 🔔 异步告警(不要阻塞请求)
|
|
||||||
_ = WeComNotifier.SendAlertAsync(
|
|
||||||
webhook: webhook,
|
|
||||||
alert: new WeComAlert
|
|
||||||
{
|
|
||||||
Env = baseUrl,
|
|
||||||
UserName = "MassTransit 自动触发邮件",
|
|
||||||
Api = "",
|
|
||||||
Message = $"异常信息:{exception.Message} ",
|
|
||||||
Stack = exception.StackTrace,
|
|
||||||
AtUsers = userList ?? []
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Logger.Error($"MassTransit里发送企业微信出现错误:{ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using IRaCIS.Core.Application.Contracts;
|
|||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
@@ -27,7 +26,6 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
public class UrgentIRUnReadTaskRecurringEventConsumer(
|
public class UrgentIRUnReadTaskRecurringEventConsumer(
|
||||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||||
IRepository<VisitTask> _visitTaskRepository,
|
IRepository<VisitTask> _visitTaskRepository,
|
||||||
IRepository<Trial> _trialRepository,
|
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
IRepository<Dictionary> _dictionaryRepository,
|
||||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
|
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
|
||||||
@@ -37,15 +35,9 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
|
|
||||||
public async Task Consume(ConsumeContext<UrgentIRUnReadTaskRecurringEvent> context)
|
public async Task Consume(ConsumeContext<UrgentIRUnReadTaskRecurringEvent> context)
|
||||||
{
|
{
|
||||||
var isEn_US = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var trialId = context.Message.TrialId;
|
var trialId = context.Message.TrialId;
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
var scenario = EmailBusinessScenario.ExpeditedReading;
|
var scenario = EmailBusinessScenario.ExpeditedReading;
|
||||||
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
@@ -74,17 +66,13 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
t.UserRole.IdentityUser.EMail,
|
t.UserRole.IdentityUser.EMail,
|
||||||
t.UserRole.IdentityUser.UserName,
|
t.UserRole.IdentityUser.UserName,
|
||||||
t.Trial.TrialCode,
|
t.Trial.TrialCode,
|
||||||
t.Trial.ResearchProgramNo,
|
t.Trial.ResearchProgramNo
|
||||||
t.UserRole.IdentityUser.UserWorkLanguage
|
|
||||||
//TrialReadingCriterionList = t.Trial.TrialReadingCriterionList.Select(t => new { t.CriterionName, TrialReadingCriterionId = t.Id }).ToList()
|
//TrialReadingCriterionList = t.Trial.TrialReadingCriterionList.Select(t => new { t.CriterionName, TrialReadingCriterionId = t.Id }).ToList()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
foreach (var trialUser in trialUserList)
|
foreach (var trialUser in trialUserList)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = trialUser.UserWorkLanguage;
|
|
||||||
isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var userId = trialUser.UserId;
|
var userId = trialUser.UserId;
|
||||||
|
|
||||||
@@ -157,7 +145,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, emailContent, workLanguage),
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, emailContent),
|
||||||
trialUser.FullName,
|
trialUser.FullName,
|
||||||
|
|
||||||
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||||
@@ -171,9 +159,9 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc, workLanguage);
|
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
|
||||||
//处理标记已通知的任务
|
//处理标记已通知的任务
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public static class OldRecurringEmailHelper
|
|||||||
public static string EmailNamePlaceholder => StaticData.EmailSend.EmailNamePlaceholder;
|
public static string EmailNamePlaceholder => StaticData.EmailSend.EmailNamePlaceholder;
|
||||||
|
|
||||||
|
|
||||||
//发送项目邮件的通用方法 已经处理
|
|
||||||
public static async Task SendTrialEmailAsync(
|
public static async Task SendTrialEmailAsync(
|
||||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
||||||
IRepository<Trial> _trialRepository,
|
IRepository<Trial> _trialRepository,
|
||||||
@@ -34,7 +34,6 @@ public static class OldRecurringEmailHelper
|
|||||||
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
|
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
|
||||||
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
|
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
|
||||||
|
|
||||||
var trialInfo=await _trialRepository.Where(t=>t.Id== trialId).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false || trialEmailConfig.IsEnable == false)
|
if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false || trialEmailConfig.IsEnable == false)
|
||||||
{
|
{
|
||||||
@@ -163,7 +162,7 @@ public static class OldRecurringEmailHelper
|
|||||||
if (sendEmailConfig != null)
|
if (sendEmailConfig != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
await SendEmailHelper.SendEmailAsync(sendEmailConfig, trialInfo);
|
await SendEmailHelper.SendEmailAsync(sendEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using MassTransit.Scheduling;
|
|||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -15,7 +14,7 @@ using System.Threading.Tasks;
|
|||||||
namespace IRaCIS.Core.Application.MassTransit.Consumer;
|
namespace IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
|
|
||||||
|
|
||||||
//项目手动选择 周期性邮件
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -35,26 +34,17 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
|
|||||||
{
|
{
|
||||||
var trialId = context.Message.TrialId;
|
var trialId = context.Message.TrialId;
|
||||||
|
|
||||||
var isEn_us = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_us = false;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
|
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
|
||||||
|
|
||||||
//找到 该项目的CRC 用户Id
|
//找到 该项目的CRC 用户Id
|
||||||
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.UserRole.FullName, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
|
||||||
|
|
||||||
//判断是否任务可以领取 ,可以的话 发送邮件
|
//判断是否任务可以领取 ,可以的话 发送邮件
|
||||||
|
|
||||||
foreach (var user in userList)
|
foreach (var user in userList)
|
||||||
{
|
{
|
||||||
|
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = user.UserWorkLanguage;
|
|
||||||
isEn_us = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var userId = user.UserId;
|
var userId = user.UserId;
|
||||||
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
||||||
var query = _trialRepository.Where(t => t.Id == trialId)
|
var query = _trialRepository.Where(t => t.Id == trialId)
|
||||||
@@ -77,7 +67,7 @@ public class QCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRepo
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
|
||||||
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent, workLanguage),
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
|
||||||
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr, isEn_us, userId);
|
return (topicStr, htmlBodyStr, isEn_us, userId);
|
||||||
@@ -112,26 +102,16 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
|
|||||||
{
|
{
|
||||||
var trialId = context.Message.TrialId;
|
var trialId = context.Message.TrialId;
|
||||||
|
|
||||||
var isEn_us = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_us = false;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr, t.DeclarationTypeEnumList }).FirstNotNullAsync();
|
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr, t.DeclarationTypeEnumList }).FirstNotNullAsync();
|
||||||
|
|
||||||
//找到 该项目的IQC 用户Id
|
//找到 该项目的IQC 用户Id
|
||||||
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
|
||||||
|
|
||||||
//判断是否任务可以领取 ,可以的话 发送邮件
|
//判断是否任务可以领取 ,可以的话 发送邮件
|
||||||
|
|
||||||
foreach (var user in userList)
|
foreach (var user in userList)
|
||||||
{
|
{
|
||||||
|
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = user.UserWorkLanguage;
|
|
||||||
isEn_us = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var userId = user.UserId;
|
var userId = user.UserId;
|
||||||
|
|
||||||
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
||||||
@@ -157,7 +137,7 @@ public class CRCImageQuestionRecurringEventConsumer(IRepository<Trial> _trialRep
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
|
||||||
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent, workLanguage),
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
|
||||||
|
|
||||||
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
||||||
|
|
||||||
@@ -191,28 +171,20 @@ public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
public async Task Consume(ConsumeContext<ImageQCRecurringEvent> context)
|
public async Task Consume(ConsumeContext<ImageQCRecurringEvent> context)
|
||||||
{
|
{
|
||||||
var trialId = context.Message.TrialId;
|
var trialId=context.Message.TrialId;
|
||||||
|
|
||||||
var isEn_us = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_us = false;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
|
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync();
|
||||||
|
|
||||||
//找到 该项目的IQC 用户Id
|
//找到 该项目的IQC 用户Id
|
||||||
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName, t.UserRole.IdentityUser.UserWorkLanguage }).ToListAsync();
|
var userList = await _trialUserRoleRepository.Where(t => t.TrialId == trialId).Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.UserRole.FullName }).ToListAsync();
|
||||||
|
|
||||||
//判断是否任务可以领取 ,可以的话 发送邮件
|
//判断是否任务可以领取 ,可以的话 发送邮件
|
||||||
var userIdList = userList.Select(t => t.UserId).ToList();
|
var userIdList = userList.Select(t => t.UserId).ToList();
|
||||||
|
|
||||||
foreach (var user in userList)
|
foreach (var user in userList)
|
||||||
{
|
{
|
||||||
//重新设置当前发送邮件的语言
|
|
||||||
var workLanguage = user.UserWorkLanguage;
|
|
||||||
isEn_us = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var userId = user.UserId;
|
var userId = user.UserId;
|
||||||
|
|
||||||
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
//过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id
|
||||||
@@ -236,11 +208,11 @@ public class ImageQCRecurringEventConsumer(IRepository<Trial> _trialRepository,
|
|||||||
|
|
||||||
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc = trialEmailConfig =>
|
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 topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo);
|
||||||
|
|
||||||
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
var htmlContent = isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN;
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent, workLanguage),
|
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, htmlContent),
|
||||||
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
user.FullName, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr, false, userId);
|
return (topicStr, htmlBodyStr, false, userId);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using IRaCIS.Core.Application.Helper;
|
|||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
@@ -43,12 +42,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
|
|
||||||
DateTime now = DateTime.Now;
|
DateTime now = DateTime.Now;
|
||||||
Console.WriteLine("发送定时过期提醒");
|
Console.WriteLine("发送定时过期提醒");
|
||||||
var isEn_US = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var systemDocQuery =
|
var systemDocQuery =
|
||||||
from sysDoc in _systemDocumentRepository.AsQueryable(false)
|
from sysDoc in _systemDocumentRepository.AsQueryable(false)
|
||||||
from identityUser in _identityUserRepository.AsQueryable(false).Where(t => t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
from identityUser in _identityUserRepository.AsQueryable(false).Where(t => t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||||
@@ -85,213 +79,199 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||||
|
|
||||||
Console.WriteLine("发送定时过期提醒:人员数量" + userinfoList.Count);
|
Console.WriteLine("发送定时过期提醒:人员数量" + userinfoList.Count);
|
||||||
|
int index = 1;
|
||||||
var scenario = EmailBusinessScenario.GeneralTraining_ExpirationNotification;
|
foreach (var userinfo in userinfoList)
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
|
||||||
if (emailConfig == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userWorkLanguageList = userinfoList.Select(x => x.UserWorkLanguage).Distinct().ToList();
|
|
||||||
foreach (var workLanguage in userWorkLanguageList)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var langUserInfoList = userinfoList.Where(x => x.UserWorkLanguage == workLanguage).ToList();
|
Console.WriteLine($"{index}发送定时过期提醒,邮箱:{userinfo.EMail},姓名{userinfo.UserName}");
|
||||||
if (!langUserInfoList.Any())
|
index++;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userIsEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
foreach (var userinfo in langUserInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
var userNames = langUserInfoList.Select(x => x.UserName).ToList();
|
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames),
|
userinfo.UserName, // 用户名 {0}
|
||||||
_systemEmailConfig.SiteUrl
|
_systemEmailConfig.SiteUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
var scenario = EmailBusinessScenario.GeneralTraining_ExpirationNotification;
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
|
||||||
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
|
if (emailConfig != null)
|
||||||
|
{
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生效通知
|
/// 生效通知
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemDocumentPublishEventConsumer(
|
public class SystemDocumentPublishEventConsumer(
|
||||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||||
IRepository<VisitTask> _visitTaskRepository,
|
IRepository<VisitTask> _visitTaskRepository,
|
||||||
IRepository<SystemDocument> _systemDocumentRepository,
|
IRepository<SystemDocument> _systemDocumentRepository,
|
||||||
IRepository<IdentityUser> _identityUserRepository,
|
IRepository<IdentityUser> _identityUserRepository,
|
||||||
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
|
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
IRepository<Dictionary> _dictionaryRepository,
|
||||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||||
|
|
||||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<SystemDocumentPublishEvent>
|
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<SystemDocumentPublishEvent>
|
||||||
|
{
|
||||||
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
|
|
||||||
|
public async Task Consume(ConsumeContext<SystemDocumentPublishEvent> context)
|
||||||
{
|
{
|
||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
public async Task Consume(ConsumeContext<SystemDocumentPublishEvent> context)
|
// 记录是否只发送给新增角色的日志
|
||||||
|
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
||||||
{
|
{
|
||||||
var isEn_US = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
Console.WriteLine($"只发送给新增的角色,角色数量: {context.Message.NewUserTypeIds.Count}");
|
||||||
|
}
|
||||||
|
// 构建查询
|
||||||
|
IQueryable<UnionDocumentWithConfirmInfoView> systemDocQuery;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
||||||
var culture = context.Message.CultureInfoName;
|
{
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
// 只查询新增角色的用户
|
||||||
|
systemDocQuery =
|
||||||
// 记录是否只发送给新增角色的日志
|
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
||||||
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||||
|
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||||
|
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||||
|
.Any(t => context.Message.NewUserTypeIds.Contains(t.UserTypeId) &&
|
||||||
|
sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||||
|
select new UnionDocumentWithConfirmInfoView()
|
||||||
{
|
{
|
||||||
Console.WriteLine($"只发送给新增的角色,角色数量: {context.Message.NewUserTypeIds.Count}");
|
IsSystemDoc = true,
|
||||||
}
|
Id = sysDoc.Id,
|
||||||
// 构建查询
|
CreateTime = sysDoc.CreateTime,
|
||||||
IQueryable<UnionDocumentWithConfirmInfoView> systemDocQuery;
|
IsDeleted = sysDoc.IsDeleted,
|
||||||
|
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
|
||||||
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
Name = sysDoc.Name,
|
||||||
|
Path = sysDoc.Path,
|
||||||
|
FileTypeId = sysDoc.FileTypeId,
|
||||||
|
UpdateTime = sysDoc.UpdateTime,
|
||||||
|
ConfirmUserId = identityUser.Id,
|
||||||
|
RealName = identityUser.FullName,
|
||||||
|
UserName = identityUser.UserName,
|
||||||
|
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
|
||||||
|
FullFilePath = sysDoc.Path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 查询所有相关角色的用户
|
||||||
|
systemDocQuery =
|
||||||
|
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
||||||
|
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||||
|
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||||
|
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||||
|
.Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||||
|
select new UnionDocumentWithConfirmInfoView()
|
||||||
{
|
{
|
||||||
// 只查询新增角色的用户
|
IsSystemDoc = true,
|
||||||
systemDocQuery =
|
Id = sysDoc.Id,
|
||||||
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
CreateTime = sysDoc.CreateTime,
|
||||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
IsDeleted = sysDoc.IsDeleted,
|
||||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
|
||||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
Name = sysDoc.Name,
|
||||||
.Any(t => context.Message.NewUserTypeIds.Contains(t.UserTypeId) &&
|
Path = sysDoc.Path,
|
||||||
sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
FileTypeId = sysDoc.FileTypeId,
|
||||||
select new UnionDocumentWithConfirmInfoView()
|
UpdateTime = sysDoc.UpdateTime,
|
||||||
|
ConfirmUserId = identityUser.Id,
|
||||||
|
RealName = identityUser.FullName,
|
||||||
|
UserName = identityUser.UserName,
|
||||||
|
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
|
||||||
|
FullFilePath = sysDoc.Path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var datalist = await systemDocQuery.IgnoreQueryFilters().Where(x => x.IsNeedSendEmial).ToListAsync();
|
||||||
|
|
||||||
|
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||||
|
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||||
|
int index = 1;
|
||||||
|
foreach (var userinfo in userinfoList)
|
||||||
|
{
|
||||||
|
string msg = $"{index}生效通知,邮箱:{userinfo.EMail},姓名{userinfo.UserName},";
|
||||||
|
index++;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var messageToSend = new MimeMessage();
|
||||||
|
//发件地址
|
||||||
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
IsSystemDoc = true,
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
Id = sysDoc.Id,
|
|
||||||
CreateTime = sysDoc.CreateTime,
|
var htmlBodyStr = string.Format(
|
||||||
IsDeleted = sysDoc.IsDeleted,
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
|
userinfo.UserName, // 用户名 {0}
|
||||||
Name = sysDoc.Name,
|
_systemEmailConfig.SiteUrl
|
||||||
Path = sysDoc.Path,
|
);
|
||||||
FileTypeId = sysDoc.FileTypeId,
|
|
||||||
UpdateTime = sysDoc.UpdateTime,
|
return (topicStr, htmlBodyStr);
|
||||||
ConfirmUserId = identityUser.Id,
|
|
||||||
RealName = identityUser.FullName,
|
|
||||||
UserName = identityUser.UserName,
|
|
||||||
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
|
|
||||||
FullFilePath = sysDoc.Path
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
else
|
var scenario = EmailBusinessScenario.GeneralTraining_EffectiveNotification;
|
||||||
{
|
|
||||||
// 查询所有相关角色的用户
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
systemDocQuery =
|
|
||||||
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
if (emailConfig != null)
|
||||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
|
||||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
|
||||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
|
||||||
.Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
|
||||||
select new UnionDocumentWithConfirmInfoView()
|
|
||||||
{
|
{
|
||||||
IsSystemDoc = true,
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
Id = sysDoc.Id,
|
|
||||||
CreateTime = sysDoc.CreateTime,
|
|
||||||
IsDeleted = sysDoc.IsDeleted,
|
|
||||||
SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes,
|
|
||||||
Name = sysDoc.Name,
|
|
||||||
Path = sysDoc.Path,
|
|
||||||
FileTypeId = sysDoc.FileTypeId,
|
|
||||||
UpdateTime = sysDoc.UpdateTime,
|
|
||||||
ConfirmUserId = identityUser.Id,
|
|
||||||
RealName = identityUser.FullName,
|
|
||||||
UserName = identityUser.UserName,
|
|
||||||
IsNeedSendEmial = identityUser.IsZhiZhun || (!identityUser.IsZhiZhun && sysDoc.DocUserSignType == DocUserSignType.InnerAndOuter),
|
|
||||||
FullFilePath = sysDoc.Path
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var datalist = await systemDocQuery.IgnoreQueryFilters().Where(x => x.IsNeedSendEmial).ToListAsync();
|
|
||||||
|
|
||||||
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
|
||||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
|
||||||
|
|
||||||
var scenario = EmailBusinessScenario.GeneralTraining_EffectiveNotification;
|
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
|
||||||
if (emailConfig == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userWorkLanguageList = userinfoList.Select(x => x.UserWorkLanguage).Distinct().ToList();
|
|
||||||
foreach (var workLanguage in userWorkLanguageList)
|
|
||||||
{
|
|
||||||
var langUserInfoList = userinfoList.Where(x => x.UserWorkLanguage == workLanguage).ToList();
|
|
||||||
if (!langUserInfoList.Any())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string msg = $"{langUserInfoList.Count}生效通知,";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
|
|
||||||
foreach (var userinfo in langUserInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var userIsEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
var userNames = langUserInfoList.Select(x => x.UserName).ToList();
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(
|
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
string.Join(',', userNames),
|
|
||||||
_systemEmailConfig.SiteUrl
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
msg += "发送成功";
|
msg += "发送成功";
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
msg += "发送失败";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Console.WriteLine(msg);
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
msg += "发送失败";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using IRaCIS.Core.Application.Helper;
|
|||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@@ -15,7 +14,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
|
||||||
using System.Reactive.Joins;
|
using System.Reactive.Joins;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -54,11 +52,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
|
|
||||||
DateTime now = DateTime.Now;
|
DateTime now = DateTime.Now;
|
||||||
Console.WriteLine("发送定时项目过期提醒");
|
Console.WriteLine("发送定时项目过期提醒");
|
||||||
var isEn_US = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
var trialDocQuery =
|
var trialDocQuery =
|
||||||
from trialDoc in _trialDocumentRepository.AsQueryable(true)
|
from trialDoc in _trialDocumentRepository.AsQueryable(true)
|
||||||
|
|
||||||
@@ -81,7 +75,6 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
CurrentStaffTrainDays = trialDoc.CurrentStaffTrainDays,
|
CurrentStaffTrainDays = trialDoc.CurrentStaffTrainDays,
|
||||||
NewStaffTrainDays = trialDoc.NewStaffTrainDays,
|
NewStaffTrainDays = trialDoc.NewStaffTrainDays,
|
||||||
Id = trialDoc.Id,
|
Id = trialDoc.Id,
|
||||||
TrialId= trialDoc.TrialId,
|
|
||||||
IsSystemDoc = false,
|
IsSystemDoc = false,
|
||||||
CreateTime = trialDoc.CreateTime,
|
CreateTime = trialDoc.CreateTime,
|
||||||
FullFilePath = trialDoc.Path,
|
FullFilePath = trialDoc.Path,
|
||||||
@@ -109,65 +102,45 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||||
|
|
||||||
Console.WriteLine("发送定时项目过期提醒:人员数量" + userinfoList.Count);
|
Console.WriteLine("发送定时项目过期提醒:人员数量" + userinfoList.Count);
|
||||||
|
int index = 1;
|
||||||
var scenario = EmailBusinessScenario.TrialTraining_ExpirationNotification;
|
foreach (var userinfo in userinfoList)
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
|
||||||
if (emailConfig == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userTrialIdList = datalist.Select(t => new { t.ConfirmUserId, t.TrialId }).Distinct().ToList();
|
|
||||||
var userWithTrialList = (from ut in userTrialIdList
|
|
||||||
join u in userinfoList on ut.ConfirmUserId equals u.Id
|
|
||||||
select new { ut.TrialId, User = u }).ToList();
|
|
||||||
|
|
||||||
var groupedList = userWithTrialList.GroupBy(x => new { x.TrialId, x.User.UserWorkLanguage }).ToList();
|
|
||||||
foreach (var groupItem in groupedList)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var langUserInfoList = groupItem.Select(x => x.User).Distinct().ToList();
|
Console.WriteLine($"{index}发送定时过期提醒,邮箱:{userinfo.EMail},姓名{userinfo.UserName}");
|
||||||
if (!langUserInfoList.Any())
|
index++;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine($"发送定时过期提醒,数量:{langUserInfoList.Count}");
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.Where(x => x.Id == groupItem.Key.TrialId).FirstOrDefaultAsync();
|
|
||||||
if (trialInfo == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var workLanguage = groupItem.Key.UserWorkLanguage;
|
|
||||||
var userIsEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
foreach (var userinfo in langUserInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
var userNames = langUserInfoList.Select(x => x.UserName).ToList();
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames),
|
userinfo.UserName, // 用户名 {0}
|
||||||
_systemEmailConfig.SiteUrl
|
_systemEmailConfig.SiteUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
var scenario = EmailBusinessScenario.TrialTraining_ExpirationNotification;
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
|
if (emailConfig != null)
|
||||||
|
{
|
||||||
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
@@ -189,7 +162,6 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
IRepository<VisitTask> _visitTaskRepository,
|
IRepository<VisitTask> _visitTaskRepository,
|
||||||
IRepository<TrialDocument> _trialDocumentRepository,
|
IRepository<TrialDocument> _trialDocumentRepository,
|
||||||
IRepository<IdentityUser> _identityUserRepository,
|
IRepository<IdentityUser> _identityUserRepository,
|
||||||
IRepository<Trial> _trialRepository,
|
|
||||||
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
|
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
IRepository<Dictionary> _dictionaryRepository,
|
||||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||||
@@ -201,11 +173,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
|
|
||||||
public async Task Consume(ConsumeContext<TrialDocumentPublishEvent> context)
|
public async Task Consume(ConsumeContext<TrialDocumentPublishEvent> context)
|
||||||
{
|
{
|
||||||
var isEn_US = context.Message.CultureInfoName == StaticData.CultureInfo.en_US;
|
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||||
|
|
||||||
//设置当前事件传递过来的语言
|
|
||||||
var culture = context.Message.CultureInfoName;
|
|
||||||
CultureInfo.CurrentCulture = new CultureInfo(culture);
|
|
||||||
|
|
||||||
// 记录是否只发送给新增角色的日志
|
// 记录是否只发送给新增角色的日志
|
||||||
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
||||||
@@ -230,7 +198,6 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
{
|
{
|
||||||
IsSystemDoc = true,
|
IsSystemDoc = true,
|
||||||
Id = trialDoc.Id,
|
Id = trialDoc.Id,
|
||||||
TrialId= trialDoc.TrialId,
|
|
||||||
CreateTime = trialDoc.CreateTime,
|
CreateTime = trialDoc.CreateTime,
|
||||||
IsDeleted = trialDoc.IsDeleted,
|
IsDeleted = trialDoc.IsDeleted,
|
||||||
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
||||||
@@ -252,9 +219,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
||||||
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
|
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
|
||||||
join trialUserRole in _trialUserRoleRepository.Where(x=>x.IsDeleted==false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
join trialUserRole in _trialUserRoleRepository.Where(x=>x.IsDeleted==false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||||
|
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
|
||||||
join trial in _trialRepository.AsQueryable(false) on trialDoc.TrialId equals trial.Id
|
|
||||||
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
|
|
||||||
on trialIdentityUser.IdentityUserId equals identityUser.Id
|
on trialIdentityUser.IdentityUserId equals identityUser.Id
|
||||||
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted &&trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
|
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted &&trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
|
||||||
|
|
||||||
@@ -263,8 +228,6 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
{
|
{
|
||||||
IsSystemDoc = false,
|
IsSystemDoc = false,
|
||||||
Id = trialDoc.Id,
|
Id = trialDoc.Id,
|
||||||
TrialId = trialDoc.TrialId,
|
|
||||||
EmailFromName =trial.EmailFromName,
|
|
||||||
CreateTime = trialDoc.CreateTime,
|
CreateTime = trialDoc.CreateTime,
|
||||||
IsDeleted = trialDoc.IsDeleted,
|
IsDeleted = trialDoc.IsDeleted,
|
||||||
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
||||||
@@ -279,70 +242,51 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
|||||||
FullFilePath = trialDoc.Path
|
FullFilePath = trialDoc.Path
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var datalist = await systemDocQuery.IgnoreQueryFilters().ToListAsync();
|
var datalist = await systemDocQuery.IgnoreQueryFilters().ToListAsync();
|
||||||
|
|
||||||
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||||
|
int index = 1;
|
||||||
var scenario = EmailBusinessScenario.TrialTraining_EffectiveNotification;
|
foreach (var userinfo in userinfoList)
|
||||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable).FirstOrDefault();
|
|
||||||
if (emailConfig == null)
|
|
||||||
{
|
{
|
||||||
return;
|
string msg = $"{index}项目生效通知,邮箱:{userinfo.EMail},姓名{userinfo.UserName},";
|
||||||
}
|
index++;
|
||||||
|
|
||||||
var userTrialIdList = datalist.Select(t => new { t.ConfirmUserId, t.TrialId }).Distinct().ToList();
|
|
||||||
var userWithTrialList = (from ut in userTrialIdList
|
|
||||||
join u in userinfoList on ut.ConfirmUserId equals u.Id
|
|
||||||
select new { ut.TrialId, User = u }).ToList();
|
|
||||||
|
|
||||||
var groupedList = userWithTrialList.GroupBy(x => new { x.TrialId, x.User.UserWorkLanguage }).ToList();
|
|
||||||
foreach (var groupItem in groupedList)
|
|
||||||
{
|
|
||||||
var langUserInfoList = groupItem.Select(x => x.User).Distinct().ToList();
|
|
||||||
if (!langUserInfoList.Any())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string msg = $"{langUserInfoList.Count}项目生效通知,";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||||
|
|
||||||
foreach (var userinfo in langUserInfoList)
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(userinfo.FullName, userinfo.EMail));
|
|
||||||
}
|
|
||||||
|
|
||||||
var workLanguage = groupItem.Key.UserWorkLanguage;
|
|
||||||
var userIsEn_US = workLanguage == UserWorkLanguage.US;
|
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
var companyName = userIsEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
var userNames = langUserInfoList.Select(x => x.UserName).ToList();
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(
|
var htmlBodyStr = string.Format(
|
||||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||||
string.Join(',', userNames),
|
userinfo.UserName, // 用户名 {0}
|
||||||
_systemEmailConfig.SiteUrl
|
_systemEmailConfig.SiteUrl
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.Where(x => x.Id == groupItem.Key.TrialId).FirstOrDefaultAsync();
|
var scenario = EmailBusinessScenario.TrialTraining_EffectiveNotification;
|
||||||
if (trialInfo == null)
|
|
||||||
|
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable).FirstOrDefault();
|
||||||
|
|
||||||
|
if (emailConfig != null)
|
||||||
{
|
{
|
||||||
continue;
|
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
msg += "发送成功";
|
||||||
}
|
}
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
msg += "发送成功";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
.WhereIf(inQuery.DoctorUserIdeaEnum != null, t => t.DoctorUserIdeaEnum == inQuery.DoctorUserIdeaEnum)
|
.WhereIf(inQuery.DoctorUserIdeaEnum != null, t => t.DoctorUserIdeaEnum == inQuery.DoctorUserIdeaEnum)
|
||||||
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.VisitTask.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.VisitTask.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
||||||
.WhereIf(inQuery.IsInvalid != null, t => t.IsInvalid == inQuery.IsInvalid)
|
.WhereIf(inQuery.IsInvalid != null, t => t.IsInvalid == inQuery.IsInvalid)
|
||||||
.WhereIf(inQuery.IsHaveQuestion != null, t => t.IsHaveQuestion == inQuery.IsHaveQuestion)
|
.WhereIf(inQuery.IsHaveQuestion != null, t => t.IsHaveQuestion == inQuery.IsHaveQuestion)
|
||||||
|
|
||||||
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime >= inQuery.BeginAllocateDate)
|
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime >= inQuery.BeginAllocateDate)
|
||||||
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime <= inQuery.EndAllocateDate)
|
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime <= inQuery.EndAllocateDate)
|
||||||
@@ -211,23 +211,23 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
.WhereIf(inQuery.SubjectId != null, t => t.VisitTask.SubjectId == inQuery.SubjectId)
|
.WhereIf(inQuery.SubjectId != null, t => t.VisitTask.SubjectId == inQuery.SubjectId)
|
||||||
.WhereIf(inQuery.TrialSiteId != null, t => t.VisitTask.Subject.TrialSiteId == inQuery.TrialSiteId)
|
.WhereIf(inQuery.TrialSiteId != null, t => t.VisitTask.Subject.TrialSiteId == inQuery.TrialSiteId)
|
||||||
.WhereIf(inQuery.IsUrgent != null, t => t.VisitTask.IsUrgent == inQuery.IsUrgent)
|
.WhereIf(inQuery.IsUrgent != null, t => t.VisitTask.IsUrgent == inQuery.IsUrgent)
|
||||||
.WhereIf(inQuery.AuditState != null, t => t.AuditState == inQuery.AuditState)
|
.WhereIf(inQuery.AuditState != null, t => t.AuditState == inQuery.AuditState)
|
||||||
.WhereIf(inQuery.DoctorUserIdeaEnum != null, t => t.DoctorUserIdeaEnum == inQuery.DoctorUserIdeaEnum)
|
.WhereIf(inQuery.DoctorUserIdeaEnum != null, t => t.DoctorUserIdeaEnum == inQuery.DoctorUserIdeaEnum)
|
||||||
.WhereIf(inQuery.TaskState != null, t => t.VisitTask.TaskState == inQuery.TaskState)
|
.WhereIf(inQuery.TaskState != null, t => t.VisitTask.TaskState == inQuery.TaskState)
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.VisitTask.Subject.Code.Contains(inQuery.SubjectCode) || t.VisitTask.Subject.MedicalNo.Contains(inQuery.SubjectCode))
|
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.VisitTask.Subject.Code.Contains(inQuery.SubjectCode) || t.VisitTask.Subject.MedicalNo.Contains(inQuery.SubjectCode))
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.VisitTask.TaskName.Contains(inQuery.TaskName) || t.VisitTask.TaskBlindName.Contains(inQuery.TaskName))
|
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.VisitTask.TaskName.Contains(inQuery.TaskName) || t.VisitTask.TaskBlindName.Contains(inQuery.TaskName))
|
||||||
.WhereIf(inQuery.DoctorUserId != null, t => t.VisitTask.DoctorUserId == inQuery.DoctorUserId)
|
.WhereIf(inQuery.DoctorUserId != null, t => t.VisitTask.DoctorUserId == inQuery.DoctorUserId)
|
||||||
.WhereIf(inQuery.ReadingCategory != null, t => t.VisitTask.ReadingCategory == inQuery.ReadingCategory)
|
.WhereIf(inQuery.ReadingCategory != null, t => t.VisitTask.ReadingCategory == inQuery.ReadingCategory)
|
||||||
.WhereIf(inQuery.ReadingTaskState != null, t => t.VisitTask.ReadingTaskState == inQuery.ReadingTaskState)
|
.WhereIf(inQuery.ReadingTaskState != null, t => t.VisitTask.ReadingTaskState == inQuery.ReadingTaskState)
|
||||||
.WhereIf(inQuery.IsInvalid != null, t => t.IsInvalid == inQuery.IsInvalid)
|
.WhereIf(inQuery.IsInvalid != null, t => t.IsInvalid == inQuery.IsInvalid)
|
||||||
.WhereIf(inQuery.IsGetBeRead, x => !x.IsInvalid && x.AuditState != MedicalReviewAuditState.HaveSigned)
|
.WhereIf(inQuery.IsGetBeRead, x => !x.IsInvalid && x.AuditState != MedicalReviewAuditState.HaveSigned)
|
||||||
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.VisitTask.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.VisitTask.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
||||||
.WhereIf(inQuery.BeginAuditSignTime != null, t => t.AuditSignTime >= inQuery.BeginAuditSignTime)
|
.WhereIf(inQuery.BeginAuditSignTime != null, t => t.AuditSignTime >= inQuery.BeginAuditSignTime)
|
||||||
.WhereIf(inQuery.EndAuditSignTime != null, t => t.AuditSignTime <= inQuery.EndAuditSignTime)
|
.WhereIf(inQuery.EndAuditSignTime != null, t => t.AuditSignTime <= inQuery.EndAuditSignTime)
|
||||||
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime >= inQuery.BeginAllocateDate)
|
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime >= inQuery.BeginAllocateDate)
|
||||||
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime <= inQuery.EndAllocateDate)
|
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime <= inQuery.EndAllocateDate)
|
||||||
|
|
||||||
.WhereIf(inQuery.ArmEnum != null, t => t.VisitTask.ArmEnum == inQuery.ArmEnum)
|
.WhereIf(inQuery.ArmEnum != null, t => t.VisitTask.ArmEnum == inQuery.ArmEnum)
|
||||||
.WhereIf(inQuery.MedicalManagerUserId != null, t => t.MedicalManagerUserId == inQuery.MedicalManagerUserId)
|
.WhereIf(inQuery.MedicalManagerUserId != null, t => t.MedicalManagerUserId == inQuery.MedicalManagerUserId)
|
||||||
.WhereIf(inQuery.BeginSignTime != null, t => t.VisitTask.SignTime > inQuery.BeginSignTime)
|
.WhereIf(inQuery.BeginSignTime != null, t => t.VisitTask.SignTime > inQuery.BeginSignTime)
|
||||||
.WhereIf(inQuery.EndSignTime != null, t => t.VisitTask.SignTime < inQuery.EndSignTime)
|
.WhereIf(inQuery.EndSignTime != null, t => t.VisitTask.SignTime < inQuery.EndSignTime)
|
||||||
|
|||||||
@@ -873,7 +873,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
arm1.TaskAllocationState = TaskAllocationState.Allocated;
|
arm1.TaskAllocationState = TaskAllocationState.Allocated;
|
||||||
arm1.AllocateTime = DateTime.Now;
|
arm1.AllocateTime = DateTime.Now;
|
||||||
arm1.DoctorUserId = assignConfigList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm1)!.DoctorUserId;
|
arm1.DoctorUserId = task1.DoctorUserId;
|
||||||
arm1.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
arm1.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +913,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
taskOne.TaskAllocationState = TaskAllocationState.Allocated;
|
taskOne.TaskAllocationState = TaskAllocationState.Allocated;
|
||||||
taskOne.AllocateTime = DateTime.Now;
|
taskOne.AllocateTime = DateTime.Now;
|
||||||
taskOne.DoctorUserId = assignConfigList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm1)!.DoctorUserId;
|
taskOne.DoctorUserId = task1!.DoctorUserId;
|
||||||
taskOne.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
taskOne.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -944,7 +944,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
arm2.TaskAllocationState = TaskAllocationState.Allocated;
|
arm2.TaskAllocationState = TaskAllocationState.Allocated;
|
||||||
arm2.AllocateTime = DateTime.Now;
|
arm2.AllocateTime = DateTime.Now;
|
||||||
arm2.DoctorUserId = assignConfigList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm2)!.DoctorUserId;
|
arm2.DoctorUserId = task2.DoctorUserId;
|
||||||
arm2.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
arm2.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,7 +986,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
taskTwo.TaskAllocationState = TaskAllocationState.Allocated;
|
taskTwo.TaskAllocationState = TaskAllocationState.Allocated;
|
||||||
taskTwo.AllocateTime = DateTime.Now;
|
taskTwo.AllocateTime = DateTime.Now;
|
||||||
taskTwo.DoctorUserId = assignConfigList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm2)!.DoctorUserId;
|
taskTwo.DoctorUserId = task2!.DoctorUserId;
|
||||||
taskTwo.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
taskTwo.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ using MassTransit;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Subject = IRaCIS.Core.Domain.Models.Subject;
|
using Subject = IRaCIS.Core.Domain.Models.Subject;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.Allocation;
|
namespace IRaCIS.Core.Application.Service.Allocation;
|
||||||
@@ -43,15 +41,10 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||||
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
||||||
IRepository<Segment> _segmentRepository,
|
|
||||||
IRepository<Segmentation> _segmentationRepository,
|
|
||||||
IRepository<SegmentBinding> _segmentBindingRepository,
|
|
||||||
IRepository<DicomInstance> _dicomInstanceRepository,
|
IRepository<DicomInstance> _dicomInstanceRepository,
|
||||||
IRepository<DicomSeries> _dicomSeriesRepository,
|
IRepository<DicomSeries> _dicomSeriesRepository,
|
||||||
IRepository<SubjectCanceDoctor> _subjectCanceDoctorRepository,
|
IRepository<SubjectCanceDoctor> _subjectCanceDoctorRepository,
|
||||||
IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMarkRepository,
|
IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMarkRepository,
|
||||||
IRepository<ReadingNoneDicomMark> _readingNoneDicomMarkRepository,
|
|
||||||
IRepository<ReadingNoneDicomMarkBinding> _readingNoneDicomMarkBindingRepository,
|
|
||||||
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
|
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
|
||||||
//IRepository<ReadingCustomTag> _readingCustomTagRepository,
|
//IRepository<ReadingCustomTag> _readingCustomTagRepository,
|
||||||
IRepository<TaskInfluence> _taskInfluenceRepository,
|
IRepository<TaskInfluence> _taskInfluenceRepository,
|
||||||
@@ -1016,9 +1009,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.IsOpenLostVistRead }).FirstOrDefault();
|
var extralObj = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.TrialExtraConfigJsonStr }).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 +1020,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 => extralObj.IsOpenLostVistRead ? t.IsLostVisit == false : true).Any(sv => sv.CheckState != CheckStateEnum.CVPassed && t.VisitTaskNum >= sv.VisitNum))
|
.Where(t => !t.Subject.SubjectVisitList.Where(t => extralConfig.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 +1043,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 => extralObj.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false).Where(y => y.TrialReadingCriterionId == trialReadingCriterionId && y.ReadingTaskState != ReadingTaskState.HaveSigned && (y.IsNeedClinicalDataSign == false || y.IsClinicalDataSign == true)
|
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)
|
||||||
//不能对包含聚合或子查询的表达式执行聚合函数
|
//不能对包含聚合或子查询的表达式执行聚合函数
|
||||||
//&& !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 => extralObj.IsOpenLostVistRead ? true : t.IsFrontTaskNeedSignButNotSign == false)
|
.Where(t => extralConfig.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()
|
||||||
@@ -1179,8 +1172,8 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == trialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect)
|
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == trialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect)
|
||||||
.WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId)
|
.WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId)
|
||||||
.WhereIf(!string.IsNullOrEmpty(subjectCode), t => (t.Subject.Code.Contains(subjectCode!) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(subjectCode!) && t.IsAnalysisCreate))
|
.WhereIf(!string.IsNullOrEmpty(subjectCode), t => (t.Subject.Code.Contains(subjectCode!) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(subjectCode!) && t.IsAnalysisCreate))
|
||||||
.WhereIf(critrion.CriterionType == CriterionType.OCT, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.Modality == "OCT").SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true)
|
.WhereIf(critrion.CriterionType == CriterionType.OCT, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true)
|
||||||
.WhereIf(critrion.CriterionType == CriterionType.IVUS, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.Modality == "IVUS").SelectMany(t => t.ImageLabelNoneDicomFileList).Any() : true);
|
.WhereIf(critrion.CriterionType == CriterionType.IVUS, t => t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.TaskStudyList.Any() : true);
|
||||||
|
|
||||||
var visitGroupQuery = visitQuery.GroupBy(x => new { x.SubjectId, x.Subject.Code, x.BlindSubjectCode });
|
var visitGroupQuery = visitQuery.GroupBy(x => new { x.SubjectId, x.Subject.Code, x.BlindSubjectCode });
|
||||||
|
|
||||||
@@ -2090,9 +2083,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
{
|
{
|
||||||
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
||||||
{
|
{
|
||||||
newTask.IsCopyLesionAnswer = true;
|
CopyForms(newTask, origenalTask);
|
||||||
|
|
||||||
//CopyForms(newTask, origenalTask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2190,6 +2181,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
||||||
{
|
{
|
||||||
CopyForms(newTask, origenalTask);
|
CopyForms(newTask, origenalTask);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2199,8 +2191,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
{
|
{
|
||||||
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
|
||||||
{
|
{
|
||||||
newTask.IsCopyLesionAnswer = true;
|
CopyForms(newTask, origenalTask);
|
||||||
//CopyForms(newTask, origenalTask);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2223,9 +2214,9 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CopyForms(VisitTask newTask, VisitTask origenalTask)
|
private void CopyForms(VisitTask newTask, VisitTask origenalTask)
|
||||||
{
|
{
|
||||||
newTask.IsCopyLesionAnswer = true;
|
|
||||||
//自定义
|
//自定义
|
||||||
//var readingCustomTagList = _readingCustomTagRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
//var readingCustomTagList = _readingCustomTagRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
||||||
|
|
||||||
@@ -2239,7 +2230,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
//_ = _readingCustomTagRepository.AddRangeAsync(readingCustomTagList).Result;
|
//_ = _readingCustomTagRepository.AddRangeAsync(readingCustomTagList).Result;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var readingTaskQuestionAnswerList = _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
var readingTaskQuestionAnswerList = _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
||||||
@@ -2268,7 +2258,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
|
|
||||||
//ReadingTableAnswerRowInfo ReadingTableQuestionAnswer 一起加
|
//ReadingTableAnswerRowInfo ReadingTableQuestionAnswer 一起加
|
||||||
var readingTableAnswerRowInfoList = _readingTableAnswerRowInfoRepository.Where(t => t.VisitTaskId == origenalTask.Id).Include(t => t.LesionAnswerList).ToList();
|
var readingTableAnswerRowInfoList = _readingTableAnswerRowInfoRepository.Where(t => t.VisitTaskId == origenalTask.Id).Include(t => t.LesionAnswerList).ToList();
|
||||||
Dictionary<Guid, Guid> lesionRelationship = new Dictionary<Guid, Guid>() { };
|
|
||||||
foreach (var item in readingTableAnswerRowInfoList)
|
foreach (var item in readingTableAnswerRowInfoList)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2276,7 +2266,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
var originalFristAddTaskId = item.FristAddTaskId;
|
var originalFristAddTaskId = item.FristAddTaskId;
|
||||||
|
|
||||||
var newRowId = NewId.NextSequentialGuid();
|
var newRowId = NewId.NextSequentialGuid();
|
||||||
lesionRelationship.Add(item.Id, newRowId);
|
|
||||||
foreach (var mark in readingTaskQuestionMarkList)
|
foreach (var mark in readingTaskQuestionMarkList)
|
||||||
{
|
{
|
||||||
mark.RowId = mark.RowId == item.Id ? newRowId : mark.RowId;
|
mark.RowId = mark.RowId == item.Id ? newRowId : mark.RowId;
|
||||||
@@ -2298,112 +2288,13 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region 分割
|
|
||||||
Dictionary<Guid, Guid> segmentationRelationship = new Dictionary<Guid, Guid>() { };
|
|
||||||
var segmentationList = _segmentationRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
|
||||||
|
|
||||||
foreach (var item in segmentationList)
|
|
||||||
{
|
|
||||||
|
|
||||||
var newSegmentationId = NewId.NextSequentialGuid();
|
|
||||||
segmentationRelationship.Add(item.Id, newSegmentationId);
|
|
||||||
item.Id = newSegmentationId;
|
|
||||||
item.VisitTaskId = newTask.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Dictionary<Guid, Guid> segmentRelationship = new Dictionary<Guid, Guid>() { };
|
|
||||||
var segmentList = _segmentRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
|
||||||
foreach (var item in segmentList)
|
|
||||||
{
|
|
||||||
var newSegmentationId = NewId.NextSequentialGuid();
|
|
||||||
segmentRelationship.Add(item.Id, newSegmentationId);
|
|
||||||
if (segmentationRelationship.ContainsKey(item.SegmentationId))
|
|
||||||
{
|
|
||||||
item.SegmentationId = segmentationRelationship[item.SegmentationId];
|
|
||||||
}
|
|
||||||
item.Id = newSegmentationId;
|
|
||||||
item.VisitTaskId = newTask.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
var segmentBindingList = _segmentBindingRepository.Where(x => x.VisitTaskId == origenalTask.Id).ToList();
|
|
||||||
|
|
||||||
foreach (var item in segmentBindingList)
|
|
||||||
{
|
|
||||||
if (segmentationRelationship.ContainsKey(item.SegmentationId))
|
|
||||||
{
|
|
||||||
item.SegmentationId = segmentationRelationship[item.SegmentationId];
|
|
||||||
}
|
|
||||||
if (segmentRelationship.ContainsKey(item.SegmentId))
|
|
||||||
{
|
|
||||||
item.SegmentId = segmentRelationship[item.SegmentId];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.RowId != null && lesionRelationship.ContainsKey(item.RowId.Value))
|
|
||||||
{
|
|
||||||
item.RowId = lesionRelationship[item.RowId.Value];
|
|
||||||
}
|
|
||||||
item.Id = NewId.NextSequentialGuid();
|
|
||||||
item.VisitTaskId = newTask.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_ = _segmentationRepository.AddRangeAsync(segmentationList).Result;
|
|
||||||
_ = _segmentRepository.AddRangeAsync(segmentList).Result;
|
|
||||||
_ = _segmentBindingRepository.AddRangeAsync(segmentBindingList).Result;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in readingTableAnswerRowInfoList)
|
|
||||||
{
|
|
||||||
if (item.SplitRowId != null && lesionRelationship.ContainsKey(item.SplitRowId.Value))
|
|
||||||
{
|
|
||||||
item.SplitRowId = lesionRelationship[item.SplitRowId.Value];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.MergeRowId != null && lesionRelationship.ContainsKey(item.MergeRowId.Value))
|
|
||||||
{
|
|
||||||
item.MergeRowId = lesionRelationship[item.MergeRowId.Value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = _readingTaskQuestionMarkRepository.AddRangeAsync(readingTaskQuestionMarkList).Result;
|
_ = _readingTaskQuestionMarkRepository.AddRangeAsync(readingTaskQuestionMarkList).Result;
|
||||||
_ = _readingTableAnswerRowInfoRepository.AddRangeAsync(readingTableAnswerRowInfoList).Result;
|
_ = _readingTableAnswerRowInfoRepository.AddRangeAsync(readingTableAnswerRowInfoList).Result;
|
||||||
|
|
||||||
|
|
||||||
var noneMarkList = _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == origenalTask.Id).ToList();
|
|
||||||
|
|
||||||
var noneMarkBindingList = _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == origenalTask.Id).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in noneMarkList)
|
|
||||||
{
|
|
||||||
var newid = NewId.NextSequentialGuid();
|
|
||||||
|
|
||||||
item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
|
|
||||||
item.VisitTaskId = newTask.Id;
|
|
||||||
foreach (var item1 in noneMarkBindingList)
|
|
||||||
{
|
|
||||||
if (item1.NoneDicomMarkId == item.Id)
|
|
||||||
{
|
|
||||||
item1.NoneDicomMarkId = newid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item.Id = newid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in noneMarkBindingList)
|
|
||||||
{
|
|
||||||
item.Id = NewId.NextSequentialGuid();
|
|
||||||
item.VisitTaskId = newTask.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = _readingNoneDicomMarkRepository.AddRangeAsync(noneMarkList).Result;
|
|
||||||
_ = _readingNoneDicomMarkBindingRepository.AddRangeAsync(noneMarkBindingList).Result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2496,10 +2387,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
//另一个阅片人的任务根据任务进度自动进入PM退回或PM申请重阅
|
//另一个阅片人的任务根据任务进度自动进入PM退回或PM申请重阅
|
||||||
filterExpression = filterExpression.And(t => t.VisitTaskNum >= task.VisitTaskNum);
|
filterExpression = filterExpression.And(t => t.VisitTaskNum >= task.VisitTaskNum);
|
||||||
|
|
||||||
//退回只影响有序的后续所有的,无序的当前访视
|
|
||||||
filterExpression = filterExpression.And(t => (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) ||
|
|
||||||
(t.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder && t.SourceSubjectVisitId == task.SourceSubjectVisitId));
|
|
||||||
|
|
||||||
|
|
||||||
var influenceTaskList = await _visitTaskRepository.Where(filterExpression, true).ToListAsync();
|
var influenceTaskList = await _visitTaskRepository.Where(filterExpression, true).ToListAsync();
|
||||||
|
|
||||||
@@ -2657,12 +2544,9 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
|
|
||||||
//删除序列数据
|
//删除序列数据
|
||||||
await _subjectCriteriaEvaluationVisitStudyFilterRepository.BatchDeleteNoTrackingAsync(t => t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB && t.SubjectVisit.SubjectId == task.SubjectId && t.SubjectVisitId == task.SourceSubjectVisitId);
|
await _subjectCriteriaEvaluationVisitStudyFilterRepository.BatchDeleteNoTrackingAsync(t => t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB && t.SubjectVisit.SubjectId == task.SubjectId && t.SubjectVisitId == task.SourceSubjectVisitId);
|
||||||
|
|
||||||
otherVisitIdList = otherVisitIdList.Where(t => t != task.SourceSubjectVisitId.Value).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//BM后续访视 ,筛选状态不变,任务生成状态重置(实际该访视任务状态 可能是重阅重置了或者失效了,需要后续生成,或者取消分配了,需要后续重新分配)
|
//BM后续访视 ,筛选状态不变,任务生成状态重置(实际该访视任务状态 可能是重阅重置了或者失效了,需要后续生成,或者取消分配了,需要后续重新分配)
|
||||||
await _subjectCriteriaEvaluationVisitFilterRepository.UpdatePartialFromQueryAsync(t => t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB && t.SubjectVisit.SubjectId == task.SubjectId && otherVisitIdList.Contains(t.SubjectVisitId),
|
await _subjectCriteriaEvaluationVisitFilterRepository.UpdatePartialFromQueryAsync(t => t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB && t.SubjectVisit.SubjectId == task.SubjectId && otherVisitIdList.Contains(t.SubjectVisitId),
|
||||||
t => new SubjectCriteriaEvaluationVisitFilter()
|
t => new SubjectCriteriaEvaluationVisitFilter()
|
||||||
@@ -2716,19 +2600,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
sv.ReviewAuditUserId = null;
|
sv.ReviewAuditUserId = null;
|
||||||
sv.SecondReviewState = SecondReviewState.None;
|
sv.SecondReviewState = SecondReviewState.None;
|
||||||
|
|
||||||
|
|
||||||
// 处理阅片期的临床数据
|
|
||||||
var readModuleIdList =await _readModuleRepository.Where(x => x.SubjectVisitId == sv.Id).Select(x => x.Id).ToListAsync();
|
|
||||||
|
|
||||||
|
|
||||||
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => readModuleIdList.Contains(t.ReadingId), c => new ReadingClinicalData()
|
|
||||||
{
|
|
||||||
IsSign = false,
|
|
||||||
ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (sv.IsBaseLine)
|
if (sv.IsBaseLine)
|
||||||
{
|
{
|
||||||
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && (t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.Subject || t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit), c => new ReadingClinicalData() { IsSign = false, ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded });
|
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && (t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.Subject || t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit), c => new ReadingClinicalData() { IsSign = false, ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded });
|
||||||
@@ -2837,13 +2708,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||||||
//默认影响的都是该标准的任务
|
//默认影响的都是该标准的任务
|
||||||
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId);
|
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//退回只影响有序的后续所有的,无序的当前访视
|
|
||||||
if (isReReading == false)
|
|
||||||
{
|
|
||||||
filterExpression = filterExpression.And(t => (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) ||
|
|
||||||
(t.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder && t.SourceSubjectVisitId == filterObj.SourceSubjectVisitId));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,187 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2025-10-28 06:22:47Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
namespace IRaCIS.Core.Application.ViewModel;
|
|
||||||
|
|
||||||
|
|
||||||
public class GetReSendEmailInDto : PageInput
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public DateTime? EmailStartDate { get; set; }
|
|
||||||
|
|
||||||
public DateTime? EmailEndDate { get; set; }
|
|
||||||
|
|
||||||
public EmailState? EmailStateEnum { get; set; }
|
|
||||||
|
|
||||||
public string ToRecipientName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CcRecipientName { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
public class EmailLogView : EmailLogAddOrEdit
|
|
||||||
{
|
|
||||||
|
|
||||||
public DateTime CreateTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime UpdateTime { get; set; }
|
|
||||||
|
|
||||||
public List<EmailRecipientLogView> RecipientList { get; set; }
|
|
||||||
|
|
||||||
public List<EmaliAttachmentInfo> AttachmentList { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class EmaliAttachmentInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 附件名称
|
|
||||||
/// </summary>
|
|
||||||
public string AttachmentName { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// 附件路径
|
|
||||||
/// </summary>
|
|
||||||
public string AttachmentPath { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EmailRecipientLogView
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件Id
|
|
||||||
/// </summary>
|
|
||||||
public Guid EmailLogId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 收件人姓名
|
|
||||||
/// </summary>
|
|
||||||
public string RecipientName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 收件人地址
|
|
||||||
/// </summary>
|
|
||||||
public string RecipientAddress { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 收件人类型
|
|
||||||
/// </summary>
|
|
||||||
public RecipientType RecipientTypeEnum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
public int Sort { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class EmailLogAddOrEdit
|
|
||||||
{
|
|
||||||
public Guid? Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件Id
|
|
||||||
/// </summary>
|
|
||||||
public string MessageId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 唯一Id
|
|
||||||
/// </summary>
|
|
||||||
public string UniqueId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件主题
|
|
||||||
/// </summary>
|
|
||||||
public string EmailSubject { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 日期
|
|
||||||
/// </summary>
|
|
||||||
public DateTime? EmailDate { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 错误信息
|
|
||||||
/// </summary>
|
|
||||||
public string ErrorInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 发件人地址
|
|
||||||
/// </summary>
|
|
||||||
public string SenderAddress { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 发件人姓名
|
|
||||||
/// </summary>
|
|
||||||
public string SenderName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件内容
|
|
||||||
/// </summary>
|
|
||||||
public string Content { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件状态
|
|
||||||
/// </summary>
|
|
||||||
public EmailState EmailStateEnum { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GetEmailInfoOutDto:EmailLogView
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class GetEmailInfoInDto
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SynchronizationEmailInDto
|
|
||||||
{
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ResendEmailInDto
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EmailAuthorization
|
|
||||||
{
|
|
||||||
public string FromEmail { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string AuthorizationCode { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EmailLogQuery:PageInput
|
|
||||||
{
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
|
|
||||||
public DateTime? EmailStartDate { get; set; }
|
|
||||||
|
|
||||||
public DateTime? EmailEndDate { get; set; }
|
|
||||||
|
|
||||||
public EmailState? EmailStateEnum { get; set; }
|
|
||||||
|
|
||||||
public string ToRecipientName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string CcRecipientName { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2026-03-10 06:15:31Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using System;
|
|
||||||
using IRaCIS.Core.Domain.Share;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
namespace IRaCIS.Core.Application.ViewModel;
|
|
||||||
|
|
||||||
public class SubjectFileUploadRecordView
|
|
||||||
{
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
public string StudyCode { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectVisitId { get; set; }
|
|
||||||
|
|
||||||
public int FileCount { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string? UploadRegion { get; set; }
|
|
||||||
public string? TargetRegion { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public DateTime CreateTime { get; set; }
|
|
||||||
public DateTime? SyncFinishedTime { get; set; }
|
|
||||||
|
|
||||||
public bool IsSync { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FileUploadRecordView : FileUploadRecordAddOrEdit
|
|
||||||
{
|
|
||||||
|
|
||||||
public DateTime CreateTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime UpdateTime { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Comment("同步结束时间-最后一个任务的时间")]
|
|
||||||
public DateTime? SyncFinishedTime { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class FileUploadRecordAddOrEdit
|
|
||||||
{
|
|
||||||
public Guid? Id { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
public long FileSize { get; set; }
|
|
||||||
|
|
||||||
public string FileType { get; set; }
|
|
||||||
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string UploadBatchId { get; set; }
|
|
||||||
public BatchDataType BatchDataType { get; set; }
|
|
||||||
|
|
||||||
public string StudyCode { get; set; }
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectVisitId { get; set; }
|
|
||||||
|
|
||||||
public Guid? DicomStudyId { get; set; }
|
|
||||||
|
|
||||||
public Guid? NoneDicomStudyId { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public string FileMarkId { get; set; }
|
|
||||||
|
|
||||||
public int? Priority { get; set; }
|
|
||||||
public string IP { get; set; }
|
|
||||||
public bool? IsNeedSync { get; set; }
|
|
||||||
public string UploadRegion { get; set; }
|
|
||||||
public string TargetRegion { get; set; }
|
|
||||||
|
|
||||||
public bool? IsSync { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public class SubjectFileUploadRecordQuery : PageInput
|
|
||||||
{
|
|
||||||
public Guid TrialId { get; set; }
|
|
||||||
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
public string? StudyCode { get; set; }
|
|
||||||
|
|
||||||
public string? UploadRegion { get; set; }
|
|
||||||
public string? TargetRegion { get; set; }
|
|
||||||
|
|
||||||
public bool? IsSync { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FileUploadRecordQuery : PageInput
|
|
||||||
{
|
|
||||||
|
|
||||||
public BatchDataType? BatchDataType { get; set; }
|
|
||||||
|
|
||||||
public Guid? TrialId { get; set; }
|
|
||||||
|
|
||||||
public int? DataFileType { get; set; }
|
|
||||||
|
|
||||||
public string StudyCode { get; set; }
|
|
||||||
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public Guid? SubjectId { get; set; }
|
|
||||||
|
|
||||||
public Guid? SubjectVisitId { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public string? FileMarkId { get; set; }
|
|
||||||
|
|
||||||
public string? FileName { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string? FileType { get; set; }
|
|
||||||
|
|
||||||
public string? IP { get; set; }
|
|
||||||
|
|
||||||
public bool? IsNeedSync { get; set; }
|
|
||||||
|
|
||||||
public bool? IsSync { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string? Path { get; set; }
|
|
||||||
|
|
||||||
public int? Priority { get; set; }
|
|
||||||
|
|
||||||
public string? TargetRegion { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string? UploadBatchId { get; set; }
|
|
||||||
|
|
||||||
public string? UploadRegion { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public DateTime? SyncFinishedStartTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime? SyncFinishedEndTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime? UploadStartTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime? UploadEndTime { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class UploadFileSyncRecordView
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public DateTime? StartTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime? EndTime { get; set; }
|
|
||||||
|
|
||||||
public jobState JobState { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string Msg { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreateTime { get; set; }
|
|
||||||
|
|
||||||
public DateTime UpdateTime { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public Guid? FileUploadRecordId { get; set; }
|
|
||||||
public string? FileName { get; set; }
|
|
||||||
|
|
||||||
public string? FileType { get; set; }
|
|
||||||
|
|
||||||
public string? Path { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public string StudyCode { get; set; }
|
|
||||||
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UploadFileSyncRecordQuery : PageInput
|
|
||||||
{
|
|
||||||
|
|
||||||
public Guid? FileUploadRecordId { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public jobState? JobState { get; set; }
|
|
||||||
|
|
||||||
public string? SubjectCode { get; set; }
|
|
||||||
|
|
||||||
public string? VisitName { get; set; }
|
|
||||||
|
|
||||||
public string? StudyCode { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BatchAddSyncFileCommand
|
|
||||||
{
|
|
||||||
public List<Guid> FileUploadRecordIdList { get; set; }
|
|
||||||
|
|
||||||
public int? Priority { get; set; }
|
|
||||||
}
|
|
||||||
@@ -159,12 +159,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||||||
public class FrontAuditConfigAddOrEdit
|
public class FrontAuditConfigAddOrEdit
|
||||||
{
|
{
|
||||||
public Guid? Id { get; set; }
|
public Guid? Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 适用的标准
|
|
||||||
/// </summary>
|
|
||||||
public List<CriterionType> ApplyCriterionList { get; set; } = new List<CriterionType>() { };
|
|
||||||
|
|
||||||
public string Value { get; set; } = string.Empty;
|
public string Value { get; set; } = string.Empty;
|
||||||
public string ValueCN { get; set; } = string.Empty;
|
public string ValueCN { get; set; } = string.Empty;
|
||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.Common.DTO
|
|
||||||
{
|
|
||||||
//public class MailModel
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
|
||||||
using IRaCIS.Application.Contracts;
|
|
||||||
using Medallion.Threading;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.Common;
|
|
||||||
|
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
|
||||||
public class DeployConfigService(IMapper _mapper, IUserInfo _userInfo, IWebHostEnvironment _hostEnvironment, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取系统基础配置信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<ServiceVerifyConfigOption> GetSystemBasicConfigInfo([FromServices] IOptionsMonitor<ServiceVerifyConfigOption> options)
|
|
||||||
{
|
|
||||||
return options.CurrentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新系统基础配置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="basicSystemConfigOption"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IResponseOutput> UpdateSystemBasicConfig(ServiceVerifyConfigOption basicSystemConfigOption)
|
|
||||||
{
|
|
||||||
var path = $"appsettings.{_hostEnvironment.EnvironmentName}.json";
|
|
||||||
|
|
||||||
string text = System.IO.File.ReadAllText(path);
|
|
||||||
|
|
||||||
// 修改
|
|
||||||
JObject obj = JObject.Parse(text);
|
|
||||||
// QCRiskControl 相关配置
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.QCRiskControl)] = basicSystemConfigOption.QCRiskControl;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.OpenUserComplexPassword)] = basicSystemConfigOption.OpenUserComplexPassword;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.OpenSignDocumentBeforeWork)] = basicSystemConfigOption.OpenSignDocumentBeforeWork;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.OpenTrialRelationDelete)] = basicSystemConfigOption.OpenTrialRelationDelete;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.OpenLoginLimit)] = basicSystemConfigOption.OpenLoginLimit;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.LoginMaxFailCount)] = basicSystemConfigOption.LoginMaxFailCount;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.LoginFailLockMinutes)] = basicSystemConfigOption.LoginFailLockMinutes;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.AutoLoginOutMinutes)] = basicSystemConfigOption.AutoLoginOutMinutes;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.OpenLoginMFA)] = basicSystemConfigOption.OpenLoginMFA;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ContinuousReadingTimeMin)] = basicSystemConfigOption.ContinuousReadingTimeMin;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ReadingRestTimeMin)] = basicSystemConfigOption.ReadingRestTimeMin;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.IsNeedChangePassWord)] = basicSystemConfigOption.IsNeedChangePassWord;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ChangePassWordDays)] = basicSystemConfigOption.ChangePassWordDays;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.TemplateType)] = ((int)basicSystemConfigOption.TemplateType); // 枚举需要转换为字符串
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.ThirdPdfUrl)] = basicSystemConfigOption.ThirdPdfUrl;
|
|
||||||
obj["BasicSystemConfig"][nameof(ServiceVerifyConfigOption.UserMFAVerifyMinutes)] = basicSystemConfigOption.UserMFAVerifyMinutes;
|
|
||||||
|
|
||||||
|
|
||||||
// 重新写入appsettings.json
|
|
||||||
string result = obj.ToString();
|
|
||||||
System.IO.File.WriteAllText(path, result);
|
|
||||||
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取系统邮件配置信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<SystemEmailSendConfig> GetEmailConfigInfo([FromServices] IOptionsMonitor<SystemEmailSendConfig> options)
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,769 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2025-10-28 06:22:42Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using DocumentFormat.OpenXml.Wordprocessing;
|
|
||||||
using IdentityModel.Client;
|
|
||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
using IRaCIS.Core.Application.Interfaces;
|
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using MailKit;
|
|
||||||
using MailKit.Net.Imap;
|
|
||||||
using MailKit.Search;
|
|
||||||
using MailKit.Security;
|
|
||||||
using MassTransit;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using MimeKit;
|
|
||||||
using Panda.DynamicWebApi.Attributes;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Mail;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
namespace IRaCIS.Core.Application.Service;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 邮件日志
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="_emailLogRepository"></param>
|
|
||||||
/// <param name="systemEmailConfig"></param>
|
|
||||||
/// <param name="_mapper"></param>
|
|
||||||
/// <param name="_userInfo"></param>
|
|
||||||
/// <param name="_localizer"></param>
|
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
|
||||||
public class EmailLogService(IRepository<EmailLog> _emailLogRepository,
|
|
||||||
IRepository<Trial> _trialRepository,
|
|
||||||
IRepository<EmailAttachmentLog> _emailAttachmentLogRepository,
|
|
||||||
IOSSService oSSService,
|
|
||||||
IRepository<EmailReSendLog> _emailReSendLog,
|
|
||||||
|
|
||||||
IRepository<EmailRecipientLog> _emailRecipientLogRepository,
|
|
||||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
|
||||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, IEmailLogService
|
|
||||||
{
|
|
||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取邮件日志列表
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inQuery"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<PageOutput<EmailLogView>> GetEmailLogList(EmailLogQuery inDto)
|
|
||||||
{
|
|
||||||
var emailFromName = await _trialRepository.Where(x=>x.Id==inDto.TrialId).Select(x=>x.EmailFromName).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
if (emailFromName.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
emailFromName = _systemEmailConfig.FromName;
|
|
||||||
}
|
|
||||||
var emailLogQueryable = _emailLogRepository
|
|
||||||
.Where(x=>x.SenderName== emailFromName)
|
|
||||||
.WhereIf(inDto.EmailStartDate.HasValue, x => x.EmailDate >= inDto.EmailStartDate.Value)
|
|
||||||
.WhereIf(inDto.EmailEndDate.HasValue, x => x.EmailDate <= inDto.EmailEndDate.Value)
|
|
||||||
.WhereIf(inDto.EmailStateEnum.HasValue, x => x.EmailStateEnum == inDto.EmailStateEnum.Value)
|
|
||||||
.WhereIf(inDto.CcRecipientName.IsNotNullOrEmpty(),x=>x.EmailRecipientLogList.Any(x=>x.RecipientTypeEnum==RecipientType.Cc&&x.RecipientName.Contains(inDto.CcRecipientName)))
|
|
||||||
.WhereIf(inDto.ToRecipientName.IsNotNullOrEmpty(), x => x.EmailRecipientLogList.Any(x => x.RecipientTypeEnum == RecipientType.To && x.RecipientName.Contains(inDto.ToRecipientName)))
|
|
||||||
.ProjectTo<EmailLogView>(_mapper.ConfigurationProvider);
|
|
||||||
|
|
||||||
var defalutSortArray = new string[] { nameof(EmailLogView.EmailDate) + " desc" };
|
|
||||||
var pageList = await emailLogQueryable.ToPagedListAsync(inDto, defalutSortArray);
|
|
||||||
|
|
||||||
return pageList;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取重发信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inDto"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<PageOutput<EmailLogView>> GetReSendEmail(GetReSendEmailInDto inDto)
|
|
||||||
{
|
|
||||||
var messageId = await _emailLogRepository.Where(x => x.Id == inDto.Id).Select(x => x.MessageId).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
var reSendMessagelist = await _emailReSendLog.Where(x => x.MainMailMessageId == messageId).Select(x => x.ReMailMessageId).ToListAsync();
|
|
||||||
var emailLogQueryable = _emailLogRepository
|
|
||||||
|
|
||||||
.Where(x => reSendMessagelist.Contains(x.MessageId))
|
|
||||||
.WhereIf(inDto.EmailStartDate.HasValue, x => x.EmailDate >= inDto.EmailStartDate.Value)
|
|
||||||
.WhereIf(inDto.EmailEndDate.HasValue, x => x.EmailDate <= inDto.EmailEndDate.Value)
|
|
||||||
.WhereIf(inDto.EmailStateEnum.HasValue, x => x.EmailStateEnum == inDto.EmailStateEnum.Value)
|
|
||||||
.WhereIf(inDto.CcRecipientName.IsNotNullOrEmpty(), x => x.EmailRecipientLogList.Any(x => x.RecipientTypeEnum == RecipientType.Cc && x.RecipientName.Contains(inDto.CcRecipientName)))
|
|
||||||
.WhereIf(inDto.ToRecipientName.IsNotNullOrEmpty(), x => x.EmailRecipientLogList.Any(x => x.RecipientTypeEnum == RecipientType.To && x.RecipientName.Contains(inDto.ToRecipientName)))
|
|
||||||
.ProjectTo<EmailLogView>(_mapper.ConfigurationProvider);
|
|
||||||
|
|
||||||
var defalutSortArray = new string[] { nameof(EmailLogView.EmailDate) + " desc" };
|
|
||||||
var pageList = await emailLogQueryable.ToPagedListAsync(inDto, defalutSortArray);
|
|
||||||
|
|
||||||
return pageList;
|
|
||||||
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// 获取单条邮件日志详情
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inDto"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<GetEmailInfoOutDto> GetEmailInfo(GetEmailInfoInDto inDto)
|
|
||||||
{
|
|
||||||
|
|
||||||
var emailInfo=await _emailLogRepository
|
|
||||||
.Where(x => x.Id == inDto.Id).Include(x=>x.EmailRecipientLogList)
|
|
||||||
.ProjectTo<GetEmailInfoOutDto>(_mapper.ConfigurationProvider).AsNoTracking()
|
|
||||||
.FirstNotNullAsync();
|
|
||||||
|
|
||||||
if (emailInfo.UniqueId.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
using (var client = new ImapClient())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await AuthenticateImap(client,inDto.TrialId);
|
|
||||||
var sentFolder = OpenSentFolder(client);
|
|
||||||
var uid = new UniqueId(uint.Parse(emailInfo.UniqueId));
|
|
||||||
var message = sentFolder.GetMessage(uid);
|
|
||||||
emailInfo.Content = message.HtmlBody ?? message.TextBody ?? string.Empty;
|
|
||||||
|
|
||||||
|
|
||||||
if (emailInfo.AttachmentList.Count == 0)
|
|
||||||
{
|
|
||||||
List< EmaliAttachmentInfo > attachmentInfos = new List<EmaliAttachmentInfo>();
|
|
||||||
foreach (var att in message.Attachments)
|
|
||||||
{
|
|
||||||
EmaliAttachmentInfo emaliAttachmentInfo = new EmaliAttachmentInfo();
|
|
||||||
emaliAttachmentInfo.AttachmentName = att.ContentDisposition?.FileName ?? att.ContentType.Name ?? "unknown";
|
|
||||||
|
|
||||||
// 2. 解码后的流直接上传,不落盘
|
|
||||||
if (att is MimePart part)
|
|
||||||
{
|
|
||||||
// 重要:每次上传新建一个独立流,否则迭代过程中流位置会乱
|
|
||||||
await using var decodeStream = new MemoryStream();
|
|
||||||
await part.Content.DecodeToAsync(decodeStream);
|
|
||||||
decodeStream.Position = 0;
|
|
||||||
|
|
||||||
|
|
||||||
emaliAttachmentInfo.AttachmentPath = await oSSService.UploadToOSSAsync(
|
|
||||||
fileStream: decodeStream,
|
|
||||||
oosFolderPath: $"EmailAttachment/{emailInfo.Id}", // OSS 虚拟目录
|
|
||||||
fileRealName: emaliAttachmentInfo.AttachmentName,
|
|
||||||
isFileNameAddGuid: true,
|
|
||||||
uploadInfo: new FileUploadRecordAddOrEdit() {TrialId= inDto.TrialId, BatchDataType = BatchDataType.EmailAttach }); // 让方法自己在文件名前加 Guid
|
|
||||||
|
|
||||||
attachmentInfos.Add(emaliAttachmentInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
List<EmailAttachmentLog> emailAttachmentLog = attachmentInfos.Select(x => new EmailAttachmentLog()
|
|
||||||
{
|
|
||||||
EmailLogId = emailInfo.Id.Value,
|
|
||||||
AttachmentName = x.AttachmentName,
|
|
||||||
AttachmentPath = x.AttachmentPath,
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
await _emailAttachmentLogRepository.AddRangeAsync(emailAttachmentLog);
|
|
||||||
await _emailAttachmentLogRepository.SaveChangesAsync();
|
|
||||||
|
|
||||||
emailInfo.AttachmentList = attachmentInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sentFolder.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.Disconnect(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName);
|
|
||||||
|
|
||||||
return emailInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重发邮件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inDto"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IResponseOutput> ResendEmail(ResendEmailInDto inDto)
|
|
||||||
{
|
|
||||||
var emailInfo = await _emailLogRepository
|
|
||||||
.Where(x => x.Id == inDto.Id)
|
|
||||||
.ProjectTo<GetEmailInfoOutDto>(_mapper.ConfigurationProvider)
|
|
||||||
.FirstNotNullAsync();
|
|
||||||
|
|
||||||
if (emailInfo.UniqueId.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
using (var client = new ImapClient())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await AuthenticateImap(client,inDto.TrialId);
|
|
||||||
var sentFolder = OpenSentFolder(client);
|
|
||||||
var uid = new UniqueId(uint.Parse(emailInfo.UniqueId));
|
|
||||||
var message = sentFolder.GetMessage(uid);
|
|
||||||
emailInfo.Content = message.HtmlBody ?? message.TextBody ?? string.Empty;
|
|
||||||
sentFolder.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.Disconnect(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
// 发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(emailInfo.SenderName, emailInfo.SenderAddress));
|
|
||||||
|
|
||||||
foreach (var item in emailInfo.RecipientList.Where(x => x.RecipientTypeEnum == RecipientType.To))
|
|
||||||
{
|
|
||||||
messageToSend.To.Add(new MailboxAddress(item.RecipientName, item.RecipientAddress));
|
|
||||||
}
|
|
||||||
foreach (var item in emailInfo.RecipientList.Where(x => x.RecipientTypeEnum == RecipientType.Cc))
|
|
||||||
{
|
|
||||||
messageToSend.Cc.Add(new MailboxAddress(item.RecipientName, item.RecipientAddress));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
messageToSend.Subject = emailInfo.EmailSubject;
|
|
||||||
|
|
||||||
var builder = new BodyBuilder();
|
|
||||||
|
|
||||||
builder.HtmlBody = emailInfo.Content;
|
|
||||||
|
|
||||||
messageToSend.Body = builder.ToMessageBody();
|
|
||||||
|
|
||||||
SystemEmailSendConfig sendConfig = new SystemEmailSendConfig()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
if (inDto.TrialId != null)
|
|
||||||
{
|
|
||||||
sendConfig = await _trialRepository.Where(x => x.Id == inDto.TrialId.Value).Select(x => new SystemEmailSendConfig()
|
|
||||||
{
|
|
||||||
Host = _systemEmailConfig.Host,
|
|
||||||
Port = _systemEmailConfig.Port,
|
|
||||||
FromEmail = x.EmailFromEmail,
|
|
||||||
AuthorizationCode = x.EmailAuthorizationCode
|
|
||||||
}).FirstNotNullAsync();
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sendConfig = _systemEmailConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
var msgid= await SendEmailHelper.SendEmailAsync(messageToSend, sendConfig);
|
|
||||||
|
|
||||||
|
|
||||||
await _emailReSendLog.AddAsync(new EmailReSendLog()
|
|
||||||
{
|
|
||||||
MainMailMessageId= emailInfo.MessageId,
|
|
||||||
ReMailMessageId= msgid
|
|
||||||
});
|
|
||||||
|
|
||||||
await _emailReSendLog.SaveChangesAsync();
|
|
||||||
|
|
||||||
await SynchronizationEmail(new SynchronizationEmailInDto() {
|
|
||||||
|
|
||||||
TrialId= inDto.TrialId
|
|
||||||
});
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 同步邮件
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IResponseOutput> SynchronizationEmail(SynchronizationEmailInDto inDto)
|
|
||||||
{
|
|
||||||
|
|
||||||
var fromEmail = _systemEmailConfig.FromEmail;
|
|
||||||
|
|
||||||
|
|
||||||
if (inDto.TrialId != null)
|
|
||||||
{
|
|
||||||
fromEmail= await _trialRepository.Where(x => x.Id == inDto.TrialId.Value).Select(x => x.EmailFromEmail).FirstNotNullAsync();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxTime = await _emailLogRepository.Where(x=>x.SenderAddress== fromEmail).MaxAsync(t => t.EmailDate);
|
|
||||||
var startDate = maxTime ?? DateTime.MinValue;
|
|
||||||
List<EmailLog> emailList = new List<EmailLog>();
|
|
||||||
List<EmailRecipientLog> EmailRecipientLogList = new List<EmailRecipientLog>();
|
|
||||||
|
|
||||||
// 第一步:同步发件箱邮件
|
|
||||||
using (var client = new ImapClient())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
await AuthenticateImap(client, inDto.TrialId);
|
|
||||||
var sentFolder = OpenSentFolder(client);
|
|
||||||
|
|
||||||
var searchQuery = SearchQuery.All.And(SearchQuery.DeliveredAfter(startDate));
|
|
||||||
var uids = sentFolder.Search(searchQuery).ToList();
|
|
||||||
|
|
||||||
foreach (var uid in uids)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = sentFolder.GetMessage(uid);
|
|
||||||
if (message.Date.DateTime <= startDate)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var emaillog = new EmailLog
|
|
||||||
{
|
|
||||||
Id = NewId.NextGuid(),
|
|
||||||
UniqueId = uid.ToString(),
|
|
||||||
MessageId = message.MessageId ?? string.Empty,
|
|
||||||
EmailSubject = message.Subject ?? string.Empty,
|
|
||||||
EmailDate = message.Date.DateTime,
|
|
||||||
EmailStateEnum = EmailState.Success,
|
|
||||||
};
|
|
||||||
|
|
||||||
var fromMailbox = message.From.Mailboxes.FirstOrDefault();
|
|
||||||
if (fromMailbox != null)
|
|
||||||
{
|
|
||||||
emaillog.SenderAddress = fromMailbox.Address;
|
|
||||||
emaillog.SenderName = fromMailbox.Name ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<EmailRecipientLog> recipientLogs = new List<EmailRecipientLog>();
|
|
||||||
|
|
||||||
int sort = 0;
|
|
||||||
message.To.Mailboxes.ForEach(x =>
|
|
||||||
{
|
|
||||||
recipientLogs.Add(new EmailRecipientLog()
|
|
||||||
{
|
|
||||||
RecipientName = x.Name ?? string.Empty,
|
|
||||||
RecipientAddress = x.Address,
|
|
||||||
EmailLogId = emaillog.Id,
|
|
||||||
RecipientTypeEnum = RecipientType.To,
|
|
||||||
Sort = sort++,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
sort = 0;
|
|
||||||
message.Cc.Mailboxes.ForEach(x =>
|
|
||||||
{
|
|
||||||
recipientLogs.Add(new EmailRecipientLog()
|
|
||||||
{
|
|
||||||
RecipientName = x.Name ?? string.Empty,
|
|
||||||
RecipientAddress = x.Address,
|
|
||||||
EmailLogId = emaillog.Id,
|
|
||||||
RecipientTypeEnum = RecipientType.Cc,
|
|
||||||
Sort = sort++,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
emailList.Add(emaillog);
|
|
||||||
EmailRecipientLogList.AddRange(recipientLogs);
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"处理邮件 {uid} 失败: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sentFolder.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"同步发件箱邮件时出错: {ex.Message}");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.Disconnect(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存同步的发件箱邮件
|
|
||||||
await _emailLogRepository.AddRangeAsync(emailList);
|
|
||||||
await _emailRecipientLogRepository.AddRangeAsync(EmailRecipientLogList);
|
|
||||||
await _emailLogRepository.SaveChangesAsync();
|
|
||||||
|
|
||||||
// 第二步:处理收件箱中的邮件发送失败通知
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await ProcessInboxFailureNotifications(startDate,inDto.TrialId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"处理收件箱失败通知邮件时出错: {ex.Message}");
|
|
||||||
Console.WriteLine($"异常堆栈: {ex.StackTrace}");
|
|
||||||
// 即使处理失败通知邮件出错,也不影响整体同步操作的成功
|
|
||||||
// 记录警告但不中断主流程
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IMailFolder OpenSentFolder(ImapClient client)
|
|
||||||
{
|
|
||||||
IMailFolder folder = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
folder = client.GetFolder(SpecialFolder.Sent);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
{
|
|
||||||
var candidates = new[] { "已发送", "已发送邮件", "Sent", "Sent Items", "[Gmail]/Sent Mail" };
|
|
||||||
foreach (var name in candidates)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var f = client.GetFolder(name);
|
|
||||||
if (f != null)
|
|
||||||
{
|
|
||||||
folder = f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var personal = client.GetFolder(client.PersonalNamespaces.FirstOrDefault());
|
|
||||||
if (personal != null)
|
|
||||||
{
|
|
||||||
foreach (var sub in personal.GetSubfolders(false))
|
|
||||||
{
|
|
||||||
if (string.Equals(sub.FullName, "Sent", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
string.Equals(sub.FullName, "Sent Items", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
folder = sub;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
throw new InvalidOperationException("未找到已发送文件夹");
|
|
||||||
|
|
||||||
folder.Open(FolderAccess.ReadOnly);
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IMailFolder OpenInboxFolder(ImapClient client)
|
|
||||||
{
|
|
||||||
IMailFolder folder = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
folder = client.GetFolder(SpecialFolder.All);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
{
|
|
||||||
var candidates = new[] { "收件箱", "Inbox" };
|
|
||||||
foreach (var name in candidates)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var f = client.GetFolder(name);
|
|
||||||
if (f != null)
|
|
||||||
{
|
|
||||||
folder = f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var personal = client.GetFolder(client.PersonalNamespaces.FirstOrDefault());
|
|
||||||
if (personal != null)
|
|
||||||
{
|
|
||||||
foreach (var sub in personal.GetSubfolders(false))
|
|
||||||
{
|
|
||||||
if (string.Equals(sub.FullName, "Inbox", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
folder = sub;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (folder == null)
|
|
||||||
throw new InvalidOperationException("未找到收件箱文件夹");
|
|
||||||
|
|
||||||
folder.Open(FolderAccess.ReadOnly);
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AuthenticateImap(ImapClient client, Guid? trialId)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
EmailAuthorization authorization = new EmailAuthorization()
|
|
||||||
{
|
|
||||||
FromEmail = _systemEmailConfig.FromEmail,
|
|
||||||
AuthorizationCode = _systemEmailConfig.AuthorizationCode,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (trialId != null)
|
|
||||||
{
|
|
||||||
authorization = await _trialRepository.Where(x => x.Id == trialId.Value).Select(x => new EmailAuthorization()
|
|
||||||
{
|
|
||||||
AuthorizationCode = x.EmailAuthorizationCode,
|
|
||||||
FromEmail = x.EmailFromEmail
|
|
||||||
}).FirstNotNullAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
client.Connect(_systemEmailConfig.Imap, _systemEmailConfig.ImapPort, SecureSocketOptions.SslOnConnect);
|
|
||||||
client.Authenticate(authorization.FromEmail, authorization.AuthorizationCode);
|
|
||||||
}
|
|
||||||
catch (AuthenticationException)
|
|
||||||
{
|
|
||||||
//if (_systemEmailConfig.UseOAuth2 && _systemEmailConfig.OAuth2AccessToken.IsNotNullOrEmpty())
|
|
||||||
//{
|
|
||||||
// var sasl = new SaslMechanismOAuth2(_systemEmailConfig.FromEmail, _systemEmailConfig.OAuth2AccessToken);
|
|
||||||
// client.Authenticate(sasl);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//if (_systemEmailConfig.OAuth2AccessToken.IsNullOrEmpty())
|
|
||||||
//{
|
|
||||||
// var token = AcquireOAuth2TokenByPassword();
|
|
||||||
// if (token.IsNotNullOrEmpty())
|
|
||||||
// {
|
|
||||||
// _systemEmailConfig.OAuth2AccessToken = token;
|
|
||||||
// var sasl = new SaslMechanismOAuth2(_systemEmailConfig.FromEmail, token);
|
|
||||||
// client.Authenticate(sasl);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 处理收件箱中的邮件发送失败通知
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task ProcessInboxFailureNotifications(DateTime startTime, Guid? trialId)
|
|
||||||
{
|
|
||||||
using (var client = new ImapClient())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
await AuthenticateImap(client, trialId);
|
|
||||||
var inboxFolder = OpenInboxFolder(client);
|
|
||||||
|
|
||||||
// 搜索可能包含失败通知的邮件
|
|
||||||
// 通常失败通知邮件会包含"失败"、"错误"、"undeliverable"、"delivery failed"等关键词
|
|
||||||
var searchQuery = SearchQuery.All.Or(SearchQuery.SubjectContains("失败"))
|
|
||||||
.Or(SearchQuery.SubjectContains("错误"))
|
|
||||||
.Or(SearchQuery.SubjectContains("undeliverable"))
|
|
||||||
.Or(SearchQuery.SubjectContains("delivery failed"))
|
|
||||||
.Or(SearchQuery.SubjectContains("Delivery Status Notification"))
|
|
||||||
.Or(SearchQuery.BodyContains("失败"))
|
|
||||||
.Or(SearchQuery.BodyContains("错误"))
|
|
||||||
.Or(SearchQuery.BodyContains("undeliverable"))
|
|
||||||
.Or(SearchQuery.BodyContains("delivery failed")).And(SearchQuery.DeliveredAfter(startTime));
|
|
||||||
|
|
||||||
var uids = inboxFolder.Search(searchQuery).ToList();
|
|
||||||
var processedCount = 0;
|
|
||||||
var updatedCount = 0;
|
|
||||||
|
|
||||||
foreach (var uid in uids)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = inboxFolder.GetMessage(uid);
|
|
||||||
|
|
||||||
// 尝试从邮件内容中提取原始邮件的Message-Id或相关信息
|
|
||||||
var originalMessageId = ExtractOriginalMessageId(message);
|
|
||||||
if (!string.IsNullOrEmpty(originalMessageId))
|
|
||||||
{
|
|
||||||
// 查找对应的EmailLog记录
|
|
||||||
var emailLog = await _emailLogRepository
|
|
||||||
.Where(x => x.MessageId == originalMessageId)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
await _emailLogRepository.BatchUpdateNoTrackingAsync(x => x.MessageId == originalMessageId, x => new EmailLog()
|
|
||||||
{
|
|
||||||
EmailStateEnum = EmailState.Error,
|
|
||||||
ErrorInfo = message.TextBody
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
updatedCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
processedCount++;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inboxFolder.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"连接收件箱处理失败通知邮件时出错: {ex.Message}");
|
|
||||||
Console.WriteLine($"异常堆栈: {ex.StackTrace}");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.Disconnect(true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"断开IMAP客户端连接时出错: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从失败通知邮件中提取原始邮件的Message-Id
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string ExtractOriginalMessageId(MimeMessage message)
|
|
||||||
{
|
|
||||||
// 首先检查邮件头中是否有原始Message-Id
|
|
||||||
var originalMessageId = message.Headers["Original-Message-ID"] ??
|
|
||||||
message.Headers["X-Original-Message-ID"] ??
|
|
||||||
message.Headers["In-Reply-To"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(originalMessageId))
|
|
||||||
{
|
|
||||||
// 清理Message-Id格式(移除尖括号)
|
|
||||||
originalMessageId = originalMessageId.Trim('<', '>');
|
|
||||||
return originalMessageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查邮件附件中是否包含.eml文件(这是最常见的失败通知格式)
|
|
||||||
foreach (var attachment in message.Attachments)
|
|
||||||
{
|
|
||||||
if (attachment is MessagePart messagePart)
|
|
||||||
{
|
|
||||||
// 直接获取嵌入的邮件消息
|
|
||||||
var originalMessageIdFromAttachment = messagePart.Message?.MessageId;
|
|
||||||
if (!string.IsNullOrEmpty(originalMessageIdFromAttachment))
|
|
||||||
{
|
|
||||||
return originalMessageIdFromAttachment.Trim('<', '>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (attachment is MimePart mimePart)
|
|
||||||
{
|
|
||||||
// 检查文件扩展名是否为.eml
|
|
||||||
var fileName = mimePart.FileName ?? mimePart.ContentType.Name;
|
|
||||||
if (!string.IsNullOrEmpty(fileName) &&
|
|
||||||
(fileName.EndsWith(".eml", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
mimePart.ContentType.MimeType.Equals("message/rfc822", StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 解析.eml附件内容
|
|
||||||
using var memoryStream = new MemoryStream();
|
|
||||||
mimePart.Content.DecodeTo(memoryStream);
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
var originalMessage = MimeMessage.Load(memoryStream);
|
|
||||||
if (!string.IsNullOrEmpty(originalMessage?.MessageId))
|
|
||||||
{
|
|
||||||
return originalMessage.MessageId.Trim('<', '>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"解析.eml附件时出错: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果邮件头和附件中都没有,尝试从邮件正文中提取
|
|
||||||
var content = message.HtmlBody ?? message.TextBody ?? string.Empty;
|
|
||||||
|
|
||||||
// 尝试匹配常见的Message-Id格式
|
|
||||||
var messageIdPattern = @"(?:Message-ID|Message-Id|message-id):\s*<?([^>\s]+)>?";
|
|
||||||
var match = System.Text.RegularExpressions.Regex.Match(content, messageIdPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|
||||||
if (match.Success)
|
|
||||||
{
|
|
||||||
return match.Groups[1].Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试从邮件引用部分提取
|
|
||||||
var referencePattern = @"^>.*Message-ID:\s*<?([^>\s]+)>?";
|
|
||||||
var matches = System.Text.RegularExpressions.Regex.Matches(content, referencePattern, System.Text.RegularExpressions.RegexOptions.Multiline | System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
|
||||||
if (matches.Count > 0)
|
|
||||||
{
|
|
||||||
return matches[0].Groups[1].Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<IResponseOutput> AddOrUpdateEmailLog(EmailLogAddOrEdit addOrEditEmailLog)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var entity = await _emailLogRepository.InsertOrUpdateAsync(addOrEditEmailLog, true);
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(entity.Id.ToString());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpDelete("{emailLogId:guid}")]
|
|
||||||
public async Task<IResponseOutput> DeleteEmailLog(Guid emailLogId)
|
|
||||||
{
|
|
||||||
var success = await _emailLogRepository.DeleteFromQueryAsync(t => t.Id == emailLogId,true);
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -4,18 +4,9 @@
|
|||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using MailKit;
|
|
||||||
using MailKit.Net.Imap;
|
|
||||||
using MailKit.Search;
|
|
||||||
using MailKit.Security;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NPOI.SS.Formula.Functions;
|
using NPOI.SS.Formula.Functions;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
@@ -26,75 +17,8 @@ namespace IRaCIS.Core.Application.Contracts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
[ApiExplorerSettings(GroupName = "Common")]
|
||||||
public class EmailNoticeConfigService(IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
public class EmailNoticeConfigService(IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||||
IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository,
|
IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IEmailNoticeConfigService
|
||||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
|
||||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IEmailNoticeConfigService
|
|
||||||
{
|
{
|
||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取邮件列表
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<object> GetEmailList()
|
|
||||||
{
|
|
||||||
|
|
||||||
List<IMessageSummary> emailList = new List<IMessageSummary>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using (var client = new ImapClient())
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 连接阿里邮箱 IMAP 服务器(使用 SSL)
|
|
||||||
client.Connect(_systemEmailConfig.Imap, 993, SecureSocketOptions.SslOnConnect);
|
|
||||||
|
|
||||||
// 登录
|
|
||||||
client.Authenticate(_systemEmailConfig.FromEmail, _systemEmailConfig.AuthorizationCode);
|
|
||||||
|
|
||||||
// 3. 获取发件箱文件夹 - 使用你找到的“已发送”
|
|
||||||
var sentFolder = client.GetFolder("已发送");
|
|
||||||
sentFolder.Open(FolderAccess.ReadOnly);
|
|
||||||
|
|
||||||
// 4. 搜索所有邮件(你可以在这里添加更精确的搜索条件)
|
|
||||||
var uids = sentFolder.Search(SearchQuery.All);
|
|
||||||
Console.WriteLine($"找到 {uids.Count} 封已发送邮件");
|
|
||||||
|
|
||||||
// 5. 遍历并处理邮件(示例中处理前10封)
|
|
||||||
foreach (var uid in uids.Take(10))
|
|
||||||
{
|
|
||||||
var message = sentFolder.GetMessage(uid);
|
|
||||||
|
|
||||||
// 输出邮件基本信息
|
|
||||||
Console.WriteLine($"主题: {message.Subject}");
|
|
||||||
Console.WriteLine($"收件人: {string.Join(", ", message.To.Mailboxes.Select(m => m.Address))}");
|
|
||||||
Console.WriteLine($"日期: {message.Date.LocalDateTime:yyyy-MM-dd HH:mm:ss}");
|
|
||||||
Console.WriteLine($"发件人: {message.From}");
|
|
||||||
Console.WriteLine("----------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
sentFolder.Close();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"操作失败: {ex.Message}");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.Disconnect(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery inQuery)
|
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery inQuery)
|
||||||
|
|||||||
+16
-440
@@ -22,8 +22,6 @@ using System.ComponentModel.Design;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using static IRaCIS.Core.Application.Service.ExcelExportHelper;
|
using static IRaCIS.Core.Application.Service.ExcelExportHelper;
|
||||||
using IDictionaryService = IRaCIS.Application.Interfaces.IDictionaryService;
|
using IDictionaryService = IRaCIS.Application.Interfaces.IDictionaryService;
|
||||||
using TrialIdentityUser = IRaCIS.Core.Domain.Models.TrialIdentityUser;
|
using TrialIdentityUser = IRaCIS.Core.Domain.Models.TrialIdentityUser;
|
||||||
@@ -34,8 +32,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
[ApiExplorerSettings(GroupName = "Common")]
|
[ApiExplorerSettings(GroupName = "Common")]
|
||||||
public class ExcelExportService(IRepository<TrialUserRole> _trialUserRoleRepository,
|
public class ExcelExportService(IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||||
IRepository<VisitTask> _visitTaskRepository,
|
IRepository<VisitTask> _visitTaskRepository,
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
|
||||||
IRepository<Internationalization> _internationalizationRepository,
|
|
||||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||||
IRepository<SystemDocNeedConfirmedUserType> _systemDocNeedConfirmedUserTypeRepository,
|
IRepository<SystemDocNeedConfirmedUserType> _systemDocNeedConfirmedUserTypeRepository,
|
||||||
IRepository<DicomStudy> _dicomStudyRepository,
|
IRepository<DicomStudy> _dicomStudyRepository,
|
||||||
@@ -471,10 +467,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.Code), o => o.TrialCode.Contains(inQuery.Code))
|
.WhereIf(!string.IsNullOrEmpty(inQuery.Code), o => o.TrialCode.Contains(inQuery.Code))
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.ResearchProgramNo), o => o.ResearchProgramNo.Contains(inQuery.ResearchProgramNo))
|
.WhereIf(!string.IsNullOrEmpty(inQuery.ResearchProgramNo), o => o.ResearchProgramNo.Contains(inQuery.ResearchProgramNo))
|
||||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), o => o.ExperimentName.Contains(inQuery.ExperimentName))
|
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), o => o.ExperimentName.Contains(inQuery.ExperimentName))
|
||||||
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OP,
|
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OP, t => t.TrialIdentityUserList.Any(t => t.IdentityUserId == _userInfo.IdentityUserId && t.IsDeleted == false) && t.IsDeleted == false)
|
||||||
t => t.TrialIdentityUserList.Any(t => t.IdentityUserId == _userInfo.IdentityUserId && t.IsDeleted == false
|
|
||||||
&& t.TrialUserRoleList.Any(t => t.UserId == _userInfo.UserRoleId && t.IsDeleted == false))
|
|
||||||
&& t.IsDeleted == false)
|
|
||||||
.WhereIf(inQuery.CriterionType != null, o => o.TrialReadingCriterionList.Any(t => t.CriterionType == inQuery.CriterionType && t.IsSigned && t.IsConfirm))
|
.WhereIf(inQuery.CriterionType != null, o => o.TrialReadingCriterionList.Any(t => t.CriterionType == inQuery.CriterionType && t.IsSigned && t.IsConfirm))
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.PM_EMail), o => o.TrialUserRoleList.Any(t => t.UserRole.IdentityUser.EMail.Contains(inQuery.PM_EMail) && (t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)))
|
.WhereIf(!string.IsNullOrEmpty(inQuery.PM_EMail), o => o.TrialUserRoleList.Any(t => t.UserRole.IdentityUser.EMail.Contains(inQuery.PM_EMail) && (t.UserRole.UserTypeEnum == UserTypeEnum.ProjectManager || t.UserRole.UserTypeEnum == UserTypeEnum.APM)))
|
||||||
.Select(t => new TrialToBeDoneDto()
|
.Select(t => new TrialToBeDoneDto()
|
||||||
@@ -984,7 +977,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
||||||
.Where(t => t.Subject.IsSubjectQuit == false || t.SubmitState >= SubmitStateEnum.ToSubmit)
|
.Where(t => t.Subject.IsSubjectQuit == false || t.SubmitState >= SubmitStateEnum.ToSubmit)
|
||||||
.WhereIf(inQuery.SubjectStatus != null, t => t.Subject.Status == inQuery.SubjectStatus)
|
|
||||||
.Where(t => t.Subject.FinalSubjectVisitId != null ? t.VisitNum <= t.Subject.FinalSubjectVisit.VisitNum : true)
|
.Where(t => t.Subject.FinalSubjectVisitId != null ? t.VisitNum <= t.Subject.FinalSubjectVisit.VisitNum : true)
|
||||||
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||||
.WhereIf(inQuery.SubjectId != null, t => t.Subject.Id == inQuery.SubjectId)
|
.WhereIf(inQuery.SubjectId != null, t => t.Subject.Id == inQuery.SubjectId)
|
||||||
@@ -1034,7 +1027,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
||||||
|
|
||||||
.Where(t => t.Subject.IsSubjectQuit == false || t.AuditState > AuditStateEnum.ToAudit)
|
.Where(t => t.Subject.IsSubjectQuit == false || t.AuditState > AuditStateEnum.ToAudit)
|
||||||
.WhereIf(inQuery.SubjectStatus != null, t => t.Subject.Status == inQuery.SubjectStatus)
|
|
||||||
.WhereIf(inQuery.VisitId != null, t => t.Id == inQuery.VisitId)
|
.WhereIf(inQuery.VisitId != null, t => t.Id == inQuery.VisitId)
|
||||||
.WhereIf(inQuery.CurrentActionUserId != null, t => t.CurrentActionUserId == inQuery.CurrentActionUserId)
|
.WhereIf(inQuery.CurrentActionUserId != null, t => t.CurrentActionUserId == inQuery.CurrentActionUserId)
|
||||||
.WhereIf(inQuery.ChallengeState != null, t => t.ChallengeState == inQuery.ChallengeState)
|
.WhereIf(inQuery.ChallengeState != null, t => t.ChallengeState == inQuery.ChallengeState)
|
||||||
@@ -1626,7 +1619,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
||||||
|
|
||||||
|
|
||||||
if (inQuery.IsRandomOrderList == true)
|
if (inQuery.IsRandomOrderList == true)
|
||||||
{
|
{
|
||||||
list = list.OrderBy(t => t.RandomOrder).ToList();
|
list = list.OrderBy(t => t.RandomOrder).ToList();
|
||||||
@@ -1765,80 +1757,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
var list = taskMedicalReviewQueryable.OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitTaskNum).ToList();
|
var list = taskMedicalReviewQueryable.OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitTaskNum).ToList();
|
||||||
|
|
||||||
|
|
||||||
#region 处理翻译对话 by he wen tao
|
|
||||||
|
|
||||||
Dictionary<string, string> i18NKeys = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{ "Msg1","trials:medicalFeedback:message:msg1"},
|
|
||||||
{ "Msg2","trials:medicalFeedback:message:msg2"},
|
|
||||||
{ "Msg3","trials:medicalFeedback:message:msg3"},
|
|
||||||
{ "Msg4", "trials:medicalFeedback:message:msg4"},
|
|
||||||
{ "Msg5", "trials:medicalFeedback:message:msg5"},
|
|
||||||
{ "CloseReasonEnum", "trials:medicalFeedback:title:closeReasonEnum"},
|
|
||||||
{ "IsEndorse", "trials:medicalFeedback:title:isEndorse"},
|
|
||||||
{ "Reason", "trials:medicalFeedback:title:reason"},
|
|
||||||
{ "IsRequestReread", "trials:medicalFeedback:title:isRequestReread"},
|
|
||||||
};
|
|
||||||
|
|
||||||
var i18Values = i18NKeys.Select(x => x.Value).ToList();
|
|
||||||
var i18nList = await _internationalizationRepository.Where(x => i18Values.Contains(x.Code))
|
|
||||||
.Select(x => new
|
|
||||||
{
|
|
||||||
Code = x.Code,
|
|
||||||
Value = _userInfo.IsEn_Us ? x.Value : x.ValueCN
|
|
||||||
}).ToListAsync();
|
|
||||||
|
|
||||||
List<string> dictionaryCodeList = new List<string>()
|
|
||||||
{
|
|
||||||
"AuditAdvice",
|
|
||||||
"MedicalDialogCloseEnum",
|
|
||||||
"MedicalReviewDoctorUserIdea",
|
|
||||||
"YesOrNo",
|
|
||||||
};
|
|
||||||
|
|
||||||
var dictionadParents = await _dictionaryRepository.Where(x => dictionaryCodeList.Contains(x.Parent.Code))
|
|
||||||
.Select(x => new
|
|
||||||
{
|
|
||||||
ParentCode = x.Parent.Code,
|
|
||||||
Code = x.Code,
|
|
||||||
Value = _userInfo.IsEn_Us ? x.Value : x.ValueCN
|
|
||||||
}).ToListAsync();
|
|
||||||
|
|
||||||
JointMedicalReviewI18n i18N = new JointMedicalReviewI18n() { };
|
|
||||||
foreach (var kv in i18NKeys)
|
|
||||||
{
|
|
||||||
PropertyInfo? pi = i18N.GetType().GetProperty(kv.Key);
|
|
||||||
if (pi != null && pi.CanWrite)
|
|
||||||
{
|
|
||||||
var value = i18nList.Where(x => x.Code == kv.Value).Select(x => x.Value).FirstOrDefault() ?? string.Empty;
|
|
||||||
object safeValue = Convert.ChangeType(value, pi.PropertyType);
|
|
||||||
pi.SetValue(i18N, safeValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var item in dictionaryCodeList)
|
|
||||||
{
|
|
||||||
PropertyInfo? pi = i18N.GetType().GetProperty(item);
|
|
||||||
if (pi != null && pi.CanWrite)
|
|
||||||
{
|
|
||||||
var value = dictionadParents.Where(x => x.ParentCode == item).ToDictionary(x => x.Code, x => x.Value);
|
|
||||||
object safeValue = Convert.ChangeType(value, pi.PropertyType);
|
|
||||||
pi.SetValue(i18N, safeValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
foreach (var dialog in item.DialogList)
|
|
||||||
{
|
|
||||||
dialog.ResultContent = JointMedicalReviewDialog(dialog, i18N);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
||||||
|
|
||||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
||||||
@@ -1848,88 +1766,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialMedicalReviewList_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(TaskMedicalReviewExportDto));
|
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialMedicalReviewList_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(TaskMedicalReviewExportDto));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取医学审核对话拼接内容
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="record"></param>
|
|
||||||
/// <param name="i18NAndDic"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string JointMedicalReviewDialog(GetMedicalReviewDialogOutDto record, JointMedicalReviewI18n i18NAndDic)
|
|
||||||
{
|
|
||||||
StringBuilder str = new StringBuilder() { };
|
|
||||||
var userTypes = new List<int>() { 14, 30 };
|
|
||||||
|
|
||||||
// 这里userTypes.Contains(record.UserTypeEnumInt) 可以提出来 但是还是按照前端写吧 免得不好对照
|
|
||||||
|
|
||||||
// v-if="[14, 30].includes(record.UserTypeEnumInt) && record.Questioning
|
|
||||||
if (userTypes.Contains(record.UserTypeEnumInt) && record.Questioning.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
// <!-- 您好,根据医学审核反馈,该阅片任务的评估有如下问题需要您确认或澄清: -->
|
|
||||||
str.AppendLine(i18NAndDic.Msg1);
|
|
||||||
|
|
||||||
str.AppendLine(record.Questioning);
|
|
||||||
|
|
||||||
if (record.FileList.Count() > 0)
|
|
||||||
{
|
|
||||||
str.AppendLine(i18NAndDic.Msg2);
|
|
||||||
record.FileList.ForEach(x =>
|
|
||||||
{
|
|
||||||
str.AppendLine(x.FileName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
str.AppendLine(i18NAndDic.Msg3);
|
|
||||||
|
|
||||||
str.AppendLine(i18NAndDic.AuditAdvice[record.AuditAdviceEnum.GetEnumInt()]);
|
|
||||||
|
|
||||||
str.AppendLine(i18NAndDic.Msg4);
|
|
||||||
}
|
|
||||||
|
|
||||||
//v-if="[14, 30].includes(record.UserTypeEnumInt) && record.MedicalDialogCloseEnum!== null"
|
|
||||||
if (userTypes.Contains(record.UserTypeEnumInt) && record.MedicalDialogCloseEnum != null)
|
|
||||||
{
|
|
||||||
str.AppendLine(i18NAndDic.CloseReasonEnum + i18NAndDic.MedicalDialogCloseEnum[record.MedicalDialogCloseEnum.Value.GetEnumInt()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v-if="[14, 30].includes(record.UserTypeEnumInt) && record.Content
|
|
||||||
if (userTypes.Contains(record.UserTypeEnumInt) && record.Content.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
str.AppendLine(record.Content);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v-if="[13].includes(record.UserTypeEnumInt)"
|
|
||||||
|
|
||||||
if (13 == record.UserTypeEnumInt)
|
|
||||||
{
|
|
||||||
str.AppendLine(i18NAndDic.IsEndorse + i18NAndDic.MedicalReviewDoctorUserIdea[record.DoctorUserIdeaEnum.GetEnumInt()]);
|
|
||||||
|
|
||||||
// v-if="record.DoctorUserIdeaEnum===2"
|
|
||||||
if ((int)record.DoctorUserIdeaEnum == 2)
|
|
||||||
{
|
|
||||||
str.AppendLine(i18NAndDic.Reason + record.DisagreeReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
// record.MedicalDialogCloseEnum!== null
|
|
||||||
|
|
||||||
if (record.MedicalDialogCloseEnum != null)
|
|
||||||
{
|
|
||||||
str.AppendLine(i18NAndDic.IsRequestReread + i18NAndDic.YesOrNo[record.IsApplyHeavyReading.ToString()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// v-if="record.FileList && record.FileList.length > 0"
|
|
||||||
|
|
||||||
if (record.FileList.Count() > 0)
|
|
||||||
{
|
|
||||||
record.FileList.ForEach(x =>
|
|
||||||
{
|
|
||||||
str.AppendLine(x.FileName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.ToString();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 影像下载记录表
|
/// 影像下载记录表
|
||||||
@@ -2474,263 +2310,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
#region 通用阅片结果导出
|
#region 通用阅片结果导出
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 一致性分析结果导出 7 8 分别是自身 和组件一致性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inQuery"></param>
|
|
||||||
/// <param name="_commonDocumentRepository"></param>
|
|
||||||
/// <param name="_dictionaryService"></param>
|
|
||||||
/// <param name="_trialRepository"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> GetAnalysisTaskList_Export(VisitTaskQuery inQuery,
|
|
||||||
[FromServices] IRepository<CommonDocument> _commonDocumentRepository,
|
|
||||||
[FromServices] IDictionaryService _dictionaryService,
|
|
||||||
[FromServices] IRepository<Trial> _trialRepository)
|
|
||||||
{
|
|
||||||
//每次查询必须是单标准的
|
|
||||||
var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionName, t.ArbitrationRule }).FirstNotNullAsync();
|
|
||||||
|
|
||||||
|
|
||||||
var query = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.TaskAllocationState == TaskAllocationState.Allocated && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
|
|
||||||
|
|
||||||
//一致性分析
|
|
||||||
.WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults, t => t.IsSelfAnalysis == true || t.IsSelfAnalysis == null)
|
|
||||||
.WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults, t => t.IsSelfAnalysis == null ? t.Subject.SubjectVisitTaskList.Any(u => u.IsSelfAnalysis == true && u.VisitTaskNum == t.VisitTaskNum && u.DoctorUserId == t.DoctorUserId && u.TrialReadingCriterionId == t.TrialReadingCriterionId) : true)
|
|
||||||
.WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfInterReaderAnalysisResults, t => t.IsSelfAnalysis == false || t.IsSelfAnalysis == null)
|
|
||||||
|
|
||||||
//访视和全局查询已签名完成的,裁判可以是未签名,未完成的
|
|
||||||
.Where(t => (t.ReadingTaskState == ReadingTaskState.HaveSigned && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)) || t.ReadingCategory == ReadingCategory.Judge)
|
|
||||||
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
|
||||||
.WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
|
|
||||||
|
|
||||||
.WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
|
|
||||||
.WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId)
|
|
||||||
.WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory)
|
|
||||||
//.WhereIf(inQuery.ReadingTaskState != null, t => t.ReadingTaskState == inQuery.ReadingTaskState)
|
|
||||||
.WhereIf(inQuery.TaskAllocationState != null, t => t.TaskAllocationState == inQuery.TaskAllocationState)
|
|
||||||
.WhereIf(inQuery.ArmEnum != null, t => t.ArmEnum == inQuery.ArmEnum)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate) || (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate == false))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
|
||||||
.WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime > inQuery.BeginAllocateDate)
|
|
||||||
.WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime < inQuery.EndAllocateDate);
|
|
||||||
|
|
||||||
var list = await query.ProjectTo<AnalysisDynamicCommonExport>(_mapper.ConfigurationProvider,
|
|
||||||
new
|
|
||||||
{
|
|
||||||
readingExportType = inQuery.ReadingExportType,
|
|
||||||
criterionType = criterion.CriterionType,
|
|
||||||
trialReadingCriterionId = inQuery.TrialReadingCriterionId,
|
|
||||||
isEn_Us = _userInfo.IsEn_Us
|
|
||||||
}).ToListAsync();
|
|
||||||
|
|
||||||
list = list.OrderBy(t => t.SubjectCode).ThenBy(t => t.ArmEnum).ThenBy(t => t.VisitTaskNum).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
|
||||||
exportInfo.CriterionName = criterion.CriterionName;
|
|
||||||
|
|
||||||
#region 处理系统标准存在疾病和整体肿瘤合并
|
|
||||||
|
|
||||||
//如果是以合并后的找翻译字典,会少,所以必须放在前面
|
|
||||||
var translateDicNameList = list.SelectMany(t => t.QuestionAnswerList).Where(t => t.TranslateDicName.IsNotNullOrEmpty()).Select(t => t.TranslateDicName).Distinct().ToList();
|
|
||||||
|
|
||||||
//针对1.1 整体肿瘤评估 有的两列要合并一列
|
|
||||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
//处理合并表头
|
|
||||||
|
|
||||||
var questionType = item.IsBaseline == true ? QuestionType.ExistDisease : QuestionType.Tumor;
|
|
||||||
|
|
||||||
var findItem = item.QuestionAnswerList.Where(t => t.QuestionType == questionType).FirstOrDefault();
|
|
||||||
|
|
||||||
if (findItem != null)
|
|
||||||
{
|
|
||||||
findItem.QuestionName = _userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (item.IsBaseline == true)
|
|
||||||
{
|
|
||||||
item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.Tumor).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ExistDisease).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
|
|
||||||
{
|
|
||||||
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
//处理合并表头
|
|
||||||
|
|
||||||
var questionType = item.IsBaseline == true ? QuestionType.ExistDisease : QuestionType.ImgOncology;
|
|
||||||
|
|
||||||
var findItem = item.QuestionAnswerList.Where(t => t.QuestionType == questionType).FirstOrDefault();
|
|
||||||
|
|
||||||
if (findItem != null)
|
|
||||||
{
|
|
||||||
findItem.QuestionName = _userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.IsBaseline == true)
|
|
||||||
{
|
|
||||||
item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ImgOncology).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ExistDisease).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (criterion.CriterionType == CriterionType.PCWG3)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (criterion.CriterionType == CriterionType.SelfDefine)
|
|
||||||
{
|
|
||||||
//自定义的又问题名称重复 所以统一加上组名
|
|
||||||
|
|
||||||
//有重复的就加,没有重复的就不加
|
|
||||||
if (list.Any(t => t.QuestionAnswerList.Select(t => t.QuestionName).Count() != t.QuestionAnswerList.Select(t => t.QuestionName).Distinct().Count()))
|
|
||||||
{
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
|
||||||
foreach (var qs in item.QuestionAnswerList)
|
|
||||||
{
|
|
||||||
qs.QuestionName = qs.Group + "_" + qs.QuestionName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
var export_Template = StaticData.Export.TrialSelfAnalysisList_Export;
|
|
||||||
|
|
||||||
#region 自身一致性分析和组间一致性分析
|
|
||||||
|
|
||||||
if (inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults)
|
|
||||||
{
|
|
||||||
//找到非一致性分析的任务
|
|
||||||
var selfExportList = list.Where(t => t.IsSelfAnalysis == null).ToList();
|
|
||||||
|
|
||||||
//处理一致性分析结果是否和原始阅片是否一致
|
|
||||||
foreach (var item in selfExportList)
|
|
||||||
{
|
|
||||||
//找到一致性分析的结果
|
|
||||||
var selfAnalysisTask = list.Where(t => t.IsSelfAnalysis == true && t.SubjectCode == item.SubjectCode && t.VisitTaskNum == item.VisitTaskNum && t.TaskName == t.TaskName && t.UserName == item.UserName).FirstOrDefault();
|
|
||||||
|
|
||||||
//将自身一致性分析的字段 赋值到访视任务这个字段
|
|
||||||
item.IsAnalysisDiffToOriginalData = selfAnalysisTask?.IsAnalysisDiffToOriginalData;
|
|
||||||
|
|
||||||
//处理再次阅片人的结果
|
|
||||||
if (selfAnalysisTask != null)
|
|
||||||
{
|
|
||||||
var cloneQuestionAnswerList = selfAnalysisTask.QuestionAnswerList.Clone();
|
|
||||||
|
|
||||||
foreach (var qItem in cloneQuestionAnswerList)
|
|
||||||
{
|
|
||||||
qItem.QuestionName = qItem.QuestionName + $"{(_userInfo.IsEn_Us ? "(Again)" : "(再次)")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
item.QuestionAnswerList = item.QuestionAnswerList.Union(cloneQuestionAnswerList).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list = selfExportList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
export_Template = StaticData.Export.TrialGroupAnalysisList_Export;
|
|
||||||
|
|
||||||
var newList = new List<AnalysisDynamicCommonExport>();
|
|
||||||
|
|
||||||
foreach (var group in list.GroupBy(t => new { t.SubjectCode, t.VisitTaskNum, t.TaskName }).OrderBy(g => g.Key.SubjectCode).ThenBy(g => g.Key.VisitTaskNum))
|
|
||||||
{
|
|
||||||
var subjectVisitGroupList = group.ToList();
|
|
||||||
|
|
||||||
|
|
||||||
//找到当前访视组间一致性分析的任务结果
|
|
||||||
|
|
||||||
var groupOtherTaskList = subjectVisitGroupList.Where(t => t.IsSelfAnalysis == false).ToList();
|
|
||||||
|
|
||||||
foreach (var subjectVisitTaskArm in subjectVisitGroupList.Where(t => t.IsSelfAnalysis == null).OrderBy(t => t.ArmEnum))
|
|
||||||
{
|
|
||||||
foreach (var otherTask in groupOtherTaskList)
|
|
||||||
{
|
|
||||||
//非一致性分析任务
|
|
||||||
var cloneObj = subjectVisitTaskArm.Clone();
|
|
||||||
|
|
||||||
var otherTaskQuestionAnserList = otherTask.QuestionAnswerList.Clone();
|
|
||||||
|
|
||||||
foreach (var qItem in otherTaskQuestionAnserList)
|
|
||||||
{
|
|
||||||
qItem.QuestionName = qItem.QuestionName + $"{(_userInfo.IsEn_Us ? "(Again)" : "(再次)")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
//处理 再次阅片人,再次阅片人角色 两列
|
|
||||||
var addQuestionList = new List<CommonQuesionInfo>();
|
|
||||||
|
|
||||||
addQuestionList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Reviwer(Again)" : "阅片人(再次)", QuestionValue = otherTask.UserName });
|
|
||||||
addQuestionList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Reviwer Role(Again)" : "阅片人角色(再次)", QuestionValue = ((int)otherTask.ArmEnum).ToString(), TranslateDicName = "ArmEnum" });
|
|
||||||
|
|
||||||
|
|
||||||
cloneObj.QuestionAnswerList = cloneObj.QuestionAnswerList.Union(addQuestionList).Union(otherTaskQuestionAnserList).ToList();
|
|
||||||
|
|
||||||
|
|
||||||
cloneObj.IsGroupAnalysisDiffToOriginalData = cloneObj.ArmEnum == Arm.DoubleReadingArm1 ? otherTask.IsGroupDiffArm1 : otherTask.IsGroupDiffArm2;
|
|
||||||
|
|
||||||
newList.Add(cloneObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
translateDicNameList.Add("ArmEnum");
|
|
||||||
|
|
||||||
list = newList;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
var columNameList = list.SelectMany(t => t.QuestionAnswerList).Where(t => t.QuestionName.IsNotNullOrEmpty()).Select(t => t.QuestionName).Distinct().ToList();
|
|
||||||
|
|
||||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list.Where(t => t.ReadingCategory != ReadingCategory.Global).ToList(), _userInfo.TimeZoneId);
|
|
||||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
|
||||||
|
|
||||||
var dynamicColumnConfig = new DynamicColumnConfig()
|
|
||||||
{
|
|
||||||
//可读的列表名行索引,不是{{}} 模板行索引
|
|
||||||
AutoColumnTitleRowIndex = 2,
|
|
||||||
AutoColumnStartIndex = 5,
|
|
||||||
TempalteLastColumnIndex = 4,
|
|
||||||
DynamicItemDicName = "TranslateDicName",
|
|
||||||
DynamicItemValueName = "QuestionValue",
|
|
||||||
DynamicItemTitleName = "QuestionName",
|
|
||||||
DynamicListName = "QuestionAnswerList",
|
|
||||||
RemoveColunmIndexList = new List<int>() { },
|
|
||||||
ColumnIdNameList = columNameList.Select(t => new DynamicColumnConfig.ColumItem() { Id = Guid.Empty, Name = t }).ToList(),
|
|
||||||
TranslateDicNameList = translateDicNameList ?? new List<string>()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var (memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(export_Template, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(AnalysisDynamicCommonExport), criterion.CriterionType, dynamicColumnConfig);
|
|
||||||
|
|
||||||
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
|
||||||
{
|
|
||||||
FileDownloadName = $"{exportInfo.ResearchProgramNo}_{exportInfo.CriterionName}_{fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取阅片标准可以导出的列表
|
/// 获取阅片标准可以导出的列表
|
||||||
@@ -2760,11 +2341,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.ReadingLession_Export, ExportCatogory = ExportResult.DetailedTableOfLesions });
|
list.Add(new ExportDocumentDes() { Code = StaticData.Export.ReadingLession_Export, ExportCatogory = ExportResult.DetailedTableOfLesions });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.Lugano2014)
|
|
||||||
{
|
|
||||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.TumorCDISC_Export, ExportCatogory = ExportResult.TumorCDISC_Export });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (criterion.CriterionType == CriterionType.OCT)
|
if (criterion.CriterionType == CriterionType.OCT)
|
||||||
{
|
{
|
||||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
|
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
|
||||||
@@ -2774,9 +2350,9 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
{
|
{
|
||||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.IVUS_CDISC_Export, ExportCatogory = ExportResult.IVUS_CDISC_Export });
|
list.Add(new ExportDocumentDes() { Code = StaticData.Export.IVUS_CDISC_Export, ExportCatogory = ExportResult.IVUS_CDISC_Export });
|
||||||
}
|
}
|
||||||
if (criterion.CriterionGroup != CriterionGroup.Tumor /*&& criterion.CriterionType != CriterionType.OCT && criterion.CriterionType != CriterionType.IVUS*/)
|
//else if (criterion.CriterionType == CriterionType.SelfDefine)
|
||||||
{
|
{
|
||||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.CDISC_Reading_Export, ExportCatogory = ExportResult.NoneTumorCDISC });
|
list.Add(new ExportDocumentDes() { Code = StaticData.Export.CDISC_Reading_Export, ExportCatogory = ExportResult.CDISC });
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (criterion.ArbitrationRule)
|
switch (criterion.ArbitrationRule)
|
||||||
@@ -2903,7 +2479,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
//阅片结果表
|
//阅片结果表
|
||||||
export_Template = StaticData.Export.CommonReading_Export;
|
export_Template = StaticData.Export.CommonReading_Export;
|
||||||
}
|
}
|
||||||
//斑块表
|
|
||||||
else if (inQuery.ReadingExportType == ExportResult.OCT_ReadingLession_Export)
|
else if (inQuery.ReadingExportType == ExportResult.OCT_ReadingLession_Export)
|
||||||
{
|
{
|
||||||
//OCT
|
//OCT
|
||||||
@@ -2957,7 +2533,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
}
|
}
|
||||||
// 非肿瘤标准 包括自定义,以及系统非肿瘤 会配置到表格层级 问题名称是 表格名称_表格子问题名
|
// 非肿瘤标准 包括自定义,以及系统非肿瘤 会配置到表格层级 问题名称是 表格名称_表格子问题名
|
||||||
else if (
|
else if (
|
||||||
criterion.CriterionGroup == CriterionGroup.Nontumorous && inQuery.ReadingExportType != ExportResult.NoneTumorCDISC
|
criterion.CriterionGroup == CriterionGroup.Nontumorous && inQuery.ReadingExportType != ExportResult.CDISC
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2974,7 +2550,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
}
|
}
|
||||||
// CDISC 导出 只管到 外层问题层级 和阅片结果表是保持一致
|
// CDISC 导出 只管到 外层问题层级 和阅片结果表是保持一致
|
||||||
else if (inQuery.ReadingExportType == ExportResult.NoneTumorCDISC)
|
else if (inQuery.ReadingExportType == ExportResult.CDISC)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (criterion.CriterionGroup == CriterionGroup.Tumor)
|
if (criterion.CriterionGroup == CriterionGroup.Tumor)
|
||||||
@@ -3042,7 +2618,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
if (inQuery.ReadingExportType != ExportResult.NoneTumorCDISC)
|
if (inQuery.ReadingExportType != ExportResult.CDISC)
|
||||||
{
|
{
|
||||||
//最终EXCEL 列
|
//最终EXCEL 列
|
||||||
var configCoumNameList = new List<DynamicColumnConfig.ColumItem>();
|
var configCoumNameList = new List<DynamicColumnConfig.ColumItem>();
|
||||||
@@ -3170,7 +2746,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Lesion Type" : "病灶类型", QuestionValue = lession.LessionType, TranslateDicName = "LesionType" });
|
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Lesion Type" : "病灶类型", QuestionValue = lession.LessionType, TranslateDicName = "LesionType" });
|
||||||
}
|
}
|
||||||
|
|
||||||
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionName = t.QuestionName, OptionTypeEnum = t.OptionTypeEnum, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName ,Unit=t.Unit});
|
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionName = t.QuestionName, OptionTypeEnum = t.OptionTypeEnum, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName });
|
||||||
|
|
||||||
//有三部分组成 外层问题+ 没有配置病灶编号和类型+ 动态的表格问题
|
//有三部分组成 外层问题+ 没有配置病灶编号和类型+ 动态的表格问题
|
||||||
var dynamicLessionInfoList = item.QuestionAnswerList.Union(addLessionInfoList).Union(dynamicPartialLessionInfoList).ToList();
|
var dynamicLessionInfoList = item.QuestionAnswerList.Union(addLessionInfoList).Union(dynamicPartialLessionInfoList).ToList();
|
||||||
@@ -3198,7 +2774,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 不管是list 还是taskList 最终处理的数据都是list 处理好数据后合并
|
#region 不管是list 还是taskList 最终处理的数据都是list 处理好数据后合并
|
||||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
||||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
|
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
|
||||||
{
|
{
|
||||||
//针对1.1 整体肿瘤评估 有的两列要合并一列
|
//针对1.1 整体肿瘤评估 有的两列要合并一列
|
||||||
@@ -3318,14 +2894,14 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionId = Guid.Empty, QuestionName = _userInfo.IsEn_Us ? "Table Name" : "表格名称", QuestionValue = firstLessionAnser.TableName });
|
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionId = Guid.Empty, QuestionName = _userInfo.IsEn_Us ? "Table Name" : "表格名称", QuestionValue = firstLessionAnser.TableName });
|
||||||
|
|
||||||
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, OptionTypeEnum = t.OptionTypeEnum, QuestionName = t.TableName + "_" + t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode, Unit = t.Unit });
|
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, OptionTypeEnum = t.OptionTypeEnum, QuestionName = t.TableName + "_" + t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
|
||||||
|
|
||||||
//有三部分组成 外层问题+ 固定列表格名称 + 动态的表格问题
|
//有三部分组成 外层问题+ 固定列表格名称 + 动态的表格问题
|
||||||
dynamicLessionInfoList = item.QuestionAnswerList.Union(addLessionInfoList).Union(dynamicPartialLessionInfoList).ToList();
|
dynamicLessionInfoList = item.QuestionAnswerList.Union(addLessionInfoList).Union(dynamicPartialLessionInfoList).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, OptionTypeEnum = t.OptionTypeEnum, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode, Unit = t.Unit });
|
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, OptionTypeEnum = t.OptionTypeEnum, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
|
||||||
|
|
||||||
//两部分组成 外层问题+ 动态的表格问题
|
//两部分组成 外层问题+ 动态的表格问题
|
||||||
dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
||||||
@@ -3372,7 +2948,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
TranslateDicNameList = translateDicNameList
|
TranslateDicNameList = translateDicNameList
|
||||||
};
|
};
|
||||||
|
|
||||||
if (export_Template == StaticData.Export.ReadingLession_Export || export_Template == StaticData.Export.CommonJudgeReadingDetail_Export || export_Template== StaticData.Export.OCT_ReadingLession_Export)
|
if (export_Template == StaticData.Export.ReadingLession_Export || export_Template == StaticData.Export.CommonJudgeReadingDetail_Export)
|
||||||
{
|
{
|
||||||
dynamicColumnConfig.TempalteLastColumnIndex = 8;
|
dynamicColumnConfig.TempalteLastColumnIndex = 8;
|
||||||
}
|
}
|
||||||
@@ -3435,7 +3011,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
var dynamicLessionInfoList = new List<CommonQuesionInfo>();
|
var dynamicLessionInfoList = new List<CommonQuesionInfo>();
|
||||||
|
|
||||||
|
|
||||||
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId,OptionTypeEnum=t.OptionTypeEnum, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode, Unit = t.Unit });
|
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId,OptionTypeEnum=t.OptionTypeEnum, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
|
||||||
|
|
||||||
//两部分组成 外层问题+ 动态的表格问题
|
//两部分组成 外层问题+ 动态的表格问题
|
||||||
dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
||||||
@@ -3648,7 +3224,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||||||
|
|
||||||
string fileName = "";
|
string fileName = "";
|
||||||
|
|
||||||
if (inQuery.ReadingExportType == ExportResult.NoneTumorCDISC)
|
if (inQuery.ReadingExportType == ExportResult.CDISC)
|
||||||
{
|
{
|
||||||
(memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(export_Template, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(CommonEvaluationExport), criterion.CriterionType, dynamicColumnConfig);
|
(memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(export_Template, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(CommonEvaluationExport), criterion.CriterionType, dynamicColumnConfig);
|
||||||
|
|
||||||
@@ -125,23 +125,7 @@ public class TumorExportBaseModel : TU_TR_RSBaseModel
|
|||||||
public string VisitNote { get; set; }
|
public string VisitNote { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 肿瘤学结果
|
|
||||||
|
|
||||||
|
|
||||||
public List<OncologyExportInfo> OncologyResultList { get; set; }
|
|
||||||
|
|
||||||
//public string OncologyUserName { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OncologyExportInfo
|
|
||||||
{
|
|
||||||
public decimal? VisitTaskNum { get; set; }
|
|
||||||
public string VisitName { get; set; }
|
|
||||||
public string OncologyResult { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public string OncologyReason { get; set; } = string.Empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -410,33 +410,7 @@ public class IVUS_OCTExportService(IRepository<ReadingQuestionCriterionTrial> _r
|
|||||||
//靶段
|
//靶段
|
||||||
var target = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegment).FirstOrDefault();
|
var target = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegment).FirstOrDefault();
|
||||||
|
|
||||||
var itemValue = target?.QuestionValue??string.Empty;
|
ivus.TARGETV = translateDataList[target?.TranslateDicName].Where(t => t.Code.ToLower() == target?.QuestionValue?.ToLower()).Select(t => isEn_Us ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
//多选
|
|
||||||
int[] enumValues = new int[0];
|
|
||||||
// 1. 反序列化 JSON 数组 (字符串枚举)
|
|
||||||
if (!itemValue.StartsWith("[") || !itemValue.EndsWith("]"))
|
|
||||||
{
|
|
||||||
enumValues = new int[1] { int.Parse(itemValue) };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enumValues = JsonConvert.DeserializeObject<int[]>(itemValue) ?? new int[0];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 2. 翻译每一项并输出逗号拼接字符串
|
|
||||||
var translatedItemData = string.Join(",",
|
|
||||||
enumValues.OrderBy(t=>t).Select(code =>
|
|
||||||
translateDataList[target?.TranslateDicName]
|
|
||||||
.FirstOrDefault(t =>
|
|
||||||
string.Equals(code.ToString(), t.Code, StringComparison.OrdinalIgnoreCase)
|
|
||||||
) is var r && r != null
|
|
||||||
? (isEn_Us ? r.Value : r.ValueCN)
|
|
||||||
: string.Empty
|
|
||||||
));
|
|
||||||
|
|
||||||
ivus.TARGETV = translatedItemData;
|
|
||||||
|
|
||||||
|
|
||||||
var marks = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegmentRemarks).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
var marks = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegmentRemarks).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
||||||
@@ -477,11 +451,6 @@ public class IVUS_OCTExportService(IRepository<ReadingQuestionCriterionTrial> _r
|
|||||||
|
|
||||||
ivus.PAV = findPAVLession?.LessionAnswerList.Where(t => t.QuestionMark == QuestionMark.PAV).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
ivus.PAV = findPAVLession?.LessionAnswerList.Where(t => t.QuestionMark == QuestionMark.PAV).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
||||||
|
|
||||||
if (ivus.PAV.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
ivus.PAV = ivus.PAV + "%";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ivus.DOST = findPAVLession?.LessionAnswerList.Where(t => t.QuestionMark == QuestionMark.PlaqueToOstiumDistance).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
ivus.DOST = findPAVLession?.LessionAnswerList.Where(t => t.QuestionMark == QuestionMark.PlaqueToOstiumDistance).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
||||||
|
|
||||||
@@ -774,33 +743,8 @@ public class IVUS_OCTExportService(IRepository<ReadingQuestionCriterionTrial> _r
|
|||||||
|
|
||||||
var target = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegment).FirstOrDefault();
|
var target = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegment).FirstOrDefault();
|
||||||
|
|
||||||
var itemValue = target?.QuestionValue ?? string.Empty;
|
oct.TARGETV = translateDataList[target?.TranslateDicName].Where(t => t.Code.ToLower() == target?.QuestionValue?.ToLower()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefault() ?? String.Empty;
|
||||||
//多选
|
|
||||||
int[] enumValueArray = new int[0];
|
|
||||||
// 1. 反序列化 JSON 数组 (字符串枚举)
|
|
||||||
if (!itemValue.StartsWith("[") || !itemValue.EndsWith("]"))
|
|
||||||
{
|
|
||||||
enumValueArray = new int[1] { int.Parse(itemValue) };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enumValueArray = JsonConvert.DeserializeObject<int[]>(itemValue) ?? new int[0];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 2. 翻译每一项并输出逗号拼接字符串
|
|
||||||
var translatedItemData = string.Join(",",
|
|
||||||
enumValueArray.OrderBy(t => t).Select(code =>
|
|
||||||
translateDataList[target?.TranslateDicName]
|
|
||||||
.FirstOrDefault(t =>
|
|
||||||
string.Equals(code.ToString(), t.Code, StringComparison.OrdinalIgnoreCase)
|
|
||||||
) is var r && r != null
|
|
||||||
? (isEn_US ? r.Value : r.ValueCN)
|
|
||||||
: string.Empty
|
|
||||||
));
|
|
||||||
|
|
||||||
oct.TARGETV = translatedItemData;
|
|
||||||
|
|
||||||
var marks = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegmentRemarks).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
var marks = task.QuestionAnswerList.Where(t => t.QuestionType == QuestionType.TargetSegmentRemarks).FirstOrDefault()?.QuestionValue ?? string.Empty;
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,589 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2026-03-10 06:15:17Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using DocumentFormat.OpenXml.Office2010.ExcelAc;
|
|
||||||
using IRaCIS.Core.Application.Helper;
|
|
||||||
using IRaCIS.Core.Application.Interfaces;
|
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
|
||||||
using IRaCIS.Core.Infra.EFCore.Common;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Spire.Doc.Interface;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Threading.Channels;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service;
|
|
||||||
|
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
|
||||||
public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRecordRepository, IRepository<UploadFileSyncRecord> _uploadFileSyncRecordRepository,
|
|
||||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IOptionsMonitor<ObjectStoreServiceOptions> options,
|
|
||||||
IFusionCache _fusionCache, IRepository<Trial> _trialRepository, FileSyncQueue _fileSyncQueue) : BaseService, IFileUploadRecordService
|
|
||||||
{
|
|
||||||
|
|
||||||
ObjectStoreServiceOptions ObjectStoreServiceConfig = options.CurrentValue;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 按照 subject visit studyCode 三个维度进行分组的查询列表 (subject相关)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inQuery"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<PageOutput<SubjectFileUploadRecordView>> GetSubjectUploadRecordList(SubjectFileUploadRecordQuery inQuery)
|
|
||||||
{
|
|
||||||
|
|
||||||
var query = _fileUploadRecordRepository.Where(t => t.TrialId == inQuery.TrialId && t.SubjectId != null)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.VisitName), t => t.SubjectVisit.VisitName.Contains(inQuery.VisitName))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.StudyCode), t => t.StudyCode.Contains(inQuery.StudyCode))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.UploadRegion), t => t.UploadRegion == inQuery.UploadRegion)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.TargetRegion), t => t.TargetRegion == inQuery.TargetRegion)
|
|
||||||
.WhereIf(inQuery.IsSync != null, t => t.IsSync == inQuery.IsSync)
|
|
||||||
.GroupBy(t => new { t.StudyCode, SubjectCode = t.Subject.Code, t.SubjectVisit.VisitName, t.SubjectId, t.SubjectVisitId })
|
|
||||||
.Select(g => new SubjectFileUploadRecordView()
|
|
||||||
{
|
|
||||||
SubjectCode = g.Key.SubjectCode,
|
|
||||||
VisitName = g.Key.VisitName,
|
|
||||||
StudyCode = g.Key.StudyCode,
|
|
||||||
SubjectId = g.Key.SubjectId,
|
|
||||||
SubjectVisitId = g.Key.SubjectVisitId,
|
|
||||||
|
|
||||||
FileCount = g.Count(),
|
|
||||||
|
|
||||||
CreateTime = g.Max(t => t.CreateTime),
|
|
||||||
|
|
||||||
SyncFinishedTime = g.Max(t => t.SyncFinishedTime),
|
|
||||||
|
|
||||||
UploadRegion = g.First().UploadRegion,
|
|
||||||
|
|
||||||
TargetRegion = g.First().TargetRegion,
|
|
||||||
|
|
||||||
IsSync = !g.Any(t => t.IsSync == false || t.IsSync == null)
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var pageList = await query.ToPagedListAsync(inQuery);
|
|
||||||
|
|
||||||
return pageList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 上传记录表--里面包含待同步任务 DataFileType= 0 :代表系统文件 1:Subject相关 2:项目相关,但是和subject 没关系
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inQuery"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<PageOutput<FileUploadRecordView>> GetFileUploadRecordList(FileUploadRecordQuery inQuery)
|
|
||||||
{
|
|
||||||
|
|
||||||
var fileUploadRecordQueryable = _fileUploadRecordRepository
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.FileName), t => t.FileName.Contains(inQuery.FileName))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.FileType), t => t.FileType.Contains(inQuery.FileType))
|
|
||||||
.WhereIf(inQuery.TrialId != null, t => t.TrialId == inQuery.TrialId)
|
|
||||||
|
|
||||||
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
|
|
||||||
.WhereIf(inQuery.SubjectVisitId != null, t => t.SubjectVisitId == inQuery.SubjectVisitId)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.StudyCode), t => t.StudyCode.Contains(inQuery.StudyCode))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.VisitName), t => t.SubjectVisit.VisitName.Contains(inQuery.VisitName))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
|
||||||
|
|
||||||
.WhereIf(inQuery.DataFileType == 1 && inQuery.SubjectId != null && inQuery.SubjectVisitId == null, t => t.SubjectVisitId == null)
|
|
||||||
.WhereIf(inQuery.DataFileType == 1 && inQuery.SubjectVisitId != null && inQuery.StudyCode == "", t => t.StudyCode == "")
|
|
||||||
.WhereIf(inQuery.DataFileType == 1 && inQuery.SubjectCode.IsNotNullOrEmpty() && inQuery.VisitName.IsNullOrEmpty(), t => t.SubjectVisitId == null)
|
|
||||||
.WhereIf(inQuery.DataFileType == 1 && inQuery.VisitName.IsNotNullOrEmpty() && inQuery.StudyCode == "", t => t.StudyCode == "")
|
|
||||||
|
|
||||||
.WhereIf(inQuery.DataFileType == 0, t => t.TrialId == null)
|
|
||||||
.WhereIf(inQuery.DataFileType == 1, t => t.SubjectId != null)
|
|
||||||
.WhereIf(inQuery.DataFileType == 2, t => t.SubjectId == null)
|
|
||||||
|
|
||||||
.WhereIf(inQuery.IsNeedSync != null, t => t.IsNeedSync == inQuery.IsNeedSync)
|
|
||||||
|
|
||||||
.WhereIf(inQuery.IsSync != null, t => t.IsSync == inQuery.IsSync)
|
|
||||||
.WhereIf(inQuery.Priority != null, t => t.Priority == inQuery.Priority)
|
|
||||||
.WhereIf(inQuery.BatchDataType != null, t => t.BatchDataType == inQuery.BatchDataType)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.UploadRegion), t => t.UploadRegion == inQuery.UploadRegion)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.TargetRegion), t => t.TargetRegion == inQuery.TargetRegion)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.UploadBatchId), t => t.UploadBatchId.Contains(inQuery.UploadBatchId))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.Path), t => t.Path.Contains(inQuery.Path))
|
|
||||||
.WhereIf(inQuery.UploadStartTime != null, t => t.CreateTime >= inQuery.UploadStartTime)
|
|
||||||
.WhereIf(inQuery.UploadEndTime != null, t => t.CreateTime <= inQuery.UploadEndTime)
|
|
||||||
.WhereIf(inQuery.SyncFinishedStartTime != null, t => t.SyncFinishedTime >= inQuery.SyncFinishedStartTime)
|
|
||||||
.WhereIf(inQuery.SyncFinishedEndTime != null, t => t.SyncFinishedTime <= inQuery.SyncFinishedEndTime)
|
|
||||||
|
|
||||||
.ProjectTo<FileUploadRecordView>(_mapper.ConfigurationProvider);
|
|
||||||
|
|
||||||
var pageList = await fileUploadRecordQueryable.ToPagedListAsync(inQuery);
|
|
||||||
|
|
||||||
return pageList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 任务具体执行记录表
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inQuery"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<PageOutput<UploadFileSyncRecordView>> GetUploadFileSyncRecordList(UploadFileSyncRecordQuery inQuery)
|
|
||||||
{
|
|
||||||
|
|
||||||
var fileUploadRecordQueryable = _uploadFileSyncRecordRepository
|
|
||||||
.WhereIf(inQuery.JobState != null, t => t.JobState == inQuery.JobState)
|
|
||||||
.WhereIf(inQuery.FileUploadRecordId != null, t => t.FileUploadRecordId == inQuery.FileUploadRecordId)
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.StudyCode), t => t.FileUploadRecord.StudyCode.Contains(inQuery.StudyCode))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.VisitName), t => t.FileUploadRecord.SubjectVisit.VisitName.Contains(inQuery.VisitName))
|
|
||||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.FileUploadRecord.Subject.Code.Contains(inQuery.SubjectCode))
|
|
||||||
|
|
||||||
.ProjectTo<UploadFileSyncRecordView>(_mapper.ConfigurationProvider);
|
|
||||||
|
|
||||||
var pageList = await fileUploadRecordQueryable.ToPagedListAsync(inQuery);
|
|
||||||
|
|
||||||
return pageList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 批量设置为需要同步,并且设置优先级
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inComand"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task<IResponseOutput> BatchAddSyncFileTask(BatchAddSyncFileCommand inComand)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
await _fileUploadRecordRepository.BatchUpdateNoTrackingAsync(t => inComand.FileUploadRecordIdList.Contains(t.Id), u => new FileUploadRecord() { IsNeedSync = true, Priority = inComand.Priority ?? 0 });
|
|
||||||
|
|
||||||
foreach (var item in inComand.FileUploadRecordIdList)
|
|
||||||
{
|
|
||||||
_fileSyncQueue.Enqueue(item, inComand.Priority ?? 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await _fileUploadRecordRepository.SaveChangesAsync();
|
|
||||||
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async Task<IResponseOutput> AddOrUpdateFileUploadRecord(FileUploadRecordAddOrEdit addOrEditFileUploadRecord)
|
|
||||||
{
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IP = _userInfo.IP;
|
|
||||||
|
|
||||||
if (ObjectStoreServiceConfig.IsOpenStoreSync && _userInfo.Domain.IsNotNullOrEmpty())
|
|
||||||
{
|
|
||||||
var find = ObjectStoreServiceConfig.SyncConfigList.FirstOrDefault(t => t.Domain == _userInfo.Domain);
|
|
||||||
if (find != null)
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.UploadRegion = find.UploadRegion;
|
|
||||||
addOrEditFileUploadRecord.TargetRegion = find.TargetRegion;
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//前后端调试的时候,上传的时候域名不对应,自动按照后端配置设置上传区域和同步区域
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
var trialDataStore = await _fusionCache.GetOrSetAsync(CacheKeys.TrialDataStoreType(addOrEditFileUploadRecord.TrialId.Value), async _ =>
|
|
||||||
{
|
|
||||||
return await _trialRepository.Where(t => t.Id == addOrEditFileUploadRecord.TrialId).Select(t => t.TrialDataStoreType)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
},
|
|
||||||
TimeSpan.FromDays(7)
|
|
||||||
);
|
|
||||||
|
|
||||||
//项目配置了,那么就设置需要同步
|
|
||||||
if (trialDataStore == TrialDataStore.MUtiCenter)
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = true;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority?? 0;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IsSync = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = false;
|
|
||||||
|
|
||||||
//addOrEditFileUploadRecord.TargetRegion = "";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//系统文件,默认同步
|
|
||||||
addOrEditFileUploadRecord.IsNeedSync = true;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.IsSync = false;
|
|
||||||
|
|
||||||
addOrEditFileUploadRecord.Priority = addOrEditFileUploadRecord.Priority ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = await _fileUploadRecordRepository.InsertOrUpdateAsync(addOrEditFileUploadRecord, true);
|
|
||||||
|
|
||||||
if (addOrEditFileUploadRecord.IsNeedSync == true)
|
|
||||||
{
|
|
||||||
_fileSyncQueue.Enqueue(entity.Id, addOrEditFileUploadRecord.Priority ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseOutput.Ok(entity.Id.ToString());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[HttpDelete("{fileUploadRecordId:guid}")]
|
|
||||||
public async Task<IResponseOutput> DeleteFileUploadRecord(Guid fileUploadRecordId)
|
|
||||||
{
|
|
||||||
var success = await _fileUploadRecordRepository.BatchDeleteNoTrackingAsync(t => t.Id == fileUploadRecordId);
|
|
||||||
return ResponseOutput.Ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#region 同步队列
|
|
||||||
|
|
||||||
|
|
||||||
public sealed class FileSyncQueue
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 优先级队列(仅负责排序)
|
|
||||||
/// </summary>
|
|
||||||
private readonly PriorityQueue<Guid, int> _queue = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前等待中的任务(唯一真实数据)
|
|
||||||
/// key = Guid
|
|
||||||
/// value = 最新 priority
|
|
||||||
/// </summary>
|
|
||||||
private readonly Dictionary<Guid, int> _waiting = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 正在执行的任务(防止重复执行)
|
|
||||||
/// </summary>
|
|
||||||
private readonly HashSet<Guid> _running = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// worker 等待信号
|
|
||||||
/// </summary>
|
|
||||||
private readonly SemaphoreSlim _signal = new(0);
|
|
||||||
|
|
||||||
|
|
||||||
private readonly object _lock = new();
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Enqueue
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 入队(同 Guid 会覆盖优先级)
|
|
||||||
/// </summary>
|
|
||||||
public void Enqueue(Guid id, int priority)
|
|
||||||
{
|
|
||||||
bool needSignal = false;
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
// 如果正在执行,忽略(防止重复)
|
|
||||||
if (_running.Contains(id))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 是否新任务(用于减少 signal 风暴)
|
|
||||||
if (!_waiting.ContainsKey(id))
|
|
||||||
needSignal = true;
|
|
||||||
|
|
||||||
// 更新为最新优先级(最后一次为准)
|
|
||||||
_waiting[id] = priority; //等价于添加或者更新
|
|
||||||
|
|
||||||
// PriorityQueue 无法更新节点
|
|
||||||
// 允许旧节点存在,Dequeue 时过滤
|
|
||||||
_queue.Enqueue(id, -priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只有新增任务才唤醒 worker
|
|
||||||
if (needSignal)
|
|
||||||
_signal.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Dequeue
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取一个待执行任务(无任务时自动等待)
|
|
||||||
/// </summary>
|
|
||||||
public async Task<Guid> DequeueAsync(CancellationToken ct)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await _signal.WaitAsync(ct);
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
while (_queue.Count > 0)
|
|
||||||
{
|
|
||||||
var id = _queue.Dequeue();
|
|
||||||
|
|
||||||
// 已被覆盖或取消 如果这个任务已经不是“当前最新版任务”,那它只是 PriorityQueue 里的垃圾数据,直接跳过。
|
|
||||||
if (!_waiting.TryGetValue(id, out _)) //能从等待任务中取到,那么就是有效的,不能取到那么就是覆盖的
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// 标记为运行中
|
|
||||||
_waiting.Remove(id);
|
|
||||||
_running.Add(id);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Complete
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 任务执行完成(必须调用)
|
|
||||||
/// </summary>
|
|
||||||
public void Complete(Guid id)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
_running.Remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Snapshot
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前等待中的任务快照
|
|
||||||
/// </summary>
|
|
||||||
public Guid[] Snapshot()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
return _waiting.Keys.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// 状态信息(调试用)
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
public int WaitingCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
return _waiting.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RunningCount
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
return _running.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// 同步队列 信号量
|
|
||||||
///// </summary>
|
|
||||||
//public class FileSyncQueue
|
|
||||||
//{
|
|
||||||
// private readonly PriorityQueue<Guid, int> _queue = new();
|
|
||||||
// private readonly SemaphoreSlim _signal = new(0);
|
|
||||||
// private readonly object _lock = new();
|
|
||||||
|
|
||||||
// public void Enqueue(Guid id, int priority)
|
|
||||||
// {
|
|
||||||
// lock (_lock)
|
|
||||||
// {
|
|
||||||
// // priority 越大越优先
|
|
||||||
// _queue.Enqueue(id, -priority);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// //类似于计数器,不会产生通知风暴,可消费资源 +1
|
|
||||||
// //if (有等待线程) 唤醒一个 else 仅增加计数
|
|
||||||
// _signal.Release(); // 唤醒一个 worker
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// 如果没有任务 → 挂起等待 有任务 → 被唤醒并返回
|
|
||||||
// /// </summary>
|
|
||||||
// /// <param name="ct"></param>
|
|
||||||
// /// <returns></returns>
|
|
||||||
// public async Task<Guid> DequeueAsync(CancellationToken ct)
|
|
||||||
// {
|
|
||||||
// await _signal.WaitAsync(ct);
|
|
||||||
|
|
||||||
// lock (_lock)
|
|
||||||
// {
|
|
||||||
// return _queue.Dequeue();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// 获取队列任务Id
|
|
||||||
// /// </summary>
|
|
||||||
// /// <returns></returns>
|
|
||||||
// public Guid[] Snapshot()
|
|
||||||
// {
|
|
||||||
// lock (_lock)
|
|
||||||
// {
|
|
||||||
// return _queue.UnorderedItems
|
|
||||||
// .Select(x => x.Element)
|
|
||||||
// .ToArray();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
#region 这里不用 SyncQueueUseChannel 和调度器 SyncScheduler
|
|
||||||
public class SyncQueueUseChannel
|
|
||||||
{
|
|
||||||
// 优先级队列(priority 越大越先执行)
|
|
||||||
private readonly PriorityQueue<Guid, int> _queue = new();
|
|
||||||
|
|
||||||
// Worker 唤醒信号
|
|
||||||
private readonly Channel<bool> _signal =
|
|
||||||
Channel.CreateUnbounded<bool>(new UnboundedChannelOptions
|
|
||||||
{
|
|
||||||
SingleReader = false,
|
|
||||||
SingleWriter = false
|
|
||||||
});
|
|
||||||
|
|
||||||
// 队列任务数量(不是CPU数量!)
|
|
||||||
private int _count = 0;
|
|
||||||
|
|
||||||
|
|
||||||
private readonly object _lock = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 入队任务
|
|
||||||
/// </summary>
|
|
||||||
public void Enqueue(Guid id, int priority)
|
|
||||||
{
|
|
||||||
bool needSignal = false;
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
// priority 越大越优先 → 转负数
|
|
||||||
_queue.Enqueue(id, -priority);
|
|
||||||
|
|
||||||
// 只有从 0 → 1 才需要唤醒 worker
|
|
||||||
if (_count == 0)
|
|
||||||
needSignal = true;
|
|
||||||
|
|
||||||
_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 避免 signal 风暴
|
|
||||||
if (needSignal)
|
|
||||||
_signal.Writer.TryWrite(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Worker 等待并获取任务
|
|
||||||
/// </summary>
|
|
||||||
public async Task<Guid> DequeueAsync(CancellationToken ct)
|
|
||||||
{
|
|
||||||
|
|
||||||
// 没任务时挂起(不会占CPU)
|
|
||||||
await _signal.Reader.ReadAsync(ct);
|
|
||||||
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
var id = _queue.Dequeue();
|
|
||||||
|
|
||||||
_count--;
|
|
||||||
|
|
||||||
// 如果还有任务,继续唤醒下一个 worker
|
|
||||||
if (_count > 0)
|
|
||||||
_signal.Writer.TryWrite(true);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前排队数量(调试用)
|
|
||||||
/// </summary>
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
return _count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 同步调度器
|
|
||||||
/// </summary>
|
|
||||||
public class FileSyncScheduler
|
|
||||||
{
|
|
||||||
private readonly FileSyncQueue _queue;
|
|
||||||
|
|
||||||
public FileSyncScheduler(FileSyncQueue queue)
|
|
||||||
{
|
|
||||||
_queue = queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Enqueue(FileUploadRecord file)
|
|
||||||
{
|
|
||||||
if (file.IsNeedSync != true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_queue.Enqueue(file.Id, file.Priority ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 如果没有任务 → 挂起等待 有任务 → 被唤醒并返回
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ct"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Task<Guid> WaitAsync(CancellationToken ct)
|
|
||||||
=> _queue.DequeueAsync(ct);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2025-10-28 06:22:47Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using System;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
namespace IRaCIS.Core.Application.Interfaces;
|
|
||||||
|
|
||||||
public interface IEmailLogService
|
|
||||||
{
|
|
||||||
|
|
||||||
Task<PageOutput<EmailLogView>> GetEmailLogList(EmailLogQuery inQuery);
|
|
||||||
|
|
||||||
Task<IResponseOutput> AddOrUpdateEmailLog(EmailLogAddOrEdit addOrEditEmailLog);
|
|
||||||
|
|
||||||
Task<IResponseOutput> DeleteEmailLog(Guid emailLogId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
|
||||||
// 生成时间 2026-03-10 06:15:31Z
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
|
||||||
//--------------------------------------------------------------------
|
|
||||||
using System;
|
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using IRaCIS.Core.Application.ViewModel;
|
|
||||||
namespace IRaCIS.Core.Application.Interfaces;
|
|
||||||
|
|
||||||
public interface IFileUploadRecordService
|
|
||||||
{
|
|
||||||
|
|
||||||
Task<PageOutput<FileUploadRecordView>> GetFileUploadRecordList(FileUploadRecordQuery inQuery);
|
|
||||||
|
|
||||||
Task<IResponseOutput> AddOrUpdateFileUploadRecord(FileUploadRecordAddOrEdit addOrEditFileUploadRecord);
|
|
||||||
|
|
||||||
Task<IResponseOutput> DeleteFileUploadRecord(Guid fileUploadRecordId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,22 +1,15 @@
|
|||||||
using DocumentFormat.OpenXml.Spreadsheet;
|
using IRaCIS.Application.Contracts;
|
||||||
using IRaCIS.Application.Contracts;
|
|
||||||
using IRaCIS.Core.Application.Auth;
|
using IRaCIS.Core.Application.Auth;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using MailKit;
|
using MailKit;
|
||||||
using MailKit.Net.Imap;
|
|
||||||
using MailKit.Search;
|
|
||||||
using MailKit.Security;
|
|
||||||
using Medallion.Threading;
|
using Medallion.Threading;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
using System.Net.Mail;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service
|
namespace IRaCIS.Core.Application.Service
|
||||||
@@ -55,7 +48,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
public interface IMailVerificationService
|
public interface IMailVerificationService
|
||||||
{
|
{
|
||||||
|
|
||||||
Task AnolymousSendEmail(Guid trialId, string emailAddress, int verificationCode);
|
Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode);
|
||||||
|
|
||||||
Task SendEmailVerification(string emailAddress, int verificationCode);
|
Task SendEmailVerification(string emailAddress, int verificationCode);
|
||||||
|
|
||||||
@@ -68,7 +61,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl);
|
Task AddUserSendEmailAsync(Guid userId, string baseUrl, string routeUrl);
|
||||||
|
|
||||||
Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456", string baseUrl = "");
|
Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456");
|
||||||
|
|
||||||
Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl);
|
Task SiteSurveyUserJoinEmail(Guid trialId, Guid userId, string userTypes, string baseUrl, string rootUrl);
|
||||||
|
|
||||||
@@ -77,14 +70,8 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
Task<(Guid identityUserId, Guid userRoleId)> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl);
|
Task<(Guid identityUserId, Guid userRoleId)> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl);
|
||||||
|
|
||||||
Task UserFeedBackMail(Guid feedBackId);
|
Task UserFeedBackMail(Guid feedBackId);
|
||||||
|
|
||||||
Task AfterUserModifyPasswordSendEmailAsync(Guid userId);
|
|
||||||
|
|
||||||
Task SiteSuervyCheckUser(Guid trialId, string email, string name);
|
|
||||||
|
|
||||||
Task SiteSuervyUpdateUser(Guid trialSiteId, string email, string name, string url);
|
|
||||||
}
|
}
|
||||||
[ApiExplorerSettings(GroupName = "Common")]
|
|
||||||
public class MailVerificationService(IRepository<VerificationCode> _verificationCodeRepository,
|
public class MailVerificationService(IRepository<VerificationCode> _verificationCodeRepository,
|
||||||
IRepository<SystemBasicData> _systemBasicDatarepository,
|
IRepository<SystemBasicData> _systemBasicDatarepository,
|
||||||
IRepository<VisitTask> _visitTaskRepository,
|
IRepository<VisitTask> _visitTaskRepository,
|
||||||
@@ -99,7 +86,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
IRepository<UserType> _userTypeRepository,
|
IRepository<UserType> _userTypeRepository,
|
||||||
IRepository<Doctor> _doctorTypeRepository,
|
IRepository<Doctor> _doctorTypeRepository,
|
||||||
IRepository<Dictionary> _dictionaryRepository,
|
IRepository<Dictionary> _dictionaryRepository,
|
||||||
|
|
||||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
||||||
IDistributedLockProvider _distributedLockProvider, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IMailVerificationService
|
IDistributedLockProvider _distributedLockProvider, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IMailVerificationService
|
||||||
@@ -107,17 +93,8 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取邮件主题和html 通用封装 以用户语言为主,没有的就用当前的请求语言_userInfo.IsEn_Us
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="scenario"></param>
|
|
||||||
/// <param name="messageToSend"></param>
|
|
||||||
/// <param name="emailFunc"></param>
|
|
||||||
/// <param name="userWorkLanguage"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
|
||||||
private async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario scenario, MimeMessage messageToSend,
|
private async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario scenario, MimeMessage messageToSend,
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc, UserWorkLanguage? userWorkLanguage = null)
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
|
||||||
{
|
{
|
||||||
var configInfo = await _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario).FirstOrDefaultAsync();
|
var configInfo = await _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario).FirstOrDefaultAsync();
|
||||||
|
|
||||||
@@ -129,9 +106,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isEn_Us = userWorkLanguage.HasValue ? userWorkLanguage.Value == UserWorkLanguage.US : _userInfo.IsEn_Us;
|
var (topicStr, htmlBodyStr) = _userInfo.IsEn_Us ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
||||||
|
|
||||||
var (topicStr, htmlBodyStr) = isEn_Us ? (configInfo.EmailTopic, configInfo.EmailHtmlContent) : (configInfo.EmailTopicCN, configInfo.EmailHtmlContentCN);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -194,16 +169,16 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
return sucessHandle;
|
return sucessHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ReplaceCompanyName(string needDealtxt)
|
||||||
|
{
|
||||||
|
var str = needDealtxt.Replace("{company}", _userInfo.IsEn_Us ? _systemEmailConfig.CompanyName : _systemEmailConfig.CompanyNameCN)
|
||||||
|
.Replace("{company abbreviation}", _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
//MFA
|
//MFA
|
||||||
public async Task SenMFAVerifyEmail(Guid userId, string userName, string emailAddress, int verificationCode, UserMFAType mfaType = UserMFAType.Login)
|
public async Task SenMFAVerifyEmail(Guid userId, string userName, string emailAddress, int verificationCode, UserMFAType mfaType = UserMFAType.Login)
|
||||||
{
|
{
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = _identityUserRepository.Where(t => t.Id == userId).Select(t => t.UserWorkLanguage).First();
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -211,13 +186,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
|
messageToSend.To.Add(new MailboxAddress(userName, emailAddress));
|
||||||
//主题---[来自{0}] 关于MFA邮箱验证的提醒
|
//主题---[来自{0}] 关于MFA邮箱验证的提醒
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
userName,
|
userName,
|
||||||
verificationCode
|
verificationCode
|
||||||
);
|
);
|
||||||
@@ -226,7 +201,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(mfaType == UserMFAType.Login ? EmailBusinessScenario.MFALogin : EmailBusinessScenario.MFAUnlock, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(mfaType == UserMFAType.Login ? EmailBusinessScenario.MFALogin : EmailBusinessScenario.MFAUnlock, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
|
||||||
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
|
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
|
||||||
@@ -249,11 +224,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
public async Task SendEmailVerification(string emailAddress, int verificationCode)
|
public async Task SendEmailVerification(string emailAddress, int verificationCode)
|
||||||
{
|
{
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var isEn_US = _userInfo.IsEn_Us;
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -262,13 +232,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//主题
|
//主题
|
||||||
//---[来自展影IRC]的提醒
|
//---[来自展影IRC]的提醒
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
"Sir/Madam",
|
"Sir/Madam",
|
||||||
//---您正在参与展影医疗IRC项目
|
//---您正在参与展影医疗IRC项目
|
||||||
@@ -280,7 +250,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.ReviewerLogin, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.ReviewerLogin, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
//此时不知道用户
|
//此时不知道用户
|
||||||
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
||||||
@@ -293,14 +263,9 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
|
|
||||||
//中心调研 登陆 发送验证码
|
//中心调研 登陆 发送验证码
|
||||||
public async Task AnolymousSendEmail(Guid trialId, string emailAddress, int verificationCode)
|
public async Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode)
|
||||||
{
|
{
|
||||||
|
//throw new BusinessValidationFailedException("模拟邮件取数据或者发送异常!!!");
|
||||||
//设置工作语言
|
|
||||||
var isEn_US = _userInfo.IsEn_Us;
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
@@ -310,13 +275,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//主题
|
//主题
|
||||||
//$"[来自展影IRC] [{researchProgramNo}] 关于中心调研的提醒";
|
//$"[来自展影IRC] [{researchProgramNo}] 关于中心调研的提醒";
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, companyName, researchProgramNo);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
"Sir/Madam",
|
"Sir/Madam",
|
||||||
//---您正在参与展影医疗IRC项目中心调研工作
|
//---您正在参与展影医疗IRC项目中心调研工作
|
||||||
@@ -328,13 +293,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurveyLogin, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurveyLogin, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
//此时不知道用户
|
//此时不知道用户
|
||||||
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
||||||
|
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo, sucessHandle);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, sucessHandle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,9 +311,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();
|
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
@@ -363,19 +325,20 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new IdentityUser() { EmailToken = token });
|
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new IdentityUser() { EmailToken = token });
|
||||||
|
|
||||||
routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&lang=" + (isEn_US ? "en" : "zh") + "&access_token=" + token;
|
routeUrl = routeUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&UserName=" + sysUserInfo.UserName + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
|
||||||
|
|
||||||
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
||||||
|
|
||||||
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
sysUserInfo.FullName,
|
||||||
sysUserInfo.EMail,
|
sysUserInfo.EMail,
|
||||||
@@ -387,22 +350,17 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysCreateUser, messageToSend, emailConfigFunc, sysUserInfo.UserWorkLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysCreateUser, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
//管理员重置密码发送邮件
|
//管理员重置密码发送邮件
|
||||||
public async Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456", string baseUrl = "")
|
public async Task AdminResetPwdSendEmailAsync(Guid userId, string pwdNotMd5 = "123456")
|
||||||
{
|
{
|
||||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();
|
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).Include(t => t.UserRoleList).ThenInclude(c => c.UserTypeRole).FirstOrDefaultAsync()).IfNullThrowException();
|
||||||
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -411,27 +369,25 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//主题
|
//主题
|
||||||
//---[来自展影IRC] 关于重置账户密码的提醒
|
//---[来自展影IRC] 关于重置账户密码的提醒
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
sysUserInfo.FullName,
|
||||||
sysUserInfo.UserName,
|
sysUserInfo.UserName,
|
||||||
//string.Join(',', sysUserInfo.UserRoleList.Select(t => t.UserTypeRole.UserTypeShortName)),
|
//string.Join(',', sysUserInfo.UserRoleList.Select(t => t.UserTypeRole.UserTypeShortName)),
|
||||||
pwdNotMd5,
|
pwdNotMd5
|
||||||
baseUrl
|
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
return (topicStr, htmlBodyStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysResetPassword, messageToSend, emailConfigFunc, sysUserInfo.UserWorkLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysResetPassword, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
}
|
}
|
||||||
@@ -439,10 +395,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//用户重置邮箱
|
//用户重置邮箱
|
||||||
public async Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode)
|
public async Task SendMailEditEmail(Guid userId, string userName, string emailAddress, int verificationCode)
|
||||||
{
|
{
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = _identityUserRepository.Where(t => t.Id == userId).Select(t => t.UserWorkLanguage).First();
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
@@ -452,13 +404,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//主题
|
//主题
|
||||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
//---[来自展影IRC] 关于重置邮箱的提醒
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
userName,
|
userName,
|
||||||
//---您正在进行邮箱重置操作
|
//---您正在进行邮箱重置操作
|
||||||
@@ -469,7 +421,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UserResetEmail, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UserResetEmail, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
|
|
||||||
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
|
var sucessHandle = GetEmailSuccessHandle(userId, verificationCode, emailAddress);
|
||||||
@@ -482,11 +434,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//不登录 通过邮箱重置密码
|
//不登录 通过邮箱重置密码
|
||||||
public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode)
|
public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode)
|
||||||
{
|
{
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var isEn_US = _userInfo.IsEn_Us;
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -494,13 +441,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
|
messageToSend.To.Add(new MailboxAddress(String.Empty, emailAddress));
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
var topicStr = string.Format(input.topicStr, companyName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
"Sir/Madam",
|
"Sir/Madam",
|
||||||
//---您正在进行邮箱重置密码操作
|
//---您正在进行邮箱重置密码操作
|
||||||
@@ -511,7 +458,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UnloginUseEmailResetPassword, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.UnloginUseEmailResetPassword, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
////此时不知道用户
|
////此时不知道用户
|
||||||
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
var sucessHandle = GetEmailSuccessHandle(Guid.Empty, verificationCode, emailAddress);
|
||||||
@@ -527,11 +474,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -550,18 +492,18 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
||||||
|
|
||||||
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (isEn_US ? "en" : "zh") + "&access_token=" + token;
|
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
|
||||||
|
|
||||||
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
sysUserInfo.FullName,
|
||||||
trialInfo.ExperimentName,
|
trialInfo.ExperimentName,
|
||||||
@@ -576,9 +518,10 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,11 +530,9 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
@@ -609,20 +550,20 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
|
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
|
||||||
}
|
}
|
||||||
|
|
||||||
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (isEn_US ? "en" : "zh") + "&access_token=" + token;
|
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
|
||||||
|
|
||||||
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
||||||
|
|
||||||
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
sysUserInfo.FullName,
|
||||||
trialInfo.ExperimentName,
|
trialInfo.ExperimentName,
|
||||||
@@ -637,9 +578,10 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,12 +620,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
saveItem.IsTestUser = true;
|
saveItem.IsTestUser = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//通过医生信息,设置工作语言
|
|
||||||
var nation = _doctorTypeRepository.Where(t => t.Id == doctorId).Select(t => t.Nation).FirstOrDefault();
|
|
||||||
saveItem.UserWorkLanguage = nation == DoctorNation.CN ? UserWorkLanguage.CN : UserWorkLanguage.US;
|
|
||||||
|
|
||||||
|
|
||||||
saveItem.UserCeateSource = UserCeateSource.ReviewerSelect;
|
saveItem.UserCeateSource = UserCeateSource.ReviewerSelect;
|
||||||
saveItem.TrialId = trialId;
|
saveItem.TrialId = trialId;
|
||||||
|
|
||||||
@@ -726,11 +662,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||||
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
@@ -746,7 +677,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
|
await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == sysUserInfo.Id, u => new Domain.Models.IdentityUser() { EmailToken = token });
|
||||||
}
|
}
|
||||||
|
|
||||||
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (isEn_US ? "en" : "zh") + "&access_token=" + token;
|
var routeUrl = rootUrl + "?UserId=" + sysUserInfo.Id + "&Email=" + sysUserInfo.EMail + "&lang=" + (_userInfo.IsEn_Us ? "en" : "zh") + "&access_token=" + token;
|
||||||
|
|
||||||
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
||||||
|
|
||||||
@@ -756,13 +687,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
// $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";
|
// $"[来自展影IRC] [{trialInfo.ResearchProgramNo}]邀请信";
|
||||||
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
sysUserInfo.FullName,
|
||||||
trialInfo.ExperimentName,
|
trialInfo.ExperimentName,
|
||||||
@@ -777,9 +708,10 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.DoctorUserFirstJoinTrial : EmailBusinessScenario.DoctorUserExistJoinTrial, messageToSend, emailConfigFunc,workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.DoctorUserFirstJoinTrial : EmailBusinessScenario.DoctorUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo, null);
|
|
||||||
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
|
||||||
|
|
||||||
//创建账号 和创建角色 一条,更新的时候才记录更新角色
|
//创建账号 和创建角色 一条,更新的时候才记录更新角色
|
||||||
if (isNeedCreateNewUser == false)
|
if (isNeedCreateNewUser == false)
|
||||||
@@ -799,19 +731,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var feedBack = await _userFeedBackRepository.Where(t => t.Id == feedBackId).Include(t => t.CreateUserRole.UserTypeRole).Include(t => t.CreateUserRole.IdentityUser).FirstNotNullAsync();
|
var feedBack = await _userFeedBackRepository.Where(t => t.Id == feedBackId).Include(t => t.CreateUserRole.UserTypeRole).Include(t => t.CreateUserRole.IdentityUser).FirstNotNullAsync();
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = _identityUserRepository.Where(t => t.Id == _userInfo.IdentityUserId).Select(t => t.UserWorkLanguage).First();
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
var messageToSend = new MimeMessage();
|
||||||
//发件地址
|
//发件地址
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||||
|
|
||||||
var isHaveTrialId = feedBack.TrialId != null;
|
var isHaveTrialId = feedBack.TrialId != null;
|
||||||
|
|
||||||
var trialinfo = await _trialRepository.Where(x => x.Id == feedBack.TrialId).FirstOrDefaultAsync();
|
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
var emialScenario = feedBack.VisitTaskId != null ? EmailBusinessScenario.IRImageError : (feedBack.SubjectVisitId != null ? EmailBusinessScenario.TrialSubjectVisitFeedBack : (feedBack.TrialId != null ? EmailBusinessScenario.TrialFeedBack : EmailBusinessScenario.SysFeedBack));
|
var emialScenario = feedBack.VisitTaskId != null ? EmailBusinessScenario.IRImageError : (feedBack.SubjectVisitId != null ? EmailBusinessScenario.TrialSubjectVisitFeedBack : (feedBack.TrialId != null ? EmailBusinessScenario.TrialFeedBack : EmailBusinessScenario.SysFeedBack));
|
||||||
|
|
||||||
@@ -834,7 +760,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
if (feedBack.VisitTaskId != null)
|
if (feedBack.VisitTaskId != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "FeedBackTypeToIR" && t.ParentId != null && t.Code == ((int)feedBack.QuestionType).ToString()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "FeedBackTypeToIR" && t.ParentId != null && t.Code == ((int)feedBack.QuestionType).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
var info = await _visitTaskRepository.Where(t => t.Id == feedBack.VisitTaskId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.SourceSubjectVisit.VisitName }).FirstNotNullAsync();
|
var info = await _visitTaskRepository.Where(t => t.Id == feedBack.VisitTaskId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.SourceSubjectVisit.VisitName }).FirstNotNullAsync();
|
||||||
@@ -843,7 +769,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
|
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
userNames,
|
userNames,
|
||||||
info.TrialCode,
|
info.TrialCode,
|
||||||
info.SubejctCode,
|
info.SubejctCode,
|
||||||
@@ -859,12 +785,12 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IRImageError, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IRImageError, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (feedBack.SubjectVisitId != null)
|
else if (feedBack.SubjectVisitId != null)
|
||||||
{
|
{
|
||||||
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialSubjectVisitFeedBack).ToString()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialSubjectVisitFeedBack).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
var info = await _subjectVisitRepository.Where(t => t.Id == feedBack.SubjectVisitId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.VisitName }).FirstNotNullAsync();
|
var info = await _subjectVisitRepository.Where(t => t.Id == feedBack.SubjectVisitId).Select(t => new { t.Trial.ResearchProgramNo, t.Trial.TrialCode, SubejctCode = t.Subject.Code, t.VisitName }).FirstNotNullAsync();
|
||||||
@@ -873,7 +799,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
|
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo, info.SubejctCode, info.VisitName);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
userNames,
|
userNames,
|
||||||
info.TrialCode,
|
info.TrialCode,
|
||||||
info.SubejctCode,
|
info.SubejctCode,
|
||||||
@@ -889,13 +815,13 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialSubjectVisitFeedBack, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialSubjectVisitFeedBack, messageToSend, emailConfigFunc);
|
||||||
}
|
}
|
||||||
//项目相关的反馈 pm admin
|
//项目相关的反馈 pm admin
|
||||||
else if (feedBack.TrialId != null)
|
else if (feedBack.TrialId != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialFeedBack).ToString()).Select(t => isEn_US ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.TrialFeedBack).ToString()).Select(t => _userInfo.IsEn_Us ? t.Value : t.ValueCN).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
|
||||||
var info = await _trialRepository.Where(t => t.Id == feedBack.TrialId).Select(t => new { t.ResearchProgramNo, t.TrialCode }).FirstNotNullAsync();
|
var info = await _trialRepository.Where(t => t.Id == feedBack.TrialId).Select(t => new { t.ResearchProgramNo, t.TrialCode }).FirstNotNullAsync();
|
||||||
@@ -904,7 +830,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo);
|
var topicStr = string.Format(input.topicStr, info.ResearchProgramNo);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
userNames,
|
userNames,
|
||||||
info.TrialCode,
|
info.TrialCode,
|
||||||
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
|
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
|
||||||
@@ -918,7 +844,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialFeedBack, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.TrialFeedBack, messageToSend, emailConfigFunc);
|
||||||
|
|
||||||
}
|
}
|
||||||
//项目无关的反馈 admin
|
//项目无关的反馈 admin
|
||||||
@@ -930,7 +856,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
var topicStr = string.Format(input.topicStr);
|
var topicStr = string.Format(input.topicStr);
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
var htmlBodyStr = string.Format(ReplaceCompanyName(input.htmlBodyStr),
|
||||||
userNames,
|
userNames,
|
||||||
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
|
feedBack.CreateUserRole.UserTypeRole.UserTypeShortName,
|
||||||
feedBack.CreateUserRole.IdentityUser.FullName,
|
feedBack.CreateUserRole.IdentityUser.FullName,
|
||||||
@@ -942,140 +868,11 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysFeedBack, messageToSend, emailConfigFunc, workLanguage);
|
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SysFeedBack, messageToSend, emailConfigFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trialinfo == null)
|
|
||||||
{
|
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//用户修改密码发送邮件
|
|
||||||
public async Task AfterUserModifyPasswordSendEmailAsync(Guid userId)
|
|
||||||
{
|
|
||||||
|
|
||||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var workLanguage = sysUserInfo.UserWorkLanguage;
|
|
||||||
var isEn_US = workLanguage == UserWorkLanguage.US;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
//发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
//收件地址
|
|
||||||
messageToSend.To.Add(new MailboxAddress(sysUserInfo.FullName, sysUserInfo.EMail));
|
|
||||||
//主题
|
|
||||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
var topicStr = string.Format(input.topicStr, companyName);
|
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
|
|
||||||
sysUserInfo.FullName,
|
|
||||||
_systemEmailConfig.PlatformName
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IdentityUser_ModifyPassword, messageToSend, emailConfigFunc, workLanguage);
|
|
||||||
|
|
||||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//中心调研核对人员提醒
|
|
||||||
public async Task SiteSuervyCheckUser(Guid trialId, string email, string name)
|
|
||||||
{
|
|
||||||
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var isEn_US = _userInfo.IsEn_Us;
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
//发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
//收件地址
|
|
||||||
messageToSend.To.Add(new MailboxAddress(name, email));
|
|
||||||
//主题
|
|
||||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
|
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
name,
|
|
||||||
trialInfo.TrialCode,
|
|
||||||
trialInfo.ResearchProgramNo
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_CheckUser, messageToSend, emailConfigFunc);
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SiteSuervyUpdateUser(Guid trialSiteId, string email, string name, string url)
|
|
||||||
{
|
|
||||||
var siteInfo = await _trialSiteRepository.Where(t => t.Id == trialSiteId).Include(x => x.Trial).FirstOrDefaultAsync();
|
|
||||||
|
|
||||||
var trialInfo = siteInfo.Trial;
|
|
||||||
|
|
||||||
|
|
||||||
//设置工作语言
|
|
||||||
var isEn_US = _userInfo.IsEn_Us;
|
|
||||||
var workLanguage = isEn_US ? UserWorkLanguage.US : UserWorkLanguage.CN;
|
|
||||||
|
|
||||||
var messageToSend = new MimeMessage();
|
|
||||||
//发件地址
|
|
||||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
|
||||||
//收件地址
|
|
||||||
messageToSend.To.Add(new MailboxAddress(name, email));
|
|
||||||
//主题
|
|
||||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
|
||||||
|
|
||||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
|
||||||
|
|
||||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
|
||||||
{
|
|
||||||
|
|
||||||
var topicStr = string.Format(input.topicStr, companyName, trialInfo.ResearchProgramNo);
|
|
||||||
|
|
||||||
var htmlBodyStr = string.Format(CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr, workLanguage),
|
|
||||||
name,
|
|
||||||
trialInfo.TrialCode,
|
|
||||||
siteInfo.TrialSiteCode,
|
|
||||||
siteInfo.TrialSiteName,
|
|
||||||
url
|
|
||||||
);
|
|
||||||
|
|
||||||
return (topicStr, htmlBodyStr);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_UpdateUser, messageToSend, emailConfigFunc);
|
|
||||||
await SendEmailHelper.SendTrialEmailAsync(messageToSend, trialInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,18 +11,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
{
|
{
|
||||||
public CommonConfig()
|
public CommonConfig()
|
||||||
{
|
{
|
||||||
// 在此处拷贝automapper 映射
|
|
||||||
CreateMap<EmailAttachmentLog, EmaliAttachmentInfo>();
|
|
||||||
CreateMap<EmailRecipientLog, EmailRecipientLogView>();
|
|
||||||
CreateMap<EmailLog, EmailLogView>()
|
|
||||||
.ForMember(t => t.RecipientList, u => u.MapFrom(c => c.EmailRecipientLogList))
|
|
||||||
.ForMember(t => t.AttachmentList, u => u.MapFrom(c => c.AttachmentList));
|
|
||||||
|
|
||||||
CreateMap<EmailLog, GetEmailInfoOutDto>()
|
|
||||||
.ForMember(t => t.RecipientList, u => u.MapFrom(c => c.EmailRecipientLogList))
|
|
||||||
.ForMember(t => t.AttachmentList, u => u.MapFrom(c => c.AttachmentList));
|
|
||||||
|
|
||||||
CreateMap<EmailLog, EmailLogAddOrEdit>().ReverseMap();
|
|
||||||
|
|
||||||
CreateMap<FrontAuditConfig, FrontAuditConfigAddOrEdit>().ReverseMap();
|
CreateMap<FrontAuditConfig, FrontAuditConfigAddOrEdit>().ReverseMap();
|
||||||
|
|
||||||
@@ -41,7 +30,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
.ForMember(t => t.EmailNoticeUserList, u => u.MapFrom(c => c.EmailNoticeUserTypeList));
|
.ForMember(t => t.EmailNoticeUserList, u => u.MapFrom(c => c.EmailNoticeUserTypeList));
|
||||||
|
|
||||||
CreateMap<EmailNoticeConfig, EmailNoticeConfigExportDto>();
|
CreateMap<EmailNoticeConfig, EmailNoticeConfigExportDto>();
|
||||||
|
|
||||||
|
|
||||||
CreateMap<Dictionary, DicView>()
|
CreateMap<Dictionary, DicView>()
|
||||||
.ForMember(t => t.ParentCode, u => u.MapFrom(c => c.Parent.Code));
|
.ForMember(t => t.ParentCode, u => u.MapFrom(c => c.Parent.Code));
|
||||||
@@ -89,14 +78,14 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
CreateMap<Internationalization, InternationalizationAddOrEdit>().ReverseMap();
|
CreateMap<Internationalization, InternationalizationAddOrEdit>().ReverseMap();
|
||||||
|
|
||||||
CreateMap<InternationalizationAddOrEdit, IRCGlobalInfoDTO>();
|
CreateMap<InternationalizationAddOrEdit, IRCGlobalInfoDTO>();
|
||||||
|
|
||||||
|
|
||||||
CreateMap<Internationalization, BatchInternationalizationDto>().ReverseMap();
|
CreateMap<Internationalization, BatchInternationalizationDto>().ReverseMap();
|
||||||
|
|
||||||
CreateMap<Internationalization, IRCGlobalInfoDTO>();
|
CreateMap<Internationalization, IRCGlobalInfoDTO>();
|
||||||
|
|
||||||
CreateMap<EventStoreRecord, EventStoreRecordView>();
|
CreateMap<EventStoreRecord, EventStoreRecordView>();
|
||||||
|
|
||||||
CreateMap<BatchAddInternationalizationDto, InternationalizationAddOrEdit>();
|
CreateMap<BatchAddInternationalizationDto, InternationalizationAddOrEdit>();
|
||||||
|
|
||||||
|
|
||||||
@@ -116,7 +105,7 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.Subject.TrialSite.TrialSiteCode));
|
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.Subject.TrialSite.TrialSiteCode));
|
||||||
|
|
||||||
|
|
||||||
CreateMap<TumorExportBaseModel, TU_Export>();
|
CreateMap<TumorExportBaseModel , TU_Export>();
|
||||||
CreateMap<TumorExportBaseModel, TR_Export>();
|
CreateMap<TumorExportBaseModel, TR_Export>();
|
||||||
CreateMap<TumorExportBaseModel, RS_Export>();
|
CreateMap<TumorExportBaseModel, RS_Export>();
|
||||||
CreateMap<TumorExportBaseModel, CO_Export>();
|
CreateMap<TumorExportBaseModel, CO_Export>();
|
||||||
@@ -124,21 +113,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
CreateMap<IVUS_OCTBaseDto, IvusExportDto>();
|
CreateMap<IVUS_OCTBaseDto, IvusExportDto>();
|
||||||
CreateMap<IVUS_OCTBaseDto, OctExportDto>();
|
CreateMap<IVUS_OCTBaseDto, OctExportDto>();
|
||||||
|
|
||||||
|
|
||||||
CreateMap<FileUploadRecord, FileUploadRecordView>()
|
|
||||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(s => s.Subject.Code))
|
|
||||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName));
|
|
||||||
CreateMap<FileUploadRecord, FileUploadRecordAddOrEdit>().ReverseMap();
|
|
||||||
|
|
||||||
|
|
||||||
CreateMap<UploadFileSyncRecord, UploadFileSyncRecordView>()
|
|
||||||
.ForMember(d => d.FileName, u => u.MapFrom(s => s.FileUploadRecord.FileName))
|
|
||||||
.ForMember(d => d.FileType, u => u.MapFrom(s => s.FileUploadRecord.FileType))
|
|
||||||
.ForMember(d => d.Path, u => u.MapFrom(s => s.FileUploadRecord.Path))
|
|
||||||
.ForMember(d => d.StudyCode, u => u.MapFrom(s => s.FileUploadRecord.StudyCode))
|
|
||||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(s => s.FileUploadRecord.Subject.Code))
|
|
||||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.FileUploadRecord.SubjectVisit.VisitName));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ namespace IRaCIS.Application.Contracts
|
|||||||
|
|
||||||
public bool? AcceptingNewTrial { get; set; }//是否接受新的项目
|
public bool? AcceptingNewTrial { get; set; }//是否接受新的项目
|
||||||
public bool? ActivelyReading { get; set; }// 是否接受新的读片任务
|
public bool? ActivelyReading { get; set; }// 是否接受新的读片任务
|
||||||
public DoctorNation? Nation { get; set; }// 0-中国医生,2-美国医生,3-全部
|
public int? Nation { get; set; }// 0-中国医生,2-美国医生,3-全部
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -183,7 +183,6 @@ namespace IRaCIS.Application.Contracts
|
|||||||
|
|
||||||
public class SelectionReviewerDTO : DoctorDTO
|
public class SelectionReviewerDTO : DoctorDTO
|
||||||
{
|
{
|
||||||
public bool IsVacation { get; set; }
|
|
||||||
public int DoctorTrialState { get; set; }
|
public int DoctorTrialState { get; set; }
|
||||||
|
|
||||||
public bool IsEnroll { get; set; } = false;
|
public bool IsEnroll { get; set; } = false;
|
||||||
|
|||||||
@@ -133,29 +133,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 维护 医生基本信息 Code
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public async Task ServiceDoctorBasicInfo()
|
|
||||||
{
|
|
||||||
var doctorList = await _doctorRepository.Where(t => t.Code == 0 && t.TrialId == null).ToListAsync();
|
|
||||||
|
|
||||||
var code = await _doctorRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync();
|
|
||||||
|
|
||||||
foreach (var doctorItem in doctorList)
|
|
||||||
{
|
|
||||||
code++;
|
|
||||||
doctorItem.Code = code;
|
|
||||||
doctorItem.ReviewerCode = AppSettings.GetCodeStr(doctorItem.Code, nameof(Doctor));
|
|
||||||
await _doctorRepository.BatchUpdateNoTrackingAsync(x => x.Id == doctorItem.Id, x => new Doctor()
|
|
||||||
{
|
|
||||||
Code = doctorItem.Code,
|
|
||||||
ReviewerCode = doctorItem.ReviewerCode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 新增修改 医生基本信息和工作
|
/// 新增修改 医生基本信息和工作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -234,7 +211,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
//重新插入新的 Title记录
|
//重新插入新的 Title记录
|
||||||
updateModel.TitleIds.ForEach(titleId => adddata.Add(new DoctorDictionary() { DoctorId = updateModel.Id.Value, KeyName = StaticData.Title, DictionaryId = titleId }));
|
updateModel.TitleIds.ForEach(titleId => adddata.Add(new DoctorDictionary() { DoctorId = updateModel.Id.Value, KeyName = StaticData.Title, DictionaryId = titleId }));
|
||||||
|
|
||||||
indto.ReviewerCode = doctor.ReviewerCode;
|
|
||||||
await _doctorDictionaryRepository.AddRangeAsync(adddata);
|
await _doctorDictionaryRepository.AddRangeAsync(adddata);
|
||||||
|
|
||||||
_mapper.Map(indto, doctor);
|
_mapper.Map(indto, doctor);
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ namespace IRaCIS.Core.Application.Service
|
|||||||
|
|
||||||
#region 医生基本信息
|
#region 医生基本信息
|
||||||
CreateMap<Doctor, SelectionReviewerDTO>()
|
CreateMap<Doctor, SelectionReviewerDTO>()
|
||||||
.ForMember(d => d.IsVacation, u => u.MapFrom(t => t.VacationList.Any(x=>x.StartDate<DateTime.Now&&x.EndDate>DateTime.Now)))
|
|
||||||
.ForMember(d => d.DoctorUserName, u => u.MapFrom(t => t.UserRole.IdentityUser.UserName));
|
.ForMember(d => d.DoctorUserName, u => u.MapFrom(t => t.UserRole.IdentityUser.UserName));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ public class AuditDocumentService(IRepository<AuditDocument> _auditDocumentRepos
|
|||||||
.WhereIf(inQuery.IdentityUserName.IsNotNullOrEmpty(), t => t.AuditRecordIdentityUserList.Any(c => c.IdentityUser.UserName.Contains(inQuery.IdentityUserName) || c.IdentityUser.FullName.Contains(inQuery.IdentityUserName)))
|
.WhereIf(inQuery.IdentityUserName.IsNotNullOrEmpty(), t => t.AuditRecordIdentityUserList.Any(c => c.IdentityUser.UserName.Contains(inQuery.IdentityUserName) || c.IdentityUser.FullName.Contains(inQuery.IdentityUserName)))
|
||||||
.WhereIf(inQuery.CompanyName.IsNotNullOrEmpty(), t => t.CompanyName.Contains(inQuery.CompanyName))
|
.WhereIf(inQuery.CompanyName.IsNotNullOrEmpty(), t => t.CompanyName.Contains(inQuery.CompanyName))
|
||||||
.WhereIf(inQuery.AuditContent.IsNotNullOrEmpty(), t => t.AuditContent.Contains(inQuery.AuditContent))
|
.WhereIf(inQuery.AuditContent.IsNotNullOrEmpty(), t => t.AuditContent.Contains(inQuery.AuditContent))
|
||||||
.WhereIf(inQuery.IsViewTrainingRecord != null, t => t.IsViewTrainingRecord == inQuery.IsViewTrainingRecord)
|
|
||||||
.ProjectTo<AuditRecordView>(_mapper.ConfigurationProvider);
|
.ProjectTo<AuditRecordView>(_mapper.ConfigurationProvider);
|
||||||
|
|
||||||
var pageList = await auditRecordQueryable.ToPagedListAsync(inQuery);
|
var pageList = await auditRecordQueryable.ToPagedListAsync(inQuery);
|
||||||
@@ -668,7 +667,7 @@ public class AuditDocumentService(IRepository<AuditDocument> _auditDocumentRepos
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
// 不能移动到自己父类这个文件夹
|
// 不能自动到自己父类这个文件夹
|
||||||
if (await _auditDocumentRepository.AnyAsync(x => x.ParentId == inDto.ParentId && inDto.Ids.Contains(x.Id)))
|
if (await _auditDocumentRepository.AnyAsync(x => x.ParentId == inDto.ParentId && inDto.Ids.Contains(x.Id)))
|
||||||
{
|
{
|
||||||
throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotMoveToParent"]);
|
throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotMoveToParent"]);
|
||||||
@@ -694,7 +693,7 @@ public class AuditDocumentService(IRepository<AuditDocument> _auditDocumentRepos
|
|||||||
public async Task<IResponseOutput> CopyFileOrFolder(MovieFileOrFolderInDto inDto)
|
public async Task<IResponseOutput> CopyFileOrFolder(MovieFileOrFolderInDto inDto)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var item in inDto.Ids)
|
foreach (var item in inDto.Ids)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user