Compare commits

..

358 Commits

Author SHA1 Message Date
he 4e66ea43d7 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-04-09 10:59:42 +08:00
he 68d69181a9 修改 2025-04-09 10:59:39 +08:00
hang b879b3f2c7 国际化修改
continuous-integration/drone/push Build is passing
2025-04-08 15:20:09 +08:00
hang 4fd77ce70d 影像回退逻辑增加
continuous-integration/drone/push Build is passing
2025-04-08 14:50:45 +08:00
he 8213c6d10f 测试肿瘤学评估
continuous-integration/drone/push Build is passing
2025-04-08 09:31:36 +08:00
he b79b4567b4 修改稽查文档
continuous-integration/drone/push Build is passing
2025-04-07 17:42:58 +08:00
he 8c5b759a92 同步修改
continuous-integration/drone/push Build is passing
2025-04-07 17:25:37 +08:00
he ab1e33a799 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-04-07 16:29:32 +08:00
he 824b65d5ee 同步系统标准修改 2025-04-07 16:29:31 +08:00
hang c68004b804 维护用户登录区域
continuous-integration/drone/push Build is passing
2025-04-07 15:45:43 +08:00
hang d5cd8dc338 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-04-07 15:24:08 +08:00
hang 1fef5509d1 修改解析IP区域位置的库 以及异地登录判断 2025-04-07 15:24:05 +08:00
he 06d12ce709 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-04-07 15:12:49 +08:00
he ad7ac80444 复制稽查文档 2025-04-07 15:11:49 +08:00
hang 29d0ebdb7c 账户日志的操作类型支持多选
continuous-integration/drone/push Build is passing
2025-04-07 14:31:06 +08:00
hang 9bcaa07c1a 测试新的解析IP的库
continuous-integration/drone/push Build is passing
2025-04-07 14:08:30 +08:00
he bf5f56f5f2 修改查询
continuous-integration/drone/push Build is passing
2025-04-07 11:06:11 +08:00
he c1c2b59641 修改
continuous-integration/drone/push Build is passing
2025-04-03 17:31:51 +08:00
he 33820c2acb 修改
continuous-integration/drone/push Build is passing
2025-04-03 17:26:19 +08:00
he 9814f63246 修改
continuous-integration/drone/push Build is passing
2025-04-03 16:27:06 +08:00
he 5e6c018199 修改
continuous-integration/drone/push Build is passing
2025-04-03 16:10:11 +08:00
he b24751287c 修改
continuous-integration/drone/push Build is running
2025-04-03 16:07:48 +08:00
he 759cc6c1be 修改
continuous-integration/drone/push Build is passing
2025-04-03 15:29:22 +08:00
he 1a929ce2ca 修改
continuous-integration/drone/push Build is passing
2025-04-03 15:10:04 +08:00
he 1e4571a814 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-04-03 14:31:25 +08:00
he 848670d128 修改 2025-04-03 14:31:23 +08:00
hang 6d9b5fdb2d 测试项目降级为8版本
continuous-integration/drone/push Build is passing
2025-04-03 14:26:11 +08:00
hang ab00d64725 移除之前的废弃包换用微软新包
continuous-integration/drone/push Build is running
2025-04-03 14:23:42 +08:00
hang 5e36054ee9 删除logdashboard 升级下fo-dicom 常见包
continuous-integration/drone/push Build is passing
2025-04-03 14:17:24 +08:00
hang 2b11042f35 升级fo-dicom
continuous-integration/drone/push Build is passing
2025-04-03 14:04:28 +08:00
hang e9e5075c1c 验证环境生成缩略图测试ok提交
continuous-integration/drone/push Build is passing
2025-04-03 13:56:54 +08:00
hang 9149dd6cf6 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8 2025-04-03 11:30:53 +08:00
hang 24bfb4920c IQC回退到CRC 上传修改
continuous-integration/drone/push Build is passing
2025-04-03 11:29:13 +08:00
he 553ad4760c 修改
continuous-integration/drone/push Build is passing
2025-04-02 15:55:12 +08:00
he 5acd56689b 修改
continuous-integration/drone/push Build is running
2025-04-02 15:52:07 +08:00
hang 5f0643d4d4 修改swagger 展示 2025-04-02 14:03:36 +08:00
he 17e4ed38be 修改
continuous-integration/drone/push Build is passing
2025-04-02 13:46:08 +08:00
he c49f16b055 修改
continuous-integration/drone/push Build is passing
2025-04-02 13:44:36 +08:00
he aa42d64cac 修改
continuous-integration/drone/push Build is passing
2025-04-01 18:05:58 +08:00
he 8f0ef86ab9 修改
continuous-integration/drone/push Build is passing
2025-04-01 17:55:48 +08:00
he c17b2f6bac 修改
continuous-integration/drone/push Build is running
2025-04-01 17:53:13 +08:00
he be498f2329 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:54:23 +08:00
he fea3d8d415 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:39:28 +08:00
he bffc8626c7 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:31:47 +08:00
he 1efe1228ac 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:21:50 +08:00
he f900b811c7 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:18:10 +08:00
he a5f7e03f6c 修改
continuous-integration/drone/push Build is passing
2025-04-01 16:05:13 +08:00
he 7aba4adc14 修改
continuous-integration/drone/push Build is passing
2025-04-01 15:52:37 +08:00
he 12c8c641ea 查询修改
continuous-integration/drone/push Build is passing
2025-04-01 15:09:47 +08:00
he 977adf3153 修改项目下拉查询
continuous-integration/drone/push Build is passing
2025-04-01 13:10:30 +08:00
he 409b76df26 修改
continuous-integration/drone/push Build is passing
2025-03-31 17:48:30 +08:00
he 2d9ebe7094 修改
continuous-integration/drone/push Build is passing
2025-03-31 15:26:13 +08:00
he 71e797cf7d 修改
continuous-integration/drone/push Build is passing
2025-03-31 14:06:17 +08:00
he f781027388 修改 2025-03-31 14:01:29 +08:00
he 56e316e6a1 修改
continuous-integration/drone/push Build is passing
2025-03-31 11:51:19 +08:00
he edef3e1990 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-31 11:09:24 +08:00
he d6d0965467 整体肿瘤评估 计算修改 2025-03-31 11:09:22 +08:00
hang 62f888710c 修改阅片人统计查询
continuous-integration/drone/push Build is passing
2025-03-28 14:55:59 +08:00
he 58e8c2392f 添加MRecisthhc
continuous-integration/drone/push Build is passing
2025-03-28 11:12:09 +08:00
he 0e1310324d 修改
continuous-integration/drone/push Build is passing
2025-03-28 09:48:46 +08:00
he efcda61104 修改
continuous-integration/drone/push Build is passing
2025-03-27 17:11:00 +08:00
he 97133a5554 文档修改
continuous-integration/drone/push Build is passing
2025-03-27 16:29:55 +08:00
he 577ed42f97 修改文件路径
continuous-integration/drone/push Build is passing
2025-03-27 16:19:08 +08:00
he 8f704c4617 修改
continuous-integration/drone/push Build is passing
2025-03-27 16:03:12 +08:00
he a03d7f55c7 稽查文档
continuous-integration/drone/push Build is passing
2025-03-27 15:48:33 +08:00
he 2bbc101f95 修改
continuous-integration/drone/push Build is passing
2025-03-27 11:17:59 +08:00
he 2b11e9165f 修改
continuous-integration/drone/push Build is passing
2025-03-27 11:08:06 +08:00
he b25dec68cb 修改项目下拉列表
continuous-integration/drone/push Build is passing
2025-03-27 10:55:45 +08:00
hang 2f57238f66 修改swagger 展示
continuous-integration/drone/push Build is passing
2025-03-26 14:22:26 +08:00
hang 8239061a84 修改异地登录bug 设置最后一次登录的iP
continuous-integration/drone/push Build is passing
2025-03-26 11:11:34 +08:00
hang a43ebc016a 修改异地登录ip逻辑
continuous-integration/drone/push Build is passing
2025-03-25 17:49:13 +08:00
hang c036aab9c4 修改refer
continuous-integration/drone/push Build is passing
2025-03-24 17:13:43 +08:00
hang dd6419dc44 撤回修改
continuous-integration/drone/push Build is passing
2025-03-24 17:13:21 +08:00
hang 54a9cfbb8e 修改refer
continuous-integration/drone/push Build is running
2025-03-24 17:12:04 +08:00
hang 2eb85b6b71 Merge branch 'Test_IRC_Net8' into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-24 16:59:47 +08:00
hang 712f1ceb61 修改非dicom 检查
continuous-integration/drone/push Build is passing
2025-03-24 16:59:11 +08:00
he adf873639c 修改稽查报错问题
continuous-integration/drone/push Build is passing
2025-03-24 16:46:33 +08:00
hang 4e9460e7da 为cdn 部署取项目Id 修改
continuous-integration/drone/push Build is passing
2025-03-24 15:17:44 +08:00
hang 5481eac988 增加环境变量
continuous-integration/drone/push Build is passing
2025-03-24 11:20:03 +08:00
he b7c9abca02 拷贝表单
continuous-integration/drone/push Build is passing
2025-03-20 17:37:18 +08:00
he 447d3fc36f Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-20 14:37:26 +08:00
he 71702b2abb 修改显示检查名称 2025-03-20 14:37:25 +08:00
hang 2ffb24d630 维护oss 数据大小
continuous-integration/drone/push Build is passing
2025-03-20 13:15:50 +08:00
he 81ecd9ff7f Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-20 09:38:24 +08:00
he ebe012ca67 修改 2025-03-20 09:38:22 +08:00
hang 805176c3ea 修改编译错误
continuous-integration/drone/push Build is running
2025-03-20 09:35:34 +08:00
hang f99cab6983 获取文件大小 oss
continuous-integration/drone/push Build is passing
2025-03-19 17:16:39 +08:00
he c94d800646 移动文件
continuous-integration/drone/push Build is passing
2025-03-19 15:47:31 +08:00
he 0cbc345f49 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-18 15:20:07 +08:00
he d34f3f1576 修改 2025-03-18 15:20:05 +08:00
hang 73f5e67e3c 切换账户排序修改
continuous-integration/drone/push Build is passing
2025-03-18 13:55:30 +08:00
he 5cf8c7a898 查询撤销
continuous-integration/drone/push Build is passing
2025-03-18 10:33:43 +08:00
he 11c9cebf47 接口修改
continuous-integration/drone/push Build is passing
2025-03-18 10:08:53 +08:00
he bd9362fb25 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-18 09:43:03 +08:00
he 3aa588f125 修改 2025-03-18 09:43:01 +08:00
hang 6d33a2c1b0 修改角色排序
continuous-integration/drone/push Build is passing
2025-03-18 09:33:38 +08:00
he 9e4cf1d1db 修改
continuous-integration/drone/push Build is passing
2025-03-17 16:44:43 +08:00
he ae38c84ef7 修改
continuous-integration/drone/push Build is passing
2025-03-17 16:30:27 +08:00
he 6306c6752a 修改
continuous-integration/drone/push Build is passing
2025-03-17 16:23:38 +08:00
he 5490630922 修改
continuous-integration/drone/push Build is passing
2025-03-17 15:31:53 +08:00
he d1ea886e76 修改排序
continuous-integration/drone/push Build is passing
2025-03-17 14:48:16 +08:00
he 7dc1205bb6 修改
continuous-integration/drone/push Build is passing
2025-03-17 14:14:01 +08:00
he 15b094a422 修改
continuous-integration/drone/push Build is passing
2025-03-17 13:52:23 +08:00
he 78c46572a2 修改路径
continuous-integration/drone/push Build is passing
2025-03-17 11:21:56 +08:00
he abeda7820d 修改文件路径
continuous-integration/drone/push Build is passing
2025-03-17 10:50:21 +08:00
he 2dac67618c 修改
continuous-integration/drone/push Build is passing
2025-03-14 17:10:22 +08:00
he bb9b1283bf 修改
continuous-integration/drone/push Build is passing
2025-03-14 16:47:39 +08:00
he b9458ecb38 修改
continuous-integration/drone/push Build is passing
2025-03-14 16:12:42 +08:00
he b205757f8f 修改
continuous-integration/drone/push Build is passing
2025-03-14 16:01:41 +08:00
he 0b937663ff 修改
continuous-integration/drone/push Build is passing
2025-03-14 15:11:21 +08:00
he 7a75d107dc 修改
continuous-integration/drone/push Build is passing
2025-03-14 14:50:12 +08:00
he 0f682dd184 修改
continuous-integration/drone/push Build is passing
2025-03-14 14:40:14 +08:00
he c2360dd519 修改
continuous-integration/drone/push Build is passing
2025-03-14 14:25:02 +08:00
he f9c2ac030a 修改
continuous-integration/drone/push Build is passing
2025-03-14 13:29:01 +08:00
he 7ce2386aea 修改
continuous-integration/drone/push Build is passing
2025-03-14 12:52:14 +08:00
he 67b226ee44 修改
continuous-integration/drone/push Build is passing
2025-03-14 11:45:20 +08:00
he 70c7f8a740 查询修改
continuous-integration/drone/push Build is passing
2025-03-14 10:20:55 +08:00
he e409aa3c05 修改
continuous-integration/drone/push Build is passing
2025-03-13 16:59:47 +08:00
he a3b5129ee2 修改
continuous-integration/drone/push Build is passing
2025-03-13 16:43:19 +08:00
he 57cd0281fa 查询条件修改
continuous-integration/drone/push Build is passing
2025-03-13 16:33:53 +08:00
he ba9d3abc52 修改
continuous-integration/drone/push Build is passing
2025-03-13 16:16:30 +08:00
he b9bc1f6da0 入项记录上传与修改
continuous-integration/drone/push Build is passing
2025-03-13 15:43:53 +08:00
he 08f1998e61 修改
continuous-integration/drone/push Build is passing
2025-03-13 15:22:40 +08:00
he bc19ead2f5 添加optuserType
continuous-integration/drone/push Build is passing
2025-03-13 14:36:37 +08:00
he f9327c56db Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-13 10:42:59 +08:00
he 17f3d821ea 修改 2025-03-13 10:42:57 +08:00
hang 02f3e97654 修改质控看到的列表
continuous-integration/drone/push Build is passing
2025-03-12 18:05:34 +08:00
he 94bba7837c 国际化修改
continuous-integration/drone/push Build is passing
2025-03-12 11:12:35 +08:00
he 626fcb9cf3 修改
continuous-integration/drone/push Build is passing
2025-03-12 09:37:36 +08:00
he bf92165432 修改
continuous-integration/drone/push Build is running
2025-03-12 09:36:55 +08:00
he 92e99edbbd 修改项目稽查
continuous-integration/drone/push Build is passing
2025-03-11 16:59:34 +08:00
he 94507c7887 修改稽查
continuous-integration/drone/push Build is passing
2025-03-11 16:41:36 +08:00
he 0cce75befa Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-11 16:36:34 +08:00
he 96469c28d3 修改 2025-03-11 16:36:33 +08:00
hang a12db2637e Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-11 15:37:18 +08:00
hang 0a406da3a4 修改过滤 2025-03-11 15:37:14 +08:00
he 6271dd4144 修改中心排序
continuous-integration/drone/push Build is passing
2025-03-11 15:12:57 +08:00
he 4182809657 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-10 17:40:03 +08:00
he ab6ec064fa 修改重复验证的问题 2025-03-10 17:40:03 +08:00
hang d921a48a09 阿里云返回oss 预览地址
continuous-integration/drone/push Build is passing
2025-03-10 17:35:30 +08:00
he 0f03dbc75b 修改
continuous-integration/drone/push Build is passing
2025-03-10 14:45:03 +08:00
he e5fa3a09b3 修改查询
continuous-integration/drone/push Build is passing
2025-03-10 14:17:22 +08:00
he 4cdfb60fdf 添加阅片人接口
continuous-integration/drone/push Build is passing
2025-03-10 13:46:12 +08:00
he 200bdaccc4 修改
continuous-integration/drone/push Build is passing
2025-03-10 11:38:10 +08:00
he 17a35e0fdb 修改
continuous-integration/drone/push Build is passing
2025-03-10 11:13:43 +08:00
he 28f2bf1629 修改
continuous-integration/drone/push Build is passing
2025-03-10 11:06:53 +08:00
he bec04ab795 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-10 10:56:12 +08:00
he 54cefab633 修改 2025-03-10 10:56:07 +08:00
hang 2918c0e93f 文件级别设置阅片过滤删除
continuous-integration/drone/push Build is passing
2025-03-07 15:54:05 +08:00
hang 92c495ed07 非dicom 预览阅片
continuous-integration/drone/push Build is passing
2025-03-07 15:41:46 +08:00
hang d9d807e3d1 修改dicom 只有一个序列设置删除 检查被过滤
continuous-integration/drone/push Build is passing
2025-03-07 10:35:18 +08:00
hang 959b49a2cc 非dicom 预览阅片影像 过滤是否阅片
continuous-integration/drone/push Build is passing
2025-03-06 16:46:17 +08:00
hang 17f131cf63 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-06 15:48:11 +08:00
hang 4ef67beafc 修改非dicom 过滤文件是否阅片,是否删除 2025-03-06 15:48:10 +08:00
he 826a04ef31 修改
continuous-integration/drone/push Build is passing
2025-03-06 14:38:12 +08:00
he 104b1208ed 修改
continuous-integration/drone/push Build is passing
2025-03-06 14:34:47 +08:00
he 8b3040c24d Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-06 13:12:10 +08:00
he 153dbd2016 添加排序 2025-03-06 13:12:09 +08:00
hang 91d5cbce16 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-06 11:06:25 +08:00
hang 7218427ec2 用户参与项目,返回授权 和禁用时间 2025-03-06 11:06:24 +08:00
he 5d91ae8157 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-06 10:47:56 +08:00
he 0f61d746e5 修改 2025-03-06 10:47:54 +08:00
hang e931e740e6 非dicom 文件修改列表预览可以查看删除
continuous-integration/drone/push Build is passing
2025-03-05 15:57:03 +08:00
hang 38917e05ab Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 15:21:05 +08:00
hang dd33f7e086 修改忽略过滤器 2025-03-05 15:21:04 +08:00
he 43d4d679b5 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 13:13:39 +08:00
he e02fa28cd0 修改非Dicom排序 2025-03-05 13:13:37 +08:00
he 055e085d2a 修改非Dicom排序
continuous-integration/drone/push Build is passing
2025-03-05 13:12:48 +08:00
he caf1fb6b32 修改
continuous-integration/drone/push Build is passing
2025-03-05 11:41:36 +08:00
he 6b049e68cd Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 11:24:53 +08:00
he 2a4360cc64 修改数据库结构 2025-03-05 11:24:50 +08:00
hang 8efc254f3c Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 10:43:11 +08:00
hang f89b3daf50 qc 序列层级返回更新时间
continuous-integration/drone/push Build is passing
2025-03-05 10:42:58 +08:00
hang 29f6196698 合并
continuous-integration/drone/push Build is passing
2025-03-05 09:47:41 +08:00
hang 09ff2468e9 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 09:44:36 +08:00
hang 1867277e1b 修改非dicom 检查编号重复问题 2025-03-05 09:44:34 +08:00
he 053a09a5b2 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-05 09:40:03 +08:00
he fae86f0836 修改非dicom 影像 排序 先按检查时间,再按创建时间排序 2025-03-05 09:39:45 +08:00
he 2e539dfa71 修改非dicom 影像 排序 先按检查时间,再按创建时间排序
continuous-integration/drone/push Build is passing
2025-03-05 09:31:37 +08:00
he a9efd85aec 修改
continuous-integration/drone/push Build is passing
2025-03-04 17:58:33 +08:00
he 09e70b9f21 修改
continuous-integration/drone/push Build is passing
2025-03-04 17:48:33 +08:00
he 2d184e0f08 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-04 16:39:44 +08:00
he 43d6c7d8db 查询条件修改 2025-03-04 16:39:42 +08:00
hang 19487acc64 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-04 15:20:27 +08:00
hang 336e7768b8 时间拼写错误
continuous-integration/drone/push Build is passing
2025-03-04 15:20:06 +08:00
hang 9b49dc41c8 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-04 11:20:51 +08:00
hang 74f896cf00 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-03-04 11:20:22 +08:00
hang 10b0bde1d0 检查列表增加时间 2025-03-04 11:20:21 +08:00
he 411b5d5f8f 培训记录修改
continuous-integration/drone/push Build is passing
2025-03-04 10:45:29 +08:00
he b6da27ac07 修改
continuous-integration/drone/push Build is passing
2025-03-03 17:20:38 +08:00
he a6b81b038f 修改
continuous-integration/drone/push Build is passing
2025-03-03 16:49:43 +08:00
he e2c80babfa 修改
continuous-integration/drone/push Build is passing
2025-03-03 16:34:58 +08:00
he 01b9f28e7b 批量添加
continuous-integration/drone/push Build is passing
2025-03-03 16:08:50 +08:00
he 2c9fad60fb 修改
continuous-integration/drone/push Build is passing
2025-03-03 16:03:04 +08:00
he 398baea876 字段修改
continuous-integration/drone/push Build is passing
2025-03-03 13:56:01 +08:00
he aec94d0a46 数据库修改
continuous-integration/drone/push Build is passing
2025-03-03 13:43:34 +08:00
he 4b69e45d44 实体修改
continuous-integration/drone/push Build is passing
2025-03-03 13:18:11 +08:00
he 12f2c2becb 修改
continuous-integration/drone/push Build is passing
2025-03-03 11:06:44 +08:00
he 699f79278b 修改
continuous-integration/drone/push Build is passing
2025-02-28 17:55:45 +08:00
he 88e07d28fd Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-28 16:35:03 +08:00
he 226ba06bf3 修改 2025-02-28 16:35:02 +08:00
hang c1667fc48b Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-28 11:29:15 +08:00
hang f900e675da 清理项目删除项目参与用户 2025-02-28 11:29:14 +08:00
he ee51b9eade 添加 ImageFormatList
continuous-integration/drone/push Build is passing
2025-02-27 17:19:53 +08:00
he bf62ee92dd 添加 ImageFormatList
continuous-integration/drone/push Build is passing
2025-02-27 17:19:35 +08:00
he 78532803bc 影像质疑超限天数修改
continuous-integration/drone/push Build is passing
2025-02-27 17:12:28 +08:00
he 86ea3ebc32 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-27 17:12:01 +08:00
he 01aba3f3e0 影像质疑超限天数修改 2025-02-27 17:11:59 +08:00
hang 6dc1ef5728 增加查询配置
continuous-integration/drone/push Build is passing
2025-02-27 16:15:11 +08:00
hang 02e5d770db 增加查询配置
continuous-integration/drone/push Build is passing
2025-02-27 16:14:46 +08:00
hang f8c3704c87 合并修改
continuous-integration/drone/push Build is passing
2025-02-27 15:39:48 +08:00
hang 4c21459e00 修改StudyName 存放位置
continuous-integration/drone/push Build is passing
2025-02-27 15:38:51 +08:00
he cdbbe460ab 修改实体
continuous-integration/drone/push Build is passing
2025-02-27 14:31:38 +08:00
he 45da1645e0 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-27 14:31:02 +08:00
he 9a1f4697c2 修改实体 2025-02-27 14:31:01 +08:00
hang 217b8713ff 合并到测试环境
continuous-integration/drone/push Build is passing
2025-02-27 13:17:08 +08:00
hang 0998f047e4 Merge branch 'Uat_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Uat_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-27 13:05:10 +08:00
hang 47755bc2aa 检查 返回配置字段 2025-02-27 13:05:09 +08:00
he 72efd36649 实体修改
continuous-integration/drone/push Build is running
2025-02-27 13:05:00 +08:00
he 553a8d392f 查询返回检查名称
continuous-integration/drone/push Build is passing
2025-02-27 11:33:31 +08:00
he f050416265 数据库文件
continuous-integration/drone/push Build is passing
2025-02-27 11:21:32 +08:00
he a7d1a92a01 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-27 11:17:15 +08:00
he bf9ce9b213 影像配置数据库字段添加 2025-02-27 11:17:13 +08:00
he a9c7c79fb5 影像配置数据库字段添加
continuous-integration/drone/push Build is passing
2025-02-27 11:16:53 +08:00
hang dc3a830909 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-27 10:49:59 +08:00
hang 171bfde031 质控删除文件 2025-02-27 10:49:58 +08:00
he f471ce1535 修改
continuous-integration/drone/push Build is passing
2025-02-26 13:37:30 +08:00
hang 56170b73ed 修改非dicom 阅片
continuous-integration/drone/push Build is passing
2025-02-26 13:25:56 +08:00
he 2a9c1ec45c Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-26 09:46:28 +08:00
he 3ccb3ff4de 授权修改 2025-02-26 09:46:26 +08:00
hang 6c078806cd 修改token 过期时间
continuous-integration/drone/push Build is passing
2025-02-25 16:36:18 +08:00
hang c2f768bef8 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-25 16:11:49 +08:00
hang 1b7bb5a4fe 修改链接过期+ 删除oss 数据ok 2025-02-25 16:11:47 +08:00
he dfe6d13182 修改
continuous-integration/drone/push Build is passing
2025-02-25 15:51:16 +08:00
he 4c04718db4 修改
continuous-integration/drone/push Build is passing
2025-02-25 15:23:42 +08:00
he 64d803cbc0 修改
continuous-integration/drone/push Build is passing
2025-02-25 15:01:57 +08:00
he 54ccae5762 修改
continuous-integration/drone/push Build is passing
2025-02-25 14:48:05 +08:00
he 8d6bf0c7b1 修改
continuous-integration/drone/push Build is passing
2025-02-25 14:26:21 +08:00
he 8496e6bcd7 修改
continuous-integration/drone/push Build is running
2025-02-25 14:24:44 +08:00
he 7770fc264b Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-25 14:07:26 +08:00
he 51f21805be 非Dicom 2025-02-25 14:07:25 +08:00
hang 434e49ea85 修改用户来源为null bug
continuous-integration/drone/push Build is passing
2025-02-25 11:31:19 +08:00
hang 468f7c7070 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is running
2025-02-25 11:29:52 +08:00
hang 4577db7582 修改bug 2025-02-25 11:29:51 +08:00
he cc17816dae Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-25 11:12:44 +08:00
he 172cecebe4 修改 2025-02-25 11:12:42 +08:00
hang 7913acdf70 修改运维增加字段
continuous-integration/drone/push Build is passing
2025-02-25 11:08:37 +08:00
hang e9f57b5001 临时注释提交,手动维护
continuous-integration/drone/push Build is passing
2025-02-25 11:02:52 +08:00
he b8c0bd7082 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-25 10:38:14 +08:00
he 6200ec1ba7 代码提交 2025-02-25 10:38:11 +08:00
hang 73912fd875 修改列表
continuous-integration/drone/push Build is passing
2025-02-25 10:26:55 +08:00
hang 812035686e 修改用户参与项目接口
continuous-integration/drone/push Build is passing
2025-02-25 09:57:45 +08:00
hang 1f8caa4616 合并
continuous-integration/drone/push Build is passing
2025-02-24 17:21:28 +08:00
hang 4a1e0a87ba 修改管理用户类型过滤 2025-02-24 17:21:09 +08:00
he 337bda45fd 修改
continuous-integration/drone/push Build is passing
2025-02-24 17:17:25 +08:00
he c2412bfb4b 复制系统到项目
continuous-integration/drone/push Build is passing
2025-02-24 16:54:05 +08:00
he cff6b87daa Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-24 16:15:00 +08:00
he 2f93a490f0 查询项目信息 2025-02-24 16:14:59 +08:00
hang 1856ef9483 修改合并
continuous-integration/drone/push Build is passing
2025-02-24 16:09:42 +08:00
hang b45602556c 用户创建来源维护,以及用户参与项目列表修改 2025-02-24 16:07:52 +08:00
he b5326d4928 修改
continuous-integration/drone/push Build is passing
2025-02-24 13:45:55 +08:00
he 8bbc8c449f 合并
continuous-integration/drone/push Build is running
2025-02-24 13:44:57 +08:00
he dcd6375d7d 系统配置 2025-02-24 13:43:22 +08:00
hang 8b53517f2c 角色修改
continuous-integration/drone/push Build is running
2025-02-24 13:43:21 +08:00
hang 1c3ddcf1cd 修改邮箱登录bug
continuous-integration/drone/push Build is passing
2025-02-24 13:32:54 +08:00
hang fc4ef6b939 账号初始化链接过期+初始化不允许忘记密码修改密码
continuous-integration/drone/push Build is passing
2025-02-24 13:24:41 +08:00
hang 6d009c4f86 增加备注
continuous-integration/drone/push Build is passing
2025-02-24 11:32:26 +08:00
hang f995187925 修改文件类型基础代码
continuous-integration/drone/push Build is passing
2025-02-24 11:25:03 +08:00
hang 67a6a5f861 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-21 17:08:35 +08:00
hang 6bfa4da72d 文档服务初步提交 2025-02-21 17:08:33 +08:00
he 9797c94aa8 修改
continuous-integration/drone/push Build is passing
2025-02-21 14:46:10 +08:00
hang 5dd2dfd17b 增加项目文档新表
continuous-integration/drone/push Build is passing
2025-02-21 14:20:39 +08:00
hang 5791aca9fd 最后一次登录时间 和ip 记录
continuous-integration/drone/push Build is passing
2025-02-20 15:26:36 +08:00
hang f61ce70b82 修改项目培训统计数字
continuous-integration/drone/push Build is passing
2025-02-20 15:05:13 +08:00
hang c8091d3215 清理签名文档的表
continuous-integration/drone/push Build is passing
2025-02-20 13:47:09 +08:00
hang 7153d810aa 删除用户角色表部分字段,修改统计
continuous-integration/drone/push Build is passing
2025-02-20 13:08:06 +08:00
hang 68053d24b6 项目创建账户的时候,没有用户名,但是目标用户Id 有值,导致查询出来有名字
continuous-integration/drone/push Build is passing
2025-02-19 14:20:06 +08:00
hang a49b4c8ef7 修改冲突
continuous-integration/drone/push Build is passing
2025-02-19 10:13:37 +08:00
hang c6c036c152 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-19 09:39:21 +08:00
hang db0d087396 修改国际化bug 2025-02-19 09:39:20 +08:00
he 263f43b1a9 项目下拉修改
continuous-integration/drone/push Build is passing
2025-02-18 13:35:22 +08:00
hang 21626cda9d 维护历史退出人员数据
continuous-integration/drone/push Build is passing
2025-02-18 13:15:05 +08:00
he 77d920a2ef Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-18 10:40:31 +08:00
he bbf7af8405 项目筛选修改 2025-02-18 10:40:29 +08:00
hang d0bbc58b20 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-17 17:15:44 +08:00
hang fed2cbe043 修改 创建账号仅仅记录一条
continuous-integration/drone/push Build is passing
2025-02-17 17:15:25 +08:00
hang 4d4bb08423 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-17 15:13:02 +08:00
hang dd09c78cd2 项目退出人员维护数据 2025-02-17 15:12:59 +08:00
hang 771091a557 IR 反馈bug 重新设置状态
continuous-integration/drone/push Build is passing
2025-02-17 14:16:34 +08:00
he 8ce1bdf21c Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-17 10:06:06 +08:00
he 679cc26225 状态修改 2025-02-17 10:06:04 +08:00
hang ff5be827d0 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-17 09:28:02 +08:00
hang 4555997957 修改文档查询条件问题
continuous-integration/drone/push Build is passing
2025-02-17 09:22:58 +08:00
hang 3b43bee0f1 x
continuous-integration/drone/push Build is passing
2025-02-14 17:30:21 +08:00
hang 3677a30bab 修改日志角色查询
continuous-integration/drone/push Build is passing
2025-02-14 17:19:50 +08:00
hang 2e8b2a24ae 合并冲突
continuous-integration/drone/push Build is passing
2025-02-14 16:51:09 +08:00
hang 26500aa1cf 修改日志
continuous-integration/drone/push Build is passing
2025-02-14 16:48:52 +08:00
hang adfd6b50c1 修改登录日志
continuous-integration/drone/push Build is failing
2025-02-14 16:39:38 +08:00
hang b58bdc184e Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-14 16:15:37 +08:00
hang 580eea7a61 修改稽查查询条件bug
continuous-integration/drone/push Build is passing
2025-02-14 16:15:21 +08:00
hang da27b65e56 用户登录日志 项目参与用户修改
continuous-integration/drone/push Build is passing
2025-02-14 16:11:48 +08:00
hang bb493fe827 修改日志,和稽查查询 2025-02-14 16:02:49 +08:00
hang 655fe18138 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-14 16:00:48 +08:00
hang 9d70d61013 修改日志,和稽查查询 2025-02-14 16:00:46 +08:00
he 68452beba0 添加是否存在未处理反馈的状态
continuous-integration/drone/push Build is passing
2025-02-14 15:40:34 +08:00
he 409e9e9bc0 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-14 15:18:12 +08:00
he f241f2cd2b 去除掉已经停止的项目 2025-02-14 15:18:10 +08:00
hang 2ea90a66ae Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-14 14:18:51 +08:00
hang c2c8f65aaa 修改质控问题答案排序
continuous-integration/drone/push Build is passing
2025-02-14 14:07:33 +08:00
hang a578be8336 Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8 2025-02-14 13:27:52 +08:00
hang 45b469682a 影像质控,质控人看到的是过滤了删除的,其他人看到的是原始的
continuous-integration/drone/push Build is passing
2025-02-14 13:09:26 +08:00
hang 1e9f4d890f 质控预览再次修改0214
continuous-integration/drone/push Build is passing
2025-02-14 10:54:00 +08:00
hang 44f74fd9e6 修改 预览根据质控状态过滤
continuous-integration/drone/push Build is passing
2025-02-13 18:01:17 +08:00
hang f1c8415899 修改阅片预览影像(同时标记了删除 和阅片)
continuous-integration/drone/push Build is passing
2025-02-13 17:11:21 +08:00
hang 823ada5673 合并
continuous-integration/drone/push Build is passing
2025-02-13 16:53:27 +08:00
hang 55f146a44a 修改序列上的Instance 数量
continuous-integration/drone/push Build is passing
2025-02-13 16:52:13 +08:00
hang 5fe972bd99 修改质控预览影像 uat 修改
continuous-integration/drone/push Build is passing
2025-02-13 16:43:59 +08:00
hang 0578263e10 修改质控预览影像 uat 修改
continuous-integration/drone/push Build is passing
2025-02-13 16:40:34 +08:00
hang 9316c0814f 合并
continuous-integration/drone/push Build is passing
2025-02-13 16:16:18 +08:00
hang 8bdd9e29ab 修改阅片看到得instance 序列
continuous-integration/drone/push Build is failing
2025-02-13 16:13:52 +08:00
hang ae14a8a530 修改预览不阅片影像数字
continuous-integration/drone/push Build is passing
2025-02-13 15:53:02 +08:00
hang 2a170cc97e 修改预览不阅片影像数字
continuous-integration/drone/push Build is passing
2025-02-13 15:52:44 +08:00
hang c109e14a93 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-13 14:01:02 +08:00
hang 240d406a1a Merge branch 'Uat_IRC_Net8' into Test_IRC_Net8 2025-02-13 14:00:53 +08:00
hang b6cf988058 导表 裁判选择原因bug
continuous-integration/drone/push Build is passing
2025-02-13 14:00:34 +08:00
he c16153fa19 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-13 13:12:11 +08:00
he a0797a99ff 修改 2025-02-13 13:12:09 +08:00
hang 376cfa3167 合并bug
continuous-integration/drone/push Build is passing
2025-02-13 11:06:32 +08:00
hang 14690dc3cc 合并修改
continuous-integration/drone/push Build is passing
2025-02-13 10:59:23 +08:00
hang 6dd0831a66 质控预览 增加是否阅片 是否删除 第二次提交
continuous-integration/drone/push Build is passing
2025-02-13 10:40:18 +08:00
hang a150156810 修改配置文件
continuous-integration/drone/push Build is passing
2025-02-13 10:21:57 +08:00
hang d61fba9d95 Uat 影像阅片初步修改 2025-02-13 10:21:49 +08:00
hang 7cb8d04ca9 Uat 影像阅片初步修改
continuous-integration/drone/push Build is passing
2025-02-13 10:17:01 +08:00
he a2fc2c5075 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-12 16:52:43 +08:00
he 1ed8788c83 修改邮箱 2025-02-12 16:52:39 +08:00
hang 14e95fd303 修改配置文件
continuous-integration/drone/push Build is passing
2025-02-12 14:01:53 +08:00
hang 3dca5aa06f Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-11 15:45:54 +08:00
hang faea3a4f86 肿瘤学阅片结果导出 2025-02-11 15:45:50 +08:00
he a5dcad1767 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-11 14:38:09 +08:00
he 6754121b17 肿瘤学修改 2025-02-11 14:38:07 +08:00
hang 131425774a 修改MFA 日志
continuous-integration/drone/push Build is passing
2025-02-10 15:08:14 +08:00
hang 585e4cdc1b 修改一致性核查对话判断
continuous-integration/drone/push Build is passing
2025-02-10 14:54:04 +08:00
hang 12ddeba2a3 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-10 09:25:38 +08:00
hang ab0c256e0b 修改国际化返回更多信息 2025-02-10 09:25:37 +08:00
hang 8a24b33757 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-08 15:58:17 +08:00
hang 8f6e2e342a 肿瘤评估标准-Id匹配合并去重bug 2025-02-08 15:58:12 +08:00
he 4dfeb653b1 修改逻辑
continuous-integration/drone/push Build is passing
2025-02-08 15:43:11 +08:00
he 670a754eb2 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-08 11:06:54 +08:00
he 3f46103dc3 修改 2025-02-08 11:06:53 +08:00
hang 6c2901daca Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
2025-02-08 10:54:45 +08:00
hang a73e5d4133 增加一致性核查排序 以及一致性核查国际化调整填充公司简称 2025-02-08 10:54:44 +08:00
he b067cb66f3 接口修改
continuous-integration/drone/push Build is running
2025-02-08 10:54:06 +08:00
he f1185758d6 修改领取规则
continuous-integration/drone/push Build is passing
2025-02-08 10:48:00 +08:00
he 0d4a0adf00 添加IsPACSConnect
continuous-integration/drone/push Build is passing
2025-02-08 10:23:22 +08:00
he 20f6f95b89 Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is running
2025-02-08 10:20:18 +08:00
he 7e7c186784 临床数据修改 2025-02-08 10:20:15 +08:00
hang 70e0a1325a HIR 推送影像bug 修改到IRC 测试
continuous-integration/drone/push Build is passing
2025-02-08 09:33:29 +08:00
he 91471dee13 修改配置
continuous-integration/drone/push Build is passing
2025-02-07 15:03:14 +08:00
201 changed files with 449889 additions and 927 deletions
+3 -3
View File
@@ -14,9 +14,9 @@
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" />
<PackageReference Include="DistributedLock.Core" Version="1.0.7" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
<PackageReference Include="fo-dicom" Version="5.1.3" />
<PackageReference Include="fo-dicom.Codecs" Version="5.15.1" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
<PackageReference Include="fo-dicom" Version="5.2.1" />
<PackageReference Include="fo-dicom.Codecs" Version="5.16.0" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Minio" Version="6.0.3" />
+16 -8
View File
@@ -126,16 +126,22 @@ builder.Services.Configure<ForwardedHeadersOptions>(options =>
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
.AddImageManager<ImageSharpImageManager>();
//Dicom影像渲染图片 跨平台
//builder.Services.AddDicomSetup();
new DicomSetupBuilder()
.RegisterServices(s =>
s.AddFellowOakDicom()
.AddTranscoderManager<NativeTranscoderManager>()
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
.AddImageManager<ImageSharpImageManager>())
.SkipValidation()
.Build();
//new DicomSetupBuilder()
// .RegisterServices(s =>
// s.AddFellowOakDicom()
// .AddTranscoderManager<NativeTranscoderManager>()
// //.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
// .AddImageManager<ImageSharpImageManager>())
// .SkipValidation()
// .Build();
@@ -211,6 +217,8 @@ else
#endregion
DicomSetupBuilder.UseServiceProvider(app.Services);
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
var server = DicomServerFactory.Create<CStoreSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services,logger: logger);
+3 -4
View File
@@ -76,9 +76,10 @@ namespace IRaCIS.Core.SCP.Service
};
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies)
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
: base(stream, fallbackEncoding, log, dependencies)
{
_serviceProvider = injectServiceProvider.CreateScope().ServiceProvider;
}
@@ -92,9 +93,7 @@ namespace IRaCIS.Core.SCP.Service
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
_serviceProvider = (IServiceProvider)this.UserState;
//_serviceProvider = (IServiceProvider)this.UserState;
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
+17 -4
View File
@@ -25,6 +25,7 @@ using RestSharp;
using RestSharp.Authenticators;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -185,7 +186,7 @@ namespace IRaCIS.Api.Controllers
[HttpGet("User/UserRedirect")]
[AllowAnonymous]
public async Task<IActionResult> UserRedirect([FromServices] IRepository<IdentityUser> _useRepository, string url, [FromServices] ILogger<ExtraController> _logger)
public async Task<IActionResult> UserRedirect([FromServices] IRepository<IdentityUser> _useRepository, string url, [FromServices] ILogger<ExtraController> _logger, [FromServices] ITokenService _tokenService)
{
var decodeUrl = System.Web.HttpUtility.UrlDecode(url);
@@ -200,10 +201,22 @@ namespace IRaCIS.Api.Controllers
var errorUrl = domainStrList[0] + "//" + domainStrList[2] + "/error";
if (!await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd))
if (lang == "zh")
{
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(lang == "zh" ? "" : "ErrorThe initialization link has expired.")} ";
CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.zh_CN);
CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.zh_CN);
}
else
{
CultureInfo.CurrentCulture = new CultureInfo(StaticData.CultureInfo.en_US);
CultureInfo.CurrentUICulture = new CultureInfo(StaticData.CultureInfo.en_US);
}
var isExpire = _tokenService.IsTokenExpired(token);
if (!await _useRepository.AnyAsync(t => t.Id == Guid.Parse(userId) && t.EmailToken == token && t.IsFirstAdd) || isExpire)
{
decodeUrl = errorUrl + $"?lang={lang}&ErrorMessage={System.Web.HttpUtility.UrlEncode(I18n.T("UserRedirect_InitializationLinkExpire"))} ";
}
return Redirect(decodeUrl);
+7 -2
View File
@@ -69,6 +69,7 @@
<ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PrivateAssets>all</PrivateAssets>
@@ -79,8 +80,6 @@
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
<PackageReference Include="LogDashboard" Version="1.4.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
@@ -114,6 +113,12 @@
</Content>
</ItemGroup>
<ItemGroup>
<None Update="Resources\GeoLite2-City.mmdb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties properties_4launchsettings_1json__JsonSchema="" />
+20 -6
View File
@@ -7,7 +7,6 @@ using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.Service.BusinessFilter;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure.Extention;
using LogDashboard;
using MassTransit;
using MassTransit.NewIdProviders;
using Microsoft.AspNetCore.Builder;
@@ -37,6 +36,11 @@ var config = new ConfigurationBuilder()
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
var openSwaggerStr = config["ASPNETCORE_OpenSwagger"];
var isOpenSwagger= openSwaggerStr == null|| openSwaggerStr?.ToLower()=="true";
if (string.IsNullOrWhiteSpace(enviromentName))
{
@@ -111,8 +115,13 @@ builder.Services.AddAutoMapperSetup();
builder.Services.AddEFSetup(_configuration, enviromentName);
//Http 响应压缩
builder.Services.AddResponseCompressionSetup();
//Swagger Api 文档
builder.Services.AddSwaggerSetup();
if (isOpenSwagger)
{
//Swagger Api 文档
builder.Services.AddSwaggerSetup();
}
//JWT Token 验证
builder.Services.AddJWTAuthSetup(_configuration);
@@ -126,7 +135,7 @@ builder.Services.AddFusionCache();
builder.Services.AddhangfireSetup(_configuration);
//Serilog 日志可视化 LogDashboard日志
builder.Services.AddLogDashboardSetup();
//builder.Services.AddLogDashboardSetup();
//Dicom影像渲染图片 跨平台
builder.Services.AddDicomSetup();
@@ -211,13 +220,18 @@ app.UseResponseCompression();
app.UseStaticFiles();
//LogDashboard
app.UseLogDashboard("/LogDashboard");
//app.UseLogDashboard("/LogDashboard");
//hangfire
app.UseHangfireConfig(env);
// Swagger
SwaggerSetup.Configure(app, env);
if (isOpenSwagger)
{
SwaggerSetup.Configure(app, env);
}
//serilog 记录请求的用户信息
app.UseSerilogConfig(env);
@@ -20,7 +20,8 @@
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Test_IRC"
"ASPNETCORE_ENVIRONMENT": "Test_IRC",
"ASPNETCORE_OpenSwagger": "true"
},
"applicationUrl": "http://localhost:6100"
},
Binary file not shown.

