Compare commits

..

129 Commits

Author SHA1 Message Date
hang 4b21ef4f14 非IVUS 空检查 又不过滤
continuous-integration/drone/push Build is passing
2026-08-27 17:13:38 +08:00
hang 1e2869abb5 坝段标注下载 修改过滤
continuous-integration/drone/push Build is passing
2026-08-27 16:43:35 +08:00
hang 8bd46c6c18 坝段标注,IR上传 是否阅片过滤修改
continuous-integration/drone/push Build is passing
2026-08-27 15:48:12 +08:00
hang f7b4382a62 后处理上传 标记不阅片过滤
continuous-integration/drone/push Build was killed
2026-08-27 15:17:42 +08:00
hang 63d3ca4971 增加上传默认排序 2026-08-27 14:50:48 +08:00
hang 29518ddea6 下载控制标志修改
continuous-integration/drone/push Build is passing
2026-08-27 11:03:51 +08:00
hang 20dd2ffd5d Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-27 10:16:53 +08:00
hang e406511755 下载接口变更 2026-08-27 10:16:51 +08:00
he e4abc61456 Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-26 14:51:44 +08:00
he c0c4df1254 IVUS和OCT 破盲修改 2026-08-26 14:51:13 +08:00
hang cc826afff1 Dixon 排序修改
continuous-integration/drone/push Build is passing
2026-08-26 13:08:56 +08:00
hang 53c18c4c4c 下载IR 上传影像 2026-08-26 10:30:37 +08:00
he 0c9f29d3b4 裁判问题标记修改1
continuous-integration/drone/push Build is passing
2026-08-25 10:43:29 +08:00
he 14f03facd2 事件配置文件修改
continuous-integration/drone/push Build is passing
2026-08-24 14:05:10 +08:00
he b469be1b14 导出OCT和Ivus 模板导出ZIP
continuous-integration/drone/push Build is running
2026-08-24 14:00:57 +08:00
he c3e5b0c4b8 事件环境配置文件修改
continuous-integration/drone/push Build is passing
2026-08-24 10:17:32 +08:00
he 5ee992efb4 裁判规则判断修改
continuous-integration/drone/push Build is passing
2026-08-21 15:49:06 +08:00
he 44b28f2d0a 修改编译错误1
continuous-integration/drone/push Build is passing
2026-08-20 15:41:32 +08:00
he b1db5bebd3 修改编译错误
continuous-integration/drone/push Build is running
2026-08-20 15:40:41 +08:00
he 3f3caaaffe 设置项目阅片信息 全局择一
continuous-integration/drone/push Build is passing
2026-08-20 15:35:17 +08:00
he b3d5b5f75e 选全局 只能泽一
continuous-integration/drone/push Build is passing
2026-08-20 15:19:17 +08:00
he ee5708f905 裁判规则配置应用到其他所有访视 修改
continuous-integration/drone/push Build is passing
2026-08-20 14:48:11 +08:00
he 140a7bb3fd 拷贝裁判表单
continuous-integration/drone/push Build is passing
2026-08-20 13:44:45 +08:00
he 65ac1498b1 稽查修改
continuous-integration/drone/push Build is passing
2026-08-20 13:29:51 +08:00
he 0f15eaabff 稽查添加
continuous-integration/drone/push Build is passing
2026-08-20 10:13:17 +08:00
he 54c8f71af7 裁判表单修改
continuous-integration/drone/push Build is passing
2026-08-20 09:37:51 +08:00
he b31178c0c0 裁判查询修改
continuous-integration/drone/push Build is passing
2026-08-20 09:33:04 +08:00
he 0af6919b5a 查询裁判表单修改
continuous-integration/drone/push Build is passing
2026-08-19 17:43:35 +08:00
he 393c915884 裁判问题编辑验证先去除
continuous-integration/drone/push Build is passing
2026-08-19 16:10:38 +08:00
he ed274d2812 限制显示 裁判默认规则修改 2026-08-19 16:05:07 +08:00
he 072e076bea Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-19 15:56:51 +08:00
he d6b5badccd 统一生成裁判任务 2026-08-19 15:56:47 +08:00
hang d237da548f 坝段标注过滤访视数量,判断已完成逻辑修改
continuous-integration/drone/push Build is passing
2026-08-19 11:05:46 +08:00
he dee6bebcb7 基线配置应用到其他访视
continuous-integration/drone/push Build is passing
2026-08-19 10:38:02 +08:00
hang 40a98048bb Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-18 17:03:02 +08:00
hang 1ea978eccd 靶段标注时间默认值问题修复 2026-08-18 17:03:00 +08:00
he bc8aeb8d7c 复制其他访视的项目阅片标准裁判规则配置
continuous-integration/drone/push Build is passing
2026-08-18 15:14:32 +08:00
he c35ec016dd 修改问题排序
continuous-integration/drone/push Build is passing
2026-08-18 14:53:30 +08:00
he 283524cb4f 获取裁判单个数据排除问题
continuous-integration/drone/push Build is pending
2026-08-18 14:36:36 +08:00
he 10c9f6b8cc 表单添加字段
continuous-integration/drone/push Build is passing
2026-08-18 14:25:12 +08:00
he e291953d09 裁判表单返回ShowQuestion
continuous-integration/drone/push Build is passing
2026-08-18 13:57:49 +08:00
he 1094c8ce2a 阅片信息签名验证接口修改 2026-08-18 13:57:47 +08:00
he 747bb29729 保存裁判规则验证 2026-08-18 13:57:44 +08:00
he 4cab822a52 不适用的访视不返回裁判配置 2026-08-18 13:57:41 +08:00
he adaa085e56 添加默认不适用规则 2026-08-18 13:57:39 +08:00
hang 1f97243482 Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10 2026-08-18 13:21:49 +08:00
hang b272a748ec 靶段标注查询列表修改 2026-08-18 13:21:40 +08:00
he b121db89f0 获取裁判的计算关系
continuous-integration/drone/push Build is passing
2026-08-18 10:25:01 +08:00
he 35e6a47f2d 获取问题修改
continuous-integration/drone/push Build is passing
2026-08-18 09:24:57 +08:00
he afeebf662b 编辑修改
continuous-integration/drone/push Build is passing
2026-08-17 17:10:45 +08:00
he 23ae346cee IVUS修改
continuous-integration/drone/push Build is passing
2026-08-17 15:55:47 +08:00
he d52c23b5c4 修改
continuous-integration/drone/push Build is pending
2026-08-17 15:52:01 +08:00
he 70e851e10d 排除访视 2026-08-17 15:51:59 +08:00
he a371db7522 添加裁判计算验证 2026-08-17 15:51:55 +08:00
he b755d12d7c 添加裁判计算过的标记 2026-08-17 15:51:49 +08:00
he 30e3a363a8 Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10 2026-08-17 15:51:43 +08:00
he 6f692c34c2 修改 可以传0 2026-08-17 15:43:01 +08:00
he 6dac36ba1a 查询修改 2026-08-17 15:42:59 +08:00
he 2623a42ea7 修改 2026-08-17 15:42:57 +08:00
he 8613c0a064 去掉验证 2026-08-17 15:42:53 +08:00
he e159f8a82b 字段修改 2026-08-17 15:42:48 +08:00
he 416793018f 获取裁判表单 返回备注和截图的信息 2026-08-17 15:42:43 +08:00
he c714a81edf 返回R1 R2 的任务Id 2026-08-17 15:42:40 +08:00
he d9b5298572 裁判签名 2026-08-17 15:42:37 +08:00
he 38ec3d55ae 裁判规则修改 2026-08-17 15:42:34 +08:00
he 046715fd07 GetNextTask 新增 ArbitrationRule 2026-08-17 15:42:33 +08:00
he 07bd02d3c8 获取项目阅片标准各访视的裁判规则配置 已经排除的访视 在获取的时候 不返回 2026-08-17 15:42:31 +08:00
he b6ad1722f6 获取下一个阅片任务新增裁判配置 2026-08-17 15:42:28 +08:00
he 240b8218f0 获取和编辑新增的裁判配置 2026-08-17 15:42:25 +08:00
he 8345b5b47d 裁判表单问题加属性 2026-08-17 15:42:21 +08:00
he 54f6fc1b12 新增修改裁表单修改 2026-08-17 15:42:19 +08:00
he 2b59cb5d02 获取单个裁判访视信息修改 2026-08-17 15:42:16 +08:00
he d9d0ceac76 获取单个访视裁判 2026-08-17 15:42:14 +08:00
he 35400b4952 访视裁判配置 2026-08-17 15:42:10 +08:00
he 1d33619a85 添加表和字段 2026-08-17 15:42:04 +08:00
hang a4f3c4bb81 无序+受试者随机后处理,也拷贝后处理影像
continuous-integration/drone/push Build is passing
2026-08-14 16:06:51 +08:00
he 166c5f3f9c IVUS验证修改
continuous-integration/drone/push Build is pending
2026-08-14 15:26:47 +08:00
he 54c7e6cc7c OCTIVUS提示语修改
continuous-integration/drone/push Build is passing
2026-08-14 14:56:23 +08:00
hang 859c9e4161 Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-14 14:32:18 +08:00
hang b33fb79718 最新的调研表过滤 2026-08-14 14:32:17 +08:00
he 24faa2d887 Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-14 11:51:27 +08:00
he e9d3dda160 OTC和IVUS验证文件类型 2026-08-14 11:51:25 +08:00
hang 53ad439257 调研导表索引变更
continuous-integration/drone/push Build is passing
2026-08-14 11:46:57 +08:00
hang d577410bb4 增加查询条件-修改最新查询记录-导表对应修改
continuous-integration/drone/push Build is passing
2026-08-14 11:29:21 +08:00
hang df0e4ddcfa 调研信息表修改
continuous-integration/drone/push Build is passing
2026-08-13 17:34:10 +08:00
hang 9948ea8df3 中心调研导表增加设备信息
continuous-integration/drone/push Build is passing
2026-08-13 15:02:23 +08:00
hang 763220dcef 更新调研表 清除 初审 复审
continuous-integration/drone/push Build is passing
2026-08-13 11:10:15 +08:00
hang 208dab27dc 拷贝日志bug、邮箱bug、废除拷贝详情
continuous-integration/drone/push Build is passing
2026-08-13 10:49:36 +08:00
hang 3c816e989e 调研导表初步修改
continuous-integration/drone/push Build is passing
2026-08-13 10:31:18 +08:00
hang c44c333997 修改中心调研路径,SPM驳回逻辑, 邮件逻辑对应修改
continuous-integration/drone/push Build is passing
2026-08-13 09:37:21 +08:00
hang 5fc700123f Merge branch 'Uat_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net10
continuous-integration/drone/push Build is passing
2026-08-12 17:34:15 +08:00
hang 49437034a3 调研-时间排序 2026-08-12 17:34:14 +08:00
hang 74486c8e30 驳回修改-导表初次提交
continuous-integration/drone/push Build is passing
2026-08-12 17:21:14 +08:00
hang d6fc7f7911 中心调研拷贝历史日式bug
continuous-integration/drone/push Build is passing
2026-08-12 14:10:39 +08:00
hang 2b5066f967 中心调研二次修改-增加日志查询参数
continuous-integration/drone/push Build is passing
2026-08-12 13:39:48 +08:00
hang a577589a92 调研增加参数修改
continuous-integration/drone/push Build is running
2026-08-12 11:40:48 +08:00
hang 62f02528c2 中心调研接口改为分页
continuous-integration/drone/push Build was killed
2026-08-11 17:22:18 +08:00
hang 5b950914e3 SPM 是否参与流程 2026-08-11 17:22:09 +08:00
hang 99942982f6 增加中心调研日志 2026-08-11 17:22:06 +08:00
hang 18e9005c3d 中心调研bug修改
continuous-integration/drone/push Build is passing
2026-08-11 13:35:35 +08:00
hang d9f6dd22e1 增加前端配置获取以及更新接口
continuous-integration/drone/push Build is passing
2026-08-10 13:39:43 +08:00
he f5579c3deb sheet页问题修改
continuous-integration/drone/push Build is passing
2026-08-06 14:06:09 +08:00
hang 60c0c66d22 增加日志详细信息:get请求参数,请求 OS Browser 信息
continuous-integration/drone/push Build is passing
2026-08-06 11:24:05 +08:00
hang a2c17da35e 中心调研这里增加额外的验证 2026-08-06 11:23:43 +08:00
hang 20f46f2dab ivus隐藏导表 2026-08-06 11:23:34 +08:00
he cbf63c0f9c 导入忽略空格
continuous-integration/drone/push Build is passing
2026-08-06 09:50:37 +08:00
he f3db7525f9 匹配去掉空格
continuous-integration/drone/push Build is passing
2026-08-06 09:34:46 +08:00
he 694325e6b9 提示修改
continuous-integration/drone/push Build is passing
2026-08-05 17:13:24 +08:00
he 138702f077 导入1和0 兼容 2
continuous-integration/drone/push Build is passing
2026-08-05 14:54:10 +08:00
he a739f856b4 导入1和0 兼容
continuous-integration/drone/push Build is passing
2026-08-05 14:30:52 +08:00
he 68af0578d0 导出靶段备注
continuous-integration/drone/push Build is running
2026-08-05 14:22:06 +08:00
he 9042017a90 导出模版只导出靶段
continuous-integration/drone/push Build is passing
2026-08-05 14:04:18 +08:00
hang 59b053faa9 增加自动触发打包net10
continuous-integration/drone/push Build is passing
2026-08-05 12:17:32 +08:00
he 63b9f4e775 导出修改 2026-08-05 12:11:04 +08:00
he efe2e7f063 重新发布 2026-08-05 09:08:46 +08:00
he 19b1d022e0 修改行数 2026-08-05 09:08:42 +08:00
he 9e1372dc01 字典修改 2026-08-05 09:08:38 +08:00
he a6a409c750 导入修改 2026-08-05 09:08:36 +08:00
he fdcb81306d 导出修改 2026-08-05 09:08:32 +08:00
he ff395f1d56 接受合并 2026-08-03 16:48:47 +08:00
he e346593ebb Revert "拷贝病灶"
continuous-integration/drone/push Build is running
This reverts commit 282e56e5fc.
2026-08-03 16:47:31 +08:00
he fab6c8c55a Merge branch 'Test_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net10
continuous-integration/drone/push Build is running
2026-08-03 16:43:50 +08:00
he 282e56e5fc 拷贝病灶 2026-08-03 16:43:46 +08:00
hang a600f11422 Merge branch 'Test_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net10 2026-07-30 17:52:53 +08:00
hang 2db4a293ed 修复后处理增加数量bug 2026-07-30 17:52:44 +08:00
he 8641a11b53 查询修改
continuous-integration/drone/push Build is passing
2026-07-30 17:39:10 +08:00
he 980248d899 Merge branch 'Test_IRC_Net10' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net10
continuous-integration/drone/push Build is passing
2026-07-30 15:59:14 +08:00
he 372ee55241 稽查修改 2026-07-30 15:59:11 +08:00
he ed8d2e285f 重复请求code改为-4 取消Get类型验证 2026-07-14 16:57:53 +08:00
62 changed files with 48919 additions and 439 deletions
@@ -89,7 +89,6 @@ public class FileUploadRecordService(IRepository<FileUploadRecord> _fileUploadRe
public async Task<IResponseOutput> AddOrUpdateFileUploadRecord(FileUploadRecordAddOrEdit addOrEditFileUploadRecord)
{
return ResponseOutput.Ok();
addOrEditFileUploadRecord.IP = _userInfo.IP;
@@ -351,6 +351,23 @@ namespace IRaCIS.Core.API.Controllers
return result;
}
/// <summary>
/// 提交阅片裁判表单
/// </summary>
/// <param name="opt"></param>
/// <returns></returns>
[HttpPost, Route("Inspection/ReadingImageTask/SubmitJudgeForm")]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> SubmitJudgeForm(DataInspectionDto<SetJudgeFormInDto> opt)
{
var singid = await _inspectionService.RecordSing(opt.SignInfo);
var result = await _iReadingImageTaskService.SubmitJudgeForm(opt.Data);
await _inspectionService.CompletedSign(singid, result);
return result;
}
/// <summary>
/// 配置 基础逻辑信息并确认
+7
View File
@@ -213,6 +213,13 @@
<param name="opt"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.SubmitJudgeForm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Service.Reading.Dto.SetJudgeFormInDto})">
<summary>
提交阅片裁判表单
</summary>
<param name="opt"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.API.Controllers.InspectionController.ConfigTrialBasicInfoConfirm(IRaCIS.Core.Application.Service.Inspection.DTO.DataInspectionDto{IRaCIS.Core.Application.Contracts.BasicTrialConfig})">
<summary>
配置 基础逻辑信息并确认
+3 -15
View File
@@ -4,30 +4,16 @@ 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;
using IRaCIS.Core.Application.Service.BusinessFilter;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit;
using MassTransit.NewIdProviders;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Localization;
using Newtonsoft.Json;
using Serilog;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using UAParser;
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
@@ -95,6 +81,8 @@ builder.Services.AddSingleton<FileSyncQueue>();
builder.Services.AddHostedService<SyncFileRecoveryService>();
builder.Services.AddHostedService<FileSyncWorker>();
builder.Services.AddSingleton(_ => Parser.GetDefault());
//minimal api 异常处理
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
//builder.Services.AddProblemDetails();
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Serilog;
using System.Linq;
using UAParser;
namespace IRaCIS.Core.API
{
@@ -17,11 +18,14 @@ namespace IRaCIS.Core.API
{
app.UseMiddleware<RequestResponseLoggingMiddleware>();
// 从 DI 容器中获取 Parser 实例
var uaParser = app.ApplicationServices.GetRequiredService<Parser>();
app.UseSerilogRequestLogging(opts
=>
{
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath} {RequestBody} responded {StatusCode} in {Elapsed:0.0000} ms";
opts.MessageTemplate = "{FullName} {UserType} {UserIp} {Host} {RequestMethod} {RequestPath}{QueryString} {RequestBody} {OS} {Browser} {DeviceType} responded {StatusCode} in {Elapsed:0.0000} ms";
opts.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
{
@@ -33,10 +37,9 @@ namespace IRaCIS.Core.API
// Only set it if available. You're not sending sensitive data in a querystring right?!
if (request.QueryString.HasValue)
{
diagnosticContext.Set("QueryString", request.QueryString.Value);
}
diagnosticContext.Set("QueryString", request.QueryString.Value ?? "");
diagnosticContext.Set("FullName", httpContext?.User?.FindFirst(JwtIRaCISClaimType.FullName)?.Value);
@@ -52,6 +55,38 @@ namespace IRaCIS.Core.API
diagnosticContext.Set("UserIp", clientIp);
// ==================== 新增:解析 User-Agent ====================
try
{
var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
if (!string.IsNullOrEmpty(userAgent))
{
var clientInfo = uaParser.Parse(userAgent);
diagnosticContext.Set("OS", clientInfo.OS.ToString());
diagnosticContext.Set("Browser", clientInfo.UA.ToString());
//diagnosticContext.Set("DeviceType", clientInfo.Device.ToString());
diagnosticContext.Set("DeviceType", userAgent.Contains("Mobile") ? "Mobile": "Desktop");
}
else
{
diagnosticContext.Set("OS", "Unknown");
diagnosticContext.Set("Browser", "Unknown");
diagnosticContext.Set("DeviceType", "Unknown");
}
}
catch (Exception ex)
{
// 解析失败时记录异常,但不要影响主流程
diagnosticContext.Set("OS", "ParseError");
diagnosticContext.Set("Browser", "ParseError");
diagnosticContext.Set("DeviceType", "ParseError");
}
// ==============================================================
#region
//diagnosticContext.Set("Protocol", request.Protocol);
//diagnosticContext.Set("Scheme", request.Scheme);
@@ -44,11 +44,11 @@
"RegionId": "cn-shanghai",
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tFUCCmz5TwghZHsj45Y",
"AccessKeySecret": "8evrBy1fVfzJG25i67Jm0xqn9Xcw2T",
"RoleArn": "acs:ram::1078130221702011:role/uat-oss-access",
"BucketName": "tl-med-irc-event-store",
"ViewEndpoint": "https://tl-med-rc-event-cache.oss-cn-shanghai.aliyuncs.com",
"AccessKeyId": "LTAI5tNRTsqL6aWmHkDmTwoH",
"AccessKeySecret": "7mtGz3qrYWI6JMMBZiLeC119VWicZH",
"RoleArn": "acs:ram::1899121822495495:role/irc-oss-access",
"BucketName": "zy-irc-store",
"ViewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
},
@@ -70,7 +70,7 @@
"OpenUserComplexPassword": true,
"OpenSignDocumentBeforeWork": true,
"OpenLoginLimit": false,
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 120,
@@ -96,7 +96,7 @@
"FromEmail": "irc@extimaging.com",
"FromName": "EIC Imaging System",
"AuthorizationCode": "ExtImg@2022",
"SiteUrl": "http://irc.extimaging.com/login",
"SiteUrl": "http://irc.event.extimaging.com/login",
"PlatformName": "EICS",
"PlatformNameCN": "展影云平台",
+4 -3
View File
@@ -24,7 +24,7 @@
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
"IsOpenStoreSync": false,
"IsOpenStoreSync": true,
"ApiDeployRegion": "CN",
"SyncConfigList": [
{
@@ -41,7 +41,7 @@
"Target": "AliyunOSS",
"UploadRegion": "US",
"TargetRegion": "CN",
"IsOpenSync": false
"IsOpenSync": true
}
],
"AliyunOSS": {
@@ -127,5 +127,6 @@
"DuplicationWindowMs": 500,
"CacheTimeSeconds": 5,
"ExcludedPaths": []
}
},
"FrontWebConfig": "222"
}
@@ -37,13 +37,13 @@ public class TrialGlobalLimitActionFilter(IFusionCache _fusionCache, IUserInfo _
#region
// 用户类型检查
//if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
//{
// //对不起,您的账户没有操作权限
// context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_NoAccessPermission")));
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
{
//对不起,您的账户没有操作权限
context.Result = new JsonResult(ResponseOutput.NotOk(I18n.T("TrialResource_NoAccessPermission")));
// return;
//}
return;
}
#endregion
@@ -47,12 +47,12 @@ public class TrialGlobalLimitEndpointFilter(IFusionCache _fusionCache, IUserInfo
}
#region
//// 用户类型检查
//if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
//{
// //对不起,您的账户没有操作权限
// return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_NoAccessPermission")));
//}
// 用户类型检查
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA && _userInfo.RequestUrl.ToLower() != "TrialDocument/userConfirm".ToLower())
{
//对不起,您的账户没有操作权限
return Results.Json(ResponseOutput.NotOk(I18n.T("TrialResource_NoAccessPermission")));
}
#endregion
@@ -28,7 +28,7 @@ public static class ExcelExportHelper
/// <param name="translateType"></param>
/// <param name="criterionType"></param>
/// <returns></returns>
public static async Task<IActionResult> DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null)
public static async Task<IActionResult> DataExportAsync(string code, ExcelExportInfo data, string exportFileNamePrefix, IRepository<CommonDocument> _commonDocumentRepository, IWebHostEnvironment _hostEnvironment, IDictionaryService? _dictionaryService = null, Type? translateType = null, CriterionType? criterionType = null, List<int> removeExcelIndexList = null)
{
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
@@ -136,7 +136,7 @@ public static class ExcelExportHelper
#region sheet
// 打开模板文件
var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
using var templateFile = new FileStream(tplPath, FileMode.Open, FileAccess.Read);
// 获取文件流
var templateStream = new MemoryStream();
@@ -158,6 +158,17 @@ public static class ExcelExportHelper
workbook.Worksheets.Delete(2); // 删除第2个(索引2
}
if (removeExcelIndexList != null)
{
var worksheet = workbook.Worksheet(1); // 索引从1开始
foreach (int colIndex in removeExcelIndexList.OrderByDescending(t => t))
{
// 删除整列
worksheet.Column(colIndex).Delete();
}
}
//中文替换项目术语
if (data.TrialObjectNameList?.Count > 0)
{
@@ -930,17 +941,17 @@ public static class ExcelExportHelper
int sheetCount = workbook.Worksheets.Count;
if (sheetCount == 2)
//if (sheetCount == 2)
//{
if (inDto.IsEnglish)
{
if (inDto.IsEnglish)
{
workbook.Worksheet(1).Delete(); // 删除第一个工作表
}
else
{
workbook.Worksheet(2).Delete(); // 删除第二个工作表
}
workbook.Worksheet(1).Delete(); // 删除第一个工作表
}
else
{
workbook.Worksheet(2).Delete(); // 删除第二个工作表
}
//}
#endregion
@@ -1080,12 +1080,15 @@ public static class DicomSortHelper
IEnumerable<T> source,
Func<T, string?> ippSelector,
Func<T, string?> iopSelector,
Func<T, int?> instanceNumberSelector)
Func<T, int?> instanceNumberSelector,string seriesDescription)
{
var list = source.ToList();
if (list.Count < 2)
return list;
if(seriesDescription.Contains("Dixon", StringComparison.OrdinalIgnoreCase))
return list.OrderBy(instanceNumberSelector).ToList();
var first = list[0];
var reference = ParseVector(ippSelector(first));
@@ -43,7 +43,7 @@
<param name="next"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ExcelExportHelper.DataExportAsync(System.String,IRaCIS.Application.Contracts.ExcelExportInfo,System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument},Microsoft.AspNetCore.Hosting.IWebHostEnvironment,IRaCIS.Application.Interfaces.IDictionaryService,System.Type,System.Nullable{IRaCIS.Core.Domain.Share.CriterionType})">
<member name="M:IRaCIS.Core.Application.Service.ExcelExportHelper.DataExportAsync(System.String,IRaCIS.Application.Contracts.ExcelExportInfo,System.String,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument},Microsoft.AspNetCore.Hosting.IWebHostEnvironment,IRaCIS.Application.Interfaces.IDictionaryService,System.Type,System.Nullable{IRaCIS.Core.Domain.Share.CriterionType},System.Collections.Generic.List{System.Int32})">
<summary>
</summary>
@@ -579,6 +579,12 @@
<param name="emailConfig"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.DeployConfigService.GetWebConfigInfo">
<summary>
获取前端配置
</summary>
<returns></returns>
</member>
<member name="P:IRaCIS.Core.Application.Service.Common.TU_TR_RSBaseModel.ResearchProgramNo">
<summary>
方案编号 STUDYID
@@ -849,6 +855,20 @@
裁决日期 CODTC
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetSiteSurveyEquipmentList_Export(IRaCIS.Core.Application.Contracts.SiteSurveyEquipmentQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteEquipmentSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteSurvey},IRaCIS.Application.Interfaces.IDictionaryService)">
<summary>
获取中心设备信息
</summary>
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetSiteSurveyInfoList_Export(IRaCIS.Core.Application.Contracts.SiteSurveyInfoQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteSurvey},IRaCIS.Application.Interfaces.IDictionaryService)">
<summary>
调研表基本信息
</summary>
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetTrialQCQuestionAnserList_Export(IRaCIS.Core.Application.Contracts.GetQCQuestionAnswerQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestion},IRaCIS.Application.Interfaces.IDictionaryService)">
<summary>
质控问题答案导出
@@ -1767,7 +1787,7 @@
<param name="_trialRepository"></param>
<param name="_oSSService"></param>
</member>
<member name="M:IRaCIS.Core.Application.Service.TrialImageDownloadService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Application.Helper.IOSSService,Microsoft.AspNetCore.Hosting.IWebHostEnvironment,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance})">
<member name="M:IRaCIS.Core.Application.Service.TrialImageDownloadService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Application.Helper.IOSSService,Microsoft.AspNetCore.Hosting.IWebHostEnvironment,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask})">
<summary>
项目影像后台下载,不打包
</summary>
@@ -2940,11 +2960,11 @@
<param name="modality"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.DownloadImageSuccess(System.Guid,System.Nullable{System.Guid})">
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.DownloadImageSuccess(IRaCIS.Core.Application.Contracts.DownloadImageSuccessCommand)">
<summary>
影像下载成功回调
</summary>
<param name="trialImageDownloadId"></param>
<param name="incommand"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetTrialDownloadList(IRaCIS.Core.Application.Contracts.TrialIamgeDownQuery)">
@@ -4562,6 +4582,13 @@
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IVUSCalculateService.GetIVUSTemplatesZip(IRaCIS.Core.Application.Service.Reading.Dto.GetExportTemplateInDto)">
<summary>
获取当前分组、受试者、标准下所有有效任务的IVUS模板压缩包
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IVUSCalculateService.UploadIVUSTemplate">
<summary>
导入IVUS数据
@@ -6221,6 +6248,13 @@
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.OCTCalculateService.GetOCTFCTTemplatesZip(IRaCIS.Core.Application.Service.Reading.Dto.GetExportTemplateInDto)">
<summary>
获取当前分组、受试者、标准下所有有效任务的OCT-FCT模板压缩包
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.OCTCalculateService.UploadOCTFCTTemplate">
<summary>
导入OCT-FCT数据
@@ -9032,6 +9066,36 @@
斑块破裂
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.TargetSegment">
<summary>
靶段
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.TargetSegmentRemarks">
<summary>
靶段备注
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.ROIAllLength">
<summary>
ROI段落总长度
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.PullbackFrameCount">
<summary>
回撤中的图像帧数
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.PlaqueType">
<summary>
斑块类型
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TemplateData.AdjustReason">
<summary>
访视点备注(如有)
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.OCTFCTUploadData.FrameNumber">
<summary>
帧数
@@ -10472,6 +10536,21 @@
默认SegmentName
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetReadingTaskDto.JudgeModeEnum">
<summary>
仲裁模式
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetReadingTaskDto.JudgeRuleEnum">
<summary>
裁判规则
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetReadingTaskDto.ArbitrationRule">
<summary>
仲裁对象
</summary>
</member>
<member name="T:IRaCIS.Core.Application.Service.Reading.Dto.GetTrialConfirmCriterionListOutDto">
<summary>
返回对象
@@ -10542,6 +10621,16 @@
裁判结果的备注
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetJudgeFormOutDto.TriggerJudgeQuestionIds">
<summary>
本次生成裁判的触发问题(包含自动计算题追溯到的源问题)
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.JudgeFormQuestionDto.IsTriggerJudge">
<summary>
是否为本次生成裁判的触发问题
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GlobalVisitJudgeQuestion.ShowOrder">
<summary>
排序
@@ -11917,6 +12006,41 @@
阅片期名称
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.CopyTrialQuestionVisitJudgeRuleInDto.SourceVisitNum">
<summary>
来源访视
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.CopyTrialQuestionVisitJudgeRuleInDto.TargetVisitNum">
<summary>
目标访视
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TrialQuestionVisitJudgeRuleItemDto.Type">
<summary>
类型
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TrialQuestionVisitJudgeRuleItemDto.QuestionGenre">
<summary>
问题类型
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TrialQuestionVisitJudgeRuleItemDto.DictionaryCode">
<summary>
字典code
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TrialQuestionVisitJudgeRuleItemDto.Unit">
<summary>
单位
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.TrialQuestionVisitJudgeRuleItemDto.AnswerCombination">
<summary>
答案组合
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateTumorAssessmentInDto.CriterionId">
<summary>
标准ID
@@ -12278,6 +12402,21 @@
仲裁规则
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetTrialJudgyInfoOutDto.JudgeModeEnum">
<summary>
仲裁模式
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetTrialJudgyInfoOutDto.JudgeRuleEnum">
<summary>
裁判规则
</summary>
</member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetTrialJudgyInfoOutDto.JudgeGenerateEnum">
<summary>
裁判任务生成
</summary>
</member>
<member name="F:IRaCIS.Core.Application.Service.Reading.Dto.NeedSynchronize.Need">
<summary>
需要
@@ -14308,6 +14447,11 @@
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.RC.ReadingQuestionService.SetTrialJudgeRuleInfo(IRaCIS.Core.Application.Service.Reading.Dto.SetTrialJudgeRuleInfoInDto)">
<summary>
编辑裁判规则配置
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.RC.ReadingQuestionService.AddOrUpdateReadingQuestionCriterionTrial(IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionCriterionTrialInDto)">
<summary>
新增修改项目问题标准(项目)
@@ -14409,11 +14553,34 @@
阅片问题.标准
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataTrialSet},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataSystemSet},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CriterionNidusSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemCriterionDictionaryCode},IRaCIS.Core.Application.Contracts.IReadingImageTaskService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingSystemCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TumorAssessment_RECIST1Point1},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.PreviousPDF},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataTrialSet},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ClinicalDataSystemSet},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CriterionNidusSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemCriterionDictionaryCode},IRaCIS.Core.Application.Contracts.IReadingImageTaskService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingSystemCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TumorAssessment_RECIST1Point1},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.PreviousPDF},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionVisitJudgeRule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitStage},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
<summary>
阅片问题.标准
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.GetTrialQuestionVisitJudgeRule(IRaCIS.Core.Application.Service.Reading.Dto.GetTrialQuestionVisitJudgeRuleInDto)">
<summary>
获取项目阅片标准各访视的裁判规则配置。
未配置规则的访视问题也会返回,供前端直接进行配置。
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.SetTrialQuestionVisitJudgeRule(IRaCIS.Core.Application.Service.Reading.Dto.SetTrialQuestionVisitJudgeRuleInDto)">
<summary>
编辑项目阅片标准各访视的裁判规则配置。
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.CopyTrialQuestionVisitJudgeRule(IRaCIS.Core.Application.Service.Reading.Dto.CopyTrialQuestionVisitJudgeRuleInDto)">
<summary>
复制其他访视的项目阅片标准裁判规则配置。
目标访视不适用的问题保留其已有的不适用规则,不参与复制。
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.ApplyBaseLineTrialQuestionVisitJudgeRule(IRaCIS.Core.Application.Service.Reading.Dto.ApplyBaseLineTrialQuestionVisitJudgeRuleInDto)">
<summary>
将基线访视(VisitNum = 0)的裁判规则配置应用到其他所有访视。
仅复制在基线和目标访视均适用的问题;目标访视不适用的问题保留其已有规则。
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.SetTrialQuestionExportResult(IRaCIS.Core.Application.Service.Reading.Dto.SetTrialQuestionExportResultInDto)">
<summary>
设置项目问题导出
@@ -14530,6 +14697,12 @@
<param name="indto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.AddNAJudgeRule(IRaCIS.Core.Domain.Models.ReadingQuestionTrial)">
<summary>
添加问题的不适用规则
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingQuestionService.GetReadingQuestionTrialList(IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialViewInDto)">
<summary>
获取项目问题(项目)
@@ -14783,7 +14956,7 @@
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMarkBinding},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingOncologyTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segmentation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SegmentBinding},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService,IRaCIS.Core.Application.Contracts.IReadingClinicalDataService,IRaCIS.Core.Application.Service.IReadingCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserFeedBack},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskRelation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingJudgeInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganTrialInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoCalculateService,IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoWithoutPETCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTrialCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CriterionKeyFileRead},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialCriterionKeyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Application.Service.IGeneralCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskStudy},Microsoft.Extensions.Configuration.IConfiguration,IRaCIS.Core.Application.Service.ImageAndDoc.IDownloadAndUploadService,IRaCIS.Core.Application.Interfaces.ITrialEmailNoticeConfigService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,ZiggyCreatures.Caching.Fusion.IFusionCache)">
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitStage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMarkBinding},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingOncologyTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Segmentation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SegmentBinding},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService,IRaCIS.Core.Application.Contracts.IReadingClinicalDataService,IRaCIS.Core.Application.Service.IReadingCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserFeedBack},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskRelation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingJudgeInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganTrialInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoCalculateService,IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoWithoutPETCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTrialCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionVisitJudgeRule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CriterionKeyFileRead},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialCriterionKeyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Application.Service.IGeneralCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskStudy},Microsoft.Extensions.Configuration.IConfiguration,IRaCIS.Core.Application.Service.ImageAndDoc.IDownloadAndUploadService,IRaCIS.Core.Application.Interfaces.ITrialEmailNoticeConfigService,Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,ZiggyCreatures.Caching.Fusion.IFusionCache)">
<summary>
IR影像阅片
</summary>
@@ -15199,6 +15372,13 @@
</summary>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.PhasedGenerationJudge(System.Guid)">
<summary>
统一生成裁判任务
</summary>
<param name=""></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.GetTrialCriterionJudgeQuestionList(IRaCIS.Core.Application.Service.Reading.Dto.GetTrialCriterionJudgeQuestionListInDto)">
<summary>
获取项目标准的裁判问题
@@ -15213,6 +15393,35 @@
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.GetSingleVisitJudgeAnswer(IRaCIS.Core.Application.Service.Reading.Dto.GetSingleVisitJudgeAnswerInDto)">
<summary>
获取单访视裁判答案
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.GetJudgeForm(IRaCIS.Core.Application.Service.Reading.Dto.GetJudgeFormInDto)">
<summary>
获取裁判表单
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.GetTriggerJudgeQuestionIds(System.Collections.Generic.List{System.Guid},System.Collections.Generic.List{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},System.Decimal,IRaCIS.Core.Domain.Models.JudgeRule)">
<summary>
重新按当前访视的裁判规则计算实际触发裁判的问题。
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.SetJudgeForm(IRaCIS.Core.Application.Service.Reading.Dto.SetJudgeFormInDto)">
<summary>
编辑裁判表单
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.SubmitJudgeForm(IRaCIS.Core.Application.Service.Reading.Dto.SetJudgeFormInDto)">
<summary>
提交裁判表单
</summary>
<param name="inDto"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.GetJudgeReadingInfo(IRaCIS.Core.Application.Service.Reading.Dto.GetJudgeReadingInfo)">
<summary>
获取裁判阅片任务信息
@@ -15246,6 +15455,16 @@
<param name="visitTaskId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.ApplyVisitJudgeRules(System.Collections.Generic.List{IRaCIS.Core.Application.Service.Reading.Dto.TaskAnswerDto},IRaCIS.Core.Domain.Models.JudgeRule)">
<summary>
应用访视裁判规则 以及剔除排除的问题
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.ApplyVisitJudgeRules(System.Collections.Generic.List{IRaCIS.Core.Application.Service.Reading.Dto.GlobalQuestionInfo},System.Decimal,IRaCIS.Core.Domain.Models.JudgeRule)">
<summary>
应用访视裁判规则 以及剔除排除的问题
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.SendWeComNotifier(System.Guid,System.String)">
<summary>
发送微信通知
@@ -15260,7 +15479,7 @@
<param name="visiTaskId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.ComputeJudgeResult(System.Collections.Generic.List{IRaCIS.Core.Application.Service.Reading.Dto.GroupTaskAnswerDto},System.Guid)">
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.ComputeJudgeResult(System.Collections.Generic.List{IRaCIS.Core.Application.Service.Reading.Dto.GroupTaskAnswerDto},System.Guid,System.Collections.Generic.HashSet{System.Guid},System.Boolean)">
<summary>
计算返回的结果 为True表示不相等
</summary>
@@ -16591,7 +16810,7 @@
<param name="regions"></param>
<param name="options"></param>
</member>
<member name="M:IRaCIS.Core.Application.Helper.DicomSortHelper.SortSlices``1(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.String},System.Func{``0,System.String},System.Func{``0,System.Nullable{System.Int32}})">
<member name="M:IRaCIS.Core.Application.Helper.DicomSortHelper.SortSlices``1(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.String},System.Func{``0,System.String},System.Func{``0,System.Nullable{System.Int32}},System.String)">
<summary>
DICOM Slice 排序(IPP + IOP
自动 fallback InstanceNumber
@@ -19340,7 +19559,7 @@
TrialSiteSurveyService
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteUserSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSite},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Doctor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VerificationCode},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteUserRole},Medallion.Threading.IDistributedLockProvider,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserType},IRaCIS.Core.Application.Service.IMailVerificationService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SiteSurveyLog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteEquipmentSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteUserSurvey},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSite},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Doctor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VerificationCode},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialSiteUserRole},Medallion.Threading.IDistributedLockProvider,IRaCIS.Core.Application.Auth.ITokenService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserType},IRaCIS.Core.Application.Service.IMailVerificationService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
<summary>
TrialSiteSurveyService
</summary>
@@ -19461,6 +19680,34 @@
<param name="siteSurvyeSubmit"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.GetSiteSurveyLogList(IRaCIS.Core.Application.Contracts.SiteSurveyLogQuery)">
<summary>
获取中心调研日志
</summary>
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.GetSiteSurveyEquipmentList(IRaCIS.Core.Application.Contracts.SiteSurveyEquipmentQuery)">
<summary>
获取中心设备信息
</summary>
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.GetSiteSurveyInfoList(IRaCIS.Core.Application.Contracts.SiteSurveyInfoQuery)">
<summary>
调研表基本信息
</summary>
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Contracts.TrialSiteSurveyService.GetTrialIsSPMJoin(System.Guid)">
<summary>
SPM 是否参与流程
</summary>
<param name="trialId"></param>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.Application.Contracts.TrialSiteUserSurveyService">
<summary>
TrialSiteUserSurveyService
@@ -269,9 +269,45 @@ public class SiteSurverRejectedEventConsumer(
if (context.Message.IsHaveSPMOrCPM)
{
//PM 驳回到SPM
if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
////PM 驳回到SPM
//if (siteSurveyInfo.State == TrialSiteSurveyEnum.CRCSubmitted)
//{
// var sPMOrCPMList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
// .Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM)
// .Select(t => new { t.UserRole.IdentityUser.EMail, t.UserRole.FullName, t.UserRole.UserTypeEnum, t.UserRole.IdentityUser.UserWorkLanguage }).ToList();
// var lan_SPMOrCPMList = sPMOrCPMList.Where(t => t.UserWorkLanguage == workLanguage);
// foreach (var user in lan_SPMOrCPMList)
// {
// messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
// }
// toUserName = string.Join('、', lan_SPMOrCPMList.Select(t => t.FullName));
//}
////SPM 驳回到CRC
//else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
//{
// //使用中心国家语言 一致才发送
// if ((siteInfo.Country == StaticData.SiteCountry.US && isEn_US) || (siteInfo.Country == StaticData.SiteCountry.CN && isEn_US == false))
// {
// messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
// }
//}
// PM 驳回到CRC
if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
{
//使用中心国家语言 一致才发送
if ((siteInfo.Country == StaticData.SiteCountry.US && isEn_US) || (siteInfo.Country == StaticData.SiteCountry.CN && isEn_US == false))
{
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
}
var sPMOrCPMList = _trialUserRoleRepository.Where(t => t.TrialId == trialId && t.TrialUser.IsDeleted == false)
.Where(t => t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM)
@@ -281,24 +317,10 @@ public class SiteSurverRejectedEventConsumer(
foreach (var user in lan_SPMOrCPMList)
{
messageToSend.To.Add(new MailboxAddress(user.FullName, user.EMail));
}
toUserName = string.Join('、', lan_SPMOrCPMList.Select(t => t.FullName));
}
//SPM 驳回到CRC
else if (siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit)
{
//使用中心国家语言 一致才发送
if ((siteInfo.Country == StaticData.SiteCountry.US && isEn_US) || (siteInfo.Country == StaticData.SiteCountry.CN && isEn_US == false))
{
messageToSend.To.Add(new MailboxAddress(toUserName, siteSurveyInfo.Email));
messageToSend.Cc.Add(new MailboxAddress(user.FullName, user.EMail));
}
}
}
else
{
@@ -312,6 +334,11 @@ public class SiteSurverRejectedEventConsumer(
}
}
Uri uri = new Uri(_systemEmailConfig.SiteUrl);
// 获取 Scheme + Host(不包含路径)
string baseUrl = uri.GetLeftPart(UriPartial.Authority);
//发件地址
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
@@ -330,8 +357,9 @@ public class SiteSurverRejectedEventConsumer(
siteInfo.TrialSiteCode, //中心编号
siteInfo.TrialSiteAliasName,//中心名称
siteSurveyInfo.LatestBackReason, //驳回原因
_systemEmailConfig.SiteUrl, //链接
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none")
$"{baseUrl}/researchLogin?trialId={trialId}", //链接
(siteSurveyInfo.State == TrialSiteSurveyEnum.ToSubmit ? "inline - block" : "none"),
trialInfo.LinkVerificationCode.IsNullOrEmpty()? trialInfo.ResearchProgramNo: trialInfo.LinkVerificationCode
);
return (topicStr, htmlBodyStr);
@@ -767,6 +767,7 @@ namespace IRaCIS.Core.Application.Service
TaskCode = AppSettings.GetCodeStr(currentMaxCodeInt, nameof(VisitTask)),
ReadingCategory = ReadingCategory.Visit,
TrialReadingCriterionId = trialReadingCriterionConfig.TrialReadingCriterionId,
IsNeedClinicalDataSign = isNeedClinicalDataSign,
IsClinicalDataSign = isClinicalDataSign,
@@ -1421,6 +1422,7 @@ namespace IRaCIS.Core.Application.Service
// AllocateTime = DateTime.Now,
//DoctorUserId = reReadingVisitTask.DoctorUserId,
IsIRImageDownloaded= reReadingVisitTask.IsIRImageDownloaded,
});
generateTaskCommand.Action(newTask);
@@ -2109,6 +2109,16 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
}
if (origenalTask.ReadingCategory == ReadingCategory.Judge)
{
//拷贝原始表单
if (visitTaskReReadingAppply.IsCopyOrigenalForms && influenceTask.Id == origenalTask.Id)
{
CopyForms(newTask, origenalTask);
}
}
}
}
@@ -2190,6 +2200,9 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
newTask.SuggesteFinishedTime = GetSuggessFinishTime(true, UrgentType.NotUrget);
CopyImages(newTask, influenceTask);
//裁判任务 需要进行特殊处理 在重阅逻辑里面处理
if (visitTaskReReadingAppply != null)
@@ -2197,7 +2210,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
//申请表 设置新任务Id
visitTaskReReadingAppply.NewReReadingTaskId = newTask.Id;
if (visitTaskReReadingAppply.IsCopyOrigenalForms && influenceTask.Id == origenalTask.Id)
{
if (origenalTask.ReadingCategory == ReadingCategory.Visit)
@@ -31,7 +31,7 @@ public class DeployConfigService(IMapper _mapper, IConfiguration _configuration,
//return config;
var path = Path.Combine( _hostEnvironment.ContentRootPath,$"appsettings.{_hostEnvironment.EnvironmentName}.json");
var path = Path.Combine(_hostEnvironment.ContentRootPath, $"appsettings.{_hostEnvironment.EnvironmentName}.json");
var json = File.ReadAllText(path);
@@ -123,7 +123,7 @@ public class DeployConfigService(IMapper _mapper, IConfiguration _configuration,
[HttpPost]
public async Task<IResponseOutput> UpdateSystemEmailConfig(SystemEmailSendConfig emailConfig)
{
var path = Path.Combine(_hostEnvironment.ContentRootPath,$"appsettings.{_hostEnvironment.EnvironmentName}.json");
var path = Path.Combine(_hostEnvironment.ContentRootPath, $"appsettings.{_hostEnvironment.EnvironmentName}.json");
//var path = $"appsettings.{_hostEnvironment.EnvironmentName}.json";
var @lock = _distributedLockProvider.CreateLock("WriteConfigFile");
@@ -171,4 +171,51 @@ public class DeployConfigService(IMapper _mapper, IConfiguration _configuration,
return ResponseOutput.Ok();
}
/// <summary>
/// 获取前端配置
/// </summary>
/// <returns></returns>
[AllowAnonymous]
public async Task<string> GetWebConfigInfo()
{
var path = Path.Combine(_hostEnvironment.ContentRootPath, $"appsettings.{_hostEnvironment.EnvironmentName}.json");
var json = File.ReadAllText(path);
var obj = JObject.Parse(json);
return obj["FrontWebConfig"]!.ToString();
}
public async Task<IResponseOutput> UpdateWebConfigInfo(string configStr)
{
var path = Path.Combine(_hostEnvironment.ContentRootPath, $"appsettings.{_hostEnvironment.EnvironmentName}.json");
//var path = $"appsettings.{_hostEnvironment.EnvironmentName}.json";
var @lock = _distributedLockProvider.CreateLock("WriteConfigFile");
using (await @lock.AcquireAsync())
{
string text = System.IO.File.ReadAllText(path);
// 修改
JObject obj = JObject.Parse(text);
// SystemEmailSendConfig 相关配置
obj["FrontWebConfig"] = configStr;
// 重新写入appsettings.json
string result = obj.ToString();
System.IO.File.WriteAllText(path, result);
}
return ResponseOutput.Ok();
}
}
@@ -10,6 +10,7 @@ using IRaCIS.Core.Infra.EFCore.Common;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Reflection;
using System.Text;
using static IRaCIS.Core.Application.Service.ExcelExportHelper;
@@ -40,6 +41,191 @@ namespace IRaCIS.Core.Application.Service.Common
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService
{
#region
[HttpPost]
public async Task<IActionResult> GetTrialSiteSurveyList_Export(TrialSiteSurveyQueryDTO inQuery,
[FromServices] IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
[FromServices] IDictionaryService _dictionaryService)
{
var trialSiteSurveyQueryable = _trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId).IgnoreQueryFilters()
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.UserKeyInfo), t => t.UserName.Contains(inQuery.UserKeyInfo) || t.Phone.Contains(inQuery.UserKeyInfo) || t.Email.Contains(inQuery.UserKeyInfo))
.WhereIf(inQuery.State != null, t => t.State == inQuery.State)
.WhereIf(inQuery.UpdateTimeBegin != null, t => t.UpdateTime >= inQuery.UpdateTimeBegin)
.WhereIf(inQuery.UpdateTimeEnd != null, t => t.UpdateTime <= inQuery.UpdateTimeEnd)
.ProjectTo<TrialSiteSurveyView>(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us })
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PreliminaryUserName), t => t.PreliminaryUser.RealName.Contains(inQuery.PreliminaryUserName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ReviewerUserName), t => t.ReviewerUser.RealName.Contains(inQuery.ReviewerUserName))
;
//var defalutSortArray = new string[] { /*nameof(TrialSiteSurveyView.LanguageType) + " desc", nameof(TrialSiteSurveyView.ShowOrder)*/ };
var list = await trialSiteSurveyQueryable.SortToListAsync(inQuery /*,defalutSortArray*/);
var exportInfo = new ExcelExportInfo();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialSiteSurvey_BasicInfo_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(TrialSiteSurveyView));
}
/// <summary>
/// 获取中心设备信息
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> GetSiteSurveyEquipmentList_Export(SiteSurveyEquipmentQuery inQuery,
[FromServices] IRepository<TrialSiteEquipmentSurvey> _trialSiteEquipmentSurveyRepository,
[FromServices] IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
[FromServices] IDictionaryService _dictionaryService)
{
//找到该中心最新的调研记录
var groupSelectIdQuery =
_trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.GroupBy(t => t.TrialSiteId)
.Select(g => g.OrderByDescending(u => u.CreateTime).Select(t => t.Id).First());
var query = _trialSiteEquipmentSurveyRepository.Where(t => t.TrialSiteSurvey.TrialId == inQuery.TrialId)
.IgnoreQueryFilters().Where(t => groupSelectIdQuery.Contains(t.TrialSiteSurveyId))
.WhereIf(inQuery.IsDeleted != null, t => t.TrialSiteSurvey.IsDeleted == inQuery.IsDeleted)
.WhereIf(inQuery.State != null, t => t.TrialSiteSurvey.State == inQuery.State)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteSurvey.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.TrialSiteCode.IsNotNullOrEmpty(), t => t.TrialSiteSurvey.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode))
.WhereIf(inQuery.TrialSiteName.IsNotNullOrEmpty(), t => t.TrialSiteSurvey.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteName) ||
t.TrialSiteSurvey.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteName))
.ProjectTo<SiteSurveyEquipmentDto>(_mapper.ConfigurationProvider);
var siteSurveryConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty;
var config = JsonConvert.DeserializeObject<TrialExtraConfig>(siteSurveryConfig) ?? new TrialExtraConfig();
var fields = new List<(string FieldName, int excelIndex)>()
{
("Parameters", 9),
("ManufacturerType", 10),
("ScannerType", 11),
("MagneticFieldStrengthType", 12),
("BodyCoilChannelCount", 13),
("HasDedicatedPdfFatQuantificationSequence", 14),
("PdfFatQuantificationSequenceType", 15),
//("OtherSequenceSpecification", 15),
("HasT2R2Correction", 16),
("CanFullyExportPdfParameterMapsAndRawDicom", 17),
("Note", 18),
};
var viewNameList = config.EquipmentControlFieldList.Where(t => t.IsView == true).Select(t => t.FiledName).ToList();
var columnsToDelete = fields.Where(f => !viewNameList.Any(t => f.FieldName == t)).Select(f => f.excelIndex).Distinct().OrderByDescending(i => i).ToList();
//var defalutSortArray = new string[] { /*nameof(TrialSiteSurveyView.LanguageType) + " desc", nameof(TrialSiteSurveyView.ShowOrder)*/ };
var list = await query.SortToListAsync(inQuery /*,defalutSortArray*/);
var exportInfo = new ExcelExportInfo();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialSiteSurvey_Equipment_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(SiteSurveyEquipmentDto), removeExcelIndexList: columnsToDelete);
}
/// <summary>
/// 调研表基本信息
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> GetSiteSurveyInfoList_Export(SiteSurveyInfoQuery inQuery,
[FromServices] IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
[FromServices] IDictionaryService _dictionaryService)
{
//找到该中心最新的调研记录
var groupSelectIdQuery =
_trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.GroupBy(t => t.TrialSiteId)
.Select(g => g.OrderByDescending(u => u.CreateTime).Select(t => t.Id).First());
var query = _trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId).IgnoreQueryFilters()
.Where(t => groupSelectIdQuery.Contains(t.Id))
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
.WhereIf(inQuery.State != null, t => t.State == inQuery.State)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.TrialSiteCode.IsNotNullOrEmpty(), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode))
.WhereIf(inQuery.TrialSiteName.IsNotNullOrEmpty(), t => t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteName) ||
t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteName))
.ProjectTo<TrialSiteSurveyView>(_mapper.ConfigurationProvider);
var siteSurveryConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty;
var config = JsonConvert.DeserializeObject<TrialExtraConfig>(siteSurveryConfig) ?? new TrialExtraConfig();
var fields = new List<(string FieldName, int excelIndex)>()
{
("AverageEngravingCycle", 8),
("IsRoutineMRIPDEE", 9),
("MRIPDFFScanTime", 10),
("MRIPDFFLeadTime", 11),
("MRIPDFFOther", 12),
("IsAuthorizeRadiologistsParticipate", 13),
("AssignFixedTechnologists", 14),
("IsConfirmImagingTechnologist", 15),
("NotConfirmReson", 16),
("EfficacyEvaluatorType", 17),
("IsFollowStudyParameters", 18),
("NotFollowReson", 19),
("ISStrictManualBurnFlag", 20),
("NotStrictManualBurnFlagReason",21)
};
//var viewNameList = config.NotShowFieldList;
var columnsToDelete = fields.Where(f => config.NotShowFieldList.Any(t => f.FieldName == t)).Select(f => f.excelIndex).Distinct().OrderByDescending(i => i).ToList();
//var defalutSortArray = new string[] { /*nameof(TrialSiteSurveyView.LanguageType) + " desc", nameof(TrialSiteSurveyView.ShowOrder)*/ };
var list = await query.SortToListAsync(inQuery /*,defalutSortArray*/);
var exportInfo = new ExcelExportInfo();
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialSiteSurvey_Info_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(TrialSiteSurveyView), removeExcelIndexList: columnsToDelete);
}
#endregion
/// <summary>
/// 质控问题答案导出
/// </summary>
@@ -1197,7 +1383,7 @@ namespace IRaCIS.Core.Application.Service.Common
t.VisitTaskList.Where(t => t.TaskState == TaskState.Effect && t.TrialReadingCriterionId == dto.TrialReadingCriterionId && t.TaskAllocationState == TaskAllocationState.Allocated && t.IsAnalysisCreate == false && t.ReadingCategory == ReadingCategory.Visit && t.ReadingTaskState == ReadingTaskState.HaveSigned).Count() == (int)trialReadingCriterion.ReadingType ?
ReadingStatusEnum.ReadCompleted : t.VisitTaskList.Where(t => t.TaskState == TaskState.Effect && t.TrialReadingCriterionId == dto.TrialReadingCriterionId && t.IsAnalysisCreate == false && t.ReadingCategory == ReadingCategory.Visit && t.TaskAllocationState == TaskAllocationState.Allocated).Count() == (int)trialReadingCriterion.ReadingType ? ReadingStatusEnum.ImageReading :
t.ReadingStatus
}).OrderBy(t=>t.VisitTaskNum).ToList(),
}).OrderBy(t => t.VisitTaskNum).ToList(),
ModuleList = subject.ReadModuleList.Where(t => t.TrialReadingCriterionId == dto.TrialReadingCriterionId).Select(t => new SubjectProgressDto.MouduleProgress()
{
@@ -2763,11 +2949,11 @@ namespace IRaCIS.Core.Application.Service.Common
if (criterion.CriterionType == CriterionType.OCT)
{
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_ReadingLession_Export, ExportCatogory = ExportResult.OCT_ReadingLession_Export });
list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_CDISC_Export, ExportCatogory = ExportResult.OCT_CDISC_Export });
//list.Add(new ExportDocumentDes() { Code = StaticData.Export.OCT_CDISC_Export, ExportCatogory = ExportResult.OCT_CDISC_Export });
}
if (criterion.CriterionType == CriterionType.IVUS)
{
list.Add(new ExportDocumentDes() { Code = StaticData.Export.IVUS_CDISC_Export, ExportCatogory = ExportResult.IVUS_CDISC_Export });
//list.Add(new ExportDocumentDes() { Code = StaticData.Export.IVUS_CDISC_Export, ExportCatogory = ExportResult.IVUS_CDISC_Export });
}
if (criterion.CriterionGroup != CriterionGroup.Tumor /*&& criterion.CriterionType != CriterionType.OCT && criterion.CriterionType != CriterionType.IVUS*/)
{
@@ -2863,7 +3049,7 @@ namespace IRaCIS.Core.Application.Service.Common
{
//仲裁阅片 才有裁判阅片明细表 同时要把模板里面的三列给去掉
//removeColumnIndexList = new List<int>() { 6, 7, 8 };
removeColumnIndexList = new List<int>() { 7, 8 ,9};
removeColumnIndexList = new List<int>() { 7, 8, 9 };
}
//阅片结果表 和阅片结果明细表 没有肿瘤学的时候需要移除肿瘤学三个字段
@@ -30,7 +30,10 @@ namespace IRaCIS.Core.Application.Service
public class TrialImageDownloadService(IRepository<Trial> _trialRepository, IRepository<SubjectVisit> _subjectVisitRepository, IOSSService _oSSService, IWebHostEnvironment _hostEnvironment,
IRepository<DicomStudy> _studyRepository,
IRepository<DicomSeries> _seriesRepository,
IRepository<DicomInstance> _instanceRepository) : BaseService
IRepository<DicomInstance> _instanceRepository,
IRepository<TaskInstance> _taskInstanceRepository,
IRepository<VisitTask> _visitTaskRepository
) : BaseService
{
@@ -491,6 +494,325 @@ namespace IRaCIS.Core.Application.Service
return ResponseOutput.Ok();
}
[HttpPost]
[AllowAnonymous]
public async Task<IResponseOutput> DownloadExcelTrialTaskImageZIPStream(Guid trialId)
{
var trialInfo = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo }).FirstOrDefault();
#region
var rootFolder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
Directory.CreateDirectory(rootFolder);
// 获取无效字符(系统定义的)
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
// 用正则表达式替换所有非法字符为下划线或空字符
string pattern = $"[{Regex.Escape(invalidChars)}]";
var regexNo = Regex.Replace(trialInfo.ResearchProgramNo, pattern, "_");
// 创建一个临时文件夹来存放文件
string trialFolderPath = Path.Combine(rootFolder, $"{regexNo}");//_{NewId.NextGuid()}
Directory.CreateDirectory(trialFolderPath);
#endregion
var oldVisits = MiniExcel.Query<SubjectTaskExcel>(Path.Combine(rootFolder, "Old.xlsx")).ToList();
var downloadTasks = MiniExcel.Query<SubjectTaskExcel>(Path.Combine(rootFolder, "download.xlsx")).ToList().Where(t => t.SubjectCode.IsNotNullOrEmpty() && t.TaskName.IsNotNullOrEmpty() && t.TaskBlindName.IsNotNullOrEmpty()).ToList();
downloadTasks = downloadTasks.Where(t => !oldVisits.Any(old => old.SubjectCode == t.SubjectCode && old.TaskBlindName == t.TaskBlindName && old.TaskName.Trim().ToLower() == t.TaskName.Trim().ToLower())).ToList();
var visitIndex = 0;
var skipCount = 0;
foreach (var downloadTask in downloadTasks)
{
visitIndex++;
var downloadInfo = _trialRepository.Where(t => t.Id == trialId).Select(t => new
{
t.ResearchProgramNo,
t.TrialCode,
TaskList = t.VisitTaskList.Where(t => t.TaskState == TaskState.Effect && t.DoctorUser.UserName == downloadTask.UserName
&& t.IsAnalysisCreate == false)
.Where(t => t.TaskName.Trim() == downloadTask.TaskName.Trim()
&& t.Subject.Code.Trim() == downloadTask.SubjectCode.Trim()
&& t.TaskBlindName.Trim() == downloadTask.TaskBlindName.Trim()
)
.Select(vt => new
{
VisitTaskId = vt.Id,
TrialSiteCode = vt.SourceSubjectVisit.TrialSite.TrialSiteCode,
SubjectCode = vt.Subject.Code,
UserName = vt.DoctorUser.UserName,
vt.TaskName,
vt.TaskBlindName,
VisitName = vt.SourceSubjectVisit.VisitName,
VisitNum = vt.SourceSubjectVisit.VisitNum,
StudyList = vt.TaskStudyList.Select(u => new
{
StudyId = u.Id,
u.PatientId,
u.StudyTime,
u.StudyCode,
u.StudyInstanceUid,
u.StudyDIRPath,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstancePathList = z.InstanceList.Select(k => new
{
InstanceId = k.Id,
k.Path,
k.IsEncapsulated,
k.NumberOfFrames,
}).ToList()
})
}).ToList(),
NoneDicomStudyList = vt.SourceSubjectVisit.NoneDicomStudyList.Where(t => t.IsReading && t.Modality != "OCT").Select(nd => new
{
nd.Modality,
nd.StudyCode,
nd.ImageDate,
FileList = nd.TaskNoneDicomFileList.Where(t => t.IsReading && t.VisitTaskId == vt.Id).Select(file => new
{
file.FileName,
file.Path,
file.FileType
}).ToList()
}).ToList()
}).OrderBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ToList()
}).FirstOrDefault();
if (downloadInfo == null)
{
continue;
}
#region
var logFilePath = Path.Combine(rootFolder, $"{trialId}_{regexNo}_download_log.csv");
if (File.Exists(logFilePath))
{
var existVisits = MiniExcel.Query<SubjectTaskExcel>(logFilePath, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
{
StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
}).ToList();
if (existVisits.Any(old => old.TaskName == downloadTask.TaskName
&& old.SubjectCode == downloadTask.SubjectCode
&& old.TaskBlindName.Trim().ToLower() == downloadTask.TaskBlindName.Trim().ToLower()
&& old.UserName.Trim().ToLower() == downloadTask.UserName.Trim().ToLower()
))
{
Log.Logger.Warning($"[{visitIndex}] Excel显示已下载,跳过当前:{downloadTask.SubjectCode} {downloadTask.TaskName} {downloadTask.TaskBlindName} {downloadTask.UserName}");
skipCount++;
continue;
}
}
#endregion
foreach (var taskItem in downloadInfo.TaskList)
{
if (taskItem.StudyList.Count() == 0 && taskItem.NoneDicomStudyList.SelectMany(t=>t.FileList).Count() == 0)
{
Log.Logger.Warning($"[{visitIndex}]查询无检查,跳过当前访视:{downloadTask.SubjectCode} {downloadTask.TaskName} {downloadTask.TaskBlindName} {downloadTask.UserName}");
skipCount++;
continue;
}
try
{
#region 访
var zipItems = new List<ZipItem>();
var visitFolderName = $"{taskItem.SubjectCode}_{taskItem.TaskBlindName.Trim()}";
#region DICOM
foreach (var studyInfo in taskItem.StudyList)
{
var dirDic = new Dictionary<string, string>();
var studyFolderName = $"{studyInfo.StudyCode}_{studyInfo.StudyTime:yyyy-MM-dd}_{string.Join('_', studyInfo.SeriesList.Select(t => t.Modality).Distinct())}";
#region DICOMDIR
if (!_taskInstanceRepository.Where(t => taskItem.VisitTaskId == t.VisitTaskId).Any(c => c.TransferSytaxUID == string.Empty))
{
var list = _visitTaskRepository.Where(t => t.Id == taskItem.VisitTaskId).SelectMany(t => t.TaskStudyList)
.SelectMany(t => t.InstanceList.Where(t => t.StudyId == studyInfo.StudyId))
.Select(t => new StudyDIRInfo()
{
DicomStudyId = t.TaskStudy.Id,
PatientId = downloadInfo.TrialCode + "-" + t.TaskStudy.Subject.Code,
PatientName = t.TaskStudy.PatientName,
PatientBirthDate = t.TaskStudy.PatientBirthDate,
PatientSex = t.TaskStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.TaskStudy.StudyId,
DicomStudyDate = t.TaskStudy.DicomStudyDate,
DicomStudyTime = t.TaskStudy.DicomStudyTime,
AccessionNumber = t.TaskStudy.AccessionNumber,
StudyDescription = t.TaskStudy.Description,
SeriesInstanceUid = t.TaskSeries.SeriesInstanceUid,
Modality = t.TaskSeries.Modality,
DicomSeriesDate = t.TaskSeries.DicomSeriesDate,
DicomSeriesTime = t.TaskSeries.DicomSeriesTime,
SeriesNumber = t.TaskSeries.SeriesNumber,
SeriesDescription = t.TaskSeries.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSytaxUID = t.TransferSytaxUID,
}).ToList();
foreach (var group in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{
using var ms = new MemoryStream();
await DicomDIRHelper.GenerateStudyDIR(group.ToList(), dirDic, outputStream: ms);
var dicomDirBytes = ms.ToArray();
zipItems.Add(new ZipItem
{
ZipEntryPath = $"{visitFolderName}/{studyFolderName}/DICOMDIR",
CustomWriter = async entryStream =>
{
await entryStream.WriteAsync(dicomDirBytes);
}
});
}
}
#endregion
foreach (var seriesInfo in studyInfo.SeriesList)
{
foreach (var instanceInfo in seriesInfo.InstancePathList)
{
zipItems.Add(new ZipItem
{
OssPath = instanceInfo.Path,
IsEncapsulated = instanceInfo.IsEncapsulated,
ZipEntryPath = $"{visitFolderName}/" + $"{studyFolderName}/" + $"IMAGE/" + $"{dirDic[instanceInfo.InstanceId.ToString()]}"
});
}
}
}
#endregion
#region NoneDicom
foreach (var study in taskItem.NoneDicomStudyList)
{
var studyFolderName = $"{study.StudyCode}_" + $"{study.ImageDate:yyyy-MM-dd}_" + $"{study.Modality}";
foreach (var file in study.FileList)
{
zipItems.Add(new ZipItem
{
OssPath = HttpUtility.UrlDecode(file.Path),
ZipEntryPath = $"{visitFolderName}/" + $"{studyFolderName}/" + $"{Path.GetFileName(file.FileName)}"
});
}
}
#endregion
#region zip
var zipPath = Path.Combine(trialFolderPath, visitFolderName + ".zip");
Log.Logger.Warning($"[{visitIndex}] {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 开始打包下载访视:{visitFolderName}");
try
{
await CreateVisitZipAsync(zipPath, zipItems);
//Log.Logger.Warning($"zip exists={File.Exists(zipPath)} size={new FileInfo(zipPath).Length}");
Log.Logger.Warning($"[{visitIndex}] {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 下载完成:{visitFolderName}");
DownloadLogger.TaskWrite(logFilePath, taskItem.SubjectCode, taskItem.TaskName, taskItem.TaskBlindName, taskItem.UserName, "Success");
}
catch (Exception ex)
{
Log.Logger.Warning($"出现异常{ex}自动删除压缩包:{visitFolderName}");
//如果有异常,删除失败的压缩包
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
}
#endregion
#endregion
}
catch (Exception ex)
{
Log.Logger.Error(ex, $"导出失败:{downloadTask.SubjectCode} {downloadTask.TaskName} {downloadTask.TaskBlindName} {downloadTask.UserName}");
}
}
}
return ResponseOutput.Ok();
}
#endregion
@@ -542,6 +864,53 @@ namespace IRaCIS.Core.Application.Service
writer.WriteLine(line);
}
public static void TaskWrite(
string logFilePath,
string subjectCode,
string taskName,
string taskBlindName,
string userName,
string? message = null)
{
bool fileExists = File.Exists(logFilePath);
// 一次性打开文件流
using var stream = new FileStream(
logFilePath,
FileMode.Append,
FileAccess.Write,
FileShare.ReadWrite);
// 首次创建时写入 BOM
if (!fileExists)
{
var bom = new UTF8Encoding(true).GetPreamble();
stream.Write(bom, 0, bom.Length);
}
using var writer = new StreamWriter(stream, new UTF8Encoding(false));
// 写入表头
if (!fileExists)
{
writer.WriteLine("Time,SubjectCode,TaskName,TaskBlindName,UserName,Message");
}
// 写入数据
string line = string.Join(",",
[
Escape(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
subjectCode,
taskName,
taskBlindName,
userName,
Escape(message)
]);
writer.WriteLine(line);
}
private static string Escape(string? value)
{
if (string.IsNullOrEmpty(value))
@@ -5,6 +5,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc.DTO
{
public class SubjectImageUploadDTO
{
public bool? IsIRImageDownloaded { get; set; }
public Guid VisitTaskId { get; set; }
public Guid TrialSiteId { get; set; }
@@ -676,6 +676,7 @@ namespace IRaCIS.Core.Application.Contracts
public class TaskNoneDicomStudyDTO : NoneDicomStudyBasicInfo
{
public bool? IsIRImageDownloaded { get; set; }
public Guid VisitTaskId { get; set; }
public int UploadedFileCount { get; set; }
@@ -1073,6 +1074,13 @@ namespace IRaCIS.Core.Application.Contracts
public string? Name { get; set; }
}
public class DownloadImageSuccessCommand
{
public Guid TrialImageDownloadId { get; set; }
public List<Guid> VisitTaskIdList { get; set; }
}
public class SubjectVisitTaskInfo
{
public Guid SubjectVisitId { get; set; }
@@ -1093,6 +1101,8 @@ namespace IRaCIS.Core.Application.Contracts
public bool? IsUrgent { get; set; }
public int? State { get; set; }
}
@@ -1122,6 +1132,10 @@ namespace IRaCIS.Core.Application.Contracts
public int? NoneDicomStudyCount { get; set; }
public int? MarkNoneDicomStudyCount { get; set; }
public DateTime? LatestDownloadTime { get; set; }
public DateTime? LatestUploadTime { get; set; }
}
public class SubjectVisitMarkStudyDto
@@ -119,11 +119,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var subjectCode = string.Empty;
var subjectId = inQuery.SubjectId;
bool? isIRImageDownloaded = true;
bool? isIRImageDownloaded = null;
if(inQuery.VisitTaskId != null)
if (inQuery.VisitTaskId != null)
{
//isIRImageDownloaded= _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => t.IsIRImageDownloaded).FirstOrDefault();
isIRImageDownloaded = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => t.IsIRImageDownloaded).FirstOrDefault();
}
if (criterionInfo.IsReadingTaskViewInOrder == ReadingOrder.Random)
@@ -228,12 +228,13 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed
/* && t.DoctorUserId == _userInfo.UserRoleId*/ && t.TaskState == TaskState.Effect)
&& t.DoctorUserId == _userInfo.UserRoleId && t.TaskState == TaskState.Effect)
//满足 有序,或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
.Select(u => new SubjectImageUploadDTO()
{
VisitTaskId = u.Id,
IsIRImageDownloaded = u.IsIRImageDownloaded,
SubejctId = u.SubjectId,
@@ -331,7 +332,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
return ResponseOutput.Ok(list, new { TrialModality = criterionInfo.Modalitys, IsReadingTaskViewInOrder = criterionInfo.IsReadingTaskViewInOrder, IsIRImageDownloaded= isIRImageDownloaded });
return ResponseOutput.Ok(list, new { TrialModality = criterionInfo.Modalitys, IsReadingTaskViewInOrder = criterionInfo.IsReadingTaskViewInOrder, IsIRImageDownloaded = isIRImageDownloaded });
}
@@ -391,9 +392,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
};
//var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
return ResponseOutput.Ok(Guid.NewGuid());
return ResponseOutput.Ok(addEntity.Id);
}
@@ -580,25 +581,25 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var trialId = incommand.TrialId;
//var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
//studyMonitor.UploadFinishedTime = DateTime.Now;
//studyMonitor.ArchiveFinishedTime = DateTime.Now;
//studyMonitor.FailedFileCount = incommand.FailedFileCount;
//studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
//studyMonitor.RecordPath = incommand.RecordPath;
//studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
studyMonitor.UploadFinishedTime = DateTime.Now;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
studyMonitor.FailedFileCount = incommand.FailedFileCount;
studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
studyMonitor.RecordPath = incommand.RecordPath;
studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString());
var findStudy = await _taskStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
//studyMonitor.StudyId = studyId;
//studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
studyMonitor.StudyId = studyId;
studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
//studyMonitor.IsDicomReUpload = findStudy != null;
studyMonitor.IsDicomReUpload = findStudy != null;
//上传
if (findStudy == null)
if (studyMonitor.IsDicomReUpload == false)
{
@@ -640,7 +641,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
await _taskStudyRepository.AddAsync(study);
//studyMonitor.StudyCode = study.StudyCode;
studyMonitor.StudyCode = study.StudyCode;
foreach (var seriesItem in incommand.Study.SeriesList)
@@ -689,9 +690,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
////重传的时候也要赋值检查Id
//studyMonitor.StudyId = findStudy.Id;
//studyMonitor.StudyCode = findStudy.StudyCode;
//重传的时候也要赋值检查Id
studyMonitor.StudyId = findStudy.Id;
studyMonitor.StudyCode = findStudy.StudyCode;
//特殊处理逻辑
findStudy.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(findStudy.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
@@ -739,7 +740,6 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
//找到该序列已经存在的instanceId
var existInstanceIdList = _taskInstanceRepository.Where(t => t.SeriesId == dicomSeries.Id).Select(t => t.Id).ToList();
foreach (var instanceItem in seriesItem.InstanceList)
{
var insntance = _mapper.Map<TaskInstance>(instanceItem);
@@ -765,14 +765,6 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
findStudy.InstanceCount++;
}
else
{
//更新,需要删除缓存,并更新路径
await _oSSService.DeleteFromPrefix(insntance.Path, true);
await _taskInstanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new TaskInstance() { Path = insntance.Path });
}
}
// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
@@ -945,7 +937,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsImageFilter, t.CriterionType, t.TrialId, t.CriterionModalitys, t.IsReadingTaskViewInOrder }).FirstNotNullAsync();
var config = await _subjectRepository.Where(t => t.Id == subjectId).Select(t => new { t.Trial.ImageFormatList, t.Trial.StudyNameList, t.Trial.IsShowStudyName, IsIRImageDownloaded= isIRImageDownloaded }).FirstOrDefaultAsync();
var config = await _subjectRepository.Where(t => t.Id == subjectId).Select(t => new { t.Trial.ImageFormatList, t.Trial.StudyNameList, t.Trial.IsShowStudyName, IsIRImageDownloaded = isIRImageDownloaded }).FirstOrDefaultAsync();
//靶段标注上传,查看访视级别,上传绑定访视级别
@@ -1010,7 +1002,8 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var list = _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId && t.SubjectVisit.CheckState == CheckStateEnum.CVPassed)
var list = _noneDicomStudyReposiotry.Where(t => t.IsReading)
.Where(t => t.SubjectId == subjectId && t.SubjectVisit.CheckState == CheckStateEnum.CVPassed)
.WhereIf(inQuery.SubjectVisitId != null, t => t.SubjectVisitId == inQuery.SubjectVisitId)
//.WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
.Select(u => new TaskNoneDicomStudyDTO()
@@ -1039,12 +1032,13 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
ReadingFileCount = u.NoneDicomFileList.Where(t => t.IsReading).Count(),
}).ToList();
}).OrderBy(t => t.VisitName).ThenBy(t => t.Modality).ToList();
var noneDicomStudyIdList = list.Select(t => t.Id).ToList();
var noneDicomStudyIdList = list.Where(t => !(t.Modality != "IVUS" && t.ReadingFileCount == 0)).Select(t => t.Id).ToList();
var noneDicomStudyList = _noneDicomStudyFileReposiotry.Where(t => t.ImageLabelNoneDicomStudyId != null)
var noneDicomStudyList = _noneDicomStudyFileReposiotry.Where(t => t.IsReading)
.Where(t => t.ImageLabelNoneDicomStudyId != null)
.Where(t => noneDicomStudyIdList.Contains((Guid)t.ImageLabelNoneDicomStudyId!))
.Select(u => new NoneDicomFileInfo
{
@@ -1068,10 +1062,10 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
else
{
var query = from u in _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed /*&& t.DoctorUserId == doctorUserId*/ && t.TaskState == TaskState.Effect)
&& t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed && t.DoctorUserId == doctorUserId && t.TaskState == TaskState.Effect)
//满足 有序,或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(info.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
join ns in _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId).WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
join ns in _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId).Where(t => t.IsReading).WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
on u.SourceSubjectVisitId equals ns.SubjectVisitId
select new TaskNoneDicomStudyDTO()
@@ -1083,6 +1077,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
ReadingTaskState = u.ReadingTaskState,
SourceSubjectVisitId = u.SourceSubjectVisitId,
VisitTaskId = u.Id,
IsIRImageDownloaded = u.IsIRImageDownloaded,
Id = ns.Id,
Description = ns.Description,
@@ -1378,7 +1373,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
VisitName = item.VisitName,
//取dicom
DicomStudyList = item.DicomStudyList,
DicomStudyList = item.DicomStudyList.Where(t => t.ReadingSeriesCount > 0).ToList(),
}).ToList();
var noneStudyList = list.Where(item => item.NoneDicomStudyList.Count > 0)
@@ -1391,12 +1386,12 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
VisitName = item.VisitName,
//非dicom
NoneDicomStudyList = item.NoneDicomStudyList,
NoneDicomStudyList = item.NoneDicomStudyList.Where(t => t.ReadingFileCount > 0).ToList(),
}).ToList();
result.AddRange(dicomStudyList);
result.AddRange(noneStudyList);
result.AddRange(dicomStudyList.Where(t => t.DicomStudyList.Count > 0));
result.AddRange(noneStudyList.Where(t => t.NoneDicomStudyList.Count > 0));
#endregion
return ResponseOutput.Ok(result);
@@ -1497,7 +1492,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
CriterionModalitys = item.CriterionModalitys,
SourceSubjectVisitId = item.SourceSubjectVisitId,
//取dicom
DicomStudyList = item.DicomStudyList,
DicomStudyList = item.DicomStudyList.Where(t => t.ReadingSeriesCount > 0).ToList(),
}).ToList();
var noneStudyList = list.Where(item => item.NoneDicomStudyList.Count > 0)
@@ -1512,12 +1507,12 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
CriterionModalitys = item.CriterionModalitys,
SourceSubjectVisitId = item.SourceSubjectVisitId,
//非dicom
NoneDicomStudyList = item.NoneDicomStudyList,
NoneDicomStudyList = item.NoneDicomStudyList.Where(t => t.ReadingFileCount > 0).ToList()
}).ToList();
result.AddRange(dicomStudyList);
result.AddRange(noneStudyList);
result.AddRange(dicomStudyList.Where(t => t.DicomStudyList.Count > 0));
result.AddRange(noneStudyList.Where(t => t.NoneDicomStudyList.Count > 0));
#endregion
@@ -1675,7 +1670,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
#endregion
var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id) && t.CheckState == CheckStateEnum.CVPassed))
//一致性分析,导致查询出来两条数据
//一致性分析,导致查询出来两条数据
join visitTask in _visitTaskRepository.Where(t => taskIdList.Contains(t.Id)) on sv.Id equals visitTask.SourceSubjectVisitId into cc
from leftVisitTask in cc.DefaultIfEmpty()
select new ImageDownloadDto()
@@ -1897,16 +1892,18 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
/// <summary>
/// 影像下载成功回调
/// </summary>
/// <param name="trialImageDownloadId"></param>
/// <param name="incommand"></param>
/// <returns></returns>
public async Task<IResponseOutput> DownloadImageSuccess(Guid trialImageDownloadId, Guid? visitTaskId)
public async Task<IResponseOutput> DownloadImageSuccess(DownloadImageSuccessCommand incommand)
{
await _trialImageDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == trialImageDownloadId, u => new TrialImageDownload()
await _trialImageDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == incommand.TrialImageDownloadId, u => new TrialImageDownload()
{ DownloadEndTime = DateTime.Now, IsSuccess = true }, true);
if (visitTaskId != null)
if (incommand.VisitTaskIdList != null && incommand.VisitTaskIdList.Count > 0)
{
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.Id == visitTaskId.Value, u => new VisitTask() { IsIRImageDownloaded = true });
incommand.VisitTaskIdList = incommand.VisitTaskIdList.Distinct().ToList();
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => incommand.VisitTaskIdList.Contains(t.Id), u => new VisitTask() { IsIRImageDownloaded = true });
}
return ResponseOutput.Ok();
}
@@ -2465,18 +2462,42 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
SubjectCode = t.Code,
IsUrgent = t.IsUrgent,
LatestDownloadTime = t.TrialImageDownloadList.Where(t => t.CreateUserRole.UserTypeEnum == UserTypeEnum.IndependentReviewer)
.OrderByDescending(t => t.CreateTime).Select(t => (DateTime?)t.CreateTime).FirstOrDefault(),
LatestUploadTime = t.SubjectVisitList
.Where(v => v.SubmitState == SubmitStateEnum.Submitted && v.CheckState == CheckStateEnum.CVPassed)
.SelectMany(v => v.TaskStudyList)
.Select(s => (DateTime?)s.CreateTime) // 假设字段名为 CreateTime,根据实际情况调整
.Union(
t.SubjectVisitList
.Where(v => v.SubmitState == SubmitStateEnum.Submitted && v.CheckState == CheckStateEnum.CVPassed)
.SelectMany(v => v.NoneDicomStudyList)
.Where(n => n.ImageLabelNoneDicomFileList.Any())
.Select(s => (DateTime?)s.CreateTime) // 假设字段名为 CreateTime,根据实际情况调整
)
.OrderByDescending(time => time)
.FirstOrDefault(),
VisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(),
MarkIVUSVisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(t => t.NoneDicomStudyList.Where(t => t.Modality == "IVUS").SelectMany(c => c.ImageLabelNoneDicomFileList).Any()),
MarkOCTVisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(t => t.NoneDicomStudyList.Where(t => t.Modality == "OCT").SelectMany(c => c.ImageLabelNoneDicomFileList).Any()),
DicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.StudyList).Count(),
//MarkDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted).SelectMany(t => t.TaskStudyList).Count(),
//DicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.StudyList).Count(),
NoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.NoneDicomStudyList).Count(),
//MarkNoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted).SelectMany(t => t.NoneDicomStudyList).Where(t => t.ImageLabelNoneDicomFileList.Any()).Count(),
}).ToPagedListAsync(inQuery);
//MarkDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.TaskStudyList).Count(),
//NoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.NoneDicomStudyList).Count(),
//MarkNoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.NoneDicomStudyList).Where(t => t.ImageLabelNoneDicomFileList.Any()).Count(),
})
.Where(t => t.VisitCount > 0)
.WhereIf(inQuery.State == 0, t => t.LatestDownloadTime == null)//待处理
.WhereIf(inQuery.State == 1, t => t.LatestDownloadTime != null && (2 * t.VisitCount) != (t.MarkIVUSVisitCount + t.MarkOCTVisitCount))//处理中
.WhereIf(inQuery.State == 2, t => t.LatestDownloadTime != null && (2 * t.VisitCount) == (t.MarkIVUSVisitCount + t.MarkOCTVisitCount))//已完成
.ToPagedListAsync(inQuery);
return ResponseOutput.Ok(list);
}
@@ -9,7 +9,7 @@ namespace IRaCIS.Core.Application.Services
{
[ApiExplorerSettings(GroupName = "Image")]
[AllowAnonymous]
public class InstanceService(IRepository<DicomInstance> _instanceRepository,
public class InstanceService(IRepository<DicomInstance> _instanceRepository, IRepository<DicomSeries> _seriesRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService, IInstanceService
{
@@ -29,12 +29,15 @@ namespace IRaCIS.Core.Application.Services
.OrderBy(s => s.InstanceNumber).ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.ProjectTo<DicomInstanceDTO>(_mapper.ConfigurationProvider).ToListAsync();
var des = _seriesRepository.Where(t => t.Id == seriesId).Select(t => t.Description).FirstOrDefault();
// ⭐ DICOM 空间排序(带兜底)
var sorted = DicomSortHelper.SortSlices(
list,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber
x => x.InstanceNumber,
des
);
var seriesInfo = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => new
@@ -59,7 +59,8 @@ namespace IRaCIS.Core.Application.Services
instances,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber
x => x.InstanceNumber,
series.Description
);
series.InstanceInfoList = sorted.Select(k =>
@@ -104,13 +105,24 @@ namespace IRaCIS.Core.Application.Services
.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, t.FileSize ,t.IsMasked}).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 ,t.IsMasked, t.ImagePositionPatient, t.ImageOrientationPatient }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList)
{
series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
var instances = instanceList.Where(x => x.SeriesId == series.Id);
// ⭐ DICOM 空间排序(带兜底)
var sorted = DicomSortHelper.SortSlices(
instances,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber,
series.Description
);
series.InstanceInfoList = sorted.Select(k =>
new InstanceBasicInfo()
{
Id = k.Id,
@@ -1,5 +1,4 @@
using DocumentFormat.OpenXml.InkML;
using FellowOakDicom;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.IO.Buffer;
using IRaCIS.Core.Application.Contracts;
@@ -68,80 +67,6 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
#endregion
}
public class DeleteImagePathCommand
{
public string Path { get; set; }
}
public async Task<IResponseOutput> DeleteImageCache(DeleteImagePathCommand incommand)
{
await _oSSService.DeleteFromPrefix(incommand.Path, true);
return ResponseOutput.Ok();
}
public async Task<IResponseOutput> GetAnonymizeInfo(Guid visitTaskId, Guid? subjectVisitId)
{
Guid svId = Guid.Empty;
if (subjectVisitId != null)
{
svId = subjectVisitId.Value;
}
else
{
svId = (Guid)_visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => t.SourceSubjectVisitId).FirstOrDefault();
}
// 写入dicom 固定的信息,以及组织路径的信息 以及匿名化的信息
var otherData = GetSaveToDicomInfo(svId);
var anonymizeList = _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7)).Result;
return ResponseOutput.Ok(new
{
DicomStoreInfo = otherData,
AnonymizeFixedList = anonymizeList.Where(t => t.IsFixed).ToList(),
AnonymizeNotFixedList = anonymizeList.Where(t => t.IsFixed == false).ToList()
});
}
public async Task<IResponseOutput> UpdateModality(Guid seriesId, string modality, bool isCRCReplace,
[FromServices] IRepository<TaskSeries> _taskSeriesRepository,
[FromServices] IRepository<TaskStudy> _taskStudyRepository
)
{
if (isCRCReplace)
{
await _dicomSeriesRepository.BatchUpdateNoTrackingAsync(t => t.Id == seriesId, u => new DicomSeries() { Modality = modality });
var studyId = _dicomSeriesRepository.Where(t => t.Id == seriesId).Select(t => t.StudyId).FirstOrDefault();
//处理Modality
var seriesModalityList = _dicomStudyRepository.Where(t => t.Id == studyId).SelectMany(u => u.SeriesList.Select(t => t.Modality)).Distinct();
string ModaliyStr = string.Join('、', seriesModalityList.ToList());
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == studyId, u => new DicomStudy() { Modalities = ModaliyStr });
}
else
{
await _taskSeriesRepository.BatchUpdateNoTrackingAsync(t => t.Id == seriesId, u => new TaskSeries() { Modality = modality });
var studyId = _taskSeriesRepository.Where(t => t.Id == seriesId).Select(t => t.StudyId).FirstOrDefault();
//处理Modality
var seriesModalityList = _taskStudyRepository.Where(t => t.Id == studyId).SelectMany(u => u.SeriesList.Select(t => t.Modality)).Distinct();
string ModaliyStr = string.Join('、', seriesModalityList.ToList());
await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == studyId, u => new TaskStudy() { Modalities = ModaliyStr });
}
return ResponseOutput.Ok();
}
private static async Task<bool> TryWriteMergedDicomAsync(Func<Task<Stream>> sourceFactory, Stream output)
{
@@ -656,9 +581,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
};
//var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);
return ResponseOutput.Ok(Guid.NewGuid());
return ResponseOutput.Ok(addEntity.Id);
}
@@ -719,20 +644,20 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
var trialId = incommand.TrialId;
//var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
//studyMonitor.UploadFinishedTime = DateTime.Now;
//studyMonitor.ArchiveFinishedTime = DateTime.Now;
//studyMonitor.FailedFileCount = incommand.FailedFileCount;
//studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
//studyMonitor.RecordPath = incommand.RecordPath;
//studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
studyMonitor.UploadFinishedTime = DateTime.Now;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
studyMonitor.FailedFileCount = incommand.FailedFileCount;
studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
studyMonitor.RecordPath = incommand.RecordPath;
studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
var findStudy = await _dicomStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
//studyMonitor.StudyId = studyId;
//studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
//studyMonitor.IsDicomReUpload = findStudy != null;
studyMonitor.StudyId = studyId;
studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
studyMonitor.IsDicomReUpload = findStudy != null;
if (incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Count() == 0)
@@ -743,7 +668,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
//上传
if ((findStudy != null) == false)
if (studyMonitor.IsDicomReUpload == false)
{
var addStudy = _mapper.Map<DicomStudy>(incommand.Study);
@@ -788,7 +713,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
//studyMonitor.StudyCode = addStudy.StudyCode;
studyMonitor.StudyCode = addStudy.StudyCode;
foreach (var seriesItem in incommand.Study.SeriesList)
@@ -847,14 +772,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
DicomSeries dicomSeries = await _dicomSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
var isNewSeries = false;
//判断重复
if (dicomSeries == null)
{
isNewSeries = true;
var series = _mapper.Map<DicomSeries>(seriesItem);
series.Id = seriesId;
@@ -870,53 +790,29 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
//新的序列 那么 检查的序列数量+1
findStudy.SeriesCount += 1;
}
//else
//{
// //该序列掉了instance
// dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
//}
//找到该序列已经存在的instanceId
var existInstanceIdList = _dicomInstanceRepository.Where(t => t.SeriesId == dicomSeries.Id).Select(t => t.Id).ToList();
else
{
//该序列掉了instance
dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
}
foreach (var instanceItem in seriesItem.InstanceList)
{
var insntance = _mapper.Map<DicomInstance>(instanceItem);
insntance.Id = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString());
insntance.StudyId = findStudy.Id;
insntance.SeriesId = dicomSeries.Id;
if (!existInstanceIdList.Any(t => t == insntance.Id))
{
insntance.StudyId = findStudy.Id;
insntance.SeriesId = dicomSeries.Id;
insntance.TrialId = incommand.TrialId;
insntance.SubjectId = incommand.SubjectId;
insntance.SubjectVisitId = incommand.SubjectVisitId;
await _dicomInstanceRepository.AddAsync(insntance);
if (isNewSeries == false)
{
dicomSeries.InstanceCount++;
}
findStudy.InstanceCount++;
}
else
{
//更新,需要删除缓存,并更新路径
await _oSSService.DeleteFromPrefix(insntance.Path, true);
await _dicomInstanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == insntance.Id, u => new DicomInstance() { Path = insntance.Path });
}
insntance.TrialId = incommand.TrialId;
insntance.SubjectId = incommand.SubjectId;
insntance.SubjectVisitId = incommand.SubjectVisitId;
await _dicomInstanceRepository.AddAsync(insntance);
}
//// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
//findStudy.InstanceCount += seriesItem.InstanceList.Count;
// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
findStudy.InstanceCount += seriesItem.InstanceList.Count;
if (incommand.Study.RadionuclideTotalDose != string.Empty
@@ -168,19 +168,6 @@ namespace IRaCIS.Core.Application.Service
.Where(t => t.UserTypeId == _userInfo.UserTypeId && (t.Menu.MenuType == "M" || t.Menu.MenuType == "C") && t.Menu.IsEnable)
.ProjectTo<MenuTreeNode>(_mapper.ConfigurationProvider).ToListAsync();
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA)
{
var otherGuid = new List<Guid>() { Guid.Parse("41d2bcbe-4ae2-4158-856e-08da0661d17d"), Guid.Parse("5acebe02-99de-4e39-f090-08da0c7fe82c") };
var otherlist = await _userTypeMenuRepository
.Where(t => otherGuid.Contains(t.MenuId) && (t.Menu.MenuType == "M" || t.Menu.MenuType == "C") && t.Menu.IsEnable)
.ProjectTo<MenuTreeNode>(_mapper.ConfigurationProvider).Distinct().ToListAsync();
menuFunctionlist.AddRange(otherlist);
}
var list = menuFunctionlist!.ToTree((root, child) => child!.ParentId == Guid.Empty,
(root, child) => child!.ParentId == root!.MenuId,
(child, datalist) =>
@@ -250,6 +250,37 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public string TaskBlindName { get; set; }
public string SubjectID { get; set; }
/// <summary>
/// 靶段
/// </summary>
public string TargetSegment { get; set; } = string.Empty;
/// <summary>
/// 靶段备注
/// </summary>
public string TargetSegmentRemarks { get; set; } = string.Empty;
/// <summary>
/// ROI段落总长度
/// </summary>
public string ROIAllLength { get; set; } = string.Empty;
/// <summary>
/// 回撤中的图像帧数
/// </summary>
public string PullbackFrameCount { get; set; } = string.Empty;
/// <summary>
/// 斑块类型
/// </summary>
public string PlaqueType { get; set; } = string.Empty;
/// <summary>
/// 访视点备注(如有)
/// </summary>
public string AdjustReason { get; set; } = string.Empty;
}
public class OCTFCTUploadData
@@ -2199,6 +2199,21 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
/// </summary>
public DefaultSegmentNameDto DefaultSegmentName { get; set; }
/// <summary>
/// 仲裁模式
/// </summary>
public JudgeMode JudgeModeEnum { get; set; } = JudgeMode.SelectOne;
/// <summary>
/// 裁判规则
/// </summary>
public JudgeRule JudgeRuleEnum { get; set; } = JudgeRule.Consistent;
/// <summary>
/// 仲裁对象
/// </summary>
public ArbitrationRule ArbitrationRule { get; set; } = ArbitrationRule.Reading;
}
public class GetReadingImgInDto
@@ -2437,6 +2452,102 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public Guid VisitTaskId { get; set; }
}
public class GetSingleVisitJudgeAnswerInDto
{
[NotDefault]
public Guid VisitTaskId { get; set; }
}
public class GetSingleVisitJudgeAnswerOutDto
{
public Guid R1VisitTaskId { get; set; }
public Guid R2VisitTaskId { get; set; }
public List<SingleVisitJudgeAnswerItemDto> QuestionList { get; set; } = new List<SingleVisitJudgeAnswerItemDto>();
}
public class SingleVisitJudgeAnswerItemDto
{
public Guid ReadingQuestionId { get; set; }
public string QuestionName { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public string TypeValue { get; set; } = string.Empty;
public int ShowOrder { get; set; }
public string R1Answer { get; set; } = string.Empty;
public string R2Answer { get; set; } = string.Empty;
public TableQuestionType? QuestionGenre { get; set; }
public string DictionaryCode { get; set; } = string.Empty;
public ValueUnit? Unit { get; set; }
public string? CustomUnit { get; set; }
public ValueOfType? ValueType { get; set; }
public JudgeReadingQuestionType QuestionType { get; set; } = JudgeReadingQuestionType.Question;
}
public class GetJudgeFormInDto
{
[NotDefault]
public Guid VisitTaskId { get; set; }
}
public class GetJudgeFormOutDto
{
public string JudgeResultRemark { get; set; } = string.Empty;
public List<string> JudgeResultImagePathList { get; set; } = new List<string>();
/// <summary>
/// 本次生成裁判的触发问题(包含自动计算题追溯到的源问题)
/// </summary>
public List<Guid> TriggerJudgeQuestionIds { get; set; } = new List<Guid>();
public List<JudgeFormQuestionDto> QuestionList { get; set; } = new List<JudgeFormQuestionDto>();
}
public class JudgeFormQuestionDto
{
public Guid ReadingQuestionId { get; set; }
/// <summary>
/// 是否为本次生成裁判的触发问题
/// </summary>
public bool IsTriggerJudge { get; set; }
public string QuestionName { get; set; } = string.Empty;
public string Type { get; set; } = string.Empty;
public ShowQuestion ShowQuestion { get; set; }
public string TypeValue { get; set; } = string.Empty;
public int ShowOrder { get; set; }
public string Answer { get; set; } = string.Empty;
public TableQuestionType? QuestionGenre { get; set; }
public string DictionaryCode { get; set; } = string.Empty;
public ValueUnit? Unit { get; set; }
public DataSources DataSource { get; set; }
public string? CustomUnit { get; set; }
public ValueOfType? ValueType { get; set; }
public string ClassifyAlgorithms { get; set; }
public ClassifyType? ClassifyType { get; set; }
public Guid? ClassifyQuestionId { get; set; }
public JudgeReadingQuestionType QuestionType { get; set; } = JudgeReadingQuestionType.Question;
}
public class SetJudgeFormInDto
{
[NotDefault]
public Guid VisitTaskId { get; set; }
public string JudgeResultRemark { get; set; } = string.Empty;
public List<string> JudgeResultImagePathList { get; set; } = new List<string>();
public List<JudgeFormAnswerDto> QuestionList { get; set; } = new List<JudgeFormAnswerDto>();
}
public class JudgeFormAnswerDto
{
public Guid ReadingQuestionId { get; set; }
public string Answer { get; set; } = string.Empty;
}
public class JudgeReadingInfoDto
{
public string VisitName { get; set; }
@@ -2908,12 +3019,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
}
public class AnswerCombinationDto
{
public List<string> AnswerGroupA { get; set; }
public List<string> AnswerGroupB { get; set; }
}
public class TaskAnswerDto
{
@@ -6,6 +6,104 @@ using System.ComponentModel.DataAnnotations.Schema;
namespace IRaCIS.Core.Application.Service.Reading.Dto
{
public class GetTrialQuestionVisitJudgeRuleInDto
{
[NotDefault]
public Guid TrialId { get; set; }
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
public decimal VisitNum { get; set; }
public Guid? ReadingQuestionId { get; set; }
}
public class SetTrialQuestionVisitJudgeRuleInDto
{
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
public decimal VisitNum { get; set; }
public List<TrialQuestionVisitJudgeRuleItemDto> QuestionList { get; set; } = new List<TrialQuestionVisitJudgeRuleItemDto>();
}
public class CopyTrialQuestionVisitJudgeRuleInDto
{
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
/// <summary>
/// 来源访视
/// </summary>
public decimal SourceVisitNum { get; set; }
/// <summary>
/// 目标访视
/// </summary>
public decimal TargetVisitNum { get; set; }
}
public class ApplyBaseLineTrialQuestionVisitJudgeRuleInDto
{
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
}
public class TrialQuestionVisitJudgeRuleItemDto
{
public Guid ReadingQuestionTrialId { get; set; }
public string QuestionName { get; set; } = string.Empty;
public int ShowOrder { get; set; }
public List<string> AnswerGroup { get; set; } = new List<string>();
public JudgeTypeEnum JudgeType { get; set; }
public decimal? JudgeDifferenceValue { get; set; }
public JudgeDifferenceType JudgeDifferenceType { get; set; }
/// <summary>
/// 类型
/// </summary>
public string Type { get; set; } = string.Empty;
public string PageName { get; set; }
public string TypeValue { get; set; }
/// <summary>
/// 问题类型
/// </summary>
public TableQuestionType? QuestionGenre { get; set; }
/// <summary>
/// 字典code
/// </summary>
public string DictionaryCode { get; set; } = string.Empty;
/// <summary>
/// 单位
/// </summary>
public ValueUnit? Unit { get; set; }
public string CustomUnit { get; set; } = string.Empty;
/// <summary>
/// 答案组合
/// </summary>
public List<AnswerCombinationDto> AnswerCombination { get; set; }
}
public class TumorAssessmentView : AddOrUpdateTumorAssessmentInDto
{
@@ -702,6 +800,16 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public Guid TrialReadingCriterionId { get; set; }
}
public class SetTrialJudgeRuleInfoInDto
{
[NotDefault]
public Guid TrialReadingCriterionId { get; set; }
public JudgeMode JudgeModeEnum { get; set; } = JudgeMode.SelectOne;
public JudgeRule JudgeRuleEnum { get; set; } = JudgeRule.Consistent;
public JudgeGenerate JudgeGenerateEnum { get; set; } = JudgeGenerate.Instant;
}
public class GetTrialJudgyInfoOutDto
{
public Guid TrialId { get; set; }
@@ -717,6 +825,24 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
/// 仲裁规则
/// </summary>
public ArbitrationRule ArbitrationRule { get; set; }
/// <summary>
/// 仲裁模式
/// </summary>
public JudgeMode JudgeModeEnum { get; set; } = JudgeMode.SelectOne;
/// <summary>
/// 裁判规则
/// </summary>
public JudgeRule JudgeRuleEnum { get; set; } = JudgeRule.Consistent;
/// <summary>
/// 裁判任务生成
/// </summary>
public JudgeGenerate JudgeGenerateEnum { get; set; } = JudgeGenerate.Instant;
public bool IsSigned { get; set; } = false;
}
public enum NeedSynchronize
@@ -1625,6 +1751,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public bool IsGetAll { get; set; } = false;
public bool IsGetJudge { get; set; } = false;
}
@@ -15,6 +15,7 @@ namespace IRaCIS.Core.Application.Contracts
Task TriggerJudgeQuestion(Guid visitTaskId);
Task<IResponseOutput> SubmitVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto);
Task<IResponseOutput> SubmitJudgeForm(SetJudgeFormInDto inDto);
Task<IResponseOutput> SubmitJudgeVisitTaskResult(SaveJudgeVisitTaskResult inDto);
Task<GetOncologyReadingInfoOutDto> GetOncologyReadingInfo(GetOncologyReadingInfoInDto inDto);
@@ -370,13 +370,62 @@ namespace IRaCIS.Core.Application.Service.RC
TrialId = x.TrialId,
IsReadingTaskViewInOrder = x.IsReadingTaskViewInOrder,
ArbitrationRule = x.ArbitrationRule,
IsArbitrationReading = x.IsArbitrationReading
IsArbitrationReading = x.IsArbitrationReading,
JudgeModeEnum = x.JudgeModeEnum,
JudgeRuleEnum = x.JudgeRuleEnum,
JudgeGenerateEnum = x.JudgeGenerateEnum,
IsSigned = x.IsSigned,
}).FirstNotNullAsync();
return result;
}
/// <summary>
/// 编辑裁判规则配置
/// </summary>
[HttpPost]
public async Task<IResponseOutput> SetTrialJudgeRuleInfo(SetTrialJudgeRuleInfoInDto inDto)
{
if (inDto.JudgeRuleEnum == JudgeRule.Consistent)
{
if (await _readingQuestionTrialRepository.AnyAsync(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId&& x.IsJudgeQuestion && x.LimitShow != LimitShow.AllShow))
{
var questionList = await _readingQuestionTrialRepository
.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId && x.IsJudgeQuestion && x.LimitShow != LimitShow.AllShow)
.OrderBy(x => x.ShowOrder)
.Select(x => new TrialQuestionVisitJudgeRuleItemDto
{
ReadingQuestionTrialId = x.Id,
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
ShowOrder = x.ShowOrder,
Type = x.Type,
TypeValue = x.TypeValue,
QuestionGenre = x.QuestionGenre,
DictionaryCode = x.DictionaryCode,
Unit = x.Unit,
CustomUnit = x.CustomUnit,
})
.ToListAsync();
var questionName=string.Join(",", questionList.Select(x => x.QuestionName));
//---当前标准裁判规则为一致性,但存在非全部显示的裁判问题,操作失败
throw new BusinessValidationFailedException(_localizer["JudgeCanNotLimitShow", questionName]);
}
}
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial()
{
JudgeModeEnum = inDto.JudgeModeEnum,
JudgeRuleEnum = inDto.JudgeRuleEnum,
JudgeGenerateEnum = inDto.JudgeGenerateEnum,
});
return ResponseOutput.Ok(await _readingQuestionCriterionTrialRepository.SaveChangesAsync());
}
/// <summary>
/// 新增修改项目问题标准(项目)
/// </summary>
@@ -482,7 +531,6 @@ namespace IRaCIS.Core.Application.Service.RC
return ResponseOutput.Ok(result);
}
#endregion
#region
@@ -1,3 +1,4 @@
using DocumentFormat.OpenXml.Office.SpreadSheetML.Y2023.MsForms;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Share;
@@ -33,10 +34,225 @@ namespace IRaCIS.Core.Application.Service
IRepository<OrganInfo> _organInfoRepository,
IRepository<ReadingTableQuestionSystem> _readingTableQuestionSystemRepository,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswer,
IRepository<PreviousPDF> _previousPDFRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IReadingQuestionService
IRepository<PreviousPDF> _previousPDFRepository,
IRepository<ReadingQuestionVisitJudgeRule> _readingQuestionVisitJudgeRuleRepository,
IRepository<VisitStage> _visitStageRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IReadingQuestionService
{
#region 访
/// <summary>
/// 获取项目阅片标准各访视的裁判规则配置。
/// 未配置规则的访视问题也会返回,供前端直接进行配置。
/// </summary>
[HttpPost]
public async Task<List<TrialQuestionVisitJudgeRuleItemDto>> GetTrialQuestionVisitJudgeRule(GetTrialQuestionVisitJudgeRuleInDto inDto)
{
var questionList = await _readingQuestionTrialRepository
.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId && x.IsJudgeQuestion)
.Where(x => x.LimitShow == LimitShow.AllShow
|| (x.LimitShow == LimitShow.BaseLineShow && inDto.VisitNum == 0)
|| (x.LimitShow == LimitShow.FollowShow && inDto.VisitNum != 0)
|| (x.LimitShow == LimitShow.ExcludeSomeVisits && !x.ExcludeShowVisitList.Contains(inDto.VisitNum)))
.WhereIf(inDto.ReadingQuestionId != null, x => x.Id == inDto.ReadingQuestionId)
.OrderBy(x => x.ShowOrder)
.Select(x => new TrialQuestionVisitJudgeRuleItemDto
{
ReadingQuestionTrialId = x.Id,
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
ShowOrder = x.ShowOrder,
Type = x.Type,
TypeValue = x.TypeValue,
QuestionGenre = x.QuestionGenre,
DictionaryCode = x.DictionaryCode,
Unit = x.Unit,
CustomUnit = x.CustomUnit,
})
.ToListAsync();
var questionIds = questionList.Select(x => x.ReadingQuestionTrialId).ToList();
var ruleList = await _readingQuestionVisitJudgeRuleRepository
.Where(x => x.VisitNum == inDto.VisitNum && questionIds.Contains(x.ReadingQuestionId))
.ToListAsync();
return questionList.Select(question =>
{
var rule = ruleList.FirstOrDefault(x => x.ReadingQuestionId == question.ReadingQuestionTrialId);
return new TrialQuestionVisitJudgeRuleItemDto
{
ReadingQuestionTrialId = question.ReadingQuestionTrialId,
QuestionName = question.QuestionName,
ShowOrder = question.ShowOrder,
Type = question.Type,
PageName = question.PageName,
TypeValue = question.TypeValue,
QuestionGenre = question.QuestionGenre,
DictionaryCode = question.DictionaryCode,
Unit = question.Unit,
CustomUnit = question.CustomUnit,
AnswerGroup = rule?.AnswerGroup ?? new List<string>(),
AnswerCombination = rule?.AnswerCombination ?? new List<AnswerCombinationDto>(),
JudgeType = rule?.JudgeType ?? JudgeTypeEnum.None,
JudgeDifferenceValue = rule?.JudgeDifferenceValue,
JudgeDifferenceType = rule?.JudgeDifferenceType ?? default,
};
}).ToList();
}
/// <summary>
/// 编辑项目阅片标准各访视的裁判规则配置。
/// </summary>
[HttpPost]
public async Task<IResponseOutput> SetTrialQuestionVisitJudgeRule(SetTrialQuestionVisitJudgeRuleInDto inDto)
{
var questionIds = inDto.QuestionList.Select(x => x.ReadingQuestionTrialId).ToList();
await _readingQuestionVisitJudgeRuleRepository.BatchDeleteNoTrackingAsync(x =>
x.VisitNum == inDto.VisitNum && questionIds.Contains(x.ReadingQuestionId));
var rules = inDto.QuestionList.Select(question => new ReadingQuestionVisitJudgeRule
{
Id = NewId.NextGuid(),
ReadingQuestionId = question.ReadingQuestionTrialId,
VisitNum = inDto.VisitNum,
AnswerGroup = question.AnswerGroup ?? new List<string>(),
AnswerCombination = question.AnswerCombination ?? new List<AnswerCombinationDto>(),
JudgeType = question.JudgeType,
JudgeDifferenceValue = question.JudgeDifferenceValue,
JudgeDifferenceType = question.JudgeDifferenceType,
}).ToList();
if (rules.Count > 0)
{
await _readingQuestionVisitJudgeRuleRepository.AddRangeAsync(rules);
}
return ResponseOutput.Result(await _readingQuestionVisitJudgeRuleRepository.SaveChangesAsync());
}
/// <summary>
/// 复制其他访视的项目阅片标准裁判规则配置。
/// 目标访视不适用的问题保留其已有的不适用规则,不参与复制。
/// </summary>
[HttpPost]
public async Task<IResponseOutput> CopyTrialQuestionVisitJudgeRule(CopyTrialQuestionVisitJudgeRuleInDto inDto)
{
var targetQuestionIds = await _readingQuestionTrialRepository
.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId && x.IsJudgeQuestion)
.Where(x => x.LimitShow == LimitShow.AllShow
|| (x.LimitShow == LimitShow.BaseLineShow && inDto.TargetVisitNum == 0)
|| (x.LimitShow == LimitShow.FollowShow && inDto.TargetVisitNum != 0)
|| (x.LimitShow == LimitShow.ExcludeSomeVisits && !x.ExcludeShowVisitList.Contains(inDto.TargetVisitNum)))
.Select(x => x.Id)
.ToListAsync();
if (targetQuestionIds.Count == 0)
{
return ResponseOutput.Ok();
}
var sourceRules = await _readingQuestionVisitJudgeRuleRepository
.Where(x => x.VisitNum == inDto.SourceVisitNum && targetQuestionIds.Contains(x.ReadingQuestionId))
.ToListAsync();
await _readingQuestionVisitJudgeRuleRepository.BatchDeleteNoTrackingAsync(x =>
x.VisitNum == inDto.TargetVisitNum && targetQuestionIds.Contains(x.ReadingQuestionId));
var targetRules = sourceRules.Select(rule => new ReadingQuestionVisitJudgeRule
{
Id = NewId.NextGuid(),
ReadingQuestionId = rule.ReadingQuestionId,
VisitNum = inDto.TargetVisitNum,
AnswerGroup = rule.AnswerGroup,
AnswerCombination = rule.AnswerCombination,
JudgeType = rule.JudgeType,
JudgeDifferenceValue = rule.JudgeDifferenceValue,
JudgeDifferenceType = rule.JudgeDifferenceType,
}).ToList();
if (targetRules.Count > 0)
{
await _readingQuestionVisitJudgeRuleRepository.AddRangeAsync(targetRules);
}
return ResponseOutput.Result(await _readingQuestionVisitJudgeRuleRepository.SaveChangesAsync());
}
/// <summary>
/// 将基线访视(VisitNum = 0)的裁判规则配置应用到其他所有访视。
/// 仅复制在基线和目标访视均适用的问题;目标访视不适用的问题保留其已有规则。
/// </summary>
[HttpPost]
public async Task<IResponseOutput> ApplyBaseLineTrialQuestionVisitJudgeRule(ApplyBaseLineTrialQuestionVisitJudgeRuleInDto inDto)
{
var trialCriterion = await _readingQuestionCriterionTrialRepository
.Where(x => x.Id == inDto.TrialReadingCriterionId)
.FirstNotNullAsync();
var targetVisitNums = await _visitStageRepository
.Where(x => x.TrialId == trialCriterion.TrialId && x.VisitNum != 0)
.Select(x => x.VisitNum)
.Distinct()
.ToListAsync();
// 计划外访视不在 VisitStage 中,也应同步基线规则。
targetVisitNums.Add(-1);
targetVisitNums = targetVisitNums.Distinct().ToList();
var rulesToAdd = new List<ReadingQuestionVisitJudgeRule>();
foreach (var targetVisitNum in targetVisitNums)
{
// 仅保留在基线和当前目标访视都显示的问题。
var targetQuestionIds = await _readingQuestionTrialRepository
.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId && x.IsJudgeQuestion)
.Where(x => x.LimitShow == LimitShow.AllShow
|| (x.LimitShow == LimitShow.ExcludeSomeVisits
&& !x.ExcludeShowVisitList.Contains(0)
&& !x.ExcludeShowVisitList.Contains(targetVisitNum)))
.Select(x => x.Id)
.ToListAsync();
if (targetQuestionIds.Count == 0)
{
continue;
}
var baseLineRules = await _readingQuestionVisitJudgeRuleRepository
.Where(x => x.VisitNum == 0 && targetQuestionIds.Contains(x.ReadingQuestionId))
.ToListAsync();
await _readingQuestionVisitJudgeRuleRepository.BatchDeleteNoTrackingAsync(x =>
x.VisitNum == targetVisitNum && targetQuestionIds.Contains(x.ReadingQuestionId));
rulesToAdd.AddRange(baseLineRules.Select(rule => new ReadingQuestionVisitJudgeRule
{
Id = NewId.NextGuid(),
ReadingQuestionId = rule.ReadingQuestionId,
VisitNum = targetVisitNum,
AnswerGroup = rule.AnswerGroup,
AnswerCombination = rule.AnswerCombination,
JudgeType = rule.JudgeType,
JudgeDifferenceValue = rule.JudgeDifferenceValue,
JudgeDifferenceType = rule.JudgeDifferenceType,
}));
}
if (rulesToAdd.Count > 0)
{
await _readingQuestionVisitJudgeRuleRepository.AddRangeAsync(rulesToAdd);
await _readingQuestionVisitJudgeRuleRepository.SaveChangesAsync();
}
return ResponseOutput.Result(true);
}
#endregion
#region
@@ -570,7 +786,7 @@ namespace IRaCIS.Core.Application.Service
if (isArbitrationReading && (await _readingQuestionTrialRepository.AnyAsync(x => x.Id == indto.Id && x.IsJudgeQuestion && x.JudgeType != JudgeTypeEnum.None)))
{
//---当前问题已经设置了裁判标准了,修改失败
throw new BusinessValidationFailedException(_localizer["ReadingQuestion_JudgmentSet"]);
// throw new BusinessValidationFailedException(_localizer["ReadingQuestion_JudgmentSet"]);
}
}
@@ -620,9 +836,61 @@ namespace IRaCIS.Core.Application.Service
}
var entity = await _readingQuestionTrialRepository.InsertOrUpdateAsync(indto, true);
await AddNAJudgeRule(entity);
return ResponseOutput.Ok(entity.Id.ToString());
}
/// <summary>
/// 添加问题的不适用规则
/// </summary>
/// <returns></returns>
private async Task AddNAJudgeRule(ReadingQuestionTrial entity)
{
List<decimal> visitNums = new List<decimal>();
if (entity.IsJudgeQuestion)
{
var visitStageNums = await _visitStageRepository
.Where(x => x.TrialId == entity.TrialId)
.Select(x => x.VisitNum)
.Distinct()
.ToListAsync();
switch (entity.LimitShow)
{
case LimitShow.BaseLineShow:
visitNums = visitStageNums.Where(x => x > 0).ToList();
visitNums.Add(-1);
break;
case LimitShow.FollowShow:
visitNums.Add(0);
break;
case LimitShow.ExcludeSomeVisits:
visitNums = entity.ExcludeShowVisitList;
break;
}
}
if (visitNums.Count==0)
{
return;
}
await _readingQuestionVisitJudgeRuleRepository.BatchDeleteNoTrackingAsync(x =>
x.ReadingQuestionId == entity.Id && visitNums.Contains(x.VisitNum));
var rules = visitNums.Select(visitNum => new ReadingQuestionVisitJudgeRule
{
Id = NewId.NextGuid(),
ReadingQuestionId = entity.Id,
VisitNum = visitNum,
JudgeType = JudgeTypeEnum.NotApplicable,
}).ToList();
await _readingQuestionVisitJudgeRuleRepository.AddRangeAsync(rules);
await _readingQuestionVisitJudgeRuleRepository.SaveChangesAsync();
}
/// <summary>
/// 获取项目问题(项目)
/// </summary>
@@ -687,6 +955,7 @@ namespace IRaCIS.Core.Application.Service
if (inDto.TrialReadingCriterionId != null)
{
return await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId)
.WhereIf(inDto.IsGetJudge,x=>x.IsJudgeQuestion)
.WhereIf(!inDto.IsGetAll, x => x.DataSource == DataSources.Automatic && x.Type == "number")
.Select(x => new CalculateRelationDto()
{
@@ -26,6 +26,7 @@ namespace IRaCIS.Core.Application.Service
public partial class ReadingImageTaskService(
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<VisitStage> _visitStageRepository,
IRepository<Trial> _trialRepository,
IRepository<TaskInstance> _taskInstanceRepository,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
@@ -66,6 +67,7 @@ namespace IRaCIS.Core.Application.Service
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<ReadingQuestionVisitJudgeRule> _readingQuestionVisitJudgeRuleRepository,
IRepository<ReadingQuestionSystem> _readingQuestionSystem,
IRepository<CriterionKeyFileRead> _criterionKeyFileReadRepository,
IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
@@ -1074,28 +1076,28 @@ namespace IRaCIS.Core.Application.Service
/// <exception cref="BusinessValidationFailedException"></exception>
private async Task VerifyTaskIsSign(Guid visitTaskid)
{
//var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskid).FirstNotNullAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskid).FirstNotNullAsync();
//if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.ReadingTaskState == ReadingTaskState.HaveSigned))
//{
// throw new BusinessValidationFailedException(_localizer["ReadingImage_BeSigned"]);
//}
if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.ReadingTaskState == ReadingTaskState.HaveSigned))
{
throw new BusinessValidationFailedException(_localizer["ReadingImage_BeSigned"]);
}
//if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.TaskState != TaskState.Effect))
//{
// throw new BusinessValidationFailedException(_localizer["ReadingImage_Beinvalid"]);
//}
if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.TaskState != TaskState.Effect))
{
throw new BusinessValidationFailedException(_localizer["ReadingImage_Beinvalid"]);
}
//if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
//&& x.IsAnalysisCreate && taskInfo.IsAnalysisCreate
//&& x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect &&
//((x.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed && x.DoctorUserId == taskInfo.DoctorUserId) || x.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
&& x.IsAnalysisCreate && taskInfo.IsAnalysisCreate
&& x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect &&
((x.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed && x.DoctorUserId == taskInfo.DoctorUserId) || x.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed)
//))
//{
// throw new BusinessValidationFailedException(_localizer["ReadingImage_PresenceReview"]);
//}
))
{
throw new BusinessValidationFailedException(_localizer["ReadingImage_PresenceReview"]);
}
}
@@ -3920,6 +3922,10 @@ namespace IRaCIS.Core.Application.Service
x.ReadingToolList,
x.CircleRadius,
x.DefaultSegmentName,
x.JudgeGenerateEnum,
x.JudgeModeEnum,
x.JudgeRuleEnum,
x.ArbitrationRule,
}).FirstNotNullAsync();
task.IsReadingShowPreviousResults = criterionInfo.IsReadingShowPreviousResults;
@@ -3983,6 +3989,9 @@ namespace IRaCIS.Core.Application.Service
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);
task.JudgeModeEnum = criterionInfo.JudgeModeEnum;
task.JudgeRuleEnum = criterionInfo.JudgeRuleEnum;
task.ArbitrationRule = criterionInfo.ArbitrationRule;
// 添加默认答案
if (inDto.VisitTaskId == null && visitTaskInfo.ReadingTaskState != ReadingTaskState.HaveSigned)
{
@@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using MimeKit;
using Newtonsoft.Json;
using System.Linq.Dynamic.Core;
namespace IRaCIS.Core.Application.Service
{
@@ -23,6 +24,29 @@ namespace IRaCIS.Core.Application.Service
/// </summary>
public partial class ReadingImageTaskService : BaseService, IReadingImageTaskService
{
/// <summary>
/// 统一生成裁判任务
/// </summary>
/// <param name=""></param>
/// <returns></returns>
[HttpPost]
public async Task PhasedGenerationJudge(Guid trialReadingCriterionId)
{
var visitTaskList = await _visitTaskRepository.Where(x =>
x.TrialReadingCriterionId == trialReadingCriterionId
&& (x.ReadingCategory == ReadingCategory.Visit||x.ReadingCategory == ReadingCategory.Global)
&&x.ReadingTaskState == ReadingTaskState.HaveSigned
&&x.TaskState==TaskState.Effect
&&!x.IsCalculatedJudge
).ToListAsync();
foreach (var item in visitTaskList)
{
await TriggerJudgeQuestion(item.Id);
}
}
#region
/// <summary>
@@ -91,6 +115,337 @@ namespace IRaCIS.Core.Application.Service
#region
/// <summary>
/// 获取单访视裁判答案
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<GetSingleVisitJudgeAnswerOutDto> GetSingleVisitJudgeAnswer(GetSingleVisitJudgeAnswerInDto inDto)
{
var judgeDataInfo = await _readingJudgeInfoRepository
.Where(x => x.JudgeTaskId == inDto.VisitTaskId)
.FirstNotNullAsync();
var taskIds = new List<Guid> { judgeDataInfo.TaskIdOne, judgeDataInfo.TaskIdTwo };
var readingTasks = await _visitTaskRepository
.Where(x => taskIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.ArmEnum,
x.TrialReadingCriterionId,
x.VisitTaskNum,
})
.ToListAsync();
var r1Task = readingTasks.First(x => x.ArmEnum == Arm.DoubleReadingArm1);
var r2Task = readingTasks.First(x => x.ArmEnum == Arm.DoubleReadingArm2);
var judgeRule = await _readingQuestionCriterionTrialRepository
.Where(x => x.Id == r1Task.TrialReadingCriterionId)
.Select(x => x.JudgeRuleEnum)
.FirstNotNullAsync();
var displayQuestions = await GetJudgeDisplayQuestions(r1Task.TrialReadingCriterionId, r1Task.VisitTaskNum, judgeRule, false);
var judgeAnswers = displayQuestions
.Select(x => new SingleVisitJudgeAnswerItemDto
{
ReadingQuestionId = x.Id,
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
Type = x.Type,
TypeValue = x.TypeValue,
ShowOrder = x.ShowOrder,
QuestionGenre = x.QuestionGenre,
DictionaryCode = x.DictionaryCode,
Unit = x.Unit,
CustomUnit = x.CustomUnit,
ValueType = x.ValueType,
})
.ToList();
var displayQuestionIds = judgeAnswers.Select(x => x.ReadingQuestionId).ToList();
var answerList = await _readingTaskQuestionAnswerRepository
.Where(x => taskIds.Contains(x.VisitTaskId) && displayQuestionIds.Contains(x.ReadingQuestionTrialId))
.Select(x => new
{
x.VisitTaskId,
x.ReadingQuestionTrialId,
x.Answer,
})
.ToListAsync();
judgeAnswers.ForEach(question =>
{
question.R1Answer = answerList.FirstOrDefault(x => x.VisitTaskId == r1Task.Id && x.ReadingQuestionTrialId == question.ReadingQuestionId)?.Answer ?? string.Empty;
question.R2Answer = answerList.FirstOrDefault(x => x.VisitTaskId == r2Task.Id && x.ReadingQuestionTrialId == question.ReadingQuestionId)?.Answer ?? string.Empty;
});
return new GetSingleVisitJudgeAnswerOutDto
{
R1VisitTaskId = r1Task.Id,
R2VisitTaskId = r2Task.Id,
QuestionList = judgeAnswers,
};
}
/// <summary>
/// 获取裁判表单
/// </summary>
[HttpPost]
public async Task<GetJudgeFormOutDto> GetJudgeForm(GetJudgeFormInDto inDto)
{
var judgeDataInfo = await _readingJudgeInfoRepository
.Where(x => x.JudgeTaskId == inDto.VisitTaskId)
.FirstNotNullAsync();
var taskIds = new List<Guid> { judgeDataInfo.TaskIdOne, judgeDataInfo.TaskIdTwo };
var readingTask = await _visitTaskRepository
.Where(x => taskIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.ArmEnum,
x.TrialReadingCriterionId,
x.VisitTaskNum,
})
.FirstNotNullAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
var judgeRule = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskInfo.TrialReadingCriterionId).Select(x => x.JudgeRuleEnum).FirstNotNullAsync();
var questionList = await GetJudgeDisplayQuestions(taskInfo.TrialReadingCriterionId, readingTask.VisitTaskNum, judgeRule, true);
var questionIds = questionList.Select(x => x.Id).ToList();
var answers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && questionIds.Contains(x.ReadingQuestionTrialId)).ToListAsync();
var triggerJudgeQuestionIds = await GetTriggerJudgeQuestionIds(taskIds, questionList, readingTask.VisitTaskNum, judgeRule);
// 自动计算题本身触发裁判时,同时标记其所有源问题(包含多层计算依赖)。
var calculateQuestions = await _readingQuestionTrialRepository
.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId)
.ToListAsync();
var calculateQuestionMap = calculateQuestions.ToDictionary(x => x.Id);
var pendingQuestionIds = new Queue<Guid>(triggerJudgeQuestionIds);
while (pendingQuestionIds.Count > 0)
{
var questionId = pendingQuestionIds.Dequeue();
if (!calculateQuestionMap.TryGetValue(questionId, out var question))
{
continue;
}
foreach (var calculateQuestionId in question.CalculateQuestionList
.Where(x => !x.IsTable && x.QuestionId.HasValue)
.Select(x => x.QuestionId!.Value))
{
if (triggerJudgeQuestionIds.Add(calculateQuestionId))
{
pendingQuestionIds.Enqueue(calculateQuestionId);
}
}
}
return new GetJudgeFormOutDto
{
JudgeResultRemark = taskInfo.JudgeResultRemark,
JudgeResultImagePathList = taskInfo.JudgeResultImagePathList,
TriggerJudgeQuestionIds = triggerJudgeQuestionIds.ToList(),
QuestionList = questionList.Select(x => new JudgeFormQuestionDto
{
ReadingQuestionId = x.Id,
IsTriggerJudge = triggerJudgeQuestionIds.Contains(x.Id),
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
Type = x.Type,
ShowQuestion = x.ShowQuestion,
TypeValue = x.TypeValue,
ShowOrder = x.ShowOrder,
Answer = answers.FirstOrDefault(answer => answer.ReadingQuestionTrialId == x.Id)?.Answer ?? string.Empty,
QuestionGenre = x.QuestionGenre,
DictionaryCode = x.DictionaryCode,
Unit = x.Unit,
DataSource = x.DataSource,
CustomUnit = x.CustomUnit,
ValueType = x.ValueType,
ClassifyQuestionId = x.ClassifyQuestionId,
ClassifyAlgorithms = x.ClassifyAlgorithms,
ClassifyType = x.ClassifyType
}).ToList(),
};
}
/// <summary>
/// 重新按当前访视的裁判规则计算实际触发裁判的问题。
/// </summary>
private async Task<HashSet<Guid>> GetTriggerJudgeQuestionIds(List<Guid> taskIds, List<ReadingQuestionTrial> questionList, decimal visitTaskNum, JudgeRule judgeRule)
{
var questionIds = questionList.Select(x => x.Id).ToList();
var questionAnswers = await (from answer in _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId) && questionIds.Contains(x.ReadingQuestionTrialId))
join question in _readingQuestionTrialRepository.Where(x => questionIds.Contains(x.Id)) on answer.ReadingQuestionTrialId equals question.Id
select new TaskAnswerDto
{
Answer = answer.Answer,
AnswerGroup = question.AnswerGroup,
AnswerCombination = question.AnswerCombination,
JudgeType = question.JudgeType,
JudgeDifferenceValue = question.JudgeDifferenceValue,
JudgeDifferenceType = question.JudgeDifferenceType,
QuestionId = question.Id,
VisitTaskId = answer.VisitTaskId,
VisitTaskNum = visitTaskNum,
}).ToListAsync();
await ApplyVisitJudgeRules(questionAnswers, judgeRule);
var groupTasks = questionAnswers.GroupBy(x => new { x.JudgeDifferenceValue, x.JudgeDifferenceType, x.QuestionId, x.AnswerGroup, x.JudgeType, x.AnswerCombination })
.Select(x => new GroupTaskAnswerDto
{
QuestionId = x.Key.QuestionId,
AnswerGroup = x.Key.AnswerGroup,
AnswerCombination = x.Key.AnswerCombination,
JudgeType = x.Key.JudgeType,
JudgeDifferenceValue = x.Key.JudgeDifferenceValue,
JudgeDifferenceType = x.Key.JudgeDifferenceType,
TaskAnswerList = x.Select(y => y.Answer).ToList(),
}).ToList();
var triggerJudgeQuestionIds = new HashSet<Guid>();
ComputeJudgeResult(groupTasks, Guid.Empty, triggerJudgeQuestionIds, false);
return triggerJudgeQuestionIds;
}
/// <summary>
/// 编辑裁判表单
/// </summary>
[HttpPost]
public async Task<IResponseOutput> SetJudgeForm(SetJudgeFormInDto inDto)
{
await SaveJudgeForm(inDto);
await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask()
{
JudgeResultRemark = inDto.JudgeResultRemark,
JudgeResultImagePath = string.Join(',', inDto.JudgeResultImagePathList),
});
return ResponseOutput.Result(await _readingTaskQuestionAnswerRepository.SaveChangesAsync());
}
private async Task SaveJudgeForm(SetJudgeFormInDto inDto)
{
var judgeDataInfo = await _readingJudgeInfoRepository
.Where(x => x.JudgeTaskId == inDto.VisitTaskId)
.FirstNotNullAsync();
var taskIds = new List<Guid> { judgeDataInfo.TaskIdOne, judgeDataInfo.TaskIdTwo };
var readingTask = await _visitTaskRepository
.Where(x => taskIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.ArmEnum,
x.TrialReadingCriterionId,
x.VisitTaskNum,
})
.FirstNotNullAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
var judgeRule = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskInfo.TrialReadingCriterionId).Select(x => x.JudgeRuleEnum).FirstNotNullAsync();
var displayQuestionIds = (await GetJudgeDisplayQuestions(taskInfo.TrialReadingCriterionId, readingTask.VisitTaskNum, judgeRule, true)).Select(x => x.Id).ToList();
var submittedQuestionIds = inDto.QuestionList.Select(x => x.ReadingQuestionId).ToList();
await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && submittedQuestionIds.Contains(x.ReadingQuestionTrialId));
if (inDto.QuestionList.Count > 0)
{
await _readingTaskQuestionAnswerRepository.AddRangeAsync(inDto.QuestionList.Select(x => new ReadingTaskQuestionAnswer
{
ReadingQuestionTrialId = x.ReadingQuestionId,
ReadingQuestionCriterionTrialId = taskInfo.TrialReadingCriterionId,
TrialId = taskInfo.TrialId,
SubjectId = taskInfo.SubjectId,
VisitTaskId = inDto.VisitTaskId,
Answer = x.Answer,
}).ToList());
}
}
/// <summary>
/// 提交裁判表单
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> SubmitJudgeForm(SetJudgeFormInDto inDto)
{
await SaveJudgeForm(inDto);
await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask()
{
JudgeResultRemark = inDto.JudgeResultRemark,
ReadingTaskState = ReadingTaskState.HaveSigned,
SignTime=DateTime.Now,
JudgeResultImagePath = string.Join(',', inDto.JudgeResultImagePathList),
});
await _readingTaskQuestionAnswerRepository.SaveChangesAsync();
await SignatureAfter(inDto.VisitTaskId);
return ResponseOutput.Ok();
}
private async Task<List<ReadingQuestionTrial>> GetJudgeDisplayQuestions(Guid trialReadingCriterionId, decimal visitNum, JudgeRule judgeRule,bool isGetShowQuestion)
{
var questionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == trialReadingCriterionId && x.IsJudgeQuestion)
.WhereIf(!isGetShowQuestion,x=>x.ShowQuestion!= ShowQuestion.Hide)
.WhereIf(visitNum == 0, x => x.LimitShow != LimitShow.FollowShow)
.WhereIf(visitNum != 0, x => x.LimitShow != LimitShow.BaseLineShow)
.Where(x=>!(x.LimitShow==LimitShow.ExcludeSomeVisits&&x.ExcludeShowVisitList.Contains(visitNum)))
.ToListAsync();
var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == trialReadingCriterionId).FirstNotNullAsync();
var questionIds = questionList.Select(x => x.Id).ToList();
var visitJudgeRules=new List<ReadingQuestionVisitJudgeRule>();
if (judgeRule == JudgeRule.Difference)
{
if (await _visitStageRepository.AnyAsync(x => x.TrialId == trialCriterion.TrialId && x.VisitNum == visitNum))
{
visitJudgeRules = await _readingQuestionVisitJudgeRuleRepository.Where(x => questionIds.Contains(x.ReadingQuestionId) && x.VisitNum == visitNum).ToListAsync();
}
else
{
visitJudgeRules = await _readingQuestionVisitJudgeRuleRepository.Where(x => questionIds.Contains(x.ReadingQuestionId) && x.VisitNum == -1).ToListAsync();
}
}
else
{
visitJudgeRules = questionList.Select(x => new ReadingQuestionVisitJudgeRule()
{
ReadingQuestionId = x.Id,
AnswerCombination = JsonConvert.DeserializeObject<List<AnswerCombinationDto>>(x.AnswerCombination.IsNullOrEmpty() ? "[]" : x.AnswerCombination),
AnswerGroup = JsonConvert.DeserializeObject<List<string>>(x.AnswerGroup.IsNullOrEmpty() ? "[]" : x.AnswerGroup),
JudgeDifferenceType = x.JudgeDifferenceType,
JudgeType = x.JudgeType,
JudgeDifferenceValue = x.JudgeDifferenceValue,
}).ToList();
}
return questionList
.Where(x => visitJudgeRules.FirstOrDefault(rule => rule.ReadingQuestionId == x.Id && rule.VisitNum == -1)?.JudgeType != JudgeTypeEnum.NotApplicable)
.OrderBy(x=>x.ShowOrder)
.ToList();
}
/// <summary>
/// 获取裁判阅片任务信息
/// </summary>
@@ -476,8 +831,15 @@ namespace IRaCIS.Core.Application.Service
});
var result = await _visitTaskRepository.SaveChangesAsync();
await SignatureAfter(inDto.VisitTaskId);
return ResponseOutput.Ok(result);
}
private async Task SignatureAfter(Guid visitTaskId)
{
// 需要判断是否添加肿瘤学任务
var taskInfo = await _visitTaskRepository.Where(x => x.JudgeVisitTaskId == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
var taskInfo = await _visitTaskRepository.Where(x => x.JudgeVisitTaskId == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
if (taskInfo.ReadingCategory == ReadingCategory.Visit)
{
@@ -514,11 +876,9 @@ namespace IRaCIS.Core.Application.Service
// 创建任务关联关系
await this.CreateTaskRelated(inDto.VisitTaskId);
await this.CreateTaskRelated(visitTaskId);
await SafeMailHelper.Run(async () => await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(inDto.VisitTaskId));
return ResponseOutput.Ok(result);
await SafeMailHelper.Run(async () => await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(visitTaskId));
}
/// <summary>
@@ -560,6 +920,11 @@ namespace IRaCIS.Core.Application.Service
List<Guid> visitTaskids = new List<Guid>();
var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).AsNoTracking().FirstNotNullAsync();
// 计算过 就不计算了
if(visitTask.IsCalculatedJudge)
{
return;
}
// 是否是组件一致性
var isGroupAnalysis = false;
@@ -624,12 +989,13 @@ namespace IRaCIS.Core.Application.Service
x.ArbitrationRule,
x.IsGlobalReading,
x.IsReadingPeriod,
x.JudgeRuleEnum,
}).FirstNotNullAsync();
var noteEqual = false;
// 判断项目是否设置了裁判
if (criterionInfo.IsArbitrationReading)
if (criterionInfo.IsArbitrationReading&& !visitTask.IsCalculatedJudge)
{
// 判断数量是否为2 是否仲裁
if (visitTaskids.Count == 2)
@@ -667,6 +1033,7 @@ namespace IRaCIS.Core.Application.Service
VisitTaskId = questionAnswer.VisitTaskId,
};
var globalVisitAnswerlist = await globalVisitQuestionQuery.ToListAsync();
await ApplyVisitJudgeRules(globalVisitAnswerlist, criterionInfo.JudgeRuleEnum);
var taskNums = globalVisitAnswerlist.Select(x => x.VisitTaskNum).Distinct().OrderBy(x => x).ToList();
@@ -697,11 +1064,13 @@ namespace IRaCIS.Core.Application.Service
AnswerCombination = question.AnswerCombination,
JudgeType = question.JudgeType,
QuestionId = question.Id,
JudgeDifferenceValue = question.JudgeDifferenceValue,
JudgeDifferenceType = question.JudgeDifferenceType,
VisitTaskId = questionAnswet.VisitTaskId,
};
JudgeDifferenceValue = question.JudgeDifferenceValue,
JudgeDifferenceType = question.JudgeDifferenceType,
VisitTaskId = questionAnswet.VisitTaskId,
VisitTaskNum = questionAnswet.VisitTask.VisitTaskNum,
};
var questionAnswerlist = await query.ToListAsync();
await ApplyVisitJudgeRules(questionAnswerlist, criterionInfo.JudgeRuleEnum);
// 将答案进行分组
List<GroupTaskAnswerDto> groupTasks = questionAnswerlist.GroupBy(x => new { x.JudgeDifferenceValue, x.JudgeDifferenceType, x.QuestionId, x.AnswerGroup, x.JudgeType, x.AnswerCombination }).Select(x => new GroupTaskAnswerDto
@@ -749,6 +1118,8 @@ namespace IRaCIS.Core.Application.Service
}
else
{
await ApplyVisitJudgeRules(item.AfterQuestionList, item.VisitNum, criterionInfo.JudgeRuleEnum);
await ApplyVisitJudgeRules(twoItem.AfterQuestionList, twoItem.VisitNum, criterionInfo.JudgeRuleEnum);
var newlist = item.AfterQuestionList.Where(x => x.QuestionId != null && x.IsJudgeQuestion).ToList().Union(
twoItem.AfterQuestionList.Where(x => x.QuestionId != null && x.IsJudgeQuestion).ToList()
).ToList();
@@ -772,6 +1143,11 @@ namespace IRaCIS.Core.Application.Service
break;
}
await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => visitTaskids.Contains(x.Id), x => new VisitTask()
{
IsCalculatedJudge = true
});
}
else
{
@@ -811,6 +1187,8 @@ namespace IRaCIS.Core.Application.Service
};
var visitTaskQuestions = await query.ToListAsync();
await ApplyVisitJudgeRules(visitTaskQuestions, lastTask.VisitNum, criterionInfo.JudgeRuleEnum);
await ApplyVisitJudgeRules(lastTask.AfterQuestionList, lastTask.VisitNum, criterionInfo.JudgeRuleEnum);
var newlist = visitTaskQuestions.Where(x => x.QuestionId != null).ToList().Union(
lastTask.AfterQuestionList.Where(x => x.QuestionId != null).ToList()
@@ -831,6 +1209,11 @@ namespace IRaCIS.Core.Application.Service
}
await _visitTaskRepository.BatchUpdateNoTrackingAsync(x =>x.Id ==visitTask.Id, x => new VisitTask()
{
IsCalculatedJudge = true
});
}
}
@@ -929,6 +1312,105 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 应用访视裁判规则 以及剔除排除的问题
/// </summary>
private async Task ApplyVisitJudgeRules(List<TaskAnswerDto> answerList, JudgeRule judgeRule)
{
if (answerList.Count == 0)
{
return;
}
var questionIds = answerList.Select(x => x.QuestionId).Distinct().ToList();
var questions = await _readingQuestionTrialRepository.Where(x => questionIds.Contains(x.Id)&&x.LimitShow == LimitShow.ExcludeSomeVisits).Select(x => new
{
x.Id,
x.ExcludeShowVisitList,
}).ToListAsync();
var excludedQuestionIds = answerList
.Where(x => questions.FirstOrDefault(question => question.Id == x.QuestionId)?.ExcludeShowVisitList.Contains(x.VisitTaskNum) == true)
.Select(x => x.QuestionId)
.Distinct()
.ToList();
answerList.RemoveAll(x => excludedQuestionIds.Contains(x.QuestionId));
if (judgeRule != JudgeRule.Difference || answerList.Count == 0)
{
return;
}
questionIds = answerList.Select(x => x.QuestionId).Distinct().ToList();
var visitNums = answerList.Select(x => x.VisitTaskNum).Distinct().ToList();
var visitRules = await _readingQuestionVisitJudgeRuleRepository
.Where(x => questionIds.Contains(x.ReadingQuestionId) && (visitNums.Contains(x.VisitNum) || x.VisitNum == -1))
.ToListAsync();
answerList.ForEach(answer =>
{
var rule = visitRules.FirstOrDefault(x => x.ReadingQuestionId == answer.QuestionId && x.VisitNum == answer.VisitTaskNum)
?? visitRules.FirstOrDefault(x => x.ReadingQuestionId == answer.QuestionId && x.VisitNum == -1);
if (rule != null)
{
answer.AnswerGroup = JsonConvert.SerializeObject(rule.AnswerGroup);
answer.AnswerCombination = JsonConvert.SerializeObject(rule.AnswerCombination);
answer.JudgeType = rule.JudgeType;
answer.JudgeDifferenceValue = rule.JudgeDifferenceValue;
answer.JudgeDifferenceType = rule.JudgeDifferenceType;
}
});
}
/// <summary>
/// 应用访视裁判规则 以及剔除排除的问题
/// </summary>
private async Task ApplyVisitJudgeRules(List<GlobalQuestionInfo> questionList, decimal visitNum, JudgeRule judgeRule)
{
if (questionList.Count == 0)
{
return;
}
var questionIds = questionList.Where(x => x.QuestionId != null).Select(x => x.QuestionId!.Value).Distinct().ToList();
#region 访
//var excludedQuestionIds = await _readingQuestionTrialRepository
// .Where(x => questionIds.Contains(x.Id) && x.ExcludeShowVisitList.Contains(visitNum))
// .Select(x => x.Id)
// .ToListAsync();
//questionList.RemoveAll(x => x.QuestionId != null && excludedQuestionIds.Contains(x.QuestionId.Value));
#endregion
if (judgeRule != JudgeRule.Difference || questionList.Count == 0)
{
return;
}
questionIds = questionList.Where(x => x.QuestionId != null).Select(x => x.QuestionId!.Value).Distinct().ToList();
var visitRules = await _readingQuestionVisitJudgeRuleRepository
.Where(x => questionIds.Contains(x.ReadingQuestionId) && (x.VisitNum == visitNum || x.VisitNum == -1))
.ToListAsync();
questionList.ForEach(question =>
{
if (question.QuestionId == null)
{
return;
}
var rule = visitRules.FirstOrDefault(x => x.ReadingQuestionId == question.QuestionId && x.VisitNum == visitNum)
?? visitRules.FirstOrDefault(x => x.ReadingQuestionId == question.QuestionId && x.VisitNum == -1);
if (rule != null)
{
question.AnswerGroup = JsonConvert.SerializeObject(rule.AnswerGroup);
question.AnswerCombination = JsonConvert.SerializeObject(rule.AnswerCombination);
question.JudgeType = rule.JudgeType;
question.JudgeDifferenceValue = rule.JudgeDifferenceValue;
question.JudgeDifferenceType = rule.JudgeDifferenceType;
}
});
}
/// <summary>
/// 发送微信通知
@@ -1077,50 +1559,53 @@ namespace IRaCIS.Core.Application.Service
/// </summary>
/// <param name="groupTasks"></param>
/// <returns></returns>
private bool ComputeJudgeResult(List<GroupTaskAnswerDto> groupTasks,Guid visiTaskId)
private bool ComputeJudgeResult(List<GroupTaskAnswerDto> groupTasks, Guid visiTaskId, HashSet<Guid>? triggerJudgeQuestionIds = null, bool notifyException = true)
{
var noteEqual = false;
foreach (var item in groupTasks)
{
if (item.JudgeType == JudgeTypeEnum.NotApplicable || item.JudgeType == JudgeTypeEnum.None)
{
continue;
}
// 裁判问题可以不必填
if(item.TaskAnswerList.Count()==0)
{
try
{
_ = SendWeComNotifier(visiTaskId, "两个阅片任务的答案等于0");
_ = SendAbnormalEmail(visiTaskId, EmailBusinessScenario.JudgeExceptio);
}
catch (Exception)
if (notifyException)
{
try
{
_ = SendWeComNotifier(visiTaskId, "两个阅片任务的答案等于0");
_ = SendAbnormalEmail(visiTaskId, EmailBusinessScenario.JudgeExceptio);
}
catch (Exception)
{
}
}
break;
}
else if (item.TaskAnswerList.Count() != 2)
{
try
{
// 发送微信通知
_ = SendWeComNotifier(visiTaskId, "两个阅片任务的答案不等于2");
_ = SendAbnormalEmail(visiTaskId, EmailBusinessScenario.JudgeExceptio);
}
catch (Exception)
if (notifyException)
{
try
{
// 发送微信通知
_ = SendWeComNotifier(visiTaskId, "两个阅片任务的答案不等于2");
_ = SendAbnormalEmail(visiTaskId, EmailBusinessScenario.JudgeExceptio);
}
catch (Exception)
{
}
}
break;
}
else if (noteEqual)
{
break;
}
else
{
var isTriggerJudge = false;
var taskAnswer1 = item.TaskAnswerList[0];
var taskAnswer2 = item.TaskAnswerList[1];
if (taskAnswer1 != taskAnswer2)
@@ -1129,7 +1614,7 @@ namespace IRaCIS.Core.Application.Service
switch (item.JudgeType)
{
case JudgeTypeEnum.AnswerDisaffinity:
noteEqual = true;
isTriggerJudge = true;
break;
case JudgeTypeEnum.AnswerGroup:
var answerGroupList = JsonConvert.DeserializeObject<List<string>>(item.AnswerGroup).Select(x => new AnswerGroup()
@@ -1142,7 +1627,7 @@ namespace IRaCIS.Core.Application.Service
var unionList = itemAnswerGroupsitem1.Intersect(itemAnswerGroupsitem2).ToList();
if (unionList.Count < 1)
{
noteEqual = true;
isTriggerJudge = true;
}
break;
case JudgeTypeEnum.AnswerCombination:
@@ -1151,11 +1636,11 @@ namespace IRaCIS.Core.Application.Service
{
if (x.AnswerGroupA.Contains(taskAnswer1) && x.AnswerGroupB.Contains(taskAnswer2))
{
noteEqual = true;
isTriggerJudge = true;
}
if (x.AnswerGroupB.Contains(taskAnswer1) && x.AnswerGroupA.Contains(taskAnswer2))
{
noteEqual = true;
isTriggerJudge = true;
}
});
break;
@@ -1165,21 +1650,21 @@ namespace IRaCIS.Core.Application.Service
// 已经判断不相等了 所以只可能有一个为Null
if (answer1 == null || answer2 == null)
{
noteEqual = true;
isTriggerJudge = true;
}
var deffaultValue = Math.Abs(taskAnswer1.IsNullOrEmptyReturn0() - taskAnswer2.IsNullOrEmptyReturn0());
if (item.JudgeDifferenceType == JudgeDifferenceType.Greater)
{
if (deffaultValue > item.JudgeDifferenceValue)
{
noteEqual = true;
isTriggerJudge = true;
}
}
else if (item.JudgeDifferenceType == JudgeDifferenceType.AboveOrEqual)
{
if (deffaultValue >= item.JudgeDifferenceValue)
{
noteEqual = true;
isTriggerJudge = true;
}
}
break;
@@ -1189,24 +1674,24 @@ namespace IRaCIS.Core.Application.Service
// 已经判断不相等了 所以只可能有一个为Null
if (answer1P == null || answer2P == null)
{
noteEqual = true;
isTriggerJudge = true;
}
var value1 = taskAnswer1.IsNullOrEmptyReturn0();
var value2 = taskAnswer2.IsNullOrEmptyReturn0();
if (value1 == 0 || value2 == 0)
{
noteEqual = true;
isTriggerJudge = true;
}
else
{
var absoluteValue = (Math.Abs(value1 - value2) * 100) / (value1 < value2 ? value1 : value2);
if (item.JudgeDifferenceType == JudgeDifferenceType.Greater)
{
noteEqual = absoluteValue > item.JudgeDifferenceValue;
isTriggerJudge = absoluteValue > item.JudgeDifferenceValue;
}
else if (item.JudgeDifferenceType == JudgeDifferenceType.AboveOrEqual)
{
noteEqual = absoluteValue >= item.JudgeDifferenceValue;
isTriggerJudge = absoluteValue >= item.JudgeDifferenceValue;
}
}
break;
@@ -1214,6 +1699,12 @@ namespace IRaCIS.Core.Application.Service
break;
}
}
if (isTriggerJudge)
{
noteEqual = true;
triggerJudgeQuestionIds?.Add(item.QuestionId);
}
}
}
@@ -1,4 +1,6 @@
using IRaCIS.Core.Application.Service.Reading.Dto;
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
@@ -6,6 +8,8 @@ using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.IO.Compression;
namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
@@ -18,12 +22,15 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<OrganInfo> _organInfoRepository,
ISubjectVisitService iSubjectVisitService,
IRepository<Dictionary> _dictionaryRepository,
IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<TumorAssessment_IRECIST1Point1> _tumorAssessmentRepository,
IGeneralCalculateService _generalCalculateService,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
IVisitTaskHelpeService _visitTaskHelpeService,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
IHttpContextAccessor httpContext,
ILogger<IRECIST1Point1CalculateService> _logger, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService
{
@@ -411,13 +418,117 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
[HttpPost]
public async Task<FileResult> GetIVUSTemplate(GetExportTemplateInDto inDto)
{
return await CreateIVUSTemplate(inDto.VisitTaskId);
}
/// <summary>
/// 获取当前分组、受试者、标准下所有有效任务的IVUS模板压缩包
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<FileResult> GetIVUSTemplatesZip(GetExportTemplateInDto inDto)
{
var currentTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x=>x.Subject).FirstNotNullAsync();
var taskList = await _visitTaskRepository.Where(x => x.ArmEnum == currentTask.ArmEnum
&& x.SubjectId == currentTask.SubjectId
&& x.TrialReadingCriterionId == currentTask.TrialReadingCriterionId
&& x.TaskState == TaskState.Effect)
.Include(x => x.Subject)
.ToListAsync();
var zipStream = new MemoryStream();
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true))
{
foreach (var task in taskList)
{
var template = await CreateIVUSTemplate(task.Id) as FileStreamResult;
await using (template.FileStream)
await using (var entryStream = archive.CreateEntry($"{GetTemplateFileName(task)}.xlsx", CompressionLevel.Optimal).Open())
{
await template.FileStream.CopyToAsync(entryStream);
}
}
}
zipStream.Position = 0;
var subjectCode = (currentTask.BlindSubjectCode.IsNullOrEmpty() ? currentTask.Subject.Code : currentTask.BlindSubjectCode);
var code = string.Concat(subjectCode.Select(c => Path.GetInvalidFileNameChars().Contains(c) ? '_' : c));
return new FileStreamResult(zipStream, "application/zip")
{
FileDownloadName = code+"_IVUS_Templates.zip"
};
}
private async Task<FileResult> CreateIVUSTemplate(Guid visitTaskId)
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x=>x.Subject).FirstNotNullAsync();
//靶段
var targetSegmentdic = await _dictionaryRepository.Where(x => x.Parent.Code == "TargetSegment").ToListAsync();
//斑块类型
var plaqueTypedic = await _dictionaryRepository.Where(x => x.Parent.Code == "PlaqueType").ToListAsync();
var awswerList=await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x=>x.ReadingQuestionTrial).ToListAsync();
var targetSegmentAnswer = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.TargetSegment).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;
if (targetSegmentAnswer.IsNotNullOrEmpty())
{
var data= JsonConvert.DeserializeObject<List<string>>(targetSegmentAnswer);
targetSegmentAnswer = string.Join(",", targetSegmentdic
.Where(x => data.Contains(x.Code))
.Select(x => x.ValueCN));
}
else
{
var targetSegmentData = await iSubjectVisitService.GetReadingVisitStudyList(new Contracts.GetReadingVisitStudyListIndto()
{
SujectVisitId = taskinfo.SourceSubjectVisitId ?? default(Guid),
TrialId = taskinfo.TrialId,
VisitTaskId = visitTaskId
});
targetSegmentAnswer = string.Join(",", targetSegmentData
.Where(x => x.BodyPartForEdit.IsNotNullOrEmpty())
.SelectMany(x => x.BodyPartForEdit.Split('|'))
.Where(s => !string.IsNullOrWhiteSpace(s))
.Distinct());
}
var plaqueTypeAnswer = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.PlaqueType).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;
if (plaqueTypeAnswer.IsNotNullOrEmpty())
{
var data = JsonConvert.DeserializeObject<List<string>>(plaqueTypeAnswer);
plaqueTypeAnswer = string.Join(",", plaqueTypedic
.Where(x => data.Contains(x.Code))
.Select(x => x.ValueCN));
}
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x=>x.Subject).FirstNotNullAsync();
var values = new TemplateData()
{
SubjectID = (taskinfo.BlindSubjectCode.IsNullOrEmpty() ? taskinfo.Subject.Code : taskinfo.BlindSubjectCode),
TaskBlindName = taskinfo.TaskBlindName,
TargetSegment= targetSegmentAnswer,
TargetSegmentRemarks = awswerList.Where(x=>x.ReadingQuestionTrial.QuestionType == QuestionType.TargetSegmentRemarks).Select(x=>x.Answer).FirstOrDefault()??string.Empty,
//ROIAllLength = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ROIAllLength).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
//PullbackFrameCount = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.PullbackFrameCount).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
//AdjustReason = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.AdjustReason).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
//PlaqueType = plaqueTypeAnswer,
};
return await _visitTaskHelpeService.ExportTemplateAsync(new IRaCIS.Application.Contracts.ExportTemplateAsyncDto()
{
@@ -427,6 +538,13 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
});
}
private static string GetTemplateFileName(VisitTask task)
{
var subjectCode = (task.BlindSubjectCode.IsNullOrEmpty() ? task.Subject.Code : task.BlindSubjectCode);
var fileName = $"{subjectCode}_{task.TaskBlindName}";
return string.Concat(fileName.Select(c => Path.GetInvalidFileNameChars().Contains(c) ? '_' : c));
}
/// <summary>
/// 导入IVUS数据
/// </summary>
@@ -442,7 +560,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
List<string> sheetNames = new List<string>()
{
"各匹配片段测量值","MeasuredValue"
"ROI测量值","ROI 测量值"
};
if (sheetNames.Intersect(uploadInfo.SheetNames).Count() == 0)
@@ -510,6 +628,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
Dictionary<string, string> isPresent = new Dictionary<string, string>()
{
{ "1","1"},
{ "0","0"},
{ "有","1"},
{ "无","0"},
{ "Existence","1"},
@@ -520,6 +640,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
Dictionary<string, string> yesOrNo = new Dictionary<string, string>()
{
{ "1","1"},
{ "0","0"},
{ "是","1"},
{ "否","0"},
{ "Yes","1"},
@@ -529,7 +651,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
List<IVUSMeasuredValue> measuredValueList = new List<IVUSMeasuredValue>();
var errorRow = new List<int> { };
for (int i = 3; i < dataTable.Rows.Count; i++)
for (int i = 9; i < dataTable.Rows.Count; i++)
{
IVUSMeasuredValue iVUSMeasuredValue = new IVUSMeasuredValue() { };
try
@@ -691,7 +813,100 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
}
}
#region
List<ReadingTaskQuestionAnswer> questionAnswers = new List<ReadingTaskQuestionAnswer>();
var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync();
var targetSegmentAnswer = dataTable.Rows[2]["B"].ToString();
if (targetSegmentAnswer.IsNotNullOrEmpty())
{
var targetSegmentValues = targetSegmentAnswer.Replace(" ", "").Replace("", ",").Split(",").ToList();
var targetSegmentdic = await _dictionaryRepository.Where(x => x.Parent.Code == "TargetSegment").ToListAsync();
targetSegmentAnswer = JsonConvert.SerializeObject(targetSegmentdic.Where(x => targetSegmentValues.Contains(x.ValueCN.Replace(" ", ""))).Select(x => x.Code).ToList());
}
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer= targetSegmentAnswer??string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.TargetSegment).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId= taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[3]["B"].ToString()??string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.TargetSegmentRemarks).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[4]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.ROIAllLength).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[5]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.PullbackFrameCount).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
var plaqueTypeAnswer = dataTable.Rows[6]["B"].ToString();
if (plaqueTypeAnswer.IsNotNullOrEmpty())
{
var plaqueTypeAnswerValues = plaqueTypeAnswer.Replace(" ", "").Replace("", ",").Split(",").ToList();
var plaqueTypeAnswerdic = await _dictionaryRepository.Where(x => x.Parent.Code == "PlaqueType").ToListAsync();
plaqueTypeAnswer = JsonConvert.SerializeObject(plaqueTypeAnswerdic
.Where(x => plaqueTypeAnswerValues.Any(val => x.ValueCN.Replace(" ", "").Contains(val)))
.Select(x => x.Code)
.ToList());
}
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = plaqueTypeAnswer ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.PlaqueType).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[7]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.AdjustReason).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
var questionids = questionAnswers.Select(x => x.ReadingQuestionTrialId).ToList();
await _readingTaskQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == taskinfo.Id && questionids.Contains(x.ReadingQuestionTrialId));
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
await _readingTaskQuestionAnswerRepository.AddRangeAsync(questionAnswers);
await _readingTaskQuestionAnswerRepository.SaveChangesAsync();
#endregion
await _readingTableAnswerRowInfoRepository.DeleteFromQueryAsync(x => x.QuestionId == questionInfo.Id && x.VisitTaskId == taskinfo.Id);
await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.QuestionId == questionInfo.Id && x.VisitTaskId == taskinfo.Id);
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
@@ -921,6 +1136,23 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
var noneDicomFiles = await _noneDicomStudyFileRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
.Select(x => new { x.FileType, x.FileName }).ToListAsync();
var hasZip = noneDicomFiles.Any(x => x.FileType == "application/zip"
|| x.FileType == "application/x-zip-compressed"
|| x.FileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase));
var hasImage = noneDicomFiles.Any(x => x.FileType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)
|| x.FileName.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)
|| x.FileName.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase)
|| x.FileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase)
|| x.FileName.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase)
|| x.FileName.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase));
if (!hasZip || !hasImage)
{
throw new BusinessValidationFailedException(_localizer["IVUSCriterionImageFileVerify"]);
}
var question = await _readingQuestionTrialRepository.Where(x => x.LesionType == LesionType.ROI && x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).FirstNotNullAsync();
@@ -2,6 +2,7 @@
using DocumentFormat.OpenXml.Drawing.Spreadsheet;
using DocumentFormat.OpenXml.Office.SpreadSheetML.Y2023.MsForms;
using DocumentFormat.OpenXml.Office2010.Excel;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
@@ -12,6 +13,8 @@ using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.IO.Compression;
namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
@@ -24,6 +27,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<OrganInfo> _organInfoRepository,
ISubjectVisitService iSubjectVisitService,
IRepository<Dictionary> _dictionaryRepository,
IHttpContextAccessor httpContext,
IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
@@ -31,6 +36,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
IGeneralCalculateService _generalCalculateService,
IVisitTaskHelpeService _visitTaskHelpeService,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
IRepository<TaskStudy> _taskStudyRepository,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
ILogger<IRECIST1Point1CalculateService> _logger, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService
{
/// <summary>
@@ -270,11 +277,113 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
[HttpPost]
public async Task<FileResult> GetOCTFCTTemplate(GetExportTemplateInDto inDto)
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).FirstNotNullAsync();
return await CreateOCTFCTTemplate(inDto.VisitTaskId);
}
/// <summary>
/// 获取当前分组、受试者、标准下所有有效任务的OCT-FCT模板压缩包
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<FileResult> GetOCTFCTTemplatesZip(GetExportTemplateInDto inDto)
{
var currentTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).FirstNotNullAsync();
var taskList = await _visitTaskRepository.Where(x => x.ArmEnum == currentTask.ArmEnum
&& x.SubjectId == currentTask.SubjectId
&& x.TrialReadingCriterionId == currentTask.TrialReadingCriterionId
&& x.TaskState == TaskState.Effect)
.Include(x => x.Subject)
.ToListAsync();
var zipStream = new MemoryStream();
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, leaveOpen: true))
{
foreach (var task in taskList)
{
var template = await CreateOCTFCTTemplate(task.Id) as FileStreamResult;
await using (template.FileStream)
await using (var entryStream = archive.CreateEntry($"{GetTemplateFileName(task)}.xlsx", CompressionLevel.Optimal).Open())
{
await template.FileStream.CopyToAsync(entryStream);
}
}
}
zipStream.Position = 0;
var subjectCode = (currentTask.BlindSubjectCode.IsNullOrEmpty() ? currentTask.Subject.Code : currentTask.BlindSubjectCode);
var code = string.Concat(subjectCode.Select(c => Path.GetInvalidFileNameChars().Contains(c) ? '_' : c));
return new FileStreamResult(zipStream, "application/zip")
{
FileDownloadName = $"{code}_OCT_FCT_Templates.zip"
};
}
private async Task<FileResult> CreateOCTFCTTemplate(Guid visitTaskId)
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.Subject).FirstNotNullAsync();
//靶段
var targetSegmentdic = await _dictionaryRepository.Where(x => x.Parent.Code == "TargetSegment").ToListAsync();
//斑块类型
var plaqueTypedic = await _dictionaryRepository.Where(x => x.Parent.Code == "PlaqueType").ToListAsync();
var awswerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x => x.ReadingQuestionTrial).ToListAsync();
var targetSegmentAnswer = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.TargetSegment).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;
if (targetSegmentAnswer.IsNotNullOrEmpty())
{
var data = JsonConvert.DeserializeObject<List<string>>(targetSegmentAnswer);
targetSegmentAnswer = string.Join(",", targetSegmentdic
.Where(x => data.Contains(x.Code))
.Select(x => x.ValueCN));
}
else
{
var targetSegmentData = await iSubjectVisitService.GetReadingVisitStudyList(new Contracts.GetReadingVisitStudyListIndto()
{
SujectVisitId = taskinfo.SourceSubjectVisitId ?? default(Guid),
TrialId = taskinfo.TrialId,
VisitTaskId = visitTaskId
});
targetSegmentAnswer = string.Join(",", targetSegmentData
.Where(x => x.BodyPartForEdit.IsNotNullOrEmpty())
.SelectMany(x => x.BodyPartForEdit.Split('|'))
.Where(s => !string.IsNullOrWhiteSpace(s))
.Distinct());
}
var plaqueTypeAnswer = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.PlaqueType).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;
if (plaqueTypeAnswer.IsNotNullOrEmpty())
{
var data = JsonConvert.DeserializeObject<List<string>>(plaqueTypeAnswer);
plaqueTypeAnswer = string.Join(",", plaqueTypedic
.Where(x => data.Contains(x.Code))
.Select(x => x.ValueCN));
}
var values = new TemplateData()
{
SubjectID = (taskinfo.BlindSubjectCode.IsNullOrEmpty() ? taskinfo.Subject.Code : taskinfo.BlindSubjectCode),
TaskBlindName = taskinfo.TaskBlindName,
TargetSegment = targetSegmentAnswer,
TargetSegmentRemarks = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.TargetSegmentRemarks).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
//ROIAllLength = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ROIAllLength).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
////PullbackFrameCount = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.PullbackFrameCount).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
//PlaqueType = plaqueTypeAnswer,
//AdjustReason = awswerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.AdjustReason).Select(x => x.Answer).FirstOrDefault() ?? string.Empty,
};
return await _visitTaskHelpeService.ExportTemplateAsync(new IRaCIS.Application.Contracts.ExportTemplateAsyncDto()
{
@@ -284,6 +393,13 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
});
}
private static string GetTemplateFileName(VisitTask task)
{
var subjectCode = (task.BlindSubjectCode.IsNullOrEmpty() ? task.Subject.Code : task.BlindSubjectCode);
var fileName = $"{subjectCode}_{task.TaskBlindName}";
return string.Concat(fileName.Select(c => Path.GetInvalidFileNameChars().Contains(c) ? '_' : c));
}
/// <summary>
/// 导入OCT-FCT数据
/// </summary>
@@ -299,7 +415,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
List<string> sheetNames = new List<string>()
{
"FCT导入","FCT"
"ROI测量值","ROI 测量值"
};
if (sheetNames.Intersect(uploadInfo.SheetNames).Count() == 0)
@@ -338,6 +454,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
Dictionary<string, string> yesOrNo = new Dictionary<string, string>()
{
{ "1","1"},
{ "0","0"},
{ "是","1"},
{ "否","0"},
{ "Yes","1"},
@@ -356,11 +474,12 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
return value;
}
}
for (int i = 3; i < dataTable.Rows.Count; i++)
for (int i = 8; i < dataTable.Rows.Count; i++)
{
try
{
// 手动抛出异常进入catch
if (!yesOrNo.ContainsKey(dataTable.Rows[i]["K"].ToString())|| !yesOrNo.ContainsKey(dataTable.Rows[i]["L"].ToString()))
{
@@ -404,6 +523,8 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
Dictionary<string, string> isPresent = new Dictionary<string, string>()
{
{ "1","1"},
{ "0","0"},
{ "有","1"},
{ "无","0"},
{ "Existence","1"},
@@ -411,7 +532,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
{ string.Empty,string.Empty},
};
int row = 3;
int row = 8;
foreach (var item in measuredValueList)
{
row++;
@@ -664,6 +785,91 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
}
}
#region
List<ReadingTaskQuestionAnswer> questionAnswers = new List<ReadingTaskQuestionAnswer>();
var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync();
var targetSegmentAnswer = dataTable.Rows[2]["B"].ToString();
if (targetSegmentAnswer.IsNotNullOrEmpty())
{
var targetSegmentValues = targetSegmentAnswer.Replace(" ", "").Replace("", ",").Split(",").ToList();
var targetSegmentdic = await _dictionaryRepository.Where(x => x.Parent.Code == "TargetSegment").ToListAsync();
targetSegmentAnswer = JsonConvert.SerializeObject(targetSegmentdic.Where(x => targetSegmentValues.Contains(x.ValueCN.Replace(" ", ""))).Select(x => x.Code).ToList());
}
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = targetSegmentAnswer ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.TargetSegment).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[3]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.TargetSegmentRemarks).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[4]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.ROIAllLength).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
var plaqueTypeAnswer = dataTable.Rows[5]["B"].ToString();
if (plaqueTypeAnswer.IsNotNullOrEmpty())
{
var plaqueTypeAnswerValues = plaqueTypeAnswer.Replace(" ", "").Replace("", ",").Split(",").ToList();
var plaqueTypeAnswerdic = await _dictionaryRepository.Where(x => x.Parent.Code == "PlaqueType").ToListAsync();
plaqueTypeAnswer = JsonConvert.SerializeObject(plaqueTypeAnswerdic
.Where(x => plaqueTypeAnswerValues.Any(val => x.ValueCN.Replace(" ", "").Contains(val)))
.Select(x => x.Code)
.ToList());
}
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = plaqueTypeAnswer ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.PlaqueType).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
questionAnswers.Add(new ReadingTaskQuestionAnswer()
{
Answer = dataTable.Rows[6]["B"].ToString() ?? string.Empty,
ReadingQuestionCriterionTrialId = taskinfo.TrialReadingCriterionId,
ReadingQuestionTrialId = readingQuestionList.Where(x => x.QuestionType == QuestionType.AdjustReason).Select(x => x.Id).FirstOrDefault(),
TrialId = taskinfo.TrialId,
SubjectId = taskinfo.SubjectId,
VisitTaskId = taskinfo.Id,
});
var questionids = questionAnswers.Select(x => x.ReadingQuestionTrialId).ToList();
await _readingTaskQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == taskinfo.Id && questionids.Contains(x.ReadingQuestionTrialId));
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
await _readingTaskQuestionAnswerRepository.AddRangeAsync(questionAnswers);
await _readingTaskQuestionAnswerRepository.SaveChangesAsync();
#endregion
await _readingTableAnswerRowInfoRepository.DeleteFromQueryAsync(x => x.QuestionId == questionInfo.Id && x.VisitTaskId == taskinfo.Id);
await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.QuestionId == questionInfo.Id && x.VisitTaskId == taskinfo.Id);
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
@@ -1445,6 +1651,18 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();
var noneDicomFiles = await _noneDicomStudyFileRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
.Select(x => new { x.FileType, x.FileName }).ToListAsync();
var hasDicom = await _taskStudyRepository.AnyAsync(x => x.VisitTaskId == inDto.VisitTaskId);
var hasZip = noneDicomFiles.Any(x => x.FileType == "application/zip"
|| x.FileType == "application/x-zip-compressed"
|| x.FileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase));
if (!hasDicom || !hasZip)
{
throw new BusinessValidationFailedException(_localizer["OCTCriterionImageFileVerify"]);
}
var question = await _readingQuestionTrialRepository.Where(x => x.LesionType == LesionType.ROI && x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).FirstNotNullAsync();
@@ -3,6 +3,8 @@
// 生成时间 2021-12-23 13:21:04
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Application.Helper;
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> TrialSiteEquipmentSurveyView 列表视图模型 </summary>
@@ -49,33 +51,44 @@ namespace IRaCIS.Core.Application.Contracts
public string ScannerType { get; set; } = string.Empty;
public string Note { get; set; } = string.Empty;
[DictionaryTranslate("SiteSurvey_ScanEquipmentType")]
[Comment("扫描设备-New")]
public int? EquipmentTypeEnum { get; set; }
public string OtherEquipmentType { get; set; }
[Comment("扫描设备厂商")]
[DictionaryTranslate("ManufacturerType")]
public int? ManufacturerType { get; set; }
[Comment("磁场强度 (1.5T / 3.0T)")]
[DictionaryTranslate("MagneticFieldStrengthType")]
public int? MagneticFieldStrengthType { get; set; }
[DictionaryTranslate("BodyCoilChannelCount")]
[Comment("体部线圈通道数 (≥16 或 16)")]
public int? BodyCoilChannelCount { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("是否具备专用的PDFF脂肪定量序列(CSE-MRI序列)")]
public bool? HasDedicatedPdfFatQuantificationSequence { get; set; }
[DictionaryTranslate("PdfFatQuantificationSequenceType")]
[Comment("专用的PDFF脂肪定量序列类型 (当 HasDedicatedPdfFatQuantificationSequence = true 时有效)")]
public int? PdfFatQuantificationSequenceType { get; set; }
[Comment("其他序列详细说明 (当 PdfFatQuantificationSequenceType = Other 时建议填写)")]
public string OtherSequenceSpecification { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("是否包含 T2/R2 校正(用于铁沉积校正)")]
public bool? HasT2R2Correction { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("是否可完整导出 PDFF 参数图及全部原始 DICOM 数据")]
public bool? CanFullyExportPdfParameterMapsAndRawDicom { get; set; }
}
@@ -5,6 +5,7 @@
//--------------------------------------------------------------------
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using System.ComponentModel.DataAnnotations;
@@ -131,13 +132,15 @@ namespace IRaCIS.Core.Application.Contracts
/// <summary> TrialSiteSurveyView 列表视图模型 </summary>
public class TrialSiteSurveyView: TrialSiteSurveyAddOrEdit
public class TrialSiteSurveyView : TrialSiteSurveyAddOrEdit
{
public string TrialSiteCode { get; set; } = String.Empty;
public string TrialSiteAliasName { get; set; } = String.Empty;
public string SiteName { get; set; } = string.Empty;
[DictionaryTranslate("YesOrNo")]
public bool IsDeleted { get; set; }
public DateTime CreateTime { get; set; }
@@ -145,7 +148,7 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
[DictionaryTranslate("ResearchRecord")]
public TrialSiteSurveyEnum State { get; set; }
public string LatestBackReason { get; set; } = string.Empty;
@@ -326,14 +329,21 @@ namespace IRaCIS.Core.Application.Contracts
public string UserName { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public int AverageEngravingCycle { get; set; }
[DictionaryTranslate("YesOrNo")]
public bool IsConfirmImagingTechnologist { get; set; }
public string NotConfirmReson { get; set; } = string.Empty;
[DictionaryTranslate("EfficacyEvaluatorType")]
public int EfficacyEvaluatorType { get; set; }
[DictionaryTranslate("YesOrNo")]
public bool IsFollowStudyParameters { get; set; }
public string NotFollowReson { get; set; } = string.Empty;
[DictionaryTranslate("YesOrNo")]
[Comment("MRI-PDEE 是否为本中心该适应症的常规诊疗检查项目")]
public bool? IsRoutineMRIPDEE { get; set; }
@@ -346,14 +356,17 @@ namespace IRaCIS.Core.Application.Contracts
[Comment("MRI-PDEE 其他")]
public string MRIPDFFOther { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("是否授权影像科老师参与")]
public bool? IsAuthorizeRadiologistsParticipate { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("保持 1-2 名固定技师")]
public bool? AssignFixedTechnologists { get; set; }
[DictionaryTranslate("YesOrNo")]
[Comment("是否严格按照影像手册参数完成刻盘")]
public bool? ISStrictManualBurnFlag { get; set; }
@@ -450,6 +463,92 @@ namespace IRaCIS.Core.Application.Contracts
}
public class SiteSurveyLogQuery:SortInput
{
[NotDefault]
public Guid TrialSiteSurveyId { get; set; }
public Guid? Id { get; set; }
}
public class SiteSurveyLogDTO
{
public Guid Id { get; set; }
public Guid TrialSiteSurveyId { get; set; }
public string Name { get; set; }
public UserTypeEnum UserType { get; set; }
public SiteSurveyOptTyp OptType { get; set; }
public string Reason { get; set; }
[MaxLength]
public string Json { get; set; }
[Comment("更新调研表之前的调研表")]
public Guid? OriginTrialSiteSurveyId { get; set; }
public string CreateTime { get; set; }
}
public class SiteSurveyEquipmentDto : TrialSiteEquipmentSurveyView
{
public string TrialSiteCode { get; set; }
public string TrialSiteName { get; set; } = String.Empty;
public string TrialSiteAliasName { get; set; } = String.Empty;
public string UserName { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
[DictionaryTranslate("YesOrNo")]
public bool IsDeleted { get; set; }
[DictionaryTranslate("ResearchRecord")]
public TrialSiteSurveyEnum State { get; set; }
}
public class SiteSurveyEquipmentQuery : PageInput
{
[NotDefault]
public Guid TrialId { get; set; }
public Guid? TrialSiteId { get; set; }
public string? TrialSiteCode { get; set; }
public string? TrialSiteName { get; set; }
public bool? IsDeleted { get; set; }
public TrialSiteSurveyEnum? State { get; set; }
}
public class SiteSurveyInfoQuery : PageInput
{
[NotDefault]
public Guid TrialId { get; set; }
public Guid? TrialSiteId { get; set; }
public string? TrialSiteCode { get; set; }
public string? TrialSiteName { get; set; }
public bool? IsDeleted { get; set; }
public TrialSiteSurveyEnum? State { get; set; }
}
public class SiteSurveyInfoDto
{
}
}
@@ -3,6 +3,9 @@
// 生成时间 2021-12-23 13:20:59
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using DocumentFormat.OpenXml.Office2013.Excel;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Vml;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Helper;
@@ -22,6 +25,8 @@ namespace IRaCIS.Core.Application.Contracts
/// </summary>
[ApiExplorerSettings(GroupName = "Trial")]
public class TrialSiteSurveyService(IRepository<TrialSiteSurvey> _trialSiteSurveyRepository,
IRepository<SiteSurveyLog> _siteSurveyLogRepository,
IRepository<TrialSiteEquipmentSurvey> _trialSiteEquipmentSurveyRepository,
IRepository<TrialSiteUserSurvey> _trialSiteUserSurveyRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<IdentityUser> _identityUserRepository,
@@ -474,6 +479,7 @@ namespace IRaCIS.Core.Application.Contracts
public async Task<IResponseOutput> SubmissionRejection(TrialSiteSubmitBackCommand trialSiteSubmitBackCommand, [FromServices] IMailVerificationService _IMailVerificationService)
{
var trialId = trialSiteSubmitBackCommand.TrialId;
var trialSiteSurveyId = trialSiteSubmitBackCommand.TrialSiteSurveyId;
var survey = await _trialSiteSurveyRepository.FirstOrDefaultAsync(t => t.Id == trialSiteSurveyId);
@@ -492,36 +498,48 @@ namespace IRaCIS.Core.Application.Contracts
}
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.APM)
{
var isTrialSPMJoin = await _trialRepository.AnyAsync(t => t.Id == trialSiteSubmitBackCommand.TrialId && t.IsSPMJoinSiteSurvey);
// var isTrialSPMJoin = await _trialRepository.AnyAsync(t => t.Id == trialSiteSubmitBackCommand.TrialId && t.IsSPMJoinSiteSurvey);
var hasSPMOrCPM = await _trialRepository.Where(t => t.Id == trialSiteSubmitBackCommand.TrialId).AnyAsync(t => t.TrialIdentityUserList.SelectMany(t => t.TrialUserRoleList).Any(t =>
t.UserRole.IdentityUser.Status == UserStateEnum.Enable
&& t.UserRole.IsUserRoleDisabled == false
&& (t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM))
);
// var hasSPMOrCPM = await _trialRepository.Where(t => t.Id == trialSiteSubmitBackCommand.TrialId).AnyAsync(t => t.TrialIdentityUserList.SelectMany(t => t.TrialUserRoleList).Any(t =>
//t.UserRole.IdentityUser.Status == UserStateEnum.Enable
//&& t.UserRole.IsUserRoleDisabled == false
//&& (t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM))
//);
var isSPMjoin = isTrialSPMJoin && hasSPMOrCPM;
// var isSPMjoin = isTrialSPMJoin && hasSPMOrCPM;
if (isSPMjoin)
{
survey.State = TrialSiteSurveyEnum.CRCSubmitted;
// if (isSPMjoin)
// {
// survey.State = TrialSiteSurveyEnum.CRCSubmitted;
survey.ReviewerUserId = null;
survey.ReviewerTime = null;
}
else
{
survey.State = TrialSiteSurveyEnum.ToSubmit;
// survey.ReviewerUserId = null;
// survey.ReviewerTime = null;
// }
// else
// {
// survey.State = TrialSiteSurveyEnum.ToSubmit;
survey.PreliminaryUserId = null;
survey.ReviewerUserId = null;
survey.PreliminaryTime = null;
survey.ReviewerTime = null;
// survey.PreliminaryUserId = null;
// survey.ReviewerUserId = null;
// survey.PreliminaryTime = null;
// survey.ReviewerTime = null;
// }
survey.State = TrialSiteSurveyEnum.ToSubmit;
survey.PreliminaryUserId = null;
survey.ReviewerUserId = null;
survey.PreliminaryTime = null;
survey.ReviewerTime = null;
}
}
var info = await GetSiteSurveyInfo(trialSiteSurveyId, trialId);
await _siteSurveyLogRepository.AddAsync(new SiteSurveyLog() { TrialSiteSurveyId = trialSiteSurveyId, Name = $"{_userInfo.FullName} ({_userInfo.UserName})", UserType = (UserTypeEnum)_userInfo.UserTypeEnumInt, OptType = SiteSurveyOptTyp.Reject, Reason = survey.LatestBackReason, Json = info.ToJsonStr() });
await _trialSiteSurveyRepository.SaveChangesAsync();
return ResponseOutput.Ok();
@@ -547,6 +565,10 @@ namespace IRaCIS.Core.Application.Contracts
survey.IsDeleted = true;
var info = await GetSiteSurveyInfo(trialSiteSurveyId, survey.TrialId);
await _siteSurveyLogRepository.AddAsync(new SiteSurveyLog() { TrialSiteSurveyId = trialSiteSurveyId, Name = $"{_userInfo.FullName} ({_userInfo.UserName})", UserType = (UserTypeEnum)_userInfo.UserTypeEnumInt, OptType = SiteSurveyOptTyp.Over, Json = info.ToJsonStr() });
await _trialSiteSurveyRepository.SaveChangesAsync();
return ResponseOutput.Ok();
@@ -612,6 +634,9 @@ namespace IRaCIS.Core.Application.Contracts
//从项目site 中找到已存在的 加到历史人员中
addSurvey.TrialSiteUserSurveyList = userList;
//添加创建日志
addSurvey.SiteSurveyLogList.Add(new SiteSurveyLog() { Name = userInfo.EmailOrPhone, OptType = SiteSurveyOptTyp.Create });
currentEntity = await _trialSiteSurveyRepository.AddAsync(addSurvey);
}
@@ -649,7 +674,7 @@ namespace IRaCIS.Core.Application.Contracts
//找到最新的调研表
var currentLatest = await _trialSiteSurveyRepository.Where(t => t.TrialId == userInfo.TrialId && t.TrialSiteId == userInfo.TrialSiteId, true)
.Include(u => u.TrialSiteEquipmentSurveyList).Include(u => u.TrialSiteUserSurveyList).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
.Include(u => u.TrialSiteEquipmentSurveyList).Include(u => u.TrialSiteUserSurveyList).Include(t => t.SiteSurveyLogList).OrderByDescending(t => t.CreateTime).FirstOrDefaultAsync();
if (currentLatest == null)
{
@@ -674,6 +699,11 @@ namespace IRaCIS.Core.Application.Contracts
{
}
//更新调研表日志 - 老的调研表
var info1 = await GetSiteSurveyInfo(currentLatest.Id, currentLatest.TrialId);
currentLatest.SiteSurveyLogList.Add(new SiteSurveyLog() { Name = userInfo.ReplaceUserEmailOrPhone, OptType = SiteSurveyOptTyp.Over, Json = info1.ToJsonStr() });
var copy = currentLatest.Clone();
copy.State = TrialSiteSurveyEnum.ToSubmit;
@@ -685,10 +715,21 @@ namespace IRaCIS.Core.Application.Contracts
copy.Id = Guid.Empty;
copy.CreateTime = DateTime.Now;
copy.PreliminaryUserId = null;
copy.ReviewerUserId = null;
copy.PreliminaryTime = null;
copy.ReviewerTime = null;
if (userInfo.ReplaceUserEmailOrPhone != userInfo.EmailOrPhone)
{
copy.UserName = String.Empty;
copy.Phone = String.Empty;
//更新调研表日志
var info = await GetSiteSurveyInfo(currentLatest.Id, currentLatest.TrialId);
copy.SiteSurveyLogList.ForEach(t => { t.Id = Guid.Empty; });
copy.SiteSurveyLogList.Add(new SiteSurveyLog() { Name = userInfo.EmailOrPhone, OptType = SiteSurveyOptTyp.Update, OriginTrialSiteSurveyId = currentLatest.Id, Json = info.ToJsonStr() });
}
@@ -885,12 +926,25 @@ namespace IRaCIS.Core.Application.Contracts
}
//审批调研表日志
var info = await GetSiteSurveyInfo(trialSiteSurveyId, trialId);
await _siteSurveyLogRepository.AddAsync(new SiteSurveyLog() { TrialSiteSurveyId = trialSiteSurveyId, Name = trialSiteSurvey.UserName, OptType = SiteSurveyOptTyp.Submit, Json = info.ToJsonStr() });
}
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.SPM || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CPM)
{
await _trialSiteSurveyRepository.UpdatePartialFromQueryAsync(t => t.Id == trialSiteSurveyId && t.State == TrialSiteSurveyEnum.CRCSubmitted, u => new TrialSiteSurvey() { State = TrialSiteSurveyEnum.SPMApproved, PreliminaryUserId = _userInfo.UserRoleId, PreliminaryTime = DateTime.Now });
//审批调研表日志
var info = await GetSiteSurveyInfo(trialSiteSurveyId, trialId);
await _siteSurveyLogRepository.AddAsync(new SiteSurveyLog() { TrialSiteSurveyId = trialSiteSurveyId, Name = $"{_userInfo.FullName} ({_userInfo.UserName})", UserType = (UserTypeEnum)_userInfo.UserTypeEnumInt, OptType = SiteSurveyOptTyp.Approved, Json = info.ToJsonStr() });
}
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.APM)
{
@@ -903,7 +957,16 @@ namespace IRaCIS.Core.Application.Contracts
//将历史锁定的调研表废弃
await _trialSiteSurveyRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trialId && t.TrialSiteId == trialSiteSurvey.TrialSiteId && t.State == TrialSiteSurveyEnum.PMCreatedAndLock && t.Id != trialSiteSurveyId, z => new TrialSiteSurvey() { IsDeleted = true });
//审批调研表日志
var info = await GetSiteSurveyInfo(trialSiteSurveyId, trialId);
await _siteSurveyLogRepository.AddAsync(new SiteSurveyLog() { TrialSiteSurveyId = trialSiteSurveyId, Name = $"{_userInfo.FullName} ({_userInfo.UserName})", UserType = (UserTypeEnum)_userInfo.UserTypeEnumInt, OptType = SiteSurveyOptTyp.Approved, Json = info.ToJsonStr() });
}
await _trialSiteSurveyRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
@@ -1149,12 +1212,19 @@ namespace IRaCIS.Core.Application.Contracts
var queitUserTypeIdList = needQuitUserList.Select(t => t.UserTypeId).ToList();
await _trialSiteUserRoleRepository.UpdatePartialFromQueryAsync(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId && queitUserTypeIdList.Contains(t.UserRole.UserTypeId), c => new TrialSiteUserRole()
foreach (var item in needQuitUserList)
{
IsDeleted = true,
DeletedTime = DateTime.Now,
});
await _trialSiteUserRoleRepository.UpdatePartialFromQueryAsync(t => t.TrialId == trialId && t.TrialSiteId == trialSiteId
&& t.UserRole.UserTypeId == item.UserTypeId
&& t.UserRole.IdentityUserId == item.SystemUserId, c => new TrialSiteUserRole()
{
IsDeleted = true,
DeletedTime = DateTime.Now,
});
}
await _trialSiteSurveyRepository.UpdatePartialFromQueryAsync(t => t.Id == trialSiteSurveyId && t.State == TrialSiteSurveyEnum.SPMApproved, u => new TrialSiteSurvey() { State = TrialSiteSurveyEnum.PMCreatedAndLock, ReviewerUserId = _userInfo.UserRoleId, ReviewerTime = DateTime.Now });
@@ -1398,5 +1468,105 @@ namespace IRaCIS.Core.Application.Contracts
/// <summary>
/// 获取中心调研日志
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<SiteSurveyLogDTO>> GetSiteSurveyLogList(SiteSurveyLogQuery inQuery)
{
return _siteSurveyLogRepository.Where(t => t.TrialSiteSurveyId == inQuery.TrialSiteSurveyId)
.WhereIf(inQuery.Id != null, t => t.Id == inQuery.Id)
.ProjectTo<SiteSurveyLogDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.CreateTime).ToList();
}
/// <summary>
/// 获取中心设备信息
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetSiteSurveyEquipmentList(SiteSurveyEquipmentQuery inQuery)
{
//找到该中心最新的调研记录
var groupSelectIdQuery =
_trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.GroupBy(t => t.TrialSiteId)
.Select(g => g.OrderByDescending(u => u.CreateTime).Select(t => t.Id).First());
var pageList = await _trialSiteEquipmentSurveyRepository.Where(t => t.TrialSiteSurvey.TrialId == inQuery.TrialId).IgnoreQueryFilters()
.Where(t => groupSelectIdQuery.Contains(t.TrialSiteSurveyId))
.WhereIf(inQuery.IsDeleted != null, t => t.TrialSiteSurvey.IsDeleted == inQuery.IsDeleted)
.WhereIf(inQuery.State != null, t => t.TrialSiteSurvey.State == inQuery.State)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteSurvey.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.TrialSiteCode.IsNotNullOrEmpty(), t => t.TrialSiteSurvey.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode))
.WhereIf(inQuery.TrialSiteName.IsNotNullOrEmpty(), t => t.TrialSiteSurvey.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteName) ||
t.TrialSiteSurvey.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteName))
.ProjectTo<SiteSurveyEquipmentDto>(_mapper.ConfigurationProvider).ToPagedListAsync(inQuery);
var siteSurveryConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty;
var config = JsonConvert.DeserializeObject<TrialExtraConfig>(siteSurveryConfig) ?? new TrialExtraConfig();
return ResponseOutput.Ok(pageList, config);
}
/// <summary>
/// 调研表基本信息
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetSiteSurveyInfoList(SiteSurveyInfoQuery inQuery)
{
//找到该中心最新的调研记录
var groupSelectIdQuery =
_trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.GroupBy(t => t.TrialSiteId)
.Select(g => g.OrderByDescending(u => u.CreateTime).Select(t => t.Id).First());
var pageList = await _trialSiteSurveyRepository.Where(t => t.TrialId == inQuery.TrialId).IgnoreQueryFilters()
.Where(t => groupSelectIdQuery.Contains(t.Id))
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted)
.WhereIf(inQuery.State != null, t => t.State == inQuery.State)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.TrialSiteCode.IsNotNullOrEmpty(), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode))
.WhereIf(inQuery.TrialSiteName.IsNotNullOrEmpty(), t => t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteName) ||
t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteName))
.ProjectTo<TrialSiteSurveyView>(_mapper.ConfigurationProvider).ToPagedListAsync(inQuery);
var siteSurveryConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty;
var config = JsonConvert.DeserializeObject<TrialExtraConfig>(siteSurveryConfig) ?? new TrialExtraConfig();
return ResponseOutput.Ok(pageList, config);
}
/// <summary>
/// SPM 是否参与流程
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task<bool> GetTrialIsSPMJoin(Guid trialId)
{
var hasSPMOrCPM = await _trialRepository.Where(t => t.Id == trialId).AnyAsync(t => t.TrialIdentityUserList.SelectMany(t => t.TrialUserRoleList).Any(t =>
t.UserRole.IdentityUser.Status == UserStateEnum.Enable
&& t.UserRole.IsUserRoleDisabled == false
&& (t.UserRole.UserTypeEnum == UserTypeEnum.SPM || t.UserRole.UserTypeEnum == UserTypeEnum.CPM))
);
var isTrialSPMJoin = await _trialRepository.AnyAsync(t => t.Id == trialId && t.IsSPMJoinSiteSurvey);
var isSPMjoin = isTrialSPMJoin && hasSPMOrCPM;
return isSPMjoin;
}
}
}
@@ -56,6 +56,12 @@ namespace IRaCIS.Core.Application.Contracts
var item = addOrEditTrialSiteUserSurvey;
if (item.UserTypeId == null)
{
throw new BusinessValidationFailedException(_localizer["SystemCommon_WebErrorArgument"]);
}
//找下系统中是否存在该用户类型的 并且邮箱 或者手机的账户
var sysUserInfo = await _identityUserRepository.Where(t => t.EMail == item.Email,true).Include(t => t.UserRoleList).FirstOrDefaultAsync();
@@ -98,6 +98,21 @@ namespace IRaCIS.Core.Application.AutoMapper
CreateMap<SiteSurveyUserImportDto, IdentityUser>();
CreateMap<SiteSurveyLog, SiteSurveyLogDTO>();
CreateMap<TrialSiteEquipmentSurvey, SiteSurveyEquipmentDto>()
.ForMember(d => d.IsDeleted, u => u.MapFrom(s => s.TrialSiteSurvey.IsDeleted))
.ForMember(d => d.State, u => u.MapFrom(s => s.TrialSiteSurvey.State))
.ForMember(d => d.Email, u => u.MapFrom(s => s.TrialSiteSurvey.Email))
.ForMember(d => d.Phone, u => u.MapFrom(s => s.TrialSiteSurvey.Phone))
.ForMember(d => d.UserName, u => u.MapFrom(s => s.TrialSiteSurvey.UserName))
.ForMember(d => d.TrialSiteAliasName, u => u.MapFrom(s => s.TrialSiteSurvey.TrialSite.TrialSiteAliasName))
.ForMember(d => d.TrialSiteName, u => u.MapFrom(s => s.TrialSiteSurvey.TrialSite.TrialSiteName))
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSiteSurvey.TrialSite.TrialSiteCode));
}
}
}
@@ -27,15 +27,16 @@ namespace IRaCIS.Core.Application
IRepository<TrialQCQuestion> _trialQCQuestionRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<ReadingQuestionVisitJudgeRule> _readingQuestionVisitJudgeRuleRepository,
IRepository<TrialCriterionDictionaryCode> _trialCriterionDictionaryCode,
IRepository<SystemCriterionDictionaryCode> _systemCriterionDictionaryCode,
IRepository<ReadingQuestionCriterionSystem> _readingQuestionCriterionSystemRepository,
IRepository<ClinicalDataTrialSet> _clinicalDataTrialSetRepository,
IRepository<ReadingCriterionPage> _readingCriterionPageRepository,
IRepository<SystemCriterionKeyFile> _systemCriterionKeyFileRepository,
IOSSService _oSSService,
IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
IRepository<SystemCriterionKeyFile> _systemCriterionKeyFileRepository,
IOSSService _oSSService,
IRepository<VisitStage> _visitStageRepository,
IRepository<TrialCriterionKeyFile> _trialCriterionKeyFileRepository,
IOrganInfoService _iOrganInfoService,
IRepository<TrialBodyPart> _trialBodyPartRepository,
IRepository<ReadingSystemCriterionDictionary> _readingCriterionDictionaryRepository,
@@ -48,7 +49,7 @@ namespace IRaCIS.Core.Application
IRepository<SystemBasicData> _systemBasicDataRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Enroll> _enrollRepository,
IRepository<TrialQCQuestionAnswer> _qcQuestionAnswerRepository,
IRepository<TrialQCQuestionAnswer> _qcQuestionAnswerRepository,
IRepository<TrialStateChange> _trialStateChangeRepository,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository, IRepository<TrialDicomAE> _dicomAERepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, ITrialConfigService
@@ -105,6 +106,40 @@ namespace IRaCIS.Core.Application
throw new BusinessValidationFailedException(_localizer["TrialConfig_JudgeTaskFail"]);
}
if (trialCriterion.JudgeRuleEnum == JudgeRule.Difference)
{
var visitStageList = await _visitStageRepository.Where(x => x.TrialId == trialCriterion.TrialId).ToListAsync();
visitStageList.Add(new VisitStage()
{
VisitName = "Out of Plan",
VisitNum=-1,
});
var judgeCount = await _readingQuestionTrialRepository.CountAsync(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId && x.IsJudgeQuestion);
var ruleList = await _readingQuestionVisitJudgeRuleRepository.Where(x => x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId).ToListAsync();
var errorList = new List<string>();
visitStageList.ForEach(x =>
{
if (judgeCount != ruleList.Count(y => y.VisitNum == x.VisitNum))
{
errorList.Add(x.VisitName);
}
});
if (errorList.Count() > 0)
{
throw new BusinessValidationFailedException(_localizer["TrialConfig_VisitjudgeDeficiency", string.Join(",", errorList)]);
}
}
return ResponseOutput.Ok(true);
}
@@ -734,9 +769,16 @@ namespace IRaCIS.Core.Application
arbitration = inDto.IsReadingPeriod ? ArbitrationRule.Reading : ArbitrationRule.Visit;
}
JudgeMode judgeMode =await _readingQuestionCriterionTrialRepository.Where(x=>x.Id==inDto.TrialReadingCriterionId).Select(x=>x.JudgeModeEnum).FirstOrDefaultAsync();
if (arbitration== ArbitrationRule.Reading)
{
judgeMode = JudgeMode.SelectOne;
}
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial()
{
CircleRadius = inDto.CircleRadius,
JudgeModeEnum = judgeMode,
ReadingToolList = inDto.ReadingToolList,
SegmentToolList = inDto.SegmentToolList,
IsImageFilter = inDto.IsImageFilter,
@@ -292,7 +292,8 @@ namespace IRaCIS.Core.Application.Services
instances,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber
x => x.InstanceNumber,
series.Description
);
series.InstanceInfoList = sorted.Select(k =>
@@ -629,7 +630,8 @@ namespace IRaCIS.Core.Application.Services
instances,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber
x => x.InstanceNumber,
series.Description
);
series.InstanceInfoList = sorted.Select(k =>
@@ -682,7 +684,8 @@ namespace IRaCIS.Core.Application.Services
series.InstanceInfoList,
x => x.ImagePositionPatient,
x => x.ImageOrientationPatient,
x => x.InstanceNumber
x => x.InstanceNumber,
series.Description
);
series.InstanceInfoList = sorted;
+20 -3
View File
@@ -295,6 +295,21 @@ namespace IRaCIS.Core.Application.Service
}
public class SubjectTaskExcel
{
public string SubjectCode { get; set; }
public string TaskName { get; set; }
public string TaskBlindName { get; set; }
public string UserName { get; set; }
}
/// <summary>
/// 访视数据模型
/// </summary>
@@ -1728,10 +1743,10 @@ namespace IRaCIS.Core.Application.Service
//var d = _dicRepository.UpdateFromDTOAsync(new AddOrEditBasicDic() { Id = Guid.Parse("60d86683-c33b-4349-b672-08da1e91b622"), ParentId = null, ChildGroup = null, Code = null }, true, true).Result;
//var a = 123;
throw new BusinessValidationFailedException(_localizer["TrialIsDoubleCheck{0}", "测试"]);
//throw new BusinessValidationFailedException(_localizer["TrialIsDoubleCheck{0}", "测试"]);
var b = _localizer["test{0}", "测试"];
return _localizer["test{0}", "测试"];
//var b = _localizer["test{0}", "测试"];
//return _localizer["test{0}", "测试"];
//var list = _subjectVisitRepository.Where(t => t.Id == Guid.NewGuid()).SelectMany(t => t.VisitTaskList).ToList();
@@ -1741,6 +1756,8 @@ namespace IRaCIS.Core.Application.Service
//var list3 = _visitTaskRepository.Where(t => t.Id == Guid.NewGuid()).SelectMany(t => t.SourceSubjectVisit.VisitTaskList).ToList();
//var list2 = _subjectRepository.Where(t => t.Id == Guid.NewGuid()).SelectMany(t => t.SubjectVisitTaskList).ToList();
//return _userInfo.LocalIp;
return _userInfo.ClientInfo;
}
@@ -3060,6 +3060,11 @@ namespace IRaCIS.Core.Domain.Share
/// </summary>
ROIAllLength = 1015,
/// <summary>
/// 斑块类型
/// </summary>
PlaqueType=1018,
/// <summary>
/// PAV(冠状动脉粥样硬化体积百分比)
/// </summary>
@@ -3376,6 +3381,11 @@ namespace IRaCIS.Core.Domain.Share
/// </summary>
PercentageDifference = 5,
/// <summary>
/// 不适用
/// </summary>
NotApplicable = 6,
}
@@ -316,6 +316,11 @@ public class VisitTask : BaseFullAuditEntity
/// </summary>
public bool IsCopyLesionAnswer { get; set; } = false;
/// <summary>
/// 是否计算过裁判
/// </summary>
public bool IsCalculatedJudge { get; set; } = false;
#region
[Comment("完全随机阅片号")]
@@ -196,6 +196,73 @@ public class ReadingQuestionCriterionTrial : BaseAddAuditEntity
/// 定圆工具默认半径
/// </summary>
public decimal CircleRadius { get; set; } = 10;
/// <summary>
/// 仲裁模式
/// </summary>
public JudgeMode JudgeModeEnum { get; set; } = JudgeMode.SelectOne;
/// <summary>
/// 裁判规则
/// </summary>
public JudgeRule JudgeRuleEnum { get; set; } = JudgeRule.Consistent;
/// <summary>
/// 裁判任务生成
/// </summary>
public JudgeGenerate JudgeGenerateEnum { get; set; } = JudgeGenerate.Instant;
}
/// <summary>
/// 裁判任务生成时间
/// </summary>
public enum JudgeGenerate
{
/// <summary>
/// 及时
/// </summary>
Instant = 0,
/// <summary>
/// 阶段性
/// </summary>
Phased = 1,
}
/// <summary>
/// 仲裁模式
/// </summary>
public enum JudgeMode
{
/// <summary>
/// 整体结果择一判定
/// </summary>
SelectOne = 0,
/// <summary>
/// 指标组合判定
/// </summary>
Combined = 1,
}
/// <summary>
/// 裁判规则
/// </summary>
public enum JudgeRule
{
/// <summary>
/// 跨访视一致规则
/// </summary>
Consistent = 0,
/// <summary>
/// 访视间差异规则
/// </summary>
Difference = 1,
}
@@ -0,0 +1,67 @@
using IRaCIS.Core.Domain.Share;
using System.Linq;
namespace IRaCIS.Core.Domain.Models;
[Comment("项目阅片访视裁判规则")]
[Table("ReadingQuestionVisitJudgeRule")]
public class ReadingQuestionVisitJudgeRule : BaseAddAuditEntity
{
#region
[Comment("分页标准")]
[ForeignKey("ReadingQuestionId")]
[JsonIgnore]
public ReadingQuestionTrial ReadingQuestionTrial { get; set; }
#endregion
/// <summary>
/// 问题Id
/// </summary>
[Comment("问题Id")]
public Guid ReadingQuestionId { get; set; }
/// <summary>
/// 访视Num (计划外是-1)
/// </summary>
public decimal VisitNum { get; set; }
/// <summary>
/// 答案分组
/// </summary>
[MaxLength]
[Comment("答案分组")]
public List<string> AnswerGroup { get; set; } = new List<string>();
/// <summary>
/// 答案组合
/// </summary>
[Comment("答案组合")]
[MaxLength]
public List<AnswerCombinationDto> AnswerCombination { get; set; } = new List<AnswerCombinationDto>();
/// <summary>
/// 裁判类型
/// </summary>
[Comment("裁判类型")]
public JudgeTypeEnum JudgeType { get; set; } = JudgeTypeEnum.AnswerDisaffinity;
/// <summary>
/// 裁判百分比或绝对值的相差值
/// </summary>
[Comment("裁判百分比或绝对值的相差值")]
public decimal? JudgeDifferenceValue { get; set; } = 0;
/// <summary>
/// 裁判百分比或绝对值的相差值匹配规则
/// </summary>
[Comment("裁判百分比或绝对值的相差值匹配规则")]
public JudgeDifferenceType JudgeDifferenceType { get; set; }
}
public class AnswerCombinationDto
{
public List<string> AnswerGroupA { get; set; }
public List<string> AnswerGroupB { get; set; }
}
@@ -23,6 +23,10 @@ public class TrialSiteSurvey : BaseFullDeleteAuditEntity
[JsonIgnore]
public CommonUploadRecord SiteSurveyFile { get; set; }
[JsonIgnore]
public List<SiteSurveyLog> SiteSurveyLogList { get; set; }=new List<SiteSurveyLog>();
#endregion
public Guid TrialSiteId { get; set; }
@@ -64,7 +68,7 @@ public class TrialSiteSurvey : BaseFullDeleteAuditEntity
public bool? IsRoutineMRIPDEE { get; set; }
[Comment("MRI-PDFF 单次检查时长")]
public string MRIPDFFScanTime { get; set; }
public string MRIPDFFScanTime { get; set; }
[Comment("MRI-PDFF 预约等待时长")]
public string MRIPDFFLeadTime { get; set; }
@@ -88,3 +92,43 @@ public class TrialSiteSurvey : BaseFullDeleteAuditEntity
public string NotStrictManualBurnFlagReason { get; set; }
}
public class SiteSurveyLog : BaseAddAuditEntity
{
[JsonIgnore]
[ForeignKey("TrialSiteSurveyId")]
public TrialSiteSurvey TrialSiteSurvey { get; set; }
public Guid TrialSiteSurveyId { get; set; }
public string Name { get; set; }
public UserTypeEnum UserType { get; set; }
public SiteSurveyOptTyp OptType { get; set; }
public string Reason { get; set; }
[MaxLength]
public string Json { get; set; }
[Comment("更新调研表之前的调研表")]
public Guid? OriginTrialSiteSurveyId { get; set; }
}
public enum SiteSurveyOptTyp
{
Create = 0,
Submit = 1,
Approved = 2,
Reject = 3,
Update = 4,
Over=5,
}
+3
View File
@@ -7,6 +7,9 @@ namespace IRaCIS.Core.Domain.Models;
public class Subject : BaseFullDeleteAuditEntity
{
#region
[JsonIgnore]
public List<TrialImageDownload> TrialImageDownloadList { get; set; } = new List<TrialImageDownload>();
[JsonIgnore]
public List<TaskStudy> TaskStudyList { get; set; } = new List<TaskStudy>();
@@ -63,5 +63,17 @@ namespace IRaCIS.Core.Domain.Share
string BrowserFingerprint { get; }
UserWorkLanguage UserWorkLanguage { get; }
ClientInfo ClientInfo { get; }
}
public class ClientInfo
{
public string Browser { get; set; }
public string OS { get; set; }
public string DeviceType { get; set; }
}
}
+52 -7
View File
@@ -1,19 +1,15 @@
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Http;
using UAParser;
namespace IRaCIS.Core.Domain.Share
{
/// <summary>
/// 用户信息
/// </summary>
public class UserInfo : IUserInfo
public class UserInfo(IHttpContextAccessor _accessor, Parser parser) : IUserInfo
{
private readonly IHttpContextAccessor _accessor;
public UserInfo(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
/// <summary>
/// 用户角色Id
@@ -348,6 +344,55 @@ namespace IRaCIS.Core.Domain.Share
}
public ClientInfo ClientInfo
{
get
{
try
{
var userAgent = _accessor?.HttpContext.Request.Headers["User-Agent"].ToString();
if (!string.IsNullOrEmpty(userAgent))
{
var clientInfo = parser.Parse(userAgent);
return new ClientInfo()
{
OS = clientInfo.OS.ToString(),
Browser = clientInfo.UA.ToString(),
DeviceType = userAgent.Contains("Mobile") ? "Mobile" : "Desktop"
};
}
else
{
return new ClientInfo()
{
OS = "Unknown",
Browser = "Unknown",
DeviceType = "Unknown"
};
}
}
catch (Exception ex)
{
return new ClientInfo()
{
OS = "ParseError",
Browser = "ParseError",
DeviceType = "ParseError"
};
}
}
}
public Guid? SignId
{
@@ -417,7 +462,7 @@ namespace IRaCIS.Core.Domain.Share
public const string PermissionStr = "permissionStr";
public const string UserWorkLanguage = "userWorkLanguage";
public const string UserWorkLanguage = "userWorkLanguage";
}
@@ -3886,6 +3886,8 @@ namespace IRaCIS.Core.Infra.EFCore.Common
// 保存影像质量 、 修改整体肿瘤评估结果 、 非dicom 保存访视阅片结果 、附加评估
if (_userInfo.RequestUrl == "ReadingImageTask/changeDicomReadingQuestionAnswer"
|| _userInfo.RequestUrl == "ReadingImageTask/saveImageQuality"
|| _userInfo.RequestUrl == "ReadingImageTask/setJudgeForm"
|| _userInfo.RequestUrl == "ReadingImageTask/SubmitJudgeForm"
|| _userInfo.RequestUrl.Contains("SaveTaskQuestion")
|| _userInfo.RequestUrl == "ReadingImageTask/saveVisitTaskQuestions"
|| _userInfo.RequestUrl == "ReadingImageTask/changeCalculationAnswer"
@@ -119,6 +119,14 @@ public class IRaCISDBContext : DbContext
);
});
modelBuilder.Entity<ReadingQuestionVisitJudgeRule>(entity =>
{
entity.Property(e => e.AnswerCombination).HasConversion(
v => v == null ? null : JsonConvert.SerializeObject(v),
v => string.IsNullOrEmpty(v) ? new List<AnswerCombinationDto>() { } : JsonConvert.DeserializeObject<List<AnswerCombinationDto>>(v)
);
});
#region pgsql codefirst
//if (base.Database.IsNpgsql())
//{
@@ -421,6 +429,8 @@ public class IRaCISDBContext : DbContext
public virtual DbSet<ReadingQuestionTrial> ReadingQuestionTrial { get; set; }
public virtual DbSet<ReadingQuestionVisitJudgeRule> ReadingQuestionVisitJudgeRule { get; set; }
public virtual DbSet<ReadingClinicalDataPDF> ReadingClinicalDataPDF { get; set; }
public virtual DbSet<ReadingConsistentClinicalData> ReadingConsistentClinicalData { get; set; }
@@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="EFCore.BulkExtensions" Version="10.0.1" />
<PackageReference Include="EntityFrameworkCore.Triggered" Version="3.2.2" />
<PackageReference Include="EntityFrameworkCore.Projectables" Version="6.0.5" />
@@ -48,7 +48,7 @@ public class AuditEntityInterceptor(IUserInfo _userInfo,
AuditEntities(eventData.Context);
//IRC稽查 放在savechange 之前 不影响之前的逻辑
//IRCDataInspection(eventData.Context);
IRCDataInspection(eventData.Context);
//return result;
@@ -64,7 +64,7 @@ public class AuditEntityInterceptor(IUserInfo _userInfo,
AuditEntities(eventData.Context);
//IRC稽查 放在savechange 之前 不影响之前的逻辑
//IRCDataInspection(eventData.Context);
IRCDataInspection(eventData.Context);
//return result;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,61 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class siteSurveylog : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "SiteSurveyLog",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TrialSiteSurveyId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: false),
UserType = table.Column<int>(type: "int", nullable: false),
OptType = table.Column<int>(type: "int", nullable: false),
Reason = table.Column<string>(type: "nvarchar(400)", maxLength: 400, nullable: false),
Json = table.Column<string>(type: "nvarchar(max)", nullable: false),
OriginTrialSiteSurveyId = table.Column<Guid>(type: "uniqueidentifier", nullable: true, comment: "更新调研表之前的调研表"),
CreateUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreateTime = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SiteSurveyLog", x => x.Id)
.Annotation("SqlServer:Clustered", false);
table.ForeignKey(
name: "FK_SiteSurveyLog_TrialSiteSurvey_TrialSiteSurveyId",
column: x => x.TrialSiteSurveyId,
principalTable: "TrialSiteSurvey",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_SiteSurveyLog_User_CreateUserId",
column: x => x.CreateUserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_SiteSurveyLog_CreateTime",
table: "SiteSurveyLog",
column: "CreateTime")
.Annotation("SqlServer:Clustered", true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SiteSurveyLog");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class JudgeRule : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsCalculatedJudge",
table: "VisitTask",
type: "bit",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int>(
name: "JudgeGenerateEnum",
table: "ReadingQuestionCriterionTrial",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "JudgeModeEnum",
table: "ReadingQuestionCriterionTrial",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "JudgeRuleEnum",
table: "ReadingQuestionCriterionTrial",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateTable(
name: "ReadingQuestionVisitJudgeRule",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
ReadingQuestionId = table.Column<Guid>(type: "uniqueidentifier", nullable: false, comment: "问题Id"),
VisitNum = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
AnswerGroup = table.Column<string>(type: "nvarchar(max)", nullable: false, comment: "答案分组"),
AnswerCombination = table.Column<string>(type: "nvarchar(max)", nullable: false, comment: "答案组合"),
JudgeType = table.Column<int>(type: "int", nullable: false, comment: "裁判类型"),
JudgeDifferenceValue = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true, comment: "裁判百分比或绝对值的相差值"),
JudgeDifferenceType = table.Column<int>(type: "int", nullable: false, comment: "裁判百分比或绝对值的相差值匹配规则"),
CreateUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
CreateTime = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ReadingQuestionVisitJudgeRule", x => x.Id)
.Annotation("SqlServer:Clustered", false);
},
comment: "项目阅片访视裁判规则");
migrationBuilder.CreateIndex(
name: "IX_ReadingQuestionVisitJudgeRule_CreateTime",
table: "ReadingQuestionVisitJudgeRule",
column: "CreateTime")
.Annotation("SqlServer:Clustered", true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ReadingQuestionVisitJudgeRule");
migrationBuilder.DropColumn(
name: "IsCalculatedJudge",
table: "VisitTask");
migrationBuilder.DropColumn(
name: "JudgeGenerateEnum",
table: "ReadingQuestionCriterionTrial");
migrationBuilder.DropColumn(
name: "JudgeModeEnum",
table: "ReadingQuestionCriterionTrial");
migrationBuilder.DropColumn(
name: "JudgeRuleEnum",
table: "ReadingQuestionCriterionTrial");
}
}
}
@@ -6834,6 +6834,15 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasColumnType("bit")
.HasComment("eCRF报告是否显示在图像页面");
b.Property<int>("JudgeGenerateEnum")
.HasColumnType("int");
b.Property<int>("JudgeModeEnum")
.HasColumnType("int");
b.Property<int>("JudgeRuleEnum")
.HasColumnType("int");
b.Property<DateTime?>("ReadingInfoSignTime")
.HasColumnType("datetime2")
.HasComment("阅片信息签名时间");
@@ -7466,6 +7475,62 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
});
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.ReadingQuestionVisitJudgeRule", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.PrimitiveCollection<string>("AnswerCombination")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasComment("答案组合");
b.PrimitiveCollection<string>("AnswerGroup")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasComment("答案分组");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<Guid>("CreateUserId")
.HasColumnType("uniqueidentifier");
b.Property<int>("JudgeDifferenceType")
.HasColumnType("int")
.HasComment("裁判百分比或绝对值的相差值匹配规则");
b.Property<decimal?>("JudgeDifferenceValue")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)")
.HasComment("裁判百分比或绝对值的相差值");
b.Property<int>("JudgeType")
.HasColumnType("int")
.HasComment("裁判类型");
b.Property<Guid>("ReadingQuestionId")
.HasColumnType("uniqueidentifier")
.HasComment("问题Id");
b.Property<decimal>("VisitNum")
.HasPrecision(18, 2)
.HasColumnType("decimal(18,2)");
b.HasKey("Id");
SqlServerKeyBuilderExtensions.IsClustered(b.HasKey("Id"), false);
b.HasIndex("CreateTime");
SqlServerIndexBuilderExtensions.IsClustered(b.HasIndex("CreateTime"));
b.ToTable("ReadingQuestionVisitJudgeRule", t =>
{
t.HasComment("项目阅片访视裁判规则");
});
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.ReadingSystemCriterionDictionary", b =>
{
b.Property<Guid>("Id")
@@ -9827,6 +9892,55 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
});
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.SiteSurveyLog", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreateTime")
.HasColumnType("datetime2");
b.Property<Guid>("CreateUserId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Json")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<int>("OptType")
.HasColumnType("int");
b.Property<Guid?>("OriginTrialSiteSurveyId")
.HasColumnType("uniqueidentifier")
.HasComment("更新调研表之前的调研表");
b.Property<string>("Reason")
.IsRequired()
.HasMaxLength(400)
.HasColumnType("nvarchar(400)");
b.Property<Guid>("TrialSiteSurveyId")
.HasColumnType("uniqueidentifier");
b.Property<int>("UserType")
.HasColumnType("int");
b.HasKey("Id");
SqlServerKeyBuilderExtensions.IsClustered(b.HasKey("Id"), false);
b.HasIndex("CreateTime");
SqlServerIndexBuilderExtensions.IsClustered(b.HasIndex("CreateTime"));
b.ToTable("SiteSurveyLog");
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.Sponsor", b =>
{
b.Property<Guid>("Id")
@@ -16633,6 +16747,9 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasColumnType("bit")
.HasComment("阅片结果是否和原数据有差异");
b.Property<bool>("IsCalculatedJudge")
.HasColumnType("bit");
b.Property<bool>("IsCanEditUrgentState")
.HasColumnType("bit")
.HasComment("是否和编辑加急状态");
@@ -18978,6 +19095,25 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Navigation("RelevanceReadingQuestionTrial");
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.ReadingQuestionVisitJudgeRule", b =>
{
b.HasOne("IRaCIS.Core.Domain.Models.UserRole", "CreateUserRole")
.WithMany()
.HasForeignKey("CreateUserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IRaCIS.Core.Domain.Models.ReadingQuestionTrial", "ReadingQuestionTrial")
.WithMany()
.HasForeignKey("ReadingQuestionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreateUserRole");
b.Navigation("ReadingQuestionTrial");
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.ReadingSystemCriterionDictionary", b =>
{
b.HasOne("IRaCIS.Core.Domain.Models.UserRole", "CreateUserRole")
@@ -19563,6 +19699,25 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Navigation("Hospital");
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.SiteSurveyLog", b =>
{
b.HasOne("IRaCIS.Core.Domain.Models.UserRole", "CreateUserRole")
.WithMany()
.HasForeignKey("CreateUserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IRaCIS.Core.Domain.Models.TrialSiteSurvey", "TrialSiteSurvey")
.WithMany("SiteSurveyLogList")
.HasForeignKey("TrialSiteSurveyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreateUserRole");
b.Navigation("TrialSiteSurvey");
});
modelBuilder.Entity("IRaCIS.Core.Domain.Models.Sponsor", b =>
{
b.HasOne("IRaCIS.Core.Domain.Models.UserRole", "CreateUserRole")
@@ -22356,6 +22511,8 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
modelBuilder.Entity("IRaCIS.Core.Domain.Models.TrialSiteSurvey", b =>
{
b.Navigation("SiteSurveyLogList");
b.Navigation("TrialSiteEquipmentSurveyList");
b.Navigation("TrialSiteUserSurveyList");
@@ -325,7 +325,11 @@ public static class StaticData
public const string TrialVisit_InfluenceStudys_Export = "TrialVisit_InfluenceStudys_Export";
public const string TrialSiteSurvey_BasicInfo_Export = "TrialSiteSurvey_BasicInfo_Export";
public const string TrialSiteSurvey_Info_Export = "TrialSiteSurvey_Info_Export";
public const string TrialSiteSurvey_Equipment_Export = "TrialSiteSurvey_Equipment_Export";
}
+33
View File
@@ -1,4 +1,37 @@
kind: pipeline
type: ssh
name: ssh-linux-uat-irc-build-image
platform:
os: Linux
arch: 386
clone:
disable: true
server:
host: 101.132.253.119
user: root
password:
from_secret: test_ssh_pwd
steps:
- name: publish-test-irc
commands:
- bash /opt/1panel/xc-deploy-new/Uat_IRC/devops-publish/uat-branch-publish.sh
- name: notify-wecom
commands:
- bash /opt/1panel/xc-deploy-new/devops-center/drone-notify-wecom.sh "$DRONE_BUILD_STATUS" "$DRONE_REPO_NAME" "$DRONE_BRANCH" "$DRONE_BUILD_NUMBER" "4355b98e-1e72-4678-8dfb-2fc6ad0bf449" "$DRONE_COMMIT_MESSAGE" "$DRONE_COMMIT_AUTHOR" "Uat_IRC_API Uat_IRC_SCP_API" "irc.uat.extimaging.com"
when:
status:
- success
- failure
trigger:
branch:
- Uat_IRC_Net10
---
kind: pipeline
type: ssh
name: ssh-linux-test-irc-publish