Compare commits

..

44 Commits

Author SHA1 Message Date
hang a47ac76729 复核指派bug修改
continuous-integration/drone/push Build is passing
2025-07-22 15:29:09 +08:00
hang f86a88332c 复核稽查修改016
continuous-integration/drone/push Build is passing
2025-07-18 13:15:23 +08:00
hang f6be5e4355 复核稽查修改015
continuous-integration/drone/push Build is failing
2025-07-18 13:04:58 +08:00
hang 8deeb0290a 复核稽查修改014
continuous-integration/drone/push Build is failing
2025-07-18 12:17:55 +08:00
hang fb6231373b 复核稽查修改013
continuous-integration/drone/push Build is passing
2025-07-18 11:34:13 +08:00
hang a407313a95 复核稽查修改012
continuous-integration/drone/push Build is passing
2025-07-18 09:25:56 +08:00
hang b1806d2eff 复核稽查修改011
continuous-integration/drone/push Build is passing
2025-07-17 17:25:45 +08:00
hang 19351f34e1 复核稽查修改010
continuous-integration/drone/push Build is passing
2025-07-17 17:10:06 +08:00
hang e0f708082d 复核稽查修改009
continuous-integration/drone/push Build is passing
2025-07-17 16:49:20 +08:00
hang 44464a809d 复核稽查修改008
continuous-integration/drone/push Build is passing
2025-07-17 15:26:28 +08:00
hang c7c01b7ba3 复核稽查修改007
continuous-integration/drone/push Build is passing
2025-07-17 15:08:11 +08:00
hang 38b71d5267 复核稽查修改006
continuous-integration/drone/push Build is passing
2025-07-17 14:00:03 +08:00
hang 3950a3453a 复核稽查修改005
continuous-integration/drone/push Build is passing
2025-07-17 13:26:44 +08:00
hang 7aa59da586 复核稽查修改004
continuous-integration/drone/push Build is passing
2025-07-17 11:51:41 +08:00
hang 9b2fbdb13f 复核稽查修改003
continuous-integration/drone/push Build is passing
2025-07-17 11:28:47 +08:00
hang c98b9e1bd4 复核稽查修改002
continuous-integration/drone/push Build is passing
2025-07-17 11:08:02 +08:00
hang 9522461508 复核稽查修改
continuous-integration/drone/push Build is passing
2025-07-17 10:34:15 +08:00
hang 5bb99180b6 修改复核-退回-003
continuous-integration/drone/push Build is passing
2025-07-16 17:59:42 +08:00
hang 62ec1e4955 修改复核查询接口-002
continuous-integration/drone/push Build is passing
2025-07-16 17:34:09 +08:00
hang 58e1af24c9 修改复核查询接口-001
continuous-integration/drone/push Build is passing
2025-07-16 16:30:03 +08:00
hang a7394e7119 指派其他质控-uat-13
continuous-integration/drone/push Build is passing
2025-07-16 10:30:55 +08:00
hang a93d81de0d 指派其他质控-uat-12 2025-07-16 10:30:51 +08:00
hang 6aafe02c6c 指派其他质控-uat-11 2025-07-16 10:30:48 +08:00
hang 1511ef1608 修改QC复核 -二次提交-uat-10 2025-07-16 10:30:43 +08:00
hang 1141439c8e 修改QC复核 -二次提交-uat-9 2025-07-16 10:30:32 +08:00
hang 559663082b 修改QC复核 -二次提交-uat-8 2025-07-16 10:26:30 +08:00
hang 3a298518f9 修改QC复核 -二次提交-uat-7 2025-07-16 10:26:25 +08:00
hang 7f20232401 修改QC复核 -二次提交-uat-6 2025-07-16 10:26:21 +08:00
hang 20b0849b40 修改QC复核 -二次提交-uat-5 2025-07-16 10:26:16 +08:00
hang db951e9195 修改QC复核 -二次提交-uat-4 2025-07-16 10:26:13 +08:00
hang d5d78a99d2 QC复核 -二次提交-uat-3 2025-07-16 10:26:08 +08:00
hang 1609a7a88a QC复核 -二次提交-uat-3 2025-07-16 10:26:03 +08:00
hang 289831fce8 QC复核 -二次提交-uat-2 2025-07-16 10:25:59 +08:00
hang dde058be18 QC 审核提交--迁移uat 2025-07-16 10:25:26 +08:00
hang be8b730ee4 返回文件大小
continuous-integration/drone/push Build is passing
2025-07-14 15:00:36 +08:00
hang 28360861aa 修改subject 随机阅片下载影像重阅bug
continuous-integration/drone/push Build is passing
2025-07-14 13:36:27 +08:00
hang 3e097fa42b uat 序列获取Instance 增加文件大小 2025-07-14 13:32:21 +08:00
hang b8a7cd6ebc 修改非dicom 设置删除,检查上的数量不变更 2025-07-14 13:32:16 +08:00
hang a9aefaf240 修改预览看到阅片影像 修改后受试者随机bug修改 4 2025-07-14 13:32:10 +08:00
hang 266a0c5dd5 修改后受试者随机bug修改 3 2025-07-14 13:32:05 +08:00
hang 54822ae038 修改后受试者随机bug修改 2 2025-07-14 13:31:07 +08:00
hang 05203d6716 受试者随机bug修改 2025-07-14 13:31:00 +08:00
hang 2ce8edde80 uat升级excel 组件测试
continuous-integration/drone/push Build is passing
2025-07-05 13:34:09 +08:00
hang 3c30f5dc14 完全随机跟下载关联
continuous-integration/drone/push Build is passing
2025-07-03 14:54:23 +08:00
30 changed files with 502 additions and 150 deletions
@@ -52,7 +52,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitOncologyReadingInfo")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SetOncologyReadingInfo(DataInspectionDto<SubmitOncologyReadingInfoInDto> opt)
@@ -69,7 +69,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitDicomVisitTask")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitDicomVisitTask(DataInspectionDto<SubmitDicomVisitTaskInDto> opt)
@@ -88,7 +88,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitGlobalReadingInfo")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitGlobalReadingInfo(DataInspectionDto<SubmitGlobalReadingInfoInDto> opt)
@@ -107,7 +107,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialReadingInfoSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> TrialReadingInfoSign(DataInspectionDto<TrialReadingInfoSignInDto> opt)
@@ -126,7 +126,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingMedicalReview/FinishMedicalReview")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> FinishMedicalReview(DataInspectionDto<FinishMedicalReviewInDto> opt)
@@ -143,7 +143,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingMedicineQuestion/ConfirmReadingMedicineQuestion")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ConfirmReadingMedicineQuestion(DataInspectionDto<ConfirmReadingMedicineQuestionInDto> opt)
@@ -161,7 +161,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitVisitTaskQuestions")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitVisitTaskQuestions(DataInspectionDto<SubmitVisitTaskQuestionsInDto> opt)
@@ -179,7 +179,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCSignClinicalData")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCSignClinicalData(DataInspectionDto<CRCSignClinicalDataInDto> opt)
@@ -197,7 +197,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCConfirmClinical(DataInspectionDto<CRCConfirmClinicalInDto> opt)
@@ -214,7 +214,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/CRCCancelConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCCancelConfirmClinical(DataInspectionDto<CRCCancelConfirmClinicalInDto> opt)
@@ -232,7 +232,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/PMConfirmClinical")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> PMConfirmClinical(DataInspectionDto<CRCConfirmClinicalInDto> opt)
@@ -250,7 +250,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingClinicalData/SignConsistencyAnalysisReadingClinicalData")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SignConsistencyAnalysisReadingClinicalData(DataInspectionDto<SignConsistencyAnalysisReadingClinicalDataInDto> opt)
@@ -267,7 +267,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ClinicalAnswer/SubmitClinicalFormAndSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitClinicalFormAndSign(DataInspectionDto<SubmitClinicalFormInDto> opt)
@@ -284,7 +284,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitJudgeVisitTaskResult")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitJudgeVisitTaskResult(DataInspectionDto<SaveJudgeVisitTaskResult> opt)
@@ -303,7 +303,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialBasicInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialBasicInfoConfirm(DataInspectionDto<BasicTrialConfig> opt)
{
@@ -345,7 +345,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialUrgentInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialUrgentInfoConfirm(DataInspectionDto<TrialUrgentConfig> opt)
{
opt.Data.IsTrialUrgentConfirmed = true;
@@ -358,7 +358,7 @@ namespace IRaCIS.Core.API.Controllers
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialPACSInfoConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "BeforeOngoingCantOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
public async Task<IResponseOutput> ConfigTrialPACSInfoConfirm(DataInspectionDto<TrialPACSConfig> opt)
{
opt.Data.IsTrialPACSConfirmed = true;
@@ -374,7 +374,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/configTrialBasicInfo/TrialConfigSignatureConfirm")]
[UnitOfWork]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> TrialConfigSignatureConfirm(DataInspectionDto<SignConfirmDTO> opt)
{
@@ -391,7 +391,7 @@ namespace IRaCIS.Core.API.Controllers
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingCriterion/ResetAndAsyncCriterion")]
[UnitOfWork]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> ResetAndAsyncCriterion(DataInspectionDto<ResetAndAsyncCriterionInDto> opt)
{
@@ -409,7 +409,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/QCOperation/CRCRequestToQC")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CRCRequestToQC(DataInspectionDto<CRCRequestToQCCommand> opt)
{
@@ -424,21 +424,31 @@ namespace IRaCIS.Core.API.Controllers
/// 设置QC 通过或者不通过 7:QC failed 8QC passed
/// </summary>
[HttpPost, Route("Inspection/QCOperation/QCPassedOrFailed")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> QCPassedOrFailed(DataInspectionDto<QCPassedOrFailedDto> opt)
{
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
await _inspectionService.CompletedSign(singid, result);
return result;
if (opt.Data.IsSecondPass != null)
{
var result = await _qCOperationService.QCSecondReviewPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, (bool)opt.Data.IsSecondPass);
await _inspectionService.CompletedSign(singid, result);
return result;
}
else
{
var result = await _qCOperationService.QCPassedOrFailed(opt.Data.trialId, opt.Data.subjectVisitId, opt.Data.auditState);
await _inspectionService.CompletedSign(singid, result);
return result;
}
}
/// <summary>
/// 一致性核查 回退 对话记录不清除 只允许PM回退
/// </summary>
[HttpPost, Route("Inspection/QCOperation/CheckBack")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> CheckBack(DataInspectionDto<IDDto> opt)
{
@@ -455,7 +465,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadClinicalData/ReadClinicalDataSign")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ReadClinicalDataSign(DataInspectionDto<ReadingClinicalDataSignIndto> opt)
{
@@ -470,7 +480,7 @@ namespace IRaCIS.Core.API.Controllers
/// CRC 设置已经重传完成
/// </summary>
[HttpPost, Route("Inspection/QCOperation/SetReuploadFinished")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SetReuploadFinished(DataInspectionDto<CRCReuploadFinishedCommand> opt)
{
@@ -486,7 +496,7 @@ namespace IRaCIS.Core.API.Controllers
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/TrialConfig/updateTrialState")]
[TrialGlobalLimit( "BeforeOngoingCantOpt")]
[TrialGlobalLimit("BeforeOngoingCantOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UpdateTrialState(DataInspectionDto<UpdateTrialStateDto> opt)
{
@@ -502,7 +512,7 @@ namespace IRaCIS.Core.API.Controllers
/// </summary>
/// <returns></returns>
[HttpPost, Route("Inspection/TrialDocument/userConfirm")]
[TrialGlobalLimit( "BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt" )]
[TrialGlobalLimit("BeforeOngoingCantOpt", "SignSystemDocNoTrialId", "AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UserConfirm(DataInspectionDto<UserConfirmCommand> opt)
{
@@ -519,10 +529,10 @@ namespace IRaCIS.Core.API.Controllers
/// </summary>
/// <returns></returns>
[HttpPost, Route("Inspection/VisitTask/ConfirmReReading")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskService _visitTaskService)
public async Task<IResponseOutput> ConfirmReReading(DataInspectionDto<ConfirmReReadingCommand> opt, [FromServices] IVisitTaskService _visitTaskService)
{
var singId = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _visitTaskService.ConfirmReReading(opt.Data);
@@ -53,7 +53,7 @@
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
<PackageReference Include="MimeKit" Version="4.11.0" />
<PackageReference Include="MiniExcel" Version="1.40.0" />
<PackageReference Include="MiniExcel" Version="1.41.3" />
<PackageReference Include="Minio" Version="6.0.4" />
<PackageReference Include="MiniWord" Version="0.9.2" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
@@ -2586,7 +2586,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
sv.SecondReviewState = SecondReviewState.None;
if (sv.IsBaseLine)
{
@@ -81,7 +81,7 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
public bool IsReading { get; set; }
public bool IsDeleted { get; set; }
public long? FileSize { get; set; }
public Guid? StudyId { get; set; }
@@ -107,8 +107,13 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
public string Modalities { get; set; }
public string Description { get; set; }
public int SeriesCount { get; set; }
public int InstanceCount { get; set; }
public int ReadingSeriesCount { get; set; }
public int ReadingInstanceCount { get; set; }
}
public class NoneDicomStudyBasicInfo
@@ -128,6 +133,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
public string Description { get; set; } = string.Empty;
public int ReadingFileCount { get; set; }
}
}
@@ -63,7 +63,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
//subject 随机阅片 或者无序 有上传 才处理任务编号
if (_visitTaskRepository.Any(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId &&
(t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.SubjectRandom ||
(t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.Random && t.TrialReadingCriterion.ImageUploadEnum != ReadingImageUpload.None))))
(t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.Random && t.TrialReadingCriterion.ImageDownloadEnum != ReadingImageDownload.None))))
{
//找到 非一致性分析,未签名,状态正常的 并且任务名称是TimePoint的 任务
var needDealTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId
@@ -882,6 +882,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
subjectCode = inQuery.SubjectCode;
}
TaskState? taskState = null;
if (inQuery.VisitTaskId != null)
{
//考虑到一致性分析,必须要这个编号进行过滤
@@ -892,20 +893,25 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code,
SubjectId = t.SubjectId,
t.DoctorUserId,
t.IsAnalysisCreate
t.IsAnalysisCreate,
t.TaskState
}).FirstNotNullAsync();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
doctorUserId = (Guid)taskInfo.DoctorUserId!;
isAnalysisCreate = taskInfo.IsAnalysisCreate;
taskState = taskInfo.TaskState;
}
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisitId != null && t.DoctorUserId == doctorUserId)
//满足 有序,或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(inQuery.VisitTaskId == null, t => t.TaskState == TaskState.Effect)//从待阅列表进入,要筛选出有效的,任务可能重阅了,也要看到该任务的
//满足 有序,或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(inQuery.VisitTaskId == null, t => t.TaskState == TaskState.Effect)//从待阅列表进入,要筛选出有效的,任务可能重阅了,也要看到该任务的
.WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
.WhereIf(taskState == TaskState.Effect || taskState == TaskState.Freeze, t => t.TaskState == TaskState.Effect)//subject 随机可能当前阅片人有退回任务,此时传递了任务Id,但是要看整个subject得,要只留生效的
.WhereIf(taskState != null && taskState != TaskState.Effect && taskState != TaskState.Freeze, t => t.Id == inQuery.VisitTaskId) //非生效只查当前任务
.ProjectTo<SubjectCRCImageUploadedDto>(_mapper.ConfigurationProvider);
//这里过滤是否是一致性分析的
@@ -1006,11 +1012,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
SeriesList = u.SeriesList.Where(t => t.IsReading).Select(z => new
{
z.Modality,
InstancePathList = z.DicomInstanceList.Select(k => new
InstancePathList = z.DicomInstanceList.Where(t => t.IsReading).Select(k => new
{
k.Path,
k.FileSize
@@ -1021,13 +1027,14 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.Where(t => t.IsReading)
.Select(nd => new
{
nd.Modality,
nd.StudyCode,
nd.ImageDate,
FileList = nd.NoneDicomFileList.Select(file => new
FileList = nd.NoneDicomFileList.Where(t => t.IsReading).Select(file => new
{
file.FileName,
file.Path,
@@ -1109,7 +1116,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize=k.FileSize,
}).ToList()
})
});
@@ -4,7 +4,7 @@ namespace IRaCIS.Core.Application.Contracts
{
public interface IStudyService
{
IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId);
IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId,bool? isReading);
Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery);
Task<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery);
(List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId);
@@ -1,5 +1,6 @@
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
@@ -19,8 +20,9 @@ namespace IRaCIS.Core.Application.Services
//医生读片那一块有耦合,关键序列 这里暂时留存
/// <summary> 指定资源Id,获取Dicom检查所属序列信息列表 </summary>
/// <param name="studyId"> Dicom检查的Id </param>
/// <param name="isReading"></param>
[HttpGet, Route("{studyId:guid}")]
public async Task<IResponseOutput<List<DicomSeriesDTO>>> List(Guid studyId)
public async Task<IResponseOutput<List<DicomSeriesDTO>>> List(Guid studyId, bool? isReading)
{
//质控的时候,要标记序列,和instance 删除 ,所以要返回全部,但是 质控通过后,pm 进去看的时候要看过滤后的
@@ -32,14 +34,16 @@ namespace IRaCIS.Core.Application.Services
//断点
var seriesList = await _seriesRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.WhereIf(isReading == true, t => t.IsReading == true)
.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
.ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
var instanceList = await _instanceRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.WhereIf(isReading == true, t => t.IsReading == true)
.OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber, t.HtmlPath, t.IsReading, t.IsDeleted }).ToListAsync();//.GroupBy(u => u.SeriesId);
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber, t.HtmlPath, t.IsReading, t.IsDeleted, t.FileSize }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList)
@@ -54,7 +58,8 @@ namespace IRaCIS.Core.Application.Services
Path = k.Path,
InstanceNumber = k.InstanceNumber,
IsReading = k.IsReading,
IsDeleted = k.IsDeleted
IsDeleted = k.IsDeleted,
FileSize = k.FileSize
}).ToList();
@@ -579,7 +579,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
/// <returns></returns>
[HttpGet("{subjectVisitId:guid}")]
[AllowAnonymous]
public IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId)
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();
@@ -607,10 +607,18 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var studyInfo = _dicomStudyRepository.Where(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException();
var query = _dicomStudyRepository.Where(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
.ProjectTo<RelationStudyDTO>(_mapper.ConfigurationProvider).ToList();
var list = _dicomStudyRepository.Where(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
.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();
var list = query.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);
}
@@ -130,16 +130,20 @@ 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));
CreateMap<DicomStudy, DicomStudyBasicInfo>();
CreateMap<NoneDicomStudy, NoneDicomStudyBasicInfo>();
CreateMap<DicomStudy, DicomStudyBasicInfo>()
.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<NoneDicomStudy, NoneDicomStudyBasicInfo>()
.ForMember(d => d.ReadingFileCount, u => u.MapFrom(s => s.NoneDicomFileList.Where(t => t.IsReading).Count()));
CreateMap<VisitTask, SubjectCRCImageUploadedDto>()
.ForMember(d => d.VisitTaskId, u => u.MapFrom(s => s.Id))
.ForMember(d => d.IsImageFilter, u => u.MapFrom(s => s.TrialReadingCriterion.IsImageFilter))
.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))
;
.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))
@@ -199,6 +199,8 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
public Guid subjectVisitId { get; set; }
public AuditStateEnum auditState { get; set; }
public bool? IsSecondPass { get; set; }
}
public class SetSeriesStateDto
@@ -251,7 +251,13 @@ namespace IRaCIS.Core.Application.Contracts.DTO
}
public class SecondReviewDto
{
public DateTime? SecondReviewTime { get; set; }
public string FullName { get; set; }
public string UserName { get; set; }
public DateTime? SignTime { get; set; }
}
public class TrialVisitQADTO
@@ -270,6 +276,7 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public QARelationInfo RelationInfo { get; set; } = new QARelationInfo();
public List<SecondReviewDto> SecondReviewList { get; set; }
}
@@ -203,6 +203,8 @@ namespace IRaCIS.Core.Application.Contracts
public bool IsShowStudyName { get; set; } = false;
public bool IsQCQuestionConfirmed { get; set; }
}
@@ -1949,6 +1951,7 @@ namespace IRaCIS.Core.Application.Contracts
public class QCQuestionAnswer
{
public Guid? AnswerId { get; set; }
public Guid Id { get; set; }
public string QuestionName { get; set; } = String.Empty;
public bool IsRequired { get; set; }
@@ -1977,6 +1980,8 @@ namespace IRaCIS.Core.Application.Contracts
// 1代表第一个人QC数据 2 代表第二个人QC数据
public CurrentQC CurrentQCEnum { get; set; }
public DateTime? SecondReviewTime { get; set; }
}
public class ForwardQuery : PageInput
@@ -2130,6 +2135,8 @@ namespace IRaCIS.Core.Application.Contracts
public class QCVisitBasicListViewModel
{
public SecondReviewState SecondReviewState { get; set; }
public bool IsSubjectQuit { get; set; }
public ChallengeStateEnum ChallengeState { get; set; }
public bool? IsConfirmedClinicalData { get; set; }
public bool IsQCConfirmedReupload { get; set; }
@@ -35,6 +35,8 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
public bool IsQuestionQCAuditPassed { get; set; }
}
public class QCQuestionFilterSelect
@@ -13,7 +13,7 @@ namespace IRaCIS.Core.Application.Image.QA
Task<IResponseOutput> QCPassedOrFailed(Guid trialId, Guid subjectVisitId, [FromRoute] AuditStateEnum auditState);
Task<IResponseOutput> SetCheckPass(SetCheckPassDt data);
Task<IResponseOutput> QCSecondReviewPassedOrFailed(Guid trialId, Guid subjectVisitId, bool isSecondPass);
Task<IResponseOutput> AddCheckChallengeReply(CheckChallengeDialogCommand checkDialogCommand);
@@ -7,6 +7,8 @@ using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit.Initializers;
using Microsoft.AspNetCore.Mvc;
using NPOI.SS.Formula.Functions;
using System.Linq;
namespace IRaCIS.Core.Application.Image.QA
{
@@ -24,6 +26,7 @@ namespace IRaCIS.Core.Application.Image.QA
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<QCChallenge> _qcChallengeRepository,
IRepository<SubjectVisitImageBackRecord> _subjectVisitImageBackRecordReposiotry,
IRepository<UserRole> _userRoleReposiotry,
IReadingImageTaskService _IReadingImageTaskService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IQCListService
{
@@ -409,10 +412,50 @@ namespace IRaCIS.Core.Application.Image.QA
var qacheckList = await GetQCQuestionAnswerList(subjectVisitId, sv.TrialId, trialQCProcess, currentQCType);
List<SecondReviewDto> secondReviewList = new List<SecondReviewDto>();
if (sv.SecondReviewState != SecondReviewState.None)
{
var trialConfirmTime = _trialRepository.Where(t => t.Id == sv.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
secondReviewList = (from answer in _trialQCQuestionAnswerRepository.Where(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.SecondReview).Where(t => t.SecondReviewTime != null)
join userRole in _userRoleReposiotry.Where() on answer.UpdateUserId equals userRole.Id
select new SecondReviewDto { SecondReviewTime = answer.SecondReviewTime, SignTime = answer.UpdateTime, FullName = userRole.FullName, UserName = userRole.UserName })
.Distinct().ToList();
var secondReviewTimeList = secondReviewList.Select(t => t.SecondReviewTime).Distinct().ToList();
//首次加入
if (!secondReviewTimeList.Contains(trialConfirmTime))
{
secondReviewList.Add(new SecondReviewDto() { SecondReviewTime = trialConfirmTime });
}
else
{
if (sv.SecondReviewState == SecondReviewState.WaitAudit)
{
foreach (var item in secondReviewList)
{
if (item.SecondReviewTime == trialConfirmTime)
{
item.SignTime = null;
item.FullName = "";
item.UserName = "";
}
}
}
}
secondReviewList = secondReviewList.OrderByDescending(t => t.SecondReviewTime).ToList();
}
return new TrialVisitQADTO
{
QCQuestionAnswerList = qacheckList,
SecondReviewList = secondReviewList,
IsHaveStudyClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.IsConfirm && x.TrialId == sv.TrialId && x.ClinicalDataLevel == ClinicalLevel.Study),
StudyList = temp.StudyList,
ExistsManual = (await _IReadingImageTaskService.GetManualList(new GetManualListInDto() { TrialId = sv.TrialId })).Count() > 0,
@@ -432,11 +475,53 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPost]
public async Task<List<QCQuestionAnswer>> GetQCQuestionAnswer(GetQCQuestionAnswerInDto inDto)
{
var questionAnswerlist = await (from data in _trialQCQuestionRepository.Where(x => x.TrialId == inDto.TrialId && x.IsEnable)
join answer in _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum).AsQueryable() on data.Id equals answer.TrialQCQuestionConfigureId into answertemp
var subjectVisitId = inDto.SubjectVisitId;
List<QCQuestionAnswer> questionAnswerlist = new List<QCQuestionAnswer>();
//判断当前访视质控是否完成,再判断复审是完成查看,还是添加编辑
var sv = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).FirstNotNullAsync();
var trialConfirmTime = _trialRepository.Where(t => t.Id == sv.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
var secondReviewTime = inDto.SecondReviewTime != null ? (DateTime)inDto.SecondReviewTime : trialConfirmTime == null ? DateTime.Now : (DateTime)trialConfirmTime;
if ((sv.AuditState == AuditStateEnum.QCPassed && inDto.CurrentQCEnum != CurrentQC.SecondReview) || (inDto.CurrentQCEnum == CurrentQC.SecondReview && secondReviewTime.AddSeconds(1) < trialConfirmTime))
{
//之前质控完的,+二次复核完的,都要从答案表中取 二次复核完的还需要加时间
questionAnswerlist = await _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum)
.Where(t => inDto.CurrentQCEnum == CurrentQC.SecondReview ? t.SecondReviewTime >= secondReviewTime && t.SecondReviewTime <= secondReviewTime.AddSeconds(1) : true)
.Select(data => new QCQuestionAnswer()
{
AnswerId = data.Id,
Answer = data.Answer,
ShowOrder = data.TrialQCQuestionConfigure.ShowOrder,
QuestionName = data.TrialQCQuestionConfigure.QuestionName,
Id = data.TrialQCQuestionConfigure.Id,
IsRequired = data.TrialQCQuestionConfigure.IsRequired,
ParentId = data.TrialQCQuestionConfigure.ParentId,
ParentTriggerValue = data.TrialQCQuestionConfigure.ParentTriggerValue,
Type = data.TrialQCQuestionConfigure.Type,
TypeValue = data.TrialQCQuestionConfigure.TypeValue
}).OrderBy(t => t.ShowOrder).ToListAsync();
}
else
{
#region
questionAnswerlist = await (from data in _trialQCQuestionRepository.Where(x => x.TrialId == inDto.TrialId && x.IsEnable)
join answer in _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum)
.Where(t => inDto.CurrentQCEnum == CurrentQC.SecondReview ? t.SecondReviewTime >= secondReviewTime && t.SecondReviewTime <= secondReviewTime.AddSeconds(1) : true)
on data.Id equals answer.TrialQCQuestionConfigureId into answertemp
from leftanswer in answertemp.DefaultIfEmpty()
select new QCQuestionAnswer()
{
AnswerId = leftanswer.Id,
Answer = leftanswer.Answer,
ShowOrder = data.ShowOrder,
QuestionName = data.QuestionName,
@@ -447,6 +532,17 @@ namespace IRaCIS.Core.Application.Image.QA
Type = data.Type,
TypeValue = data.TypeValue
}).OrderBy(t => t.ShowOrder).ToListAsync();
#endregion
}
var result = questionAnswerlist.Where(x => x.ParentId == null).OrderBy(t => t.ShowOrder).ToList();
result.ForEach(x =>
@@ -384,6 +384,7 @@ namespace IRaCIS.Core.Application.Image.QA
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
sv.SecondReviewState = SecondReviewState.None;
if (sv.IsBaseLine)
@@ -691,6 +692,7 @@ namespace IRaCIS.Core.Application.Image.QA
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
sv.SecondReviewState = SecondReviewState.None;
//var success1 = _studyRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
//var succeess2 = _instanceRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
@@ -727,9 +729,17 @@ namespace IRaCIS.Core.Application.Image.QA
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> AddOrUpdateQCQuestionAnswerList(QCQuestionAnswerCommand[] qcQuestionAnswerCommands, Guid trialId, Guid subjectVisitId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
{
if (currentQCType == CurrentQC.SecondReview)
{
//二次复核自动领取,如果有人先领取了,那么后续不能操作
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId && t.CurrentActionUserId == null, u => new SubjectVisit() { CurrentActionUserId = _userInfo.UserRoleId, IsTake = true }, true);
}
//验证是否能操作
await VerifyIsCanQCAsync(null, subjectVisitId);
var trialConfirmTime = _trialRepository.Where(t => t.Id == trialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
//更新
if (qcQuestionAnswerCommands.Any(t => t.Id != null))
{
@@ -774,11 +784,13 @@ namespace IRaCIS.Core.Application.Image.QA
{
var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);
addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });
addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; t.SecondReviewTime = currentQCType == CurrentQC.SecondReview ? trialConfirmTime : null; });
await _trialQCQuestionAnswerRepository.AddRangeAsync(addlist);
return ResponseOutput.Result(await _trialQCQuestionAnswerRepository.SaveChangesAsync());
return ResponseOutput.Ok(await _trialQCQuestionAnswerRepository.SaveChangesAsync());
}
@@ -961,6 +973,9 @@ namespace IRaCIS.Core.Application.Image.QA
var noneDicomStudyFile = (await _noneDicomStudyFileRepository.Where(t => t.Id == noneDicomStudyFileId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
var noneDicomStudy = (await _noneDicomStudyRepository.Where(t => t.Id == noneDicomStudyFile.NoneDicomStudyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
if (state == 1)
{
noneDicomStudyFile.IsReading = false;
@@ -972,10 +987,15 @@ namespace IRaCIS.Core.Application.Image.QA
else if (state == 4)
{
noneDicomStudyFile.IsDeleted = true;
noneDicomStudy.FileCount = noneDicomStudy.FileCount - 1;
}
else if (state == 5)
{
noneDicomStudyFile.IsDeleted = false;
noneDicomStudy.FileCount = noneDicomStudy.FileCount + 1;
}
}
@@ -1165,10 +1185,12 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> ReplaceQCTaskActionUser(Guid trialId, Guid subjectVisitId)
public async Task<IResponseOutput> ReplaceQCTaskActionUser(Guid trialId, Guid subjectVisitId, Guid? replaceUserRoleId)
{
var dbSubjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();
//await VerifyIsCanQCAsync(dbSubjectVisit);
if (dbSubjectVisit.CurrentActionUserId == null && dbSubjectVisit.IsTake == false)
{
@@ -1179,7 +1201,7 @@ namespace IRaCIS.Core.Application.Image.QA
dbSubjectVisit.IsTake = true;
dbSubjectVisit.CurrentActionUserId = _userInfo.UserRoleId;
dbSubjectVisit.CurrentActionUserId = replaceUserRoleId == null || replaceUserRoleId == Guid.Empty ? _userInfo.UserRoleId : replaceUserRoleId;
dbSubjectVisit.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);
@@ -1347,6 +1369,12 @@ namespace IRaCIS.Core.Application.Image.QA
if (obtaionOrCancel)
{
//复核的时候,指派后,另外一个人进来的时候如果是自己,那么不进行后续流程
if (dbSubjectVisit.CurrentActionUserId == _userInfo.UserRoleId)
{
return ResponseOutput.Ok();
}
if (dbSubjectVisit.CurrentActionUserId != null && dbSubjectVisit.IsTake)
{
//throw new BusinessValidationFailedException("当前访视已被领取,不允许领取");
@@ -1378,65 +1406,69 @@ namespace IRaCIS.Core.Application.Image.QA
// return ResponseOutput.NotOk("您已经领取了其他受试者,完成后才允许领取新的受试者");
//}
#region
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
if (dbSubjectVisit.SecondReviewState == SecondReviewState.None)
{
//---项目配置为不审,没有领取QC Task
return ResponseOutput.NotOk(_localizer["QCOperation_NoQC"]);
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.UserRoleId)
#region
if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
{
//---初审已通过,不能继续领取
return ResponseOutput.NotOk(_localizer["QCOperation_InitialAuditPassed"]);
//---项目配置为不审,没有领取QC Task
return ResponseOutput.NotOk(_localizer["QCOperation_NoQC"]);
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.UserRoleId)
{
//---初审已通过,不能继续领取
return ResponseOutput.NotOk(_localizer["QCOperation_InitialAuditPassed"]);
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
//单审QC 释放后 也是可以领取的
}
else
{
// ---项目配置为单审,不满足Submmit State:已提交 或者 Audit State:待审核/审核中, 不允许领取,请刷新界面
return ResponseOutput.NotOk(_localizer["QCOperation_NoSingleAudit"]);
}
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.UserRoleId)
{
//---复审不能和初审是同一个人
return ResponseOutput.NotOk(_localizer["QCOperation_NoSameReviewer"]);
}
//提交 并且初审通过 那么领取后进入 复审中
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.PrimaryQCPassed)
{
dbSubjectVisit.AuditState = AuditStateEnum.InSecondaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
{
//初审中 复审中 领取也是ok的 其他人接着做
}
else
{
//---项目配置为复审,不满足提交状态:已提交 或者 审核状态:待审核/QC中, 不允许领取,请刷新界面
return ResponseOutput.NotOk(_localizer["QCOperation_NoSecondaryAudit"]);
}
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
{
//单审QC 释放后 也是可以领取的
}
else
{
// ---项目配置为单审,不满足Submmit State:已提交 或者 Audit State:待审核/审核中, 不允许领取,请刷新界面
return ResponseOutput.NotOk(_localizer["QCOperation_NoSingleAudit"]);
}
}
else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
{
if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.UserRoleId)
{
//---复审不能和初审是同一个人
return ResponseOutput.NotOk(_localizer["QCOperation_NoSameReviewer"]);
}
//提交 并且初审通过 那么领取后进入 复审中
if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.PrimaryQCPassed)
{
dbSubjectVisit.AuditState = AuditStateEnum.InSecondaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
{
dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
}
else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
{
//初审中 复审中 领取也是ok的 其他人接着做
}
else
{
//---项目配置为复审,不满足提交状态:已提交 或者 审核状态:待审核/QC中, 不允许领取,请刷新界面
return ResponseOutput.NotOk(_localizer["QCOperation_NoSecondaryAudit"]);
}
#endregion
}
#endregion
dbSubjectVisit.IsTake = true;
@@ -2069,8 +2101,46 @@ namespace IRaCIS.Core.Application.Image.QA
}
public async Task<IResponseOutput> QCSecondReviewPassedOrFailed(Guid trialId, Guid subjectVisitId, bool isSecondPass)
{
if (!await _trialUserRoleRepository.AnyAsync(t => t.TrialId == trialId && t.UserId == _userInfo.UserRoleId))
{
//---您已经被移出项目,没有操作权限。
return ResponseOutput.NotOk(_localizer["QCOperation_RemoveItem"]);
}
var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
await VerifyIsCanQCAsync(sv);
var trialConfirmTime = _trialRepository.Where(t => t.Id == sv.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
if (sv.SecondReviewState == SecondReviewState.WaitAudit)
{
if (isSecondPass)
{
sv.SecondReviewState = SecondReviewState.AuditPassed;
sv.IsTake = false;
sv.CurrentActionUserId = null;
sv.CurrentActionUserExpireTime = null;
}
else
{
sv.SecondReviewState = SecondReviewState.AuditFailed;
}
await _trialQCQuestionAnswerRepository.BatchUpdateNoTrackingAsync(t => t.SubjectVisitId == sv.Id && t.CurrentQCEnum == CurrentQC.SecondReview && t.SecondReviewTime == trialConfirmTime, u => new TrialQCQuestionAnswer()
{
UpdateUserId = _userInfo.UserRoleId,
UpdateTime = DateTime.Now
});
}
await _subjectVisitRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 设置、取消 访视紧急
@@ -472,6 +472,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialQCQuestion, TrialQCQuestionAddOrEdit>();
CreateMap<TrialQCQuestion, TrialQCQuestionConfigureView>()
.ForMember(d => d.IsQuestionQCAuditPassed, u => u.MapFrom(s => s.TrialQCQuestionAnswerList.Any(c => c.TrialQCQuestionConfigureId == s.Id && c.SubjectVisit.AuditState == AuditStateEnum.QCPassed)))
.ForMember(d => d.ParentShowOrder, u => u.MapFrom(s => s.ParentQCQuestion.ShowOrder));
CreateMap<TrialQCQuestionSelect, TrialQCQuestionConfigureView>();
@@ -139,5 +139,16 @@ namespace IRaCIS.Core.Application.Contracts.DTO
}
public class TrialSelectUserBasicInfo
{
public Guid UserRoleId { get; set; }
public string FullName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
}
@@ -6,6 +6,7 @@ using IRaCIS.Core.Application.Helper;
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;
@@ -41,6 +42,7 @@ namespace IRaCIS.Core.Application
IRepository<SystemBasicData> _systemBasicDataRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Enroll> _enrollRepository,
IRepository<TrialQCQuestionAnswer> _qcQuestionAnswerRepository,
IRepository<TrialStateChange> _trialStateChangeRepository,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, ITrialConfigService
@@ -562,7 +564,7 @@ namespace IRaCIS.Core.Application
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial()
{
ReadingToolList=inDto.ReadingToolList,
ReadingToolList = inDto.ReadingToolList,
IsImageFilter = inDto.IsImageFilter,
ImageDownloadEnum = inDto.ImageDownloadEnum,
ImageUploadEnum = inDto.ImageUploadEnum,
@@ -837,9 +839,46 @@ namespace IRaCIS.Core.Application
{
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialUrgentConfirmed = true });
}
else
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirmUpdate).ToString())
{
var trialConfirmTime = _trialRepository.Where(t => t.Id == signConfirmDTO.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
if (trialConfirmTime != null)
{
//删除复审中间临时数据
await _qcQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisit.TrialId == signConfirmDTO.TrialId && t.SubjectVisit.SecondReviewState == SecondReviewState.WaitAudit
&& t.CurrentQCEnum == CurrentQC.SecondReview && t.UpdateTime > trialConfirmTime);
}
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = null, QCQuestionConfirmedUserId = null, IsQCQuestionConfirmed = false });
}
else if (signConfirmDTO.SignCode == ((int)SignEnum.SecondReviewConfirm).ToString())
{
var trialConfirmTime = _trialRepository.Where(t => t.Id == signConfirmDTO.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
if (trialConfirmTime != null)
{
//删除复审中间临时数据--没重置,一直点生成复核任务
await _qcQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisit.TrialId == signConfirmDTO.TrialId && t.SubjectVisit.SecondReviewState == SecondReviewState.WaitAudit
&& t.CurrentQCEnum == CurrentQC.SecondReview && t.UpdateTime > trialConfirmTime);
//删除质控中 临时保存的问题答案 (因为添加那里只会新增 和全部更新,如果不处理,那么有新增,也有更新,稽查那里也会有问题)
await _qcQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisit.TrialId == signConfirmDTO.TrialId && t.SubjectVisit.AuditState == AuditStateEnum.InPrimaryQC
&& t.CurrentQCEnum == CurrentQC.First);
await _qcQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisit.TrialId == signConfirmDTO.TrialId && t.SubjectVisit.AuditState == AuditStateEnum.InSecondaryQC
&& t.CurrentQCEnum == CurrentQC.Second);
//重复二次复核签名
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.TrialId == signConfirmDTO.TrialId && t.AuditState == AuditStateEnum.QCPassed
&& !t.TrialQCQuestionAnswerList.Any(t => t.SecondReviewTime == trialConfirmTime), u => new SubjectVisit() { SecondReviewState = SecondReviewState.WaitAudit });
}
}
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
{
var trialConfig = (await _trialRepository
@@ -879,14 +918,14 @@ namespace IRaCIS.Core.Application
throw new BusinessValidationFailedException(_localizer["TrialConfig_AuditQuestionConfirmed"]);
}
await _trialQCQuestionRepository.UpdatePartialFromQueryAsync(t => t.TrialId == signConfirmDTO.TrialId, x => new TrialQCQuestion
await _trialQCQuestionRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == signConfirmDTO.TrialId, x => new TrialQCQuestion
{
IsConfirm = true
});
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = DateTime.Now, QCQuestionConfirmedUserId = _userInfo.UserRoleId, IsQCQuestionConfirmed = true });
await _trialRepository.SaveChangesAsync();
}
await _trialRepository.SaveChangesAsync();
return ResponseOutput.Ok();
@@ -1311,7 +1350,7 @@ namespace IRaCIS.Core.Application
/// <returns></returns>
public async Task<IResponseOutput<List<TrialBodyPartView>>> GetTrialBodyPartList(Guid trialId)
{
var list = await _trialRepository.Where(t => t.Id == trialId).SelectMany(t => t.TrialBodyPartList).Select(t => new TrialBodyPartView() { Code = t.Code, Name = _userInfo.IsEn_Us ? t.Name : t.NameCN, Id = t.Id, IsHandAdd = t.IsHandAdd }).OrderBy(t=>t.Name).ToListAsync();
var list = await _trialRepository.Where(t => t.Id == trialId).SelectMany(t => t.TrialBodyPartList).Select(t => new TrialBodyPartView() { Code = t.Code, Name = _userInfo.IsEn_Us ? t.Name : t.NameCN, Id = t.Id, IsHandAdd = t.IsHandAdd }).OrderBy(t => t.Name).ToListAsync();
return ResponseOutput.Ok(list);
}
@@ -1394,7 +1433,7 @@ namespace IRaCIS.Core.Application
[HttpPost]
public async Task<IResponseOutput> UpdateTrialStudyNameList(UpdateTrialStudyNameListInDto inDto)
{
var trial = await _trialRepository.FirstOrDefaultAsync(x => x.Id == inDto.TrialId);
@@ -6,9 +6,11 @@ using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit.Serialization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Storage.Json;
using NPOI.SS.Formula.Functions;
using System;
namespace IRaCIS.Core.Application.Service
@@ -56,8 +58,8 @@ namespace IRaCIS.Core.Application.Service
IsDeleted = t.IsDeleted,
UserTypeId = t.UserRole.UserTypeRole.Id,
UserTypeShortName = t.UserRole.UserTypeRole.UserTypeShortName,
CreateTime=t.CreateTime,
UpdateTime=t.UpdateTime,
CreateTime = t.CreateTime,
UpdateTime = t.UpdateTime,
}).ToList(),
}).ToPagedListAsync(inQuery);
@@ -315,7 +317,29 @@ namespace IRaCIS.Core.Application.Service
}
public async Task<List<TrialSelectUserBasicInfo>> GetTrialUserRoleList(Guid trialId, Guid? subjectVisitId, UserTypeEnum? userTypeEnum)
{
var isSeconReview = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).AnyAsync(t => t.SecondReviewState == SecondReviewState.WaitAudit);
//复审指派需要过滤初审的人
var firstUserId = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => t.PreliminaryAuditUserId).FirstOrDefaultAsync();
var list = await _trialIdentityUserRepository.Where(t => t.TrialId == trialId)
.SelectMany(t => t.TrialUserRoleList)
.WhereIf(userTypeEnum != null, t => t.UserRole.UserTypeEnum == userTypeEnum)
.Where(t => t.UserRole.Id != _userInfo.UserRoleId)//iQC 指派过滤自己
.WhereIf(firstUserId != null && isSeconReview == false, t => t.UserRole.Id != firstUserId)//iQC 过滤初审的人,复核不过滤
.Select(t => new TrialSelectUserBasicInfo()
{
FullName = t.TrialUser.IdentityUser.FullName,
UserRoleId = t.UserRole.Id,
UserName = t.TrialUser.IdentityUser.UserName,
Phone = t.TrialUser.IdentityUser.Phone,
Email = t.TrialUser.IdentityUser.EMail
})
.ToListAsync();
return list;
}
}
}
@@ -42,7 +42,7 @@ namespace IRaCIS.Core.Application.Service
var instanceList = await _instanceRepository.Where(s => s.StudyId == scpStudyId).OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber }).ToListAsync();//.GroupBy(u => u.SeriesId);
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber,t.FileSize }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList)
{
@@ -55,6 +55,7 @@ namespace IRaCIS.Core.Application.Service
//HtmlPath = string.Empty,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize=k.FileSize,
}).ToList();
}
@@ -233,7 +233,7 @@ namespace IRaCIS.Core.Application.Services
var studyList = await _dicomStudyRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).IgnoreQueryFilters()
.Where(t => isImageFilter ? ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.WhereIf(isReading == 1 || isQCFinished, s=> s.IsDeleted == false)
.WhereIf(isReading == 1 || isQCFinished, s => s.IsDeleted == false)
.Select(k => new VisitStudyDTO()
{
InstanceCount = k.InstanceCount,
@@ -248,7 +248,7 @@ namespace IRaCIS.Core.Application.Services
var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId)).IgnoreQueryFilters()
.WhereIf(isReading == 1, s => s.IsReading && s.IsDeleted == false)
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.HtmlPath, t.IsReading, t.IsDeleted }).ToListAsync();
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.HtmlPath, t.IsReading, t.IsDeleted, t.FileSize }).ToListAsync();
foreach (var t in studyList)
{
@@ -272,6 +272,7 @@ namespace IRaCIS.Core.Application.Services
InstanceNumber = k.InstanceNumber,
IsReading = k.IsReading,
IsDeleted = k.IsDeleted,
FileSize = k.FileSize,
}).ToList();
series.InstanceCount = series.InstanceInfoList.Count();
@@ -303,7 +304,7 @@ namespace IRaCIS.Core.Application.Services
DicomSeriesDTO series = await _dicomSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstNotNullAsync();
var instanceList = await _dicomInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId)
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation }).ToListAsync();
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync();
@@ -315,6 +316,7 @@ namespace IRaCIS.Core.Application.Services
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize = k.FileSize
}).ToList();
@@ -391,7 +393,7 @@ namespace IRaCIS.Core.Application.Services
var seriesIds = ctseriesIds.Union(ptseriesIds).ToList(); //并集
var instanceList = await _dicomInstanceRepository.Where(t => seriesIds.Contains(t.SeriesId))
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath }).ToListAsync();
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.FileSize }).ToListAsync();
var studyIds = instanceList.Select(x => x.StudyId).Distinct().ToList();
@@ -422,7 +424,7 @@ namespace IRaCIS.Core.Application.Services
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize = k.FileSize
}).ToList();
@@ -506,7 +508,7 @@ namespace IRaCIS.Core.Application.Services
.Select(k => new VisitStudyDTO()
{
InstanceCount = k.InstanceCount,
StudyName=k.StudyName,
StudyName = k.StudyName,
Modalities = k.Modalities,
//SeriesCount = k.SeriesCount,
StudyCode = k.StudyCode,
@@ -516,7 +518,7 @@ namespace IRaCIS.Core.Application.Services
var studyIds = dicomStudyList.Select(t => t.StudyId).ToList();
var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId) && t.IsReading)
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.IsReading }).ToListAsync();
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.IsReading, t.FileSize }).ToListAsync();
List<DicomSeriesDTO> seriesLists = await _dicomSeriesRepository.Where(s => studyIds.Contains(s.StudyId))
.WhereIf(isManualGenerate == false, t => t.IsReading)
@@ -537,6 +539,7 @@ namespace IRaCIS.Core.Application.Services
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize = k.FileSize
}).ToList();
@@ -613,7 +616,7 @@ namespace IRaCIS.Core.Application.Services
var markInstanceIdList = rowInfoList.Where(y => y.InstanceId != null).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(y => y.InstanceId!.Value).Distinct().ToList();
item.InstanceInfoList = await _dicomInstanceRepository.Where(t => markInstanceIdList.Contains(t.Id)).OrderBy(s => s.DicomSerie.SeriesNumber).ThenBy(s => s.DicomSerie.SeriesTime).ThenBy(x=>x.InstanceTime).Select(k =>
item.InstanceInfoList = await _dicomInstanceRepository.Where(t => markInstanceIdList.Contains(t.Id)).OrderBy(s => s.DicomSerie.SeriesNumber).ThenBy(s => s.DicomSerie.SeriesTime).ThenBy(x => x.InstanceTime).Select(k =>
new InstanceBasicInfo()
{
Id = k.Id,
@@ -623,6 +626,7 @@ namespace IRaCIS.Core.Application.Services
InstanceNumber = k.InstanceNumber,
StudyId = k.StudyId,
SeriesId = k.SeriesId,
FileSize = k.FileSize
}).ToListAsync();
item.InstanceInfoList.ForEach(x =>
@@ -707,7 +711,7 @@ namespace IRaCIS.Core.Application.Services
{
var nodicom = noDicomList.Where(x => x.Id == item.StudyId).First();
var instanceCount = await _noneDicomStudyFileRepository.Where(t=>t.IsReading)
var instanceCount = await _noneDicomStudyFileRepository.Where(t => t.IsReading)
.WhereIf(isExistTaskNoneDicomFile, x => x.OriginNoneDicomStudyId == item.StudyId)
.WhereIf(isExistTaskNoneDicomFile == false, x => x.NoneDicomStudyId == item.StudyId).CountAsync();
@@ -29,6 +29,13 @@ namespace IRaCIS.Core.Domain.Share
TrialQCQuestionConfirm=107,
//重置质控问题配置
TrialQCQuestionConfirmUpdate=112,
SecondReviewConfirm = 113,
}
}
@@ -19,4 +19,14 @@ namespace IRaCIS.Core.Domain.Share
}
public enum SecondReviewState
{
None = 0,
WaitAudit=1,
AuditPassed=2,
AuditFailed=3,
}
}
@@ -14,7 +14,11 @@
First = 1,
Second = 2
Second = 2,
//二次复核,只会一个人
SecondReview=3,
}
+1
View File
@@ -108,6 +108,7 @@ public abstract class BaseFullAuditEntity : Entity, IAuditUpdate, IAuditAdd
[ForeignKey("CreateUserId")]
[JsonIgnore]
public UserRole CreateUserRole { get; set; }
}
public abstract class BaseFullDeleteAuditEntity : Entity, IAuditUpdate, IAuditAdd, ISoftDelete
{
@@ -8,6 +8,9 @@ public class TrialQCQuestionAnswer : BaseFullAuditEntity
#region
[JsonIgnore]
public TrialQCQuestion TrialQCQuestionConfigure { get; set; }
[JsonIgnore]
public SubjectVisit SubjectVisit { get; set; }
#endregion
public Guid TrialId { get; set; }
@@ -20,4 +23,7 @@ public class TrialQCQuestionAnswer : BaseFullAuditEntity
public Guid SubjectVisitId { get; set; }
public Guid TrialQCQuestionConfigureId { get; set; }
public DateTime? SecondReviewTime { get; set; }
}
+4 -2
View File
@@ -6,6 +6,8 @@ namespace IRaCIS.Core.Domain.Models;
public class SubjectVisit : BaseFullDeleteAuditEntity
{
#region
[JsonIgnore]
public List<TrialQCQuestionAnswer> TrialQCQuestionAnswerList { get; set; }
[JsonIgnore]
public TrialSite TrialSite { get; set; }
@@ -72,7 +74,7 @@ public class SubjectVisit : BaseFullDeleteAuditEntity
public List<SubjectCriteriaEvaluationVisitFilter> SubjectCriteriaEvaluationVisitFilterList { get; set; }
[JsonIgnore]
public List<SubjectVisitImageBackRecord> SubjectVisitImageBackRecordList { get; set; }
public List<SubjectVisitImageBackRecord> SubjectVisitImageBackRecordList { get; set; }
#endregion
public Guid TrialSiteId { get; set; }
@@ -185,7 +187,7 @@ public class SubjectVisit : BaseFullDeleteAuditEntity
public Guid? SubmitUserId { get; set; }
public ReadingStatusEnum ReadingStatus { get; set; }
public SecondReviewState SecondReviewState { get; set; }
}
[Comment("受试者访视影像回退记录表")]
+31 -13
View File
@@ -92,7 +92,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
/// <param name="unitDataList">单位字典</param>
/// <param name="answer">答案</param>
/// <returns></returns>
public string Translationunit(string answerType, ValueUnit? unit, string customUnit, List<UnitData> unitDataList,string? answer)
public string Translationunit(string answerType, ValueUnit? unit, string customUnit, List<UnitData> unitDataList, string? answer)
{
if (answerType == "upload")
{
@@ -198,6 +198,13 @@ namespace IRaCIS.Core.Infra.EFCore.Common
extraIdentification = oldentity.IsConfigureEmail ? "/EmailUpdate" : "/EmailSave";
break;
case "configTrialBasicInfo/TrialConfigSignatureConfirm":
if (entity.IsQCQuestionConfirmed == false)
{
extraIdentification = $"/ConfirmReset";
}
break;
}
@@ -1971,7 +1978,15 @@ namespace IRaCIS.Core.Infra.EFCore.Common
//待处理?
case "qcoperation/qcpassedorfailed":
extraIdentification = "/" + (40 % (int)entity.AuditState).ToString();
if (entity.AuditState == AuditStateEnum.QCPassed && (entity.SecondReviewState == SecondReviewState.AuditPassed || entity.SecondReviewState == SecondReviewState.AuditFailed))
{
extraIdentification = "/SecondReviewFinished";
}
else
{
extraIdentification = "/" + (40 % (int)entity.AuditState).ToString();
}
break;
@@ -2001,15 +2016,18 @@ namespace IRaCIS.Core.Infra.EFCore.Common
}
break;
}
if (entity.CheckChallengeState == CheckChanllengeTypeEnum.CRCWaitPMReply || entity.CheckChallengeState == CheckChanllengeTypeEnum.PMWaitCRCReply)
if(_userInfo.RequestUrl== "QCOperation/addCheckChallengeReply" || _userInfo.RequestUrl == "QCOperation/UploadVisitCheckExcel")
{
//发送对话 修改质疑状态 不需要区分接口
isDistinctionInterface = false;
if (entity.CheckChallengeState == CheckChanllengeTypeEnum.CRCWaitPMReply || entity.CheckChallengeState == CheckChanllengeTypeEnum.PMWaitCRCReply)
{
//发送对话 修改质疑状态 不需要区分接口
isDistinctionInterface = false;
extraIdentification = "/ModifyCheckChallengeState";
extraIdentification = "/ModifyCheckChallengeState";
}
}
#endregion
@@ -3127,7 +3145,7 @@ namespace IRaCIS.Core.Infra.EFCore.Common
(t, u) =>
new
{
Answer = Translationunit(u.AnswerType, u.Unit,u.CustomUnit, unitDataList, t.Answer),
Answer = Translationunit(u.AnswerType, u.Unit, u.CustomUnit, unitDataList, t.Answer),
u.DictionaryCode,
u.QuestionName,
u.QuestionEnName,
@@ -3235,12 +3253,12 @@ namespace IRaCIS.Core.Infra.EFCore.Common
string extraIdentification = string.Empty;
var readingQuestion = await _dbContext.ReadingQuestionTrial.Where(t => t.Id == entity.QuestionId).Include(x=>x.ReadingQuestionCriterionTrial).FirstNotNullAsync();
var readingQuestion = await _dbContext.ReadingQuestionTrial.Where(t => t.Id == entity.QuestionId).Include(x => x.ReadingQuestionCriterionTrial).FirstNotNullAsync();
if (readingQuestion.ReadingQuestionCriterionTrial.CriterionGroup == CriterionGroup.Nontumorous)
{
extraIdentification = "/Nontumorous";
}
await InsertInspection<ReadingTableAnswerRowInfo>(entity, type, x => new InspectionConvertDTO()
@@ -3664,9 +3682,9 @@ namespace IRaCIS.Core.Infra.EFCore.Common
}
}
if(entity.TaskBlindName.Contains("Timepoint Ran"))
if (entity.TaskBlindName.Contains("Timepoint Ran"))
{
if(_dbContext.VisitTask.Where(t => t.Id == entity.Id).Any(t => !t.TaskBlindName.Contains("Timepoint Ran")))
if (_dbContext.VisitTask.Where(t => t.Id == entity.Id).Any(t => !t.TaskBlindName.Contains("Timepoint Ran")))
{
isDistinctionInterface = false;
extraIdentification = "/TriggerSystemBlindingName";