Compare commits
317 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 43455da7bc | |||
| 0030eac22e | |||
| 671c071a45 | |||
| 3419015542 | |||
| 3eea6cf8b7 | |||
| 2c407c6e4e | |||
| ab90591e7c | |||
| 33a2b7f373 | |||
| 680a6cb437 | |||
| 21c19f4b6d | |||
| 8c03167f7e | |||
| b629b2eec4 | |||
| 01af8f72d3 | |||
| 4d10db054c | |||
| a019a542b0 | |||
| b42325337e | |||
| a3152bb6e1 | |||
| 4ec0441d28 | |||
| 9adc8a93b1 | |||
| 3f3d1a562b | |||
| 1b6ba91240 | |||
| c406976a6d | |||
| d213fa7a99 | |||
| 60707150a6 | |||
| 008906d245 | |||
| 762b8b7425 | |||
| 24228428fa | |||
| 9148651556 | |||
| 1c9c3eb893 | |||
| 17e0517e5b | |||
| 7662880352 | |||
| c3c433244e | |||
| df65d592ad | |||
| 7873523c1b | |||
| 8b5800b32e | |||
| 2e46791466 | |||
| fc0ef2e89f | |||
| 1de687cbf3 | |||
| 3a017dbfa3 | |||
| 1f828b403b | |||
| f75fafaa42 | |||
| 7c561a4656 | |||
| 033b849bdc | |||
| 8ae0b0d621 | |||
| b6bad061b7 | |||
| 1dd8515ac2 | |||
| 9f3bb29004 | |||
| 52dd676cf9 | |||
| 342b567e2c | |||
| 35ee76be0b | |||
| b4d40a4770 | |||
| 84bfcb4d3e | |||
| f030ed9b66 | |||
| c6920a1995 | |||
| 2d681ce6bc | |||
| 3981f2cd50 | |||
| 2b961c7985 | |||
| fb2fdd2c27 | |||
| f6bcefd1e8 | |||
| 1d7b28e7f9 | |||
| 3ea2bdfc92 | |||
| 4aa0161c41 | |||
| ff4ab39025 | |||
| bb35ae1b9a | |||
| 0e0ce59d74 | |||
| 82d3157e2a | |||
| 12cb53b167 | |||
| 5fc53a1999 | |||
| b712abd1d5 | |||
| a1c13b5850 | |||
| a0fe7be308 | |||
| bbfa966b57 | |||
| 6d11fc68b4 | |||
| eef764dd90 | |||
| 8423b00bec | |||
| dbaac006c7 | |||
| 510c73dd24 | |||
| 41486798d2 | |||
| f40faa5519 | |||
| eecfe6dcae | |||
| 8a004ef35f | |||
| 369805e6c6 | |||
| 93b93f6a3a | |||
| 9fbee7e0c9 | |||
| 46704d5299 | |||
| 4225014cdd | |||
| ae36d4680a | |||
| d48f736392 | |||
| b0d8a49929 | |||
| e45791c676 | |||
| ca425c602b | |||
| 44e7ffaeeb | |||
| cf42b2e57f | |||
| 840de08e69 | |||
| 929903aa1b | |||
| 5eafcc9c8c | |||
| a1657f5827 | |||
| dff2e712ad | |||
| a5f3430965 | |||
| 5059d66aa1 | |||
| 668af5ee0b | |||
| a70caefe01 | |||
| 64bd6a5604 | |||
| b68deafa82 | |||
| d29c150081 | |||
| 4d3ecd05dc | |||
| 143d7f0c4b | |||
| 4d2f04b30e | |||
| 955ca4a1a6 | |||
| 6e92895043 | |||
| 6102309828 | |||
| 8f34644d45 | |||
| f347b34f59 | |||
| dc7e71dc74 | |||
| 749bf95761 | |||
| a67472c9b4 | |||
| 32c8d70179 | |||
| 510dfcac30 | |||
| 9b59a55423 | |||
| 0bd269f93e | |||
| e55a13cfb1 | |||
| 1617de2fc1 | |||
| 40c3ea65ff | |||
| 541e000183 | |||
| 0e93894ed8 | |||
| 7f1621915f | |||
| 70e4829f32 | |||
| c77b3d74c8 | |||
| 1f4ea09bc6 | |||
| c45020f24f | |||
| ca679057c4 | |||
| 456793293b | |||
| 75d3908911 | |||
| a7fbd00530 | |||
| 785d5ec869 | |||
| c5feb98ed8 | |||
| 121b1d4eb4 | |||
| 8e2b99333c | |||
| 5bd055c77d | |||
| 5ea9d63cb9 | |||
| 0134d6c723 | |||
| a9c80a670b | |||
| 998b92aa79 | |||
| 60ce8c45b2 | |||
| a66d25f564 | |||
| 91b66660a6 | |||
| 1031222e47 | |||
| 2005eacaa9 | |||
| b581afebe6 | |||
| 1532ac4a7e | |||
| 231b3f71c5 | |||
| 308f5140a1 | |||
| ef673fc44b | |||
| f347b0cace | |||
| 102cf5f6dc | |||
| d9ca71009f | |||
| 114ee50273 | |||
| 54bb66f738 | |||
| 19f52bc133 | |||
| 2439dec9fb | |||
| fb0fd7d91f | |||
| 3765b390a6 | |||
| f6be3186e7 | |||
| 7399568e36 | |||
| 37d798627a | |||
| fe2a375b4e | |||
| 70443b7b8d | |||
| 7a37c01b7f | |||
| 7215c75f5a | |||
| a34c47dc3c | |||
| 6fdad9a482 | |||
| 08e62e4500 | |||
| 3cfb4556f3 | |||
| b8e3e83b80 | |||
| 7e9bf65f9f | |||
| 5197e49c1f | |||
| 7880836f39 | |||
| 487eb9dca8 | |||
| 473cee0e30 | |||
| 817cdcc8f7 | |||
| bf03430958 | |||
| 58321c4c82 | |||
| 8cabc8c96a | |||
| 7f050a1dd6 | |||
| e5e2a0394b | |||
| a56ab0680b | |||
| ee13d0ae2e | |||
| ee2c66c8fb | |||
| f1fb2068de | |||
| 95e0239e42 | |||
| 0b28ef5461 | |||
| 68fe2b75dc | |||
| ecfeee1693 | |||
| 9cda4360ca | |||
| 18b9c08101 | |||
| d4e89aec20 | |||
| 01a3a9057b | |||
| 2107a42e37 | |||
| d96e746db7 | |||
| be034d4d8b | |||
| ca44b4786a | |||
| 74056167d6 | |||
| e6aec6b559 | |||
| 9a488610da | |||
| f82420b7ef | |||
| fbeaec2820 | |||
| b4907bfe9b | |||
| 6e75e45942 | |||
| 3292b9f978 | |||
| 1959045ab2 | |||
| 6a99e3104a | |||
| ab91d360b1 | |||
| 50a4a82819 | |||
| 498c02431b | |||
| fd54d64ae3 | |||
| ac80e3a455 | |||
| c6a55949b3 | |||
| 18547cdec1 | |||
| d29707c8ee | |||
| c7e29116dd | |||
| a85cc1236c | |||
| 7b4c603fa6 | |||
| 67c93e654e | |||
| 9b0c874314 | |||
| d172e48c79 | |||
| 2a2419af90 | |||
| 7e39094b13 | |||
| 8936e9db99 | |||
| bd92d48232 | |||
| 57f7b29cc7 | |||
| f55f498626 | |||
| 955fe25d30 | |||
| 86c24e6002 | |||
| b835a028ad | |||
| c8d5b94154 | |||
| d03d294e97 | |||
| 28014139f5 | |||
| b42a86922e | |||
| 09bf2b4d91 | |||
| 3685686447 | |||
| b6d2128034 | |||
| 9545e699c2 | |||
| 87955d2ca0 | |||
| 0a8573091e | |||
| a713ffdc61 | |||
| 406235cc03 | |||
| 1095e07f87 | |||
| 14b8cbac23 | |||
| 92063da2bf | |||
| 9c6b835800 | |||
| f71b71bb54 | |||
| 6d39e72506 | |||
| a90edaff51 | |||
| bb8fb0a968 | |||
| 348ca93086 | |||
| e3b2046cb8 | |||
| 99350c3a17 | |||
| 1523450b88 | |||
| fb20b1f1b2 | |||
| 5c90b66fc9 | |||
| bc1a6562d5 | |||
| be1fbf2059 | |||
| 7a3bbbeb19 | |||
| d263ecbe2a | |||
| 447e916564 | |||
| 48c9721ab4 | |||
| e641e78fb3 | |||
| d37c1cb872 | |||
| da2afd0d5a | |||
| 09305928ed | |||
| e16fd2f4de | |||
| b2389403d9 | |||
| 29c137a2c5 | |||
| 2e1a68fa14 | |||
| 7ec76f6ce3 | |||
| 87e70447f3 | |||
| f72e3f4300 | |||
| 7154196667 | |||
| 0081cf16d0 | |||
| 2eec5f02da | |||
| 4b011ee727 | |||
| b115dd5253 | |||
| 84349c19e7 | |||
| 84d08c0378 | |||
| 197aa9bf0a | |||
| f83819d0c9 | |||
| 43c0885e0a | |||
| 1cff4f7603 | |||
| 71f978609b | |||
| 774e7ccc25 | |||
| c89b65b550 | |||
| a8800b01f3 | |||
| fcc2a68618 | |||
| a353c90bf7 | |||
| 8e730fc342 | |||
| 53149bf8a0 | |||
| b2d681da09 | |||
| 49a36b8214 | |||
| 270941431d | |||
| 2e3c209de2 | |||
| 0be5763ce3 | |||
| 7f1232e2ff | |||
| 9669032e6c | |||
| fd5711a31d | |||
| 25c5b32fa7 | |||
| 5f75413c9c | |||
| 9fa73705ba | |||
| 0f27e246a6 | |||
| 0d26daa3b0 | |||
| 8186ec1b02 | |||
| 0f0967f893 | |||
| 56165f5037 | |||
| 0b707117c6 | |||
| 5186a530f8 | |||
| b3ed2dd497 | |||
| 5cfa209cc2 | |||
| ca5accfaa0 |
@@ -14,12 +14,12 @@
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
||||
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.4" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Minio" Version="6.0.4" />
|
||||
<PackageReference Include="Minio" Version="6.0.3" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
|
||||
@@ -22,6 +22,7 @@ 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
|
||||
{
|
||||
@@ -40,7 +41,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
private IServiceProvider _serviceProvider { get; set; }
|
||||
|
||||
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
|
||||
private List<Guid> _SCPStudyIdList => _ImageUploadList.Where(t => t.SCPStudyId != Guid.Empty).Select(t => t.SCPStudyId).ToList();
|
||||
|
||||
private List<ImageUploadInfo> _ImageUploadList { get; set; } = new List<ImageUploadInfo>();
|
||||
|
||||
private SCPImageUpload _upload { get; set; }
|
||||
|
||||
@@ -163,27 +166,48 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
public async Task OnReceiveAssociationReleaseRequestAsync()
|
||||
{
|
||||
await DataMaintenanceAsaync();
|
||||
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||
|
||||
var @lock = _distributedLockProvider.CreateLock($"{_upload.CallingAE}");
|
||||
|
||||
using (await @lock.AcquireAsync())
|
||||
{
|
||||
|
||||
await DataMaintenanceAsaync();
|
||||
|
||||
//记录监控
|
||||
|
||||
await AddUploadLogAsync();
|
||||
|
||||
|
||||
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
|
||||
}
|
||||
|
||||
await SendAssociationReleaseResponseAsync();
|
||||
|
||||
}
|
||||
|
||||
private async Task AddUploadLogAsync()
|
||||
{
|
||||
//记录监控
|
||||
|
||||
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
||||
|
||||
_upload.EndTime = DateTime.Now;
|
||||
_upload.StudyCount = _SCPStudyIdList.Count;
|
||||
_upload.StudyCount = _ImageUploadList.Count;
|
||||
_upload.TrialId = _trialId;
|
||||
_upload.TrialSiteId = _trialSiteId;
|
||||
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||
_upload.UploadJsonStr = (new SCPImageLog() { UploadList = _ImageUploadList }).ToJsonStr();
|
||||
|
||||
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
|
||||
await SendAssociationReleaseResponseAsync();
|
||||
//可能是测试echo 导致记录了
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, _upload.FileCount > 0 ? true : false);
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +273,11 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
//await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
//记录日志
|
||||
await AddUploadLogAsync();
|
||||
}
|
||||
|
||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
||||
}
|
||||
@@ -259,17 +288,24 @@ namespace IRaCIS.Core.SCP.Service
|
||||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||
{
|
||||
|
||||
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID,string.Empty);
|
||||
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
|
||||
string seriesInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
|
||||
string sopInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
|
||||
string patientIdStr = request.Dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
|
||||
|
||||
if(studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||
if (studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||
{
|
||||
Log.Logger.Error($"接收数据读取StudyInstanceUID:{studyInstanceUid}、SeriesInstanceUID:{seriesInstanceUid}、SOPInstanceUID:{sopInstanceUid}有空 ");
|
||||
|
||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||
}
|
||||
|
||||
//确保来了影像集合存在
|
||||
if (!_ImageUploadList.Any(t => t.StudyInstanceUid == studyInstanceUid))
|
||||
{
|
||||
_ImageUploadList.Add(new ImageUploadInfo() { StudyInstanceUid = studyInstanceUid });
|
||||
}
|
||||
|
||||
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _trialId.ToString());
|
||||
@@ -288,11 +324,70 @@ namespace IRaCIS.Core.SCP.Service
|
||||
long fileSize = 0;
|
||||
try
|
||||
{
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
await request.File.SaveAsync(ms);
|
||||
|
||||
#region 1帧拆成多个固定大小的,方便移动端浏览
|
||||
|
||||
// 回到开头,读取 dicom
|
||||
ms.Position = 0;
|
||||
var dicomFile = DicomFile.Open(ms);
|
||||
|
||||
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||
var syntax = pixelData.Syntax;
|
||||
|
||||
// 每个 fragment 固定大小 (64KB 示例,可以自己调整)
|
||||
int fragmentSize = 20 * 1024;
|
||||
|
||||
if (syntax.IsEncapsulated)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 替换原 PixelData
|
||||
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||
|
||||
|
||||
// 重新保存 dicom 到流
|
||||
ms.SetLength(0);
|
||||
dicomFile.Save(ms);
|
||||
}
|
||||
|
||||
|
||||
ms.Position = 0;
|
||||
|
||||
#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
|
||||
|
||||
|
||||
//irc 从路径最后一截取Guid
|
||||
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
||||
|
||||
@@ -315,12 +410,8 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
try
|
||||
{
|
||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.File, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE,fileSize);
|
||||
|
||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
||||
{
|
||||
_SCPStudyIdList.Add(scpStudyId);
|
||||
}
|
||||
|
||||
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||
|
||||
@@ -349,12 +440,40 @@ namespace IRaCIS.Core.SCP.Service
|
||||
|
||||
|
||||
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++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ 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
|
||||
{
|
||||
@@ -52,8 +53,10 @@ namespace IRaCIS.Core.SCP.Service
|
||||
/// <param name="dataset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, 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;
|
||||
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
@@ -82,7 +85,7 @@ namespace IRaCIS.Core.SCP.Service
|
||||
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);
|
||||
|
||||
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||
if (findPatient == null && findStudy==null)
|
||||
if (findPatient == null /*&& findStudy==null*/)
|
||||
{
|
||||
isPatientNeedAdd = true;
|
||||
|
||||
@@ -151,6 +154,32 @@ namespace IRaCIS.Core.SCP.Service
|
||||
}
|
||||
|
||||
findPatient.LatestPushTime = DateTime.Now;
|
||||
findPatient.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
findPatient.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||
findPatient.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||
findPatient.PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty);
|
||||
|
||||
if (findPatient.PatientBirthDate.Length == 8)
|
||||
{
|
||||
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||||
|
||||
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||||
|
||||
int year = 0;
|
||||
|
||||
var canParse = int.TryParse(yearStr, out year);
|
||||
|
||||
if (canParse && year > 1900)
|
||||
{
|
||||
findPatient.PatientBirthDate = birthDateStr;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
findPatient.PatientBirthDate = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (findStudy == null)
|
||||
@@ -167,6 +196,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
TrialSiteId = trialSiteId,
|
||||
StudyInstanceUid = studyInstanceUid,
|
||||
StudyTime = studyTime,
|
||||
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||
|
||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
//ModalityForEdit = modalityForEdit,
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
@@ -188,6 +220,12 @@ namespace IRaCIS.Core.SCP.Service
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, 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,
|
||||
@@ -201,6 +239,19 @@ namespace IRaCIS.Core.SCP.Service
|
||||
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
findStudy.DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
|
||||
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
||||
findStudy.CalledAE = calledAE;
|
||||
findStudy.CallingAE = callingAE;
|
||||
findStudy.PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
findStudy.PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty);
|
||||
findStudy.PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty);
|
||||
findStudy.UpdateTime = DateTime.Now;
|
||||
|
||||
await _patientRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.PatientId, u => new SCPPatient() { LatestPushTime = DateTime.Now });
|
||||
}
|
||||
|
||||
|
||||
if (findSerice == null)
|
||||
@@ -218,6 +269,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
||||
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
||||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||||
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
@@ -233,13 +287,29 @@ namespace IRaCIS.Core.SCP.Service
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, 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
|
||||
};
|
||||
|
||||
++findStudy.SeriesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
findSerice.DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty);
|
||||
findSerice.DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty);
|
||||
findSerice.UpdateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
var transferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
|
||||
|
||||
var isEncapsulated = false;
|
||||
if (transferSyntaxUID.IsNotNullOrEmpty())
|
||||
{
|
||||
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
|
||||
}
|
||||
|
||||
if (findInstance == null)
|
||||
{
|
||||
@@ -271,6 +341,21 @@ namespace IRaCIS.Core.SCP.Service
|
||||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, 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,
|
||||
|
||||
FileSize= fileSize,
|
||||
@@ -280,6 +365,15 @@ namespace IRaCIS.Core.SCP.Service
|
||||
++findStudy.InstanceCount;
|
||||
++findSerice.InstanceCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
findInstance.SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
|
||||
findInstance.MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
|
||||
findInstance.TransferSytaxUID = transferSyntaxUID;
|
||||
findInstance.MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
|
||||
findInstance.IsEncapsulated = isEncapsulated;
|
||||
findInstance.UpdateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
if (isPatientNeedAdd)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
public interface IDicomArchiveService
|
||||
{
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE,long fileSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace IRaCIS.Api.Controllers
|
||||
var token = _tokenService.GetToken(new UserTokenInfo()
|
||||
{
|
||||
IdentityUserId = Guid.NewGuid(),
|
||||
UserName = "Share001",
|
||||
UserName = "ImageShare",
|
||||
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||
|
||||
});
|
||||
|
||||
@@ -273,6 +273,7 @@ namespace IRaCIS.Core.API.Controllers
|
||||
|
||||
public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
|
||||
public class OSSFileDTO
|
||||
{
|
||||
@@ -521,7 +522,17 @@ namespace IRaCIS.Core.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
|
||||
if (incommand.IsImageSegmentLabel == true)
|
||||
{
|
||||
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, ImageLabelNoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId.Value, FileType = item.FileType, FileSize = item.FileFize });
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -557,6 +568,7 @@ namespace IRaCIS.Core.API.Controllers
|
||||
/// 一致性核查 excel上传 支持三种格式
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <param name="isFullCheck"></param>
|
||||
/// <param name="oSSService"></param>
|
||||
/// <param name="_inspectionFileRepository"></param>
|
||||
/// <returns></returns>
|
||||
@@ -564,12 +576,14 @@ namespace IRaCIS.Core.API.Controllers
|
||||
[HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
|
||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||
|
||||
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||
public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId, bool isFullCheck, [FromServices] IOSSService oSSService, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||
{
|
||||
|
||||
var fileName = string.Empty;
|
||||
var templateFileStream = new MemoryStream();
|
||||
|
||||
var inspectionFileId = Guid.Empty;
|
||||
|
||||
await FileUploadToOSSAsync(async (realFileName, fileStream) =>
|
||||
{
|
||||
fileName = realFileName;
|
||||
@@ -586,7 +600,9 @@ namespace IRaCIS.Core.API.Controllers
|
||||
|
||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName);
|
||||
|
||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||
var addEntity = await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||
|
||||
inspectionFileId = addEntity.Id;
|
||||
|
||||
return ossRelativePath;
|
||||
|
||||
@@ -732,8 +748,11 @@ namespace IRaCIS.Core.API.Controllers
|
||||
|
||||
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"]);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -753,6 +772,8 @@ namespace IRaCIS.Core.API.Controllers
|
||||
|
||||
if (etcCheckList.Count == 0)
|
||||
{
|
||||
await _inspectionFileRepository.BatchUpdateNoTrackingAsync(t => t.Id == inspectionFileId, u => new InspectionFile() { CheckState = EDCCheckState.Failed });
|
||||
|
||||
//---请保证上传数据符合模板文件中的样式,且存在有效数据。
|
||||
return ResponseOutput.NotOk(_localizer["UploadDownLoad_InvalidData"]);
|
||||
}
|
||||
@@ -764,8 +785,19 @@ namespace IRaCIS.Core.API.Controllers
|
||||
//var client = _mediator.CreateRequestClient<ConsistenCheckCommand>();
|
||||
//await client.GetResponse<ConsistenCheckResult>(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
||||
|
||||
//不获取结果,不用定义返回类型
|
||||
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
||||
if (isFullCheck)
|
||||
{
|
||||
await _mediator.Send(new ConsistenFullCheckCommand() { ETCList = etcCheckList, TrialId = trialId, InspectionFileId = inspectionFileId });
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//不获取结果,不用定义返回类型
|
||||
await _mediator.Send(new ConsistenCheckCommand() { ETCList = etcCheckList, TrialId = trialId });
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
@@ -972,7 +1004,11 @@ namespace IRaCIS.Core.API.Controllers
|
||||
|
||||
EmailBodyHtml = 4,
|
||||
|
||||
Other = 5
|
||||
ReadKeyFile = 5,
|
||||
|
||||
Other = 6,
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1004,6 +1040,9 @@ namespace IRaCIS.Core.API.Controllers
|
||||
case UploadFileType.EmailBodyHtml:
|
||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
|
||||
break;
|
||||
case UploadFileType.ReadKeyFile:
|
||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.ReadKetFile, fileName));
|
||||
break;
|
||||
|
||||
default:
|
||||
result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));
|
||||
|
||||
@@ -56,7 +56,7 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 项目手动选择,周期性邮件
|
||||
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 })
|
||||
.ToListAsync();
|
||||
|
||||
@@ -318,11 +318,12 @@
|
||||
<param name="_noneDicomStudyFileRepository"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<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})">
|
||||
<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})">
|
||||
<summary>
|
||||
一致性核查 excel上传 支持三种格式
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<param name="isFullCheck"></param>
|
||||
<param name="oSSService"></param>
|
||||
<param name="_inspectionFileRepository"></param>
|
||||
<returns></returns>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using IRaCIS.Core.API;
|
||||
using IRaCIS.Core.API.HostService;
|
||||
using IRaCIS.Core.Application.BusinessFilter;
|
||||
using IRaCIS.Core.Application.BusinessFilter.LegacyController.Database.Api;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
using IRaCIS.Core.Application.Service;
|
||||
@@ -100,6 +101,7 @@ builder.Services.AddControllers(options =>
|
||||
options.Filters.Add<UnitOfWorkFilter>();
|
||||
options.Filters.Add<LimitUserRequestAuthorization>();
|
||||
options.Filters.Add<TrialGlobalLimitActionFilter>();
|
||||
options.Filters.Add<RequestDuplicationFilter>();
|
||||
|
||||
})
|
||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -126,6 +126,51 @@ namespace IRaCIS.Core.API
|
||||
}
|
||||
|
||||
|
||||
public class DateOnlyUniversalJsonConverter : JsonConverter
|
||||
{
|
||||
private readonly string _format;
|
||||
|
||||
public DateOnlyUniversalJsonConverter(string format = "yyyy-MM-dd")
|
||||
{
|
||||
_format = format;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(DateOnly) || objectType == typeof(DateOnly?);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteValue(""); // null -> 空字符串
|
||||
return;
|
||||
}
|
||||
|
||||
var date = (DateOnly)value;
|
||||
if (date == default)
|
||||
{
|
||||
writer.WriteValue(""); // default(DateOnly) -> 空字符串
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteValue(date.ToString(_format));
|
||||
}
|
||||
}
|
||||
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var str = reader.TokenType == JsonToken.Null ? null : reader.Value?.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str) || !DateOnly.TryParse(str, out var date))
|
||||
{
|
||||
return objectType == typeof(DateOnly?) ? null : default(DateOnly);
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
#region 废弃
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ namespace IRaCIS.Core.API
|
||||
//必须放在后面
|
||||
options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
|
||||
|
||||
//options.SerializerSettings.Converters.Add(new DateOnlyUniversalJsonConverter("yyyy-MM-dd"));
|
||||
|
||||
|
||||
})
|
||||
.AddControllersAsServices()//动态webApi属性注入需要
|
||||
|
||||
@@ -28,12 +28,13 @@ public static class ServiceCollectionSetup
|
||||
services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||||
services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||
services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
|
||||
services.AddOptions().Configure<RequestDuplicationOptions>(_configuration.GetSection("RequestDuplicationOptions"));
|
||||
services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));
|
||||
services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));
|
||||
|
||||
services.Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
|
||||
|
||||
//转发头设置 获取真实IP
|
||||
//ת��ͷ���� ��ȡ��ʵIP
|
||||
services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders =
|
||||
@@ -51,7 +52,7 @@ public static class ServiceCollectionSetup
|
||||
|
||||
services.AddScoped<IObtainTaskAutoCancelJob, ObtainTaskAutoCancelJob>();
|
||||
|
||||
// 注册以Service 结尾的服务
|
||||
// ע����Service ��β�ķ���
|
||||
services.Scan(scan => scan
|
||||
.FromAssemblies(typeof(BaseService).Assembly)
|
||||
.AddClasses(classes => classes.Where(t => t.Name.Contains("Service")))
|
||||
@@ -70,23 +71,23 @@ public static class ServiceCollectionSetup
|
||||
#endregion
|
||||
|
||||
|
||||
// MediatR 进程内消息 事件解耦 从程序集中 注册命令和handler对应关系
|
||||
// MediatR ��������Ϣ �¼����� �ӳ����� ע�������handler��Ӧ��ϵ
|
||||
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());
|
||||
|
||||
|
||||
|
||||
#region 历史废弃配置
|
||||
#region ��ʷ��������
|
||||
//builder.Services.AddMemoryCache();
|
||||
////上传限制 配置
|
||||
////�ϴ����� ����
|
||||
//builder.Services.Configure<FormOptions>(options =>
|
||||
//{
|
||||
// options.MultipartBodyLengthLimit = int.MaxValue;
|
||||
// options.ValueCountLimit = int.MaxValue;
|
||||
// options.ValueLengthLimit = int.MaxValue;
|
||||
//});
|
||||
//IP 限流 可设置白名单 或者黑名单
|
||||
//IP ���� �����ð����� ���ߺ�����
|
||||
//services.AddIpPolicyRateLimitSetup(_configuration);
|
||||
// 用户类型 策略授权
|
||||
// �û����� ������Ȩ
|
||||
//services.AddAuthorizationPolicySetup(_configuration);
|
||||
#endregion
|
||||
}
|
||||
@@ -94,25 +95,25 @@ public static class ServiceCollectionSetup
|
||||
|
||||
}
|
||||
|
||||
#region Autofac 废弃
|
||||
#region Autofac ����
|
||||
//public class AutofacModuleSetup : Autofac.Module
|
||||
//{
|
||||
// protected override void Load(ContainerBuilder containerBuilder)
|
||||
// {
|
||||
|
||||
// #region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
|
||||
// #region byzhouhang 20210917 �˴�ע�᷺�Ͳִ� ���Լ���Domain�� ��Infra.EFcore ���� �յIJִ��ӿڶ���� �ִ��ļ�����
|
||||
|
||||
// containerBuilder.RegisterGeneric(typeof(Repository<>))
|
||||
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
|
||||
// .As(typeof(IRepository<>)).InstancePerLifetimeScope();//ע�᷺�Ͳִ�
|
||||
|
||||
// containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
// #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)
|
||||
// .Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
||||
// .PropertiesAutowired();
|
||||
@@ -128,7 +129,7 @@ public static class ServiceCollectionSetup
|
||||
// //containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
// //注册hangfire任务 依赖注入
|
||||
// //ע��hangfire���� ����ע��
|
||||
// containerBuilder.RegisterType<ObtainTaskAutoCancelJob>().As<IObtainTaskAutoCancelJob>().InstancePerDependency();
|
||||
|
||||
// }
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
"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",
|
||||
"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
|
||||
},
|
||||
@@ -55,11 +55,14 @@
|
||||
"ChangePassWordDays": 90,
|
||||
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 2
|
||||
"TemplateType": 2,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
},
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"Imap": "imap.qiye.aliyun.com",
|
||||
"FromEmail": "uat@extimaging.com",
|
||||
"FromName": "UAT_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
@@ -69,7 +72,13 @@
|
||||
"CompanyShortName": "Extensive Imaging",
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -53,12 +53,15 @@
|
||||
"IsNeedChangePassWord": true,
|
||||
"ChangePassWordDays": 90,
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 2
|
||||
"TemplateType": 2,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"Imap": "imap.qiye.aliyun.com",
|
||||
"FromEmail": "irc@extimaging.com",
|
||||
"FromName": "IRC Imaging System",
|
||||
"AuthorizationCode": "ExtImg@2022",
|
||||
@@ -78,6 +81,12 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "11113",
|
||||
"IP": "101.132.193.237"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -115,7 +115,9 @@
|
||||
// 是否打开项目关联删除
|
||||
"OpenTrialRelationDelete": true,
|
||||
// 转换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": {
|
||||
@@ -123,6 +125,8 @@
|
||||
"Port": 465,
|
||||
// 企业邮箱SMTP服务器地址
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
|
||||
"Imap": "imap.qiye.aliyun.com",
|
||||
// 发件人邮箱地址
|
||||
"FromEmail": "test@extimaging.com",
|
||||
// 发件人显示名称
|
||||
@@ -160,5 +164,16 @@
|
||||
"Port": "11113",
|
||||
// PACS服务器IP地址
|
||||
"IP": "106.14.89.110"
|
||||
},
|
||||
// 重复请求配置
|
||||
"RequestDuplicationOptions": {
|
||||
// 是否启用重复请求检测
|
||||
"IsEnabled": true,
|
||||
// 重复请求时间窗口(毫秒)
|
||||
"DuplicationWindowMs": 200,
|
||||
// 缓存请求时间(秒)
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"Imap": "imap.qiye.aliyun.com",
|
||||
"FromEmail": "test@extimaging.com",
|
||||
"FromName": "Test_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
@@ -91,5 +92,12 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "11113",
|
||||
"IP": "106.14.89.110"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,13 +57,16 @@
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 1,
|
||||
|
||||
"OpenTrialRelationDelete": false
|
||||
"OpenTrialRelationDelete": false,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"Imap": "imap-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
@@ -85,6 +88,13 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "44.210.231.169"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,12 +66,15 @@
|
||||
"ChangePassWordDays": 90,
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 1,
|
||||
"OpenLoginMFA": true
|
||||
"OpenLoginMFA": true,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"Imap": "imap-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
@@ -92,6 +95,13 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "3.226.182.187"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,12 +65,15 @@
|
||||
"IsNeedChangePassWord": true,
|
||||
"ChangePassWordDays": 90,
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 1
|
||||
"TemplateType": 1,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"Imap": "imap-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
@@ -92,6 +95,12 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "104",
|
||||
"IP": "3.226.182.187"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,12 +72,15 @@
|
||||
"IsNeedChangePassWord": true,
|
||||
"ChangePassWordDays": 90,
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 2
|
||||
"TemplateType": 2,
|
||||
//MFA免验证发送天数
|
||||
"UserMFAVerifyDays": 1
|
||||
|
||||
},
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"Imap": "imap.qiye.aliyun.com",
|
||||
"FromEmail": "uat@extimaging.com",
|
||||
"FromName": "Uat IRC Imaging System",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
@@ -99,6 +102,13 @@
|
||||
"SystemPacsConfig": {
|
||||
"Port": "11113",
|
||||
"IP": "101.132.253.119"
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,5 +74,12 @@
|
||||
"redirect_uri": "https://oauthlogin.net/oauth/githubcallback",
|
||||
"scope": "repo"
|
||||
}
|
||||
},
|
||||
"RequestDuplicationOptions": {
|
||||
"IsEnabled": true,
|
||||
"DuplicationWindowMs": 200,
|
||||
"CacheTimeSeconds": 5,
|
||||
"ExcludedPaths": [
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ public class ServiceVerifyConfigOption
|
||||
|
||||
public string ThirdPdfUrl { get; set; }
|
||||
|
||||
public int UserMFAVerifyMinutes { get; set; } = 1440;
|
||||
|
||||
}
|
||||
|
||||
public class SystemEmailSendConfig
|
||||
@@ -45,6 +47,8 @@ public class SystemEmailSendConfig
|
||||
public int Port { get; set; }
|
||||
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
public string Imap { get; set; } = string.Empty;
|
||||
public string FromEmail { get; set; } = string.Empty;
|
||||
|
||||
public string FromName { get; set; } = string.Empty;
|
||||
@@ -53,7 +57,7 @@ public class SystemEmailSendConfig
|
||||
|
||||
public string SiteUrl { get; set; } = string.Empty;
|
||||
|
||||
public string SystemShortName { get; set; } = string.Empty;
|
||||
public string SystemShortName { get; set; } = string.Empty;
|
||||
|
||||
public string OrganizationName { get; set; } = string.Empty;
|
||||
public string OrganizationNameCN { get; set; } = string.Empty;
|
||||
@@ -72,12 +76,12 @@ public class SystemEmailSendConfig
|
||||
|
||||
public string EmailRegexStr { get; set; }
|
||||
|
||||
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
|
||||
public List<string> ErrorNoticeEmailList { get; set; } = new List<string>();
|
||||
}
|
||||
|
||||
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 CompanyNameCN { get; set; } = string.Empty;
|
||||
@@ -105,6 +109,54 @@ public class IRCEncreptOption
|
||||
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 string DoctorCodePrefix { get; set; }
|
||||
|
||||
@@ -61,6 +61,9 @@ public static class CacheKeys
|
||||
/// <returns></returns>
|
||||
public static string StartRestTime(Guid userId) => $"{userId}StartRestTime";
|
||||
|
||||
//每个用户 每个浏览器独立时间
|
||||
public static string UserMFAVerifyPass(Guid userId,string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}";
|
||||
|
||||
}
|
||||
|
||||
public static class CacheHelper
|
||||
|
||||
@@ -42,6 +42,7 @@ public static class SendEmailHelper
|
||||
|
||||
await smtp.DisconnectAsync(true);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -54,6 +55,20 @@ public static class SendEmailHelper
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置发送邮箱
|
||||
/// </summary>
|
||||
/// <param name="messageToSend"></param>
|
||||
/// <param name="senderName"></param>
|
||||
public static void ChangeEmailSenderName(MimeMessage messageToSend, string senderName)
|
||||
{
|
||||
var fromAddress = messageToSend.From.Mailboxes.FirstOrDefault();
|
||||
if (fromAddress != null)
|
||||
{
|
||||
messageToSend.From.Clear();
|
||||
messageToSend.From.Add(new MailboxAddress(senderName, fromAddress.Address));
|
||||
}
|
||||
}
|
||||
public static async Task<bool> TestEmailConfigAsync(SystemEmailSendConfig _systemEmailConfig)
|
||||
{
|
||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
|
||||
|
||||
@@ -1038,6 +1038,34 @@ 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 memoryStream = new MemoryStream();
|
||||
|
||||
var config = new OpenXmlConfiguration()
|
||||
{
|
||||
IgnoreTemplateParameterMissing = true,
|
||||
};
|
||||
|
||||
await MiniExcel.SaveAsByTemplateAsync(memoryStream, tplPath, 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>
|
||||
@@ -1119,4 +1147,7 @@ public static class ExcelExportHelper
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -143,7 +143,7 @@ public enum ObjectStoreUse
|
||||
public interface IOSSService
|
||||
{
|
||||
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
|
||||
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
||||
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false);
|
||||
|
||||
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
||||
|
||||
@@ -294,7 +294,7 @@ public class OSSService : IOSSService
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
//token 过期了
|
||||
else if (AliyunOSSTempToken.Expiration.AddSeconds(10) <= DateTime.Now)
|
||||
if (AliyunOSSTempToken?.Expiration.AddSeconds(10) <= DateTime.Now)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
@@ -308,7 +308,7 @@ public class OSSService : IOSSService
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
//token 过期了
|
||||
else if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
|
||||
if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
@@ -322,9 +322,10 @@ public class OSSService : IOSSService
|
||||
/// <param name="localFilePath"></param>
|
||||
/// <param name="oosFolderPath"></param>
|
||||
/// <param name="isFileNameAddGuid"></param>
|
||||
/// <param name="randomFileName">随机文件名</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true, bool randomFileName = false)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
|
||||
@@ -332,6 +333,11 @@ public class OSSService : IOSSService
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
||||
|
||||
if (randomFileName)
|
||||
{
|
||||
var fileExtension = localFileName.Split(".").LastOrDefault();
|
||||
ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}.{fileExtension}";
|
||||
}
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
|
||||
@@ -41,11 +41,11 @@
|
||||
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
||||
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
|
||||
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
|
||||
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
|
||||
<PackageReference Include="DistributedLock.Redis" Version="1.1.0" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.3" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
|
||||
<PackageReference Include="MailKit" Version="4.11.0" />
|
||||
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
|
||||
@@ -53,7 +53,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||
<PackageReference Include="MimeKit" Version="4.11.0" />
|
||||
<PackageReference Include="MiniExcel" Version="1.41.2" />
|
||||
<PackageReference Include="Minio" Version="6.0.5" />
|
||||
<PackageReference Include="Minio" Version="6.0.3" />
|
||||
<PackageReference Include="MiniWord" Version="0.9.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
@@ -62,9 +62,8 @@
|
||||
<PackageReference Include="NPOI" Version="2.7.4" />
|
||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
|
||||
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -75,4 +74,8 @@
|
||||
<Folder Include="Service\MinimalApiService\CodeTemplate\FrontTemplate\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Service\TrialSiteUser\TrialStatService.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,21 @@
|
||||
using MiniExcelLibs.Attributes;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using MiniExcelLibs.Attributes;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
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 List<CheckViewModel> ETCList { get; set; } = new List<CheckViewModel>();
|
||||
@@ -17,13 +30,20 @@ namespace IRaCIS.Core.Application.MassTransit.Command
|
||||
|
||||
public class CheckDBModel : CheckViewModel
|
||||
{
|
||||
|
||||
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public Guid StudyId { 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; }
|
||||
}
|
||||
|
||||
|
||||
//[ExcelImporter(/*ImportResultFilter = typeof(ImportResultFilteTest),*/ IsLabelingError = true)]
|
||||
@@ -62,8 +82,13 @@ namespace IRaCIS.Core.Application.MassTransit.Command
|
||||
[ExcelColumnName("Modality")]
|
||||
public string Modality { get; set; } = string.Empty;
|
||||
|
||||
#region 全量一致性核查加入
|
||||
[DictionaryTranslateAttribute("Subject_Visit_Status")]
|
||||
public SubjectStatus SubjectStatus { get; set; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
|
||||
@@ -1,53 +1,49 @@
|
||||
using AutoMapper;
|
||||
using IRaCIS.Application.Contracts;
|
||||
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.Helper;
|
||||
using IRaCIS.Core.Application.MassTransit.Command;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.MassTransit.Consumer
|
||||
{
|
||||
public class ConsistencyCheckConsumer : IConsumer<ConsistenCheckCommand>
|
||||
public class ConsistencyCheckConsumer(
|
||||
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 IRepository<Dictionary> _dictionaryRepository;
|
||||
/// <summary>
|
||||
/// 构造函数注入
|
||||
/// </summary>
|
||||
private readonly SystemEmailSendConfig _systemEmailConfig = _systemEmailSendConfig.CurrentValue;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -67,8 +63,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));
|
||||
|
||||
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId && x.Subject.IsSubjectQuit == false &&
|
||||
(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 &&
|
||||
(x.CheckState == CheckStateEnum.ToCheck || x.CheckState == CheckStateEnum.CVIng);
|
||||
|
||||
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
||||
join subject in _subjectRepository.AsQueryable() on sv.SubjectId equals subject.Id
|
||||
@@ -117,7 +113,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -201,7 +197,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
||||
var dbExceptExcel = dbVisitStudyList.Except(etcVisitStudyList);
|
||||
|
||||
// excel 存在
|
||||
var excelExceptDB = etcVisitStudyList.Except(dbCheckList);
|
||||
var excelExceptDB = etcVisitStudyList.Except(dbVisitStudyList);
|
||||
|
||||
//ETC 和系统的完全一致 两者没有差别
|
||||
if (dbExceptExcel.Count() == 0 && excelExceptDB.Count() == 0)
|
||||
@@ -301,12 +297,167 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
||||
}
|
||||
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.AsQueryable() 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,
|
||||
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,
|
||||
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");
|
||||
|
||||
|
||||
//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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,8 +365,11 @@ public class ImageConsumer(
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
|
||||
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(inDto.EmailNoticeConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -500,6 +503,7 @@ public class ImageConsumer(
|
||||
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailNoticeConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ public class UrgentMedicalReviewAddedEventConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
|
||||
}
|
||||
@@ -235,7 +235,7 @@ public class UrgentIRRepliedMedicalReviewConsumer(
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ public class UrgentMIMRepliedMedicalReviewConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -462,7 +462,7 @@ public class UrgentIRApplyedReReadingConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public class UserSiteSurveySubmitedEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ public class SiteSurveySPMSubmitedEventConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ public class SiteSurverRejectedEventConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ public class CRCSubmitedAndQCToAuditEventConsumer(
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ public class CRCRepliedQCChallengeEventConsumer(
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -338,7 +338,7 @@ public class QCRepliedQCChallengeEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -438,7 +438,7 @@ public class CRCRepliedCheckChallengeEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -548,7 +548,7 @@ public class PMRepliedCheckChallengeEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -647,7 +647,7 @@ public class CheckStateChangedToAuditEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
@@ -756,7 +756,7 @@ public class QCClaimTaskEventConsumer(
|
||||
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
@@ -26,6 +27,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
public class UrgentIRUnReadTaskRecurringEventConsumer(
|
||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigrepository,
|
||||
@@ -38,6 +40,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||
var trialId = context.Message.TrialId;
|
||||
|
||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
|
||||
var scenario = EmailBusinessScenario.ExpeditedReading;
|
||||
var trialEmailConfig = _trialEmailNoticeConfigrepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||
|
||||
@@ -160,7 +163,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
};
|
||||
|
||||
await CommonEmailHelper.GetTrialEmailSubejctAndHtmlInfoAndBuildAsync(trialEmailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
|
||||
//处理标记已通知的任务
|
||||
|
||||
@@ -14,7 +14,7 @@ using System.Threading.Tasks;
|
||||
namespace IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
|
||||
|
||||
|
||||
//项目手动选择 周期性邮件
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
if (emailConfig != null)
|
||||
{
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using MassTransit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -57,17 +58,15 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
|
||||
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
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id == trialIdentityUser.IdentityUserId &&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
|
||||
on trialIdentityUser.IdentityUserId equals identityUser.Id
|
||||
|
||||
|
||||
join confirm in _trialDocConfirmedUserRepository.Where() on
|
||||
new { trialIdentityUser.IdentityUserId, TrialDocumentId = trialDoc.Id } equals new { IdentityUserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
|
||||
|
||||
from confirm in cc.DefaultIfEmpty()
|
||||
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted && trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
|
||||
select new TrialSignDocView()
|
||||
{
|
||||
TrialCode = trialDoc.Trial.TrialCode,
|
||||
@@ -138,7 +137,7 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
if (emailConfig != null)
|
||||
{
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
@@ -191,12 +190,10 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
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 trialUserRole in _trialUserRoleRepository.Where(x => x.IsDeleted == false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id == trialIdentityUser.IdentityUserId &&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => context.Message.NewUserTypeIds.Contains(t.UserTypeId) &&
|
||||
trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
|
||||
on trialIdentityUser.IdentityUserId equals identityUser.Id
|
||||
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted && context.Message.NewUserTypeIds.Contains(ur.UserRole.UserTypeId) && trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
|
||||
|
||||
select new UnionDocumentWithConfirmInfoView()
|
||||
{
|
||||
IsSystemDoc = true,
|
||||
@@ -222,11 +219,11 @@ namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
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 trialUserRole in _trialUserRoleRepository.Where(x=>x.IsDeleted==false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id== trialIdentityUser.IdentityUserId&&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
join identityUser in _identityUserRepository.AsQueryable(false).Where(u => u.Status == UserStateEnum.Enable)
|
||||
on trialIdentityUser.IdentityUserId equals identityUser.Id
|
||||
where trialIdentityUser.TrialUserRoleList.Any(ur => !ur.IsDeleted &&trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == ur.UserRole.UserTypeId))
|
||||
|
||||
|
||||
select new UnionDocumentWithConfirmInfoView()
|
||||
{
|
||||
IsSystemDoc = false,
|
||||
|
||||
@@ -490,6 +490,8 @@ namespace IRaCIS.Core.Application.ViewModel
|
||||
|
||||
public int? RandomOrder { get; set; }
|
||||
public bool? IsRandomOrderList { get; set; }
|
||||
|
||||
public CriterionType? CriterionType { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由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 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 class ResendEmailInDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -159,6 +159,12 @@ namespace IRaCIS.Core.Application.ViewModel
|
||||
public class FrontAuditConfigAddOrEdit
|
||||
{
|
||||
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 ValueCN { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
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
|
||||
//{
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,695 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-10-28 06:22:42Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
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 IdentityModel.Client;
|
||||
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 System.IO;
|
||||
using System.Linq;
|
||||
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<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<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
|
||||
{
|
||||
client.Connect(_systemEmailConfig.Imap, 993, SecureSocketOptions.SslOnConnect);
|
||||
AuthenticateImap(client);
|
||||
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); // 让方法自己在文件名前加 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
|
||||
{
|
||||
client.Connect(_systemEmailConfig.Imap, 993, SecureSocketOptions.SslOnConnect);
|
||||
AuthenticateImap(client);
|
||||
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();
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步邮件
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> SynchronizationEmail()
|
||||
{
|
||||
|
||||
var maxTime=await _emailLogRepository.MaxAsync(t => t.EmailDate);
|
||||
|
||||
List<EmailLog> emailList = new List<EmailLog>();
|
||||
List<EmailRecipientLog> EmailRecipientLogList = new List<EmailRecipientLog>();
|
||||
|
||||
using (var client = new ImapClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Connect(_systemEmailConfig.Imap, 993, SecureSocketOptions.SslOnConnect);
|
||||
AuthenticateImap(client);
|
||||
var sentFolder = OpenSentFolder(client);
|
||||
|
||||
var startDate = maxTime ?? DateTime.MinValue;
|
||||
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);
|
||||
// var emailView = ConvertToEmailLogView(uid, message);
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.Disconnect(true);
|
||||
}
|
||||
|
||||
await _emailLogRepository.AddRangeAsync(emailList);
|
||||
await _emailRecipientLogRepository.AddRangeAsync(EmailRecipientLogList);
|
||||
await _emailLogRepository.SaveChangesAsync();
|
||||
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 void AuthenticateImap(ImapClient client)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Authenticate(_systemEmailConfig.FromEmail, _systemEmailConfig.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;
|
||||
}
|
||||
}
|
||||
|
||||
//private string AcquireOAuth2TokenByPassword()
|
||||
//{
|
||||
// if (_systemEmailConfig.OAuthTenantId.IsNullOrEmpty() || _systemEmailConfig.OAuthClientId.IsNullOrEmpty())
|
||||
// return string.Empty;
|
||||
|
||||
// using var http = new HttpClient();
|
||||
// var req = new PasswordTokenRequest
|
||||
// {
|
||||
// Address = $"https://login.microsoftonline.com/{_systemEmailConfig.OAuthTenantId}/oauth2/v2.0/token",
|
||||
// ClientId = _systemEmailConfig.OAuthClientId,
|
||||
// ClientSecret = _systemEmailConfig.OAuthClientSecret,
|
||||
// Scope = "offline_access https://outlook.office365.com/IMAP.AccessAsUser.All",
|
||||
// UserName = _systemEmailConfig.FromEmail,
|
||||
// Password = _systemEmailConfig.AuthorizationCode
|
||||
// };
|
||||
// var resp = http.RequestPasswordTokenAsync(req).GetAwaiter().GetResult();
|
||||
// if (resp.IsError || resp.AccessToken.IsNullOrEmpty())
|
||||
// return string.Empty;
|
||||
// return resp.AccessToken;
|
||||
//}
|
||||
|
||||
// 取skip的值
|
||||
public int CalcReverseSkip(int pageIndex, int pageSize, int totalCount)
|
||||
{
|
||||
|
||||
int lastPageFullSkip = totalCount / pageSize * pageSize; // 最后一页“整页”起点
|
||||
int skip = lastPageFullSkip - pageIndex * pageSize; // 倒着减
|
||||
return Math.Max(skip, 0); // 防止负值
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮件筛选条件构建
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
private SearchQuery BuildSearchQuery(EmailLogQuery query)
|
||||
{
|
||||
var searchQuery = SearchQuery.All;
|
||||
|
||||
// 日期范围筛选
|
||||
if (query.EmailStartDate.HasValue || query.EmailEndDate.HasValue)
|
||||
{
|
||||
var startDate = query.EmailStartDate ?? DateTime.MinValue;
|
||||
var endDate = query.EmailEndDate ?? DateTime.MaxValue;
|
||||
|
||||
searchQuery = searchQuery.And(SearchQuery.DeliveredAfter(startDate)
|
||||
.And(SearchQuery.DeliveredBefore(endDate.AddDays(1)))); // 包含结束日期当天
|
||||
}
|
||||
|
||||
// 主题关键词筛选(如果IMAP服务器支持)
|
||||
if (!string.IsNullOrEmpty(query.ToRecipientName))
|
||||
{
|
||||
searchQuery = searchQuery.And(SearchQuery.HeaderContains("To", query.ToRecipientName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(query.CcRecipientName))
|
||||
{
|
||||
searchQuery = searchQuery.And(SearchQuery.HeaderContains("Cc", query.CcRecipientName));
|
||||
}
|
||||
|
||||
return searchQuery;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 邮件排序处理
|
||||
/// </summary>
|
||||
/// <param name="sentFolder"></param>
|
||||
/// <param name="uids"></param>
|
||||
/// <returns></returns>
|
||||
private List<EmailLogView> GetEmailsWithSorting(IMailFolder sentFolder, IList<UniqueId> uids)
|
||||
{
|
||||
var emailList = new List<EmailLogView>();
|
||||
|
||||
|
||||
|
||||
// 获取完整的邮件信息
|
||||
foreach (var uid in uids)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = sentFolder.GetMessage(uid);
|
||||
var emailView = ConvertToEmailLogView(uid, message);
|
||||
emailList.Add(emailView);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"处理邮件 {uid} 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return emailList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取完整的邮件信息
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
private EmailLogView ConvertToEmailLogView(UniqueId uid, MimeMessage message)
|
||||
{
|
||||
string saveFolder = @"D:\MailAttachments";
|
||||
Directory.CreateDirectory(saveFolder);
|
||||
var emailView = new EmailLogView
|
||||
{
|
||||
UniqueId = uid.ToString(),
|
||||
MessageId = message.MessageId ?? string.Empty,
|
||||
EmailSubject = message.Subject ?? string.Empty,
|
||||
EmailDate = message.Date.UtcDateTime,
|
||||
Content = message.HtmlBody ?? string.Empty,
|
||||
};
|
||||
|
||||
var toHeader = message.Headers[HeaderId.To]; // 原始头,未解码
|
||||
Console.WriteLine($"原始To头 = |{toHeader}|");
|
||||
|
||||
foreach (var att in message.Attachments)
|
||||
{
|
||||
// att 可能是 MimePart 或 MessagePart
|
||||
if (att is MimePart part && !string.IsNullOrEmpty(part.FileName))
|
||||
{
|
||||
var file = Path.Combine(saveFolder, part.FileName);
|
||||
using (var stream = File.Create(file))
|
||||
part.Content.DecodeTo(stream);
|
||||
Console.WriteLine($" 附件已保存:{file}");
|
||||
}
|
||||
}
|
||||
|
||||
// 处理发件人信息
|
||||
var fromMailbox = message.From.Mailboxes.FirstOrDefault();
|
||||
if (fromMailbox != null)
|
||||
{
|
||||
emailView.SenderAddress = fromMailbox.Address;
|
||||
emailView.SenderName = fromMailbox.Name ?? string.Empty;
|
||||
}
|
||||
|
||||
//// 处理收件人
|
||||
//emailView.ToRecipients = message.To.Mailboxes.Select(address => new EmaliSendInfo
|
||||
//{
|
||||
// Name = address.Name ?? string.Empty,
|
||||
// Address = address.Address
|
||||
//}).ToList();
|
||||
|
||||
//// 处理抄送人
|
||||
//emailView.CcRecipients = message.Cc.Mailboxes.Select(address => new EmaliSendInfo
|
||||
//{
|
||||
// Name = address.Name ?? string.Empty,
|
||||
// Address = address.Address
|
||||
//}).ToList();
|
||||
|
||||
//// 处理密送人
|
||||
//emailView.BccRecipients = message.Bcc.Mailboxes.Select(address => new EmaliSendInfo
|
||||
//{
|
||||
// Name = address.Name ?? string.Empty,
|
||||
// Address = address.Address
|
||||
//}).ToList();
|
||||
|
||||
// 处理附件
|
||||
//emailView.Attachments = ProcessAttachments(message);
|
||||
//emailView.HasAttachments = emailView.Attachments.Any();
|
||||
//emailView.AttachmentCount = emailView.Attachments.Count;
|
||||
|
||||
return emailView;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 处理附件信息
|
||||
///// </summary>
|
||||
///// <param name="message"></param>
|
||||
///// <returns></returns>
|
||||
//private List<EmailAttachmentInfo> ProcessAttachments(MimeMessage message)
|
||||
//{
|
||||
// var attachments = new List<EmailAttachmentInfo>();
|
||||
|
||||
// foreach (var attachment in message.Attachments)
|
||||
// {
|
||||
// var attachmentInfo = new EmailAttachmentInfo();
|
||||
|
||||
// if (attachment is MimePart mimePart)
|
||||
// {
|
||||
// attachmentInfo.FileName = mimePart.FileName ??
|
||||
// mimePart.ContentType?.Name ??
|
||||
// "未知文件";
|
||||
// attachmentInfo.ContentType = mimePart.ContentType.MimeType;
|
||||
// attachmentInfo.ContentId = mimePart.ContentId ?? string.Empty;
|
||||
// attachmentInfo.IsInline = mimePart.ContentDisposition != null &&
|
||||
// mimePart.ContentDisposition.Disposition.Equals("inline", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// // 获取附件大小
|
||||
// try
|
||||
// {
|
||||
// if (mimePart.ContentObject.Stream != null)
|
||||
// {
|
||||
// attachmentInfo.Size = mimePart.ContentObject.Stream.Length;
|
||||
// }
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// attachmentInfo.Size = 0;
|
||||
// }
|
||||
// }
|
||||
// else if (attachment is MessagePart messagePart)
|
||||
// {
|
||||
// // 处理内嵌消息作为附件的情况
|
||||
// attachmentInfo.FileName = "embedded-message.eml";
|
||||
// attachmentInfo.ContentType = "message/rfc822";
|
||||
// attachmentInfo.IsInline = false;
|
||||
// }
|
||||
|
||||
// attachments.Add(attachmentInfo);
|
||||
// }
|
||||
|
||||
// return attachments;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 应用内存中的过滤条件(对于无法通过IMAP搜索的条件)
|
||||
/// </summary>
|
||||
/// <param name="emails"></param>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
private List<EmailLogView> ApplyMemoryFilters(List<EmailLogView> emails, EmailLogQuery query)
|
||||
{
|
||||
var filtered = emails.AsEnumerable();
|
||||
|
||||
// 收件人姓名筛选
|
||||
//if (!string.IsNullOrEmpty(query.Keyword))
|
||||
//{
|
||||
// filtered = filtered.Where(e =>
|
||||
// e.ToRecipients.Any(r =>
|
||||
// r.Name.Contains(query.Keyword, StringComparison.OrdinalIgnoreCase)) ||
|
||||
// e.CcRecipients.Any(r =>
|
||||
// r.Name.Contains(query.Keyword, StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
// );
|
||||
//}
|
||||
|
||||
// 发件人姓名筛选
|
||||
//if (!string.IsNullOrEmpty(query.SenderName))
|
||||
//{
|
||||
// filtered = filtered.Where(e =>
|
||||
// e.SenderName.Contains(query.SenderName, StringComparison.OrdinalIgnoreCase));
|
||||
//}
|
||||
|
||||
return filtered.ToList();
|
||||
}
|
||||
|
||||
|
||||
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,9 +4,18 @@
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using MailKit;
|
||||
using MailKit.Net.Imap;
|
||||
using MailKit.Search;
|
||||
using MailKit.Security;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@@ -17,8 +26,75 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "Common")]
|
||||
public class EmailNoticeConfigService(IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||
IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IEmailNoticeConfigService
|
||||
IRepository<EmailNoticeUserType> _emailNoticeUserTypeRepository,
|
||||
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]
|
||||
public async Task<PageOutput<EmailNoticeConfigView>> GetEmailNoticeConfigList(EmailNoticeConfigQuery inQuery)
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
QuestionAnswerList = g.Select(t => new QCQuestionAnswerExport() { Answer = t.Answer, QuestionName = t.QuesitonName, ShowOrder = t.ShowOrder, QuestionId = t.QuestionId }).OrderBy(t => t.ShowOrder).ToList()
|
||||
|
||||
|
||||
}).OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ThenBy(t=>t.CurrentQCEnum).ThenBy(t=>t.AuditTime).ToList();
|
||||
}).OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ThenBy(t => t.CurrentQCEnum).ThenBy(t => t.AuditTime).ToList();
|
||||
|
||||
|
||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
@@ -2597,13 +2597,19 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
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)
|
||||
{
|
||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
|
||||
}
|
||||
//else if (criterion.CriterionType == CriterionType.SelfDefine)
|
||||
|
||||
if (criterion.CriterionGroup != CriterionGroup.Tumor)
|
||||
{
|
||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.CDISC_Reading_Export, ExportCatogory = ExportResult.CDISC });
|
||||
list.Add(new ExportDocumentDes() { Code = StaticData.Export.CDISC_Reading_Export, ExportCatogory = ExportResult.NoneTumorCDISC });
|
||||
}
|
||||
|
||||
switch (criterion.ArbitrationRule)
|
||||
@@ -2784,7 +2790,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
}
|
||||
// 非肿瘤标准 包括自定义,以及系统非肿瘤 会配置到表格层级 问题名称是 表格名称_表格子问题名
|
||||
else if (
|
||||
criterion.CriterionGroup == CriterionGroup.Nontumorous && inQuery.ReadingExportType != ExportResult.CDISC
|
||||
criterion.CriterionGroup == CriterionGroup.Nontumorous && inQuery.ReadingExportType != ExportResult.NoneTumorCDISC
|
||||
)
|
||||
{
|
||||
|
||||
@@ -2801,7 +2807,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
|
||||
}
|
||||
// CDISC 导出 只管到 外层问题层级 和阅片结果表是保持一致
|
||||
else if (inQuery.ReadingExportType == ExportResult.CDISC)
|
||||
else if (inQuery.ReadingExportType == ExportResult.NoneTumorCDISC)
|
||||
{
|
||||
|
||||
if (criterion.CriterionGroup == CriterionGroup.Tumor)
|
||||
@@ -2869,7 +2875,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
#endregion
|
||||
|
||||
|
||||
if (inQuery.ReadingExportType != ExportResult.CDISC)
|
||||
if (inQuery.ReadingExportType != ExportResult.NoneTumorCDISC)
|
||||
{
|
||||
//最终EXCEL 列
|
||||
var configCoumNameList = new List<DynamicColumnConfig.ColumItem>();
|
||||
@@ -2898,7 +2904,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
{
|
||||
#region 外层问题处理
|
||||
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
|
||||
{
|
||||
|
||||
fistLeveLNameList = trialConfigQuestionList.Select(t => new DynamicColumnConfig.ColumItem()
|
||||
@@ -2941,7 +2948,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
var extralNameList = new List<DynamicColumnConfig.ColumItem>();
|
||||
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC
|
||||
|| criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
|
||||
{
|
||||
|
||||
//if(inQuery.ReadingExportType == ExportResult.DetailedTableOfLesions)
|
||||
@@ -2982,7 +2990,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
var addLessionInfoList = new List<CommonQuesionInfo>();
|
||||
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC
|
||||
|| criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
|
||||
{
|
||||
//病灶编号 和病灶类型没有配置,但是需要有的
|
||||
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Lesion ID" : "病灶编号", QuestionValue = lession.LessionCode });
|
||||
@@ -3022,7 +3031,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
#endregion
|
||||
|
||||
#region 不管是list 还是taskList 最终处理的数据都是list 处理好数据后合并
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
|
||||
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|
||||
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
|
||||
{
|
||||
//针对1.1 整体肿瘤评估 有的两列要合并一列
|
||||
foreach (var item in list)
|
||||
@@ -3471,7 +3481,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
||||
|
||||
string fileName = "";
|
||||
|
||||
if (inQuery.ReadingExportType == ExportResult.CDISC)
|
||||
if (inQuery.ReadingExportType == ExportResult.NoneTumorCDISC)
|
||||
{
|
||||
(memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(export_Template, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(CommonEvaluationExport), criterion.CriterionType, dynamicColumnConfig);
|
||||
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.Common;
|
||||
|
||||
|
||||
public class TumorCommonQustionInfo
|
||||
{
|
||||
//问题标识,肿瘤评估用于区分是什么问题
|
||||
public QuestionType? QuestionType { get; set; }
|
||||
|
||||
public Guid QuestionId { get; set; }
|
||||
public string QuestionName { get; set; }
|
||||
|
||||
public string QuestionValue { get; set; }
|
||||
|
||||
public string TranslateDicName { get; set; }
|
||||
|
||||
public ValueUnit? Unit { get; set; }
|
||||
|
||||
public ValueOfType? ValueType { get; set; }
|
||||
}
|
||||
|
||||
public class TumorLessionInfo
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid? OrganInfoId { get; set; }
|
||||
//病灶编号
|
||||
public string LessionCode { get; set; }
|
||||
|
||||
public LesionType? LessionType { get; set; }
|
||||
|
||||
public Guid? SplitRowId { get; set; }
|
||||
|
||||
public string? DicomModality { get; set; }
|
||||
|
||||
public string? NoneDicomModality { get; set; }
|
||||
|
||||
//病灶答案
|
||||
public List<TumorLessionAnswerInfo> LessionAnswerList { get; set; }
|
||||
}
|
||||
|
||||
public class TumorLessionAnswerInfo
|
||||
{
|
||||
public QuestionMark? QuestionMark { get; set; }
|
||||
|
||||
//病灶Id
|
||||
public Guid RowId { get; set; }
|
||||
|
||||
//如果是4 就取CustomUnit 否则就是字典翻译
|
||||
[Comment("单位")]
|
||||
public ValueUnit? Unit { get; set; }
|
||||
|
||||
|
||||
public int ShowOrder { get; set; }
|
||||
|
||||
public Guid TableQuesionId { get; set; }
|
||||
|
||||
public string QuestionName { get; set; }
|
||||
|
||||
public string QuestionValue { get; set; }
|
||||
|
||||
public string TranslateDicName { get; set; }
|
||||
}
|
||||
|
||||
public class TumorGlobalQuestionAnserInfo
|
||||
{
|
||||
[Comment("原任务ID")]
|
||||
public Guid TaskId { get; set; }
|
||||
|
||||
public GlobalAnswerType GlobalAnswerType { get; set; }
|
||||
|
||||
[Comment("问题答案")]
|
||||
public string Answer { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class TumorExportBaseModel : TU_TR_RSBaseModel
|
||||
{
|
||||
public List<TumorLessionInfo> LesionList { get; set; } = new List<TumorLessionInfo>();
|
||||
|
||||
public List<TumorCommonQustionInfo> QuestionAnswerList { get; set; }
|
||||
|
||||
public List<TumorGlobalQuestionAnserInfo> GlobalResultList { get; set; }
|
||||
|
||||
#region 后续处理额外添加字段
|
||||
|
||||
|
||||
|
||||
public DateTime? JudgeSignTime { get; set; }
|
||||
|
||||
public Guid? SourceSubjectVisitId { get; set; }
|
||||
|
||||
public List<decimal> SubjectCriterionReadingPeriodVisitNumList { get; set; }
|
||||
|
||||
public decimal VisitTaskNum { get; set; }
|
||||
|
||||
public ReadingTaskState ReadingTaskState { get; set; }
|
||||
|
||||
public ReadingCategory ReadingCategory { get; set; }
|
||||
|
||||
//裁判结果选择的访视或者全局任务Id
|
||||
public Arm? JudgeArmEnum { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
//在当前访视触发裁判,或者在截止日期小于等于当前访视的阅片期触发裁判
|
||||
[DictionaryTranslateAttribute("YesOrNoAudit")]
|
||||
public bool? IsTrigerJudge { get; set; }
|
||||
|
||||
//(如果是访视点裁判,则仅在所选阅片人对应访视 显示;如果是阅片期裁判,则在所选阅片人 阅片期内的所有访视 显示此原因)
|
||||
public string JudgeNote { get; set; } = string.Empty;
|
||||
|
||||
public string VisitNote { get; set; }
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TU_TR_RSBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 方案编号 STUDYID
|
||||
/// </summary>
|
||||
public string ResearchProgramNo { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 域 DOMAIN TU TR RS
|
||||
/// </summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 取值类型 TUSPID TRSPID RSSPID
|
||||
/// </summary>
|
||||
public string ValueType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 受试者编号 USUBJID 实际展示TrialSiteSubjectCode
|
||||
/// </summary>
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 供应商 TUNAM (Extensive Imaging)
|
||||
/// </summary>
|
||||
public string Vendor { get; set; } = "Extensive Imaging";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 阅片人 TUEVAL TREVAL RSEVAL
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片人标识 TUEVALID TREVALID RSEVALID
|
||||
/// </summary>
|
||||
public Arm ArmEnum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访视编号 VISITNUM
|
||||
/// </summary>
|
||||
public decimal? VisitNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访视名称 VISIT
|
||||
/// </summary>
|
||||
public string? VisitName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 拍片日期 TUDTC TRDTC RSDTC
|
||||
/// </summary>
|
||||
public DateTime? LatestScanDate { get; set; }
|
||||
|
||||
public DateTime? EarliestScanDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// eCRF标识 TUREFID TRREFID RSREFID
|
||||
/// </summary>
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
|
||||
#region 移动位置
|
||||
|
||||
/// <summary>
|
||||
/// RSCAT 阅片标准
|
||||
/// </summary>
|
||||
public string CriterionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RSACPTFL 裁定标记 TUACPTFL
|
||||
/// </summary>
|
||||
//裁判选择标记
|
||||
//根据裁判的任务结果 设置访视任务的这个字段 该字段表示 裁判认同该任务的结果
|
||||
public bool? IsJudgeSelect { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public DateTime? SignTime { get; set; }
|
||||
|
||||
public string TaskName { get; set; }
|
||||
|
||||
#region 额外翻译字段
|
||||
|
||||
|
||||
|
||||
public string IsJudgeSelectStr => IsJudgeSelect == true ? "Y" : "";
|
||||
|
||||
public bool IsTargetPD { get; set; } = false;
|
||||
|
||||
public bool IsOverallResponsePD { get; set; } = false;
|
||||
|
||||
//TR表 靶病灶PD了,访视层级的都是最早拍片日期 RS表 整体肿瘤评估PD了,那么疗效评估的拍片日期都给最早的
|
||||
public bool IsPD => Domain == "TR" ? IsTargetPD : IsOverallResponsePD;
|
||||
|
||||
public string ArmEnumStr { get; set; }
|
||||
public string LatestScanDateStr
|
||||
{
|
||||
get
|
||||
{
|
||||
var date = IsPD ? EarliestScanDate : LatestScanDate;
|
||||
return date?.ToString("yyyy-MM-dd") ?? "";
|
||||
}
|
||||
}
|
||||
public string TrialSiteSubjectCode => ResearchProgramNo + SubjectCode;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public class TU_Export : TU_TR_RSBaseModel
|
||||
{
|
||||
|
||||
///// <summary>
|
||||
///// 取值类型 TUSPID
|
||||
///// </summary>
|
||||
//public string TUValueType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 序号 TUSEQ (同一个访视,所有阅片人选择病灶给个顺序号)
|
||||
/// </summary>
|
||||
public int No { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 链接ID TULNKID (阅片人角色_病灶编号)不同访视可以重复
|
||||
/// </summary>
|
||||
public string ARM_TumorNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤识别简称 TUTESTCD
|
||||
/// </summary>
|
||||
public string TumorIdentificationSimple { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤识别全称 TUTEST
|
||||
/// </summary>
|
||||
public string TumorIdentificationFullName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤鉴定结果 TUORRES
|
||||
/// </summary>
|
||||
public string TumorIdentificationResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤识别结果类型 TUSTRESC
|
||||
/// </summary>
|
||||
public string TumorIdentificationResultType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 部位 TULOC (对应病灶表的部位,需要国际化)
|
||||
/// </summary>
|
||||
public string BodyPart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 鉴定方法 TUMETHOD (Modality?)
|
||||
/// </summary>
|
||||
public string IdentificationMethod { get; set; }
|
||||
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// 裁定标记 TUACPTFL
|
||||
///// </summary>
|
||||
//public bool? IsJudgeSelect { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 部位描述 LOCTEXT
|
||||
/// </summary>
|
||||
public string BodyPartDes { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TR_Export : TU_TR_RSBaseModel
|
||||
{
|
||||
|
||||
///// <summary>
|
||||
///// 取值类型 TRSPID
|
||||
///// </summary>
|
||||
//public string TRValueType { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 每个subject 按照顺序编号 TRSEQ
|
||||
/// </summary>
|
||||
public int TRSEQ { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
///TRGRPID 组ID 对应TU表肿瘤鉴定结果 TumorIdentificationResult
|
||||
/// </summary>
|
||||
public string TRGRPID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// TRLNKID 链接ID 对应TU表的链接ID TumorNo(阅片人角色_病灶编号)
|
||||
/// </summary>
|
||||
public string ARM_TumorNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///TRLNKGRP 链接组 ARM-任务名(访视名) 对应RS的链接组
|
||||
/// </summary>
|
||||
public string ARM_VisitName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤评估简称 TRTESTCD
|
||||
/// </summary>
|
||||
public string TumorAssessmentSimpleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 肿瘤评估全称 TRTEST
|
||||
/// </summary>
|
||||
public string TumorAssessmentFullName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 原始测量 TRORRES
|
||||
/// </summary>
|
||||
public string OriginalMeasurements { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原始单位 TRORRESU
|
||||
/// </summary>
|
||||
public string OriginalUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标准结果(字符) TRSTRESC
|
||||
/// </summary>
|
||||
public string StandardResult_Character => OriginalMeasurements;
|
||||
|
||||
/// <summary>
|
||||
/// 标准结果(数值) TRORRESU
|
||||
/// </summary>
|
||||
public string StandardResult_Numeric => double.TryParse(OriginalMeasurements, out _) ||
|
||||
(OriginalMeasurements?.EndsWith("%") == true &&
|
||||
double.TryParse(OriginalMeasurements.TrimEnd('%'), out _))
|
||||
? OriginalMeasurements
|
||||
: "";
|
||||
|
||||
/// <summary>
|
||||
/// 标准单位 TRSTRESU
|
||||
/// </summary>
|
||||
public string StandardUnit => OriginalUnit;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 完成状态 TRSTAT
|
||||
/// </summary>
|
||||
public string CompletionStatus { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 完成状态 TRMETHOD
|
||||
/// </summary>
|
||||
public string IdentificationMethod { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 无法测量原因 TRREASND
|
||||
/// </summary>
|
||||
public string NotMeasuredReason { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class RS_Export : TU_TR_RSBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// RSSEQ 按照subject 的数据顺序编号
|
||||
/// </summary>
|
||||
public int RSSEQ { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RSLNKGRP 链接组 ARM_任务名(访视名)
|
||||
/// </summary>
|
||||
public string ARM_VisitName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RSTESTCD 疗效评估简称
|
||||
/// </summary>
|
||||
public string EfficacyEvaluationSimpleName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RSTEST 疗效评估全称
|
||||
/// </summary>
|
||||
public string EfficacyEvaluationName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RSORRES 响应评估原始结果
|
||||
/// </summary>
|
||||
public string RespondEfficacyAssessment { get; set; }
|
||||
/// <summary>
|
||||
/// RSSTRESC 标准疗效评估
|
||||
/// </summary>
|
||||
public string StandardEfficacyAssessment => RespondEfficacyAssessment;
|
||||
|
||||
/// <summary>
|
||||
/// RSSTAT 完成状态
|
||||
/// </summary>
|
||||
public string CompletionStatus { get; set; }
|
||||
/// <summary>
|
||||
/// RSREASND 无法评估原因
|
||||
/// </summary>
|
||||
public string NotAssessmentReason { get; set; }
|
||||
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// 裁定标记 RSACPTFL
|
||||
///// </summary>
|
||||
//public bool? IsJudgeSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// REASASM 评估原因
|
||||
/// </summary>
|
||||
public string AssessmentReason { get; set; }
|
||||
/// <summary>
|
||||
/// REASOVR 重新评估原因
|
||||
/// </summary>
|
||||
public string ReAssessmentReason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// REASUPD 更新评估原因
|
||||
/// </summary>
|
||||
public string UpdateAssessmentReason { get; set; }
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public bool? IsOveralResponse { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class CO_Export : TU_TR_RSBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 关联域 RS:(访视点备注) 空:裁判选择原因
|
||||
/// </summary>
|
||||
public string RDOMAIN { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COSEQ 序号
|
||||
/// </summary>
|
||||
public int COSEQ { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// IDVAR 标识变量 RSSEQ 空:裁判选择原因
|
||||
/// </summary>
|
||||
public string IdentificationVariable { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标识 IDVARVAL RSSEQ具体的值 空:裁判选择原因
|
||||
/// </summary>
|
||||
public string Identification { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// COREF 备注引用
|
||||
/// </summary>
|
||||
public string RemarksQuote { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注 COVAL
|
||||
/// </summary>
|
||||
public string Remarks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 裁决日期 CODTC
|
||||
/// </summary>
|
||||
public string CODTC { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由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);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,16 @@ using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using MailKit;
|
||||
using MailKit.Net.Imap;
|
||||
using MailKit.Search;
|
||||
using MailKit.Security;
|
||||
using Medallion.Threading;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using System.Net.Mail;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
@@ -70,8 +75,14 @@ namespace IRaCIS.Core.Application.Service
|
||||
Task<(Guid identityUserId, Guid userRoleId)> DoctorJoinTrialEmail(Guid trialId, Guid doctorId, string baseUrl, string rootUrl);
|
||||
|
||||
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,
|
||||
IRepository<SystemBasicData> _systemBasicDatarepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
@@ -86,12 +97,14 @@ namespace IRaCIS.Core.Application.Service
|
||||
IRepository<UserType> _userTypeRepository,
|
||||
IRepository<Doctor> _doctorTypeRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
|
||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
|
||||
IDistributedLockProvider _distributedLockProvider, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IMailVerificationService
|
||||
{
|
||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||
|
||||
|
||||
|
||||
private async Task<EmailNoticeConfig> GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario scenario, MimeMessage messageToSend,
|
||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailFunc)
|
||||
@@ -330,7 +343,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
var domain = baseUrl.Substring(0, baseUrl.IndexOf("/login"));
|
||||
|
||||
var redirectUrl = $"{domain}/api/User/UserRedirect?url={System.Web.HttpUtility.UrlEncode(routeUrl)}";
|
||||
|
||||
|
||||
|
||||
var companyName = _userInfo.IsEn_Us ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||
|
||||
@@ -520,7 +533,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
|
||||
|
||||
}
|
||||
@@ -580,7 +593,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.SiteUseOrExternalUserFirstrJoinTrial : EmailBusinessScenario.SiteUserOrExternalUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
|
||||
}
|
||||
@@ -710,7 +723,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(sysUserInfo.IsFirstAdd ? EmailBusinessScenario.DoctorUserFirstJoinTrial : EmailBusinessScenario.DoctorUserExistJoinTrial, messageToSend, emailConfigFunc);
|
||||
|
||||
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
|
||||
|
||||
//创建账号 和创建角色 一条,更新的时候才记录更新角色
|
||||
@@ -760,7 +773,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
if (feedBack.VisitTaskId != null)
|
||||
{
|
||||
|
||||
var emailType = await _dictionaryRepository.Where(t => t.Parent.Code == "Email_BusinessScenario" && t.ParentId != null && t.Code == ((int)EmailBusinessScenario.IRImageError).ToString()).Select(t => _userInfo.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();
|
||||
@@ -874,5 +887,112 @@ namespace IRaCIS.Core.Application.Service
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//用户修改密码发送邮件
|
||||
public async Task AfterUserModifyPasswordSendEmailAsync(Guid userId)
|
||||
{
|
||||
|
||||
var sysUserInfo = (await _identityUserRepository.Where(t => t.Id == userId).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
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 = _userInfo.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(ReplaceCompanyName(input.htmlBodyStr),
|
||||
|
||||
sysUserInfo.FullName
|
||||
);
|
||||
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.IdentityUser_ModifyPassword, messageToSend, emailConfigFunc);
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
//中心调研核对人员提醒
|
||||
public async Task SiteSuervyCheckUser(Guid trialId, string email, string name)
|
||||
{
|
||||
var trialInfo = await _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.TrialCode, t.EmailFromName, t.ResearchProgramNo }).FirstOrDefaultAsync();
|
||||
|
||||
var messageToSend = new MimeMessage();
|
||||
//发件地址
|
||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||
//收件地址
|
||||
messageToSend.To.Add(new MailboxAddress(name, email));
|
||||
//主题
|
||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
||||
|
||||
var companyName = _userInfo.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(ReplaceCompanyName(input.htmlBodyStr),
|
||||
name,
|
||||
trialInfo.TrialCode,
|
||||
trialInfo.ResearchProgramNo
|
||||
);
|
||||
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_CheckUser, messageToSend, emailConfigFunc);
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
public async Task SiteSuervyUpdateUser(Guid trialSiteId, string email, string name, string url)
|
||||
{
|
||||
var trialInfo = await _trialSiteRepository.Where(t => t.Id == trialSiteId).Select(t => new { t.Trial.TrialCode, t.Trial.EmailFromName, t.Trial.ResearchProgramNo, t.TrialSiteCode, t.TrialSiteName, t.TrialSiteAliasName }).FirstOrDefaultAsync();
|
||||
|
||||
var messageToSend = new MimeMessage();
|
||||
//发件地址
|
||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||
//收件地址
|
||||
messageToSend.To.Add(new MailboxAddress(name, email));
|
||||
//主题
|
||||
//---[来自展影IRC] 关于重置邮箱的提醒
|
||||
|
||||
var companyName = _userInfo.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(ReplaceCompanyName(input.htmlBodyStr),
|
||||
name,
|
||||
trialInfo.TrialCode,
|
||||
trialInfo.TrialSiteCode,
|
||||
trialInfo.TrialSiteName,
|
||||
url
|
||||
);
|
||||
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
|
||||
await GetEmailSubejctAndHtmlInfoAndBuildAsync(EmailBusinessScenario.SiteSurvey_UpdateUser, messageToSend, emailConfigFunc);
|
||||
SendEmailHelper.ChangeEmailSenderName(messageToSend, trialInfo.EmailFromName);
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.Service.Common;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
@@ -10,7 +11,18 @@ namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -104,6 +116,10 @@ namespace IRaCIS.Core.Application.Service
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.Subject.TrialSite.TrialSiteCode));
|
||||
|
||||
|
||||
CreateMap<TumorExportBaseModel , TU_Export>();
|
||||
CreateMap<TumorExportBaseModel, TR_Export>();
|
||||
CreateMap<TumorExportBaseModel, RS_Export>();
|
||||
CreateMap<TumorExportBaseModel, CO_Export>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,99 @@ using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.ViewModel;
|
||||
|
||||
|
||||
public class AuditRecordView : AuditRecordAddOrEdit
|
||||
{
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
public new List<Guid> IdnetityUserIdList => IdentityUserList.Select(t => t.Id).ToList();
|
||||
public List<AuditIdentiUserInfo> IdentityUserList { get; set; }
|
||||
}
|
||||
|
||||
public class AuditIdentiUserInfo
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string UserName { get; set; }
|
||||
|
||||
public string FullName { get; set; }
|
||||
}
|
||||
|
||||
public class AuditRecordAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string CompanyName { get; set; }
|
||||
|
||||
public string AuditContent { get; set; }
|
||||
|
||||
public DateOnly AuditTime { get; set; }
|
||||
|
||||
|
||||
public DateTime? BeginTime { get; set; }
|
||||
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
public AuditState AuditState { get; set; }
|
||||
|
||||
public AuditType AuditType { get; set; }
|
||||
|
||||
public bool IsViewTrainingRecord { get; set; }
|
||||
|
||||
//public List<Guid> IdnetityUserIdList { get; set; }
|
||||
}
|
||||
|
||||
public class AddOrDeleteAuditUserCommand
|
||||
{
|
||||
public Guid AuditRecordId { get; set; }
|
||||
|
||||
public List<Guid> IdentityUserIdList { get; set; }
|
||||
|
||||
public bool IsAdd { get; set; }
|
||||
}
|
||||
|
||||
public class AuditRecordQuery : PageInput
|
||||
{
|
||||
public string? CompanyName { get; set; }
|
||||
|
||||
public string? AuditContent { get; set; }
|
||||
|
||||
public DateOnly? BeginAuditTime { get; set; }
|
||||
public DateOnly? EndAuditTime { get; set; }
|
||||
|
||||
|
||||
public DateTime? BeginTime { get; set; }
|
||||
|
||||
public DateTime? EndTime { get; set; }
|
||||
|
||||
public AuditState? AuditState { get; set; }
|
||||
|
||||
public AuditType? AuditType { get; set; }
|
||||
|
||||
|
||||
public DateTime? BeginCreateTime { get; set; }
|
||||
|
||||
public DateTime? EndCreateTime { get; set; }
|
||||
|
||||
public string? IdentityUserName { get; set; }
|
||||
|
||||
public bool? IsViewTrainingRecord { get; set; }
|
||||
}
|
||||
|
||||
public class SetAuditRecordPermissionCommand
|
||||
{
|
||||
|
||||
public List<Guid> AuditDocumentIdList { get; set; }
|
||||
|
||||
public Guid AuditRecordId { get; set; }
|
||||
|
||||
public bool IsAuthorization { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class DeleteAudit
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
@@ -24,16 +117,21 @@ public class DeleteAuditDocumentInDto
|
||||
public List<Guid> Ids { get; set; }
|
||||
}
|
||||
|
||||
public class GetAuditDocumentDataInDto:PageInput
|
||||
public class GetAuditDocumentDataInDto : PageInput
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public Guid? SelfId { get; set; }
|
||||
|
||||
|
||||
public bool? IsAuthorization { get; set; }
|
||||
|
||||
public bool? IsCurrentAuditRecordAuthorization { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
//当前稽查记录Id
|
||||
public Guid? AuditRecordId { get; set; }
|
||||
}
|
||||
|
||||
public class GetAuditDocumentDataOutDto
|
||||
@@ -53,17 +151,20 @@ public class AuditDocumentData : AuditDocumentUpdateDto
|
||||
public int? Version { get; set; }
|
||||
|
||||
public int HistoricalVersionsCount { get; set; }
|
||||
public List<AuditDocumentData> Children { get; set; }=new List<AuditDocumentData> (){ };
|
||||
public List<AuditDocumentData> Children { get; set; } = new List<AuditDocumentData>() { };
|
||||
|
||||
|
||||
public bool? IsCurrentAuditRecordAuthorization { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class AuditDocumentView : AuditDocumentAddOrEdit
|
||||
{
|
||||
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SetIsAuthorizationInDto
|
||||
@@ -80,7 +181,7 @@ public class SetCurrentVersionInDto
|
||||
|
||||
public class GetHistoricalVersionInDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
public class GetHistoricalVersionOutDto
|
||||
@@ -93,10 +194,10 @@ public class MovieFileOrFolderInDto
|
||||
{
|
||||
public List<Guid> Ids { get; set; }
|
||||
|
||||
public Guid ParentId { get; set; }
|
||||
public Guid? ParentId { get; set; }
|
||||
}
|
||||
|
||||
public class HistoricalVersionDto: AuditDocumentUpdateDto
|
||||
public class HistoricalVersionDto : AuditDocumentUpdateDto
|
||||
{
|
||||
public bool IsCurrentVersion { get; set; } = false;
|
||||
|
||||
@@ -113,7 +214,7 @@ public class AuditDocumentUpdateDto
|
||||
|
||||
public AuditDocumentType AuditDocumentTypeEnum { get; set; }
|
||||
|
||||
public string? FileFormat { get; set; }
|
||||
public string? FileFormat { get; set; }
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
@@ -133,34 +234,34 @@ public class GetBreadcrumbDataInDto
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
public class AuditDocumentAddOrEdit: AuditDocumentUpdateDto
|
||||
public class AuditDocumentAddOrEdit : AuditDocumentUpdateDto
|
||||
{
|
||||
|
||||
|
||||
public List<AuditDocumentAddOrEdit> Children { get; set; }=new List<AuditDocumentAddOrEdit>() { };
|
||||
|
||||
public List<AuditDocumentAddOrEdit> Children { get; set; } = new List<AuditDocumentAddOrEdit>() { };
|
||||
|
||||
public bool IsUpdate { get; set; } = true;
|
||||
}
|
||||
|
||||
public class AuditDocumentQuery:PageInput
|
||||
public class AuditDocumentQuery : PageInput
|
||||
{
|
||||
public AuditDocumentType? AuditDocumentTypeEnum { get; set; }
|
||||
|
||||
|
||||
public string? FileFormat { get; set; }
|
||||
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public decimal? FileSize { get; set; }
|
||||
|
||||
|
||||
public decimal? FileSize { get; set; }
|
||||
|
||||
public bool? IsAuthorization { get; set; }
|
||||
|
||||
public Guid? MainFileId { get; set; }
|
||||
|
||||
|
||||
public Guid? MainFileId { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public Guid? ParentId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public Guid? ParentId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,10 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public bool? IsPublish { get; set; }
|
||||
|
||||
public string? FileTypeCode { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary> TrialDocumentAddOrEdit 列表查询参数模型</summary>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-10-20 06:17:15Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.Service.DTO;
|
||||
|
||||
public class UserAgreementView : UserAgreementAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class UserAgreementAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public DateTime EffectiveDate { get; set; }
|
||||
|
||||
public string FileContent { get; set; }
|
||||
|
||||
public string FileEnContent { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public string FileVersion { get; set; }
|
||||
|
||||
public bool IsCurrentVersion { get; set; }
|
||||
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
public UserAgreementType UserAgreementTypeEnum { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class SetUserAgreementCurrentVersionInDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
public class GetUserAgreementByIdInDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
public class UserAgreementQuery:PageInput
|
||||
{
|
||||
public DateTime? StartEffectiveDate { get; set; }
|
||||
|
||||
public DateTime? EndEffectiveDate { get; set; }
|
||||
|
||||
public string? FileContent { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public string? FileVersion { get; set; }
|
||||
|
||||
public bool? IsCurrentVersion { get; set; }
|
||||
|
||||
public DateTime? StartUpdateDate { get; set; }
|
||||
|
||||
public DateTime? EndUpdateDate { get; set; }
|
||||
|
||||
public UserAgreementType? UserAgreementTypeEnum { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
//入组确认/PD确认
|
||||
|
||||
|
||||
public async Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm)
|
||||
{
|
||||
EmailBusinessScenario businessScenarioEnum;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-10-20 06:17:15Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Application.Service.DTO;
|
||||
namespace IRaCIS.Core.Application.Service.Interface;
|
||||
|
||||
public interface IUserAgreementService
|
||||
{
|
||||
|
||||
Task<PageOutput<UserAgreementView>> GetUserAgreementList(UserAgreementQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateUserAgreement(UserAgreementAddOrEdit addOrEditUserAgreement);
|
||||
|
||||
Task<IResponseOutput> DeleteUserAgreement(Guid userAgreementId);
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
var beforeUserTypeIds = document.NeedConfirmedUserTypeList.Select(x => x.NeedConfirmUserTypeId).ToList();
|
||||
|
||||
_mapper.Map(addOrEditSystemDocument, document);
|
||||
|
||||
document.UpdateTime = DateTime.Now;
|
||||
#region 之前区分路径文件夹 现在不区分废弃
|
||||
|
||||
//if (document.FileTypeId != addOrEditSystemDocument.FileTypeId)
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class TrialDocumentService(IRepository<TrialDocument> _trialDocumentRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<AuditRecord> _auditRecordRepository,
|
||||
IRepository<TrialDocumentAttachment> _trialDocumentAttachmentRepository,
|
||||
ISystemDocumentService _systemDocumentService,
|
||||
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
|
||||
@@ -151,8 +152,10 @@ namespace IRaCIS.Core.Application.Services
|
||||
var trialDocumentQueryable = _trialDocumentRepository.AsQueryable(true).Where(t => t.TrialId == inQuery.TrialId)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.Name), t => t.Name.Contains(inQuery.Name))
|
||||
.WhereIf(inQuery.FileTypeId != null, t => t.FileTypeId == inQuery.FileTypeId)
|
||||
.WhereIf(inQuery.UserTypeId != null, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
|
||||
.WhereIf(inQuery.UserTypeId != null, t => t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
|
||||
.WhereIf(inQuery.IsPublish != null, t => t.IsPublish == inQuery.IsPublish)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.FileTypeCode), t => t.FileType.Code== inQuery.FileTypeCode)
|
||||
.ProjectTo<TrialDocumentView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, isEn_Us = _userInfo.IsEn_Us });
|
||||
|
||||
return await trialDocumentQueryable.ToPagedListAsync(inQuery);
|
||||
@@ -900,7 +903,12 @@ namespace IRaCIS.Core.Application.Services
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput> GetSysDocSignUserList()
|
||||
{
|
||||
var list = _systemDocConfirmedUserRepository.Where(t => t.ConfirmTime != null).Select(t => new { t.ConfirmUserId, t.ConfirmUser.UserName, t.ConfirmUser.FullName }).Distinct().ToList();
|
||||
//EA 只能查看内部人员文档
|
||||
var isEA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.EA;
|
||||
|
||||
var list = _systemDocConfirmedUserRepository.Where(t => t.ConfirmTime != null)
|
||||
.WhereIf(isEA, t => t.ConfirmUser.IsZhiZhun == true)
|
||||
.Select(t => new { t.ConfirmUserId, t.ConfirmUser.UserName, t.ConfirmUser.FullName }).Distinct().ToList();
|
||||
|
||||
return ResponseOutput.Ok(list);
|
||||
}
|
||||
@@ -911,12 +919,21 @@ namespace IRaCIS.Core.Application.Services
|
||||
|
||||
var isInternal = _userInfo.IsZhiZhun;
|
||||
|
||||
var isEA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.EA;
|
||||
|
||||
//EA 但是没有在进行的培训记录查看权限,那么返回空数据
|
||||
if (isEA && !_auditRecordRepository.Any(t => t.IsViewTrainingRecord && t.AuditState == AuditState.Ongoing))
|
||||
{
|
||||
return ResponseOutput.Ok(new PageOutput<UnionDocumentWithConfirmInfoView>());
|
||||
}
|
||||
|
||||
var systemDocQuery =
|
||||
from sysDoc in _systemDocumentRepository.AsQueryable(false)
|
||||
.Where(t => inQuery.UserTypeId != null ? t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId) : true)
|
||||
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)))
|
||||
.Where(t => inQuery.UserId != null ? t.Id == inQuery.UserId : true)
|
||||
.Where(t => inQuery.UserTypeId != null ? t.UserRoleList.Any(t => t.UserTypeId == inQuery.UserTypeId && t.IsUserRoleDisabled == false) : true)
|
||||
.Where(t => isEA ? t.IsZhiZhun == true : true) //EA 只能查看内部人员文档
|
||||
join confirm in _systemDocConfirmedUserRepository.Where() on new { ConfirmUserId = identityUser.Id, SystemDocumentId = sysDoc.Id } equals new { confirm.ConfirmUserId, confirm.SystemDocumentId } into cc
|
||||
from confirm in cc.DefaultIfEmpty()
|
||||
select new UnionDocumentWithConfirmInfoView()
|
||||
@@ -942,7 +959,14 @@ namespace IRaCIS.Core.Application.Services
|
||||
//UserTypeId = trialUser.UserRole.UserTypeId,
|
||||
//UserTypeShortName = trialUser.UserRole.UserTypeRole.UserTypeShortName,
|
||||
|
||||
FullFilePath = sysDoc.Path
|
||||
FullFilePath = sysDoc.Path,
|
||||
|
||||
AttachmentCount = sysDoc.SystemDocumentAttachmentList.Where(t => t.OffLine == false).Count(),
|
||||
|
||||
DocNeedSignUserTypeList = sysDoc.NeedConfirmedUserTypeList.Select(t => t.UserTypeRole.UserTypeShortName).ToList(),
|
||||
|
||||
IdentityUserTypeList = identityUser.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Select(c => c.UserTypeRole.UserTypeShortName).ToList()
|
||||
|
||||
};
|
||||
|
||||
var unionQuery = systemDocQuery.IgnoreQueryFilters().Where(t => !(t.IsDeleted == true && t.ConfirmTime == null))
|
||||
@@ -956,44 +980,44 @@ namespace IRaCIS.Core.Application.Services
|
||||
.WhereIf(inQuery.EndCreateTime != null, t => t.CreateTime <= inQuery.EndCreateTime)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.UserName), t => t.UserName.Contains(inQuery.UserName))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
|
||||
.WhereIf(isInternal == false, t => t.ConfirmTime != null);
|
||||
.WhereIf(isInternal == false, t => t.ConfirmTime != null); //不是内部的人,看有签名时间的
|
||||
|
||||
var result = await unionQuery.ToPagedListAsync(inQuery);
|
||||
|
||||
#region 处理文档 需要签署的角色类型 和每个人的角色信息
|
||||
|
||||
var trialDocIdList = result.CurrentPageData.Where(t => t.IsSystemDoc == false).Select(t => t.Id).ToList();
|
||||
//var trialDocIdList = result.CurrentPageData.Where(t => t.IsSystemDoc == false).Select(t => t.Id).ToList();
|
||||
|
||||
var sysDocIdList = result.CurrentPageData.Where(t => t.IsSystemDoc == true).Select(t => t.Id).ToList();
|
||||
//var sysDocIdList = result.CurrentPageData.Where(t => t.IsSystemDoc == true).Select(t => t.Id).ToList();
|
||||
|
||||
var identityUserIdList = result.CurrentPageData.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||
//var identityUserIdList = result.CurrentPageData.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||
|
||||
|
||||
var sysDocUserTypeList = _systemDocNeedConfirmedUserTypeRepository.Where(t => sysDocIdList.Contains(t.SystemDocumentId)).Select(t => new { t.SystemDocumentId, t.UserTypeRole.UserTypeShortName }).ToList();
|
||||
//var sysDocUserTypeList = _systemDocNeedConfirmedUserTypeRepository.Where(t => sysDocIdList.Contains(t.SystemDocumentId)).Select(t => new { t.SystemDocumentId, t.UserTypeRole.UserTypeShortName }).ToList();
|
||||
|
||||
var identityUserUserTypeList = _identityUserRepository.Where(t => identityUserIdList.Contains(t.Id)).IgnoreQueryFilters().Select(t => new { IdentityUserId = t.Id, UserTypeList = t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Select(c => c.UserTypeRole.UserTypeShortName).ToList() });
|
||||
//var identityUserUserTypeList = _identityUserRepository.Where(t => identityUserIdList.Contains(t.Id)).IgnoreQueryFilters().Select(t => new { IdentityUserId = t.Id, UserTypeList = t.UserRoleList.Where(t => t.IsUserRoleDisabled == false).Select(c => c.UserTypeRole.UserTypeShortName).ToList() });
|
||||
|
||||
//Concat 不能用导航属性
|
||||
var sysids = result.CurrentPageData.Where(t => t.IsSystemDoc == true).Select(t => t.Id).ToList();
|
||||
////Concat 不能用导航属性
|
||||
//var sysids = result.CurrentPageData.Where(t => t.IsSystemDoc == true).Select(t => t.Id).ToList();
|
||||
|
||||
var sysDataList = await _systemDocumentRepository.Where(x => sysids.Contains(x.Id)).Include(x => x.SystemDocumentAttachmentList).ToListAsync();
|
||||
//var sysDataList = await _systemDocumentRepository.Where(x => sysids.Contains(x.Id)).Include(x => x.SystemDocumentAttachmentList).ToListAsync();
|
||||
|
||||
foreach (var item in result.CurrentPageData)
|
||||
{
|
||||
//foreach (var item in result.CurrentPageData)
|
||||
//{
|
||||
|
||||
if (sysDataList.Any(y => y.Id == item.Id))
|
||||
{
|
||||
item.AttachmentCount = sysDataList.Where(y => y.Id == item.Id).Select(x => x.SystemDocumentAttachmentList.Where(z => !z.OffLine).Count()).FirstOrDefault();
|
||||
}
|
||||
// if (sysDataList.Any(y => y.Id == item.Id))
|
||||
// {
|
||||
// item.AttachmentCount = sysDataList.Where(y => y.Id == item.Id).Select(x => x.SystemDocumentAttachmentList.Where(z => !z.OffLine).Count()).FirstOrDefault();
|
||||
// }
|
||||
|
||||
if (item.IsSystemDoc)
|
||||
{
|
||||
item.DocNeedSignUserTypeList = sysDocUserTypeList.Where(t => t.SystemDocumentId == item.Id).Select(t => t.UserTypeShortName).ToList();
|
||||
}
|
||||
// if (item.IsSystemDoc)
|
||||
// {
|
||||
// item.DocNeedSignUserTypeList = sysDocUserTypeList.Where(t => t.SystemDocumentId == item.Id).Select(t => t.UserTypeShortName).ToList();
|
||||
// }
|
||||
|
||||
|
||||
item.IdentityUserTypeList = identityUserUserTypeList.Where(t => t.IdentityUserId == item.ConfirmUserId).SelectMany(c => c.UserTypeList).ToList();
|
||||
}
|
||||
// item.IdentityUserTypeList = identityUserUserTypeList.Where(t => t.IdentityUserId == item.ConfirmUserId).SelectMany(c => c.UserTypeList).ToList();
|
||||
//}
|
||||
|
||||
|
||||
#endregion
|
||||
@@ -1064,7 +1088,7 @@ namespace IRaCIS.Core.Application.Services
|
||||
var beforeUserTypeIds = document.NeedConfirmedUserTypeList.Select(x => x.NeedConfirmUserTypeId).ToList();
|
||||
|
||||
_mapper.Map(addOrEditTrialDocument, document);
|
||||
|
||||
document.UpdateTime = DateTime.Now;
|
||||
#region 不区分路径了
|
||||
|
||||
//if (document.FileTypeId != addOrEditTrialDocument.FileTypeId)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-10-20 06:17:11Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Service.Interface;
|
||||
using IRaCIS.Core.Application.Service.DTO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
namespace IRaCIS.Core.Application.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 用户协议和隐私采集服务
|
||||
/// </summary>
|
||||
/// <param name="_userAgreementRepository"></param>
|
||||
/// <param name="_mapper"></param>
|
||||
/// <param name="_userInfo"></param>
|
||||
/// <param name="_localizer"></param>
|
||||
[ApiExplorerSettings(GroupName = "FileRecord")]
|
||||
public class UserAgreementService(IRepository<UserAgreement> _userAgreementRepository,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, IUserAgreementService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户协议和隐私采集列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<UserAgreementView>> GetUserAgreementList(UserAgreementQuery inQuery)
|
||||
{
|
||||
var userAgreementQueryable =_userAgreementRepository
|
||||
.WhereIf(inQuery.StartEffectiveDate.HasValue, t => t.EffectiveDate >= inQuery.StartEffectiveDate.Value)
|
||||
.WhereIf(inQuery.EndEffectiveDate.HasValue, t => t.EffectiveDate <= inQuery.EndEffectiveDate.Value)
|
||||
.WhereIf(inQuery.FileContent != null, t => t.FileContent.Contains(inQuery.FileContent))
|
||||
.WhereIf(inQuery.FileName != null, t => t.FileName.Contains(inQuery.FileName))
|
||||
.WhereIf(inQuery.FileVersion != null, t => t.FileVersion.Contains(inQuery.FileVersion))
|
||||
.WhereIf(inQuery.IsCurrentVersion != null, t => t.IsCurrentVersion==inQuery.IsCurrentVersion)
|
||||
.WhereIf(inQuery.UserAgreementTypeEnum != null, t => t.UserAgreementTypeEnum == inQuery.UserAgreementTypeEnum)
|
||||
.WhereIf(inQuery.StartUpdateDate.HasValue, t => t.UpdateDate >= inQuery.StartUpdateDate.Value)
|
||||
.WhereIf(inQuery.EndUpdateDate.HasValue, t => t.UpdateDate <= inQuery.EndUpdateDate.Value)
|
||||
.ProjectTo<UserAgreementView>(_mapper.ConfigurationProvider);
|
||||
var pageList= await userAgreementQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前版本的用户协议和隐私采集
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
public async Task<List<UserAgreementView>> GetCurrentVersionUserAgreements()
|
||||
{
|
||||
var userAgreementList = await _userAgreementRepository.Where(x=>x.IsCurrentVersion)
|
||||
.ProjectTo<UserAgreementView>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
return userAgreementList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据Id获取用户协议和隐私采集
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost]
|
||||
public async Task<UserAgreementView> GetUserAgreementById(GetUserAgreementByIdInDto inDto)
|
||||
{
|
||||
var userAgreement = await _userAgreementRepository.Where(x => x.Id == inDto.Id)
|
||||
.ProjectTo<UserAgreementView>(_mapper.ConfigurationProvider)
|
||||
.FirstNotNullAsync();
|
||||
return userAgreement;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 设置为当前版本
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> SetCurrentVersion(SetUserAgreementCurrentVersionInDto inDto)
|
||||
{
|
||||
var userAgreement=await _userAgreementRepository.Where(x=>x.Id==inDto.Id).FirstNotNullAsync();
|
||||
await _userAgreementRepository.UpdatePartialFromQueryAsync(
|
||||
x => x.UserAgreementTypeEnum== userAgreement.UserAgreementTypeEnum&&x.IsCurrentVersion,
|
||||
x => new UserAgreement { IsCurrentVersion = false },true);
|
||||
|
||||
await _userAgreementRepository.UpdatePartialFromQueryAsync(
|
||||
inDto.Id,
|
||||
x => new UserAgreement { IsCurrentVersion = true },true);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或者修改用户协议和隐私采集
|
||||
/// </summary>
|
||||
/// <param name="addOrEditUserAgreement"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> AddOrUpdateUserAgreement(UserAgreementAddOrEdit addOrEditUserAgreement)
|
||||
{
|
||||
var entity = await _userAgreementRepository.InsertOrUpdateAsync(addOrEditUserAgreement, true);
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除用户协议和隐私采集
|
||||
/// </summary>
|
||||
/// <param name="userAgreementId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{userAgreementId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteUserAgreement(Guid userAgreementId)
|
||||
{
|
||||
var success = await _userAgreementRepository.DeleteFromQueryAsync(t => t.Id == userAgreementId,true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ namespace IRaCIS.Core.Application.Service
|
||||
var userId = Guid.Empty;
|
||||
var isEn_Us = false;
|
||||
|
||||
// 在此处拷贝automapper 映射
|
||||
|
||||
CreateMap<UserAgreement, UserAgreementView>();
|
||||
CreateMap<UserAgreement, UserAgreementAddOrEdit>().ReverseMap();
|
||||
|
||||
// 在此处拷贝automapper 映射
|
||||
CreateMap<TrialDocumentAttachment, TrialDocumentAttachmentView>();
|
||||
CreateMap<TrialDocumentAttachment, TrialDocumentAttachmentAddOrEdit>().ReverseMap();
|
||||
@@ -29,7 +34,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
CreateMap<AuditDocument, AuditDocumentUpdateDto>();
|
||||
CreateMap<AuditDocument, HistoricalVersionDto>();
|
||||
CreateMap<AuditDocumentUpdateDto, AuditDocumentAddOrEdit>();
|
||||
CreateMap<AuditDocument, AuditDocumentData>();
|
||||
CreateMap<AuditDocument, AuditDocumentData>()
|
||||
.ForMember(d => d.HistoricalVersionsCount, u => u.MapFrom(s => s.AuditDocumentOldVersionList.Count()));
|
||||
CreateMap<AuditDocument, AuditDocumentAddOrEdit>().ReverseMap();
|
||||
CreateMap<SystemDocument, SystemDocumentView>()
|
||||
.ForMember(d => d.AttachmentCount, u => u.MapFrom(s => s.SystemDocumentAttachmentList.Count()))
|
||||
@@ -43,7 +49,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
.ForMember(dest => dest.CreateUserRole, opt => opt.Ignore());
|
||||
|
||||
CreateMap<TrialDocument, TrialDocumentView>()
|
||||
.ForMember(d => d.AttachmentCount, u => u.MapFrom(s =>s.TrialDocumentAttachmentList.Count()))
|
||||
.ForMember(d => d.AttachmentCount, u => u.MapFrom(s => s.TrialDocumentAttachmentList.Count()))
|
||||
.ForMember(d => d.FileType, u => u.MapFrom(s => isEn_Us ? s.FileType.Value : s.FileType.ValueCN))
|
||||
.ForMember(d => d.IsSomeUserSigned, u => u.MapFrom(s => s.TrialDocConfirmedUserList.Any(t => t.ConfirmTime != null)))
|
||||
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path));
|
||||
@@ -81,7 +87,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
CreateMap<BatchAddTrialEmailNoticeConfig, TrialEmailNoticeConfig>();
|
||||
|
||||
CreateMap<TrialSelectEmailNoticeConfigView, BatchAddTrialEmailNoticeConfig > ();
|
||||
CreateMap<TrialSelectEmailNoticeConfigView, BatchAddTrialEmailNoticeConfig>();
|
||||
|
||||
|
||||
CreateMap<AddOrEditTrialDocument, TrialDocument>()
|
||||
@@ -94,13 +100,14 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
|
||||
CreateMap<AddOrEditSystemDocument, SystemDocument>().ForMember(d => d.NeedConfirmedUserTypeList, c => c.MapFrom(t => t.NeedConfirmedUserTypeIdList));
|
||||
CreateMap<Guid, SystemDocNeedConfirmedUserType>().EqualityComparison((odto, o) => odto == o.NeedConfirmUserTypeId)
|
||||
CreateMap<Guid, SystemDocNeedConfirmedUserType>()
|
||||
.EqualityComparison((odto, o) => odto == o.NeedConfirmUserTypeId)
|
||||
.ForMember(d => d.NeedConfirmUserTypeId, c => c.MapFrom(t => t))
|
||||
.ForMember(d => d.SystemDocumentId, c => c.Ignore());
|
||||
|
||||
|
||||
CreateMap<TrialEmailNoticeConfig, TrialEmailNoticeConfigView>()
|
||||
.ForMember(d => d.SysCriterionTypeList, c => c.MapFrom(t => t.SysEmailNoticeConfig.CriterionTypeList))
|
||||
.ForMember(d => d.SysCriterionTypeList, c => c.MapFrom(t => t.SysEmailNoticeConfig.CriterionTypeList))
|
||||
.ForMember(d => d.TrialCriterionName, c => c.MapFrom(t => t.TrialReadingCriterion.CriterionName))
|
||||
.ForMember(d => d.TrialEmailNoticeUserList, c => c.MapFrom(t => t.TrialEmailNoticeUserList));
|
||||
|
||||
@@ -146,6 +153,26 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
CreateMap<TrialHistoryRecordFile, TrialHistoryRecordFileView>();
|
||||
CreateMap<TrialHistoryRecordFile, TrialHistoryRecordFileAddOrEdit>().ReverseMap();
|
||||
|
||||
|
||||
|
||||
CreateMap<AuditRecord, AuditRecordView>()
|
||||
.ForMember(d => d.IdentityUserList, c => c.MapFrom(t => t.AuditRecordIdentityUserList));
|
||||
|
||||
CreateMap<AuditRecordAddOrEdit, AuditRecord>()
|
||||
/* .ForMember(d => d.AuditRecordIdentityUserList, c => c.MapFrom(t => t.IdnetityUserIdList))*/;
|
||||
|
||||
CreateMap<Guid, AuditRecordIdentityUser>()
|
||||
.EqualityComparison((odto, o) => odto == o.IdentityUserId)
|
||||
.ForMember(d => d.AuditRecordId, c => c.Ignore())
|
||||
.ForMember(d => d.IdentityUserId, c => c.MapFrom(t => t));
|
||||
|
||||
|
||||
CreateMap<AuditRecordIdentityUser, AuditIdentiUserInfo>()
|
||||
.ForMember(d => d.Id, c => c.MapFrom(t => t.IdentityUser.Id))
|
||||
.ForMember(d => d.UserName, c => c.MapFrom(t => t.IdentityUser.UserName))
|
||||
.ForMember(d => d.FullName, c => c.MapFrom(t => t.IdentityUser.FullName));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
{
|
||||
@@ -27,6 +28,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
|
||||
public List<StudyBasicInfo> UploadStudyList { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<StudyBasicInfo> OriginalTaskStudyList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +106,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
|
||||
public string BodyPartForEdit { get; set; }
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
|
||||
public DateTime? StudyTime { get; set; }
|
||||
|
||||
public string Modalities { get; set; }
|
||||
@@ -114,6 +120,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
public int ReadingSeriesCount { get; set; }
|
||||
|
||||
public int ReadingInstanceCount { get; set; }
|
||||
|
||||
public Guid? SubjectVisitId { get; set; }
|
||||
}
|
||||
|
||||
public class NoneDicomStudyBasicInfo
|
||||
@@ -126,6 +134,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
|
||||
public string BodyPart { get; set; }
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
|
||||
public string Modality { get; set; }
|
||||
|
||||
public DateTime ImageDate { get; set; }
|
||||
@@ -136,5 +146,10 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
|
||||
public int ReadingFileCount { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ImageMarkNoneDicomStudyBasicInfo: NoneDicomStudyBasicInfo
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,7 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public int FileCount { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class PreArchiveDicomStudyCommand
|
||||
@@ -237,6 +238,9 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public Guid? VisitTaskId { get; set; }
|
||||
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TaskStudyArchiveConfirmResult
|
||||
@@ -267,6 +271,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
[NotDefault]
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
}
|
||||
|
||||
public class NewArchiveStudyCommand
|
||||
@@ -324,13 +330,26 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public string BodyPartExamined { get; set; } = string.Empty;
|
||||
|
||||
public string DicomStudyDate { get; set; }
|
||||
public string DicomStudyDate { get; set; } = string.Empty;
|
||||
|
||||
public string DicomStudyTime { get; set; }
|
||||
public string DicomStudyTime { get; set; } = string.Empty;
|
||||
|
||||
public List<AddOrUpdateSeriesDto> SeriesList { get; set; }
|
||||
|
||||
#region 模态支持增加字段
|
||||
|
||||
public string Manufacturer { get; set; } = string.Empty;
|
||||
|
||||
public string ManufacturerModelName { get; set; } = string.Empty;
|
||||
|
||||
public string DeviceSerialNumber { get; set; } = string.Empty;
|
||||
public string DeviceUID { get; set; } = string.Empty;
|
||||
|
||||
public string SoftwareVersions { get; set; } = string.Empty;
|
||||
|
||||
public string PatientWeight { get; set; } = string.Empty;
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@@ -358,14 +377,22 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public string ImageResizePath { get; set; } = string.Empty;
|
||||
|
||||
public string DicomSeriesDate { get; set; }
|
||||
public string DicomSeriesDate { get; set; } = string.Empty;
|
||||
|
||||
public string DicomSeriesTime { get; set; }
|
||||
public string DicomSeriesTime { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public List<AddInstanceDto> InstanceList { get; set; }
|
||||
|
||||
public Guid? VisitTaskId { get; set; }
|
||||
|
||||
#region 模态增加
|
||||
|
||||
public string RadiopharmaceuticalInformationSequence { get; set; } = string.Empty;
|
||||
|
||||
public string AcquisitionDate { get; set; } = string.Empty;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -398,15 +425,46 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public long FileSize { get; set; }
|
||||
|
||||
public string SOPClassUID { get; set; }
|
||||
public string SOPClassUID { get; set; } = string.Empty;
|
||||
|
||||
public string MediaStorageSOPClassUID { get; set; }
|
||||
public string MediaStorageSOPClassUID { get; set; } = string.Empty;
|
||||
|
||||
public string TransferSytaxUID { get; set; }
|
||||
public string TransferSytaxUID { get; set; } = string.Empty;
|
||||
|
||||
public string MediaStorageSOPInstanceUID { get; set; }
|
||||
public string MediaStorageSOPInstanceUID { get; set; } = string.Empty;
|
||||
|
||||
public bool IsEncapsulated => DicomTransferSyntax.Lookup(DicomUID.Parse(TransferSytaxUID)).IsEncapsulated;
|
||||
public bool IsEncapsulated => !string.IsNullOrEmpty(TransferSytaxUID) ? DicomTransferSyntax.Lookup(DicomUID.Parse(TransferSytaxUID)).IsEncapsulated : false;
|
||||
|
||||
#region 模态支持增加字段
|
||||
|
||||
public string PhotometricInterpretation { get; set; } = string.Empty;
|
||||
|
||||
public int BitsAllocated { get; set; }
|
||||
|
||||
public string PixelRepresentation { get; set; } = string.Empty;
|
||||
|
||||
public string RescaleIntercept { get; set; } = string.Empty;
|
||||
|
||||
public string RescaleSlope { get; set; } = string.Empty;
|
||||
|
||||
public string ImagePositionPatient { get; set; } = string.Empty;
|
||||
public string ImageOrientationPatient { get; set; } = string.Empty;
|
||||
|
||||
//可能大
|
||||
public string SequenceOfUltrasoundRegions { get; set; } = string.Empty;
|
||||
|
||||
public string FrameTime { get; set; } = string.Empty;
|
||||
|
||||
public string CorrectedImage { get; set; } = string.Empty;
|
||||
|
||||
public string Units { get; set; } = string.Empty;
|
||||
public string DecayCorrection { get; set; } = string.Empty;
|
||||
|
||||
public string EncapsulatedDocument { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@@ -440,6 +498,10 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public string? SubjectCode { get; set; }
|
||||
|
||||
public Guid? VisitTaskId { get; set; }
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
|
||||
public Guid? SubjectVisitId { get; set; }
|
||||
}
|
||||
|
||||
public class IRTaskUploadedDicomStudyQuery
|
||||
@@ -519,6 +581,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public string TaskBlindName { get; set; }
|
||||
|
||||
public string TaskName { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
public Guid? SourceSubjectVisitId { get; set; }
|
||||
|
||||
public ReadingTaskState ReadingTaskState { get; set; }
|
||||
@@ -536,11 +600,15 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public string TaskBlindName { get; set; }
|
||||
|
||||
|
||||
|
||||
public Guid VisitId { get; set; }
|
||||
|
||||
public List<DownloadDicomStudyDto> StudyList { get; set; }
|
||||
public List<DownloadNoneDicomStudyDto> NoneDicomStudyList { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<DownloadDicomStudyDto> TaskStudyList { get; set; }
|
||||
|
||||
public List<DownloadNoneDicomStudyDto> NoneDicomStudyList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomStudyDto
|
||||
@@ -551,14 +619,14 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public string StudyInstanceUid { get; set; }
|
||||
public string StudyDIRPath { get; set; }
|
||||
|
||||
public List<DownloadDicomSeriesDto> SeriesList { get; set; }
|
||||
public List<DownloadDicomSeriesDto> SeriesList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomSeriesDto
|
||||
{
|
||||
public string Modality { get; set; }
|
||||
|
||||
public List<DownloadDicomInstanceDto> InstanceList { get; set; }
|
||||
public List<DownloadDicomInstanceDto> InstanceList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomInstanceDto
|
||||
@@ -609,6 +677,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public string? SubjectCode { get; set; }
|
||||
|
||||
public Guid? VisitTaskId { get; set; }
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -629,6 +699,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public List<Guid> NoneDicomStudyIdList { get; set; }
|
||||
|
||||
public bool? IsImageSegmentLabel { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TrialKeyImageExportDTO
|
||||
@@ -735,7 +807,7 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
? $"{TotalReadingImageSize.Value / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
public string ImageTypeStr => $"{(IsHaveDicom ? "DICOM" : "")}{(IsHaveNoneDicom&&IsHaveDicom?" , ":"")}{(IsHaveNoneDicom ? "Non-DICOM" : "")}";
|
||||
public string ImageTypeStr => $"{(IsHaveDicom ? "DICOM" : "")}{(IsHaveNoneDicom && IsHaveDicom ? " , " : "")}{(IsHaveNoneDicom ? "Non-DICOM" : "")}";
|
||||
|
||||
public bool IsHaveDicom { get; set; }
|
||||
|
||||
@@ -878,4 +950,87 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public Guid TaskId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class SubjectVisitMarkQuery:PageInput
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid? SubjectId { get; set; }
|
||||
|
||||
public Guid? TrialReadingCriterionId { get; set; }
|
||||
|
||||
public string? SubjectCode { get; set; }
|
||||
|
||||
public bool? IsUrgent { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SubjectVisitMarkDTO
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public bool IsUrgent { get; set; }
|
||||
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public int? VisitCount { get; set; }
|
||||
|
||||
|
||||
public int? MarkVisitCount { get; set; }
|
||||
|
||||
|
||||
public int? DicomStudyCount { get; set; }
|
||||
|
||||
public int? MarkDicomStudyCount { get; set; }
|
||||
|
||||
public int? NoneDicomStudyCount { get; set; }
|
||||
|
||||
public int? MarkNoneDicomStudyCount { get; set; }
|
||||
}
|
||||
|
||||
public class SubjectVisitMarkStudyDto
|
||||
{
|
||||
public bool IsDicom => DicomStudyList.Count() > 0;
|
||||
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public Guid SourceSubjectVisitId { get; set; }
|
||||
|
||||
|
||||
public List<DicomStudyBasicInfo> DicomStudyList { get; set; } = new List<DicomStudyBasicInfo>();
|
||||
|
||||
public List<NoneDicomStudyBasicInfo> NoneDicomStudyList { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class SubjectVisitMarkUploadDto
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
public Guid SubejctId { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public Guid? SourceSubjectVisitId => SubjectVisitId;
|
||||
|
||||
|
||||
|
||||
public List<StudyBasicInfo> OrginalStudyList { get; set; }
|
||||
|
||||
public List<StudyBasicInfo> UploadStudyList { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -323,18 +323,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
|
||||
}
|
||||
|
||||
#region 只配置单个部位自动赋值
|
||||
//项目配置的影像部位
|
||||
var trialBodyParts = _trialRepository.Where(t => t.Id == trialId).Select(t => t.BodyPartTypes).FirstOrDefault();
|
||||
|
||||
var trialBodyPartList = trialBodyParts.Split('|', StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (trialBodyPartList.Count() == 1)
|
||||
{
|
||||
var first = trialBodyPartList.First();
|
||||
findStudy.BodyPartForEdit = first;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");
|
||||
@@ -579,7 +568,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
/// <returns></returns>
|
||||
[HttpGet("{subjectVisitId:guid}")]
|
||||
[AllowAnonymous]
|
||||
public IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId,bool? isReading)
|
||||
public IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId, bool? isReading)
|
||||
{
|
||||
#region 废弃
|
||||
//var studylist = _studyRepository.Where(u => u.SubjectVisitId == subjectVisitId && u.IsDeleted == false).Select(t => new { StudyId = t.Id, t.SubjectId, t.TrialId }).ToList();
|
||||
@@ -608,17 +597,17 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
var studyInfo = _dicomStudyRepository.Where(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException();
|
||||
|
||||
var list = _dicomStudyRepository.Where(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
|
||||
.Select(t=> new RelationStudyDTO()
|
||||
.Select(t => new RelationStudyDTO()
|
||||
{
|
||||
StudyId = t.Id,
|
||||
StudyCode = t.StudyCode,
|
||||
VisitName = t.SubjectVisit.VisitName,
|
||||
Modalities = t.Modalities,
|
||||
Description = t.Description,
|
||||
SeriesCount = t.SeriesList.Where(t=> isReading==true? t.IsReading==true:true).Count()
|
||||
}) .ToList();
|
||||
SeriesCount = t.SeriesList.Where(t => isReading == true ? t.IsReading == true : true).Count()
|
||||
}).ToList();
|
||||
|
||||
list = list.Where(t=>t.SeriesCount>0).OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList();
|
||||
list = list.Where(t => t.SeriesCount > 0).OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList();
|
||||
|
||||
return ResponseOutput.Ok(list);
|
||||
}
|
||||
@@ -628,7 +617,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
/// <param name="studyId"> Dicom检查的Id </param>
|
||||
[HttpGet, Route("{studyId:guid}")]
|
||||
[AllowAnonymous]
|
||||
public IResponseOutput<DicomStudyDTO> Item(Guid studyId,bool? isPacs)
|
||||
public IResponseOutput<DicomStudyDTO> Item(Guid studyId, bool? isPacs)
|
||||
{
|
||||
if (isPacs == true)
|
||||
{
|
||||
@@ -861,7 +850,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||
|
||||
|
||||
|
||||
var verifyStudyInfo = _dicomStudyRepository.Where(t => t.TrialId == trialId && t.Id == expectStudyId,false,true).ProjectTo<VerifyStudyDto>(_mapper.ConfigurationProvider).FirstOrDefault();
|
||||
var verifyStudyInfo = _dicomStudyRepository.Where(t => t.TrialId == trialId && t.Id == expectStudyId, false, true).ProjectTo<VerifyStudyDto>(_mapper.ConfigurationProvider).FirstOrDefault();
|
||||
result.StudyInfo = verifyStudyInfo;
|
||||
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
CreateMap<DicomStudy, DicomStudyDTO>();
|
||||
CreateMap<DicomSeries, DicomSeriesDTO>()
|
||||
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.SubjectVisit.Subject.Code))
|
||||
.ForMember(o => o.VisitName, t => t.MapFrom(u => u.SubjectVisit.VisitName));
|
||||
.ForMember(o => o.VisitName, t => t.MapFrom(u => u.SubjectVisit.VisitName));
|
||||
CreateMap<SCPSeries, DicomSeriesDTO>();
|
||||
|
||||
|
||||
@@ -136,6 +136,11 @@ namespace IRaCIS.Core.Application.Service
|
||||
.ForMember(d => d.ReadingSeriesCount, u => u.MapFrom(s => s.SeriesList.Where(t => t.IsReading).Count()))
|
||||
.ForMember(d => d.ReadingInstanceCount, u => u.MapFrom(s => s.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading).Count()));
|
||||
|
||||
CreateMap<TaskStudy, DicomStudyBasicInfo>()
|
||||
//.ForMember(d => d.SubjectVisitId, u => u.MapFrom(s => s.SubjectVisitId))
|
||||
.ForMember(d => d.ReadingSeriesCount, u => u.MapFrom(s => s.SeriesCount))
|
||||
.ForMember(d => d.ReadingInstanceCount, u => u.MapFrom(s => s.InstanceCount));
|
||||
|
||||
CreateMap<NoneDicomStudy, NoneDicomStudyBasicInfo>()
|
||||
.ForMember(d => d.ReadingFileCount, u => u.MapFrom(s => s.NoneDicomFileList.Where(t => t.IsReading).Count()));
|
||||
|
||||
@@ -145,7 +150,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
.ForMember(d => d.CriterionModalitys, u => u.MapFrom(s => s.TrialReadingCriterion.CriterionModalitys))
|
||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(u => u.IsAnalysisCreate == true ? u.BlindSubjectCode : u.Subject.Code))
|
||||
.ForMember(d => d.DicomStudyList, u => u.MapFrom(s => s.SourceSubjectVisit.StudyList))
|
||||
.ForMember(d => d.NoneDicomStudyList, u => u.MapFrom(s => s.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.IsReading)));
|
||||
.ForMember(d => d.NoneDicomStudyList, u => u.MapFrom(s => s.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.IsReading)));
|
||||
|
||||
CreateMap<TrialImageDownload, TrialImageDownloadView>()
|
||||
.ForMember(d => d.UserFullName, u => u.MapFrom(s => s.CreateUserRole.FullName))
|
||||
@@ -158,7 +163,25 @@ namespace IRaCIS.Core.Application.Service
|
||||
CreateMap<SCPSeries, DicomSeriesDTO>();
|
||||
|
||||
CreateMap<NoneDicomEdit, NoneDicomStudy>();
|
||||
|
||||
|
||||
|
||||
CreateMap<SubjectVisit, SubjectVisitMarkStudyDto>()
|
||||
.ForMember(d => d.SourceSubjectVisitId, u => u.MapFrom(u => u.Id))
|
||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(u => u.Subject.Code))
|
||||
.ForMember(d => d.DicomStudyList, u => u.MapFrom(s => s.StudyList))
|
||||
.ForMember(d => d.NoneDicomStudyList, u => u.MapFrom(s => s.NoneDicomStudyList.Where(t => t.IsReading)));
|
||||
|
||||
|
||||
|
||||
CreateMap<NoneDicomStudy, ImageMarkNoneDicomStudyBasicInfo>()
|
||||
.ForMember(d => d.SubjectVisitId, u => u.MapFrom(s => s.SubjectVisitId))
|
||||
.ForMember(d => d.FileCount, u => u.MapFrom(s => s.ImageLabelNoneDicomFileList.Count()))
|
||||
.ForMember(d => d.ReadingFileCount, u => u.MapFrom(s => s.ImageLabelNoneDicomFileList.Count()));
|
||||
|
||||
CreateMap<ImageMarkNoneDicomStudyBasicInfo, NoneDicomStudyBasicInfo>();
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +372,10 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
|
||||
public string ModuleTypeName { get; set; } = string.Empty;
|
||||
public string ModuleTypeNameCN { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 标准枚举
|
||||
/// </summary>
|
||||
public CriterionType? CriterionType { get; set; }
|
||||
public string SignText { get; set; } = string.Empty;
|
||||
|
||||
public decimal? VisitNum { get; set; }
|
||||
|
||||
@@ -1232,6 +1232,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
from leftObjectTypeIdtemp in ObjectTypeIdtemp.DefaultIfEmpty()
|
||||
select new FrontAuditConfigView()
|
||||
{
|
||||
ApplyCriterionList=data.ApplyCriterionList,
|
||||
IsShowParent = data.IsShowParent,
|
||||
ChildrenTypeId = data.ChildrenTypeId,
|
||||
Code = data.Code,
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
||||
public class InspectionService(IRepository<DataInspection> _dataInspectionRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<TrialSign> _trialSignRepository,
|
||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||
IRepository<IdentityUser> _identityUserRepository,
|
||||
IRepository<TrialAuditShow> _trialAuditShowRepository,
|
||||
IRepository<UserRole> _userRoleRepository,
|
||||
@@ -102,6 +103,9 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
||||
join trial in _trialRepository.Where().IgnoreQueryFilters() on data.TrialId equals trial.Id into trialtemp
|
||||
from leftrial in trialtemp.DefaultIfEmpty()
|
||||
|
||||
join readingQuestionCriterionTrial in _readingQuestionCriterionTrialRepository.Where().IgnoreQueryFilters() on data.TrialReadingCriterionId equals readingQuestionCriterionTrial.Id into readingQuestionCriterionTrialtemp
|
||||
from leftreadingQuestionCriterionTrial in readingQuestionCriterionTrialtemp.DefaultIfEmpty()
|
||||
|
||||
|
||||
join trialSite in _trialSiteRepository.Where().IgnoreQueryFilters() on data.TrialSiteId equals trialSite.Id into trialSitetemp
|
||||
from lefttrialSite in trialSitetemp.DefaultIfEmpty()
|
||||
@@ -136,6 +140,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
||||
{
|
||||
IsShow = lefttrialShow != null ? lefttrialShow.IsShow : leftfrontAuditConfig.IsDefaultChoice,
|
||||
CreateTime = data.CreateTime,
|
||||
CriterionType= leftreadingQuestionCriterionTrial==null? null: leftreadingQuestionCriterionTrial.CriterionType,
|
||||
CreateUserId = data.CreateUserId,
|
||||
ModuleTypeId = leftmoduleTypec.Id,
|
||||
BlindName = data.VisitTask.TaskBlindName,
|
||||
|
||||
@@ -112,7 +112,15 @@ namespace IRaCIS.Application.Contracts
|
||||
/// </summary>
|
||||
public DateTime? LastChangePassWordTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户协议Id
|
||||
/// </summary>
|
||||
public Guid? UserAgreementId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 隐私政策Id
|
||||
/// </summary>
|
||||
public Guid? PrivacyPolicyId { get; set; }
|
||||
}
|
||||
|
||||
public class MenuFuncTreeNodeView
|
||||
@@ -292,6 +300,8 @@ namespace IRaCIS.Application.Contracts
|
||||
public string OrganizationName { get; set; } = string.Empty;
|
||||
public Guid? UserType { get; set; }
|
||||
|
||||
public UserTypeEnum? UserTypeEnum { get; set; }
|
||||
|
||||
public bool? IsTestUser { get; set; }
|
||||
|
||||
public bool? IsZhiZhun { get; set; }
|
||||
@@ -313,6 +323,10 @@ namespace IRaCIS.Application.Contracts
|
||||
public DateTime? EndLastChangePassWordTime { get; set; }
|
||||
|
||||
public UserCeateSource? UserCeateSource { get; set; }
|
||||
|
||||
public Guid? AuditRecordId { get; set; }
|
||||
|
||||
public bool? IsAuditRecordUserSelect { get; set; }
|
||||
}
|
||||
|
||||
public class UserRoleInfoDTO
|
||||
@@ -352,6 +366,9 @@ namespace IRaCIS.Application.Contracts
|
||||
#endregion
|
||||
|
||||
public int JoinedTrialCount { get; set; }
|
||||
|
||||
|
||||
public bool IsAuditRecordUserSelect { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace IRaCIS.Core.Application.Service
|
||||
Task<IResponseOutput<UserAddedReturnDTO>> AddUser(UserCommand userAddModel);
|
||||
//Task<IResponseOutput> DeleteUser(Guid userId);
|
||||
//Task<UserDetailDTO> GetUser(Guid id);
|
||||
Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO param);
|
||||
//Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO param);
|
||||
//Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password);
|
||||
Task<IResponseOutput> VerifyMFACodeAsync(string Code);
|
||||
Task<IResponseOutput> VerifyMFACodeAsync(string Code,bool isRemember);
|
||||
|
||||
Task<IResponseOutput> SendMFAEmail(SendMfaCommand sendMfa);
|
||||
Task<UserBasicInfo> GetUserBasicInfo(Guid userId, string pwd);
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
public class UserService(IRepository<UserRole> _userRoleRepository,
|
||||
IMailVerificationService _mailVerificationService,
|
||||
IRepository<VerificationCode> _verificationCodeRepository,
|
||||
IRepository<UserAgreement> _userAgreementRepository,
|
||||
IRepository<TrialUserRole> _userTrialRepository,
|
||||
IRepository<UserLog> _userLogRepository,
|
||||
IRepository<UserPassWordLog> _userPassWordLogRepository,
|
||||
@@ -40,7 +41,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
IRepository<Doctor> _doctorRepository,
|
||||
ISearcher _searcher, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IUserService
|
||||
{
|
||||
|
||||
private ServiceVerifyConfigOption _serviceVerifyConfigConfig = _verifyConfig.CurrentValue;
|
||||
private SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||
|
||||
private async Task VerifyUserNameAsync(Guid? identityUserId, string userName)
|
||||
@@ -435,6 +436,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = identityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = identityUserId, OptType = UserOptType.UnloginModifyPasswoed }, true);
|
||||
|
||||
await _mailVerificationService.AfterUserModifyPasswordSendEmailAsync(identityUserId);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
@@ -481,6 +483,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = _userInfo.IdentityUserId, OptType = UserOptType.LoginModifyPassword }, true);
|
||||
|
||||
await _mailVerificationService.AfterUserModifyPasswordSendEmailAsync(_userInfo.IdentityUserId);
|
||||
|
||||
return ResponseOutput.Result(success);
|
||||
|
||||
|
||||
@@ -495,7 +499,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO inQuery)
|
||||
public async Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO inQuery, [FromServices] IRepository<AuditRecordIdentityUser> _auditRecordIdentityUserRepository)
|
||||
{
|
||||
|
||||
var userQueryable = _identityUserRepository.Where(x => x.UserRoleList.Any(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin))
|
||||
@@ -510,14 +514,36 @@ namespace IRaCIS.Core.Application.Service
|
||||
.WhereIf(inQuery.EndLastLoginTime != null, t => t.LastLoginTime <= inQuery.EndLastLoginTime)
|
||||
.WhereIf(inQuery.BeginLastChangePassWordTime != null, t => t.LastChangePassWordTime >= inQuery.BeginLastChangePassWordTime)
|
||||
.WhereIf(inQuery.EndLastChangePassWordTime != null, t => t.LastChangePassWordTime <= inQuery.EndLastChangePassWordTime)
|
||||
.WhereIf(inQuery.UserType != null, t => t.UserRoleList.Any(t => t.UserTypeId == inQuery.UserType && t.IsUserRoleDisabled==false))
|
||||
.WhereIf(inQuery.UserType != null, t => t.UserRoleList.Any(t => t.UserTypeId == inQuery.UserType && t.IsUserRoleDisabled == false))
|
||||
.WhereIf(inQuery.UserTypeEnum != null, t => t.UserRoleList.Any(t => t.UserTypeRole.UserTypeEnum == inQuery.UserTypeEnum && t.IsUserRoleDisabled == false))
|
||||
.WhereIf(inQuery.UserState != null, t => t.Status == inQuery.UserState)
|
||||
.WhereIf(inQuery.IsTestUser != null, t => t.IsTestUser == inQuery.IsTestUser)
|
||||
.WhereIf(inQuery.IsZhiZhun != null, t => t.IsZhiZhun == inQuery.IsZhiZhun)
|
||||
.WhereIf(inQuery.UserCeateSource != null, t => t.UserCeateSource == inQuery.UserCeateSource)
|
||||
.WhereIf(inQuery.AuditRecordId != null && inQuery.IsAuditRecordUserSelect == true, t => t.AuditRecordList.Any(t => t.AuditRecordId == inQuery.AuditRecordId))
|
||||
.WhereIf(inQuery.AuditRecordId != null && inQuery.IsAuditRecordUserSelect == false, t => !t.AuditRecordList.Any(t => t.AuditRecordId == inQuery.AuditRecordId))
|
||||
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
|
||||
|
||||
return await userQueryable.ToPagedListAsync(inQuery);
|
||||
var pageList = await userQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
|
||||
if (inQuery.AuditRecordId != null)
|
||||
{
|
||||
var selectIdList = _auditRecordIdentityUserRepository.Where(t => t.AuditRecordId == inQuery.AuditRecordId).Select(t => t.IdentityUserId).ToList();
|
||||
|
||||
foreach (var item in selectIdList)
|
||||
{
|
||||
var find = pageList.CurrentPageData.Where(t => t.Id == item).FirstOrDefault();
|
||||
|
||||
if (find != null)
|
||||
{
|
||||
find.IsAuditRecordUserSelect = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pageList;
|
||||
|
||||
}
|
||||
|
||||
@@ -800,9 +826,10 @@ namespace IRaCIS.Core.Application.Service
|
||||
/// 验证MFA 邮件
|
||||
/// </summary>
|
||||
/// <param name="Code"></param>
|
||||
/// <param name="isRemember"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task<IResponseOutput> VerifyMFACodeAsync(string Code)
|
||||
public async Task<IResponseOutput> VerifyMFACodeAsync(string Code, bool isRemember)
|
||||
{
|
||||
var identityUserId = _userInfo.IdentityUserId;
|
||||
|
||||
@@ -832,6 +859,13 @@ namespace IRaCIS.Core.Application.Service
|
||||
}
|
||||
}
|
||||
|
||||
if (isRemember)
|
||||
{
|
||||
await _fusionCache.SetAsync(CacheKeys.UserMFAVerifyPass(identityUserId, _userInfo.BrowserFingerprint), _userInfo.BrowserFingerprint, TimeSpan.FromMinutes(_serviceVerifyConfigConfig.UserMFAVerifyMinutes));
|
||||
|
||||
}
|
||||
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
@@ -863,8 +897,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
.WhereIf(inQuery.OptTypeList != null && inQuery.OptTypeList.Count > 0, t => inQuery.OptTypeList.Contains(t.OptType))
|
||||
.WhereIf(inQuery.BeginDate != null, t => t.CreateTime >= inQuery.BeginDate)
|
||||
.WhereIf(inQuery.EndDate != null, t => t.CreateTime <= inQuery.EndDate)
|
||||
.WhereIf(inQuery.IsLoginUncommonly != null , t => t.IsLoginUncommonly== inQuery.IsLoginUncommonly)
|
||||
|
||||
.WhereIf(inQuery.IsLoginUncommonly != null, t => t.IsLoginUncommonly == inQuery.IsLoginUncommonly)
|
||||
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginUserName), t => t.ActionUserName.Contains(inQuery.LoginUserName!))
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginFaildName), t => t.ActionUserName.Contains(inQuery.LoginFaildName!))
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.IP), t => t.IP.Contains(inQuery.IP!))
|
||||
@@ -895,9 +929,19 @@ namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
await _fusionCache.RemoveAsync(CacheKeys.UserToken(identityUserId));
|
||||
|
||||
var userName = await _userRoleRepository.Where(t => t.Id == userRoleId).Select(t => t.IdentityUser.UserName).FirstOrDefaultAsync();
|
||||
if (_identityUserRepository.Any(t => t.Id == identityUserId))
|
||||
{
|
||||
|
||||
var userName = await _userRoleRepository.Where(t => t.Id == userRoleId).Select(t => t.IdentityUser.UserName).FirstOrDefaultAsync();
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = identityUserId, ActionUserName = userName, OptType = UserOptType.LoginOut }, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = null, ActionUserName = _userInfo.UserName, OptType = UserOptType.LoginOut }, true);
|
||||
}
|
||||
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = identityUserId, ActionUserName = userName, OptType = UserOptType.LoginOut }, true);
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
@@ -922,7 +966,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
var password = loginDto.Password;
|
||||
|
||||
var emailConfig = _emailConfig.CurrentValue;
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN,SystemShortName=emailConfig.SystemShortName ,EmailRegexStr=emailConfig.EmailRegexStr};
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN, SystemShortName = emailConfig.SystemShortName, EmailRegexStr = emailConfig.EmailRegexStr };
|
||||
|
||||
|
||||
int maxFailures = _verifyConfig.CurrentValue.LoginMaxFailCount;
|
||||
@@ -991,7 +1035,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
//超过90天没修改密码
|
||||
|
||||
if (loginUser!= null&&_verifyConfig.CurrentValue.IsNeedChangePassWord && loginUser.LastChangePassWordTime != null && DateTime.Now.AddDays(-_verifyConfig.CurrentValue.ChangePassWordDays) > loginUser.LastChangePassWordTime.Value)
|
||||
if (loginUser != null && _verifyConfig.CurrentValue.IsNeedChangePassWord && loginUser.LastChangePassWordTime != null && DateTime.Now.AddDays(-_verifyConfig.CurrentValue.ChangePassWordDays) > loginUser.LastChangePassWordTime.Value)
|
||||
{
|
||||
loginUser.NeedChangePassWord = true;
|
||||
}
|
||||
@@ -1002,12 +1046,12 @@ namespace IRaCIS.Core.Application.Service
|
||||
UserOptType.LoginLockedAccount
|
||||
};
|
||||
|
||||
var actionUserName= loginUser!= null ? loginUser.UserName : userName;
|
||||
var actionUserName = loginUser != null ? loginUser.UserName : userName;
|
||||
|
||||
var lastLoginIPRegion = await _userLogRepository.Where(t => t.ActionUserName == actionUserName && userOptTypes.Contains(t.OptType))
|
||||
.OrderByDescending(t => t.CreateTime).Select(t => t.IPRegion).FirstOrDefaultAsync();
|
||||
|
||||
if (lastLoginIPRegion != string.Empty)
|
||||
if (lastLoginIPRegion != null && lastLoginIPRegion != string.Empty)
|
||||
{
|
||||
// 与上一次区域不一致
|
||||
//if (SplitAndConcatenate(existUserLoginInfo.LastLoginIP) != SplitAndConcatenate(iPRegion))
|
||||
@@ -1022,7 +1066,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
//异地登录
|
||||
loginUser.LoginState = 2;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1058,6 +1102,53 @@ namespace IRaCIS.Core.Application.Service
|
||||
//登录成功 清除缓存
|
||||
await _fusionCache.SetAsync(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes));
|
||||
|
||||
// 记录同意用户协议以及隐私政策
|
||||
#region 记录同意用户协议以及隐私政策
|
||||
|
||||
var userAgreementList = await _userAgreementRepository.Where(t => t.IsCurrentVersion).OrderByDescending(t => t.CreateTime).ToListAsync();
|
||||
|
||||
var userAgreement = userAgreementList.FirstOrDefault(t => t.UserAgreementTypeEnum == UserAgreementType.UserAgreement);
|
||||
|
||||
if (userAgreement != null && loginUser.UserAgreementId != userAgreement.Id)
|
||||
{
|
||||
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
|
||||
{
|
||||
UserAgreementId = userAgreement.Id,
|
||||
});
|
||||
|
||||
var obj = new
|
||||
{
|
||||
UserAgreementTypeEnum = UserAgreementType.UserAgreement,
|
||||
FileVersion = userAgreement.FileVersion,
|
||||
UserAgreementId = userAgreement.Id,
|
||||
IsEn_Us = _userInfo.IsEn_Us,
|
||||
};
|
||||
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = loginUser.UserName, OptType = UserOptType.AcceptUserAgreement, JsonObj = obj.ToJsonStr() }, true);
|
||||
|
||||
}
|
||||
|
||||
var privacyCollection = userAgreementList.FirstOrDefault(t => t.UserAgreementTypeEnum == UserAgreementType.PrivacyCollection);
|
||||
|
||||
if (privacyCollection != null && loginUser.PrivacyPolicyId != privacyCollection.Id)
|
||||
{
|
||||
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
|
||||
{
|
||||
PrivacyPolicyId = privacyCollection.Id,
|
||||
});
|
||||
|
||||
var obj = new
|
||||
{
|
||||
UserAgreementTypeEnum = UserAgreementType.PrivacyCollection,
|
||||
FileVersion = privacyCollection.FileVersion,
|
||||
UserAgreementId = privacyCollection.Id
|
||||
};
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = loginUser.UserName, OptType = UserOptType.AcceptPrivacyPolicy, JsonObj = obj.ToJsonStr() }, true);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = loginUser.UserName, OptType = UserOptType.Login, IsLoginUncommonly = isLoginUncommonly }, true);
|
||||
|
||||
@@ -1085,9 +1176,16 @@ namespace IRaCIS.Core.Application.Service
|
||||
if (_verifyConfig.CurrentValue.OpenLoginMFA)
|
||||
{
|
||||
|
||||
//MFA 发送邮件
|
||||
if ((await _fusionCache.GetOrDefaultAsync(CacheKeys.UserMFAVerifyPass(identityUserId, _userInfo.BrowserFingerprint), "")) == _userInfo.BrowserFingerprint)
|
||||
{
|
||||
userLoginReturnModel.IsMFA = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//MFA 发送邮件
|
||||
|
||||
userLoginReturnModel.IsMFA = true;
|
||||
userLoginReturnModel.IsMFA = true;
|
||||
}
|
||||
|
||||
var email = userLoginReturnModel.BasicInfo.EMail;
|
||||
|
||||
@@ -1098,9 +1196,10 @@ namespace IRaCIS.Core.Application.Service
|
||||
//修改密码 || 90天修改密码再mfa 之前
|
||||
if (userLoginReturnModel.BasicInfo.IsFirstAdd || userLoginReturnModel.BasicInfo.NeedChangePassWord)
|
||||
{
|
||||
//移动到上面去了
|
||||
//userLoginReturnModel.JWTStr = _tokenService.GetToken(userLoginReturnModel.BasicInfo);
|
||||
}
|
||||
else
|
||||
else if (userLoginReturnModel.IsMFA == true)
|
||||
{
|
||||
//正常登录才发送邮件
|
||||
await SendMFAEmail(new SendMfaCommand() { IdentityUserId = identityUserId, MFAType = UserMFAType.Login });
|
||||
|
||||
@@ -55,6 +55,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public string Modality { get; set; } = string.Empty;
|
||||
public DateTime ImageDate { get; set; }
|
||||
public string ModifyReason { get; set; }
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
}
|
||||
|
||||
///<summary> NoneDicomStudyAddOrEdit 列表查询参数模型</summary>
|
||||
@@ -81,6 +83,8 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public string VideoUrl { get; set; } = string.Empty;
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
|
||||
public string BodyPart { get; set; } = String.Empty;
|
||||
|
||||
public string ModifyReason { get; set; }
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +41,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
|
||||
|
||||
public string BodyPart { get; set; } = String.Empty;
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class QCQuestionAnswerCommand
|
||||
@@ -144,44 +148,25 @@ namespace IRaCIS.Core.Application.Contracts.DTO
|
||||
}
|
||||
|
||||
|
||||
public class GetUserUploadFileDto/*: ConsistencyCheckFile*/
|
||||
public class GetUserUploadFileDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名称
|
||||
/// </summary>
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 相对路径
|
||||
/// </summary>
|
||||
public string RelativePath { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建人
|
||||
/// </summary>
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 项目ID
|
||||
/// </summary>
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者名称
|
||||
/// </summary>
|
||||
public string CreateUserName { get; set; }
|
||||
|
||||
#region 一致性核查额外增加字段
|
||||
|
||||
public EDCCheckState? CheckState { get; set; }
|
||||
|
||||
public string ResultPath { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -427,6 +412,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
|
||||
|
||||
public bool IsCompleteClinicalData { get; set; }
|
||||
|
||||
public string BodyPartForEditOther { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class QASeriesInfoDto
|
||||
|
||||
@@ -518,7 +518,11 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public int? CheckWaitReplyCount { get; set; }
|
||||
|
||||
public string SuspendReason { get; set; }
|
||||
|
||||
public string Reason { get; set; }
|
||||
|
||||
public string ExportReason => Status == SubjectStatus.OutOfVisit ? Reason : (Status == SubjectStatus.EndOfVisit ? SuspendReason : "");
|
||||
}
|
||||
|
||||
|
||||
@@ -1144,7 +1148,9 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
|
||||
public class SelftAnalysisExport : AnalysisExortCommon
|
||||
{
|
||||
//自身一致性分析任务特有
|
||||
//自身
|
||||
//
|
||||
//任务特有
|
||||
|
||||
[DictionaryTranslateAttribute("YesOrNo")]
|
||||
public bool? IsAnalysisDiffToOriginalData { get; set; }
|
||||
@@ -1795,7 +1801,7 @@ namespace IRaCIS.Core.Application.Contracts
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
[DictionaryTranslateAttribute("Subject_Visit_Status")]
|
||||
public SubjectStatus SubjectStatus { get; set; }
|
||||
public SubjectStatus SubjectStatus { get; set; }
|
||||
public string SubjectCode { get; set; } = String.Empty;
|
||||
|
||||
public String TrialSiteCode { get; set; } = String.Empty;
|
||||
|
||||
@@ -767,9 +767,9 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<GetUserUploadFileDto>> GetConsistencyCheckFile(GetConsistencyCheckFileInDto inQuery, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||
public async Task<PageOutput<GetUserUploadFileDto>> GetConsistencyCheckFileList(GetConsistencyCheckFileInDto inQuery, [FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||
{
|
||||
var query = _inspectionFileRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||
var query = _inspectionFileRepository.Where(t => t.TrialId == inQuery.TrialId && (t.CheckState == EDCCheckState.Success || t.CheckState == EDCCheckState.Failed))
|
||||
.ProjectTo<GetUserUploadFileDto>(_mapper.ConfigurationProvider);
|
||||
|
||||
return await query.ToPagedListAsync(inQuery);
|
||||
|
||||
@@ -541,6 +541,7 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
|
||||
sv.CheckUserId = _userInfo.UserRoleId;
|
||||
sv.CheckState = CheckStateEnum.CVPassed;
|
||||
sv.CheckTime = DateTime.Now;
|
||||
|
||||
sv.ReadingStatus = ReadingStatusEnum.TaskAllocate;
|
||||
|
||||
@@ -1049,11 +1050,15 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
}
|
||||
else
|
||||
{
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.Id == updateModalityCommand.SubjectVisitId && t.SubmitState == SubmitStateEnum.Submitted && !t.QCChallengeList.Any(c => c.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload)))
|
||||
if (!_dicomStudyRepository.Where(t => t.Id == updateModalityCommand.Id).Any(t => t.CreateTime > t.SubjectVisit.SubmitTime))
|
||||
{
|
||||
//---提交之后,不允许修改!
|
||||
throw new BusinessValidationFailedException(_localizer["QCOperation_NoModifyAfterSubmit"]);
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.Id == updateModalityCommand.SubjectVisitId && t.SubmitState == SubmitStateEnum.Submitted && !t.QCChallengeList.Any(c => c.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload)))
|
||||
{
|
||||
//---提交之后,不允许修改!
|
||||
throw new BusinessValidationFailedException(_localizer["QCOperation_NoModifyAfterSubmit"]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1066,6 +1071,7 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
|
||||
|
||||
study.BodyPartForEdit = updateModalityCommand.BodyPart;
|
||||
study.BodyPartForEditOther = updateModalityCommand.BodyPartForEditOther;
|
||||
|
||||
study.ModalityForEdit = updateModalityCommand.Modality;
|
||||
study.StudyName = updateModalityCommand.StudyName;
|
||||
@@ -1126,13 +1132,19 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId)
|
||||
{
|
||||
|
||||
//提交了 但是IQC同意的时候 是可以删除的 | 普通提交后也不能删除
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
|
||||
(!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
|
||||
if (!_dicomStudyRepository.Where(t => ids.Contains(t.Id)).All(t => t.CreateTime > t.SubjectVisit.SubmitTime))
|
||||
{
|
||||
//---CRC已经提交,不允许删除。
|
||||
return ResponseOutput.NotOk(_localizer["QCOperation_CrcNoDelete"]);
|
||||
//提交了 但是IQC同意的时候 是可以删除的 | 普通提交后也不能删除
|
||||
if (await _subjectVisitRepository.AnyAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
|
||||
(!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
|
||||
{
|
||||
//---CRC已经提交,不允许删除。
|
||||
return ResponseOutput.NotOk(_localizer["QCOperation_CrcNoDelete"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var waitDeleteStudyList = await _dicomStudyRepository.Where(x => ids.Contains(x.Id), false, true).ToListAsync();
|
||||
|
||||
foreach (var item in waitDeleteStudyList)
|
||||
@@ -1963,6 +1975,7 @@ namespace IRaCIS.Core.Application.Image.QA
|
||||
SubjectVisitId = dbSubjectVisit.Id,
|
||||
ModuleName = $"G-{dbSubjectVisit.VisitName}",
|
||||
ModuleType = ModuleTypeEnum.Global,
|
||||
ReadModuleAddTypeEnum= dbSubjectVisit.PDState == PDStateEnum.PDProgress? ReadModuleAddType.PDConfirmation : ReadModuleAddType.FinalVisit,
|
||||
IsUrgent = dbSubjectVisit.IsUrgent,
|
||||
TrialId = dbSubjectVisit.TrialId,
|
||||
SubjectId = dbSubjectVisit.SubjectId
|
||||
|
||||
@@ -679,8 +679,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
;
|
||||
|
||||
// 一致性核查文件
|
||||
CreateMap<InspectionFile, GetUserUploadFileDto>()
|
||||
.ForMember(d => d.CreateUserName, u => u.MapFrom(t => t.CreateUserRole.FullName));
|
||||
CreateMap<InspectionFile, GetUserUploadFileDto>();
|
||||
|
||||
|
||||
//CRC 质疑列表
|
||||
|
||||
@@ -43,6 +43,87 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
}
|
||||
|
||||
public class GetReadModulePageListInDto : PageInput
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid TrialReadingCriterionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片期名称
|
||||
/// </summary>
|
||||
public string ModuleName { get; set; } = string.Empty;
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public Guid? TrialSiteId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 阅片配置的类型
|
||||
/// </summary>
|
||||
public ReadingSetType? ReadingSetType { get; set; }
|
||||
|
||||
public ReadModuleAddType? ReadModuleAddTypeEnum { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetReadModulePageListOutDto
|
||||
{
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片期类型
|
||||
/// </summary>
|
||||
public ReadingSetType ReadingSetType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片期名称
|
||||
/// </summary>
|
||||
public string ModuleName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 中心编号
|
||||
/// </summary>
|
||||
public string SiteCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 受试者编号
|
||||
/// </summary>
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访视名称
|
||||
/// </summary>
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 最晚拍片日期
|
||||
/// </summary>
|
||||
public DateTime? LatestScanDate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 来源
|
||||
/// </summary>
|
||||
public ReadModuleAddType ReadModuleAddTypeEnum { get; set; } = ReadModuleAddType.Normal;
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成任务
|
||||
/// </summary>
|
||||
public bool IsGenerateTask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成任务时间
|
||||
/// </summary>
|
||||
public DateTime? GenerateTaskTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class GetSubjectReadVisitsOutDto
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
@@ -308,6 +308,43 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public string OverallEfficacy { get; set; }
|
||||
}
|
||||
|
||||
public class FrontGetSiteVisitForTumorEvaluationInDto
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
public int NumberOfDaysBetween { get; set; }
|
||||
}
|
||||
|
||||
public class FrontGetSiteVisitForTumorEvaluationOutDto
|
||||
{
|
||||
public List<FrontGetSiteVisitForTumor> ResultList { get; set; }
|
||||
}
|
||||
|
||||
public class FrontGetSiteVisitForTumor
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public string TumorEvaluationResult { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class PCWGSiteVisitForTumor
|
||||
{
|
||||
public bool IsPD { get; set; }
|
||||
|
||||
public string? LastTaskResult { get; set; }
|
||||
|
||||
public Guid? LastTaskId { get; set; }
|
||||
}
|
||||
|
||||
public class SiteVisitForTumorEvaluationByDayOutDto
|
||||
{
|
||||
public string Result { get; set; } = string.Empty;
|
||||
|
||||
public string? LastTaskResult { get; set; }
|
||||
|
||||
public Guid? LastTaskId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 阅片计算Dto
|
||||
/// </summary>
|
||||
@@ -385,6 +422,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public string Answer { get; set; }
|
||||
|
||||
public string? PCWGInterimAnswer { get; set; }
|
||||
/// <summary>
|
||||
/// 问题名称
|
||||
/// </summary>
|
||||
|
||||
@@ -83,6 +83,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public string QuestionName { get; set; }
|
||||
|
||||
public string QuestionEnName { get; set; }
|
||||
|
||||
public bool IsCanEditPosition { get; set; } = false;
|
||||
|
||||
public string BlindName { get; set; }
|
||||
@@ -136,6 +138,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public string? ReportMark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 高亮问题的答案
|
||||
/// </summary>
|
||||
@@ -192,6 +199,16 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
}
|
||||
|
||||
public class Globalanswer
|
||||
{
|
||||
public Guid TaskId { get; set; }
|
||||
|
||||
public string Answer { get; set; }
|
||||
|
||||
public decimal VisitTaskNum { get; set; }
|
||||
|
||||
public Guid? QuestionId { get; set; }
|
||||
}
|
||||
|
||||
public class LesionDto
|
||||
{
|
||||
@@ -445,6 +462,50 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public string TaskBlindName { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
public class GetReportsChartDataOutDto
|
||||
{
|
||||
public List<string> VisitTaskNameList { get; set; }
|
||||
|
||||
public List<DateTime?> LatestScanDateList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
public ValueUnit? Unit { get; set; }
|
||||
|
||||
public List<ReportChartData> ChartDataList { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class ReportChartData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public List<string> Value { get; set; }
|
||||
}
|
||||
|
||||
public class GetReportsChartDataInDto
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid? QuestionId { get; set; }
|
||||
|
||||
public Guid? TableQuestionId { get; set; }
|
||||
|
||||
public decimal? RowIndex { get; set; }
|
||||
|
||||
public ReportChartType? ReportChartTypeEnum { get; set; }
|
||||
}
|
||||
public class SetReadKeyFileInDto
|
||||
{
|
||||
public Guid TrialCriterionId { get; set; }
|
||||
}
|
||||
public class ViewStudyPartInDto
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteSingleTableQuestionMarkInDto
|
||||
{
|
||||
@@ -855,12 +916,6 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public string? PicturePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 第一次添加的任务ID
|
||||
/// </summary>
|
||||
public decimal FristAddTaskNum { get; set; } = 0;
|
||||
|
||||
|
||||
public SplitOrMergeType? SplitOrMergeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -973,6 +1028,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// 问题分类
|
||||
/// </summary>
|
||||
public QuestionClassify? QuestionClassify { get; set; }
|
||||
|
||||
public bool IsDicomReading { get; set; } = true;
|
||||
}
|
||||
|
||||
public class GetReadingTableQuestionOutDto
|
||||
@@ -990,6 +1047,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public List<CrterionDictionaryGroup> CrterionDictionaryGroup { get; set; }
|
||||
|
||||
public CriterionType CriterionType { get; set; }
|
||||
|
||||
public bool IsPage { get; set; } = false;
|
||||
|
||||
public string Answer { get; set; }
|
||||
@@ -1006,6 +1065,10 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public int? PageShowOrder { get; set; }
|
||||
|
||||
public bool IsPreinstall { get {
|
||||
return this.TableQuestions.Questions.Any(x => x.IsPreinstall);
|
||||
} }
|
||||
|
||||
|
||||
|
||||
public List<TrialReadQuestionData> Childrens { get; set; }
|
||||
@@ -1033,6 +1096,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public string MergeName { get; set; }
|
||||
|
||||
public decimal FristAddTaskNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 病灶类型
|
||||
/// </summary>
|
||||
@@ -1265,6 +1330,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public string? PicturePath { get; set; }
|
||||
|
||||
public string? Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// NumberOfFrames
|
||||
/// </summary>
|
||||
@@ -1867,6 +1934,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public int? DigitPlaces { get; set; } = 2;
|
||||
|
||||
/// <summary>
|
||||
/// 是否查看检查部位
|
||||
/// </summary>
|
||||
public bool IsViewStudyPart { get; set; } = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 标准类型
|
||||
@@ -1931,6 +2003,10 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public bool IsConvertedTask { get; set; } = false;
|
||||
|
||||
public bool IsReadKeyFile { get; set; } = false;
|
||||
|
||||
public bool IsHaveKeyFile { get; set; } = false;
|
||||
|
||||
}
|
||||
|
||||
public class GetReadingImgInDto
|
||||
@@ -2350,8 +2426,6 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public bool? IsCanEditPosition { get; set; }
|
||||
|
||||
public decimal FristAddTaskNum { get; set; } = 0;
|
||||
|
||||
public decimal? WW { get; set; }
|
||||
|
||||
public decimal? WL { get; set; }
|
||||
@@ -2432,6 +2506,59 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public Guid VisitTaskId { get; set; }
|
||||
}
|
||||
|
||||
public class ChangePlottingScaleChangeAnswerInDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 标记id
|
||||
/// </summary>
|
||||
public Guid NoneDicomFileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否移除比例关系
|
||||
/// </summary>
|
||||
public bool IsRemovePlottingScale { get; set; } = false;
|
||||
|
||||
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string PicturePath { get; set; } = string.Empty;
|
||||
|
||||
public List<PlottingAnswerInfo> AnswerList { get; set; }
|
||||
}
|
||||
|
||||
public class PlottingAnswerInfo
|
||||
{
|
||||
public Guid? QuestionId { get; set; }
|
||||
public Guid? RowId { get; set; }
|
||||
|
||||
public Guid? TableQuestionId { get; set; }
|
||||
|
||||
public string Answer { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetNoneDicomMarkAndBindingInDto
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
}
|
||||
|
||||
public class GetNoneDicomMarkAndBindingOutDto
|
||||
{
|
||||
public List<AddNoneDicomMarkInDto> NoneDicomMarkList { get; set; }
|
||||
public List<BindingData> BindingList { get; set; }
|
||||
}
|
||||
|
||||
public class BindingData:BindingInfo
|
||||
{
|
||||
public Guid NoneDicomMarkId { get; set; }
|
||||
|
||||
public Guid? MarkId { get; set; }
|
||||
|
||||
public Guid VisitTaskId { get; set; }
|
||||
}
|
||||
|
||||
public class AddNoneDicomMarkInDto
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
@@ -2439,14 +2566,68 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public Guid VisitTaskId { get; set; }
|
||||
|
||||
public Guid? StudyId { get; set; }
|
||||
|
||||
public string MarkTool { get; set; }
|
||||
|
||||
|
||||
public string OrderMarkName { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 比例
|
||||
///// </summary>
|
||||
//public decimal? Proportion { get; set; }
|
||||
|
||||
public Guid? MarkId { get; set; }
|
||||
public Guid? NoneDicomFileId { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string PicturePath { get; set; } = string.Empty;
|
||||
|
||||
public string MeasureData { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
public class DeleteBindingInDto
|
||||
{
|
||||
public Guid BindingIdId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class AddNoneDicomMarkAndBinding
|
||||
{
|
||||
public Guid VisitTaskId { get; set; }
|
||||
public Guid? StudyId { get; set; }
|
||||
|
||||
public string MarkTool { get; set; }
|
||||
|
||||
public string OrderMarkName { get; set; }
|
||||
|
||||
public Guid? MarkId { get; set; }
|
||||
public Guid? NoneDicomFileId { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string PicturePath { get; set; } = string.Empty;
|
||||
|
||||
public string MeasureData { get; set; } = string.Empty;
|
||||
|
||||
public Guid QuestionId { get; set; }
|
||||
public Guid? RowId { get; set; }
|
||||
|
||||
public Guid? TableQuestionId { get; set; }
|
||||
|
||||
public string Answer { get; set; }
|
||||
}
|
||||
|
||||
public class BindingInfo
|
||||
{
|
||||
public Guid? QuestionId { get; set; }
|
||||
public Guid? RowId { get; set; }
|
||||
|
||||
public Guid? TableQuestionId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
@@ -203,6 +203,65 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public Guid TaskMedicalReviewId { get; set; }
|
||||
}
|
||||
|
||||
public class JointMedicalReviewI18n
|
||||
{
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:message:msg1
|
||||
/// </summary>
|
||||
public string Msg1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:message:msg2
|
||||
/// </summary>
|
||||
public string Msg2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:message:msg3
|
||||
/// </summary>
|
||||
public string Msg3 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:message:msg4
|
||||
/// </summary>
|
||||
public string Msg4 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:message:msg5
|
||||
/// </summary>
|
||||
public string Msg5 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:title:closeReasonEnum
|
||||
/// </summary>
|
||||
public string CloseReasonEnum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:title:isEndorse
|
||||
/// </summary>
|
||||
public string IsEndorse { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:title:reason
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// trials:medicalFeedback:title:isRequestReread
|
||||
/// </summary>
|
||||
public string IsRequestReread { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AuditAdvice
|
||||
/// </summary>
|
||||
public Dictionary<string, string> AuditAdvice { get; set; }
|
||||
|
||||
public Dictionary<string, string> MedicalDialogCloseEnum { get; set; }
|
||||
|
||||
public Dictionary<string, string> MedicalReviewDoctorUserIdea { get; set; }
|
||||
|
||||
public Dictionary<string, string> YesOrNo { get; set; }
|
||||
}
|
||||
|
||||
public class GetMedicalReviewDialogOutDto
|
||||
{
|
||||
|
||||
@@ -79,8 +79,73 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public Guid ReadingPeriodSetId { get; set; }
|
||||
}
|
||||
|
||||
public class IsChangeReadingPlanInDto
|
||||
{
|
||||
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片范围
|
||||
/// </summary>
|
||||
public ReadingScopeEnum ReadingScope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 中心ID
|
||||
/// </summary>
|
||||
public List<Guid> SiteIds { get; set; } = new List<Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// 项目ID
|
||||
/// </summary>
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 截止日期
|
||||
/// </summary>
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 截止访视
|
||||
/// </summary>
|
||||
public decimal? ExpirationVisitNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 访视计划ID
|
||||
/// </summary>
|
||||
public Guid? VisitStageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片期名称
|
||||
/// </summary>
|
||||
public string ReadingPeriodName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public ReadingSetType ReadingSetType { get; set; }
|
||||
|
||||
public Guid? TrialReadingCriterionId { get; set; }
|
||||
}
|
||||
|
||||
public class AddReadingPlanAndGenerateReadModuleInDto
|
||||
{
|
||||
public Guid ReadingPeriodSetId { get; set; }
|
||||
|
||||
public List<Guid> SubjectVisitIdList { get; set; } = new List<Guid>();
|
||||
}
|
||||
|
||||
public class SetBatchAddOrRemoveReadingPlanInDto
|
||||
{
|
||||
public List<Guid> SubjectVisitIdList { get; set; } = new List<Guid>();
|
||||
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
|
||||
public class PreviewTheReadingListInDto : PageInput
|
||||
{
|
||||
|
||||
public Guid? ReadingPeriodSetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 阅片范围
|
||||
/// </summary>
|
||||
@@ -123,7 +188,25 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
|
||||
public Guid? TrialReadingCriterionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 中心Id
|
||||
/// </summary>
|
||||
public Guid? SiteId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 受试者Code
|
||||
/// </summary>
|
||||
public string SubjectCode { get; set; }=string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否加入阅片计划
|
||||
/// </summary>
|
||||
public bool? IsJoin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成阅片计划
|
||||
/// </summary>
|
||||
public bool? IsGenerate { get; set; }
|
||||
|
||||
}
|
||||
|
||||
@@ -185,6 +268,26 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public DateTime? EffectOfTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否加入阅片计划
|
||||
/// </summary>
|
||||
public bool? IsJoin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成阅片计划
|
||||
/// </summary>
|
||||
public bool? IsGenerate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否生成任务
|
||||
/// </summary>
|
||||
public bool? IsGenerateTask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成时间
|
||||
/// </summary>
|
||||
public DateTime? GeneratedTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ReadingPeriodSetView
|
||||
@@ -313,6 +416,33 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public ReadingPeriodStatus IsTakeEffect { get; set; }
|
||||
}
|
||||
|
||||
public class AddReadModuleInDto
|
||||
{
|
||||
public Guid TrialReadingCriterionId { get; set; }
|
||||
|
||||
public Guid ReadingPeriodSetId { get; set; }
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public string ReadingPeriodName { get; set; }
|
||||
|
||||
public ReadingSetType ReadingSetType { get; set; }
|
||||
|
||||
public List<AddReadModuleVisitInfo> VisitInfoList { get; set; } = new List<AddReadModuleVisitInfo>();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class AddReadModuleVisitInfo
|
||||
{
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public Guid? ReadingPeriodPlanId { get; set; }
|
||||
public bool IsUrgent { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ReadingPeriodSetQuery : PageInput
|
||||
{
|
||||
|
||||
|
||||
@@ -324,6 +324,12 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public ImageMark? ImageMarkEnum { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否预设
|
||||
/// </summary>
|
||||
public bool IsPreinstall { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 影像工具
|
||||
/// </summary>
|
||||
@@ -425,6 +431,12 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// 数据来源
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
|
||||
@@ -513,6 +525,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public ValueOfType? ValueType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否预设
|
||||
/// </summary>
|
||||
public bool IsPreinstall { get; set; } = false;
|
||||
|
||||
public bool IsCopy { get; set; } = false;
|
||||
|
||||
|
||||
@@ -550,6 +567,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
@@ -1050,10 +1072,6 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public Guid ReadingQuestionCriterionTrialId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否复制病灶
|
||||
/// </summary>
|
||||
public bool IsCopyLesions { get; set; } = false;
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
@@ -1234,6 +1252,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 问题英文名称
|
||||
/// </summary>
|
||||
@@ -1345,6 +1368,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
@@ -1692,6 +1720,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
{
|
||||
public Guid QuestionId { get; set; }
|
||||
|
||||
|
||||
public string QuestionName { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
@@ -1809,6 +1838,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
[Comment("数据来源")]
|
||||
public DataSources DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
[Comment("限制编辑")]
|
||||
public LimitEdit LimitEdit { get; set; } = LimitEdit.None;
|
||||
|
||||
@@ -2215,6 +2249,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
@@ -2451,11 +2490,6 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public Guid? ClassifyQuestionId { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否复制病灶
|
||||
/// </summary>
|
||||
public bool IsCopyLesions { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 全局阅片显示类型
|
||||
/// </summary>
|
||||
@@ -2627,6 +2661,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
/// </summary>
|
||||
public DataSources? DataSource { get; set; } = DataSources.ManualEntry;
|
||||
|
||||
/// <summary>
|
||||
/// 显示图表类型
|
||||
/// </summary>
|
||||
public ShowChartType ShowChartTypeEnum { get; set; } = ShowChartType.NotShow;
|
||||
|
||||
/// <summary>
|
||||
/// 单位
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:46:41Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
|
||||
public class SystemCriterionKeyFileView : SystemCriterionKeyFileAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class SystemCriterionKeyFileAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public Guid SystemCriterionId { get; set; }
|
||||
}
|
||||
|
||||
public class SystemCriterionKeyFileQuery:PageInput
|
||||
{
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public Guid SystemCriterionId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:51:58Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
|
||||
public class TrialCriterionKeyFileView : TrialCriterionKeyFileAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TrialCriterionKeyFileAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public Guid TrialCriterionId { get; set; }
|
||||
}
|
||||
|
||||
public class TrialCriterionKeyFileQuery:PageInput
|
||||
{
|
||||
public string? FileName { get; set; }
|
||||
|
||||
|
||||
public Guid TrialCriterionId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace IRaCIS.Core.Application.ViewModel
|
||||
public class SetAutoCutNextTaskInDto
|
||||
{
|
||||
public bool AutoCutNextTask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否双屏
|
||||
/// </summary>
|
||||
public bool IsDoubleScreen { get; set; } = false;
|
||||
}
|
||||
|
||||
///<summary> UserWLTemplateAddOrEdit 列表查询参数模型</summary>
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
|
||||
public string TaskBlindName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否查看检查部位
|
||||
/// </summary>
|
||||
public bool IsViewStudyPart { get; set; } = false;
|
||||
|
||||
//任务来源访视Id 方便回更访视读片状态
|
||||
public Guid? SourceSubjectVisitId { get; set; }
|
||||
public Guid? SouceReadModuleId { get; set; }
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:46:41Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
namespace IRaCIS.Core.Application.Service.Reading.Interface;
|
||||
|
||||
public interface ISystemCriterionKeyFileService
|
||||
{
|
||||
|
||||
Task<PageOutput<SystemCriterionKeyFileView>> GetSystemCriterionKeyFileList(SystemCriterionKeyFileQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateSystemCriterionKeyFile(SystemCriterionKeyFileAddOrEdit addOrEditSystemCriterionKeyFile);
|
||||
|
||||
Task<IResponseOutput> DeleteSystemCriterionKeyFile(Guid systemCriterionKeyFileId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:51:58Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
namespace IRaCIS.Core.Application.Service.Reading.Interface;
|
||||
|
||||
public interface ITrialCriterionKeyFileService
|
||||
{
|
||||
|
||||
Task<PageOutput<TrialCriterionKeyFileView>> GetTrialCriterionKeyFileList(TrialCriterionKeyFileQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateTrialCriterionKeyFile(TrialCriterionKeyFileAddOrEdit addOrEditTrialCriterionKeyFile);
|
||||
|
||||
Task<IResponseOutput> DeleteTrialCriterionKeyFile(Guid trialCriterionKeyFileId);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,17 @@ using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore.Common;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
@@ -19,6 +24,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
public class ReadingMedicalReviewService(IRepository<ReadingMedicineTrialQuestion> _readingMedicineTrialQuestionRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<Internationalization> _internationalizationRepository,
|
||||
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
||||
IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository,
|
||||
|
||||
@@ -628,6 +635,167 @@ namespace IRaCIS.Core.Application.Service
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试获取医学审核对话拼接内容
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<string> TestGetJointMedicalReviewDialog(Guid id)
|
||||
{
|
||||
var dialog = await _readingMedicalReviewDialogRepository.Where(x => x.Id == id)
|
||||
.ProjectTo<GetMedicalReviewDialogOutDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return await JointMedicalReviewDialog(dialog,i18N);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取医学审核对话拼接内容
|
||||
/// </summary>
|
||||
/// <param name="record"></param>
|
||||
/// <param name="i18NAndDic"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<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>
|
||||
|
||||
@@ -68,8 +68,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingQuestion_CDISCCodeRepeat"]);
|
||||
}
|
||||
|
||||
if(inDto.QuestionList.Any(x=>x.ExportResult.Contains(ExportResult.CDISC)&&x.CDISCCode.IsNullOrEmpty())
|
||||
|| inDto.TableQuestionList.Any(x => x.ExportResult.Contains(ExportResult.CDISC) && x.CDISCCode.IsNullOrEmpty())
|
||||
if(inDto.QuestionList.Any(x=>x.ExportResult.Contains(ExportResult.NoneTumorCDISC)&&x.CDISCCode.IsNullOrEmpty())
|
||||
|| inDto.TableQuestionList.Any(x => x.ExportResult.Contains(ExportResult.NoneTumorCDISC) && x.CDISCCode.IsNullOrEmpty())
|
||||
)
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingQuestion_CDISCCodeCannotEmpty"]);
|
||||
@@ -847,7 +847,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新增修改想想项目表格问题
|
||||
/// 新增修改项目表格问题
|
||||
/// </summary>
|
||||
/// <param name="indto"></param>
|
||||
/// <returns></returns>
|
||||
@@ -861,6 +861,13 @@ namespace IRaCIS.Core.Application.Service
|
||||
//---问题编号重复
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingQuestion_IdDup"]);
|
||||
}
|
||||
if (indto.IsPreinstall)
|
||||
{
|
||||
if (await _readingTableQuestionTrialRepository.AnyAsync(x => x.ReadingQuestionId == indto.ReadingQuestionId && x.Id != indto.Id && x.IsPreinstall))
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingQuestion_OnlyOnePreinstall"]);
|
||||
}
|
||||
}
|
||||
|
||||
indto.ParentTriggerValue = string.Join(',', indto.ParentTriggerValueList);
|
||||
indto.RelevanceValue = string.Join(',', indto.RelevanceValueList);
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:46:38Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Application.Service.Reading.Interface;
|
||||
namespace IRaCIS.Core.Application.Service;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 系统标准阅片关键点文件服务
|
||||
/// </summary>
|
||||
/// <param name="_systemCriterionKeyFileRepository"></param>
|
||||
/// <param name="_mapper"></param>
|
||||
/// <param name="_userInfo"></param>
|
||||
/// <param name="_localizer"></param>
|
||||
[ApiExplorerSettings(GroupName = "Reading")]
|
||||
public class SystemCriterionKeyFileService(IRepository<SystemCriterionKeyFile> _systemCriterionKeyFileRepository,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, ISystemCriterionKeyFileService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统标准阅片关键点文件列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<SystemCriterionKeyFileView>> GetSystemCriterionKeyFileList(SystemCriterionKeyFileQuery inQuery)
|
||||
{
|
||||
|
||||
var systemCriterionKeyFileQueryable =_systemCriterionKeyFileRepository
|
||||
.Where(x=>x.SystemCriterionId==inQuery.SystemCriterionId)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.FileName),x=>x.FileName.Contains(inQuery.FileName))
|
||||
.ProjectTo<SystemCriterionKeyFileView>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList= await systemCriterionKeyFileQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新增或者修改系统标准阅片关键点文件
|
||||
/// </summary>
|
||||
/// <param name="addOrEditSystemCriterionKeyFile"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput> AddOrUpdateSystemCriterionKeyFile(SystemCriterionKeyFileAddOrEdit addOrEditSystemCriterionKeyFile)
|
||||
{
|
||||
// 在此处拷贝automapper 映射
|
||||
var entity = await _systemCriterionKeyFileRepository.InsertOrUpdateAsync(addOrEditSystemCriterionKeyFile, true);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统标准阅片关键点文件
|
||||
/// </summary>
|
||||
/// <param name="systemCriterionKeyFileId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{systemCriterionKeyFileId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteSystemCriterionKeyFile(Guid systemCriterionKeyFileId)
|
||||
{
|
||||
var success = await _systemCriterionKeyFileRepository.DeleteFromQueryAsync(t => t.Id == systemCriterionKeyFileId,true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-11-12 06:51:56Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Service.Reading.Interface;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
namespace IRaCIS.Core.Application.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 项目标准阅片关键点文件服务
|
||||
/// </summary>
|
||||
/// <param name="_trialCriterionKeyFileRepository"></param>
|
||||
/// <param name="_mapper"></param>
|
||||
/// <param name="_userInfo"></param>
|
||||
/// <param name="_localizer"></param>
|
||||
[ApiExplorerSettings(GroupName = "Reading")]
|
||||
public class TrialCriterionKeyFileService(IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, ITrialCriterionKeyFileService
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目标准阅片关键点文件列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<TrialCriterionKeyFileView>> GetTrialCriterionKeyFileList(TrialCriterionKeyFileQuery inQuery)
|
||||
{
|
||||
|
||||
var trialCriterionKeyFileQueryable =_trialCriterionKeyFileRepository
|
||||
.Where(x=>x.TrialCriterionId==inQuery.TrialCriterionId)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.FileName),x=>x.FileName.Contains(inQuery.FileName))
|
||||
.ProjectTo<TrialCriterionKeyFileView>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList= await trialCriterionKeyFileQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新增或者修改项目标准阅片关键点文件
|
||||
/// </summary>
|
||||
/// <param name="addOrEditTrialCriterionKeyFile"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> AddOrUpdateTrialCriterionKeyFile(TrialCriterionKeyFileAddOrEdit addOrEditTrialCriterionKeyFile)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var entity = await _trialCriterionKeyFileRepository.InsertOrUpdateAsync(addOrEditTrialCriterionKeyFile, true);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除项目标准阅片关键点文件
|
||||
/// </summary>
|
||||
/// <param name="trialCriterionKeyFileId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{trialCriterionKeyFileId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteTrialCriterionKeyFile(Guid trialCriterionKeyFileId)
|
||||
{
|
||||
var success = await _trialCriterionKeyFileRepository.DeleteFromQueryAsync(t => t.Id == trialCriterionKeyFileId,true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+203
-25
@@ -1,4 +1,5 @@
|
||||
using DocumentFormat.OpenXml;
|
||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||
using DocumentFormat.OpenXml.Office2019.Excel.ThreadedComments;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
@@ -22,6 +23,7 @@ using Newtonsoft.Json.Serialization;
|
||||
using NPOI.POIFS.Properties;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
using System.Linq;
|
||||
using ZiggyCreatures.Caching.Fusion;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
@@ -34,8 +36,10 @@ namespace IRaCIS.Core.Application.Service
|
||||
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<TaskInstance> _taskInstanceRepository,
|
||||
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
|
||||
IRepository<ReadingNoneDicomMark> _readingNoneDicomMarkRepository,
|
||||
IRepository<ReadingNoneDicomMarkBinding> _readingNoneDicomMarkBindingRepository,
|
||||
IRepository<UserLog> _userLogRepository,
|
||||
IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
|
||||
IRepository<ReadingOncologyTaskInfo> _readingOncologyTaskInfoRepository,
|
||||
@@ -57,6 +61,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
IRepository<OrganTrialInfo> _organTrialInfoRepository,
|
||||
IRepository<TrialDocument> _trialDocumentRepository,
|
||||
ILuganoCalculateService _luganoCalculateService,
|
||||
ILuganoWithoutPETCalculateService _LuganoWithoutPETCalculateService,
|
||||
//IRepository<ReadingCustomTag> _readingCustomTagRepository,
|
||||
IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMarkRepository,
|
||||
IRepository<ReadingTrialCriterionDictionary> _readingTrialCriterionDictionaryRepository,
|
||||
@@ -66,6 +71,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||
IRepository<ReadingQuestionSystem> _readingQuestionSystem,
|
||||
IRepository<CriterionKeyFileRead> _criterionKeyFileReadRepository,
|
||||
IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
|
||||
IRepository<NoneDicomStudyFile> _noneDicomStudyFileSystem,
|
||||
IGeneralCalculateService _generalCalculateService,
|
||||
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
|
||||
@@ -75,7 +82,34 @@ namespace IRaCIS.Core.Application.Service
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IReadingImageTaskService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取报告图表数据
|
||||
/// </summary>
|
||||
/// <param name=""></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<GetReportsChartDataOutDto> GetReportsChartData(GetReportsChartDataInDto inDto)
|
||||
{
|
||||
return await _readingCalculateService.GetReportsChartData(inDto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置已阅读关键文件
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> SetReadKeyFile(SetReadKeyFileInDto inDto)
|
||||
{
|
||||
await _criterionKeyFileReadRepository.AddAsync(new CriterionKeyFileRead()
|
||||
{
|
||||
IdentityUserId=_userInfo.IdentityUserId,
|
||||
TrialCriterionId= inDto.TrialCriterionId,
|
||||
});
|
||||
await _criterionKeyFileReadRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
#region 计算
|
||||
|
||||
@@ -92,6 +126,22 @@ namespace IRaCIS.Core.Application.Service
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 查看检查部位
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<bool> ViewStudyPart(ViewStudyPartInDto inDto)
|
||||
{
|
||||
await _visitTaskRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask()
|
||||
{
|
||||
IsViewStudyPart = true,
|
||||
});
|
||||
return await _visitTaskRepository.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除单个表格问题标记
|
||||
@@ -407,7 +457,8 @@ namespace IRaCIS.Core.Application.Service
|
||||
};
|
||||
|
||||
return await _trialDocumentRepository.Where(x => x.TrialId == inDto.TrialId
|
||||
&& x.TrialDocConfirmedUserList.Any(y => y.ConfirmUserId == _userInfo.UserRoleId && y.ConfirmTime != null)
|
||||
&& x.IsPublish
|
||||
//&& x.TrialDocConfirmedUserList.Any(y => y.ConfirmUserId == _userInfo.UserRoleId && y.ConfirmTime != null)
|
||||
&& x.NeedConfirmedUserTypeList.Any(y => y.NeedConfirmUserTypeId == _userInfo.UserTypeId))
|
||||
.WhereIf(userType == UserTypeEnum.IndependentReviewer, t => t.FileType.Code == "2" || t.FileType.Code == "6")
|
||||
.WhereIf(userType == UserTypeEnum.IQC, t => t.FileType.Code == "4" || t.FileType.Code == "5")
|
||||
@@ -1289,14 +1340,49 @@ namespace IRaCIS.Core.Application.Service
|
||||
var organIds = tableAnsweRowInfos.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList();
|
||||
var organList = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync();
|
||||
|
||||
var tableQuestionMarkList=new List<QuestionMarkInfo>();
|
||||
if (inDto.IsDicomReading)
|
||||
{
|
||||
// 删除病灶不删除病灶标记 所以查询question的时候 已经删除的病灶对应的标记的信息要排除
|
||||
var rowids = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).Select(x => x.Id).ToListAsync();
|
||||
|
||||
// 删除病灶不删除病灶标记 所以查询question的时候 已经删除的病灶对应的标记的信息要排除
|
||||
var rowids = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).Select(x => x.Id).ToListAsync();
|
||||
List<Guid?> rowidnull = rowids.Select(x => (Guid?)x).ToList();
|
||||
|
||||
List<Guid?> rowidnull = rowids.Select(x => (Guid?)x).ToList();
|
||||
tableQuestionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId != null
|
||||
).ProjectTo<QuestionMarkInfo>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
var markList = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId
|
||||
).ProjectTo<QuestionMarkInfo>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
var tableQuestionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId&&x.QuestionId!=null
|
||||
).ProjectTo<QuestionMarkInfo>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
var bingList= await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
|
||||
.ProjectTo<QuestionMarkInfo>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
|
||||
tableQuestionMarkList = markList
|
||||
.GroupJoin(
|
||||
bingList,
|
||||
l => l.MarkId,
|
||||
r => r.MarkId,
|
||||
(l, rs) => rs.DefaultIfEmpty()
|
||||
.Select(r =>
|
||||
{
|
||||
var info = l.Clone();
|
||||
info.QuestionId = r?.QuestionId;
|
||||
info.TableQuestionId = r?.TableQuestionId;
|
||||
info.RowId = r?.RowId;
|
||||
return info;
|
||||
}))
|
||||
.SelectMany(g => g).ToList();
|
||||
tableQuestionMarkList = tableQuestionMarkList.Where(x => x.QuestionId != null).ToList();
|
||||
|
||||
}
|
||||
|
||||
|
||||
var isHaveBindingQuestion=(await _readingQuestionTrialRepository.AnyAsync(x=>x.ReadingQuestionCriterionTrialId==taskInfo.TrialReadingCriterionId&&x.ImageToolAttribute!=string.Empty))
|
||||
|
||||
|| (await _readingTableQuestionTrialRepository.AnyAsync(x=>x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.ImageToolAttribute != string.Empty));
|
||||
|
||||
return (await GetReadingTableQuestion(
|
||||
new GetReadingTableQuestionOrAnswerInDto()
|
||||
@@ -1312,6 +1398,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
}
|
||||
), new
|
||||
{
|
||||
IsHaveBindingQuestion= isHaveBindingQuestion,
|
||||
IsBaseline = taskInfo.SourceSubjectVisit != null && taskInfo.SourceSubjectVisit.IsBaseLine,
|
||||
ReadingTaskState = taskInfo.ReadingTaskState,
|
||||
QuestionMarkInfoList = tableQuestionMarkList,
|
||||
@@ -1477,7 +1564,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
laskTaskId = Guid.NewGuid();
|
||||
}
|
||||
|
||||
lastTaskTableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == laskTaskId).Include(x => x.ReadingTableQuestionTrial).ToListAsync();
|
||||
lastTaskTableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == laskTaskId).Include(x=>x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync();
|
||||
|
||||
|
||||
if (taskInfo.BeforeConvertedTaskId != null)
|
||||
@@ -1692,7 +1779,18 @@ namespace IRaCIS.Core.Application.Service
|
||||
answers.Add("IsCurrentTaskAdd", rowInfo == null ? false.ToString() : rowInfo.IsCurrentTaskAdd.ToString());
|
||||
answers.Add("SplitOrMergeLesionName", rowInfo == null ? string.Empty : rowInfo.SplitName.IsNullOrEmpty() ? rowInfo.MergeName : rowInfo.SplitName);
|
||||
answers.Add("SplitOrMergeType", rowInfo == null ? string.Empty : rowInfo.SplitOrMergeType == null ? string.Empty : ((int)rowInfo.SplitOrMergeType).ToString());
|
||||
answers.Add("LastTaskState", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
|
||||
switch (item.CriterionType)
|
||||
{
|
||||
case CriterionType.PCWG3:
|
||||
|
||||
answers.Add("LastTaskState", lastTaskTableAnswer.Where(n => n.ReadingQuestionTrial.OrderMark == item.OrderMark && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
break;
|
||||
default:
|
||||
answers.Add("LastTaskState", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
break;
|
||||
}
|
||||
|
||||
answers.Add("LastTaskMajorAxis", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.MajorAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
answers.Add("LastTaskShortAxis", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
answers.Add("BaseLineMajorAxis", baseLineTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.MajorAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty);
|
||||
@@ -1760,13 +1858,13 @@ namespace IRaCIS.Core.Application.Service
|
||||
QuestionMark.IsLymph,
|
||||
};
|
||||
|
||||
|
||||
List<QuestionMark?> needSetNa = new List<QuestionMark?>() { };
|
||||
|
||||
switch (taskInfo.TrialReadingCriterion.CriterionType)
|
||||
{
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
List<QuestionMark?> needSetNa = new List<QuestionMark?>()
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
needSetNa = new List<QuestionMark?>()
|
||||
{
|
||||
QuestionMark.LowPPDAddPercent,
|
||||
QuestionMark.NadirPPD,
|
||||
@@ -1802,10 +1900,6 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
|
||||
};
|
||||
tableAnswers.ForEach(x =>
|
||||
{
|
||||
x.Answer = needSetNa.Contains(x.QuestionMark) ? "NA" : x.Answer;
|
||||
});
|
||||
break;
|
||||
|
||||
case CriterionType.mRECISTHCC:
|
||||
@@ -1826,7 +1920,19 @@ namespace IRaCIS.Core.Application.Service
|
||||
x.RowIndex = newRowIndex;
|
||||
x.VisitTaskId = inDto.VisitTaskId;
|
||||
x.RowId = rowAnswer.Id;
|
||||
x.Answer = needSaveMark.Contains(x.QuestionMark) ? x.Answer : string.Empty;
|
||||
|
||||
var answer = string.Empty;
|
||||
if (needSaveMark.Contains(x.QuestionMark))
|
||||
{
|
||||
answer = x.Answer;
|
||||
}
|
||||
|
||||
if (needSetNa.Contains(x.QuestionMark))
|
||||
{
|
||||
answer = "NA";
|
||||
}
|
||||
|
||||
x.Answer = answer;
|
||||
});
|
||||
await _readingTableAnswerRowInfoRepository.AddAsync(rowAnswer);
|
||||
await _readingTableQuestionAnswerRepository.AddRangeAsync(_mapper.Map<List<ReadingTableQuestionAnswer>>(tableAnswers));
|
||||
@@ -1844,7 +1950,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task MergeLesion(MergeLesionInDto inDto)
|
||||
public async Task<IResponseOutput> MergeLesion(MergeLesionInDto inDto)
|
||||
{
|
||||
await VerifyTaskIsSign(inDto.VisitTaskId);
|
||||
await VerifyIsBaseLineTask(inDto.VisitTaskId);
|
||||
@@ -1887,6 +1993,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
switch (taskinfo.TrialReadingCriterion.CriterionType)
|
||||
{
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
await _luganoCalculateService.CalculateMergeTargetLesionStatus(new CalculateTargetLesionStatusInDto()
|
||||
{
|
||||
QuestionId = inDto.QuestionId,
|
||||
@@ -1894,7 +2001,17 @@ namespace IRaCIS.Core.Application.Service
|
||||
RowNumber = mergeRow.RowIndex,
|
||||
});
|
||||
break;
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
await _LuganoWithoutPETCalculateService.CalculateMergeTargetLesionStatus(new CalculateTargetLesionStatusInDto()
|
||||
{
|
||||
QuestionId = inDto.QuestionId,
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
RowNumber = mergeRow.RowIndex,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1920,6 +2037,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
// (无法评估 或者 状态为消失的非靶病灶) 并且不能是无法评估的病灶
|
||||
query = query.Where(x =>
|
||||
(x.MeasureData == string.Empty ||
|
||||
@@ -2223,9 +2341,9 @@ namespace IRaCIS.Core.Application.Service
|
||||
break;
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
// 先找到需要删除的
|
||||
|
||||
|
||||
foreach (var item in needDeleteMarkQuestionIds)
|
||||
{
|
||||
// 对于要删除的标记不能删除 要与问题解绑
|
||||
@@ -2557,6 +2675,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
switch (taskinfo.TrialReadingCriterion.CriterionType)
|
||||
{
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
if (deleteRowInfo.RowIndex % 1 != 0)
|
||||
{
|
||||
await _luganoCalculateService.CalculateTargetLesionStatus(new CalculateTargetLesionStatusInDto()
|
||||
@@ -2567,6 +2686,18 @@ namespace IRaCIS.Core.Application.Service
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
|
||||
if (deleteRowInfo.RowIndex % 1 != 0)
|
||||
{
|
||||
await _LuganoWithoutPETCalculateService.CalculateTargetLesionStatus(new CalculateTargetLesionStatusInDto()
|
||||
{
|
||||
QuestionId = inDto.QuestionId,
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
RowNumber = deleteRowInfo.RowIndex
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ResponseOutput.Ok(true);
|
||||
}
|
||||
@@ -2601,7 +2732,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
await VerifyTaskIsSign(inDto.VisitTaskId);
|
||||
if (inDto.InstanceId != null && inDto.IsDicomReading)
|
||||
{
|
||||
if (!(await _dicomInstanceRepository.AnyAsync(x => x.Id == inDto.InstanceId && x.SeriesId == inDto.SeriesId)))
|
||||
if ((!(await _dicomInstanceRepository.AnyAsync(x => x.Id == inDto.InstanceId && x.SeriesId == inDto.SeriesId))) && (!(await _taskInstanceRepository.AnyAsync(x => x.Id == inDto.InstanceId && x.SeriesId == inDto.SeriesId))))
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingImage_Idnotcorrespond"]);
|
||||
}
|
||||
@@ -2732,6 +2863,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
}
|
||||
break;
|
||||
case CriterionType.Lugano2014:
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
|
||||
var targetTablequestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion).ToListAsync();
|
||||
|
||||
@@ -3030,6 +3162,17 @@ namespace IRaCIS.Core.Application.Service
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
if (inDto.RowIndex % 1 != 0)
|
||||
{
|
||||
await _LuganoWithoutPETCalculateService.CalculateTargetLesionStatus(new CalculateTargetLesionStatusInDto()
|
||||
{
|
||||
QuestionId = inDto.QuestionId,
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
RowNumber = inDto.RowIndex
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -3131,10 +3274,11 @@ namespace IRaCIS.Core.Application.Service
|
||||
.WhereIf(taskInfo.SourceSubjectVisit.IsBaseLine, x => ((x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show) && (x.LimitEdit == LimitEdit.None || x.LimitEdit == LimitEdit.OnlyBaseLine)))
|
||||
.WhereIf(!taskInfo.SourceSubjectVisit.IsBaseLine, x => ((x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show) && (x.LimitEdit == LimitEdit.None || x.LimitEdit == LimitEdit.OnlyVisit)))
|
||||
.WhereIf(taskInfo.TrialReadingCriterion.CriterionType == CriterionType.PCWG3, x => x.QuestionType != QuestionType.SiteVisitForTumorEvaluation)
|
||||
|
||||
//.WhereIf(!criterion.IseCRFShowInDicomReading,x=>x.IsShowInDicom)
|
||||
.ToListAsync();
|
||||
|
||||
// 排除访视
|
||||
readingQuestionList = readingQuestionList.Where(x => !(x.LimitShow == LimitShow.ExcludeSomeVisits && x.ExcludeShowVisitList.Contains(taskInfo.VisitTaskNum))).ToList();
|
||||
|
||||
var answerQuestionIds = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.Answer != string.Empty).Select(x => x.ReadingQuestionTrialId).ToListAsync();
|
||||
|
||||
readingQuestionList = readingQuestionList.Where(x => !answerQuestionIds.Contains(x.Id)).ToList();
|
||||
@@ -3176,7 +3320,9 @@ namespace IRaCIS.Core.Application.Service
|
||||
|
||||
var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
|
||||
var isBaseline = await _subjectVisitRepository.Where(x => x.Id == taskInfo.SourceSubjectVisitId).Select(x => x.IsBaseLine).FirstOrDefaultAsync();
|
||||
var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.Type != "group"
|
||||
|
||||
|
||||
var readingQuestionList = await _readingQuestionTrialRepository.Where(x => !x.ExcludeShowVisitList.Contains(taskInfo.VisitTaskNum) &&x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.Type != "group"
|
||||
&& (x.IsJudgeQuestion || (x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show))
|
||||
).ToListAsync();
|
||||
if (isBaseline)
|
||||
@@ -3295,6 +3441,15 @@ namespace IRaCIS.Core.Application.Service
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingImage_IDMust"]);
|
||||
}
|
||||
|
||||
if (inDto.SubjectCode.IsNotNullOrEmpty() && inDto.SubjectId != null)
|
||||
{
|
||||
if (! (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == inDto.TrialReadingCriterionId
|
||||
&& x.SubjectId == inDto.SubjectId && (x.BlindSubjectCode == inDto.SubjectCode || x.Subject.Code == inDto.SubjectCode))))
|
||||
{
|
||||
throw new BusinessValidationFailedException(_localizer["ReadingImage_SubjectCodeError"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region 跳过阅片
|
||||
var clearSkipReadingCache = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId));
|
||||
@@ -3620,6 +3775,9 @@ namespace IRaCIS.Core.Application.Service
|
||||
task.ReadingVersionEnum = criterionInfo.ReadingVersionEnum;
|
||||
task.ReadingToolList = criterionInfo.ReadingToolList;
|
||||
task.IsExistUnprocessedFeedback = await _userFeedBackRepository.AnyAsync(x => x.VisitTaskId == task.VisitTaskId && x.State == 0);
|
||||
task.IsViewStudyPart= visitTaskInfo.ReadingCategory==ReadingCategory.Judge|| visitTaskInfo.IsViewStudyPart;
|
||||
task.IsReadKeyFile = await _criterionKeyFileReadRepository.AnyAsync(x => x.IdentityUserId == _userInfo.IdentityUserId && x.TrialCriterionId == task.TrialReadingCriterionId);
|
||||
task.IsHaveKeyFile = await _trialCriterionKeyFileRepository.AnyAsync(x => x.TrialCriterionId == task.TrialReadingCriterionId);
|
||||
// 添加默认答案
|
||||
if (inDto.VisitTaskId == null && visitTaskInfo.ReadingTaskState != ReadingTaskState.HaveSigned)
|
||||
{
|
||||
@@ -3650,18 +3808,20 @@ namespace IRaCIS.Core.Application.Service
|
||||
await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId);
|
||||
await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId);
|
||||
await _readingTaskQuestionMarkRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId);
|
||||
|
||||
await _readingNoneDicomMarkRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId);
|
||||
await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId);
|
||||
await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask()
|
||||
{
|
||||
ReadingTaskState = ReadingTaskState.WaitReading
|
||||
});
|
||||
await _visitTaskRepository.SaveChangesAsync();
|
||||
_userInfo.IsNotNeedInspection = true;
|
||||
await AddDefaultValueToTask(inDto.VisitTaskId);
|
||||
await _readingCalculateService.AddTaskLesionAnswerFromLastTask(new AddTaskLesionAnswerFromLastTaskInDto()
|
||||
{
|
||||
VisitTaskId = inDto.VisitTaskId
|
||||
});
|
||||
await AddDefaultValueToTask(inDto.VisitTaskId);
|
||||
|
||||
return new ResetReadingTaskOutDto() { };
|
||||
}
|
||||
/// <summary>
|
||||
@@ -3770,6 +3930,24 @@ namespace IRaCIS.Core.Application.Service
|
||||
private async Task SubmitTaskChangeState(Guid visitTaskId)
|
||||
{
|
||||
await VerifyTaskIsSign(visitTaskId);
|
||||
|
||||
var taskInfo=await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x=>x.TrialReadingCriterion).FirstNotNullAsync();
|
||||
// 如果是PCGW标准 则把中间答案赋值给正式答案
|
||||
if (taskInfo.TrialReadingCriterion.CriterionType == CriterionType.PCWG3)
|
||||
{
|
||||
var answerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTask.TaskState==TaskState.Effect&& x.VisitTask.SubjectId == taskInfo.SubjectId && x.VisitTask.ArmEnum == taskInfo.ArmEnum && x.PCWGInterimAnswer != null).ToListAsync();
|
||||
|
||||
foreach (var item in answerList)
|
||||
{
|
||||
await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x=>x.Id==item.Id, x => new ReadingTaskQuestionAnswer()
|
||||
{
|
||||
//这里已经筛选过 不为null了
|
||||
Answer = item.PCWGInterimAnswer,
|
||||
PCWGInterimAnswer = null,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
await _visitTaskRepository.UpdatePartialFromQueryAsync(visitTaskId, x => new VisitTask()
|
||||
{
|
||||
ReadingTaskState = ReadingTaskState.HaveSigned,
|
||||
|
||||
@@ -924,7 +924,12 @@ namespace IRaCIS.Core.Application.Service
|
||||
var noteEqual = false;
|
||||
foreach (var item in groupTasks)
|
||||
{
|
||||
if (item.TaskAnswerList.Count() != 2)
|
||||
// 裁判问题可以不必填
|
||||
if(item.TaskAnswerList.Count()==0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (item.TaskAnswerList.Count() != 2)
|
||||
{
|
||||
noteEqual = true;
|
||||
break;
|
||||
@@ -1013,14 +1018,14 @@ namespace IRaCIS.Core.Application.Service
|
||||
}
|
||||
else
|
||||
{
|
||||
var absoluteValue = (Math.Abs(value1 - value2)*100)/(value1<value2?value1:value2) ;
|
||||
var absoluteValue = (Math.Abs(value1 - value2) * 100) / (value1 < value2 ? value1 : value2);
|
||||
if (item.JudgeDifferenceType == JudgeDifferenceType.Greater)
|
||||
{
|
||||
noteEqual= absoluteValue > item.JudgeDifferenceValue;
|
||||
noteEqual = absoluteValue > item.JudgeDifferenceValue;
|
||||
}
|
||||
else if (item.JudgeDifferenceType == JudgeDifferenceType.AboveOrEqual)
|
||||
{
|
||||
noteEqual= absoluteValue >= item.JudgeDifferenceValue;
|
||||
noteEqual = absoluteValue >= item.JudgeDifferenceValue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
+319
-2
@@ -1,10 +1,13 @@
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using Amazon.Runtime.Internal.Auth;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore.Common;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
using System.Linq.Dynamic.Core;
|
||||
|
||||
@@ -32,6 +35,315 @@ namespace IRaCIS.Core.Application.Service
|
||||
return ResponseOutput.Ok(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存答案和非Dicom标记绑定关系
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> SaveAnswerAndBindingNoneDicomMark(AddNoneDicomMarkAndBinding inDto)
|
||||
{
|
||||
var visitTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
|
||||
// 说明要移除标记数据
|
||||
if (inDto.MeasureData == string.Empty)
|
||||
{
|
||||
// 先找到绑定关系
|
||||
var binding = await _readingNoneDicomMarkBindingRepository.Where(x =>
|
||||
x.VisitTaskId == inDto.VisitTaskId &&
|
||||
x.QuestionId == inDto.QuestionId &&
|
||||
x.RowId == inDto.RowId &&
|
||||
x.TableQuestionId == inDto.TableQuestionId).FirstOrDefaultAsync();
|
||||
if (binding != null)
|
||||
{
|
||||
if ((await _readingNoneDicomMarkBindingRepository.Where(x => x.NoneDicomMarkId == binding.NoneDicomMarkId).CountAsync()) == 1)
|
||||
{
|
||||
|
||||
await _readingNoneDicomMarkBindingRepository.DeleteFromQueryAsync(x => x.Id == binding.Id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 找到标记信息
|
||||
var mark = await _readingNoneDicomMarkRepository.Where(x => x.MarkId == inDto.MarkId).FirstOrDefaultAsync();
|
||||
if (mark != null)
|
||||
{
|
||||
if (mark.MeasureData != inDto.MeasureData || mark.Path != inDto.Path|| mark.OrderMarkName != inDto.OrderMarkName || mark.MarkTool != inDto.MarkTool)
|
||||
{
|
||||
await _readingNoneDicomMarkRepository.UpdatePartialFromQueryAsync(x => x.Id == mark.Id, u => new Domain.Models.ReadingNoneDicomMark()
|
||||
{
|
||||
MeasureData = inDto.MeasureData,
|
||||
MarkTool=inDto.MarkTool,
|
||||
OrderMarkName=inDto.OrderMarkName,
|
||||
Path = inDto.Path
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 添加标记信息
|
||||
mark = new ReadingNoneDicomMark()
|
||||
{
|
||||
Id = NewId.NextGuid(),
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
StudyId = inDto.StudyId,
|
||||
MarkTool = inDto.MarkTool,
|
||||
OrderMarkName = inDto.OrderMarkName,
|
||||
NoneDicomFileId = inDto.NoneDicomFileId,
|
||||
Path = inDto.Path,
|
||||
PicturePath = inDto.PicturePath,
|
||||
MeasureData = inDto.MeasureData,
|
||||
MarkId = inDto.MarkId
|
||||
};
|
||||
await _readingNoneDicomMarkRepository.AddAsync(mark);
|
||||
}
|
||||
|
||||
await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x =>
|
||||
x.VisitTaskId == inDto.VisitTaskId &&
|
||||
x.QuestionId == inDto.QuestionId &&
|
||||
x.RowId == inDto.RowId &&
|
||||
x.TableQuestionId == inDto.TableQuestionId);
|
||||
|
||||
await _readingNoneDicomMarkBindingRepository.AddAsync(new ReadingNoneDicomMarkBinding()
|
||||
{
|
||||
Id = NewId.NextGuid(),
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
QuestionId = inDto.QuestionId,
|
||||
RowId = inDto.RowId,
|
||||
TableQuestionId = inDto.TableQuestionId,
|
||||
NoneDicomMarkId = mark.Id,
|
||||
MarkId = mark.MarkId
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 处理答案
|
||||
|
||||
if (inDto.RowId == null)
|
||||
{
|
||||
await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId);
|
||||
await _readingTaskQuestionAnswerRepository.AddAsync(new ReadingTaskQuestionAnswer()
|
||||
{
|
||||
Id = NewId.NextGuid(),
|
||||
SubjectId = visitTask.SubjectId,
|
||||
Answer = inDto.Answer,
|
||||
ReadingQuestionTrialId = inDto.QuestionId,
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
TrialId = visitTask.TrialId
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowId == inDto.RowId&&x.TableQuestionId==inDto.TableQuestionId);
|
||||
|
||||
var rowinfo=await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId.Value).FirstNotNullAsync();
|
||||
await _readingTableQuestionAnswerRepository.AddAsync(new ReadingTableQuestionAnswer()
|
||||
{
|
||||
Id = NewId.NextGuid(),
|
||||
RowId = inDto.RowId.Value,
|
||||
Answer = inDto.Answer,
|
||||
QuestionId= inDto.QuestionId,
|
||||
TableQuestionId= inDto.TableQuestionId.Value,
|
||||
VisitTaskId = inDto.VisitTaskId,
|
||||
TrialId = visitTask.TrialId,
|
||||
RowIndex= rowinfo.RowIndex,
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
await _visitTaskRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改比例修改答案
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> ChangePlottingScaleChangeAnswer(ChangePlottingScaleChangeAnswerInDto inDto)
|
||||
{
|
||||
if (inDto.IsRemovePlottingScale)
|
||||
{
|
||||
await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == inDto.NoneDicomFileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var answerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync();
|
||||
|
||||
|
||||
|
||||
var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync();
|
||||
|
||||
|
||||
foreach (var item in inDto.AnswerList)
|
||||
{
|
||||
if (item.RowId == null)
|
||||
{
|
||||
var answer= answerList.Where(x => x.ReadingQuestionTrialId == item.QuestionId).FirstOrDefault();
|
||||
if (answer!=null)
|
||||
{
|
||||
await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(answer.Id, x => new ReadingTaskQuestionAnswer()
|
||||
{
|
||||
Answer = item.Answer
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var answer = tableAnswerList.Where(x => x.QuestionId == item.QuestionId&&x.RowId==item.RowId&&x.TableQuestionId==item.TableQuestionId).FirstOrDefault();
|
||||
if (answer != null)
|
||||
{
|
||||
await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(answer.Id, x => new ReadingTableQuestionAnswer()
|
||||
{
|
||||
Answer = item.Answer
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await _readingNoneDicomMarkRepository.UpdatePartialFromQueryAsync(x=>x.VisitTaskId==inDto.VisitTaskId&&x.Path==inDto.Path, x => new ReadingNoneDicomMark()
|
||||
{
|
||||
PicturePath = inDto.PicturePath
|
||||
});
|
||||
}
|
||||
|
||||
await _visitTaskRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改比例修改答案 现在弃用了
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="proportion"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<IResponseOutput> ChangePlottingScale(Guid? id, decimal proportion)
|
||||
{
|
||||
var markInfo = await _readingNoneDicomMarkRepository.Where(x => x.Id == id).Select(x => new
|
||||
{
|
||||
x.NoneDicomFileId,
|
||||
x.VisitTaskId
|
||||
}).FirstNotNullAsync();
|
||||
|
||||
var visitTask = await _visitTaskRepository.Where(x => x.Id == markInfo.VisitTaskId).Include(x=>x.TrialReadingCriterion).FirstNotNullAsync();
|
||||
|
||||
|
||||
var digitPlaces = visitTask.TrialReadingCriterion.DigitPlaces??0;
|
||||
|
||||
if (proportion == -1)
|
||||
{
|
||||
await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == markInfo.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == markInfo.NoneDicomFileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var bindingList= await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == markInfo.NoneDicomFileId)
|
||||
.ToListAsync();
|
||||
|
||||
List<string> ImageToolAttributeList = new List<string>()
|
||||
{
|
||||
"length",
|
||||
"perimeter",
|
||||
"area"
|
||||
};
|
||||
|
||||
var questionAnswerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId &&
|
||||
bindingList.Select(b => b.QuestionId).Contains(x.ReadingQuestionTrialId)
|
||||
&& ImageToolAttributeList.Contains(x.ReadingQuestionTrial.ImageToolAttribute)).Include(x=>x.ReadingQuestionTrial)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in questionAnswerList)
|
||||
{
|
||||
var answerValue = item.Answer.IsNullOrEmptyReturn0();
|
||||
switch (item.ReadingQuestionTrial.ImageToolAttribute)
|
||||
{
|
||||
case "length":
|
||||
case "perimeter":
|
||||
answerValue = answerValue * proportion;
|
||||
break;
|
||||
case "area":
|
||||
answerValue = answerValue * proportion * proportion;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(item.Id, x => new ReadingTaskQuestionAnswer()
|
||||
{
|
||||
Answer= decimal.Round(answerValue, digitPlaces).ToString("F" + digitPlaces.ToString())
|
||||
});
|
||||
}
|
||||
|
||||
var tableQuestionAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId &&
|
||||
bindingList.Select(b => b.TableQuestionId).Contains(x.TableQuestionId)
|
||||
&& ImageToolAttributeList.Contains(x.ReadingTableQuestionTrial.ImageToolAttribute)).Include(x => x.ReadingTableQuestionTrial)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in tableQuestionAnswerList)
|
||||
{
|
||||
var answerValue = item.Answer.IsNullOrEmptyReturn0();
|
||||
switch (item.ReadingTableQuestionTrial.ImageToolAttribute)
|
||||
{
|
||||
case "length":
|
||||
case "perimeter":
|
||||
answerValue = answerValue * proportion;
|
||||
break;
|
||||
case "area":
|
||||
answerValue = answerValue * proportion * proportion;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(item.Id, x => new ReadingTableQuestionAnswer()
|
||||
{
|
||||
Answer = decimal.Round(answerValue, digitPlaces).ToString("F" + digitPlaces.ToString())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除绑定关系
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> DeleteBinding(DeleteBindingInDto inDto)
|
||||
{
|
||||
await _readingNoneDicomMarkBindingRepository.DeleteFromQueryAsync(x =>x.Id==inDto.BindingIdId, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取非Dicom标记和绑定关系
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<GetNoneDicomMarkAndBindingOutDto> GetNoneDicomMarkAndBinding(GetNoneDicomMarkAndBindingInDto inDto)
|
||||
{
|
||||
GetNoneDicomMarkAndBindingOutDto result=new GetNoneDicomMarkAndBindingOutDto ();
|
||||
result.NoneDicomMarkList = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
|
||||
.ProjectTo<AddNoneDicomMarkInDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
result.BindingList = await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
|
||||
.ProjectTo<BindingData>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加非Dicom标记
|
||||
@@ -41,7 +353,12 @@ namespace IRaCIS.Core.Application.Service
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> AddNoneDicomMark(AddNoneDicomMarkInDto inDto)
|
||||
{
|
||||
var entity = await _readingNoneDicomMarkRepository.InsertOrUpdateAsync(inDto, true);
|
||||
|
||||
var entity = await _readingNoneDicomMarkRepository.InsertOrUpdateAsync(inDto,true);
|
||||
|
||||
|
||||
|
||||
await _visitTaskRepository.SaveChangesAsync();
|
||||
return ResponseOutput.Ok(entity.Id);
|
||||
}
|
||||
|
||||
|
||||
@@ -826,6 +826,42 @@ namespace IRaCIS.Core.Application.Service
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取读片模块分页列表 //加了标准参数
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<GetReadModulePageListOutDto>> GetReadModulePageList(GetReadModulePageListInDto inDto)
|
||||
{
|
||||
|
||||
var readModuleQueryable = _readModuleRepository
|
||||
.Where(x => x.TrialReadingCriterionId == inDto.TrialReadingCriterionId)
|
||||
.WhereIf(inDto.ReadModuleAddTypeEnum != null, x => x.ReadModuleAddTypeEnum == inDto.ReadModuleAddTypeEnum)
|
||||
.WhereIf(inDto.ReadingSetType != null, x => x.ReadingSetType == inDto.ReadingSetType)
|
||||
.WhereIf(inDto.SubjectCode.IsNotNullOrEmpty(), x => x.Subject.Code.Contains(inDto.SubjectCode))
|
||||
.WhereIf(inDto.VisitName.IsNotNullOrEmpty(), x => x.SubjectVisit.VisitName.Contains(inDto.VisitName))
|
||||
.WhereIf(inDto.ModuleName.IsNotNullOrEmpty(), x => x.ModuleName.Contains(inDto.ModuleName))
|
||||
.WhereIf(inDto.TrialSiteId != null, x => x.Subject.TrialSiteId == inDto.TrialSiteId)
|
||||
.ProjectTo<GetReadModulePageListOutDto>(_mapper.ConfigurationProvider);
|
||||
|
||||
|
||||
var pageList = await readModuleQueryable.ToPagedListAsync(inDto);
|
||||
var ids = pageList.CurrentPageData.Select(x => x.Id as Guid?).ToList();
|
||||
|
||||
|
||||
var taskList=await _visitTaskRepository.Where(x => ids.Contains(x.SouceReadModuleId)).ToListAsync();
|
||||
|
||||
pageList.CurrentPageData.ForEach(x =>
|
||||
{
|
||||
|
||||
x.IsGenerateTask= taskList.Any(t => t.SouceReadModuleId == x.Id);
|
||||
x.GenerateTaskTime= taskList.Any(t => t.SouceReadModuleId == x.Id)? taskList.Where(t => t.SouceReadModuleId == x.Id).OrderByDescending(t => t.CreateTime).Select(t => t.CreateTime).FirstOrDefault():null;
|
||||
|
||||
});
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取单条详情信息
|
||||
@@ -962,6 +998,7 @@ namespace IRaCIS.Core.Application.Service
|
||||
SubjectId = dto.SubjectId,
|
||||
ModuleType = moduleType,
|
||||
IsUrgent = visit.IsUrgent,
|
||||
ReadModuleAddTypeEnum=ReadModuleAddType.Normal,
|
||||
ModuleName = dto.Name,
|
||||
SubjectVisitId = visit.Id,
|
||||
ReadingSetType = dto.ReadingSetType,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user