After

Width:  |  Height:  |  Size: 73 MiB

@@ -1,15 +1,15 @@
using LogDashboard;
using LogDashboard.Authorization;
//using LogDashboard;
//using LogDashboard.Authorization;
namespace IRaCIS.Core.API.Filter
{
//namespace IRaCIS.Core.API.Filter
//{
public class LogDashBoardAuthFilter : ILogDashboardAuthorizationFilter
{
//在此可以利用 本系统的UerTypeEnum 判断
public bool Authorization(LogDashboardContext context)
{
return context.HttpContext.User.Identity.IsAuthenticated;
}
}
}
// public class LogDashBoardAuthFilter : ILogDashboardAuthorizationFilter
// {
// //在此可以利用 本系统的UerTypeEnum 判断
// public bool Authorization(LogDashboardContext context)
// {
// return context.HttpContext.User.Identity.IsAuthenticated;
// }
// }
//}
@@ -1,25 +1,25 @@
using LogDashboard;
using Microsoft.Extensions.DependencyInjection;
//using LogDashboard;
//using Microsoft.Extensions.DependencyInjection;
namespace IRaCIS.Core.API
{
public static class LogDashboardSetup
{
public static void AddLogDashboardSetup(this IServiceCollection services)
{
//IIS 配置虚拟路径部署,会出现IIS静态文件404
services.AddLogDashboard(opt =>
{
//opt.PathMatch = "/api/LogDashboard";
opt.PathMatch = "/LogDashboard";
//namespace IRaCIS.Core.API
//{
// public static class LogDashboardSetup
// {
// public static void AddLogDashboardSetup(this IServiceCollection services)
// {
// //IIS 配置虚拟路径部署,会出现IIS静态文件404
// services.AddLogDashboard(opt =>
// {
// //opt.PathMatch = "/api/LogDashboard";
// opt.PathMatch = "/LogDashboard";
//opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
// //opt.AddAuthorizationFilter(new LogDashboardBasicAuthFilter("admin", "zhizhun2018"));
//opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
// //opt.AddAuthorizationFilter(new LogDashBoardAuthFilter());
});
// });
}
}
}
// }
// }
//}
@@ -16,27 +16,30 @@ namespace IRaCIS.Core.API;
public enum SwaggerVersion
{
[Description("医生模块")]
[Description("文件记录(FileRecord)")]
FileRecord = -1,
[Description("医生模块(Reviewer)")]
Reviewer = 1,
[Description("项目模块")]
[Description("项目模块(Trial)")]
Trial = 2,
[Description("入组模块")]
[Description("入组模块(Enroll)")]
Enroll = 3,
[Description("工作量模块")]
[Description("工作量模块(Workload)")]
Workload = 4,
[Description("通用信息获取")]
[Description("通用信息获取(Common)")]
Common = 5,
[Description("机构信息模块")]
[Description("机构信息模块(Institution)")]
Institution = 6,
[Description("统计模块")]
[Description("统计模块(DashboardStatistics)")]
DashboardStatistics = 7,
[Description("财务模块")]
[Description("财务模块(Financial)")]
Financial = 8,
[Description("管理模块")]
[Description("管理模块(Management)")]
Management =9,
[Description("影像模块")]
[Description("影像模块(Image)")]
Image =10,
[Description("读片模块")]
[Description("读片模块(Reading)")]
Reading =11
};
+2 -2
View File
@@ -7,8 +7,8 @@
}
},
"ConnectionStrings": {
"RemoteNew": "Server=47.117.164.182,1434;Database=Event_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=47.117.164.182,1434;Database=Event_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
"RemoteNew": "Server=101.132.253.119,1435;Database=irc_Prpd_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
"Hangfire": "Server=101.132.253.119,1435;Database=irc_Hangfire_bak;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
},
"ObjectStoreService": {
"ObjectStoreUse": "AliyunOSS",
+2 -1
View File
@@ -43,7 +43,7 @@
"OpenLoginLimit": true,
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 360,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": false,
@@ -61,6 +61,7 @@
"FromName": "irc",
"AuthorizationCode": "ExtImg@2022",
"SiteUrl": "http://irc.extimaging.com/login",
"SystemShortName": "IRC",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
+5 -2
View File
@@ -23,9 +23,11 @@
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
"BucketName": "zy-irc-test-store",
"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
//"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
"ViewEndpoint": "https://zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com",
"Region": "oss-cn-shanghai",
"DurationSeconds": 7200
"DurationSeconds": 7200,
"PreviewEndpoint": "https://test-oss.test.extimaging.com"
},
"MinIO": {
"EndPoint": "hir-oss.test.extimaging.com",
@@ -81,6 +83,7 @@
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.test.extimaging.com/login",
"SystemShortName": "IRC",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
@@ -67,6 +67,7 @@
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
@@ -75,6 +75,7 @@
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
@@ -73,6 +73,7 @@
"FromName": "LiLi",
"AuthorizationCode": "Q#669869497420ul",
"SystemShortName": "LiLi",
"OrganizationName": "Elevate Imaging",
"OrganizationNameCN": "Elevate Imaging",
"CompanyName": "Elevate Imaging Inc.",
+3 -1
View File
@@ -62,7 +62,7 @@
"LoginMaxFailCount": 5,
"LoginFailLockMinutes": 30,
"AutoLoginOutMinutes": 60,
"AutoLoginOutMinutes": 120,
"OpenLoginMFA": false,
@@ -80,6 +80,8 @@
"FromName": "UAT_IRC",
"AuthorizationCode": "SHzyyl2021",
"SiteUrl": "http://irc.uat.extimaging.com/login",
"SystemShortName": "IRC",
"OrganizationName": "Extlmaging",
"OrganizationNameCN": "Extlmaging",
"CompanyName": "Extensive Imaging",
+1 -1
View File
@@ -3,7 +3,7 @@
"SecurityKey": "ShangHaiZhanYing_SecurityKey_SHzyyl@2021",
"Issuer": "Extimaging",
"Audience": "EICS",
"TokenExpireDays": "7"
"TokenExpireMinute": "10080"//7天
},
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
+1 -1
View File
@@ -23,7 +23,7 @@ namespace IRaCIS.Core.Application.Auth
/// <summary>
/// 过期时间
/// </summary>
public int TokenExpireDays { get; set; }
public int TokenExpireMinute { get; set; }
//public Dictionary<string, object> Claims { get; set; }
+17 -1
View File
@@ -9,6 +9,8 @@ namespace IRaCIS.Core.Application.Auth
public interface ITokenService
{
string GetToken(UserTokenInfo user);
bool IsTokenExpired(string token);
}
@@ -47,13 +49,27 @@ namespace IRaCIS.Core.Application.Auth
signingCredentials: _jwtSetting.Credentials,
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddDays(_jwtSetting.TokenExpireDays)
expires: DateTime.Now.AddMinutes(_jwtSetting.TokenExpireMinute)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
return jwtToken;
}
public bool IsTokenExpired(string token)
{
var handler = new JwtSecurityTokenHandler();
try
{
var jwtToken = handler.ReadJwtToken(token);
return jwtToken.ValidTo < DateTime.UtcNow;
}
catch
{
return true; // 无效 Token 也视为已过期
}
}
}
@@ -51,6 +51,8 @@ public class SystemEmailSendConfig
public string SiteUrl { get; set; } = string.Empty;
public string SystemShortName { get; set; } = string.Empty;
public string OrganizationName { get; set; } = string.Empty;
public string OrganizationNameCN { get; set; } = string.Empty;
@@ -300,6 +300,17 @@ public static class ExcelExportHelper
{
public Guid Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
if (obj is not ColumItem other) return false;
return Id == other.Id && Name == other.Name;
}
public override int GetHashCode()
{
return HashCode.Combine(Id, Name);
}
}
public List<string> ColumnIdList => ColumnIdNameList == null ? new List<string>() : ColumnIdNameList.Select(t => t.Id.ToString()).ToList();
@@ -0,0 +1,42 @@
using IRaCIS.Core.Domain.Models;
using MaxMind.GeoIP2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Helper
{
public static class IPCityHelper
{
public static string GetCityResponse(string ip)
{
var path = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "GeoLite2-City.mmdb");
try
{
using (var reader = new DatabaseReader(path))
{
var city = reader.City(ip);
//Console.WriteLine(city.Country.IsoCode); // 'US' 'CN'
//Console.WriteLine(city.Country.Name); // 'United States' 'China'
////Console.WriteLine(city.Country.Names["zh-CN"]); // '美国'
//Console.WriteLine(city.MostSpecificSubdivision.Name); // 'Minnesota' 'Hubei'
//Console.WriteLine(city.City.Name); // 'Minneapolis' 'WUHan'
return $"{city.Country.Name} | {city.MostSpecificSubdivision.Name} | {city.City.Name}";
}
}
catch (Exception ex)
{
return $"UN | UN | {ip}";
}
}
}
}
+366 -8
View File
@@ -1,5 +1,6 @@
using AlibabaCloud.SDK.Sts20150401;
using Aliyun.OSS;
using Aliyun.OSS.Common;
using Amazon;
using Amazon.Runtime;
using Amazon.S3;
@@ -9,9 +10,12 @@ using Amazon.SecurityToken.Model;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
using MassTransit;
using MassTransit.Caching.Internals;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel;
using Minio.DataModel.Args;
using Minio.Exceptions;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
@@ -59,7 +63,7 @@ public class AliyunOSSOptions
public int DurationSeconds { get; set; }
public string PreviewEndpoint { get; set; }
}
@@ -105,6 +109,7 @@ public class AliyunOSSTempToken
public string SecurityToken { get; set; }
public DateTime Expiration { get; set; }
public string PreviewEndpoint { get; set; }
}
@@ -143,11 +148,17 @@ public interface IOSSService
public Task<string> GetSignedUrl(string ossRelativePath);
public Task DeleteFromPrefix(string prefix);
public Task DeleteFromPrefix(string prefix, bool isCache = false);
public Task DeleteObjects(List<string> objectKeys);
List<string> GetRootFolderNames();
public ObjectStoreDTO GetObjectStoreTempToken();
public Task MoveObject(string sourcePath, string destPath, bool overwrite = true);
public Task<long> GetObjectSizeAsync(string sourcePath);
}
@@ -528,6 +539,185 @@ public class OSSService : IOSSService
}
/// <summary>
/// 移动OSS文件到新路径
/// </summary>
/// <param name="sourcePath">原文件路径(格式:bucket/key</param>
/// <param name="destPath">新文件路径(格式:bucket/key</param>
/// <param name="overwrite">是否覆盖已存在的目标文件(默认true</param>
public async Task MoveObject(string sourcePath, string destPath, bool overwrite = true)
{
GetObjectStoreTempToken();
switch (ObjectStoreServiceOptions.ObjectStoreUse)
{
case "AliyunOSS":
#region
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var client = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
if (sourcePath.StartsWith("/"))
{
sourcePath = sourcePath.Substring(1);
}
if (destPath.StartsWith("/"))
{
destPath = destPath.Substring(1);
}
var sourceBucket = aliConfig.BucketName;
var sourceKey = sourcePath;
var destBucket = aliConfig.BucketName;
var destKey = destPath;
try
{
// 检查目标是否存在(当不允许覆盖时)
if (!overwrite && client.DoesObjectExist(destBucket, destKey))
{
throw new InvalidOperationException("File Exist");
}
//var copyRequest = new Aliyun.OSS.CopyObjectRequest(sourceBucket, sourceKey, sourceBucket, destKey);
//var result = client.CopyObject(copyRequest);
//// 2. 删除原文件(可选,根据是否需要保留原文件)
//client.DeleteObject(sourceBucket, sourceKey);
// 执行复制
var copyRequestAli = new Aliyun.OSS.CopyObjectRequest(
sourceBucket, sourceKey,
destBucket, destKey);
// 保持原文件元数据
copyRequestAli.NewObjectMetadata = new ObjectMetadata
{
ContentType = client.GetObjectMetadata(sourceBucket, sourceKey).ContentType
};
var result = client.CopyObject(copyRequestAli);
// 删除原文件(仅在复制成功后)
client.DeleteObject(sourceBucket, sourceKey);
}
catch (OssException ex)
{
throw new Exception($"[{ex.ErrorCode}] {ex.Message}", ex);
}
#endregion
break;
case "MinIO":
#region MinIO
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient()
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
.WithSSL(minIOConfig.UseSSL)
.Build();
// 定义源路径和目标路径
string destinationKey = "b路径/文件名";
try
{
// 1. 复制文件到新路径[2,5](@ref)
using (var memoryStream = new MemoryStream())
{
// 下载源文件流
await minioClient.GetObjectAsync(new GetObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(sourcePath)
.WithCallbackStream(stream => stream.CopyTo(memoryStream)));
memoryStream.Position = 0; // 重置流位置
// 上传到新路径
await minioClient.PutObjectAsync(new PutObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(destinationKey)
.WithStreamData(memoryStream)
.WithObjectSize(memoryStream.Length));
}
// 2. 删除原文件[1,6](@ref)
await minioClient.RemoveObjectAsync(new RemoveObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(sourcePath));
}
catch (MinioException ex)
{
// 处理异常(例如:记录日志或抛出)
throw new Exception();
}
#endregion
break;
case "AWS":
#region AWS
var awsConfig = ObjectStoreServiceOptions.AWS;
var credentials = new SessionAWSCredentials(
AWSTempToken.AccessKeyId,
AWSTempToken.SecretAccessKey,
AWSTempToken.SessionToken
);
var clientConfig = new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1,
UseHttp = true,
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
// 定义原路径和目标路径
// 1. 复制对象到新路径
var copyRequest = new Amazon.S3.Model.CopyObjectRequest
{
SourceBucket = awsConfig.BucketName,
SourceKey = sourcePath,
DestinationBucket = awsConfig.BucketName,
DestinationKey = destPath
};
try
{
// 执行复制操作
await amazonS3Client.CopyObjectAsync(copyRequest);
// 2. 删除原对象
var deleteRequest = new Amazon.S3.Model.DeleteObjectRequest
{
BucketName = awsConfig.BucketName,
Key = sourcePath
};
await amazonS3Client.DeleteObjectAsync(deleteRequest);
}
catch (AmazonS3Exception ex)
{
Console.WriteLine($"ERROR: {ex.Message}");
// 可根据异常类型细化处理(如文件不存在、权限问题等)
}
#endregion
break;
default:
throw new BusinessValidationFailedException("ERROR");
}
}
/// <summary>
/// 获取所有根目录名称
/// </summary>
@@ -550,9 +740,9 @@ public class OSSService : IOSSService
do
{
// 列出根目录下的对象和文件夹
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
{
MaxKeys = 1000,
Marker = nextMarker,
Delimiter = "/" // 使用分隔符来模拟文件夹
@@ -582,7 +772,7 @@ public class OSSService : IOSSService
/// </summary>
/// <param name="prefix"></param>
/// <returns></returns>
public async Task DeleteFromPrefix(string prefix)
public async Task DeleteFromPrefix(string prefix, bool isCache = false)
{
GetObjectStoreTempToken();
@@ -592,6 +782,21 @@ public class OSSService : IOSSService
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
var bucketName = string.Empty;
if (isCache)
{
Uri uri = new Uri(aliConfig.ViewEndpoint);
string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
string[] parts = host.Split('.');
bucketName = parts[0];
}
else
{
bucketName = aliConfig.BucketName;
}
try
{
@@ -600,7 +805,7 @@ public class OSSService : IOSSService
do
{
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(bucketName)
{
Prefix = prefix,
MaxKeys = 1000,
@@ -612,7 +817,7 @@ public class OSSService : IOSSService
// 删除获取到的文件
if (keys.Count > 0)
{
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, keys, false));
}
// 设置 NextMarker 以获取下一页的数据
@@ -669,7 +874,6 @@ public class OSSService : IOSSService
var awsConfig = ObjectStoreServiceOptions.AWS;
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
@@ -721,6 +925,159 @@ public class OSSService : IOSSService
}
}
public async Task DeleteObjects(List<string> objectKeys)
{
GetObjectStoreTempToken();
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
if (objectKeys.Count > 0)
{
var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, objectKeys, false));
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.Build();
if (objectKeys.Count > 0)
{
var objArgs = new RemoveObjectsArgs()
.WithBucket(minIOConfig.BucketName)
.WithObjects(objectKeys);
// 删除对象
await minioClient.RemoveObjectsAsync(objArgs);
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var awsConfig = ObjectStoreServiceOptions.AWS;
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
//提供awsEndPoint(域名)进行访问配置
var clientConfig = new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1,
UseHttp = true,
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
if (objectKeys.Count > 0)
{
// 准备删除请求
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
{
BucketName = awsConfig.BucketName,
Objects = objectKeys.Select(t => new KeyVersion() { Key = t }).ToList()
};
// 批量删除对象
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
}
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
private bool isFirstCall = true;
public async Task<long> GetObjectSizeAsync(string sourcePath)
{
if (isFirstCall)
{
GetObjectStoreTempToken();
isFirstCall = false;
}
var objectkey = sourcePath.Trim('/');
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, objectkey);
long fileSize = metadata.ContentLength; // 文件大小(字节)
return fileSize;
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
{
var minIOConfig = ObjectStoreServiceOptions.MinIO;
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
.Build();
var stat = await minioClient.StatObjectAsync(new Minio.DataModel.Args.StatObjectArgs()
.WithBucket(minIOConfig.BucketName)
.WithObject(objectkey));
return stat.Size; // 文件大小(字节)
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
var awsConfig = ObjectStoreServiceOptions.AWS;
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
//提供awsEndPoint(域名)进行访问配置
var clientConfig = new AmazonS3Config
{
RegionEndpoint = RegionEndpoint.USEast1,
UseHttp = true,
};
var request = new Amazon.S3.Model.GetObjectMetadataRequest
{
BucketName = awsConfig.BucketName,
Key = objectkey
};
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
var response = await amazonS3Client.GetObjectMetadataAsync(request);
long fileSize = response.ContentLength; // 文件大小(字节)
return fileSize;
}
else
{
throw new BusinessValidationFailedException("未定义的存储介质类型");
}
}
public ObjectStoreDTO GetObjectStoreTempToken()
{
@@ -764,6 +1121,7 @@ public class OSSService : IOSSService
BucketName = ossOptions.BucketName,
EndPoint = ossOptions.EndPoint,
ViewEndpoint = ossOptions.ViewEndpoint,
PreviewEndpoint = ossOptions.PreviewEndpoint
};
@@ -15,14 +15,20 @@ public static class ImageHelper
fileStorePath = fileStorePath ?? filePath + ".preview.jpeg";
using (var image = SixLabors.ImageSharp.Image.Load(filePath))
{
// 读取 DICOM 文件
var dicomImage = new DicomImage(filePath);
// 渲染 DICOM 图像到 ImageSharp 格式
using (var image = dicomImage.RenderImage().AsSharpImage())
{
// 生成缩略图(调整大小)
image.Mutate(x => x.Resize(500, 500));
image.Save(fileStorePath);
// 保存缩略图为 JPEG
image.Save(fileStorePath, new JpegEncoder());
}
}
@@ -37,31 +37,32 @@
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" />
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
<PackageReference Include="AWSSDK.S3" Version="3.7.405" />
<PackageReference Include="DocX" Version="3.0.1" />
<PackageReference Include="DocX" Version="4.0.25105.5786" />
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
<PackageReference Include="Hangfire.Core" Version="1.8.14" />
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
<PackageReference Include="fo-dicom" Version="5.1.3" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
<PackageReference Include="fo-dicom.Codecs" Version="5.15.1" />
<PackageReference Include="fo-dicom" Version="5.2.1" />
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
<PackageReference Include="fo-dicom.Codecs" Version="5.16.0" />
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
<PackageReference Include="MailKit" Version="4.7.1.1" />
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
<PackageReference Include="MimeKit" Version="4.7.1" />
<PackageReference Include="MiniExcel" Version="1.34.2" />
<PackageReference Include="Minio" Version="6.0.3" />
<PackageReference Include="MiniWord" Version="0.8.0" />
<PackageReference Include="MiniWord" Version="0.9.2" />
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="NPOI" Version="2.7.1" />
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
<PackageReference Include="RestSharp" Version="112.1.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
<PackageReference Include="ZiggyCreatures.FusionCache" Version="1.4.0" />
</ItemGroup>
File diff suppressed because it is too large Load Diff
@@ -4,6 +4,7 @@ using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Domain.Share;
using MassTransit;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Text;
@@ -21,6 +22,8 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
public IStringLocalizer _localizer { get; set; }
private readonly SystemEmailSendConfig _systemEmailConfig;
/// <summary>
/// 构造函数注入
/// </summary>
@@ -28,7 +31,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
public ConsistencyCheckConsumer(IRepository<DicomStudy> studyRepository, IUserInfo userInfo,
IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<TrialSite> trialSiteRepository, IRepository<NoneDicomStudy> noneDicomStudyRepository,
IMapper mapper, IStringLocalizer localizer)
IMapper mapper, IStringLocalizer localizer, IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig)
{
_noneDicomStudyRepository = noneDicomStudyRepository;
_studyRepository = studyRepository;
@@ -38,6 +41,8 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
_trialSiteRepository = trialSiteRepository;
_mapper = mapper;
_localizer = localizer;
_systemEmailConfig = systemEmailConfig.CurrentValue;
}
@@ -186,7 +191,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
{
dialogMsg.AppendLine($"<br/>");
//---核对EDC数据,完全一致, 审核通过
dialogMsg.AppendLine(_localizer["ConsistencyVerification_EDCA"]);
dialogMsg.AppendLine(_localizer["ConsistencyVerification_EDCA", _systemEmailConfig.SystemShortName]);
// dialogMsg.AppendLine(@$"<br>说明:为高效解决/处理以上全部质疑问题,麻烦您准确核实实际影像检查情况。请注意影像日期与实际检查的日期可能会不一致,部分检查(如PET -CT)可能同时存在多种模态影像。准确核实后,请回复该访视正确的影像检查情况。");
@@ -196,7 +201,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
dbSV.CheckChallengeState = CheckChanllengeTypeEnum.Closed;
//---核对EDC数据,完全一致
dbSV.CheckResult = _localizer["ConsistencyVerification_EDCB"];
dbSV.CheckResult = _localizer["ConsistencyVerification_EDCB", _systemEmailConfig.SystemShortName];
//---自动核查通过
dbSV.ManualPassReason = _localizer["ConsistencyVerification_Auto"];
@@ -224,7 +229,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
{
num++;
//影像检查(EDC 缺少) ConsistencyVerification_EdcL
dialogMsg.AppendLine($"<br/><div style='text-indent: 20px;'>{num}. {_localizer["ConsistencyVerification_EdcL", item.StudyDate, item.Modality]}</div>");
dialogMsg.AppendLine($"<br/><div style='text-indent: 20px;'>{num}. {_localizer["ConsistencyVerification_EdcL", item.StudyDate, item.Modality, _systemEmailConfig.SystemShortName]}</div>");
}
@@ -232,15 +237,15 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
{
num++;
// 影像检查(IRC 缺少)
dialogMsg.AppendLine($"<br/><div style='text-indent: 20px;'>{num}. {_localizer["ConsistencyVerification_IrcLi", item.StudyDate, item.Modality]}</div>");
dialogMsg.AppendLine($"<br/><div style='text-indent: 20px;'>{num}. {_localizer["ConsistencyVerification_IrcLi", item.StudyDate, item.Modality, _systemEmailConfig.SystemShortName]}</div>");
}
dialogMsg.AppendLine($"<br/>");
dialogMsg.AppendLine(@$"<div>{_localizer["ConsistencyVerification_Desc"]}</div>");
dbSV.CheckResult = _localizer["ConsistencyVerification_Conf"] +
String.Join(" | ", dbExceptExcel.Select(t => $"{_localizer["ConsistencyVerification_EdcL", t.StudyDate, t.Modality]}")) + " | "
+ String.Join(" | ", excelExceptDB.Select(t => $"{_localizer["ConsistencyVerification_IrcLi", t.StudyDate, t.Modality]}"));
dbSV.CheckResult =
String.Join(" | ", dbExceptExcel.Select(t => $"{_localizer["ConsistencyVerification_EdcL", t.StudyDate, t.Modality, _systemEmailConfig.SystemShortName]}")) + " | "
+ String.Join(" | ", excelExceptDB.Select(t => $"{_localizer["ConsistencyVerification_IrcLi", t.StudyDate, t.Modality, _systemEmailConfig.SystemShortName]}"));
//新增一致性核查质疑记录
@@ -339,6 +339,16 @@ namespace IRaCIS.Core.Application.ViewModel
public int UrgentCount { get; set; }
/// <summary>
/// 是否存在未处理的反馈
/// </summary>
public bool IsExistUnprocessedFeedback
{
get
{
return UnReadCanReadTaskList.Any(t => t.IsExistUnprocessedFeedback);
}
}
public List<IRUnreadTaskView> UnReadCanReadTaskList { get; set; } = new List<IRUnreadTaskView>();
@@ -355,6 +365,11 @@ namespace IRaCIS.Core.Application.ViewModel
/// 是否是一致性分析产生
/// </summary>
public bool IsAnalysisCreate { get; set; }
/// <summary>
/// 是否存在未处理的反馈
/// </summary>
public bool IsExistUnprocessedFeedback { get; set; }
public bool IsUrgent { get; set; }
@@ -4,10 +4,12 @@
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using DocumentFormat.OpenXml.Spreadsheet;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
@@ -1055,6 +1055,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
ReadingCategory = u.ReadingCategory,
IsAnalysisCreate = u.IsAnalysisCreate,
ArmEnum = u.ArmEnum,
IsExistUnprocessedFeedback=u.UserFeedBackList.Any(t => t.State ==0),
TrialReadingCriterionId = u.TrialReadingCriterionId,
IsNeedClinicalDataSign = u.IsNeedClinicalDataSign,
IsClinicalDataSign = u.IsClinicalDataSign,
@@ -1085,6 +1086,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
ReadingCategory = u.ReadingCategory,
IsAnalysisCreate = u.IsAnalysisCreate,
ArmEnum = u.ArmEnum,
IsExistUnprocessedFeedback = u.UserFeedBackList.Any(t => t.State == 0),
TrialReadingCriterionId = u.TrialReadingCriterionId,
IsNeedClinicalDataSign = u.IsNeedClinicalDataSign,
IsClinicalDataSign = u.IsClinicalDataSign,
@@ -1194,6 +1196,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
ReadingCategory = u.ReadingCategory,
IsAnalysisCreate = u.IsAnalysisCreate,
ArmEnum = u.ArmEnum,
IsExistUnprocessedFeedback = u.UserFeedBackList.Any(t => t.State == 0),
TrialReadingCriterionId = u.TrialReadingCriterionId,
IsNeedClinicalDataSign = u.IsNeedClinicalDataSign,
IsClinicalDataSign = u.IsClinicalDataSign,
@@ -2549,6 +2552,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
//回退后,回退状态恢复
sv.RequestBackState = RequestBackStateEnum.NotRequest;
sv.ImageBackState = ImageBackStateEnum.None;
sv.IsCheckBack = false;
sv.CheckBackTime = null;
sv.CheckState = CheckStateEnum.None;
@@ -96,6 +96,8 @@ namespace IRaCIS.Core.Application.ViewModel
public int State { get; set; }
public Guid? PublishLogId { get; set; }
public List<BatchAddInternationalizationDto> AddList { get; set; }
}
@@ -112,6 +114,8 @@ namespace IRaCIS.Core.Application.ViewModel
public int? State { get; set; }
public int InternationalizationType { get; set; }
}
public class BatchAddInternationalizationDto : BatchInternationalizationDto
@@ -121,6 +125,9 @@ namespace IRaCIS.Core.Application.ViewModel
public class InternationalizationSimpleDto : BatchInternationalizationDto
{
public string Version { get; set; }
public DateTime CreateTime { get; set; }
}
@@ -4,6 +4,7 @@ using IRaCIS.Application.Interfaces;
using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
@@ -81,7 +82,7 @@ namespace IRaCIS.Core.Application.Service.Common
.WhereIf(param.IsDeleted != null, t => t.IsDeleted == param.IsDeleted)
.WhereIf(!string.IsNullOrWhiteSpace(param.OrganizationName),
t => t.UserRole.OrganizationName.Contains(param.OrganizationName))
t => t.UserRole.IdentityUser.OrganizationName.Contains(param.OrganizationName))
.WhereIf(!string.IsNullOrWhiteSpace(param.UserRealName),
t => (t.UserRole.FullName).Contains(param.UserRealName))
.Select(t => new TrialMaintenanceDTO()
@@ -1613,8 +1614,52 @@ namespace IRaCIS.Core.Application.Service.Common
}
public List<T> DealOncologyResult<T>(IRepository<ReadingOncologyTaskInfo> _oncologyRepository, bool isOncology, List<T> list) where T : CommonEvaluationExport
{
if (isOncology)
{
var subjectIdList = list.Select(t => t.SubjectId).Distinct().ToList();
//已阅片完的肿瘤学结果
var oncologyResultList = _oncologyRepository.Where(t => subjectIdList.Contains(t.OncologyVisitTask.SubjectId)
&& t.OncologyVisitTask.IsAnalysisCreate == false && t.OncologyVisitTask.ReadingTaskState == ReadingTaskState.HaveSigned && t.OncologyVisitTask.TaskState == TaskState.Effect)
.Select(t => new { t.OncologyVisitTask.SubjectId, OncologyVisitTaskNum = t.OncologyVisitTask.VisitTaskNum, OncologyUserName = t.OncologyVisitTask.DoctorUser.UserName, t.VisitTask.VisitTaskNum, t.VisitTaskId, t.EvaluationReason, t.EvaluationResult })
.ToList();
foreach (var subjectOncologyResult in oncologyResultList.GroupBy(t => t.SubjectId))
{
//最后已完成的肿瘤学任务号
var lastOncologyVisitTaskNum = subjectOncologyResult.OrderByDescending(t => t.OncologyVisitTaskNum).FirstOrDefault().OncologyVisitTaskNum;
//需要填充的肿瘤学结果
var subjectOncologyList = subjectOncologyResult.Where(t => t.OncologyVisitTaskNum == lastOncologyVisitTaskNum).ToList();
foreach (var subjectOncology in subjectOncologyList)
{
foreach (var item in list)
{
if (item.SubjectId == subjectOncology.SubjectId && item.VisitTaskNum == subjectOncology.VisitTaskNum)
{
item.OncologyReason = subjectOncology.EvaluationReason;
item.OncologyResult = subjectOncology.EvaluationResult;
item.OncologyUserName = subjectOncology.OncologyUserName;
}
}
}
}
}
return list;
}
public List<T> DealJudgeMark<T>(ArbitrationRule arbitrationRule, bool isGlobalReading, IEnumerable<T> list) where T : CommonEvaluationExport
{
//处理访视任务的裁判标记
@@ -2172,12 +2217,13 @@ namespace IRaCIS.Core.Application.Service.Common
[FromServices] IDictionaryService _dictionaryService,
[FromServices] IRepository<ReadingQuestionTrial> _trialReadingQuestionRepository,
[FromServices] IRepository<ReadingTableQuestionTrial> _trialReadingTableQuestionRepository,
[FromServices] IRepository<ReadingOncologyTaskInfo> _oncologyRepository,
[FromServices] IRepository<Trial> _trialRepository)
{
var trialId = inQuery.TrialId;
var trialReadingCriterionId = inQuery.TrialReadingCriterionId;
//每次查询必须是单标准的
var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionGroup, t.IsGlobalReading, t.IsArbitrationReading, t.CriterionName, t.ArbitrationRule }).FirstNotNullAsync();
var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionGroup, t.IsGlobalReading, t.IsArbitrationReading, t.IsOncologyReading, t.CriterionName, t.ArbitrationRule }).FirstNotNullAsync();
var query = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
@@ -2218,6 +2264,16 @@ namespace IRaCIS.Core.Application.Service.Common
//仲裁阅片 才有裁判阅片明细表 同时要把模板里面的三列给去掉
removeColumnIndexList = new List<int>() { 6, 7, 8 };
}
//阅片结果表 和阅片结果明细表 没有肿瘤学的时候需要移除肿瘤学三个字段
if (!criterion.IsOncologyReading)
{
if (inQuery.ReadingExportType == ExportResult.TableOfAssessmentResults || inQuery.ReadingExportType == ExportResult.DetailedTableOfAssessmentResults)
{
removeColumnIndexList = removeColumnIndexList.Union(new List<int>() { 9, 10, 11 }).ToList();
}
}
}
var export_Template = StaticData.Export.CommonReading_Export;
@@ -2400,7 +2456,7 @@ namespace IRaCIS.Core.Application.Service.Common
{
Id = Guid.Empty,
Name = (t.QuestionType == QuestionType.ExistDisease || t.QuestionType == QuestionType.Tumor) ? (_userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估") : t.QuestionName
}).ToList();
}).Distinct().ToList();
@@ -2413,7 +2469,7 @@ namespace IRaCIS.Core.Application.Service.Common
{
Id = Guid.Empty,
Name = (t.QuestionType == QuestionType.ExistDisease || t.QuestionType == QuestionType.ImgOncology) ? (_userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估") : t.QuestionName
}).ToList();
}).Distinct().ToList();
}
else if (criterion.CriterionType == CriterionType.PCWG3)
@@ -2422,7 +2478,7 @@ namespace IRaCIS.Core.Application.Service.Common
{
Id = Guid.Empty,
Name = t.QuestionName
}).ToList();
}).Distinct().ToList();
}
@@ -2636,7 +2692,7 @@ namespace IRaCIS.Core.Application.Service.Common
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionId = Guid.Empty, QuestionName = _userInfo.IsEn_Us ? "Table Name" : "表格名称", QuestionValue = firstLessionAnser.TableName });
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId=t.TableQuesionId, QuestionName = t.TableName + "_" + t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, QuestionName = t.TableName + "_" + t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
//有三部分组成 外层问题+ 固定列表格名称 + 动态的表格问题
dynamicLessionInfoList = item.QuestionAnswerList.Union(addLessionInfoList).Union(dynamicPartialLessionInfoList).ToList();
@@ -2678,7 +2734,7 @@ namespace IRaCIS.Core.Application.Service.Common
{
AutoColumnTitleRowIndex = 2,
AutoColumnStartIndex = 6,
TempalteLastColumnIndex = 8,
TempalteLastColumnIndex = 11,
DynamicItemDicName = "TranslateDicName",
DynamicItemValueName = "QuestionValue",
DynamicItemTitleName = "QuestionName",
@@ -2731,7 +2787,8 @@ namespace IRaCIS.Core.Application.Service.Common
#region
if (inQuery.ReadingExportType == ExportResult.DetailedTableOfAdjudicationResults)
//裁判阅片明细表
if (export_Template == StaticData.Export.CommonJudgeReadingDetail_Export)
{
//R1 R2 两个人的访视都阅片完成了才可以,去除只有一个人阅片完成的访视
//找到只有一个人阅片的受试者 和访视
@@ -2747,7 +2804,10 @@ namespace IRaCIS.Core.Application.Service.Common
//处理裁判标记
list = DealJudgeMark(criterion.ArbitrationRule, criterion.IsGlobalReading, list);
//裁判阅片明细表
//处理肿瘤学结果
list = DealOncologyResult(_oncologyRepository, criterion.IsOncologyReading, list);
//裁判阅片明细表 处理完标记后处理
if (export_Template == StaticData.Export.CommonJudgeReadingDetail_Export)
{
//裁判产生标记为空的数据过滤掉
@@ -94,7 +94,7 @@ namespace IRaCIS.Core.Application.Service
#region DTO
public class DoctorDownloadInfo
{
public Guid Id { get; set; }
public Guid? Id { get; set; }
public string Name { get; set; }
public string ReviewerCode { get; set; }
@@ -111,7 +111,7 @@ namespace IRaCIS.Core.Application.Service
{
public int Language { get; set; }
public List<Guid> DoctorIdList { get; set; }
public List<Guid?> DoctorIdList { get; set; }
}
public class GetDoctoreAttachPathCommand
@@ -45,6 +45,11 @@ namespace IRaCIS.Core.Application.Service
ValueCN = t.ValueCN,
FrontType = t.FrontType,
Description = t.Description,
Module = t.Module,
State = t.State,
Version = t.PublishLog.Version,
CreateTime = t.CreateTime,
InternationalizationType = t.InternationalizationType
}).ToListAsync();
await _fusionCache.SetAsync<List<InternationalizationSimpleDto>>(CacheKeys.FrontInternational, list, TimeSpan.FromDays(1));
@@ -55,7 +60,7 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 前端批量提交,后端判断不存在就添加,存在就更新
/// 前端批量提交,后端查询判断不存在就添加,存在就更新 (这里提交接口也能提交后端的标识,对后端标识进行更新)
/// </summary>
/// <returns></returns>
[AllowAnonymous]
@@ -65,7 +70,7 @@ namespace IRaCIS.Core.Application.Service
foreach (var item in batchList)
{
var find = await _internationalizationRepository.FirstOrDefaultAsync(t => t.Code == item.Code && t.Description == item.Description && t.InternationalizationType == 0);
var find = await _internationalizationRepository.FirstOrDefaultAsync(t => t.Code == item.Code && t.InternationalizationType == item.InternationalizationType);
if (find != null)
{
@@ -77,7 +82,7 @@ namespace IRaCIS.Core.Application.Service
var frontState = item.State == null ? 0 : (int)item.State;
var mapItem = _mapper.Map<Internationalization>(item);
mapItem.InternationalizationType = 0;
//mapItem.InternationalizationType = 0;
// 0 是预翻译 1是已确认 2是后端废弃
mapItem.State = frontState;
@@ -138,6 +143,7 @@ namespace IRaCIS.Core.Application.Service
mapItem.InternationalizationType = batchAdd.InternationalizationType;
mapItem.State = batchAdd.State;
mapItem.PublishLogId = batchAdd.PublishLogId;
var verifyExp1 = new EntityVerifyExp<Internationalization>()
{
@@ -7,6 +7,7 @@ using IRaCIS.Core.Infrastructure;
using MailKit;
using Medallion.Threading;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using MimeKit;
@@ -485,8 +486,6 @@ namespace IRaCIS.Core.Application.Service
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = userId, OptType = UserOptType.UpdateUserRole }, true);
}
//Site调研 用户加入项目
@@ -547,8 +546,6 @@ namespace IRaCIS.Core.Application.Service
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = userId, OptType = UserOptType.UpdateUserRole }, true);
}
@@ -563,6 +560,9 @@ namespace IRaCIS.Core.Application.Service
var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer);
//需要创建新的账户
var isNeedCreateNewUser = false;
var @lock = _distributedLockProvider.CreateLock($"UserCode");
using (await @lock.AcquireAsync())
@@ -572,6 +572,7 @@ namespace IRaCIS.Core.Application.Service
if (!isDoctorHaveAccount)
{
isNeedCreateNewUser = true;
var saveItem = new IdentityUser() { FirstName = doctor.FirstName, LastName = doctor.LastName, EMail = doctor.EMail };
@@ -582,6 +583,8 @@ namespace IRaCIS.Core.Application.Service
saveItem.IsTestUser = true;
}
saveItem.UserCeateSource = UserCeateSource.ReviewerSelect;
saveItem.TrialId = trialId;
saveItem.Code = _identityUserRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1;
@@ -673,7 +676,12 @@ namespace IRaCIS.Core.Application.Service
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig, null);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = sysUserInfo.Id, OptType = UserOptType.UpdateUserRole }, true);
//创建账号 和创建角色 一条,更新的时候才记录更新角色
if (isNeedCreateNewUser == false)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = sysUserInfo.Id, OptType = UserOptType.UpdateUserRole }, true);
}
return (sysUserInfo.Id, sysUserInfo.UserRoleList.First(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer).Id);
@@ -1,5 +1,8 @@
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
@@ -9,7 +12,11 @@ namespace IRaCIS.Core.Application.Service
/// 医生文档关联关系维护
/// </summary>
[ApiExplorerSettings(GroupName = "Reviewer")]
public class AttachmentService(IRepository<Attachment> _attachmentrepository, IRepository<Doctor> _doctorrepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IAttachmentService
public class AttachmentService(IRepository<Attachment> _attachmentrepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<Enroll> _enrollRepository,
IOSSService _oSSService,
IRepository<Doctor> _doctorrepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IAttachmentService
{
@@ -89,6 +96,150 @@ namespace IRaCIS.Core.Application.Service
return attachmentList;
}
/// <summary>
/// 获取项目医生附件
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<AttachmentDTO>> GetTrialAttachments(GetTrialAttachmentsInDto inDto)
{
var dicList=await _dictionaryRepository.Where(x => x.Parent.Code == "CertificateFileType").Select(x=>x.Code).ToListAsync();
var attachmentList = await _attachmentrepository
.Where(a =>a.Doctor.EnrollList.Any(x=>x.TrialId == inDto.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup)|| a.TrialId == inDto.TrialId)
.WhereIf(inDto.DoctorId!=null,x=>x.DoctorId==inDto.DoctorId)
.WhereIf(inDto.IsAuthorizedView != null, x => x.IsAuthorizedView == inDto.IsAuthorizedView)
.WhereIf(inDto.Type.IsNotNullOrEmpty(), x => x.Type == inDto.Type)
.WhereIf(inDto.FileName.IsNotNullOrEmpty(), x => inDto.FileName.Contains(x.FileName))
.Where(a => dicList.Contains(a.Type)||a.Type==string.Empty)
.ProjectTo<AttachmentDTO>(_mapper.ConfigurationProvider, new { TrialId = inDto.TrialId }).ToPagedListAsync(inDto);
return attachmentList;
}
/// <summary>
/// 获取医生列表
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<GetTrialDoctorListOutDto>> GetTrialDoctorList(GetTrialDoctorSelectInDto inDto)
{
var result= await _enrollRepository.Where(x => x.TrialId == inDto.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup).Select(x => x.Doctor)
.ProjectTo<GetTrialDoctorListOutDto>(_mapper.ConfigurationProvider).OrderBy(x=>x.BlindName).ToListAsync();
return result;
}
/// <summary>
/// 修改稽查状态
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> SetAuthorizedView(SetAttachmentAuthorizedView inDto)
{
await _attachmentrepository.UpdatePartialFromQueryAsync(x => inDto.Ids.Contains(x.Id), x => new Attachment() { IsAuthorizedView = inDto.IsAuthorizedView });
await _attachmentrepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 删除
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> DeleteAttachment(DeleteAttachment inDto)
{
var success = await _attachmentrepository.DeleteFromQueryAsync(t => inDto.Ids.Contains(t.Id));
await _attachmentrepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 上传项目医生
/// </summary>
/// <param name="attachmentList"></param>
/// <returns></returns>
[HttpPost]
public async Task<IEnumerable<AttachmentDTO>> SaveTrialAttachments(IEnumerable<AttachmentDTO> attachmentList)
{
foreach (var item in attachmentList)
{
if (item.DoctorId != null)
{
await _attachmentrepository.BatchDeleteNoTrackingAsync(a => a.DoctorId == item.DoctorId && a.Type == item.Type);
}
}
var attachments = _mapper.Map<IEnumerable<Attachment>>(attachmentList).ToList();
var newAttachment = attachments.Where(t => t.Id == Guid.Empty);
await _attachmentrepository.AddRangeAsync(newAttachment);
await _attachmentrepository.SaveChangesAsync();
var list = _mapper.Map<IEnumerable<AttachmentDTO>>(attachments).ToList();
list.ForEach(t => t.FullPath = t.Path + "?access_token=" + _userInfo.UserToken);
return list;
}
/// <summary>
/// 更新医生资质
/// </summary>
/// <param name="attachment"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> UpdateTrialAttachments(AttachmentDTO attachment)
{
if (!attachment.Path.Contains(attachment.DoctorId.ToString()))
{
var attachmentData= await _attachmentrepository.Where(a => a.Id == attachment.Id).FirstNotNullAsync();
var fileName= attachmentData.Path.Split("/").Last();
attachment.Path = $"/systemData/reviewe/{attachment.Type}/{attachment.DoctorId}/{fileName}";
await _oSSService.MoveObject(attachmentData.Path, attachment.Path);
}
if (attachment.DoctorId != null)
{
await _attachmentrepository.DeleteFromQueryAsync(a =>a.Id!=attachment.Id&& a.DoctorId == attachment.DoctorId && a.Type == attachment.Type);
}
attachment.UpdateTime = DateTime.Now;
await _attachmentrepository.UpdateFromDTOAsync(attachment);
await _attachmentrepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[NonDynamicMethod]
public async Task<AttachmentDTO> GetDetailById(Guid attachmentId)
{
@@ -2,19 +2,80 @@
{
public class AttachmentDTO
{
public Guid Id { get; set; }
public Guid DoctorId { get; set; }
public Guid? Id { get; set; }
public Guid? DoctorId { get; set; }
public bool IsOfficial { get; set; }
public string Type { get; set; } = string.Empty;
public string Path { get; set; } = string.Empty;
public string FullPath { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public DateTime? CreateTime { get; set; }
public DateTime? UpdateTime { get; set; }
public int Language { get; set; }
public bool ReUpload { get; set; } = false;
public Guid? TrialId { get; set; }
/// <summary>
/// 是否授权
/// </summary>
public bool IsAuthorizedView { get; set; } = false;
public string BlindName { get; set; } = string.Empty;
public string BlindNameCN { get; set; } = string.Empty;
public string ChineseName { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string FullName => LastName + " / " + FirstName;
public string LastName { get; set; } = string.Empty;
public string UserName { get; set; } = string.Empty;
}
public class SetAttachmentAuthorizedView
{
public List<Guid> Ids { get; set; }
public bool IsAuthorizedView { get; set; }
}
public class DeleteAttachment
{
public List<Guid> Ids { get; set; }
}
public class GetTrialDoctorSelectInDto
{
public Guid TrialId { get; set; }
}
public class GetTrialDoctorListOutDto
{
public Guid Id { get; set; }
public string BlindName { get; set; } = string.Empty;
public string BlindNameCN { get; set; } = string.Empty;
public string ChineseName { get; set; } = string.Empty;
public string FirstName { get; set; } = string.Empty;
public string FullName => LastName + " / " + FirstName;
public string LastName { get; set; } = string.Empty;
}
public class GetTrialAttachmentsInDto:PageInput
{
public Guid TrialId { get; set; }
public string? Type { get; set; }
public Guid? DoctorId { get; set; }
public string? FileName { get; set; }
public bool? IsAuthorizedView { get; set; }
}
public class ReviewerAckDTO
{
public Guid Id { get; set; }
@@ -169,6 +169,16 @@ namespace IRaCIS.Application.Contracts
public class ReviewerConfirmationQueryDTO : PageInput
{
public Guid TrialId { get; set; } = Guid.Empty;
public DateTime? OptStartTime{ get; set; }
public DateTime? OptEndTime { get; set; }
public string? Code { get; set; }
public UserTypeEnum? UserTypeEnum { get; set; }
public string? OptUserName { get; set; }
}
public class SelectionReviewerDTO : DoctorDTO
@@ -194,14 +204,48 @@ namespace IRaCIS.Application.Contracts
public string City { get; set; } = string.Empty;
public string HospitalName { get; set; } = string.Empty;
public string HospitalNameCN { get; set; } = string.Empty;
public string Country { get; set; } = string.Empty;
}
public class GetTrialDoctorListInDto : PageInput
{
public Guid TrialId { get; set; } = Guid.Empty;
/// <summary>
/// 亚专业
/// </summary>
public Guid? SubspecialityId { get; set; }
/// <summary>
/// 专业
/// </summary>
public Guid? SpecialityId { get; set; }
/// <summary>
/// 机构
/// </summary>
public Guid? HospitalId { get; set; }
}
public class TrialDoctorInfo : ConfirmationReviewerDTO
{
public List<string> SubspecialityList => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.Value).ToList();
public List<string> SubspecialityCNList => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.ValueCN).ToList();
}
public class ConfirmationReviewerDTO : DoctorOptDTO
{
public int DoctorTrialState { get; set; }
public string OptUserName { get; set; } = string.Empty;
public UserTypeEnum? UserTypeEnum { get; set; }
public DateTime? OptTime { get; set; }
public string? OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss");
@@ -223,6 +267,8 @@ namespace IRaCIS.Application.Contracts
public List<Guid> SubspecialityIds => DictionaryList.Where(t => t.ParentCode == StaticData.Subspeciality).OrderBy(t => t.ShowOrder).Select(t => t.Id).ToList();
public Guid? HospitalId { get; set; }
}
@@ -235,6 +281,10 @@ namespace IRaCIS.Application.Contracts
public string OptUserName { get; set; } = String.Empty;
public DateTime? OptTime { get; set; }
public int OptUserType { get; set; }
public UserTypeEnum UserTypeEnum { get; set; }
}
#endregion
@@ -523,6 +573,8 @@ namespace IRaCIS.Application.Contracts
{
public string BlindName { get; set; }
public bool IsHaveAccount { get; set; } = false;
public string BlindNameCN { get; set; } = string.Empty;
public List<DicView> DoctorDicViewDtos = new List<DicView>();
@@ -243,11 +243,137 @@ namespace IRaCIS.Core.Application.Service
{
#region
//var query = from enroll in _enrollRepository.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup)
// join enrollDetail in _enrollDetailRepository.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup) on new { enroll.DoctorId, enroll.EnrollStatus } equals new { enrollDetail.DoctorId, enrollDetail.EnrollStatus } into enrollDetailtemp
// from leftenrollDetail in enrollDetailtemp.DefaultIfEmpty()
// select new ConfirmationReviewerDTO()
// {
// DoctorTrialState = (int)leftenrollDetail.EnrollStatus,
// OptTime = leftenrollDetail.CreateTime,
// UserTypeEnum = leftenrollDetail.CreateUserRole.UserTypeEnum,
// OptUserName = leftenrollDetail.CreateUserRole.UserName,
// SubmmitTime = leftenrollDetail.CreateTime,
// SubmmitUserName = leftenrollDetail.CreateUserRole.UserName,
// //BlindName= enroll.BlindName,
// //BlindNameCN= enroll.BlindNameCN,
// SpecialityId = enroll.Doctor.SpecialityId,
// SpecialityCN = enroll.Doctor.Speciality.ValueCN,
// Speciality = enroll.Doctor.Speciality.Value,
// //SpecialityOther=enroll.Doctor.Speciality.SpecialityOther,
// //SpecialityOtherCN= enroll.Doctor.Speciality.SpecialityOtherCN,
// DictionaryList = enroll.Doctor.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder).Select(x => new DicView()
// {
// Id = x.Id,
// ParentCode = x.Parent.Code,
// ShowOrder = x.ShowOrder,
// Value = x.Value,
// ValueCN = x.ValueCN
// }).ToList(),
// //HospitalId= enroll.BlindName
// Id = enroll.Doctor.Id,
// Code = enroll.DoctorUser.UserName,
// //FirstName=enroll.FirstName,
// //LastName = enroll.LastName,
// //ChineseName = enroll.ChineseName,
// //City = enroll.City,
// //HospitalName = enroll.HospitalName,
// //Country = enroll.Country,
// };
//var result = await query
// .WhereIf(inQuery.OptStartTime != null, x => x.OptTime >= inQuery.OptStartTime)
// .WhereIf(inQuery.OptEndTime != null, x => x.OptTime <= inQuery.OptEndTime)
// .WhereIf(inQuery.UserTypeEnum != null, x => x.UserTypeEnum == inQuery.UserTypeEnum)
// .WhereIf(inQuery.Code.IsNotNullOrEmpty(), x => x.Code.Contains(inQuery.Code))
// .WhereIf(inQuery.OptUserName.IsNotNullOrEmpty(), x => x.OptUserName.Contains(inQuery.OptUserName))
// .ToPagedListAsync(inQuery);
#endregion
#region
// 这里这样写的原因是因为 要取最新的入组详情 然后还要根据时间筛选 入组信息
var query = _enrollDetailRepository
.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup);
var enrollStateList = await query
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
enrollStateList = enrollStateList.GroupBy(e => e.DoctorId)
.Select(g => g.OrderByDescending(e => e.OptTime).FirstOrDefault()).ToList();
enrollStateList = enrollStateList
.WhereIf(inQuery.OptStartTime != null, x => x.OptTime >= inQuery.OptStartTime)
.WhereIf(inQuery.OptEndTime != null, x => x.OptTime <= inQuery.OptEndTime)
.WhereIf(inQuery.UserTypeEnum != null, x => x.UserTypeEnum == inQuery.UserTypeEnum)
.ToList();
#endregion
var doctorids = enrollStateList.Select(x => x.DoctorId).ToList();
var doctorQuery = _enrollRepository.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup)
.ProjectTo<ConfirmationReviewerDTO>(_mapper.ConfigurationProvider);
.WhereIf(inQuery.OptStartTime != null || inQuery.OptEndTime != null || inQuery.UserTypeEnum != null, x => doctorids.Contains(x.DoctorId))
.ProjectTo<ConfirmationReviewerDTO>(_mapper.ConfigurationProvider)
.WhereIf(inQuery.Code.IsNotNullOrEmpty(), x => x.Code.Contains(inQuery.Code))
.WhereIf(inQuery.OptUserName.IsNotNullOrEmpty(), x => x.OptUserName.Contains(inQuery.OptUserName));
var doctorPageList = await doctorQuery.ToPagedListAsync(inQuery);
doctorPageList.CurrentPageData.ToList().ForEach(u =>
{
u.DoctorTrialState = (int)EnrollStatus.InviteIntoGroup;
var opt = enrollStateList.OrderByDescending(x=>x.OptTime).FirstOrDefault(t => t.DoctorId == u.Id);
if (opt != null)
{
u.DoctorTrialState = opt.IntoGroupState;
u.OptTime = opt.OptTime;
u.UserTypeEnum = opt.UserTypeEnum;
u.OptUserName = opt.OptUserName;
}
});
return doctorPageList;
}
/// <summary>
/// 获取项目下医生列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<TrialDoctorInfo>> GetTrialDoctorList(
GetTrialDoctorListInDto inQuery)
{
var doctorQuery = _enrollRepository.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus == EnrollStatus.ConfirmIntoGroup)
.ProjectTo<TrialDoctorInfo>(_mapper.ConfigurationProvider);
var doctorPageList = await doctorQuery
.WhereIf(inQuery.HospitalId!=null,x=>x.HospitalId==inQuery.HospitalId.Value)
.WhereIf(inQuery.SpecialityId != null, x => x.SpecialityId == inQuery.SpecialityId.Value)
.WhereIf(inQuery.SubspecialityId != null, x => x.DictionaryList.Any(x=>x.Id==inQuery.SubspecialityId.Value))
.ToPagedListAsync(inQuery);
var enrollStateList = await _enrollDetailRepository.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus > EnrollStatus.InviteIntoGroup)
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
@@ -17,6 +17,7 @@ namespace IRaCIS.Core.Application.Service
IRepository<DoctorDictionary> _doctorDictionaryRepository,
IRepository<DoctorSummarize> _doctorSummarizeRepository,
IRepository<Enroll> _enrollRepository,
IRepository<UserRole> _userRoleRepository,
IRepository<Hospital> _hospitalRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<Attachment> _attachmentRepository,
@@ -490,7 +491,7 @@ namespace IRaCIS.Core.Application.Service
var doctorBasicInfo = (await _doctorRepository.Where(t => t.Id == doctorId)
.ProjectTo<DoctorBasicInfoDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
doctorBasicInfo.IsHaveAccount =await _userRoleRepository.AnyAsync(x => x.DoctorId == doctorId);
return doctorBasicInfo;
@@ -13,6 +13,8 @@ namespace IRaCIS.Core.Application.Service
{
var isEn_Us = false;
Guid TrialId = Guid.Empty;
// 从 DateTime 映射到 DateOnly
CreateMap<DateTime, DateOnly>().ConvertUsing(dt => DateOnly.FromDateTime(dt));
@@ -70,7 +72,15 @@ namespace IRaCIS.Core.Application.Service
CreateMap<Postgraduate, PostgraduateViewModel>();
// .ForMember(t => t.Hospital, c => c.MapFrom(d => d.HospitalEnt.HospitalName))
//.ForMember(t => t.HospitalCN, c => c.MapFrom(d => d.HospitalEnt.HospitalNameCN));
CreateMap<Attachment, AttachmentDTO>();
CreateMap<Attachment, AttachmentDTO>()
.ForMember(d => d.BlindName, u => u.MapFrom(t => t.Doctor.BlindName))
.ForMember(d => d.BlindNameCN, u => u.MapFrom(t => t.Doctor.BlindNameCN))
.ForMember(d => d.ChineseName, u => u.MapFrom(t => t.Doctor.ChineseName))
.ForMember(d => d.FirstName, u => u.MapFrom(t => t.Doctor.FirstName))
.ForMember(d => d.LastName, u => u.MapFrom(t => t.Doctor.LastName))
.ForMember(d => d.UserName, u => u.MapFrom(t => t.Doctor.EnrollList.Where(y=>y.TrialId== TrialId).Select(x=>x.DoctorUser.UserName).First()))
;
CreateMap<Doctor, GetTrialDoctorListOutDto>();
CreateMap<Doctor, ResumeConfirmDTO>();
CreateMap<Doctor, DoctorSelectDTO>();
@@ -178,16 +188,30 @@ namespace IRaCIS.Core.Application.Service
CreateMap<Hospital, EmploymentDTO>();
CreateMap<EnrollDetail, DoctorStateModelDTO>()
.ForMember(d => d.UserTypeEnum, u => u.MapFrom(s => s.CreateUserRole.UserTypeEnum))
.ForMember(d => d.IntoGroupState, u => u.MapFrom(s => s.EnrollStatus))
.ForMember(d => d.OptTime, u => u.MapFrom(s => s.CreateTime))
.ForMember(d => d.OptUserName, u => u.MapFrom(s => s.CreateUserRole.IdentityUser.UserName));
CreateMap<Enroll, TrialDoctorInfo>().IncludeMembers(t => t.Doctor, t => t.Doctor.Hospital)
.ForMember(o => o.DictionaryList, t => t.MapFrom(u => u.Doctor.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)))
.ForMember(d => d.Speciality, u => u.MapFrom(s => s.Doctor.Speciality.Value))
.ForMember(d => d.SpecialityCN, u => u.MapFrom(s => s.Doctor.Speciality.ValueCN))
.ForMember(d => d.Id, u => u.MapFrom(s => s.Doctor.Id))
.ForMember(d => d.Code, u => u.MapFrom(s => s.DoctorUser.UserName));
CreateMap<Doctor, TrialDoctorInfo>();
CreateMap<Hospital, TrialDoctorInfo>();
CreateMap<Enroll, ConfirmationReviewerDTO>().IncludeMembers(t => t.Doctor, t => t.Doctor.Hospital)
.ForMember(o => o.DictionaryList, t => t.MapFrom(u => u.Doctor.DoctorDicRelationList.Where(t => t.KeyName == StaticData.ReadingType || t.KeyName == StaticData.Subspeciality).Select(t => t.Dictionary).OrderBy(t => t.ShowOrder)))
.ForMember(d => d.Speciality, u => u.MapFrom(s => s.Doctor.Speciality.Value))
.ForMember(d => d.SpecialityCN, u => u.MapFrom(s => s.Doctor.Speciality.ValueCN))
.ForMember(d => d.Id, u => u.MapFrom(s => s.Doctor.Id))
.ForMember(d => d.Code, u => u.MapFrom(s => s.DoctorUser.UserName))
.ForMember(d => d.HospitalName, u => u.MapFrom(s => s.Doctor.HospitalName))
.ForMember(d => d.HospitalNameCN, u => u.MapFrom(s => s.Doctor.HospitalNameCN))
;
CreateMap<Doctor, ConfirmationReviewerDTO>();
CreateMap<Hospital, ConfirmationReviewerDTO>();
@@ -0,0 +1,533 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-03-27 06:13:33Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
using AutoMapper.Execution;
using System.Linq;
using IRaCIS.Core.Infrastructure;
using DocumentFormat.OpenXml.Office2010.Excel;
using MassTransit;
using NPOI.POIFS.Properties;
using Org.BouncyCastle.Crypto;
using Microsoft.AspNetCore.Http;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 稽查文档
/// </summary>
/// <returns></returns>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class AuditDocumentService(IRepository<AuditDocument> _auditDocumentRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService
{
/// <summary>
/// 获取稽查文档
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<AuditDocumentView>> GetAuditDocumentList(AuditDocumentQuery inQuery)
{
var auditDocumentQueryable = _auditDocumentRepository
.ProjectTo<AuditDocumentView>(_mapper.ConfigurationProvider);
var pageList = await auditDocumentQueryable.ToPagedListAsync(inQuery);
return pageList;
}
/// <summary>
/// 修改稽查文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> UpdateAuditDocument(AuditDocumentUpdateDto inDto)
{
AuditDocumentAddOrEdit addOrEdit = _mapper.Map<AuditDocumentAddOrEdit>(inDto);
addOrEdit.IsUpdate = true;
var result= await AddOrUpdateAuditDocument(addOrEdit);
return ResponseOutput.Ok(result.Id);
}
/// <summary>
/// 新增稽查文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AddAuditDocument(List<AuditDocumentAddOrEdit> inDto)
{
List<Guid> resultData = new List<Guid>();
inDto.ForEach(x => x.IsUpdate = false);
await addData(inDto);
async Task addData(List<AuditDocumentAddOrEdit> data)
{
foreach(var item in data)
{
var result= await AddOrUpdateAuditDocument(item);
resultData.Add(result.Id);
item.Children.ForEach(x => {
x.ParentId = result.Id;
x.IsUpdate = false;
});
if (item.Children.Count() > 0)
{
await addData(item.Children);
}
}
}
return ResponseOutput.Ok(resultData);
}
/// <summary>
/// 通用方法
/// </summary>
/// <param name="inDto"></param>
private async Task<AuditDocument> AddOrUpdateAuditDocument(AuditDocumentAddOrEdit inDto)
{
var alikeData = await _auditDocumentRepository.Where(x =>x.Id!=inDto.Id&& x.ParentId == inDto.ParentId&&x.Name==inDto.Name&&x.AuditDocumentTypeEnum==inDto.AuditDocumentTypeEnum).FirstOrDefaultAsync();
if (alikeData != null)
{
if (inDto.AuditDocumentTypeEnum == AuditDocumentType.Folder)
{
if (inDto.IsUpdate)
{
throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotAddFolder"]);
}
else
{
return alikeData;
}
}
else
{
var entityData = await _auditDocumentRepository.InsertOrUpdateAsync(inDto, true);
var historicalVersionIds = await _auditDocumentRepository.Where(x => x.MainFileId == alikeData.Id).OrderBy(x => x.Version).Select(x => x.Id).ToListAsync();
historicalVersionIds.Add(alikeData.Id);
int num = 1;
foreach (var item in historicalVersionIds)
{
await _auditDocumentRepository.UpdatePartialFromQueryAsync(item, x => new AuditDocument()
{
MainFileId = entityData.Id,
ParentId = null,
Version = num,
AuditDocumentTypeEnum = AuditDocumentType.HistoricalVersion
},true);
num++;
}
return entityData;
}
}
var entity = await _auditDocumentRepository.InsertOrUpdateAsync(inDto, true);
return entity;
}
/// <summary>
/// 获取面包屑导航
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<AuditDocumentUpdateDto>> GetBreadcrumbData(GetBreadcrumbDataInDto inDto)
{
List<AuditDocumentUpdateDto> result=new List<AuditDocumentUpdateDto>();
await findParent(result, inDto.Id);
async Task findParent(List<AuditDocumentUpdateDto> datas, Guid id)
{
var data= await _auditDocumentRepository.Where(x => x.Id == id).ProjectTo<AuditDocumentUpdateDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
datas.Add(data);
if (data.ParentId != null)
{
await findParent(datas, data.ParentId.Value);
}
}
result.Reverse();
return result;
}
/// <summary>
/// 获取文件树形结构 (传Id 根节点就是自己)
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<AuditDocumentData>> GetAuditDocumentData(GetAuditDocumentDataInDto inDto)
{
var defalutSortArray = new string[] { nameof(AuditDocumentData.AuditDocumentTypeEnum), nameof(AuditDocumentData.Name) };
// 新取出来排序 然后再找子项
var data= (await _auditDocumentRepository
.Where(x=>x.AuditDocumentTypeEnum!=AuditDocumentType.HistoricalVersion)
.WhereIf(inDto.IsAuthorization!=null,x=>x.IsAuthorization==inDto.IsAuthorization)
.ProjectTo<AuditDocumentData>(_mapper.ConfigurationProvider).ToPagedListAsync(new PageInput() {
PageIndex=1,
PageSize=999999,
}, defalutSortArray) ).CurrentPageData.ToList();
if (inDto.Name.IsNotNullOrEmpty())
{
List<Guid> findIds = new List<Guid>();
var findData = data.Where(x => x.Name.Contains(inDto.Name)).Select(x => x.Id.Value).ToList();
GetParentId(findIds, findData, data);
findIds.AddRange(findData);
data = data.Where(x => findIds.Distinct().Contains(x.Id.Value)).ToList();
}
var query = data
.WhereIf(inDto.SelfId != null, x => inDto.SelfId == x.Id)
.WhereIf(inDto.Id != null, x => inDto.Id == x.ParentId)
.WhereIf(inDto.Id == null&& inDto.SelfId == null, x => x.ParentId == null);
PageOutput<AuditDocumentData> result = new PageOutput<AuditDocumentData>()
{
PageIndex = inDto.PageIndex,
PageSize = inDto.PageSize,
TotalCount = query.Count(),
};
var root = query
.Skip(inDto.PageSize * (inDto.PageIndex - 1)).Take(inDto.PageSize).ToList();
foreach (var item in root)
{
GetChildren(item, data);
}
result.CurrentPageData = root;
return result;
}
private void GetParentId(List<Guid> parentIds, List<Guid> ids, List<AuditDocumentData> dataList)
{
var parentid = dataList.Where(x => ids.Contains(x.Id.Value) && x.ParentId != null).Select(x => x.ParentId.Value).ToList();
if (parentid.Count() > 0)
{
parentIds.AddRange(parentid);
GetParentId(parentIds, parentid, dataList);
}
}
private void GetChildren(AuditDocumentData item, List<AuditDocumentData> dataList)
{
item.Children = dataList.Where(x => x.ParentId == item.Id).ToList();
foreach (var x in item.Children)
{
GetChildren(x, dataList);
}
}
/// <summary>
/// 删除稽查文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> DeleteAuditDocument(DeleteAuditDocumentInDto inDto)
{
var data = await _auditDocumentRepository.Select(x => new DeleteAudit (){
Id=x.Id,
ParentId= x.ParentId,
MainFileId= x.MainFileId
}).ToListAsync();
List<Guid> DeleteId= inDto.Ids;
finId(inDto.Ids, data);
void finId(List<Guid> deletids, List<DeleteAudit> deletes)
{
DeleteId.AddRange(deletids);
var temp = deletes.Where(x =>(x.ParentId!=null&& deletids.Contains(x.ParentId.Value))||(x.MainFileId!=null&& deletids.Contains(x.MainFileId.Value))).Select(x => x.Id).ToList();
if (temp.Count() > 0)
{
finId(temp, deletes);
}
}
DeleteId = DeleteId.Distinct().ToList();
var mainFileId=await _auditDocumentRepository.Where(x => DeleteId.Contains(x.Id)&&x.MainFileId!=null).Select(x => x.MainFileId).Distinct().ToListAsync();
var success = await _auditDocumentRepository.DeleteFromQueryAsync(t => DeleteId.Distinct().Contains(t.Id), true);
foreach (var item in mainFileId)
{
var historicalVersionList = await _auditDocumentRepository.Where(x => x.MainFileId == item).OrderBy(x=>x.Version).ToListAsync();
var num = 1;
foreach (var historical in historicalVersionList)
{
await _auditDocumentRepository.UpdatePartialFromQueryAsync(historical.Id, x => new AuditDocument()
{
Version = num,
}, true);
num++;
}
}
return ResponseOutput.Ok();
}
/// <summary>
/// 移动文件或者文件夹 到其他文件夹
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> MovieFileOrFolder(MovieFileOrFolderInDto inDto)
{
var data = await _auditDocumentRepository.Select(x => new DeleteAudit()
{
Id = x.Id,
ParentId = x.ParentId,
AuditDocumentTypeEnum = x.AuditDocumentTypeEnum,
MainFileId = x.MainFileId
}).ToListAsync();
foreach (var id in inDto.Ids)
{
var file = data.Where(x => x.Id == id).FirstOrDefault();
if (file.AuditDocumentTypeEnum == AuditDocumentType.Folder)
{
if (finChild(new List<Guid> { id }, inDto.ParentId, data))
{
throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotMove"]);
}
}
}
bool finChild(List<Guid> ids, Guid ChildId, List<DeleteAudit> data)
{
var child = data.Where(x => x.ParentId != null && ids.Contains(x.ParentId.Value)).ToList();
if (child.Count() == 0)
{
return false;
}
else if (child.Any(x => x.Id == ChildId))
{
return true;
}
else
{
var newids = child.Select(x => x.Id).ToList();
return finChild(newids, ChildId, data);
}
}
foreach (var id in inDto.Ids)
{
await _auditDocumentRepository.UpdatePartialFromQueryAsync(id, x => new AuditDocument()
{
ParentId = inDto.ParentId
});
await _auditDocumentRepository.SaveChangesAsync();
}
return ResponseOutput.Ok();
}
/// <summary>
/// 复制文件或者文件夹
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> CopyFileOrFolder(MovieFileOrFolderInDto inDto)
{
foreach (var item in inDto.Ids)
{
var data = (await GetAuditDocumentData(new GetAuditDocumentDataInDto()
{
SelfId =item,
PageIndex=1,
PageSize= 1000
})).CurrentPageData;
List<AuditDocumentAddOrEdit> auditDocumentAddOrEdits = _mapper.Map<List<AuditDocumentAddOrEdit>>(data);
auditDocumentAddOrEdits.ForEach(x => x.IsUpdate = false);
await addData(auditDocumentAddOrEdits);
}
async Task addData(List<AuditDocumentAddOrEdit> data)
{
foreach (var item in data)
{
item.Id = null;
var result = await AddOrUpdateAuditDocument(item);
item.Children.ForEach(x => {
x.ParentId = result.Id;
x.IsUpdate = false;
});
if (item.Children.Count() > 0)
{
await addData(item.Children);
}
}
}
return ResponseOutput.Ok();
}
/// <summary>
/// 获取历史版本
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<HistoricalVersionDto>> GetHistoricalVersion(GetHistoricalVersionInDto inDto)
{
List< HistoricalVersionDto > result=new List<HistoricalVersionDto>();
result = await _auditDocumentRepository.Where(x => x.MainFileId == inDto.Id).ProjectTo<HistoricalVersionDto>(_mapper.ConfigurationProvider).OrderByDescending(x => x.Version).ToListAsync();
var currentData = await _auditDocumentRepository.Where(x => x.Id == inDto.Id).ProjectTo<HistoricalVersionDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
currentData.IsCurrentVersion = true;
result.Insert(0, currentData);
return result;
}
/// <summary>
/// 把历史版本设置为当前版本
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> SetCurrentVersion(SetCurrentVersionInDto inDto)
{
var file = await _auditDocumentRepository.Where(x => x.Id == inDto.Id).FirstNotNullAsync();
if (file.AuditDocumentTypeEnum != AuditDocumentType.HistoricalVersion)
{
throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotSetCurrentVersion"]);
}
var mainFile = await _auditDocumentRepository.Where(x => x.Id == file.MainFileId).FirstNotNullAsync();
var historicalVersionIds= await _auditDocumentRepository.Where(x => x.MainFileId == mainFile.Id&&x.Id!=inDto.Id).OrderBy(x=>x.Version).Select(x=>x.Id).ToListAsync();
historicalVersionIds.Add(mainFile.Id);
await _auditDocumentRepository.UpdatePartialFromQueryAsync(inDto.Id, x => new AuditDocument() {
MainFileId=null,
ParentId= mainFile.ParentId,
AuditDocumentTypeEnum=AuditDocumentType.File,
});
int num = 1;
foreach (var item in historicalVersionIds)
{
await _auditDocumentRepository.UpdatePartialFromQueryAsync(item, x => new AuditDocument()
{
MainFileId = inDto.Id,
ParentId = null,
Version=num,
AuditDocumentTypeEnum= AuditDocumentType.HistoricalVersion
});
num++;
}
await _auditDocumentRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 设置是否授权
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> SetIsAuthorization(SetIsAuthorizationInDto inDto)
{
var data = await _auditDocumentRepository.Select(x => new DeleteAudit()
{
Id = x.Id,
ParentId = x.ParentId,
MainFileId = x.MainFileId
}).ToListAsync();
List<Guid> allid = new List<Guid>();
findChild(allid, inDto.Ids, data);
await _auditDocumentRepository.UpdatePartialFromQueryAsync(t => allid.Contains(t.Id), x => new AuditDocument() {
IsAuthorization = inDto.IsAuthorization
});
await _auditDocumentRepository.SaveChangesAsync();
return ResponseOutput.Ok();
void findChild(List<Guid> allId,List<Guid> current, List<DeleteAudit> data)
{
allId.AddRange(current);
var child = data.Where(x =>(x.ParentId!=null&& current.Contains(x.ParentId.Value))||(x.MainFileId!=null&&current.Contains(x.MainFileId.Value))).Select(x => x.Id).ToList();
if (child.Count() > 0)
{
findChild(allId, child, data);
}
}
}
}
@@ -0,0 +1,162 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-03-27 06:13:37Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel;
public class DeleteAudit
{
public Guid Id { get; set; }
public AuditDocumentType AuditDocumentTypeEnum { get; set; }
public Guid? ParentId { get; set; }
public Guid? MainFileId { get; set; }
}
public class DeleteAuditDocumentInDto
{
public List<Guid> Ids { get; set; }
}
public class GetAuditDocumentDataInDto:PageInput
{
public Guid? Id { get; set; }
public Guid? SelfId { get; set; }
public bool? IsAuthorization { get; set; }
public string Name { get; set; } = string.Empty;
}
public class GetAuditDocumentDataOutDto
{
public List<AuditDocumentData> Data { get; set; } = new List<AuditDocumentData> { };
}
public class AuditDocumentData : AuditDocumentUpdateDto
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public int? Version { get; set; }
public List<AuditDocumentData> Children { get; set; }=new List<AuditDocumentData> (){ };
}
public class AuditDocumentView : AuditDocumentAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class SetIsAuthorizationInDto
{
public List<Guid> Ids { get; set; }
public bool IsAuthorization { get; set; }
}
public class SetCurrentVersionInDto
{
public Guid Id { get; set; }
}
public class GetHistoricalVersionInDto
{
public Guid Id { get; set; }
}
public class GetHistoricalVersionOutDto
{
public AuditDocumentData CurrentData { get; set; }
public List<AuditDocumentData> HistoricalVersionList { get; set; } = new List<AuditDocumentData> { };
}
public class MovieFileOrFolderInDto
{
public List<Guid> Ids { get; set; }
public Guid ParentId { get; set; }
}
public class HistoricalVersionDto: AuditDocumentUpdateDto
{
public bool IsCurrentVersion { get; set; } = false;
public int? Version { get; set; }
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class AuditDocumentUpdateDto
{
public Guid? Id { get; set; }
public AuditDocumentType AuditDocumentTypeEnum { get; set; }
public string? FileFormat { get; set; }
public string? FilePath { get; set; }
public decimal? FileSize { get; set; }
public bool IsAuthorization { get; set; }
// public Guid? MainFileId { get; set; }
public string Name { get; set; }
public Guid? ParentId { get; set; }
}
public class GetBreadcrumbDataInDto
{
public Guid Id { get; set; }
}
public class AuditDocumentAddOrEdit: AuditDocumentUpdateDto
{
public List<AuditDocumentAddOrEdit> Children { get; set; }=new List<AuditDocumentAddOrEdit>() { };
public bool IsUpdate { get; set; } = true;
}
public class AuditDocumentQuery:PageInput
{
public AuditDocumentType? AuditDocumentTypeEnum { get; set; }
public string? FileFormat { get; set; }
public string? FilePath { get; set; }
public decimal? FileSize { get; set; }
public bool? IsAuthorization { get; set; }
public Guid? MainFileId { get; set; }
public string? Name { get; set; }
public Guid? ParentId { get; set; }
}
@@ -0,0 +1,61 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel;
public class SysFileTypeView : SysFileTypeAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class SysFileTypeAddOrEdit
{
public Guid? Id { get; set; }
public ArchiveType ArchiveTypeEnum { get; set; }
public bool IsConfirmRecord { get; set; }
public bool IsEnable { get; set; }
public string Name { get; set; }
public string NameCN { get; set; }
/// <summary>
/// 显示顺序
/// </summary>
public int ShowOrder { get; set; }
public SubIdentification SubIdentificationEnum { get; set; }
}
public class SysFileTypeQuery : PageInput
{
public ArchiveType? ArchiveTypeEnum { get; set; }
public bool? IsConfirmRecord { get; set; }
public bool? IsEnable { get; set; }
public string? Name { get; set; }
public string? NameCN { get; set; }
public SubIdentification? SubIdentificationEnum { get; set; }
}
@@ -178,7 +178,25 @@ namespace IRaCIS.Core.Application.Contracts
public bool? IsConfirmed { get; set; }
/// <summary>
/// 课时状态
/// </summary>
public bool? IsDeleted { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string? UserName { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime? StartConfirmTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime? EndConfirmTime { get; set; }
}
///<summary> SystemDocumentAddOrEdit 列表查询参数模型</summary>
@@ -0,0 +1,153 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection.Metadata;
namespace IRaCIS.Core.Application.ViewModel;
public class TrialFileTypeView : TrialFileTypeAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class GetTrialFileTypeDataOutDto
{
public List<TrialFileTypeData> TrialFileTypeDataList { get; set; }
}
public class TrialFileTypeData
{
public ArchiveType ArchiveTypeEnum { get; set; }
public List<TrialFileTypeView> TrialFileTypeList { get; set; }
}
public class GetTrialFileTypeFileInDto
{
public Guid TrialFileTypeId { get; set; }
}
public class UploadTrialFileTypeFileInDto
{
public Guid TrialFileTypeId { get; set; }
/// <summary>
/// 文件
/// </summary>
public TrialFileDto? FileRecord { get; set; }
}
public class SetAuthorizedViewInDto
{
public Guid Id { get; set; }
public bool IsEnable { get; set; }
}
public class GetTrialFileTypeDataInDto
{
public Guid TrialId { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnable { get; set; } = false;
}
public class CopySystemFileTypeToTrialInDto
{
public Guid TrialId { get; set; }
}
public class TrialFileTypeSelectView
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool IsEnable { get; set; }
public bool IsSelfDefine { get; set; }
public ArchiveType ArchiveTypeEnum { get; set; }
}
public class TrialFileTypeAddOrEdit
{
public Guid? Id { get; set; }
public ArchiveType ArchiveTypeEnum { get; set; }
public DateOnly? FirstFinalDate { get; set; }
public bool IsConfirmRecord { get; set; }
public bool IsEnable { get; set; }
public bool IsSelfDefine { get; set; }
public string Name { get; set; }
public string NameCN { get; set; }
public SubIdentification SubIdentificationEnum { get; set; }
public Guid? SysFileTypeId { get; set; }
public Guid TrialId { get; set; }
/// <summary>
/// 显示顺序
/// </summary>
public int ShowOrder { get; set; }
}
public class TrialFileTypeQuery : PageInput
{
public ArchiveType? ArchiveTypeEnum { get; set; }
public DateOnly? FirstFinalDate { get; set; }
public bool? IsConfirmRecord { get; set; }
public bool? IsEnable { get; set; }
public bool? IsSelfDefine { get; set; }
public string? Name { get; set; }
public string? NameCN { get; set; }
public SubIdentification? SubIdentificationEnum { get; set; }
[NotDefault]
public Guid TrialId { get; set; }
}
public class TrialFileTypeSelectQuery
{
[NotDefault]
public Guid TrialId { get; set; }
public bool? IsEnable { get; set; }
public bool? IsSelfDefine { get; set; }
public ArchiveType? ArchiveTypeEnum { get; set; }
}
@@ -0,0 +1,115 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.ViewModel;
public class TrialFinalRecordView : TrialFinalRecordAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class DeleteTrialNormalRecordListInDto
{
public List<Guid> Ids { get; set; }
}
public class AuthorizedTrialFinalRecordInDto
{
public List<Guid> Ids { get; set; }
public bool IsAuthorizedView { get; set; }
}
public class TrialFinalRecordAddOrEdit
{
public Guid? Id { get; set; }
public bool IsAuthorizedView { get; set; }
public string Name { get; set; }
public int State { get; set; }
public Guid TrialFileTypeId { get; set; }
public Guid TrialId { get; set; }
public string Version { get; set; }
/// <summary>
/// 定稿PDF
/// </summary>
public TrialFileDto? PDFFileRecord { get; set; }
/// <summary>
/// 定稿Word
/// </summary>
public TrialFileDto? WordFileRecord { get; set; }
/// <summary>
/// 签名页
/// </summary>
public TrialFileDto? SignFileRecord { get; set; }
/// <summary>
/// 历史记录
/// </summary>
public TrialFileDto? HistoryFileRecord { get; set; }
}
public class TrialFileDto
{
public Guid TrialFileTypeId { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string FileSize { get; set; }
public string FileFormat { get; set; }
}
public class TrialFinalRecordQuery : PageInput
{
public Guid? HistoryFileRecordId { get; set; }
public bool? IsAuthorizedView { get; set; }
public string? Name { get; set; }
[NotDefault]
public Guid TrialFileTypeId { get; set; }
public Guid? TrialId { get; set; }
public string? Version { get; set; }
public Guid? WordFileRecordId { get; set; }
}
@@ -0,0 +1,60 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel;
public class TrialNormalRecordView : TrialNormalRecordAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public string FileName { get; set; }
}
public class BatchAddTrialNormalRecordInDto
{
public List<TrialNormalRecordAddOrEdit> TrialNormalRecordList { get; set; }
}
public class TrialNormalRecordAddOrEdit
{
public Guid? Id { get; set; }
public bool IsAuthorizedView { get; set; }
public int State { get; set; }
public TrialFileDto? TrialFileRecord { get; set; }
public TrialFileDto? HistoryFileRecord { get; set; }
public Guid TrialFileTypeId { get; set; }
public Guid TrialId { get; set; }
}
public class TrialNormalRecordQuery : PageInput
{
public bool? IsAuthorizedView { get; set; }
public int? State { get; set; }
public string? FileName { get; set; }
public Guid? TrialFileTypeId { get; set; }
public Guid? TrialId { get; set; }
}
@@ -0,0 +1,77 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Domain.Share;
using System.Collections.Generic;
namespace IRaCIS.Core.Application.ViewModel;
public class TrialTrianingRecordView : TrialTrianingRecordAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public string FileName { get; set; }
}
public class BatchAddTTrianingRecordInDto
{
public List<TrialTrianingRecordAddOrEdit> TrianingRecordList { get; set; }
}
public class TrialTrianingRecordAddOrEdit
{
public Guid? Id { get; set; }
public bool IsAuthorizedView { get; set; }
public string Note { get; set; }=string.Empty;
public int? State { get; set; }
public TrialFileDto? TrialFileRecord { get; set; }
public TrialFileDto? HistoryFileRecord { get; set; }
public Guid TrialFileTypeId { get; set; }
public Guid TrialId { get; set; }
public int? TrianingCount { get; set; }
public DateOnly? TrianingDate { get; set; }
public string? TrianingState { get; set; }
}
public class TrialTrianingRecordQuery : PageInput
{
public bool? IsAuthorizedView { get; set; }
public string? FileName { get; set; }
public Guid? TrialFileTypeId { get; set; }
public Guid? TrialId { get; set; }
public int? TrianingCount { get; set; }
public DateOnly? TrianingDateStartTime { get; set; }
public DateOnly? TrianingDateEndTime { get; set; }
public DateTime? UpdateStartTime { get; set; }
public DateTime? UpdateEndTime { get; set; }
public string? TrianingState { get; set; }
}
@@ -0,0 +1,23 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Interfaces;
public interface ISysFileTypeService
{
Task<PageOutput<SysFileTypeView>> GetSysFileTypeList(SysFileTypeQuery inQuery);
Task<IResponseOutput> AddOrUpdateSysFileType(SysFileTypeAddOrEdit addOrEditSysFileType);
Task<IResponseOutput> DeleteSysFileType(Guid sysFileTypeId);
}
@@ -0,0 +1,23 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Interfaces;
public interface ITrialFileTypeService
{
Task<PageOutput<TrialFileTypeView>> GetTrialFileTypeList(TrialFileTypeQuery inQuery);
Task<IResponseOutput> AddOrUpdateTrialFileType(TrialFileTypeAddOrEdit addOrEditTrialFileType);
Task<IResponseOutput> DeleteTrialFileType(Guid trialFileTypeId);
}
@@ -0,0 +1,23 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Interfaces;
public interface ITrialFinalRecordService
{
Task<PageOutput<TrialFinalRecordView>> GetTrialFinalRecordList(TrialFinalRecordQuery inQuery);
Task<IResponseOutput> AddOrUpdateTrialFinalRecord(TrialFinalRecordAddOrEdit addOrEditTrialFinalRecord);
Task<IResponseOutput> DeleteTrialFinalRecord(Guid trialFinalRecordId);
}
@@ -0,0 +1,23 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Interfaces;
public interface ITrialNormalRecordService
{
Task<PageOutput<TrialNormalRecordView>> GetTrialNormalRecordList(TrialNormalRecordQuery inQuery);
Task<IResponseOutput> AddOrUpdateTrialNormalRecord(TrialNormalRecordAddOrEdit addOrEditTrialNormalRecord);
Task<IResponseOutput> DeleteTrialNormalRecord(Guid trialNormalRecordId);
}
@@ -0,0 +1,23 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using System;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Application.ViewModel;
namespace IRaCIS.Core.Application.Interfaces;
public interface ITrialTrianingRecordService
{
Task<PageOutput<TrialTrianingRecordView>> GetTrialTrianingRecordList(TrialTrianingRecordQuery inQuery);
Task<IResponseOutput> AddOrUpdateTrialTrianingRecord(TrialTrianingRecordAddOrEdit addOrEditTrialTrianingRecord);
Task<IResponseOutput> DeleteTrialTrianingRecord(Guid trialTrianingRecordId);
}
@@ -0,0 +1,87 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:24Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 系统文件类型
/// </summary>
/// <param name="_sysFileTypeRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class SysFileTypeService(IRepository<SysFileType> _sysFileTypeRepository, IRepository<TrialFileType> _trialFileTypeRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ISysFileTypeService
{
[HttpPost]
public async Task<PageOutput<SysFileTypeView>> GetSysFileTypeList(SysFileTypeQuery inQuery)
{
var sysFileTypeQueryable = _sysFileTypeRepository
.WhereIf(inQuery.ArchiveTypeEnum != null, t => t.ArchiveTypeEnum == inQuery.ArchiveTypeEnum)
.WhereIf(inQuery.IsConfirmRecord != null, t => t.IsConfirmRecord == inQuery.IsConfirmRecord)
.WhereIf(inQuery.SubIdentificationEnum != null, t => t.SubIdentificationEnum == inQuery.SubIdentificationEnum)
.WhereIf(inQuery.IsEnable != null, t => t.IsEnable == inQuery.IsEnable)
.WhereIf(inQuery.Name.IsNotNullOrEmpty(), t => t.Name.Contains(inQuery.Name))
.WhereIf(inQuery.NameCN.IsNotNullOrEmpty(), t => t.NameCN.Contains(inQuery.NameCN))
.ProjectTo<SysFileTypeView>(_mapper.ConfigurationProvider);
var defalutSortArray = new string[] { nameof(SysFileTypeView.ArchiveTypeEnum), nameof(SysFileTypeView.ShowOrder)};
var pageList = await sysFileTypeQueryable.ToPagedListAsync(inQuery, defalutSortArray);
return pageList;
}
public async Task<IResponseOutput> AddOrUpdateSysFileType(SysFileTypeAddOrEdit addOrEditSysFileType)
{
var verifyExp = new EntityVerifyExp<SysFileType>()
{
VerifyExp = u => u.IsEnable == addOrEditSysFileType.IsEnable && (u.Name == addOrEditSysFileType.Name || u.NameCN == addOrEditSysFileType.NameCN),
// "当前类型启用的文件类型名称重复"
VerifyMsg = _localizer["SysFileType_NameRepeat"],
IsVerify = addOrEditSysFileType.IsEnable == false
};
var entity = await _sysFileTypeRepository.InsertOrUpdateAsync(addOrEditSysFileType, true, verifyExp);
//启用的才进行更新
if (addOrEditSysFileType.Id != null && addOrEditSysFileType.IsEnable)
{
await _trialFileTypeRepository.BatchUpdateNoTrackingAsync(t => t.SysFileTypeId == addOrEditSysFileType.Id, u => new TrialFileType() { Name = addOrEditSysFileType.Name, NameCN = addOrEditSysFileType.NameCN,ShowOrder=addOrEditSysFileType.ShowOrder });
}
return ResponseOutput.Ok(entity.Id.ToString());
}
[HttpDelete("{sysFileTypeId:guid}")]
public async Task<IResponseOutput> DeleteSysFileType(Guid sysFileTypeId)
{
var success = await _sysFileTypeRepository.DeleteFromQueryAsync(t => t.Id == sysFileTypeId, true);
return ResponseOutput.Ok();
}
}
@@ -400,7 +400,7 @@ namespace IRaCIS.Core.Application.Services
var unionQuery = systemDocQuery.Concat(trialDocQuery)
//过滤掉删除的,并且没有签名的
.Where(t=>!(t.IsDeleted == true && t.ConfirmTime==null))
.Where(t => !(t.IsDeleted == true && t.ConfirmTime == null))
.WhereIf(!string.IsNullOrEmpty(inQuery.Name), t => t.Name.Contains(inQuery.Name))
.WhereIf(inQuery.FileTypeId != null, t => t.FileTypeId == inQuery.FileTypeId)
.WhereIf(inQuery.IsSign == true, t => t.ConfirmTime != null)
@@ -473,10 +473,12 @@ namespace IRaCIS.Core.Application.Services
var trialDocQuery =
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(t => t.TrialId == inQuery.TrialId)
.Where(t => inQuery.UserTypeId != null ? t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId) : true)
from trialUser in _trialIdentityUserRepository.AsQueryable(false).Where(t => t.TrialId == inQuery.TrialId
from trialUser in _trialIdentityUserRepository.AsQueryable(false).Where(t => t.TrialId == inQuery.TrialId
&& t.TrialUserRoleList.AsQueryable().Any(t => trialDoc.NeedConfirmedUserTypeList.Any(c => c.NeedConfirmUserTypeId == t.UserRole.UserTypeId))
)
.Where(t => inQuery.UserId != null ? t.IdentityUserId == inQuery.UserId : true)
.Where(t => inQuery.UserTypeId != null ? t.TrialUserRoleList.Any(t => t.UserRole.UserTypeId == inQuery.UserTypeId) : true)
join confirm in _trialDocConfirmedUserRepository.Where(t => t.TrialDocument.TrialId == inQuery.TrialId) on
new { trialUser.IdentityUserId, TrialDocumentId = trialDoc.Id } equals new { IdentityUserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
@@ -514,10 +516,11 @@ namespace IRaCIS.Core.Application.Services
var systemDocQuery =
from sysDoc in _systemDocumentRepository.AsQueryable(false).Where(u => trialInfo.TrialFinishedTime != null ? u.CreateTime < trialInfo.TrialFinishedTime : true)
.Where(t => inQuery.UserTypeId != null ? t.NeedConfirmedUserTypeList.Any(t => t.NeedConfirmUserTypeId == inQuery.UserTypeId) : true)
from trialUser in _trialIdentityUserRepository.AsQueryable(false).Where(t => t.TrialId == inQuery.TrialId
&& t.TrialUserRoleList.Any(t => sysDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserRole.UserTypeId)))
.Where(t => inQuery.UserId != null ? t.IdentityUserId == inQuery.UserId : true)
.Where(t => inQuery.UserTypeId != null ? t.TrialUserRoleList.Any(t => t.UserRole.UserTypeId == inQuery.UserTypeId) : true)
join confirm in _systemDocConfirmedUserRepository.Where() on new { ConfirmUserId = trialUser.IdentityUserId, SystemDocumentId = sysDoc.Id } equals new { confirm.ConfirmUserId, confirm.SystemDocumentId } into cc
from confirm in cc.DefaultIfEmpty()
select new UnionDocumentWithConfirmInfoView()
@@ -554,6 +557,9 @@ namespace IRaCIS.Core.Application.Services
.WhereIf(inQuery.FileTypeId != null, t => t.FileTypeId == inQuery.FileTypeId)
.WhereIf(inQuery.IsConfirmed == true, t => t.ConfirmTime != null)
.WhereIf(inQuery.IsConfirmed == false, t => t.ConfirmTime == null)
.WhereIf(inQuery.StartConfirmTime != null, t => t.ConfirmTime >= inQuery.StartConfirmTime.Value)
.WhereIf(inQuery.EndConfirmTime != null, t => t.ConfirmTime <= inQuery.EndConfirmTime.Value)
.WhereIf(!string.IsNullOrEmpty(inQuery.UserName), t => t.UserName.Contains(inQuery.UserName))
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == inQuery.IsDeleted);
var result = await unionQuery.ToPagedListAsync(inQuery);
@@ -570,7 +576,7 @@ namespace IRaCIS.Core.Application.Services
var sysDocUserTypeList = _systemDocNeedConfirmedUserTypeRepository.Where(t => sysDocIdList.Contains(t.SystemDocumentId)).Select(t => new { t.SystemDocumentId, t.UserTypeRole.UserTypeShortName }).ToList();
var trialUserUserTypeList = _trialIdentityUserRepository.Where(t => t.TrialId==inQuery.TrialId && trialIdentityUserIdList.Contains(t.IdentityUserId)).IgnoreQueryFilters().Select(t => new { t.IdentityUserId, UserTypeList = t.TrialUserRoleList.Select(c => c.UserRole.UserTypeRole.UserTypeShortName).ToList() });
var trialUserUserTypeList = _trialIdentityUserRepository.Where(t => t.TrialId == inQuery.TrialId && trialIdentityUserIdList.Contains(t.IdentityUserId)).IgnoreQueryFilters().Select(t => new { t.IdentityUserId, UserTypeList = t.TrialUserRoleList.Select(c => c.UserRole.UserTypeRole.UserTypeShortName).ToList() });
foreach (var item in result.CurrentPageData)
@@ -0,0 +1,241 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 项目文件类型
/// </summary>
/// <param name="_trialFileTypeRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class TrialFileTypeService(IRepository<TrialFileType> _trialFileTypeRepository,
IRepository<TrialFile> _trialFileRepository,
IRepository<SysFileType> _sysFileTypeRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITrialFileTypeService
{
[HttpPost]
public async Task<PageOutput<TrialFileTypeView>> GetTrialFileTypeList(TrialFileTypeQuery inQuery)
{
var trialFileTypeQueryable = _trialFileTypeRepository
.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.ArchiveTypeEnum != null, t => t.ArchiveTypeEnum == inQuery.ArchiveTypeEnum)
.WhereIf(inQuery.IsConfirmRecord != null, t => t.IsConfirmRecord == inQuery.IsConfirmRecord)
.WhereIf(inQuery.SubIdentificationEnum != null, t => t.SubIdentificationEnum == inQuery.SubIdentificationEnum)
.WhereIf(inQuery.IsEnable != null, t => t.IsEnable == inQuery.IsEnable)
.WhereIf(inQuery.Name.IsNotNullOrEmpty(), t => t.Name.Contains(inQuery.Name))
.WhereIf(inQuery.NameCN.IsNotNullOrEmpty(), t => t.NameCN.Contains(inQuery.NameCN))
.WhereIf(inQuery.IsSelfDefine != null, t => t.IsSelfDefine == inQuery.IsSelfDefine)
.ProjectTo<TrialFileTypeView>(_mapper.ConfigurationProvider);
var pageList = await trialFileTypeQueryable.ToPagedListAsync(inQuery);
return pageList;
}
/// <summary>
/// 获取项目文件类型下拉框
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
public async Task<List<TrialFileTypeSelectView>> GetTrialFileTypeSelectList(TrialFileTypeSelectQuery inQuery)
{
var list = _trialFileTypeRepository
.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.ArchiveTypeEnum != null, t => t.ArchiveTypeEnum == inQuery.ArchiveTypeEnum)
.WhereIf(inQuery.IsSelfDefine != null, t => t.IsSelfDefine == inQuery.IsSelfDefine)
.WhereIf(inQuery.IsEnable != null, t => t.IsEnable == inQuery.IsEnable)
.Select(t => new TrialFileTypeSelectView()
{
Id = t.Id,
IsEnable = t.IsEnable,
Name = _userInfo.IsEn_Us ? t.Name : t.NameCN,
IsSelfDefine = t.IsSelfDefine,
ArchiveTypeEnum = t.ArchiveTypeEnum,
}).ToList();
return list;
}
public async Task<IResponseOutput> AddOrUpdateTrialFileType(TrialFileTypeAddOrEdit addOrEditTrialFileType)
{
if (await _trialFileTypeRepository.AnyAsync(u => u.TrialId == addOrEditTrialFileType.TrialId && u.Id != addOrEditTrialFileType.Id && u.IsEnable == addOrEditTrialFileType.IsEnable && (u.Name == addOrEditTrialFileType.Name || u.NameCN == addOrEditTrialFileType.NameCN)))
{
throw new BusinessValidationFailedException(_localizer["TrialFileType_NameRepeat"]);
}
var entity = await _trialFileTypeRepository.InsertOrUpdateAsync(addOrEditTrialFileType, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
[HttpDelete("{trialFileTypeId:guid}")]
public async Task<IResponseOutput> DeleteTrialFileType(Guid trialFileTypeId)
{
var success = await _trialFileTypeRepository.DeleteFromQueryAsync(t => t.Id == trialFileTypeId, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 复制系统数据到项目
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<IResponseOutput> CopySystemFileTypeToTrial(CopySystemFileTypeToTrialInDto inDto)
{
if (!(await _trialFileTypeRepository.AnyAsync(x => x.TrialId == inDto.TrialId)))
{
var trialFileTypeList = await _sysFileTypeRepository
.ProjectTo<TrialFileType>(_mapper.ConfigurationProvider)
.ToListAsync();
trialFileTypeList.ForEach(x => {
x.TrialId = inDto.TrialId;
x.Id = NewId.NextGuid();
});
await _trialFileTypeRepository.AddRangeAsync(trialFileTypeList, true);
}
return ResponseOutput.Ok();
}
/// <summary>
/// 获取项目文件类型数据
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<GetTrialFileTypeDataOutDto> GetTrialFileTypeData(GetTrialFileTypeDataInDto inDto)
{
await this.CopySystemFileTypeToTrial(new CopySystemFileTypeToTrialInDto()
{
TrialId = inDto.TrialId
});
var trialFileTypeList = await _trialFileTypeRepository.Where(x => x.TrialId == inDto.TrialId)
.WhereIf(inDto.IsEnable, x => x.IsEnable)
.OrderBy(x => x.ShowOrder)
.ProjectTo<TrialFileTypeView>(_mapper.ConfigurationProvider)
.ToListAsync();
List<TrialFileTypeData> result = new List<TrialFileTypeData>();
foreach (ArchiveType type in Enum.GetValues(typeof(ArchiveType)))
{
result.Add(new TrialFileTypeData()
{
ArchiveTypeEnum = type,
TrialFileTypeList = trialFileTypeList.Where(x => x.ArchiveTypeEnum == type).OrderBy(x => x.SysFileTypeId == null).ThenBy(x => x.ShowOrder).ToList()
});
}
return new GetTrialFileTypeDataOutDto() { TrialFileTypeDataList = result };
}
/// <summary>
/// 修改授权状态
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> SetAuthorizedView(SetAuthorizedViewInDto inDto)
{
await _trialFileTypeRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.Id, x => new TrialFileType() { IsEnable = inDto.IsEnable }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 上传同意入项记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> UploadTrialFileTypeFile(UploadTrialFileTypeFileInDto inDto)
{
var trialFileType = await _trialFileTypeRepository.Where(x => x.Id == inDto.TrialFileTypeId).FirstNotNullAsync();
if (trialFileType.FileRecordId != null)
{
await _trialFileRepository.BatchDeleteNoTrackingAsync(x => x.Id == trialFileType.FileRecordId);
}
inDto.FileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
var entity = await _trialFileRepository.InsertFromDTOAsync(inDto.FileRecord, true);
await _trialFileTypeRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.TrialFileTypeId, x => new TrialFileType()
{
FileRecordId = entity.Id
});
await _trialFileTypeRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 获取入项记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<TrialFileDto> GetTrialFileTypeFile(GetTrialFileTypeFileInDto inDto)
{
var trialFileType = await _trialFileTypeRepository.Where(x => x.Id == inDto.TrialFileTypeId).FirstNotNullAsync();
if (trialFileType.FileRecordId == null)
{
return new TrialFileDto() { };
}
var file = await _trialFileRepository.Where(x => x.Id == trialFileType.FileRecordId).ProjectTo<TrialFileDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
return file;
}
/// <summary>
/// 删除入项记录
/// </summary>
/// <param name="trialFileTypeId"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> DeleteTrialTypeFile(Guid trialFileTypeId)
{
var trialFileType = await _trialFileTypeRepository.Where(x => x.Id == trialFileTypeId).FirstNotNullAsync();
await _trialFileRepository.DeleteFromQueryAsync(x => x.Id == trialFileType.FileRecordId, true);
await _trialFileTypeRepository.UpdatePartialFromQueryAsync(x => x.Id == trialFileTypeId, x => new TrialFileType() { FileRecordId = null }, true);
return ResponseOutput.Ok();
}
}
@@ -0,0 +1,119 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 项目定稿记录
/// </summary>
/// <param name="_trialFinalRecordRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class TrialFinalRecordService(IRepository<TrialFinalRecord> _trialFinalRecordRepository,
IRepository<TrialFile> _trialFileRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITrialFinalRecordService
{
[HttpPost]
public async Task<PageOutput<TrialFinalRecordView>> GetTrialFinalRecordList(TrialFinalRecordQuery inDto)
{
var trialFinalRecordQueryable = _trialFinalRecordRepository
.Where(x=>x.TrialFileTypeId==inDto.TrialFileTypeId)
.WhereIf(inDto.Name.IsNotNullOrEmpty(),x=>x.Name.Contains(inDto.Name))
.WhereIf(inDto.Version.IsNotNullOrEmpty(), x => x.Version.Contains(inDto.Version))
.WhereIf(inDto.IsAuthorizedView!=null, x => x.IsAuthorizedView==inDto.IsAuthorizedView)
// .Include(x=>x.PDFFileRecord).Include(x => x.WordFileRecord).Include(x => x.SignFileRecord).Include(x => x.HistoryFileRecord)
.ProjectTo<TrialFinalRecordView>(_mapper.ConfigurationProvider);
var pageList = await trialFinalRecordQueryable.ToPagedListAsync(inDto);
return pageList;
}
/// <summary>
/// 新增或者修改文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<IResponseOutput> AddOrUpdateTrialFinalRecord(TrialFinalRecordAddOrEdit inDto)
{
// 在此处拷贝automapper 映射
if (inDto.PDFFileRecord != null) inDto.PDFFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.WordFileRecord != null) inDto.WordFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.SignFileRecord != null) inDto.SignFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.HistoryFileRecord != null) inDto.HistoryFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (await _trialFinalRecordRepository.AnyAsync(x => x.Id != inDto.Id && x.TrialFileTypeId == inDto.TrialFileTypeId && x.Name == inDto.Name && x.Version == inDto.Version))
{
throw new BusinessValidationFailedException(_localizer["TrialFinalRecord_NameRepeat"]);
}
if (inDto.Id != null)
{
var trialFinalRecord = await _trialFinalRecordRepository.Where(x => x.Id == inDto.Id.Value).FirstNotNullAsync();
List<Guid?> ids= new List<Guid?>() {
trialFinalRecord.WordFileRecordId,
trialFinalRecord.PDFFileRecordId,
trialFinalRecord.SignFileRecordId,
trialFinalRecord.HistoryFileRecordId
};
var fileIds = ids.Where(x => x != null).Select(x => (Guid)x).ToList();
await _trialFileRepository.BatchDeleteNoTrackingAsync(x => fileIds.Contains(x.Id));
}
var entity = await _trialFinalRecordRepository.InsertOrUpdateAsync(inDto, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
/// <summary>
/// 授权文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<IResponseOutput> AuthorizedTrialFinalRecord(AuthorizedTrialFinalRecordInDto inDto)
{
await _trialFinalRecordRepository.UpdatePartialFromQueryAsync(t =>inDto.Ids.Contains(t.Id), t => new TrialFinalRecord() { IsAuthorizedView = inDto.IsAuthorizedView });
await _trialFinalRecordRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 删除文档
/// </summary>
/// <param name="trialFinalRecordId"></param>
/// <returns></returns>
[HttpDelete("{trialFinalRecordId:guid}")]
public async Task<IResponseOutput> DeleteTrialFinalRecord(Guid trialFinalRecordId)
{
var success = await _trialFinalRecordRepository.DeleteFromQueryAsync(t => t.Id == trialFinalRecordId, true);
return ResponseOutput.Ok();
}
}
@@ -0,0 +1,130 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 项目-一般文件记录
/// </summary>
/// <param name="_trialNormalRecordRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class TrialNormalRecordService(IRepository<TrialNormalRecord> _trialNormalRecordRepository,
IRepository<TrialFile> _trialFileRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITrialNormalRecordService
{
[HttpPost]
public async Task<PageOutput<TrialNormalRecordView>> GetTrialNormalRecordList(TrialNormalRecordQuery inDto)
{
var trialNormalRecordQueryable = _trialNormalRecordRepository
.Where(x => x.TrialFileTypeId == inDto.TrialFileTypeId)
.WhereIf(inDto.IsAuthorizedView != null, x => x.IsAuthorizedView == inDto.IsAuthorizedView)
.WhereIf(inDto.FileName.IsNotNullOrEmpty(), x => x.TrialFileRecord.FileName.Contains(inDto.FileName))
.ProjectTo<TrialNormalRecordView>(_mapper.ConfigurationProvider);
var pageList = await trialNormalRecordQueryable.ToPagedListAsync(inDto);
return pageList;
}
public async Task<IResponseOutput> AddOrUpdateTrialNormalRecord(TrialNormalRecordAddOrEdit inDto)
{
if (inDto.TrialFileRecord != null) inDto.TrialFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.HistoryFileRecord != null) inDto.HistoryFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.Id != null)
{
var trialFinalRecord = await _trialNormalRecordRepository.Where(x => x.Id == inDto.Id.Value).FirstNotNullAsync();
List<Guid?> ids = new List<Guid?>() {
trialFinalRecord.TrialFileRecordId,
trialFinalRecord.HistoryFileRecordId,
};
var fileIds = ids.Where(x => x != null).Select(x => (Guid)x).ToList();
await _trialFileRepository.BatchDeleteNoTrackingAsync(x => fileIds.Contains(x.Id));
}
var entity = await _trialNormalRecordRepository.InsertOrUpdateAsync(inDto, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
/// <summary>
/// 批量新增一般文件记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> BatchAddTrialNormalRecord(BatchAddTrialNormalRecordInDto inDto)
{
foreach (var item in inDto.TrialNormalRecordList)
{
if (item.TrialFileRecord != null) item.TrialFileRecord.TrialFileTypeId = item.TrialFileTypeId;
if (item.HistoryFileRecord != null) item.HistoryFileRecord.TrialFileTypeId = item.TrialFileTypeId;
var entity = await _trialNormalRecordRepository.InsertFromDTOAsync(item);
}
var result= await _trialNormalRecordRepository.SaveChangesAsync();
return ResponseOutput.Ok(result);
}
/// <summary>
/// 授权文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<IResponseOutput> AuthorizedTTrialNormalRecord(AuthorizedTrialFinalRecordInDto inDto)
{
await _trialNormalRecordRepository.UpdatePartialFromQueryAsync(t => inDto.Ids.Contains(t.Id), t => new TrialNormalRecord() { IsAuthorizedView = inDto.IsAuthorizedView });
await _trialNormalRecordRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpDelete("{trialNormalRecordId:guid}")]
public async Task<IResponseOutput> DeleteTrialNormalRecord(Guid trialNormalRecordId)
{
var success = await _trialNormalRecordRepository.DeleteFromQueryAsync(t => t.Id == trialNormalRecordId, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 批量删除一般文件记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> DeleteTrialNormalRecordList(DeleteTrialNormalRecordListInDto inDto)
{
var success = await _trialNormalRecordRepository.DeleteFromQueryAsync(t => inDto.Ids.Contains(t.Id), true);
return ResponseOutput.Ok();
}
}
@@ -0,0 +1,140 @@
//--------------------------------------------------------------------
// 此代码由liquid模板自动生成 byzhouhang 20240909
// 生成时间 2025-02-21 07:47:30Z
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
namespace IRaCIS.Core.Application.Service;
/// <summary>
/// 项目-培训记录
/// </summary>
/// <param name="_trialTrianingRecordRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class TrialTrianingRecordService(IRepository<
TrialTrianingRecord> _trialTrianingRecordRepository,
IRepository<TrialFile> _trialFileRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITrialTrianingRecordService
{
/// <summary>
/// 获取培训记录列表
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<TrialTrianingRecordView>> GetTrialTrianingRecordList(TrialTrianingRecordQuery inDto)
{
var trialTrianingRecordQueryable = _trialTrianingRecordRepository
.Where(x => x.TrialFileTypeId == inDto.TrialFileTypeId)
.WhereIf(inDto.IsAuthorizedView != null, x => x.IsAuthorizedView == inDto.IsAuthorizedView)
.WhereIf(inDto.FileName.IsNotNullOrEmpty(), x => x.TrialFileRecord.FileName.Contains(inDto.FileName))
.WhereIf(inDto.TrianingDateStartTime != null, x => x.TrianingDate >= inDto.TrianingDateStartTime)
.WhereIf(inDto.TrianingDateEndTime != null, x => x.TrianingDate <= inDto.TrianingDateEndTime)
.WhereIf(inDto.UpdateStartTime != null, x => x.UpdateTime >= inDto.UpdateStartTime)
.WhereIf(inDto.UpdateEndTime != null, x => x.UpdateTime < inDto.UpdateEndTime.Value.AddDays(1))
.ProjectTo<TrialTrianingRecordView>(_mapper.ConfigurationProvider);
var pageList = await trialTrianingRecordQueryable.ToPagedListAsync(inDto);
return pageList;
}
public async Task<IResponseOutput> AddOrUpdateTrialTrianingRecord(TrialTrianingRecordAddOrEdit inDto)
{
// 在此处拷贝automapper 映射
if (inDto.TrialFileRecord != null) inDto.TrialFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.HistoryFileRecord != null) inDto.HistoryFileRecord.TrialFileTypeId = inDto.TrialFileTypeId;
if (inDto.Id != null)
{
var trialFinalRecord = await _trialTrianingRecordRepository.Where(x => x.Id == inDto.Id.Value).FirstNotNullAsync();
List<Guid?> ids = new List<Guid?>() {
trialFinalRecord.TrialFileRecordId,
trialFinalRecord.HistoryFileRecordId,
};
var fileIds = ids.Where(x => x != null).Select(x => (Guid)x).ToList();
await _trialFileRepository.BatchDeleteNoTrackingAsync(x => fileIds.Contains(x.Id));
}
var entity = await _trialTrianingRecordRepository.InsertOrUpdateAsync(inDto, true);
return ResponseOutput.Ok(entity.Id.ToString());
}
/// <summary>
/// 批量新增培训记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> BatchAddTrialTrianingRecord(BatchAddTTrianingRecordInDto inDto)
{
foreach (var item in inDto.TrianingRecordList)
{
if (item.TrialFileRecord != null) item.TrialFileRecord.TrialFileTypeId = item.TrialFileTypeId;
if (item.HistoryFileRecord != null) item.HistoryFileRecord.TrialFileTypeId = item.TrialFileTypeId;
var entity = await _trialTrianingRecordRepository.InsertFromDTOAsync(item);
}
var result = await _trialTrianingRecordRepository.SaveChangesAsync();
return ResponseOutput.Ok(result);
}
/// <summary>
/// 授权文档
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AuthorizedTrialTrianingRecord(AuthorizedTrialFinalRecordInDto inDto)
{
await _trialTrianingRecordRepository.UpdatePartialFromQueryAsync(t => inDto.Ids.Contains(t.Id), t => new TrialTrianingRecord() { IsAuthorizedView = inDto.IsAuthorizedView });
await _trialTrianingRecordRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
[HttpDelete("{trialTrianingRecordId:guid}")]
public async Task<IResponseOutput> DeleteTrialTrianingRecord(Guid trialTrianingRecordId)
{
var success = await _trialTrianingRecordRepository.DeleteFromQueryAsync(t => t.Id == trialTrianingRecordId, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 批量删除培训记录
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> DeleteTrialTrianingRecordList(DeleteTrialNormalRecordListInDto inDto)
{
var success = await _trialTrianingRecordRepository.DeleteFromQueryAsync(t => inDto.Ids.Contains(t.Id), true);
return ResponseOutput.Ok();
}
}
@@ -3,6 +3,7 @@ using AutoMapper.EquivalencyExpression;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
namespace IRaCIS.Core.Application.Service
{
@@ -13,11 +14,24 @@ namespace IRaCIS.Core.Application.Service
var userId = Guid.Empty;
var isEn_Us = false;
CreateMap<AuditDocumentData, AuditDocumentAddOrEdit>();
//CreateMap<List<AuditDocumentData>, List<AuditDocumentAddOrEdit>>();
CreateMap<AuditDocument, AuditDocumentView>();
CreateMap<AuditDocument, AuditDocumentUpdateDto>();
CreateMap<AuditDocument, HistoricalVersionDto>();
CreateMap<AuditDocumentUpdateDto, AuditDocumentAddOrEdit>();
CreateMap<AuditDocument, AuditDocumentData>();
CreateMap<AuditDocument, AuditDocumentAddOrEdit>().ReverseMap();
CreateMap<SystemDocument, SystemDocumentView>()
.ForMember(d => d.FileType, u => u.MapFrom(s => isEn_Us ? s.FileType.Value : s.FileType.ValueCN))
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path));
CreateMap<SysFileType, TrialFileType>()
.ForMember(d => d.SysFileTypeId, u => u.MapFrom(s => s.Id))
.ForMember(d => d.IsSelfDefine, u => u.MapFrom(s => false))
.ForMember(dest => dest.CreateUserRole, opt => opt.Ignore());
CreateMap<TrialDocument, TrialDocumentView>()
.ForMember(d => d.FileType, u => u.MapFrom(s => isEn_Us ? s.FileType.Value : s.FileType.ValueCN))
.ForMember(d => d.IsSomeUserSigned, u => u.MapFrom(s => s.TrialDocConfirmedUserList.Any(t => t.ConfirmTime != null)))
@@ -51,6 +65,9 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialUserRole, TrialDocumentUserConfirmView>();
CreateMap<TrialFileDto, TrialFile>();
CreateMap<TrialFile, TrialFileDto>();
CreateMap<BatchAddTrialEmailNoticeConfig, TrialEmailNoticeConfig>();
CreateMap<TrialSelectEmailNoticeConfigView, BatchAddTrialEmailNoticeConfig > ();
@@ -87,6 +104,33 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialEmailNoticeUser, EmailUserInfoDto>();
CreateMap<SysFileType, SysFileTypeView>();
CreateMap<SysFileType, SysFileTypeAddOrEdit>().ReverseMap();
CreateMap<TrialFileType, TrialFileTypeView>();
CreateMap<TrialFileType, TrialFileTypeAddOrEdit>().ReverseMap();
CreateMap<TrialFinalRecord, TrialFinalRecordView>();
CreateMap<TrialFinalRecordAddOrEdit, TrialFinalRecord>();
//.ForMember(d => d.HistoryFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId))
//.ForMember(d => d.SignFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId))
//.ForMember(d => d.WordFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId))
//.ForMember(d => d.PDFFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId));
CreateMap<TrialNormalRecord, TrialNormalRecordView>()
.ForMember(d => d.FileName, c => c.MapFrom(t => t.TrialFileRecord.FileName));
CreateMap<TrialNormalRecord, TrialNormalRecordAddOrEdit>().ReverseMap();
CreateMap<TrialTrianingRecord, TrialTrianingRecordView>()
.ForMember(d => d.FileName, c => c.MapFrom(t => t.TrialFileRecord.FileName));
CreateMap<TrialTrianingRecord, TrialTrianingRecordAddOrEdit>().ReverseMap();
}
}
@@ -79,6 +79,11 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
public int InstanceNumber { get; set; }
public bool IsReading { get; set; }
public bool IsDeleted { get; set; }
public Guid? StudyId { get; set; }
public List<int?> KeyFramesList { get; set; } = new List<int?> { };
@@ -44,7 +44,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
IRepository<NoneDicomStudyFile> _noneDicomStudyFileReposiotry,
IDistributedLockProvider _distributedLockProvider,
IRepository<TrialImageDownload> _trialImageDownloadRepository,
IRepository<Subject> _subjectRepository,
IRepository<Subject> _subjectRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IDownloadAndUploadService
{
@@ -257,7 +257,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> PreArchiveDicomStudy(PriArchiveTaskStudyCommand preArchiveStudyCommand)
{
@@ -356,7 +356,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> AddOrUpdateArchiveTaskStudy(TaskArchiveStudyCommand incommand)
{
#region subject 访
@@ -620,12 +620,25 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
if (dicomStudyId == null)
{
var deleteStudyPathList = await _taskInstanceRepository.Where(t => t.VisitTaskId == visitTaskId).GroupBy(t => t.StudyId).Select(g => g.First().Path).ToListAsync();
foreach (var fisrtPath in deleteStudyPathList)
{
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
}
await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
}
else
{
var fisrtPath = await _taskInstanceRepository.Where(t => t.VisitTaskId == visitTaskId && t.StudyId == dicomStudyId).Select(t => t.Path).FirstOrDefaultAsync();
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
@@ -689,7 +702,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
SubjectCode = u.IsSelfAnalysis == true ? u.BlindSubjectCode : u.Subject.Code,
TaskBlindName = u.TaskBlindName,
TaskName = u.TaskName,
ReadingTaskState=u.ReadingTaskState,
ReadingTaskState = u.ReadingTaskState,
SourceSubjectVisitId = u.SourceSubjectVisitId,
VisitTaskId = u.Id,
@@ -761,9 +774,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
select new
{
TrialId = sv.TrialId,
SubjectId=sv.SubjectId,
SubjectId = sv.SubjectId,
SubjectCode = sv.Subject.Code,
TrialSiteCode=sv.TrialSite.TrialSiteCode,
TrialSiteCode = sv.TrialSite.TrialSiteCode,
VisitName = sv.VisitName,
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
@@ -971,7 +984,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
var subjectVisitIdList = inQuery.SubjectVisitTaskList.Select(t => t.SubjectVisitId).ToList();
var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault()??string.Empty;
var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault() ?? string.Empty;
var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id)))
//一致性分析,导致查询出来两条数据
@@ -1032,9 +1045,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
Id = NewId.NextSequentialGuid(),
TrialId = info.TrialId,
SubjectId=inQuery.SubjectId,
SubjectId = inQuery.SubjectId,
SubjectCode = inQuery.SubjectCode,
TrialSiteCode= trialSiteCode,
TrialSiteCode = trialSiteCode,
IP = _userInfo.IP,
DownloadStartTime = DateTime.Now,
IsSuccess = false,
@@ -19,13 +19,19 @@ namespace IRaCIS.Core.Application.Services
[HttpGet("{seriesId:guid}")]
public async Task<IResponseOutput<List<DicomInstanceDTO>>> List(Guid seriesId)
{
var list = await _instanceRepository.Where(s => s.SeriesId == seriesId)/*.OrderBy(s => s.SliceLocation)*/.OrderBy(s => s.InstanceNumber).
ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
var qcAuditState = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => t.DicomStudy.SubjectVisit.AuditState).FirstOrDefaultAsync();
//质控通过以后,过滤删除的 质控之前的不过滤
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
var list = await _instanceRepository.Where(s => s.SeriesId == seriesId).IgnoreQueryFilters()
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.OrderBy(s => s.InstanceNumber).ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.ProjectTo<DicomInstanceDTO>(_mapper.ConfigurationProvider).ToListAsync();
var imageResizePath = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => t.DicomSerie.ImageResizePath).FirstOrDefaultAsync();
var seriesInfo = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => new { t.DicomSerie.ImageResizePath,t.DicomSerie.IsDeleted,t.DicomSerie.IsReading }).FirstOrDefaultAsync();
return ResponseOutput.Ok(list, new { ImageResizePath = imageResizePath });
return ResponseOutput.Ok(list, seriesInfo);
}
@@ -8,6 +8,7 @@ using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using NPOI.SS.Formula.Functions;
using System.ComponentModel.DataAnnotations;
namespace IRaCIS.Core.Application.Contracts
@@ -28,33 +29,49 @@ namespace IRaCIS.Core.Application.Contracts
[HttpGet]
public async Task<List<NoneDicomStudyView>> GetNoneDicomStudyList(
public async Task<IResponseOutput<List<NoneDicomStudyView>>> GetNoneDicomStudyList(
[FromQuery, NotDefault] Guid subjectVisitId,
[FromQuery] Guid? nonedicomStudyId,
[FromQuery] bool isFilterZip,
[FromQuery] Guid? visitTaskId)
[FromQuery] Guid? visitTaskId,
[FromQuery] bool isReading)
{
var qcAuditState = await _subjectVisitRepository.Where(s => s.Id == subjectVisitId).Select(t => t.AuditState).FirstOrDefaultAsync();
//质控过程中,因为会修改统计数字,但是此时其他人看,应该看到完整的影像
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
//质控过程中并且不是IQC时,可以看到删除的(不需要忽略过滤器) 质控中iqc 也需要看到删除的
var isViewDelete = !isQCFinished;
IQueryable<NoneDicomStudyView> noneDicomStudyQueryable = default;
if (visitTaskId == null)
{
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId).WhereIf(nonedicomStudyId != null, t => t.Id == nonedicomStudyId)
//质控过程中,需要忽略过滤质控设置删除的检查,以及设置删除的文件,质控通过后才
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId, ignoreQueryFilters: isViewDelete)
.WhereIf(nonedicomStudyId != null, t => t.Id == nonedicomStudyId)
.WhereIf(isReading, t => t.IsReading && t.IsDeleted==false)
.ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = isFilterZip });
.ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = isFilterZip, isReading= isReading });
}
else
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(t => new { t.BlindSubjectCode, t.TrialReadingCriterionId, t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.TaskNoneDicomFileList.Any(t => t.VisitTaskId == visitTaskId))
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.TaskNoneDicomFileList.Any(t => t.VisitTaskId == visitTaskId), ignoreQueryFilters: isViewDelete)
.WhereIf(isReading, t => t.IsReading && t.IsDeleted == false)
.Where(t => taskinfo.IsImageFilter ? ("|" + taskinfo.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.WhereIf(nonedicomStudyId != null, t => t.Id == nonedicomStudyId)
.ProjectTo<TaskDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = isFilterZip, visiTaskId = visitTaskId });
.ProjectTo<TaskDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = isFilterZip, visiTaskId = visitTaskId, isReading = isReading });
}
return await noneDicomStudyQueryable.ToListAsync();
var list = await noneDicomStudyQueryable.OrderBy(x => x.ImageDate).ThenBy(x => x.CreateTime).ToListAsync();
var config = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.Trial.ImageFormatList, t.Trial.StudyNameList, t.Trial.IsShowStudyName, AuditState = qcAuditState }).FirstOrDefaultAsync();
return ResponseOutput.Ok(list, config);
}
@@ -83,10 +100,12 @@ namespace IRaCIS.Core.Application.Contracts
//默认会是0
var code = await _noneDicomStudyRepository.Where(t => t.TrialId == addOrEditNoneDicomStudy.TrialId).Select(x => x.Code).DefaultIfEmpty().MaxAsync();
addOrEditNoneDicomStudy.Code = code + 1;
optEntity = await _noneDicomStudyRepository.InsertFromDTOAsync(addOrEditNoneDicomStudy);
optEntity.Code = code + 1;
optEntity.StudyCode = AppSettings.GetCodeStr(optEntity.Code, nameof(NoneDicomStudy));
}
@@ -158,18 +177,35 @@ namespace IRaCIS.Core.Application.Contracts
[HttpGet("{noneDicomStudyId:guid}")]
public async Task<List<NoneDicomStudyFileView>> GetNoneDicomStudyFileList(Guid noneDicomStudyId)
{
return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudyId == noneDicomStudyId)
var qcAuditState = await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudyId == noneDicomStudyId).Select(t => t.NoneDicomStudy.SubjectVisit.AuditState).FirstOrDefaultAsync();
//质控过程中,因为会修改统计数字,但是此时其他人看,应该看到完整的影像
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
//质控过程中并且不是IQC时,可以看到删除的(不需要忽略过滤器)
var isViewDelete = !isQCFinished;
return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudyId == noneDicomStudyId, ignoreQueryFilters: isViewDelete)
.ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider).OrderBy(t => t.CreateTime).ToListAsync();
}
[HttpGet("{subjectVisitId:guid}")]
public async Task<List<NoneDicomStudyFileView>> GetVisitNoneDicomStudyFileList(Guid subjectVisitId)
{
return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudy.SubjectVisitId == subjectVisitId)
var qcAuditState = await _subjectVisitRepository.Where(s => s.Id == subjectVisitId).Select(t => t.AuditState).FirstOrDefaultAsync();
//质控过程中,因为会修改统计数字,但是此时其他人看,应该看到完整的影像
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
//质控过程中并且不是IQC时, 不需要忽略过滤器+质控设置删除的
var isViewDelete = !isQCFinished;
return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudy.SubjectVisitId == subjectVisitId, ignoreQueryFilters: isViewDelete)
.ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider).ToListAsync();
}
}
}
@@ -9,7 +9,7 @@ namespace IRaCIS.Core.Application.Services
[ApiExplorerSettings(GroupName = "Image")]
[AllowAnonymous]
public class SeriesService(IRepository<DicomSeries> _seriesRepository,
IRepository<DicomInstance> _instanceRepository,
IRepository<DicomInstance> _instanceRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService
{
@@ -22,14 +22,25 @@ namespace IRaCIS.Core.Application.Services
[HttpGet, Route("{studyId:guid}")]
public async Task<IResponseOutput<List<DicomSeriesDTO>>> List(Guid studyId)
{
//断点
var seriesList = await _seriesRepository.Where(s => s.StudyId == studyId).OrderBy(s => s.SeriesNumber).
ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
//质控的时候,要标记序列,和instance 删除 ,所以要返回全部,但是 质控通过后,pm 进去看的时候要看过滤后的
var qcAuditState = await _seriesRepository.Where(s => s.StudyId == studyId).Select(t => t.DicomStudy.SubjectVisit.AuditState).FirstOrDefaultAsync();
//质控通过以后,预览过滤删除的 质控之前的不过滤
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
//断点
var seriesList = await _seriesRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
.ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
var instanceList = await _instanceRepository.Where(s => s.StudyId == studyId).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 }).ToListAsync();//.GroupBy(u => u.SeriesId);
var instanceList = await _instanceRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
.WhereIf(isQCFinished, t => t.IsDeleted == false)
.OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber, t.HtmlPath, t.IsReading, t.IsDeleted }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList)
{
@@ -42,8 +53,12 @@ namespace IRaCIS.Core.Application.Services
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
IsReading = k.IsReading,
IsDeleted = k.IsDeleted
}).ToList();
series.InstanceCount = series.InstanceInfoList.Count;
}
#region
@@ -63,12 +63,15 @@ namespace IRaCIS.Core.Application.Service
// .ForMember(o => o.InstancePathList, t => t.MapFrom(u => u.DicomInstanceList.OrderBy(t=>t.InstanceNumber).Select(t => t.Path)))
;
var isNeedStat = false;
CreateMap<DicomStudy, QAStudyInfoDTO>()
.ForMember(o => o.IsCompleteClinicalData, t => t.MapFrom(u => !u.ReadingClinicalDataList.Any(x => x.ReadingClinicalDataPDFList.Count() == 0)))
.ForMember(o => o.UploadedTime, t => t.MapFrom(u => u.CreateTime))
.ForMember(o => o.Uploader, t => t.MapFrom(u => u.CreateUserRole.IdentityUser.FullName))
.ForMember(o => o.StudyId, t => t.MapFrom(u => u.Id))
.ForMember(o => o.IsHaveUploadFailed, t => t.MapFrom(u => u.DicomStudyMonitorList.Any(t => t.FailedFileCount > 0)))
.ForMember(o => o.SeriesCount, t => t.MapFrom(u => isNeedStat == false ? u.SeriesCount : u.SeriesList.Count()))
.ForMember(o => o.InstanceCount, t => t.MapFrom(u => isNeedStat == false ? u.InstanceCount : u.InstanceList.Count()))
.ForMember(o => o.IsHaveUploadFailed, t => t.MapFrom(u => u.DicomStudyMonitorList.Any(t => t.FailedFileCount > 0)))
.ForMember(o => o.Modalities, t => t.MapFrom(u => string.Join('、', u.SeriesList.Select(t => t.Modality).Distinct())));
@@ -84,9 +87,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<DicomInstance, DicomInstanceDTO>()
.ForMember(o => o.IsDeleted, t => t.MapFrom(u => u.DicomSerie.IsDeleted))
.ForMember(o => o.SliceThickness, t => t.MapFrom(u => u.DicomSerie.SliceThickness))
.ForMember(o => o.IsReading, t => t.MapFrom(u => u.DicomSerie.IsReading));
.ForMember(o => o.SliceThickness, t => t.MapFrom(u => u.DicomSerie.SliceThickness));
CreateMap<DicomStudy, DicomStudyDTO>();
CreateMap<DicomSeries, DicomSeriesDTO>();
CreateMap<SCPSeries, DicomSeriesDTO>();
@@ -472,7 +472,7 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
/// </summary>
public string OpByUserName { get; set; } = string.Empty;
public string? CreateUserName { get; set; }
public string? CreateUserRealName { get; set; }
/// <summary>
/// 阅读片人
@@ -106,7 +106,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
//OptType = data.OptType,
IP = data.IP,
Reason = data.Reason,
IsSign = leftfrontAuditConfig.IsHaveSign && lefttrialSign.SignText!=null&& lefttrialSign.SignText!=string.Empty,
IsSign = leftfrontAuditConfig.IsHaveSign && lefttrialSign.SignText != null && lefttrialSign.SignText != string.Empty,
SignId = data.SignId,
ParentId = data.ParentId,
ChildrenTypeId = data.ChildrenTypeId,
@@ -190,7 +190,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
.WhereIf(!inQuery.TaskName.IsNullOrEmpty(), x => x.TaskName.Contains(inQuery.TaskName) || x.BlindName.Contains(inQuery.TaskName))
.WhereIf(!inQuery.SubjectInfo.IsNullOrEmpty(), x => x.SubjectCode.Contains(inQuery.SubjectInfo))
.WhereIf(!inQuery.RoleName.IsNullOrEmpty(), x => x.RoleName.Contains(inQuery.RoleName))
.WhereIf(!inQuery.RoleName.IsNullOrEmpty(), x => x.RoleName == inQuery.RoleName)
//.WhereIf(dto.VisitPlanInfo != null&& dto.VisitPlanInfo!=(decimal) 1.11, x => x.VisitNum == dto.VisitPlanInfo)
//.WhereIf(dto.VisitPlanInfo != (decimal)1.11,x=>x.InPlan!=null&& x.InPlan==false)
.WhereIf(inQuery.StartTime != null, x => x.CreateTime >= inQuery.StartTime)
@@ -198,7 +198,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
.WhereIf(inQuery.ModuleType != null, x => x.ModuleTypeId == inQuery.ModuleType)
.WhereIf(!inQuery.Description.IsNullOrEmpty(), x => x.Description.Contains(inQuery.Description) || x.DescriptionCN.Contains(inQuery.Description))
.WhereIf(!inQuery.OpByUserName.IsNullOrEmpty(), x => x.CreateUserName.Contains(inQuery.OpByUserName))
.WhereIf(!inQuery.CreateUserName.IsNullOrEmpty(), x => x.CreateUserName.Contains(inQuery.CreateUserName) || x.CreateUserRealName.Contains(inQuery.CreateUserName))
.WhereIf(!inQuery.CreateUserRealName.IsNullOrEmpty(), x => x.CreateUserName.Contains(inQuery.CreateUserRealName) || x.CreateUserRealName.Contains(inQuery.CreateUserRealName))
//.WhereIf(!dto.SubjectInfo.IsNullOrEmpty(), x => x.SubjectCode.Contains(dto.SubjectInfo))
.WhereIf(inQuery.IsSign != null, x => x.IsSign == inQuery.IsSign);
@@ -4,6 +4,7 @@
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Share;
using Newtonsoft.Json;
namespace IRaCIS.Core.Application.ViewModel
{
/// <summary> UserLogView 列表视图模型 </summary>
@@ -13,7 +14,7 @@ namespace IRaCIS.Core.Application.ViewModel
public string IP { get; set; }
public string ActionUserType { get; set; }
public int OptType { get; set; }
public UserOptType OptType { get; set; }
public string? ActionUserName { get; set; }
@@ -26,10 +27,14 @@ namespace IRaCIS.Core.Application.ViewModel
public bool IsLoginUncommonly { get; set; }
public bool IsIgnoreUncommonly { get; set; }
public string JsonObj { get; set; }
public string IPRegion { get; set; }
[JsonIgnore]
public UserLogJsonObj UserObj => JsonObj.IsNotNullOrEmpty() ? JsonConvert.DeserializeObject<UserLogJsonObj>(JsonObj) :new UserLogJsonObj();
}
public class SendMfaCommand
@@ -39,29 +44,41 @@ namespace IRaCIS.Core.Application.ViewModel
public UserMFAType MFAType { get; set; } = UserMFAType.Login;
}
public class SetIsIgnoreUncommonlyInDto
{
public Guid Id { get; set; }
public bool IsIgnoreUncommonly { get; set; }
}
///<summary>UserLogQuery 列表查询参数模型</summary>
public class UserLogQuery : PageInput
{
public Guid? TrialId { get; set; }
public UserOptType? OptType { get; set; }
public List<UserOptType>? OptTypeList { get; set; }
public List<UserOptType> OptTypeList { get; set; } = new List<UserOptType>();
public string? IP { get; set; }
public string? LoginFaildName { get; set; }
public string? LoginUserName { get; set; }
public DateTime? BeginDate { get; set; }
public DateTime? EndDate { get; set; }
public UserTypeEnum? LoginUserTypeEnum { get; set; }
public string? LoginUserType { get; set; }
public Guid? UserTypeId { get; set; }
public Guid? IdentityUserId { get; set; }
public Guid? TargetIdentityUserId { get; set; }
public bool? IsLoginUncommonly { get; set; }
}
@@ -311,6 +311,8 @@ namespace IRaCIS.Application.Contracts
public DateTime? BeginLastChangePassWordTime { get; set; }
public DateTime? EndLastChangePassWordTime { get; set; }
public UserCeateSource? UserCeateSource { get; set; }
}
public class UserRoleInfoDTO
@@ -336,6 +338,18 @@ namespace IRaCIS.Application.Contracts
public DateTime? LastChangePassWordTime { get; set; }
public List<IdentityUserTypeDTO> UserRoleList { get; set; }
#region
public UserCeateSource UserCeateSource { get; set; }
public Guid? TrialId { get; set; }
public string TrialCode { get; set; }
public string ResearchProgramNo { get; set; }
#endregion
}
@@ -53,7 +53,7 @@ namespace IRaCIS.Core.Application.Contracts
public string PermissionStr { get; set; } = string.Empty;
public int Order { get; set; }
public bool IsEnable { get; set; }
public List<Guid> UserTypeGroupIdList { get; set; } = new List<Guid>();
@@ -93,6 +93,16 @@ namespace IRaCIS.Core.Application.Contracts
}
public class UserTypeSelectDto
{
public bool IsDeleted { get; set; }
public Guid UserTypeId { get; set; }
public string UserTypeShortName { get; set; } = string.Empty;
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
}
public class UserTypeSimpleDTO
{
public Guid Id { get; set; }
@@ -10,7 +10,7 @@ namespace IRaCIS.Core.Application.Service
//Task<IResponseOutput> DeleteUser(Guid userId);
//Task<UserDetailDTO> GetUser(Guid id);
Task<PageOutput<UserListDTO>> GetUserList(UserListQueryDTO param);
Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password);
//Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password);
Task<IResponseOutput> VerifyMFACodeAsync(string Code);
Task<IResponseOutput> SendMFAEmail(SendMfaCommand sendMfa);
@@ -87,6 +87,8 @@ namespace IRaCIS.Core.Application.Service
addOrEditUserFeedBack.TrialSiteId = info.TrialSiteId;
addOrEditUserFeedBack.SubjectVisitId = info.SourceSubjectVisitId;
}
addOrEditUserFeedBack.State = 0;//设置解决后IR 更新反馈自动变为未解决
}
else if (addOrEditUserFeedBack.SubjectVisitId != null)
@@ -37,7 +37,7 @@ namespace IRaCIS.Core.Application.Service
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig,
IRepository<IdentityUser> _identityUserRepository,
IRepository<Doctor> _doctorRepository,
ISearcher _searcher, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IUserService
{
@@ -182,6 +182,13 @@ namespace IRaCIS.Core.Application.Service
await VerifyUserEmailAsync(_userInfo.IdentityUserId, newEmail);
// 修改用户邮箱的时候 需要修改医生表的邮箱
var oldEmail = await _identityUserRepository.Where(t => t.Id == _userInfo.IdentityUserId).Select(t => t.EMail).FirstOrDefaultAsync();
await _doctorRepository.UpdatePartialFromQueryAsync(x => x.EMail == oldEmail, u => new Doctor()
{
EMail = newEmail
});
await _identityUserRepository.UpdatePartialFromQueryAsync(_userInfo.IdentityUserId, u => new IdentityUser()
{
@@ -327,14 +334,21 @@ namespace IRaCIS.Core.Application.Service
}
////查找改邮箱或者手机的用户
var exist = await _identityUserRepository.AnyAsync(t => t.EMail == email && t.Status == UserStateEnum.Enable);
var existUser = await _identityUserRepository.Where(t => t.EMail == email && t.Status == UserStateEnum.Enable).FirstOrDefaultAsync();
if (!exist)
if (existUser == null)
{
//---邮箱错误。
return ResponseOutput.NotOk(_localizer["User_EmailError"]);
}
else
{
if (existUser.IsFirstAdd && existUser.UserName.IsNullOrEmpty())
{
return ResponseOutput.NotOk(_localizer["User_Notinitialized"]);
}
}
//验证码 6位
@@ -407,6 +421,7 @@ namespace IRaCIS.Core.Application.Service
await _identityUserRepository.UpdatePartialFromQueryAsync(t => t.Id == identityUserId, u => new IdentityUser()
{
Password = newPwd,
LastChangePassWordTime = DateTime.Now,
IsFirstAdd = false
});
@@ -452,6 +467,7 @@ namespace IRaCIS.Core.Application.Service
var success = await _identityUserRepository.BatchUpdateNoTrackingAsync(t => t.Id == _userInfo.IdentityUserId, u => new IdentityUser()
{
Password = editPwModel.NewPassWord,
LastChangePassWordTime = DateTime.Now,
IsFirstAdd = false
});
@@ -498,6 +514,7 @@ namespace IRaCIS.Core.Application.Service
.WhereIf(inQuery.UserState != null, t => t.Status == inQuery.UserState)
.WhereIf(inQuery.IsTestUser != null, t => t.IsTestUser == inQuery.IsTestUser)
.WhereIf(inQuery.IsZhiZhun != null, t => t.IsZhiZhun == inQuery.IsZhiZhun)
.WhereIf(inQuery.UserCeateSource != null, t => t.UserCeateSource == inQuery.UserCeateSource)
.ProjectTo<UserListDTO>(_mapper.ConfigurationProvider);
return await userQueryable.ToPagedListAsync(inQuery);
@@ -518,7 +535,7 @@ namespace IRaCIS.Core.Application.Service
if (user != null)
{
user.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToListAsync();
user.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).OrderBy(t => t.UserTypeShortName).ToListAsync();
}
return user;
@@ -563,7 +580,7 @@ namespace IRaCIS.Core.Application.Service
saveItem.OrganizationName = organizationName;
}
saveItem.UserCeateSource = UserCeateSource.AdminCreate;
saveItem.Password = MD5Helper.Md5(IRCEmailPasswordHelper.GenerateRandomPassword(10));
var addRoleList = new List<UserRole>();
@@ -810,7 +827,7 @@ namespace IRaCIS.Core.Application.Service
{
//删除验证码历史记录
await _verificationCodeRepository.BatchDeleteNoTrackingAsync(t => t.Id == verificationRecord.Id);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionUserName = _userInfo.UserName, TargetIdentityUserId = identityUserId, OptType = UserOptType.MFALogin }, true);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionUserName = _userInfo.UserName, ActionIdentityUserId = identityUserId, OptType = UserOptType.MFALogin }, true);
}
}
@@ -819,114 +836,15 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 用户登陆
/// 设置是否忽略异地登录
/// </summary>
/// <param name="userName"></param>
/// <param name="password"></param>
/// <param name="inDto"></param>
/// <returns></returns>
[NonDynamicMethod]
public async Task<IResponseOutput<LoginReturnDTO>> Login(string userName, string password)
[HttpPost]
public async Task<IResponseOutput> SetIsIgnoreUncommonly(SetIsIgnoreUncommonlyInDto inDto)
{
int maxFailures = _verifyConfig.CurrentValue.LoginMaxFailCount;
int lockoutMinutes = _verifyConfig.CurrentValue.LoginFailLockMinutes;
// 生成缓存键
string cacheKey = CacheKeys.UserLoginError(userName);
// 从缓存中获取登录失败次数
int? failCount = await _fusionCache.GetOrDefaultAsync<int?>(cacheKey);
if (failCount == null)
{
failCount = 0;
}
//每次登录 都重置缓存时间
await _fusionCache.SetAsync<int?>(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes));
if (failCount >= maxFailures)
{
//await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = Guid.Empty, OptUserId = Guid.Empty, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountLocked }, true);
//$"密码连续错误{maxFailures}次,当前账号已被限制登录,请等待 {lockoutMinutes} 分钟后再试。"
throw new BusinessValidationFailedException(_localizer["User_ErrorLimit", maxFailures, lockoutMinutes]);
}
var userLoginReturnModel = new LoginReturnDTO();
var loginUser = await _userRoleRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
if (loginUser == null)
{
//错误次数累加
failCount++;
await _fusionCache.SetAsync(cacheKey, failCount, TimeSpan.FromMinutes(lockoutMinutes));
var errorPwdUserId = await _identityUserRepository.Where(u => u.UserName == userName).Select(t => t.Id).FirstOrDefaultAsync();
//await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = errorPwdUserId, OptUserId = errorPwdUserId, LoginFaildName = userName, LoginPassword = password, OptType = UserOptType.AccountOrPasswordError }, true);
return ResponseOutput.NotOk(_localizer["User_CheckNameOrPw"], new LoginReturnDTO());
}
if (loginUser.Status == 0)
{
//await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = loginUser.IdentityUserId, OptUserId = loginUser.IdentityUserId, LoginFaildName = userName, OptType = UserOptType.LoginLockedAccount }, true);
//---该用户已经被禁用。
return ResponseOutput.NotOk(_localizer["User_Disabled"], new LoginReturnDTO());
}
//登录成功 清除缓存
await _fusionCache.SetAsync(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes));
var ipinfo = _searcher.Search(_userInfo.IP);
var iPRegion = string.Join('|', ipinfo.Split('|').TakeLast(3));
if (loginUser.LastLoginIP != string.Empty)
{
// 与上一次IP不一致
if (loginUser.LastLoginIP != iPRegion)
{
loginUser.LoginState = 2;
}
}
//超过90天没修改密码
if (_verifyConfig.CurrentValue.IsNeedChangePassWord && loginUser.LastChangePassWordTime != null && DateTime.Now.AddDays(-_verifyConfig.CurrentValue.ChangePassWordDays) > loginUser.LastChangePassWordTime.Value)
{
loginUser.NeedChangePassWord = true;
}
//await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, LoginUserId = loginUser.IdentityUserId, OptUserId = loginUser.IdentityUserId, OptType = UserOptType.Login }, true);
userLoginReturnModel.BasicInfo = loginUser;
if (loginUser.LastChangePassWordTime == null)
{
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastChangePassWordTime = DateTime.Now
});
}
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == loginUser.IdentityUserId, x => new IdentityUser()
{
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
return ResponseOutput.Ok(userLoginReturnModel);
await _userLogRepository.UpdatePartialFromQueryAsync(inDto.Id, x => new UserLog() { IsIgnoreUncommonly = inDto.IsIgnoreUncommonly }, true);
return ResponseOutput.Ok();
}
[HttpPost]
@@ -934,25 +852,41 @@ namespace IRaCIS.Core.Application.Service
{
DateTime? trialCreateTime = inQuery.TrialId != null ? _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => t.CreateTime).FirstOrDefault() : null;
var userLogQueryable =
_userLogRepository.AsQueryable().IgnoreQueryFilters()
.WhereIf(inQuery.IdentityUserId != null, t => t.ActionIdentityUserId == inQuery.IdentityUserId || t.TargetIdentityUserId == inQuery.IdentityUserId)
.WhereIf(inQuery.OptTypeList.Count()>0, t => inQuery.OptTypeList.Contains(t.OptType))
.WhereIf(inQuery.IdentityUserId != null, t => t.ActionIdentityUserId == inQuery.IdentityUserId)
.WhereIf(inQuery.TargetIdentityUserId != null, t => t.TargetIdentityUserId == inQuery.TargetIdentityUserId)
.WhereIf(inQuery.TrialId != null, t => t.ActionIdentityUser.UserTrialList.Any(c => c.TrialId == inQuery.TrialId) || t.TargetIdentityUser.UserTrialList.Any(c => c.TrialId == inQuery.TrialId))
.WhereIf(trialCreateTime != null, t => t.CreateTime >= trialCreateTime)
.WhereIf(inQuery.OptType != null, t => t.OptType == inQuery.OptType)
.WhereIf(inQuery.OptTypeList != null && inQuery.OptTypeList.Count > 0, t => inQuery.OptTypeList.Contains(t.OptType))
.WhereIf(inQuery.BeginDate != null, t => t.CreateTime >= inQuery.BeginDate)
.WhereIf(inQuery.EndDate != null, t => t.CreateTime <= inQuery.EndDate)
.WhereIf(inQuery.IsLoginUncommonly != null, t => t.IsLoginUncommonly == inQuery.IsLoginUncommonly)
.WhereIf(inQuery.IsLoginUncommonly != null && inQuery.IsLoginUncommonly.Value, t => t.IsLoginUncommonly&&!t.IsIgnoreUncommonly)
.WhereIf(inQuery.IsLoginUncommonly != null && !inQuery.IsLoginUncommonly.Value, t => !t.IsLoginUncommonly || t.IsIgnoreUncommonly)
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginUserName), t => t.ActionUserName.Contains(inQuery.LoginUserName!))
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginFaildName), t => t.ActionUserName.Contains(inQuery.LoginFaildName!))
.WhereIf(!string.IsNullOrEmpty(inQuery.IP), t => t.IP.Contains(inQuery.IP!))
.WhereIf(inQuery.LoginUserTypeEnum != null, t => t.CreateUserRole.UserTypeEnum == inQuery.LoginUserTypeEnum)
.WhereIf(!string.IsNullOrEmpty(inQuery.LoginUserType), t => t.ActionUserType == inQuery.LoginUserType)
.WhereIf(inQuery.UserTypeId != null, t => t.CreateUserRole.UserTypeId == inQuery.UserTypeId)
.ProjectTo<UserLogView>(_mapper.ConfigurationProvider);
var pageList = await userLogQueryable.ToPagedListAsync(inQuery);
//项目创建账户的时候,没有用户名,但是目标用户Id 有值,导致查询出来有名字,所以在此单独处理下
foreach (var item in pageList.CurrentPageData)
{
if (item.OptType == UserOptType.AddUser)
{
item.TargetIdentityUserName = item.UserObj.UserName;
}
}
return pageList;
}
@@ -1023,9 +957,9 @@ namespace IRaCIS.Core.Application.Service
var userLoginReturnModel = new IRCLoginReturnDTO();
var loginUser = await _identityUserRepository.Where(u => u.UserName.Equals(userName) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
var loginUser = await _identityUserRepository.Where(u => (u.UserName.Equals(userName) || u.EMail.Equals(userName)) && u.Password == password).ProjectTo<UserBasicInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
var existUserLoginInfo = await _identityUserRepository.Where(u => u.UserName == userName).Select(t => new { t.LastLoginIP, t.LastChangePassWordTime, t.Id }).FirstOrDefaultAsync();
var existUserLoginInfo = await _identityUserRepository.Where(u => u.UserName == userName || u.EMail == userName).Select(t => new { t.LastLoginIP, t.LastChangePassWordTime, t.Id }).FirstOrDefaultAsync();
var isExistAccount = existUserLoginInfo != null;
@@ -1036,31 +970,35 @@ namespace IRaCIS.Core.Application.Service
//账号在系统存在
if (isExistAccount || loginUser != null)
{
var ipinfo = _searcher.Search(_userInfo.IP);
//var ipinfo = _searcher.Search(_userInfo.IP);
var iPRegion = string.Join('|', ipinfo.Split('|').TakeLast(3));
//var iPRegion = string.Join('|', ipinfo.Split('|').TakeLast(3));
string SplitAndConcatenate(string input)
//string SplitAndConcatenate(string input)
//{
// string[] parts = input.Split('|');
// return parts.Length >= 3 ? parts[0] + parts[1] : string.Join("", parts);
//}
var iPRegion = IPCityHelper.GetCityResponse(_userInfo.IP);
//设置本次登录的IP
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == existUserLoginInfo.Id, x => new IdentityUser()
{
string[] parts = input.Split('|');
return parts.Length >= 3 ? parts[0] + parts[1] : string.Join("", parts);
}
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
if (existUserLoginInfo.LastLoginIP != string.Empty)
{
// 与上一次区域不一致
if (SplitAndConcatenate(existUserLoginInfo.LastLoginIP) != SplitAndConcatenate(iPRegion))
//if (SplitAndConcatenate(existUserLoginInfo.LastLoginIP) != SplitAndConcatenate(iPRegion))
if (existUserLoginInfo.LastLoginIP != iPRegion)
{
isLoginUncommonly = true;
//设置上次登录的IP
await _identityUserRepository.BatchUpdateNoTrackingAsync(x => x.Id == existUserLoginInfo.Id, x => new IdentityUser()
{
LastLoginIP = iPRegion,
LastLoginTime = DateTime.Now
});
if (loginUser != null)
{
@@ -1095,13 +1033,10 @@ namespace IRaCIS.Core.Application.Service
}
//登录成功的,才会算异地登录
if (loginUser.Status == 0)
{
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = userName, OptType = UserOptType.LoginLockedAccount, IsLoginUncommonly = isLoginUncommonly }, true);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = loginUser.UserName, OptType = UserOptType.LoginLockedAccount, IsLoginUncommonly = isLoginUncommonly }, true);
//---该用户已经被禁用。
return ResponseOutput.NotOk(_localizer["User_Disabled"], new IRCLoginReturnDTO());
@@ -1111,7 +1046,7 @@ namespace IRaCIS.Core.Application.Service
await _fusionCache.SetAsync(cacheKey, 0, TimeSpan.FromMinutes(lockoutMinutes));
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, OptType = UserOptType.Login, IsLoginUncommonly = isLoginUncommonly }, true);
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = loginUser.IdentityUserId, ActionUserName = loginUser.UserName, OptType = UserOptType.Login, IsLoginUncommonly = isLoginUncommonly }, true);
userLoginReturnModel.BasicInfo = loginUser;
@@ -1167,7 +1102,7 @@ namespace IRaCIS.Core.Application.Service
await _fusionCache.SetAsync(CacheKeys.UserAutoLoginOut(identityUserId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromMinutes(_verifyConfig.CurrentValue.AutoLoginOutMinutes));
userLoginReturnModel.BasicInfo.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).ToListAsync();
userLoginReturnModel.BasicInfo.AccountList = await _userRoleRepository.Where(t => t.IdentityUserId == identityUserId).ProjectTo<UserAccountInfo>(_mapper.ConfigurationProvider).OrderBy(t => t.UserTypeShortName).ToListAsync();
userLoginReturnModel.CompanyInfo = companyInfo;
@@ -20,6 +20,7 @@ namespace IRaCIS.Core.Application.Contracts
{
var userTypeRoleQueryable = _userTypeRepository
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.IsEnable == true)
.WhereIf(!string.IsNullOrWhiteSpace(userTypeQuery.SearchFilter), t => t.Description.Contains(userTypeQuery.SearchFilter!) || t.UserTypeName.Contains(userTypeQuery.SearchFilter!) || t.UserTypeShortName.Contains(userTypeQuery.SearchFilter!))
.WhereIf(userTypeQuery.GroupId != null, t => t.UserTypeGroupList.Any(t => t.DictionaryId == userTypeQuery.GroupId))
@@ -140,7 +141,7 @@ namespace IRaCIS.Core.Application.Contracts
var query = _userTypeRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)
var query = _userTypeRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin && x.IsEnable==true)
.WhereIf(userTypeSelectEnum != UserTypeSelectEnum.None, t => userTypeEnums.Contains(t.UserTypeEnum))
.OrderBy(t => t.UserTypeShortName).ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
@@ -158,7 +159,8 @@ namespace IRaCIS.Core.Application.Contracts
public async Task<List<TrialUserType>> GetTrialUserTypeList()
{
//排除其他组的用户
var query = _userTypeRepository.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin)
var query = _userTypeRepository
.Where(x => x.UserTypeEnum != UserTypeEnum.SuperAdmin && x.IsEnable==true)
.Where(t => !t.UserTypeGroupList.Any(t => t.Group.Code == "3"))
.OrderBy(t => t.UserTypeShortName).ProjectTo<TrialUserType>(_mapper.ConfigurationProvider);
@@ -152,7 +152,9 @@ namespace IRaCIS.Core.Application.Service
CreateMap<IdentityUser, UserBasicInfo>()
.ForMember(d => d.IdentityUserId, c => c.MapFrom(t => t.Id));
CreateMap<IdentityUser, UserListDTO>();
CreateMap<IdentityUser, UserListDTO>()
.ForMember(d => d.TrialCode, u => u.MapFrom(s => s.Trial.TrialCode))
.ForMember(d => d.ResearchProgramNo, u => u.MapFrom(s => s.Trial.ResearchProgramNo));
CreateMap<UserAddUserType, UserRole>().ReverseMap();
@@ -172,7 +174,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<UpdateTrialUserCommand, TrialIdentityUser>();
}
@@ -6,14 +6,9 @@
namespace IRaCIS.Core.Application.Contracts
{
/// <summary> NoneDicomStudyFileView 列表视图模型 </summary>
public class NoneDicomStudyFileView
public class NoneDicomStudyFileView: NoneDicomStudyFileAddOrEdit
{
public Guid Id { get; set; }
public string Path { get; set; } = string.Empty;
public string FileName { get; set; } = string.Empty;
public DateTime CreateTime { get; set; }
public Guid CreateUserId { get; set; }
public Guid NoneDicomStudyId { get; set; }
public long? FileSize { get; set; }
@@ -21,7 +16,9 @@ namespace IRaCIS.Core.Application.Contracts
public string FileType { get; set; }
public bool IsReading { get; set; }
public bool IsDeleted { get; set; }
}
@@ -33,24 +30,9 @@ namespace IRaCIS.Core.Application.Contracts
public string AuditInfo { get; set; } = string.Empty;
}
public class NoneDicomStudyAndFile
{
public string NoneDicomStudyCode { get; set; } = string.Empty;
public List<NoneDicomStudyFileView> NoneDicomStudyFileList { get; set; } = new List<NoneDicomStudyFileView>();
}
///<summary>NoneDicomStudyFileQuery 列表查询参数模型</summary>
public class NoneDicomStudyFileQuery
{
///<summary> Path</summary>
public string Path { get; set; } = string.Empty;
///<summary> FileName</summary>
public string FileName { get; set; } = string.Empty;
}
///<summary> NoneDicomStudyFileAddOrEdit 列表查询参数模型</summary>
public class NoneDicomStudyFileAddOrEdit
@@ -8,19 +8,25 @@ namespace IRaCIS.Core.Application.Contracts
/// <summary> NoneDicomStudyView 列表视图模型 </summary>
public class NoneDicomStudyView : NoneDicomStudyAddOrEdit
{
public DateTime CreateTime { get; set; }
public DateTime UpdateTime { get; set; }
public string CodeView { get; set; }
public int FileCount { get; set; }
public bool IsCriticalSequence { get; set; } = false;
public List<NoneDicomStudyFileView> NoneDicomStudyFileList { get; set; } = new List<NoneDicomStudyFileView>();
public bool IsReading { get; set; }
public bool IsDeleted { get; set; }
}
public class TaskDicomStudyView : NoneDicomStudyView
{
}
///<summary>NoneDicomStudyQuery 列表查询参数模型</summary>
@@ -51,8 +57,7 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime ImageDate { get; set; }
public string Description { get; set; } = string.Empty;
public int Code { get; set; }
public string StudyName { get; set; }
public string VideoName { get; set; } = string.Empty;
@@ -18,6 +18,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public int Type { get; set; }
public string StudyName { get; set; } = String.Empty;
public string Modality { get; set; } = String.Empty;
public string BodyPart { get; set; } = String.Empty;
@@ -353,8 +355,13 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public int? NotClosedChallengeCount { get; set; }
public List<StudyName> StudyNameList { get; set; }
public List<string> ImageFormatList { get; set; }
public bool IsShowStudyName { get; set; } = false;
}
public class QAStudyInfoDTO
{
@@ -382,10 +389,15 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public DateTime? StudyTime { get; set; }
public DateTime? UploadedTime { get; set; }
public DateTime UpdateTime { get; set; }
public string BodyPartExamined { get; set; } = String.Empty;
public string BodyPartForEdit { get; set; } = String.Empty;
public string StudyName { get; set; } = string.Empty;
public string ModalityForEdit { get; set; } = string.Empty;
public bool IsHaveUploadFailed { get; set; }
@@ -422,6 +434,8 @@ namespace IRaCIS.Core.Application.Contracts.DTO
//public Guid[] InstanceList = new Guid[0];
//public List<string> InstancePathList = new List<string>();
public DateTime UpdateTime { get; set; }
}
@@ -81,6 +81,11 @@ namespace IRaCIS.Core.Application.Contracts
public Guid? SubjectId { get; set; }
public Guid? VisitId { get; set; }
/// <summary>
/// 是否领取了
/// </summary>
public bool IsReceived { get; set; } = false;
}
public class CRCRequestToQCCommand
@@ -161,6 +166,13 @@ namespace IRaCIS.Core.Application.Contracts
[Comment("阅片任务产生之前 采集影像")]
public CollectImagesType CollectImagesEnum { get; set; }
public List<StudyName> StudyNameList { get; set; }
public List<string> ImageFormatList { get; set; }
public bool IsShowStudyName { get; set; } = false;
}
@@ -1211,6 +1223,8 @@ namespace IRaCIS.Core.Application.Contracts
public Guid Id { get; set; }
public Guid SubjectId { get; set; }
public Guid? DoctorUserId { get; set; }
public string TaskName { get; set; }
@@ -1265,6 +1279,17 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime? SignTime { get; set; }
#endregion
#region
[DictionaryTranslateAttribute("OncologyAssessType")]
public string OncologyResult { get; set; } = string.Empty;
public string OncologyReason { get; set; } = string.Empty;
public string OncologyUserName { get; set; }
#endregion
}
public class CommonLessionExport : CommonEvaluationExport
@@ -2083,6 +2108,7 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime? ReviewAuditTime { get; set; }
public DateTime? PreliminaryAuditTime { get; set; }
public ImageBackStateEnum ImageBackState { get; set; }
public DateTime? AuditTime => QCProcessEnum == TrialQCProcess.SingleAudit ? PreliminaryAuditTime : (QCProcessEnum == TrialQCProcess.DoubleAudit ? ReviewAuditTime : null);
}
@@ -1,6 +1,7 @@
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MassTransit.Initializers;
@@ -279,7 +280,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<(PageOutput<QCCheckWithModalityView>, TrialSubjectAndSVConfig)> GetConsistencyVerificationList(CheckQuery inQuery)
public async Task<IResponseOutput<PageOutput<QCCheckWithModalityView>>> GetConsistencyVerificationList(CheckQuery inQuery)
{
var svExpression = QCCommon.GetSubjectVisitFilter(inQuery.VisitPlanArray);
@@ -294,9 +295,14 @@ namespace IRaCIS.Core.Application.Image.QA
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.UserRoleId))//CRC 过滤负责的site
.ProjectTo<QCCheckWithModalityView>(_mapper.ConfigurationProvider);
var pageList = await query.ToPagedListAsync(inQuery);
var defalutSortArray = new string[] { nameof(QCCheckWithModalityView.CheckState), nameof(QCCheckWithModalityView.IsUrgent), nameof(QCCheckWithModalityView.SubjectCode), nameof(QCCheckWithModalityView.VisitNum) };
var pageList = await query.ToPagedListAsync(inQuery, defalutSortArray);
var config = await _trialRepository.Where(t => t.Id == inQuery.TrialId).ProjectTo<TrialSubjectAndSVConfig>(_mapper.ConfigurationProvider).FirstOrDefaultAsync().IfNullThrowException();
return (pageList, config);
return ResponseOutput.Ok(pageList, config);
}
/// <summary>
@@ -374,7 +380,7 @@ namespace IRaCIS.Core.Application.Image.QA
ExistsManual = (await _IReadingImageTaskService.GetManualList(new GetManualListInDto() { TrialId = sv.TrialId })).Count() > 0,
SeriesList = temp.SeriesList,
RelationInfo = await GetVisitQCSubjectInfo(subjectVisitId),
NoneDicomStudyList = await _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId).ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider).ToListAsync(),
NoneDicomStudyList = await _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId,ignoreQueryFilters:true).ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider).ToListAsync(),
SubjectClinicalData = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
.ProjectTo<SubjectClinicalDataDto>(_mapper.ConfigurationProvider, new { subjectVisitId = subjectVisitId, token = _userInfo.UserToken }).FirstOrDefaultAsync()
};
@@ -402,9 +408,9 @@ namespace IRaCIS.Core.Application.Image.QA
ParentTriggerValue = data.ParentTriggerValue,
Type = data.Type,
TypeValue = data.TypeValue
}).ToListAsync();
}).OrderBy(t => t.ShowOrder).ToListAsync();
var result = questionAnswerlist.Where(x => x.ParentId == null).ToList();
var result = questionAnswerlist.Where(x => x.ParentId == null).OrderBy(t=>t.ShowOrder).ToList();
result.ForEach(x =>
{
GetQuestionChild(x, questionAnswerlist);
@@ -416,7 +422,7 @@ namespace IRaCIS.Core.Application.Image.QA
private void GetQuestionChild(QCQuestionAnswer parent, List<QCQuestionAnswer> dataList)
{
parent.Childrens = dataList.Where(x => x.ParentId == parent.Id).ToList();
parent.Childrens = dataList.Where(x => x.ParentId == parent.Id).OrderBy(t => t.ShowOrder).ToList();
if (parent.Childrens.Count != 0)
{
@@ -519,9 +525,16 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpGet("{subjectVisitId:guid}")]
public async Task<IResponseOutput<List<QAStudyInfoDTO>>> GetSubjectVisitUploadedStudyList(Guid subjectVisitId)
{
var qcAuditState = await _subjectVisitRepository.Where(s => s.Id == subjectVisitId).Select(t => t.AuditState).FirstOrDefaultAsync();
//质控过程中,因为会修改统计数字,但是此时其他人看,应该看到完整的影像
var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
var isNeedStat = _userInfo.UserTypeEnumInt != (int)UserTypeEnum.IQC && !isQCFinished;
var visit = await _subjectVisitRepository.Where(x => x.Id == subjectVisitId).FirstNotNullAsync();
var list = await _dicomStudyRepository.Where(s => s.SubjectVisitId == subjectVisitId).IgnoreQueryFilters().ProjectTo<QAStudyInfoDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.StudyCode).ToListAsync();
var list = await _dicomStudyRepository.Where(s => s.SubjectVisitId == subjectVisitId).IgnoreQueryFilters().ProjectTo<QAStudyInfoDTO>(_mapper.ConfigurationProvider,new { isNeedStat= isNeedStat }).OrderBy(t => t.StudyCode).ToListAsync();
var config = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => t.Trial).ProjectTo<TrialSubjectAndSVConfig>(_mapper.ConfigurationProvider).FirstOrDefaultAsync().IfNullThrowException();
@@ -530,7 +543,7 @@ namespace IRaCIS.Core.Application.Image.QA
config.IsPacsConnectConfiged = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).AnyAsync(t => t.Trial.IsPACSConnect && t.Subject.TrialSite.TrialSiteDicomAEList.Any());
return ResponseOutput.Ok (list, config);
return ResponseOutput.Ok(list, config);
}
@@ -3,6 +3,7 @@ using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
@@ -33,8 +34,12 @@ namespace IRaCIS.Core.Application.Image.QA
IRepository<ReadModule> _readModuleRepository,
IRepository<DicomInstance> _dicomInstanceRepository,
IRepository<TrialQCQuestionAnswer> _trialQCQuestionAnswerRepository,
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IDistributedLockProvider _distributedLockProvider, IReadingClinicalDataService _readingClinicalDataService,
IDistributedLockProvider _distributedLockProvider, IReadingClinicalDataService _readingClinicalDataService,
IOSSService _oSSService,
IRepository<ReadingClinicalData> _readingClinicalDataReposiotry,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService, IQCOperationService
{
@@ -43,7 +48,7 @@ namespace IRaCIS.Core.Application.Image.QA
#region QC质疑
[HttpGet("{trialId:guid}/{subjectVisitId:guid}/{currentQCType:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> VerifyQCCanAddChallenge(Guid subjectVisitId, [FromRoute] CurrentQC currentQCType)
{
@@ -67,7 +72,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="currentQCType"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> AddOrUpdateQCChallenge(QCChallengeCommand qaQuestionCommand, Guid trialId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
{
@@ -126,7 +131,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPut]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> CloseQCChallenge(CloseQCChallengeInDto input)
@@ -181,7 +186,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> DeleteQCChallenge(Guid qcChallengeId)
{
@@ -209,7 +214,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="qaDialogCommand"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
// [Authorize(Policy = IRaCISPolicy.CRC_IQC)]
public async Task<IResponseOutput> AddQCChallengeReply(QADialogCommand qaDialogCommand)
{
@@ -236,6 +241,137 @@ namespace IRaCIS.Core.Application.Image.QA
#endregion
#region CRC IQC 退
/// <summary>
/// CRC IQC 申请影像回退
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPut]
public async Task<IResponseOutput> RequestImageBack(Guid subjectVisitId)
{
if (!_subjectVisitRepository.Any(t => t.Id == subjectVisitId && t.CheckState < CheckStateEnum.CVPassed && t.SubmitState == SubmitStateEnum.Submitted))
{
//一致性核查通过前已提交的影像才允许进行回退
throw new BusinessValidationFailedException(_localizer["QCOperation_ShouldBeforeCheckPassed"]);
}
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator)
{
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { ImageBackState = ImageBackStateEnum.CRCRequestBack }, true);
}
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC)
{
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { ImageBackState = ImageBackStateEnum.IQCRequestBack }, true);
}
return ResponseOutput.Ok();
}
/// <summary>
/// PM 审核CRC IQC 申请影像回退
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="isAgree"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPut]
public async Task<IResponseOutput> AuditImageBack(Guid subjectVisitId, bool isAgree)
{
var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();
if (sv.ImageBackState != ImageBackStateEnum.CRCRequestBack && sv.ImageBackState != ImageBackStateEnum.IQCRequestBack)
{
//当前访视状态不在影像申请回退状态,不允许审核通过
throw new BusinessValidationFailedException(_localizer["QCOperation_NotInRequestImageBackState"]);
}
if (isAgree)
{
if (sv.SubmitState == SubmitStateEnum.Submitted && sv.CheckState < CheckStateEnum.CVPassed)
{
sv.ImageBackState = ImageBackStateEnum.PMAgreeBack;
}
else
{
//一致性核查通过前已提交的影像才允许进行回退
throw new BusinessValidationFailedException(_localizer["QCOperation_ShouldBeforeCheckPassed"]);
}
#region 退
//需要重新产生任务
sv.IsVisitTaskGenerated = false;
sv.IsPMBackOrReReading = true;
sv.AuditState = AuditStateEnum.None;
sv.SubmitState = SubmitStateEnum.ToSubmit;
sv.ReadingStatus = ReadingStatusEnum.ImageNotSubmit;
//回退后,回退状态恢复
sv.RequestBackState = RequestBackStateEnum.NotRequest;
sv.IsCheckBack = false;
sv.CheckBackTime = null;
sv.CheckState = CheckStateEnum.None;
sv.CheckChallengeState = CheckChanllengeTypeEnum.None;
sv.SVENDTC = null;
sv.SVSTDTC = null;
sv.PreliminaryAuditTime = null;
sv.SubmitTime = null;
sv.ReviewAuditTime = null;
sv.CurrentActionUserExpireTime = null;
sv.IsTake = false;
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
if (sv.IsBaseLine)
{
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && (t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.Subject || t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit), c => new ReadingClinicalData() { IsSign = false, ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded });
}
else
{
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit, c => new ReadingClinicalData()
{
IsSign = false,
ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded,
IsBlind = null,
IsComplete = null
});
}
await _trialQCQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisitId == subjectVisitId);
#endregion
}
else
{
sv.ImageBackState = ImageBackStateEnum.PMNotAgreeBack;
}
await _subjectVisitRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
#endregion
#region
/// <summary>
@@ -244,7 +380,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="checkDialogCommand"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.PM_APM_CRC)]
public async Task<IResponseOutput> AddCheckChallengeReply(CheckChallengeDialogCommand checkDialogCommand)
{
@@ -264,7 +400,7 @@ namespace IRaCIS.Core.Application.Image.QA
sv.CheckChallengeState = CheckChanllengeTypeEnum.CRCWaitPMReply;
}
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager || _userInfo.UserTypeEnumInt != (int)UserTypeEnum.APM)
else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.APM)
{
sv.CheckChallengeState = CheckChanllengeTypeEnum.PMWaitCRCReply;
}
@@ -284,7 +420,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPut("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
public async Task<IResponseOutput> CloseCheckChallenge(CloseCheckChallengeDto input)
{
@@ -320,7 +456,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPut("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
[UnitOfWork]
public async Task<IResponseOutput> SetCheckPass(SetCheckPassDt data)
@@ -367,7 +503,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="subjectVisitId"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> CRCRequstCheckBack(Guid subjectVisitId)
{
@@ -413,7 +549,7 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> RejectCheckBack(Guid subjectVisitId)
{
//if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.APM)
@@ -446,7 +582,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.PM_APM)]
[UnitOfWork]
public async Task<IResponseOutput> CheckBack(Guid subjectVisitId)
@@ -525,7 +661,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// 添加或者更新 QC核对问题列表 两个人不能同时操作,就算意外进去了,提交数据,也不会覆盖前一个人数据, 后台已经做好判断
/// </summary>
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> AddOrUpdateQCQuestionAnswerList(QCQuestionAnswerCommand[] qcQuestionAnswerCommands, Guid trialId, Guid subjectVisitId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
{
@@ -597,7 +733,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="state"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{studyId:guid}/{seriesId:guid}/{state:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> SetSeriesState(Guid subjectVisitId, Guid studyId, Guid seriesId, int state)
{
@@ -659,12 +795,139 @@ namespace IRaCIS.Core.Application.Image.QA
return ResponseOutput.Ok(await _dicomStudyRepository.SaveChangesAsync());
}
/// <summary>
/// 1、设置为不读片,2 设置为读片(取消 先前设置为不读片) 4 设置为删除(数据库记录软删除) 5 恢复为未删除
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="seriesId"></param>
/// <param name="instanceId"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{seriesId:guid}/{instanceId:guid}/{state:int}")]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SetInstanceState(Guid subjectVisitId, Guid seriesId, Guid instanceId, int state)
{
await VerifyIsCanQCAsync(null, subjectVisitId);
var instance = (await _dicomInstanceRepository.Where(t => t.Id == instanceId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
if (state == 1)
{
instance.IsReading = false;
}
else if (state == 2)
{
instance.IsReading = true;
}
else if (state == 4)
{
instance.IsDeleted = true;
var series = (await _dicomSeriesRepository.Where(t => t.Id == seriesId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
series.InstanceCount = series.InstanceCount - 1;
var study = (await _dicomStudyRepository.Where(t => t.Id == series.StudyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
study.InstanceCount = study.InstanceCount - 1;
}
else if (state == 5)
{
instance.IsDeleted = false;
var series = (await _dicomSeriesRepository.Where(t => t.Id == seriesId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
series.InstanceCount = series.InstanceCount + 1;
var study = (await _dicomStudyRepository.Where(t => t.Id == series.StudyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
study.InstanceCount = study.InstanceCount + 1;
}
return ResponseOutput.Ok(await _dicomStudyRepository.SaveChangesAsync());
}
/// <summary>
/// 1、设置为不读片,2 设置为读片(取消 先前设置为不读片) 4 设置为删除(数据库记录软删除) 5 恢复为未删除
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="noneDicomStudyId"></param>
/// <param name="noneDicomStudyFileId"></param>
/// <param name="state"></param>
/// <returns></returns>
[HttpPut]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SetNodicomStudyState(Guid subjectVisitId, Guid noneDicomStudyId, Guid? noneDicomStudyFileId, int state)
{
await VerifyIsCanQCAsync(null, subjectVisitId);
//设置检查
if (noneDicomStudyFileId == null)
{
var noneDicomStudy = (await _noneDicomStudyRepository.Where(t => t.Id == noneDicomStudyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
if (state == 1)
{
noneDicomStudy.IsReading = false;
}
else if (state == 2)
{
noneDicomStudy.IsReading = true;
}
else if (state == 4)
{
noneDicomStudy.IsDeleted = true;
}
else if (state == 5)
{
noneDicomStudy.IsDeleted = false;
}
}
//设置检查下面的文件
else
{
var noneDicomStudyFile = (await _noneDicomStudyFileRepository.Where(t => t.Id == noneDicomStudyFileId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();
if (state == 1)
{
noneDicomStudyFile.IsReading = false;
}
else if (state == 2)
{
noneDicomStudyFile.IsReading = true;
}
else if (state == 4)
{
noneDicomStudyFile.IsDeleted = true;
}
else if (state == 5)
{
noneDicomStudyFile.IsDeleted = false;
}
}
await _noneDicomStudyRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
///type 1 :study 2: series 3:非dicom QC修改检查部位和 拍片类型
/// </summary>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
// [Authorize(Policy = IRaCISPolicy.CRC_IQC)]
public async Task<IResponseOutput> UpdateModality(UpdateModalityCommand updateModalityCommand)
{
@@ -694,6 +957,8 @@ namespace IRaCIS.Core.Application.Image.QA
study.BodyPartForEdit = updateModalityCommand.BodyPart;
study.ModalityForEdit = updateModalityCommand.Modality;
study.StudyName = updateModalityCommand.StudyName;
await _dicomSeriesRepository.BatchUpdateNoTrackingAsync(t => t.StudyId == studyId, r => new DicomSeries() { BodyPartForEdit = updateModalityCommand.BodyPart });
}
@@ -744,7 +1009,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="trialId"></param>
/// <returns></returns>SeriesCount
[HttpPost, Route("{trialId:guid}/{subjectVisitId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
// [Authorize(Policy = IRaCISPolicy.CRC_IQC)]
public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId)
@@ -767,6 +1032,8 @@ namespace IRaCIS.Core.Application.Image.QA
await _dicomStudyRepository.DeleteAsync(study);
var fisrtPath = await _dicomInstanceRepository.Where(t => t.StudyId == id).Select(t => t.Path).FirstOrDefaultAsync();
var succeess2 = await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == id);
var success3 = await _dicomSeriesrepository.BatchDeleteNoTrackingAsync(t => t.StudyId == id);
@@ -774,6 +1041,9 @@ namespace IRaCIS.Core.Application.Image.QA
await _scpStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == id, u => new SCPStudy() { SubjectVisitId = null });
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
//var success3 = await _dicomSeriesrepository.DeleteFromQueryAsync(t => t.StudyId == id, true);
//var success4 = await _repository.BatchDeleteAsync<StudyMonitor>(t => t.StudyId == id);
@@ -848,7 +1118,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <summary>替换当前领取人 </summary>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> ReplaceQCTaskActionUser(Guid trialId, Guid subjectVisitId)
{
var dbSubjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();
@@ -882,7 +1152,7 @@ namespace IRaCIS.Core.Application.Image.QA
{
var nextIQCQuality = await this.GetNextIQCQuality(inDto);
if (nextIQCQuality.VisitId != null)
if (nextIQCQuality.VisitId != null && nextIQCQuality.IsReceived == false)
{
var visit = await _subjectVisitRepository.Where(x => x.Id == nextIQCQuality.VisitId).FirstNotNullAsync();
if (!visit.IsTake)
@@ -910,6 +1180,22 @@ namespace IRaCIS.Core.Application.Image.QA
.FirstOrDefaultAsync(t => t.TrialId == inDto.TrialId)
.IfNullThrowException();
var currentActionList = await _subjectVisitRepository.Where(x => x.TrialId == inDto.TrialId && x.CurrentActionUserId == _userInfo.UserRoleId).OrderByDescending(x => x.IsUrgent)
.ThenBy(x => x.Subject.Code).ThenBy(x => x.VisitNum).ToListAsync();
if (currentActionList.Count() > 0)
{
return new GetNextIQCQualityOutDto()
{
IsReceived = true,
SubjectId = currentActionList[0].SubjectId,
VisitId = currentActionList[0].Id,
};
}
SubjectVisit? subjectVisit = null;
List<SubjectVisit>? visitList = null;
switch (trialConfig.QCProcessEnum)
@@ -994,7 +1280,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="obtaionOrCancel">true 获取 false是取消领取</param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{obtaionOrCancel:bool}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> ObtainOrCancelQCTask(Guid trialId, Guid subjectVisitId, bool obtaionOrCancel)
{
@@ -1219,7 +1505,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// </summary>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> CRCRequestToQC(CRCRequestToQCCommand cRCRequestToQCCommand)
{
@@ -1507,7 +1793,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="auditState"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{subjectVisitId:guid}/{auditState:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
[UnitOfWork]
public async Task<IResponseOutput> QCPassedOrFailed(Guid trialId, Guid subjectVisitId, [FromRoute] AuditStateEnum auditState)
@@ -1543,8 +1829,11 @@ namespace IRaCIS.Core.Application.Image.QA
//删除 软删除的物理文件
var instancePathList = await _dicomInstanceRepository.Where(t => t.DicomSerie.IsDeleted && t.SubjectVisitId == subjectVisitId)
var instancePathList = await _dicomInstanceRepository.Where(t => (t.DicomSerie.IsDeleted || t.IsDeleted) && t.SubjectVisitId == subjectVisitId, false, true)
.Select(t => t.Path).ToListAsync();
var noneDicomFileList = await _noneDicomStudyFileRepository.Where(t => (t.NoneDicomStudy.IsDeleted || t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId, false, true)
.Select(t => t.Path).ToListAsync();
//维护统一状态
dbSubjectVisit.ReadingStatus = ReadingStatusEnum.ConsistencyCheck;
@@ -1582,17 +1871,15 @@ namespace IRaCIS.Core.Application.Image.QA
dbSubjectVisit.ReadingStatus = trialConfig.IsImageConsistencyVerification ? ReadingStatusEnum.ConsistencyCheck : ReadingStatusEnum.TaskAllocate;
//删除影像
instancePathList.ForEach(path =>
{
await _dicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => (t.DicomSerie.IsDeleted || t.IsDeleted) && t.SubjectVisitId == subjectVisitId);
await _noneDicomStudyFileRepository.BatchDeleteNoTrackingAsync(t => (t.NoneDicomStudy.IsDeleted || t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId);
await _noneDicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _oSSService.DeleteObjects(instancePathList.Select(t => t.TrimStart('/')).ToList());
await _oSSService.DeleteObjects(noneDicomFileList.Select(t => t.TrimStart('/')).ToList());
var physicalPath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, path);
if (System.IO.File.Exists(physicalPath))
{
File.Delete(physicalPath);
}
});
}
else
@@ -1646,18 +1933,10 @@ namespace IRaCIS.Core.Application.Image.QA
dbSubjectVisit.ReadingStatus = trialConfig.IsImageConsistencyVerification ? ReadingStatusEnum.ConsistencyCheck : ReadingStatusEnum.TaskAllocate;
//删除影像
instancePathList.ForEach(path =>
{
var physicalPath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, path);
if (System.IO.File.Exists(physicalPath))
{
File.Delete(physicalPath);
}
});
await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => (t.DicomSerie.IsDeleted || t.IsDeleted) && t.SubjectVisitId == subjectVisitId);
await _noneDicomStudyFileRepository.BatchDeleteNoTrackingAsync(t => (t.NoneDicomStudy.IsDeleted || t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId);
await _oSSService.DeleteObjects(instancePathList.Select(t => t.TrimStart('/')).ToList());
await _oSSService.DeleteObjects(noneDicomFileList.Select(t => t.TrimStart('/')).ToList());
}
else
{
@@ -1741,7 +2020,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="setOrCancel"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{setOrCancel:bool}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> SetVisitUrgent(Guid trialId, Guid subjectVisitId, bool setOrCancel)
{
@@ -1779,7 +2058,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="qcChallengeId"></param>
/// <returns></returns>
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.IQC)]
public async Task<IResponseOutput> SetNeedReupload(Guid trialId, Guid qcChallengeId)
{
@@ -1880,7 +2159,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> SetReuploadFinished(CRCReuploadFinishedCommand cRCReuploadFinishedCommand)
{
@@ -1993,7 +2272,7 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
//[Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> CRCRequestReUpload(Guid qcChallengeId)
{
@@ -2040,7 +2319,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <returns></returns>
[HttpPut("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> UpdateSubjectAndSVInfo(UploadSubjectAndVisitCommand command)
{
var dbSubjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == command.SubjectVisitId)).IfNullThrowException();
@@ -6,6 +6,7 @@ using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using NPOI.SS.Formula.Functions;
using System.Linq;
namespace IRaCIS.Core.Application.Service
@@ -257,7 +258,7 @@ namespace IRaCIS.Core.Application.Service
(arbitrationRule == ArbitrationRule.Reading ?
u.Subject.SubjectVisitTaskList.Any(t => t.TaskState == TaskState.Effect && t.IsAnalysisCreate == false && t.ReadingCategory == ReadingCategory.Judge && t.TrialReadingCriterionId == trialReadingCriterionId && u.VisitTaskNum < t.VisitTaskNum) :
false)))
.ForMember(o => o.JudgeNote, t => t.MapFrom(u => u.ReadingCategory == ReadingCategory.Judge ? u.JudgeResultRemark : u.JudgeVisitTask.JudgeResultRemark))
.ForMember(o => o.JudgeNote, t => t.MapFrom(u => u.ReadingCategory == ReadingCategory.Judge ? u.JudgeResultRemark : ""))
.ForMember(o => o.VisitNote, t => t.MapFrom(u => u.ReadingTaskQuestionAnswerList.Where(c => c.ReadingQuestionTrial.QuestionType == QuestionType.AdjustReason).FirstOrDefault()!.Answer))
//.ForMember(o => o.IsSubjectHaveReadingPeriod, t => t.MapFrom(u => arbitrationRule == ArbitrationRule.Reading ?
//u.Subject.ReadModuleList.Any(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.ReadingSetType == ReadingSetType.ImageReading) : false))
@@ -401,6 +402,10 @@ namespace IRaCIS.Core.Application.Service
bool isFilterZip = false;
bool isIgnoreDelete = false;
bool isReading = false;
string token = string.Empty;
//一致性核查
@@ -537,10 +542,12 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.MedicalNo, u => u.MapFrom(s => s.Subject.MedicalNo))
.ForMember(d => d.Sex, u => u.MapFrom(s => s.Subject.Sex))
.ForMember(d => d.Age, u => u.MapFrom(t => t.Subject.Age))
.ForMember(d => d.IsHaveClinicalData, u => u.MapFrom(t => t.PreviousHistoryList.Any() || t.PreviousOtherList.Any()
|| t.Subject.ClinicalFormList.Any(x => x.ClinicalDataTrialSet.UploadRole == UploadRole.CRC && x.ReadingId == t.Id)
|| t.ReadingClinicalDataList.Any(x => x.ClinicalDataTrialSet.UploadRole == Domain.Share.UploadRole.CRC && x.ReadingClinicalDataPDFList.Count > 0)
|| t.PreviousSurgeryList.Any()))
.ForMember(d => d.IsHaveClinicalData,
u => u.MapFrom(t => t.PreviousHistoryList.Any() ||
t.PreviousOtherList.Any() ||
t.Subject.ClinicalFormList.Any(x => x.ClinicalDataTrialSet.UploadRole == UploadRole.CRC && x.ReadingId == t.Id) ||
t.ReadingClinicalDataList.Any(x => x.ClinicalDataTrialSet.UploadRole == Domain.Share.UploadRole.CRC && x.ReadingClinicalDataPDFList.Count > 0) ||
t.PreviousSurgeryList.Any()))
.ForMember(d => d.IsHaveUploadFailed, u => u.MapFrom(t => t.StudyList.SelectMany(c => c.DicomStudyMonitorList).Any(h => h.FailedFileCount > 0)))
@@ -588,7 +595,10 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.SubjectFirstGiveMedicineTime, u => u.MapFrom(s => s.Subject.FirstGiveMedicineTime))
.ForMember(d => d.SiteName, u => u.MapFrom(s => s.TrialSite.TrialSiteName))
.ForMember(d => d.TotalChallengeCount, u => u.MapFrom(s => s.QCChallengeList.Count()))
.ForMember(d => d.NotClosedChallengeCount, u => u.MapFrom(s => s.QCChallengeList.Count(c => c.IsClosed == false)));
.ForMember(d => d.NotClosedChallengeCount, u => u.MapFrom(s => s.QCChallengeList.Count(c => c.IsClosed == false)))
.ForMember(d => d.IsShowStudyName, u => u.MapFrom(s => s.Trial.IsShowStudyName))
.ForMember(d => d.StudyNameList, u => u.MapFrom(s => s.Trial.StudyNameList))
.ForMember(d => d.ImageFormatList, u => u.MapFrom(s => s.Trial.ImageFormatList));
CreateMap<Subject, QARelationInfo>(MemberList.None);
@@ -715,14 +725,16 @@ namespace IRaCIS.Core.Application.Service
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path));
CreateMap<NoneDicomStudy, NoneDicomStudyView>()
.ForMember(d => d.NoneDicomStudyFileList, u => u.MapFrom(s => isFilterZip ? s.NoneDicomFileList.Where(t => !t.FileType.Contains(StaticData.FileType.Zip)).OrderBy(t => t.CreateTime).ThenBy(t => t.FileName) : s.NoneDicomFileList.OrderBy(t => t.CreateTime).ThenBy(t => t.FileName)))
.ForMember(d => d.NoneDicomStudyFileList, u => u.MapFrom(s =>
s.NoneDicomFileList.Where(t => isFilterZip ? !t.FileType.Contains(StaticData.FileType.Zip) : true).Where(t => isReading ? t.IsReading && t.IsDeleted == false : true).OrderBy(t => t.CreateTime).ThenBy(t => t.FileName)))
.ForMember(d => d.CodeView, u => u.MapFrom(s => s.StudyCode));
Guid? visiTaskId = null;
CreateMap<NoneDicomStudy, TaskDicomStudyView>()
.ForMember(d => d.NoneDicomStudyFileList, u => u.MapFrom(s => isFilterZip ?
s.TaskNoneDicomFileList.Where(t => visiTaskId != null ? t.VisitTaskId == visiTaskId : true).Where(t => !t.FileType.Contains(StaticData.FileType.Zip)).OrderBy(t => t.CreateTime).ThenBy(t => t.FileName)
: s.TaskNoneDicomFileList.Where(t => visiTaskId != null ? t.VisitTaskId == visiTaskId : true).OrderBy(t => t.CreateTime).ThenBy(t => t.FileName)))
.ForMember(d => d.NoneDicomStudyFileList, u => u.MapFrom(s =>
s.TaskNoneDicomFileList.Where(t => visiTaskId != null ? t.VisitTaskId == visiTaskId : true).Where(t => isFilterZip ? !t.FileType.Contains(StaticData.FileType.Zip):true)
.Where(t => isReading ? t.IsReading && t.IsDeleted == false : true)
.OrderBy(t => t.CreateTime).ThenBy(t => t.FileName)))
.ForMember(d => d.CodeView, u => u.MapFrom(s => s.StudyCode));
}
@@ -407,6 +407,7 @@ namespace IRaCIS.Core.Application.Service
{
if (await _readModuleRepository.AnyAsync(x => x.SubjectId == inDto.SubjectId && x.SubjectVisit.LatestScanDate <= clinicalForm.CheckDate && x.IsCRCConfirm))
{
throw new BusinessValidationFailedException(_localizer["ClinicalAnswer_unableToAddOrUpdate", clinicalForm.CheckDate.Value.ToString("yyyy-MM-dd")]);
}
@@ -372,6 +372,8 @@ namespace IRaCIS.Core.Application.Service
ClinicalDataSetEnName = x.ClinicalDataSetEnName,
UploadRole = x.UploadRole,
FileName = x.FileName,
EnFileName = x.EnFileName,
EnPath = x.EnPath,
Path = x.Path,
TrialId = trialId,
IsApply = x.IsApply,
@@ -159,9 +159,10 @@ namespace IRaCIS.Core.Application.Service
ClinicalDataLevel = x.ClinicalDataTrialSet.ClinicalDataLevel,
ClinicalDataSetEnName = x.ClinicalDataTrialSet.ClinicalDataSetEnName,
ClinicalDataTrialSetId = x.ClinicalDataTrialSet.Id,
FileName = x.ClinicalDataTrialSet.FileName,
FileName = _userInfo.IsEn_Us?x.ClinicalDataTrialSet.EnFileName: x.ClinicalDataTrialSet.FileName,
Path = _userInfo.IsEn_Us ? x.ClinicalDataTrialSet.EnPath : x.ClinicalDataTrialSet.Path,
UploadRole = x.ClinicalDataTrialSet.UploadRole,
Path = x.ClinicalDataTrialSet.Path,
IsBlind = x.IsBlind,
IsComplete = x.IsComplete,
ClinicalFromList = x.Subject.ClinicalFormList.Where(y => y.ReadingId == x.ReadingId && y.ClinicalDataTrialSetId == x.ClinicalDataTrialSetId).Select(y => new ClinicalFromData()
@@ -231,9 +232,10 @@ namespace IRaCIS.Core.Application.Service
ClinicalDataLevel = x.ClinicalDataTrialSet.ClinicalDataLevel,
ClinicalDataSetEnName = x.ClinicalDataTrialSet.ClinicalDataSetEnName,
ClinicalDataTrialSetId = x.ClinicalDataTrialSet.Id,
FileName = x.ClinicalDataTrialSet.FileName,
FileName = _userInfo.IsEn_Us?x.ClinicalDataTrialSet.EnFileName: x.ClinicalDataTrialSet.FileName,
Path = _userInfo.IsEn_Us ? x.ClinicalDataTrialSet.EnPath : x.ClinicalDataTrialSet.Path,
UploadRole = x.ClinicalDataTrialSet.UploadRole,
Path = x.ClinicalDataTrialSet.Path,
IsBlind = x.IsBlind,
IsComplete = x.IsComplete,
ClinicalFromList = x.Subject.ClinicalFormList.Where(y => y.ReadingId == x.ReadingId && y.ClinicalDataTrialSetId == x.ClinicalDataTrialSetId).Select(y => new ClinicalFromData()
@@ -682,8 +684,8 @@ namespace IRaCIS.Core.Application.Service
ClinicalDataSetName = x.ClinicalDataSetName.LanguageName(x.ClinicalDataSetEnName, _userInfo.IsEn_Us),
ClinicalDataSetEnName = x.ClinicalDataSetEnName,
ClinicalUploadType = x.ClinicalUploadType,
FileName = x.FileName,
Path = x.Path,
FileName = _userInfo.IsEn_Us?x.EnFileName: x.FileName,
Path = _userInfo.IsEn_Us ? x.EnPath : x.Path,
Id = x.Id,
CriterionEnumList = x.CriterionEnumList,
}).ToListAsync();
@@ -66,6 +66,16 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
/// </summary>
public string Path { get; set; }
/// <summary>
/// 英文模板文件名称
/// </summary>
public string EnFileName { get; set; } = string.Empty;
/// <summary>
/// 英文文件路径
/// </summary>
public string EnPath { get; set; } = string.Empty;
public List<Guid> TrialCriterionIdList { get; set; }
@@ -139,6 +149,17 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public string Path { get; set; }
/// <summary>
/// 英文模板文件名称
/// </summary>
public string EnFileName { get; set; } = string.Empty;
/// <summary>
/// 英文文件路径
/// </summary>
public string EnPath { get; set; } = string.Empty;
//public List<Guid> SystemCriterionIdList { get; set; }
@@ -291,6 +291,23 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public List<string> SheetNames { get; set; }
}
public class TestOncologyDto
{
public Guid Id { get; set; }
public string TargetLesion { get; set; }
public string NonTargetLesions { get; set; }
public string NewLesion { get; set; }
public string OverallEfficacy { get; set; }
}
/// <summary>
/// 阅片计算Dto
/// </summary>
@@ -1495,6 +1495,11 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public class GetRelatedVisitTaskOutDto
{
/// <summary>
/// 是否存在未处理的反馈
/// </summary>
public bool IsExistUnprocessedFeedback { get; set; }
public Guid VisitTaskId { get; set; }
public string TaskName { get; set; }
@@ -1845,6 +1850,8 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public bool ExistsManual { get; set; }
public bool IsBaseLine { get; set; }
public ReadingCategory ReadingCategory { get; set; }
public decimal VisitNum { get; set; }
@@ -1864,6 +1871,16 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public ReadingTaskState ReadingTaskState { get; set; }
/// <summary>
/// 是否显示检查名称
/// </summary>
public bool IsShowStudyName { get; set; }
/// <summary>
/// 是否存在未处理的反馈
/// </summary>
public bool IsExistUnprocessedFeedback { get; set; }
/// <summary>
/// 是否是转变的任务(转为IRECIST)
/// </summary>
@@ -2355,6 +2372,32 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public Guid VisitTaskId { get; set; }
}
public class GetNoneDicomMarkListOutDto
{
public List<AddNoneDicomMarkInDto> NoneDicomMarkList { get; set; }
}
public class GetNoneDicomMarkListInDtoDto
{
public Guid VisitTaskId { get; set; }
}
public class AddNoneDicomMarkInDto
{
public Guid? Id { get; set; }
public Guid VisitTaskId { get; set; }
public Guid? StudyId { get; set; }
public Guid? NoneDicomFileId { get; set; }
public string Path { get; set; }
public string MeasureData { get; set; } = string.Empty;
}
/// <summary>
///
/// </summary>
@@ -86,7 +86,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto
public Guid NewSystemCriterionId { get; set; }
public bool IsCopyQuestion { get; set; }
//public bool IsCopyQuestion { get; set; }
}
public class EditCriterionDictionaryInDto
@@ -22,8 +22,10 @@ namespace IRaCIS.Core.Application.Service
IRepository<ClinicalDataTrialSet> _clinicalDataTrialSetRepository,
IRepository<ClinicalDataSystemSet> _clinicalDataSystemSetRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<CriterionNidusSystem> _criterionNidusSystemRepository,
IRepository<SystemCriterionDictionaryCode> _systemCriterionDictionaryCodeRepository,
IReadingImageTaskService _iReadingImageTaskService,
IRepository<ReadingSystemCriterionDictionary> _readingCriterionDictionaryRepository,
IRepository<ReadingSystemCriterionDictionary> _readingSystemCriterionDictionaryRepository,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
IRepository<ReadingCriterionPage> _readingCriterionPageRepository,
IRepository<Trial> _trialRepository,
@@ -939,8 +941,7 @@ namespace IRaCIS.Core.Application.Service
[HttpPost]
public async Task<IResponseOutput> CopySystemCriterionData(CopySystemCriterionDataInDto inDto)
{
if (inDto.IsCopyQuestion)
{
var newSystemQuestionList = await _readingQuestionSystemRepository.Where(x => x.ReadingQuestionCriterionSystemId == inDto.SourceSystemCriterionId)
.ProjectTo<ReadingQuestionSystemData>(_mapper.ConfigurationProvider).ToListAsync();
newSystemQuestionList.ForEach(x =>
@@ -961,7 +962,12 @@ namespace IRaCIS.Core.Application.Service
{
question.RelevanceId = copyNewQuestionList.Where(y => x.RelevanceId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
}
needAddDatas.Add(question);
if (question.GroupId != null)
{
question.GroupId = copyNewQuestionList.Where(y => x.GroupId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
}
needAddDatas.Add(question);
};
await _readingQuestionSystemRepository.BatchDeleteNoTrackingAsync(x => x.ReadingQuestionCriterionSystemId == inDto.NewSystemCriterionId);
@@ -970,14 +976,24 @@ namespace IRaCIS.Core.Application.Service
#region
var newSystemTableQuestionList = await _readingTableQuestionSystemRepository.Where(x => x.SystemCriterionId == inDto.SourceSystemCriterionId)
.ProjectTo<ReadingTableQuestionSystemData>(_mapper.ConfigurationProvider).ToListAsync();
foreach (var question in newSystemTableQuestionList)
{
question.SystemCriterionId = inDto.NewSystemCriterionId;
question.Id = NewId.NextGuid();
}
var copeNewSystemTableQuestionList = newSystemTableQuestionList.Clone();
var needAddTableDatas = new List<ReadingTableQuestionSystemData>();
foreach (var x in newSystemTableQuestionList)
{
var tableQuestion = x.Clone();
tableQuestion.SystemCriterionId = inDto.NewSystemCriterionId;
tableQuestion.Id = NewId.NextGuid();
if (tableQuestion.ParentId != null)
tableQuestion.ReadingQuestionId = copyNewQuestionList.Where(y => x.ReadingQuestionId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
if (tableQuestion.ParentId != null)
{
tableQuestion.ParentId = copeNewSystemTableQuestionList.Where(y => x.ParentId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
}
@@ -989,26 +1005,67 @@ namespace IRaCIS.Core.Application.Service
{
tableQuestion.DependParentId = copeNewSystemTableQuestionList.Where(y => x.DependParentId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
}
needAddTableDatas.Add(tableQuestion);
if (tableQuestion.ClassifyTableQuestionId != null)
{
tableQuestion.ClassifyTableQuestionId = copeNewSystemTableQuestionList.Where(y => x.ClassifyTableQuestionId == y.OriginalId).Select(y => y.Id).FirstOrDefault();
}
needAddTableDatas.Add(tableQuestion);
}
await _readingTableQuestionSystemRepository.BatchDeleteNoTrackingAsync(x => x.SystemCriterionId == inDto.NewSystemCriterionId);
await _readingTableQuestionSystemRepository.AddRangeAsync(needAddTableDatas);
#endregion
#endregion
}
else
#region
var organData = await _organInfoRepository.Where(x => x.SystemCriterionId == inDto.SourceSystemCriterionId).ToListAsync();
organData.ForEach(x =>
{
var organData = await _organInfoRepository.Where(x => x.SystemCriterionId == inDto.SourceSystemCriterionId).ToListAsync();
x.Id = NewId.NextGuid();
x.SystemCriterionId = inDto.NewSystemCriterionId;
});
await _organInfoRepository.BatchDeleteNoTrackingAsync(x => x.SystemCriterionId == inDto.NewSystemCriterionId);
await _organInfoRepository.AddRangeAsync(organData);
#endregion
organData.ForEach(x =>
{
x.Id = NewId.NextGuid();
x.SystemCriterionId = inDto.NewSystemCriterionId;
});
await _organInfoRepository.BatchDeleteNoTrackingAsync(x => x.SystemCriterionId == inDto.NewSystemCriterionId);
await _organInfoRepository.AddRangeAsync(organData);
#region Code
var dictionaryCodes = await _systemCriterionDictionaryCodeRepository.Where(x => x.SystemCriterionId == inDto.SourceSystemCriterionId).ToListAsync();
}
dictionaryCodes.ForEach(x =>
{
x.Id = NewId.NextGuid();
x.SystemCriterionId = inDto.NewSystemCriterionId;
});
await _systemCriterionDictionaryCodeRepository.BatchDeleteNoTrackingAsync(x => x.SystemCriterionId == inDto.NewSystemCriterionId);
await _systemCriterionDictionaryCodeRepository.AddRangeAsync(dictionaryCodes);
#endregion
#region
var criterionDictionaries = await _readingSystemCriterionDictionaryRepository.Where(x => x.CriterionId == inDto.SourceSystemCriterionId).ToListAsync();
criterionDictionaries.ForEach(x =>
{
x.Id = NewId.NextGuid();
x.CriterionId = inDto.NewSystemCriterionId;
});
await _readingSystemCriterionDictionaryRepository.BatchDeleteNoTrackingAsync(x => x.CriterionId == inDto.NewSystemCriterionId);
await _readingSystemCriterionDictionaryRepository.AddRangeAsync(criterionDictionaries);
#endregion
#region criterionNidus
var criterionNidusSystems = await _criterionNidusSystemRepository.Where(x => x.CriterionId == inDto.SourceSystemCriterionId).ToListAsync();
criterionNidusSystems.ForEach(x =>
{
x.Id = NewId.NextGuid();
x.CriterionId = inDto.NewSystemCriterionId;
});
await _criterionNidusSystemRepository.BatchDeleteNoTrackingAsync(x => x.CriterionId == inDto.NewSystemCriterionId);
await _criterionNidusSystemRepository.AddRangeAsync(criterionNidusSystems);
#endregion
@@ -29,30 +29,30 @@ namespace IRaCIS.Core.Application.Service.TA
result = await _tumorAssessmentRepository1Point1.AsQueryable().ToPagedListAsync(inQuery, nameof(TumorAssessmentView.Id));
columnList = new List<ColumnInfo>()
{
new ColumnInfo(){ ColumnName="靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName="非靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName="新病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName="整体疗效",ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_TargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NonTargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NewLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_OverallEfficacy"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
};
break;
case CriterionType.RECIST1Pointt1_MB:
result = await _tumorAssessmentRepository1Point1BM.AsQueryable().ToPagedListAsync(inQuery, nameof(TumorAssessmentView.Id));
columnList = new List<ColumnInfo>()
{
new ColumnInfo(){ ColumnName="靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName="非靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName="新病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName="整体疗效",ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_TargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NonTargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NewLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_OverallEfficacy"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
};
break;
case CriterionType.IRECIST1Point1:
result = await _tumorAssessmentIRepository1Point1.AsQueryable().ToPagedListAsync(inQuery, nameof(TumorAssessmentView.Id));
columnList = new List<ColumnInfo>()
{
new ColumnInfo(){ ColumnName="靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName="非靶病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName="新病灶",ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName="整体疗效",ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_TargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.TargetLesion),DictionaryKey=typeof(TargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NonTargetLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NonTargetLesions),DictionaryKey=typeof(NoTargetAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_NewLesions"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.NewLesion),DictionaryKey=typeof(NewLesionAssessment).Name },
new ColumnInfo(){ ColumnName=_localizer["Tumor_OverallEfficacy"],ColumnKey=nameof(TumorAssessment_RECIST1Point1.OverallEfficacy),DictionaryKey=typeof(OverallAssessment).Name },
};
break;
}
@@ -32,6 +32,8 @@ namespace IRaCIS.Core.Application.Service
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<Trial> _trialRepository,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
IRepository<ReadingNoneDicomMark> _readingNoneDicomMarkRepository,
IRepository<UserLog> _userLogRepository,
IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
IRepository<ReadingOncologyTaskInfo> _readingOncologyTaskInfoRepository,
@@ -41,6 +43,7 @@ namespace IRaCIS.Core.Application.Service
IReadingCalculateService _readingCalculateService,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Subject> _subjectRepository,
IRepository<UserFeedBack> _userFeedBackRepository,
IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository,
IRepository<ReadingCriterionPage> _readingCriterionPageRepository,
@@ -642,7 +645,7 @@ namespace IRaCIS.Core.Application.Service
IsCurrentTask = x.Id == inDto.VisitTaskId,
IsConvertedTask = x.IsConvertedTask,
IsFirstChangeTask = x.BeforeConvertedTaskId != null,
IsExistUnprocessedFeedback=x.UserFeedBackList.Any(y => y.State == 0),
}).ToListAsync();
@@ -3154,6 +3157,7 @@ namespace IRaCIS.Core.Application.Service
});
}
var trialInfo = await _trialRepository.Where(x => x.Id == visitTaskInfo.TrialId).FirstNotNullAsync();
// 如果已经签名 就不需要再读了
task.IsNeedReadClinicalData = visitTaskInfo.ReadingTaskState == ReadingTaskState.HaveSigned ? false : task.IsNeedReadClinicalData;
@@ -3166,6 +3170,9 @@ namespace IRaCIS.Core.Application.Service
task.SubjectCode = blindSubjectCode.IsNullOrEmpty() ? task.SubjectCode : blindSubjectCode;
task.ExistsManual = (await GetManualList(new GetManualListInDto() { TrialId = visitTaskInfo.TrialId })).Count > 0;
task.ReadingTaskState = visitTaskInfo.ReadingTaskState;
task.IsShowStudyName= trialInfo.IsShowStudyName;
task.IsBaseLine = isBaseLine;
task.IsExistUnprocessedFeedback = await _userFeedBackRepository.AnyAsync(x => x.VisitTaskId == task.VisitTaskId && x.State == 0);
// 添加默认答案
if (inDto.VisitTaskId == null && visitTaskInfo.ReadingTaskState != ReadingTaskState.HaveSigned)
{
@@ -523,7 +523,7 @@ namespace IRaCIS.Core.Application.Service
var readModule = await _readModuleRepository.Where(x => x.SubjectVisitId == taskinfo.SourceSubjectVisitId && x.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId).FirstOrDefaultAsync();
if (criterion.IsReadingPeriod && !criterion.IsGlobalReading && readModule != null)
if (criterion.IsReadingPeriod && readModule != null)
{
return true;
}
@@ -1,10 +1,12 @@
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using Panda.DynamicWebApi.Attributes;
using System.Linq.Dynamic.Core;
namespace IRaCIS.Core.Application.Service
{
@@ -31,13 +33,56 @@ namespace IRaCIS.Core.Application.Service
}
/// <summary>
/// 添加非Dicom标记
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> AddNoneDicomMark(AddNoneDicomMarkInDto inDto)
{
var entity = await _readingNoneDicomMarkRepository.InsertOrUpdateAsync(inDto, true);
return ResponseOutput.Ok(entity.Id);
}
/// <summary>
/// 获取非Dicom标记
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task<GetNoneDicomMarkListOutDto> GetNoneDicomMarkListOutDto(GetNoneDicomMarkListInDtoDto inDto)
{
var result = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId)
.ProjectTo<AddNoneDicomMarkInDto>(_mapper.ConfigurationProvider)
.ToListAsync();
return new GetNoneDicomMarkListOutDto()
{
NoneDicomMarkList = result
};
}
/// <summary>
/// 删除非Dicom标记
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost("{id:guid}")]
public async Task<IResponseOutput> DeleteTrialFileType(Guid id)
{
var success = await _readingNoneDicomMarkRepository.DeleteFromQueryAsync(t => t.Id == id, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 保存任务问题
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SaveVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto)
{
await VerifyTaskIsSign(inDto.VisitTaskId);
@@ -84,26 +129,41 @@ namespace IRaCIS.Core.Application.Service
visitIds.AddRange(await _subjectVisitRepository.Where(x => x.VisitNum <= task.VisitNum && x.SubjectId == task.SubjectId).Select(x => x.Id).ToListAsync());
}
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisistTaskId).Select(t => new { t.BlindSubjectCode, t.TrialReadingCriterionId, t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisistTaskId).Select(t => new { t.BlindSubjectCode, t.ReadingTaskState, t.TrialReadingCriterionId, t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
IQueryable<NoneDicomStudyView> noneDicomStudyQueryable = default;
noneDicomStudyQueryable = _noneDicomStudyRepository
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.IsReading)
.Where(t => visitIds.Contains(t.SubjectVisitId) && t.NoneDicomFileList.Any(t => !t.FileType.Contains(StaticData.FileType.Zip)))
.WhereIf(taskinfo.IsImageFilter == true, t => taskinfo.CriterionModalitys.Contains(t.Modality))
.ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = true });
.ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = true, isReading = true });
if (inDto.VisistTaskId != null && _noneDicomStudyFileSystem.Any(t => t.VisitTaskId == inDto.VisistTaskId))
{
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.TaskNoneDicomFileList.Any(t => t.VisitTaskId == inDto.VisistTaskId))
noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.IsReading)
.Where(t => t.TaskNoneDicomFileList.Any(t => t.VisitTaskId == inDto.VisistTaskId))
.Where(t => taskinfo.IsImageFilter ? ("|" + taskinfo.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.Where(t => visitIds.Contains(t.SubjectVisitId))
.ProjectTo<TaskDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = true, visiTaskId = inDto.VisistTaskId });
.ProjectTo<TaskDicomStudyView>(_mapper.ConfigurationProvider, new { isFilterZip = true, isReading = true, visiTaskId = inDto.VisistTaskId });
}
List<NoneDicomStudyView> result = await noneDicomStudyQueryable.OrderBy(x => x.ImageDate).ThenBy(x => x.CreateTime).ToListAsync();
var nonoDicomStudyFileIds = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisistTaskId).ToListAsync();
if (nonoDicomStudyFileIds.Count > 0 && taskinfo.ReadingTaskState == ReadingTaskState.HaveSigned)
{
var studyId = nonoDicomStudyFileIds.Select(x => x.StudyId).FirstOrDefault();
var noneDicomids = nonoDicomStudyFileIds.Select(x => x.NoneDicomFileId).ToList();
var noneDicomStudyViewMark = new NoneDicomStudyView() { Id = Guid.NewGuid() };
noneDicomStudyViewMark.IsCriticalSequence = true;
noneDicomStudyViewMark.NoneDicomStudyFileList = await _noneDicomStudyFileRepository.Where(x => noneDicomids.Contains(x.Id)).ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider).ToListAsync();
result.Insert(0, noneDicomStudyViewMark);
}
List<NoneDicomStudyView> result = await noneDicomStudyQueryable.ToListAsync();
var trialInfo = await _trialRepository.Where(x => x.Id == inDto.TrialId).Select(x => new
@@ -232,6 +232,7 @@ namespace IRaCIS.Core.Application.Service
x.ReadingCategory == ReadingCategory.Oncology
&& x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId
&& x.TaskState == TaskState.Effect
&&x.SubjectId == taskInfo.SubjectId
&& x.ReadingTaskState == ReadingTaskState.HaveSigned
&& x.IsAnalysisCreate == taskInfo.IsAnalysisCreate
&& x.VisitTaskNum < taskInfo.VisitTaskNum
@@ -65,6 +65,8 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialClinicalTableQuestion, ClinicalTablePreviewDto>();
#endregion
CreateMap<TableMarkInfo, ReadingTaskQuestionMark>();
CreateMap<AddNoneDicomMarkInDto, ReadingNoneDicomMark>();
CreateMap<ReadingNoneDicomMark, AddNoneDicomMarkInDto>();
CreateMap<ReadingTaskQuestionMark, TableMarkInfo>();
CreateMap<VisitTask, VisitTaskDto>();
CreateMap<SaveTableQuestionMarkInDto, ReadingTaskQuestionMark>();

Some files were not shown because too many files have changed in this diff Show More